View Javadoc

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