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     */
016    package org.kuali.rice.kew.rule.bo;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.kuali.rice.core.api.uif.RemotableAttributeError;
020    import org.kuali.rice.core.api.util.ConcreteKeyValue;
021    import org.kuali.rice.core.api.util.KeyValue;
022    import org.kuali.rice.core.api.util.RiceKeyConstants;
023    import org.kuali.rice.core.web.format.BooleanFormatter;
024    import org.kuali.rice.core.web.format.CollectionFormatter;
025    import org.kuali.rice.core.web.format.DateFormatter;
026    import org.kuali.rice.core.web.format.Formatter;
027    import org.kuali.rice.kew.api.KewApiServiceLocator;
028    import org.kuali.rice.kew.api.rule.RuleTemplate;
029    import org.kuali.rice.kew.api.rule.RuleTemplateAttribute;
030    import org.kuali.rice.kew.lookupable.MyColumns;
031    import org.kuali.rice.kew.rule.RuleBaseValues;
032    import org.kuali.rice.kew.rule.WorkflowRuleAttributeRows;
033    import org.kuali.rice.kew.rule.service.RuleServiceInternal;
034    import org.kuali.rice.kew.rule.service.RuleTemplateService;
035    import org.kuali.rice.kew.service.KEWServiceLocator;
036    import org.kuali.rice.kim.api.KimConstants;
037    import org.kuali.rice.kim.api.group.Group;
038    import org.kuali.rice.kim.api.group.GroupService;
039    import org.kuali.rice.kim.api.identity.Person;
040    import org.kuali.rice.kim.api.identity.principal.Principal;
041    import org.kuali.rice.kim.api.services.KimApiServiceLocator;
042    import org.kuali.rice.kns.document.authorization.BusinessObjectRestrictions;
043    import org.kuali.rice.kns.lookup.HtmlData;
044    import org.kuali.rice.kns.lookup.KualiLookupableHelperServiceImpl;
045    import org.kuali.rice.kns.lookup.LookupableHelperService;
046    import org.kuali.rice.kns.service.KNSServiceLocator;
047    import org.kuali.rice.kns.web.comparator.CellComparatorHelper;
048    import org.kuali.rice.kns.web.struts.form.LookupForm;
049    import org.kuali.rice.kns.web.ui.Column;
050    import org.kuali.rice.kns.web.ui.Field;
051    import org.kuali.rice.kns.web.ui.ResultRow;
052    import org.kuali.rice.kns.web.ui.Row;
053    import org.kuali.rice.krad.bo.BusinessObject;
054    import org.kuali.rice.krad.bo.PersistableBusinessObject;
055    import org.kuali.rice.krad.exception.ValidationException;
056    import org.kuali.rice.krad.util.GlobalVariables;
057    import org.kuali.rice.krad.util.KRADConstants;
058    import org.kuali.rice.krad.util.ObjectUtils;
059    
060    import java.sql.Date;
061    import java.util.ArrayList;
062    import java.util.Collection;
063    import java.util.HashMap;
064    import java.util.Iterator;
065    import java.util.List;
066    import java.util.Map;
067    
068    /**
069     * This is a description of what this class does - jjhanso don't forget to fill this in.
070     *
071     * @author Kuali Rice Team (rice.collab@kuali.org)
072     *
073     */
074    public class RuleBaseValuesLookupableHelperServiceImpl extends KualiLookupableHelperServiceImpl {
075        private List<Row> rows = new ArrayList<Row>();
076        //private List<Column> columns = establishColumns();
077        //private Long previousRuleTemplateId;
078        private LookupableHelperService ruleDelegationLookupableHelperService;
079        private List<?> delegationPkNames;
080    
081        private static final String RULE_TEMPLATE_PROPERTY_NAME = "ruleTemplate.name";
082        private static final String RULE_ID_PROPERTY_NAME = "id";
083        private static final String RULE_TEMPLATE_ID_PROPERTY_NAME = "ruleTemplateId";
084        private static final String ACTIVE_IND_PROPERTY_NAME = "active";
085        private static final String DELEGATE_RULE_PROPERTY_NAME = "delegateRule";
086        private static final String GROUP_REVIEWER_PROPERTY_NAME = "groupReviewer";
087        private static final String GROUP_REVIEWER_NAME_PROPERTY_NAME = "groupReviewerName";
088        private static final String GROUP_REVIEWER_NAMESPACE_PROPERTY_NAME = "groupReviewerNamespace";
089        private static final String PERSON_REVIEWER_PROPERTY_NAME = "personReviewer";
090        private static final String PERSON_REVIEWER_TYPE_PROPERTY_NAME = "personReviewerType";
091        private static final String DOC_TYP_NAME_PROPERTY_NAME = "documentType.name";
092        private static final String RULE_DESC_PROPERTY_NAME = "description";
093    
094        private static final String BACK_LOCATION = "backLocation";
095        private static final String DOC_FORM_KEY = "docFormKey";
096        private static final String INVALID_WORKGROUP_ERROR = "The Group Reviewer Namespace and Name combination is not valid";
097        private static final String INVALID_PERSON_ERROR = "The Person Reviewer is not valid";
098    
099        @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    }