View Javadoc

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.kew.rule.bo;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.uif.RemotableAttributeError;
20  import org.kuali.rice.core.api.util.ConcreteKeyValue;
21  import org.kuali.rice.core.api.util.KeyValue;
22  import org.kuali.rice.core.api.util.RiceKeyConstants;
23  import org.kuali.rice.core.web.format.BooleanFormatter;
24  import org.kuali.rice.core.web.format.CollectionFormatter;
25  import org.kuali.rice.core.web.format.DateFormatter;
26  import org.kuali.rice.core.web.format.Formatter;
27  import org.kuali.rice.kew.api.KewApiServiceLocator;
28  import org.kuali.rice.kew.api.rule.RuleTemplate;
29  import org.kuali.rice.kew.api.rule.RuleTemplateAttribute;
30  import org.kuali.rice.kew.lookupable.MyColumns;
31  import org.kuali.rice.kew.rule.RuleBaseValues;
32  import org.kuali.rice.kew.rule.WorkflowRuleAttributeRows;
33  import org.kuali.rice.kew.rule.service.RuleServiceInternal;
34  import org.kuali.rice.kew.rule.service.RuleTemplateService;
35  import org.kuali.rice.kew.service.KEWServiceLocator;
36  import org.kuali.rice.kim.api.KimConstants;
37  import org.kuali.rice.kim.api.group.Group;
38  import org.kuali.rice.kim.api.group.GroupService;
39  import org.kuali.rice.kim.api.identity.Person;
40  import org.kuali.rice.kim.api.identity.principal.Principal;
41  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
42  import org.kuali.rice.kns.document.authorization.BusinessObjectRestrictions;
43  import org.kuali.rice.kns.lookup.HtmlData;
44  import org.kuali.rice.kns.lookup.KualiLookupableHelperServiceImpl;
45  import org.kuali.rice.kns.lookup.LookupableHelperService;
46  import org.kuali.rice.kns.service.KNSServiceLocator;
47  import org.kuali.rice.kns.web.comparator.CellComparatorHelper;
48  import org.kuali.rice.kns.web.struts.form.LookupForm;
49  import org.kuali.rice.kns.web.ui.Column;
50  import org.kuali.rice.kns.web.ui.Field;
51  import org.kuali.rice.kns.web.ui.ResultRow;
52  import org.kuali.rice.kns.web.ui.Row;
53  import org.kuali.rice.krad.bo.BusinessObject;
54  import org.kuali.rice.krad.bo.PersistableBusinessObject;
55  import org.kuali.rice.krad.exception.ValidationException;
56  import org.kuali.rice.krad.util.GlobalVariables;
57  import org.kuali.rice.krad.util.KRADConstants;
58  import org.kuali.rice.krad.util.ObjectUtils;
59  
60  import java.sql.Date;
61  import java.util.ArrayList;
62  import java.util.Collection;
63  import java.util.HashMap;
64  import java.util.Iterator;
65  import java.util.List;
66  import java.util.Map;
67  
68  /**
69   * This is a description of what this class does - jjhanso don't forget to fill this in.
70   *
71   * @author Kuali Rice Team (rice.collab@kuali.org)
72   *
73   */
74  public class RuleBaseValuesLookupableHelperServiceImpl extends KualiLookupableHelperServiceImpl {
75      private List<Row> rows = new ArrayList<Row>();
76      //private List<Column> columns = establishColumns();
77      //private Long previousRuleTemplateId;
78      private LookupableHelperService ruleDelegationLookupableHelperService;
79      private List<?> delegationPkNames;
80  
81      private static final String RULE_TEMPLATE_PROPERTY_NAME = "ruleTemplate.name";
82      private static final String RULE_ID_PROPERTY_NAME = "id";
83      private static final String RULE_TEMPLATE_ID_PROPERTY_NAME = "ruleTemplateId";
84      private static final String ACTIVE_IND_PROPERTY_NAME = "active";
85      private static final String DELEGATE_RULE_PROPERTY_NAME = "delegateRule";
86      private static final String GROUP_REVIEWER_PROPERTY_NAME = "groupReviewer";
87      private static final String GROUP_REVIEWER_NAME_PROPERTY_NAME = "groupReviewerName";
88      private static final String GROUP_REVIEWER_NAMESPACE_PROPERTY_NAME = "groupReviewerNamespace";
89      private static final String PERSON_REVIEWER_PROPERTY_NAME = "personReviewer";
90      private static final String PERSON_REVIEWER_TYPE_PROPERTY_NAME = "personReviewerType";
91      private static final String DOC_TYP_NAME_PROPERTY_NAME = "documentType.name";
92      private static final String RULE_DESC_PROPERTY_NAME = "description";
93  
94      private static final String BACK_LOCATION = "backLocation";
95      private static final String DOC_FORM_KEY = "docFormKey";
96      private static final String INVALID_WORKGROUP_ERROR = "The Group Reviewer Namespace and Name combination is not valid";
97      private static final String INVALID_PERSON_ERROR = "The Person Reviewer is not valid";
98  
99      @Override
100 	public List<Row> getRows() {
101         List<Row> superRows = super.getRows();
102         List<Row> returnRows = new ArrayList<Row>();
103         returnRows.addAll(superRows);
104         returnRows.addAll(rows);
105         return returnRows;
106     }
107 
108     @Override
109     public boolean checkForAdditionalFields(Map<String, String> fieldValues) {
110         String ruleTemplateNameParam = fieldValues.get(RULE_TEMPLATE_PROPERTY_NAME);
111 
112         if (StringUtils.isNotBlank(ruleTemplateNameParam)) {
113             rows = new ArrayList<Row>();
114             RuleTemplate ruleTemplate = KewApiServiceLocator.getRuleService().getRuleTemplateByName(ruleTemplateNameParam);
115 
116             for (RuleTemplateAttribute ruleTemplateAttribute : ruleTemplate.getActiveRuleTemplateAttributes()) {
117                 if (!RuleAttribute.isWorkflowAttribute(ruleTemplateAttribute.getRuleAttribute().getType())) {
118                     continue;
119                 }
120                 // run through the attributes fields once to populate field values we have to do this
121                 // to allow rows dependent on another row value to populate correctly in the loop below
122                 WorkflowRuleAttributeRows workflowRuleAttributeRows =
123                         KEWServiceLocator.getWorkflowRuleAttributeMediator().getSearchRows(fieldValues, ruleTemplateAttribute);
124                 for (Row row : workflowRuleAttributeRows.getRows()) {
125                     List<Field> fields = new ArrayList<Field>();
126                     for (Iterator<Field> iterator2 = row.getFields().iterator(); iterator2.hasNext(); ) {
127                         Field field = (Field) iterator2.next();
128                         if (fieldValues.get(field.getPropertyName()) != null) {
129                             field.setPropertyValue(fieldValues.get(field.getPropertyName()));
130                         }
131                         fields.add(field);
132                         fieldValues.put(field.getPropertyName(), field.getPropertyValue());
133                     }
134                 }
135                 // now run through a second time with our shiny new field values
136                 // ...by the way, just trying to preserve behavior from Rice 1.0.x here...generally speaking, this stuff is crazy!!!
137                 workflowRuleAttributeRows =
138                         KEWServiceLocator.getWorkflowRuleAttributeMediator().getSearchRows(fieldValues, ruleTemplateAttribute);
139                 for (Row row : workflowRuleAttributeRows.getRows()) {
140                     List<Field> fields = new ArrayList<Field>();
141                     for (Iterator<Field> iterator2 = row.getFields().iterator(); iterator2.hasNext(); ) {
142                         Field field = iterator2.next();
143                         if (fieldValues.get(field.getPropertyName()) != null) {
144                             field.setPropertyValue(fieldValues.get(field.getPropertyName()));
145                         }
146                         fields.add(field);
147                         fieldValues.put(field.getPropertyName(), field.getPropertyValue());
148                     }
149                     row.setFields(fields);
150                     rows.add(row);
151 
152                 }
153             }
154             return true;
155         }
156         rows.clear();
157         return false;
158     }
159 
160     @Override
161     public List<? extends BusinessObject> getSearchResults(Map<String, String> fieldValues) {
162         String docTypeNameParam = fieldValues.get(DOC_TYP_NAME_PROPERTY_NAME);
163         String ruleTemplateIdParam = fieldValues.get(RULE_TEMPLATE_ID_PROPERTY_NAME);
164         String ruleTemplateNameParam = fieldValues.get(RULE_TEMPLATE_PROPERTY_NAME);
165         String groupIdParam = fieldValues.get(GROUP_REVIEWER_PROPERTY_NAME);
166         String groupNameParam = fieldValues.get(GROUP_REVIEWER_NAME_PROPERTY_NAME);
167         String groupNamespaceParam = fieldValues.get(GROUP_REVIEWER_NAMESPACE_PROPERTY_NAME);
168         String networkIdParam = fieldValues.get(PERSON_REVIEWER_PROPERTY_NAME);
169         String userDirectiveParam = fieldValues.get(PERSON_REVIEWER_TYPE_PROPERTY_NAME);
170         String activeParam = fieldValues.get(ACTIVE_IND_PROPERTY_NAME);
171         String ruleIdParam = fieldValues.get(RULE_ID_PROPERTY_NAME);
172         String ruleDescription = fieldValues.get(RULE_DESC_PROPERTY_NAME);
173         String deleteSelection = fieldValues.get(DELEGATE_RULE_PROPERTY_NAME);
174 
175         String docTypeSearchName = null;
176         String workflowId = null;
177         String workgroupId = null;
178         String ruleTemplateId = null;
179         Boolean isDelegateRule = null;
180         Boolean isActive = null;
181         String ruleId = null;
182       
183         
184         //for KULRICE-3678
185         if(StringUtils.isNotBlank(deleteSelection))
186         {
187         	if(deleteSelection.equalsIgnoreCase("Y")) {
188 				isDelegateRule = Boolean.TRUE;
189 			} else {
190 				isDelegateRule = Boolean.FALSE;
191 			}
192         }
193         
194         if (StringUtils.isNotBlank(ruleIdParam)) {
195             ruleId = ruleIdParam.trim();
196         }
197 
198         if (StringUtils.isNotBlank(activeParam)) {
199             if (activeParam.equals("Y")) {
200                 isActive = Boolean.TRUE;
201             } else {
202                 isActive = Boolean.FALSE;
203             }
204         }
205 
206         if (StringUtils.isNotBlank(docTypeNameParam)) {
207             docTypeSearchName = docTypeNameParam.replace('*', '%');
208             docTypeSearchName = "%" + docTypeSearchName.trim() + "%";
209         }
210 
211         if (StringUtils.isNotBlank(networkIdParam)) {
212             Principal principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(networkIdParam);
213         	if (principal != null) {
214         		workflowId = principal.getPrincipalId();
215         	}
216         }
217         
218         if (!StringUtils.isEmpty(groupIdParam) || !StringUtils.isEmpty(groupNameParam)) {
219             Group group = null;
220             if (groupIdParam != null && !"".equals(groupIdParam)) {
221                 group = getGroupService().getGroup(groupIdParam.trim());
222             } else {
223                 if (groupNamespaceParam == null) {
224                     groupNamespaceParam = KimConstants.KIM_GROUP_DEFAULT_NAMESPACE_CODE;
225                 }
226                 group = getGroupService().getGroupByNamespaceCodeAndName(groupNamespaceParam, groupNameParam.trim());
227                 if (group == null) {
228                     GlobalVariables.getMessageMap().putError(GROUP_REVIEWER_NAMESPACE_PROPERTY_NAME, RiceKeyConstants.ERROR_CUSTOM, INVALID_WORKGROUP_ERROR);
229                 } else {
230                     workgroupId = group.getId();
231                 }
232             }
233         }
234 
235         Map<String, String> attributes = null;
236         MyColumns myColumns = new MyColumns();
237         if (StringUtils.isNotBlank(ruleTemplateNameParam) || StringUtils.isNotBlank(ruleTemplateIdParam) && !"null".equals(ruleTemplateIdParam)) {
238             RuleTemplate ruleTemplate = null;
239             if (StringUtils.isNotBlank(ruleTemplateIdParam)) {
240                 ruleTemplate = KewApiServiceLocator.getRuleService().getRuleTemplate(ruleTemplateIdParam);
241             } else {
242                 ruleTemplate = KewApiServiceLocator.getRuleService().getRuleTemplateByName(ruleTemplateNameParam.trim());
243                 ruleTemplateId = ruleTemplate.getId();
244             }
245 
246             attributes = new HashMap<String, String>();
247             for (RuleTemplateAttribute ruleTemplateAttribute : ruleTemplate.getActiveRuleTemplateAttributes()) {
248                 if (!RuleAttribute.isWorkflowAttribute(ruleTemplateAttribute.getRuleAttribute().getType())) {
249                     continue;
250                 }
251                 WorkflowRuleAttributeRows workflowRuleAttributeRows =
252                         KEWServiceLocator.getWorkflowRuleAttributeMediator().getSearchRows(fieldValues, ruleTemplateAttribute, false);
253 
254                 for (RemotableAttributeError error : workflowRuleAttributeRows.getValidationErrors()) {
255                     GlobalVariables.getMessageMap().putError(error.getAttributeName(), RiceKeyConstants.ERROR_CUSTOM, error.getMessage());
256                 }
257 
258                 for (Row row : workflowRuleAttributeRows.getRows()) {
259                     for (Field field : row.getFields()) {
260                         if (fieldValues.get(field.getPropertyName()) != null) {
261                             String attributeParam = fieldValues.get(field.getPropertyName());
262                             if (!attributeParam.equals("")) {
263                                 attributes.put(field.getPropertyName(), attributeParam.trim());
264                             }
265                         }
266                         if (field.getFieldType().equals(Field.TEXT) || field.getFieldType().equals(Field.DROPDOWN) || field.getFieldType().equals(Field.DROPDOWN_REFRESH) || field.getFieldType().equals(Field.RADIO)) {
267                             myColumns.getColumns().add(new ConcreteKeyValue(field.getPropertyName(), ruleTemplateAttribute.getId()));
268                         }
269                     }
270                 }
271             }
272         }
273 
274         if (!StringUtils.isEmpty(ruleDescription)) {
275             ruleDescription = ruleDescription.replace('*', '%');
276             ruleDescription = "%" + ruleDescription.trim() + "%";
277         }
278        
279         if (!GlobalVariables.getMessageMap().hasNoErrors()) {
280             throw new ValidationException("errors in search criteria");
281         }
282        
283 
284         // TODO: replace this with new API find method ??
285         List<RuleBaseValues> rules = getRuleService().search(docTypeSearchName, ruleId, ruleTemplateId, ruleDescription, workgroupId, workflowId, isDelegateRule, isActive, attributes, userDirectiveParam);
286         List<RuleBaseValues> displayList = new ArrayList<RuleBaseValues>();
287 
288         for (RuleBaseValues record : rules) {
289             if (StringUtils.isEmpty(record.getDescription())) {
290                 record.setDescription("");
291             }
292 
293             if (ruleTemplateNameParam != null && !ruleTemplateNameParam.trim().equals("") || ruleTemplateIdParam != null && !"".equals(ruleTemplateIdParam) && !"null".equals(ruleTemplateIdParam)) {
294                 MyColumns myNewColumns = new MyColumns();
295                 for (KeyValue pair : myColumns.getColumns()) {
296                     final KeyValue newPair;
297                     if (record.getRuleExtensionValue(pair.getValue(), pair.getKey().toString()) != null) {
298                     	newPair = new ConcreteKeyValue(pair.getKey(), record.getRuleExtensionValue(pair.getValue(), pair.getKey().toString()).getValue());
299                     } else {
300                     	newPair = new ConcreteKeyValue(pair.getKey(), "");
301                     }
302                     myNewColumns.getColumns().add(newPair);
303                     record.getFieldValues().put(newPair.getKey(), newPair.getValue());
304                 }
305                 record.setMyColumns(myNewColumns);
306             }
307 
308             StringBuffer returnUrl = new StringBuffer("<a href=\"");
309             returnUrl.append(fieldValues.get(BACK_LOCATION)).append("?methodToCall=refresh&docFormKey=").append(fieldValues.get(DOC_FORM_KEY)).append("&");
310 
311             returnUrl.append(RULE_ID_PROPERTY_NAME);
312             returnUrl.append("=").append(record.getId()).append("\">return value</a>");
313             record.setReturnUrl(returnUrl.toString());
314 
315             String destinationUrl = "<a href=\"Rule.do?methodToCall=report&currentRuleId=" + record.getId() + "\">report</a>";
316 
317             record.setDestinationUrl(destinationUrl);
318 
319             displayList.add(record);
320         }
321         return displayList;
322 
323     }
324 
325 
326 
327     private GroupService getGroupService() {
328        return KimApiServiceLocator.getGroupService();
329     }
330 
331     private RuleTemplateService getRuleTemplateService() {
332         return (RuleTemplateService) KEWServiceLocator.getService(KEWServiceLocator.RULE_TEMPLATE_SERVICE);
333     }
334     private RuleServiceInternal getRuleService() {
335         return (RuleServiceInternal) KEWServiceLocator.getService(KEWServiceLocator.RULE_SERVICE);
336     }
337 
338     @Override
339     public void validateSearchParameters(Map<String, String> fieldValues) {
340         super.validateSearchParameters(fieldValues);
341 
342         // make sure that if we have either groupName or Namespace, that both are filled in
343         String groupName = (String)fieldValues.get(GROUP_REVIEWER_NAME_PROPERTY_NAME);
344         String groupNamespace = (String)fieldValues.get(GROUP_REVIEWER_NAMESPACE_PROPERTY_NAME);
345         String principalName = (String)fieldValues.get(PERSON_REVIEWER_PROPERTY_NAME);
346 
347         if (StringUtils.isEmpty(groupName) && !StringUtils.isEmpty(groupNamespace)) {
348             String attributeLabel = getDataDictionaryService().getAttributeLabel(getBusinessObjectClass(), GROUP_REVIEWER_NAME_PROPERTY_NAME);
349             GlobalVariables.getMessageMap().putError(GROUP_REVIEWER_NAME_PROPERTY_NAME, RiceKeyConstants.ERROR_REQUIRED, attributeLabel);
350         }
351 
352         if  (!StringUtils.isEmpty(groupName) && StringUtils.isEmpty(groupNamespace)) {
353             String attributeLabel = getDataDictionaryService().getAttributeLabel(getBusinessObjectClass(), GROUP_REVIEWER_NAMESPACE_PROPERTY_NAME);
354             GlobalVariables.getMessageMap().putError(GROUP_REVIEWER_NAMESPACE_PROPERTY_NAME, RiceKeyConstants.ERROR_REQUIRED, attributeLabel);
355         }
356 
357         if  (!StringUtils.isEmpty(groupName) && !StringUtils.isEmpty(groupNamespace)) {
358             Group group = KimApiServiceLocator.getGroupService().getGroupByNamespaceCodeAndName(groupNamespace,
359                     groupName);
360             if (group == null) {
361                 GlobalVariables.getMessageMap().putError(GROUP_REVIEWER_NAME_PROPERTY_NAME, RiceKeyConstants.ERROR_CUSTOM, INVALID_WORKGROUP_ERROR);
362             }
363         }
364 
365         if  (!StringUtils.isEmpty(principalName)) {
366             Person person = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(principalName);
367             if (person == null) {
368                 GlobalVariables.getMessageMap().putError(PERSON_REVIEWER_PROPERTY_NAME, RiceKeyConstants.ERROR_CUSTOM, INVALID_PERSON_ERROR);
369             }
370         }
371         if (!GlobalVariables.getMessageMap().hasNoErrors()) {
372             throw new ValidationException("errors in search criteria");
373         }
374     }
375 
376     @Override
377     public Collection performLookup(LookupForm lookupForm,
378             Collection resultTable, boolean bounded) {
379         //return super.performLookup(lookupForm, resultTable, bounded);
380         setBackLocation((String) lookupForm.getFieldsForLookup().get(KRADConstants.BACK_LOCATION));
381         setDocFormKey((String) lookupForm.getFieldsForLookup().get(KRADConstants.DOC_FORM_KEY));
382         Collection displayList;
383 
384         // call search method to get results
385         if (bounded) {
386             displayList = getSearchResults(lookupForm.getFieldsForLookup());
387         }
388         else {
389             displayList = getSearchResultsUnbounded(lookupForm.getFieldsForLookup());
390         }
391 
392         HashMap<String,Class> propertyTypes = new HashMap<String, Class>();
393 
394         boolean hasReturnableRow = false;
395 
396         List returnKeys = getReturnKeys();
397         List pkNames = getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(getBusinessObjectClass());
398         Person user = GlobalVariables.getUserSession().getPerson();
399         
400         // iterate through result list and wrap rows with return url and action urls
401         for (Iterator iter = displayList.iterator(); iter.hasNext();) {
402             BusinessObject element = (BusinessObject) iter.next();
403             if(element instanceof PersistableBusinessObject){
404                 lookupForm.setLookupObjectId(((PersistableBusinessObject)element).getObjectId());
405             }
406 
407             BusinessObjectRestrictions businessObjectRestrictions = getBusinessObjectAuthorizationService().getLookupResultRestrictions(element, user);
408 
409             HtmlData returnUrl = getReturnUrl(element, lookupForm, returnKeys, businessObjectRestrictions);
410 
411             String actionUrls = getActionUrls(element, pkNames, businessObjectRestrictions);
412             //Fix for JIRA - KFSMI-2417
413             if("".equals(actionUrls)){
414                 actionUrls = ACTION_URLS_EMPTY;
415             }
416 
417             // Determine whether or not this rule is a delegate rule.
418             boolean isRuleDelegation = (element instanceof RuleBaseValues && ((RuleBaseValues) element).getDelegateRule().booleanValue());
419             
420             List<Column> columns = getColumns();
421             for (Object element2 : columns) {
422 
423                 Column col = (Column) element2;
424                 Formatter formatter = col.getFormatter();
425 
426                 // pick off result column from result list, do formatting
427                 String propValue = KRADConstants.EMPTY_STRING;
428                 Object prop = null;
429                 boolean skipPropTypeCheck = false;
430                 //try to get value elsewhere
431                 if (element instanceof RuleBaseValues) {
432                     prop = ((RuleBaseValues)element).getFieldValues().get(col.getPropertyName());
433                     skipPropTypeCheck = true;
434                 }
435                 if (prop == null) {
436                     prop = ObjectUtils.getPropertyValue(element, col.getPropertyName());
437                 }
438 
439                 // set comparator and formatter based on property type
440                 Class propClass = propertyTypes.get(col.getPropertyName());
441                 if ( propClass == null && !skipPropTypeCheck) {
442                     try {
443                         propClass = ObjectUtils.getPropertyType( element, col.getPropertyName(), getPersistenceStructureService() );
444                         propertyTypes.put( col.getPropertyName(), propClass );
445                     } catch (Exception e) {
446                         throw new RuntimeException("Cannot access PropertyType for property " + "'" + col.getPropertyName() + "' " + " on an instance of '" + element.getClass().getName() + "'.", e);
447                     }
448                 }
449 
450                 // formatters
451                 if (prop != null) {
452                     // for Booleans, always use BooleanFormatter
453                     if (prop instanceof Boolean) {
454                         formatter = new BooleanFormatter();
455                     }
456 
457                     // for Dates, always use DateFormatter
458                     if (prop instanceof Date) {
459                         formatter = new DateFormatter();
460                     }
461 
462                     // for collection, use the list formatter if a formatter hasn't been defined yet
463                     if (prop instanceof Collection && formatter == null) {
464                     formatter = new CollectionFormatter();
465                     }
466 
467                     if (formatter != null) {
468                         propValue = (String) formatter.format(prop);
469                     }
470                     else {
471                         propValue = prop.toString();
472                     }
473                 }
474 
475                 // comparator
476                 col.setComparator(CellComparatorHelper.getAppropriateComparatorForPropertyClass(propClass));
477                 col.setValueComparator(CellComparatorHelper.getAppropriateValueComparatorForPropertyClass(propClass));
478 
479                 propValue = maskValueIfNecessary(element.getClass(), col.getPropertyName(), propValue, businessObjectRestrictions);
480 
481                 col.setPropertyValue(propValue);
482 
483                 if (StringUtils.isNotBlank(propValue)) {
484                 	if (RULE_ID_PROPERTY_NAME.equals(col.getPropertyName()) && isRuleDelegation) {
485                 		// If the row represents a delegate rule, make the ID column's inquiry link lead to the corresponding delegate rule instead.
486                    		List<?> delegationList = KEWServiceLocator.getRuleDelegationService().findByDelegateRuleId(
487                    				((RuleBaseValues) element).getId());
488                 		if (ObjectUtils.isNotNull(delegationList) && !delegationList.isEmpty()) {
489                 			BusinessObject ruleDelegation = (BusinessObject) delegationList.get(0);
490                 			col.setColumnAnchor(getInquiryUrl(ruleDelegation, "ruleDelegationId"));
491                 		} else {
492                 			col.setColumnAnchor(getInquiryUrl(element, col.getPropertyName()));
493                 		}
494                 	}else {
495                 		col.setColumnAnchor(getInquiryUrl(element, col.getPropertyName()));
496                 	}
497 
498                 }
499             }
500 
501             ResultRow row = new ResultRow(columns, returnUrl.constructCompleteHtmlTag(), actionUrls);
502             row.setRowId(returnUrl.getName());
503             row.setReturnUrlHtmlData(returnUrl);
504             // because of concerns of the BO being cached in session on the ResultRow,
505             // let's only attach it when needed (currently in the case of export)
506             if (getBusinessObjectDictionaryService().isExportable(getBusinessObjectClass())) {
507                 row.setBusinessObject(element);
508             }
509             if(element instanceof PersistableBusinessObject){
510                 row.setObjectId((((PersistableBusinessObject)element).getObjectId()));
511             }
512 
513 
514             boolean rowReturnable = isResultReturnable(element);
515             row.setRowReturnable(rowReturnable);
516             if (rowReturnable) {
517                 hasReturnableRow = true;
518             }
519             resultTable.add(row);
520         }
521 
522         lookupForm.setHasReturnableRow(hasReturnableRow);
523 
524         return displayList;
525     }
526 
527     @Override
528     public List<Column> getColumns() {
529         List<Column> columns = super.getColumns();
530         for (Row row : rows) {
531             for (Field field : row.getFields()) {
532                 Column newColumn = new Column();
533                 newColumn.setColumnTitle(field.getFieldLabel());
534                 newColumn.setMaxLength(field.getMaxLength());
535                 newColumn.setPropertyName(field.getPropertyName());
536                 columns.add(newColumn);
537             }
538         }
539         return columns;
540     }
541 
542     @Override
543     public List<HtmlData> getCustomActionUrls(BusinessObject businessObject,
544             List pkNames) {
545         RuleBaseValues ruleBaseValues = (RuleBaseValues)businessObject;
546         List<HtmlData> htmlDataList = new ArrayList<HtmlData>();
547         if (StringUtils.isNotBlank(ruleBaseValues.getRuleTemplateName()) && StringUtils.isNotBlank(getMaintenanceDocumentTypeName())) {
548         	if (ruleBaseValues.getDelegateRule().booleanValue()) {
549         		// If the rule is a delegate rule, have the edit/copy links open the rule delegation maintenance document screen instead.
550         		List<?> delegationList = KEWServiceLocator.getRuleDelegationService().findByDelegateRuleId(ruleBaseValues.getId());
551         		if (ObjectUtils.isNotNull(delegationList) && !delegationList.isEmpty()) {
552         			BusinessObject ruleDelegation = (BusinessObject) delegationList.get(0);
553     				// Retrieve the rule delegation lookupable helper service and the primary key names, if they have not been obtained yet.
554         	        if (ruleDelegationLookupableHelperService == null) {
555         				ruleDelegationLookupableHelperService = KNSServiceLocator.getLookupable(
556                                 KNSServiceLocator.getBusinessObjectDictionaryService()
557                                         .getLookupableID(ruleDelegation.getClass())).getLookupableHelperService();
558         				if (ruleDelegationLookupableHelperService.getBusinessObjectClass() == null) {
559         					ruleDelegationLookupableHelperService.setBusinessObjectClass(ruleDelegation.getClass());
560         				}
561         				delegationPkNames = getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(ruleDelegation.getClass());
562         			}
563         	        // Allow the rule delegation's lookupable helper service to handle the custom action URL generation instead.
564         			htmlDataList = ruleDelegationLookupableHelperService.getCustomActionUrls(ruleDelegation, delegationPkNames);
565         		}
566         	} else {
567         		// Otherwise, have the links open the regular routing rule maintenance document screen.
568         		if (allowsMaintenanceEditAction(businessObject)) {
569         			htmlDataList.add(getUrlData(businessObject, KRADConstants.MAINTENANCE_EDIT_METHOD_TO_CALL, pkNames));
570         		}
571         		if (allowsMaintenanceNewOrCopyAction()) {
572                 	htmlDataList.add(getUrlData(businessObject, KRADConstants.MAINTENANCE_COPY_METHOD_TO_CALL, pkNames));
573             	}
574         	}
575         }
576         
577         return htmlDataList;
578     }
579 
580 
581 
582 }