001    /**
002     * Copyright 2005-2011 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.RemotableAttributeField;
020    import org.kuali.rice.core.api.uif.RemotableCheckboxGroup;
021    import org.kuali.rice.core.api.uif.RemotableRadioButtonGroup;
022    import org.kuali.rice.core.api.uif.RemotableSelect;
023    import org.kuali.rice.core.api.uif.RemotableTextInput;
024    import org.kuali.rice.core.api.util.ConcreteKeyValue;
025    import org.kuali.rice.core.api.util.KeyValue;
026    import org.kuali.rice.core.api.util.RiceKeyConstants;
027    import org.kuali.rice.core.web.format.BooleanFormatter;
028    import org.kuali.rice.core.web.format.CollectionFormatter;
029    import org.kuali.rice.core.web.format.DateFormatter;
030    import org.kuali.rice.core.web.format.Formatter;
031    import org.kuali.rice.kew.api.KewApiServiceLocator;
032    import org.kuali.rice.kew.api.rule.RuleTemplate;
033    import org.kuali.rice.kew.api.rule.RuleTemplateAttribute;
034    import org.kuali.rice.kew.api.validation.ValidationResults;
035    import org.kuali.rice.kew.framework.KewFrameworkServiceLocator;
036    import org.kuali.rice.kew.framework.rule.attribute.WorkflowRuleAttributeHandlerService;
037    import org.kuali.rice.kew.lookupable.MyColumns;
038    import org.kuali.rice.kew.rule.RuleBaseValues;
039    import org.kuali.rice.kew.rule.RuleDelegationBo;
040    import org.kuali.rice.kew.rule.service.RuleDelegationService;
041    import org.kuali.rice.kew.rule.service.RuleTemplateService;
042    import org.kuali.rice.kew.service.KEWServiceLocator;
043    import org.kuali.rice.kew.api.KewApiConstants;
044    import org.kuali.rice.kim.api.KimConstants;
045    import org.kuali.rice.kim.api.group.Group;
046    import org.kuali.rice.kim.api.group.GroupService;
047    import org.kuali.rice.kim.api.identity.Person;
048    import org.kuali.rice.kim.api.services.KimApiServiceLocator;
049    import org.kuali.rice.kns.document.authorization.BusinessObjectRestrictions;
050    import org.kuali.rice.kns.lookup.HtmlData;
051    import org.kuali.rice.kns.lookup.KualiLookupableHelperServiceImpl;
052    import org.kuali.rice.kns.util.FieldUtils;
053    import org.kuali.rice.kns.web.comparator.CellComparatorHelper;
054    import org.kuali.rice.kns.web.struts.form.LookupForm;
055    import org.kuali.rice.kns.web.ui.Column;
056    import org.kuali.rice.kns.web.ui.Field;
057    import org.kuali.rice.kns.web.ui.ResultRow;
058    import org.kuali.rice.kns.web.ui.Row;
059    import org.kuali.rice.krad.bo.BusinessObject;
060    import org.kuali.rice.krad.bo.PersistableBusinessObject;
061    import org.kuali.rice.krad.exception.ValidationException;
062    import org.kuali.rice.krad.util.GlobalVariables;
063    import org.kuali.rice.krad.util.KRADConstants;
064    import org.kuali.rice.krad.util.ObjectUtils;
065    
066    import java.sql.Date;
067    import java.util.ArrayList;
068    import java.util.Collection;
069    import java.util.HashMap;
070    import java.util.Iterator;
071    import java.util.List;
072    import java.util.Map;
073    
074    /**
075     * This is a description of what this class does - jjhanso don't forget to fill this in.
076     *
077     * @author Kuali Rice Team (rice.collab@kuali.org)
078     *
079     */
080    public class RuleDelegationLookupableHelperServiceImpl extends KualiLookupableHelperServiceImpl {
081        private List<Row> rows = new ArrayList<Row>();
082        //private List<Column> columns = establishColumns();
083        //private Long previousRuleTemplateId;
084        private static final String PARENT_RESPONSIBILITY_ID_PROPERTY_NAME = "responsibilityId";
085        private static final String PARENT_RULE_ID_PROPERTY_NAME = "ruleResponsibility.ruleBaseValues.ruleBaseValuesId";
086        private static final String RULE_TEMPLATE_PROPERTY_NAME = "delegationRuleBaseValues.ruleTemplate.name";
087        private static final String RULE_ID_PROPERTY_NAME = "delegationRuleBaseValues.ruleBaseValuesId";
088        private static final String ACTIVE_IND_PROPERTY_NAME = "delegationRuleBaseValues.active";
089        private static final String DELEGATION_PROPERTY_NAME = "delegationType";
090        private static final String GROUP_REVIEWER_PROPERTY_NAME = "delegationRuleBaseValues.groupReviewer";
091        private static final String GROUP_REVIEWER_NAME_PROPERTY_NAME = "delegationRuleBaseValues.groupReviewerName";
092        private static final String GROUP_REVIEWER_NAMESPACE_PROPERTY_NAME = "delegationRuleBaseValues.groupReviewerNamespace";
093        private static final String PERSON_REVIEWER_PROPERTY_NAME = "delegationRuleBaseValues.personReviewer";
094        private static final String PERSON_REVIEWER_TYPE_PROPERTY_NAME = "delegationRuleBaseValues.personReviewerType";
095        private static final String DOC_TYP_NAME_PROPERTY_NAME = "delegationRuleBaseValues.documentType.name";
096        private static final String RULE_DESC_PROPERTY_NAME = "delegationRuleBaseValues.description";
097    
098        private static final String BACK_LOCATION = "backLocation";
099        private static final String DOC_FORM_KEY = "docFormKey";
100        private static final String INVALID_WORKGROUP_ERROR = "The Group Reviewer Namespace and Name combination is not valid";
101        private static final String INVALID_PERSON_ERROR = "The Person Reviewer is not valid";
102    
103        @Override
104            public List<Row> getRows() {
105            List<Row> superRows = super.getRows();
106            List<Row> returnRows = new ArrayList<Row>();
107            returnRows.addAll(superRows);
108            returnRows.addAll(rows);
109            return returnRows;
110        }
111    
112        @Override
113        public boolean checkForAdditionalFields(Map fieldValues) {
114            String ruleTemplateNameParam = (String) fieldValues.get(RULE_TEMPLATE_PROPERTY_NAME);
115    
116            if (StringUtils.isNotBlank(ruleTemplateNameParam)) {
117                rows = new ArrayList<Row>();
118                RuleTemplate ruleTemplate = KewApiServiceLocator.getRuleService().getRuleTemplateByName(ruleTemplateNameParam);
119    
120                for (RuleTemplateAttribute ruleTemplateAttribute : ruleTemplate.getActiveRuleTemplateAttributes()) {
121                    List<RemotableAttributeField> attributeFields = null;
122                    WorkflowRuleAttributeHandlerService wrahs = KewFrameworkServiceLocator
123                            .getWorkflowRuleAttributeHandlerService();
124                    String attributeName = ruleTemplateAttribute.getRuleAttribute().getName();
125                    attributeFields = wrahs.getSearchRows(attributeName);
126    
127                    List<Row> searchRows = FieldUtils.convertRemotableAttributeFields(attributeFields);
128                    rows.addAll(searchRows);
129                }
130                return true;
131            }
132            rows.clear();
133            return false;
134        }
135    
136        @Override
137        public List<? extends BusinessObject> getSearchResults(Map<String, String> fieldValues) {
138            List errors = new ArrayList();
139    
140            String parentRuleBaseValueId = fieldValues.get(PARENT_RULE_ID_PROPERTY_NAME);
141            String parentResponsibilityId = fieldValues.get(PARENT_RESPONSIBILITY_ID_PROPERTY_NAME);
142            String docTypeNameParam = fieldValues.get(DOC_TYP_NAME_PROPERTY_NAME);
143            String ruleTemplateIdParam = null;//(String) fieldValues.get(RULE_TEMPLATE_ID_PROPERTY_NAME);
144            String ruleTemplateNameParam = fieldValues.get(RULE_TEMPLATE_PROPERTY_NAME);
145            String groupIdParam = fieldValues.get(GROUP_REVIEWER_PROPERTY_NAME);
146            String groupNameParam = fieldValues.get(GROUP_REVIEWER_NAME_PROPERTY_NAME);
147            String groupNamespaceParam = fieldValues.get(GROUP_REVIEWER_NAMESPACE_PROPERTY_NAME);
148            String networkIdParam = fieldValues.get(PERSON_REVIEWER_PROPERTY_NAME);
149            String userDirectiveParam = fieldValues.get(PERSON_REVIEWER_TYPE_PROPERTY_NAME);
150            String activeParam = fieldValues.get(ACTIVE_IND_PROPERTY_NAME);
151            String delegationParam = fieldValues.get(DELEGATION_PROPERTY_NAME);
152            String ruleIdParam = fieldValues.get(RULE_ID_PROPERTY_NAME);
153            fieldValues.get(KewApiConstants.DELEGATION_WIZARD);
154            String ruleDescription = fieldValues.get(RULE_DESC_PROPERTY_NAME);
155    
156            String docTypeSearchName = null;
157            String workflowId = null;
158            String workgroupId = null;
159            String ruleTemplateId = null;
160            Boolean isActive = null;
161            String ruleId = null;
162    
163            if (ruleIdParam != null && !"".equals(ruleIdParam.trim())) {
164                try {
165                    ruleId = ruleIdParam.trim();
166                } catch (NumberFormatException e) {
167                    // TODO: KULRICE-5201 - verify that this is a reasonable initialization given that ruleId is no longer a Long
168                    ruleId = "-1";
169                }
170            }
171    
172            if (!activeParam.equals("")) {
173                if (activeParam.equals("Y")) {
174                    isActive = Boolean.TRUE;
175                } else {
176                    isActive = Boolean.FALSE;
177                }
178            }
179    
180            if (docTypeNameParam != null && !"".equals(docTypeNameParam.trim())) {
181                docTypeSearchName = docTypeNameParam.replace('*', '%');
182                docTypeSearchName = "%" + docTypeSearchName.trim() + "%";
183            }
184    
185            if (!StringUtils.isEmpty(networkIdParam)) {
186                    Person person = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(networkIdParam);
187                    if (person != null) {
188                            workflowId = person.getPrincipalId();
189                    }
190            }
191    
192            if (!StringUtils.isEmpty(groupIdParam) || !StringUtils.isEmpty(groupNameParam)) {
193                Group group = null;
194                if (groupIdParam != null && !"".equals(groupIdParam)) {
195                    group = getGroupService().getGroup(groupIdParam.trim());
196                } else {
197                    if (groupNamespaceParam == null) {
198                        groupNamespaceParam = KimConstants.KIM_GROUP_DEFAULT_NAMESPACE_CODE;
199                    }
200                    group = getGroupService().getGroupByNameAndNamespaceCode(groupNamespaceParam, groupNameParam.trim());
201                    if (group == null) {
202                        GlobalVariables.getMessageMap().putError(GROUP_REVIEWER_NAMESPACE_PROPERTY_NAME, RiceKeyConstants.ERROR_CUSTOM, INVALID_WORKGROUP_ERROR);
203                    } else {
204                        workgroupId = group.getId();
205                    }
206                }
207            }
208    
209            Map<String, String> attributes = null;
210            MyColumns myColumns = new MyColumns();
211            if (StringUtils.isNotBlank(ruleTemplateNameParam) || StringUtils.isNotBlank(ruleTemplateIdParam) && !"null".equals(ruleTemplateIdParam)) {
212                RuleTemplate ruleTemplate = null;
213                if (StringUtils.isNotBlank(ruleTemplateIdParam)) {
214                    ruleTemplate = KewApiServiceLocator.getRuleService().getRuleTemplate(ruleTemplateIdParam);
215                } else {
216                    ruleTemplate = KewApiServiceLocator.getRuleService().getRuleTemplateByName(ruleTemplateNameParam.trim());
217                    ruleTemplateId = ruleTemplate.getId();
218                }
219    
220                attributes = new HashMap<String, String>();
221                for (RuleTemplateAttribute ruleTemplateAttribute : ruleTemplate.getActiveRuleTemplateAttributes()) {
222                    /*WorkflowRuleAttribute attribute = (WorkflowRuleAttribute)GlobalResourceLoader.getObject(new ObjectDefinition(ruleTemplateAttribute.getRuleAttribute().getResourceDescriptor(), ruleTemplateAttribute.getRuleAttribute().getApplicationId()));//SpringServiceLocator.getExtensionService().getWorkflowAttribute(ruleTemplateAttribute.getRuleAttribute().getClassName());
223                    RuleAttribute ruleAttribute = ruleTemplateAttribute.getRuleAttribute();
224                    ExtensionDefinition extensionDefinition = RuleAttribute.to(ruleAttribute);
225                    if (ruleAttribute.getType().equals(KewApiConstants.RULE_XML_ATTRIBUTE_TYPE)) {
226                        ((GenericXMLRuleAttribute) attribute).setExtensionDefinition(extensionDefinition);
227                    }
228                    attribute.setRequired(false);*/
229                    List<RemotableAttributeField> searchRows = null;
230                    String curExtId = "0";//debugging for EN-1682
231    
232                    String attributeName = ruleTemplateAttribute.getRuleAttribute().getName();
233                    WorkflowRuleAttributeHandlerService wrahs = KewFrameworkServiceLocator.getWorkflowRuleAttributeHandlerService();
234                    ValidationResults validationResults = wrahs.validateRuleData(attributeName, fieldValues);
235                    for (Map.Entry<String, String> entry : validationResults.getErrors().entrySet()) {
236                        GlobalVariables.getMessageMap().putError(entry.getValue(), RiceKeyConstants.ERROR_CUSTOM, entry.getKey());
237                        }
238    
239                    //Validate extension data
240                    Map<String, String> curExts = ruleTemplateAttribute.getRuleExtensionMap();
241                    ValidationResults extensionValidationResults = wrahs.validateRuleData(attributeName, curExts);
242                    if (!extensionValidationResults.getErrors().isEmpty()) {
243                        for (Map.Entry<String, String> entry : extensionValidationResults.getErrors().entrySet()) {
244                            LOG.warn("Exception caught attempting to validate attribute data for extension id:" + entry.getKey() + ". Reason: " + entry.getValue());
245                        }
246                    }
247    
248                    searchRows = wrahs.getSearchRows(attributeName);
249    
250                    for (RemotableAttributeField field : searchRows) {
251                        if (fieldValues.get(field.getName()) != null) {
252                            String attributeParam = fieldValues.get(field.getName());
253                            if (StringUtils.isNotBlank(attributeParam)) {
254                                attributes.put(field.getName(), attributeParam.trim());
255                                    }
256                                }
257                        if (field.getControl() instanceof RemotableTextInput || field.getControl() instanceof RemotableSelect
258                                || field.getControl() instanceof RemotableCheckboxGroup
259                                || field.getControl() instanceof RemotableRadioButtonGroup) {
260                            myColumns.getColumns().add(new ConcreteKeyValue(field.getName(), ruleTemplateAttribute.getId()));
261                        }
262                    }
263                }
264            }
265    
266            if (!StringUtils.isEmpty(ruleDescription)) {
267                ruleDescription = ruleDescription.replace('*', '%');
268                ruleDescription = "%" + ruleDescription.trim() + "%";
269            }
270    
271            if (!GlobalVariables.getMessageMap().hasNoErrors()) {
272                throw new ValidationException("errors in search criteria");
273            }
274    
275            // TODO: replace this with new API find method ??
276            Iterator<RuleDelegationBo> rules = getRuleDelegationService().search(parentRuleBaseValueId, parentResponsibilityId, docTypeSearchName, ruleId, ruleTemplateId, ruleDescription, workgroupId, workflowId, delegationParam, isActive, attributes, userDirectiveParam).iterator();
277            List<RuleDelegationBo> displayList = new ArrayList<RuleDelegationBo>();
278    
279            while (rules.hasNext()) {
280                RuleDelegationBo ruleDelegation = rules.next();
281                RuleBaseValues record = ruleDelegation.getDelegationRule();
282    
283                if (org.apache.commons.lang.StringUtils.isEmpty(record.getDescription())) {
284                    record.setDescription(KewApiConstants.HTML_NON_BREAKING_SPACE);
285                }
286    
287                if (ruleTemplateNameParam != null && !ruleTemplateNameParam.trim().equals("") || ruleTemplateIdParam != null && !"".equals(ruleTemplateIdParam) && !"null".equals(ruleTemplateIdParam)) {
288                    MyColumns myNewColumns = new MyColumns();
289                    for (Object element : myColumns.getColumns()) {
290                        KeyValue pair = (KeyValue) element;
291                        final KeyValue newPair;
292                        if (record.getRuleExtensionValue(pair.getKey(), pair.getKey().toString()) != null) {
293                            newPair = new ConcreteKeyValue(pair.getKey(), record.getRuleExtensionValue(pair.getValue(), pair.getKey().toString()).getValue());
294                        } else {
295                            newPair = new ConcreteKeyValue(pair.getKey(), KewApiConstants.HTML_NON_BREAKING_SPACE);
296                        }
297                        myNewColumns.getColumns().add(newPair);
298                        record.getFieldValues().put(newPair.getKey(), newPair.getValue());
299                    }
300                    record.setMyColumns(myNewColumns);
301                }
302    
303                StringBuffer returnUrl = new StringBuffer("<a href=\"");
304                returnUrl.append(fieldValues.get(BACK_LOCATION)).append("?methodToCall=refresh&docFormKey=").append(fieldValues.get(DOC_FORM_KEY)).append("&");
305    
306                returnUrl.append(RULE_ID_PROPERTY_NAME);
307                returnUrl.append("=").append(record.getId()).append("\">return value</a>");
308                record.setReturnUrl(returnUrl.toString());
309    
310                String destinationUrl = "<a href=\"Rule.do?methodToCall=report&currentRuleId=" + record.getId() + "\">report</a>";
311    
312                record.setDestinationUrl(destinationUrl);
313    
314                displayList.add(ruleDelegation);
315            }
316            return displayList;
317    
318        }
319    
320    
321    
322        private GroupService getGroupService() {
323           return KimApiServiceLocator.getGroupService();
324        }
325    
326        private RuleTemplateService getRuleTemplateService() {
327            return (RuleTemplateService) KEWServiceLocator.getService(KEWServiceLocator.RULE_TEMPLATE_SERVICE);
328        }
329        private RuleDelegationService getRuleDelegationService() {
330            return (RuleDelegationService) KEWServiceLocator.getService(KEWServiceLocator.RULE_DELEGATION_SERVICE);
331        }
332    
333        @Override
334        public void validateSearchParameters(Map fieldValues) {
335            super.validateSearchParameters(fieldValues);
336    
337            // make sure that if we have either groupName or Namespace, that both are filled in
338            String groupName = (String)fieldValues.get(GROUP_REVIEWER_NAME_PROPERTY_NAME);
339            String groupNamespace = (String)fieldValues.get(GROUP_REVIEWER_NAMESPACE_PROPERTY_NAME);
340            String principalName = (String)fieldValues.get(PERSON_REVIEWER_PROPERTY_NAME);
341    
342            if (StringUtils.isEmpty(groupName) && !StringUtils.isEmpty(groupNamespace)) {
343                String attributeLabel = getDataDictionaryService().getAttributeLabel(getBusinessObjectClass(), GROUP_REVIEWER_NAME_PROPERTY_NAME);
344                GlobalVariables.getMessageMap().putError(GROUP_REVIEWER_NAME_PROPERTY_NAME, RiceKeyConstants.ERROR_REQUIRED, attributeLabel);
345            }
346    
347            if  (!StringUtils.isEmpty(groupName) && StringUtils.isEmpty(groupNamespace)) {
348                String attributeLabel = getDataDictionaryService().getAttributeLabel(getBusinessObjectClass(), GROUP_REVIEWER_NAMESPACE_PROPERTY_NAME);
349                GlobalVariables.getMessageMap().putError(GROUP_REVIEWER_NAMESPACE_PROPERTY_NAME, RiceKeyConstants.ERROR_REQUIRED, attributeLabel);
350            }
351    
352            if  (!StringUtils.isEmpty(groupName) && !StringUtils.isEmpty(groupNamespace)) {
353                Group group = KimApiServiceLocator.getGroupService().getGroupByNameAndNamespaceCode(groupNamespace,
354                        groupName);
355                if (group == null) {
356                    GlobalVariables.getMessageMap().putError(GROUP_REVIEWER_NAME_PROPERTY_NAME, RiceKeyConstants.ERROR_CUSTOM, INVALID_WORKGROUP_ERROR);
357                }
358            }
359    
360            if  (!StringUtils.isEmpty(principalName)) {
361                Person person = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(principalName);
362                if (person == null) {
363                    GlobalVariables.getMessageMap().putError(PERSON_REVIEWER_PROPERTY_NAME, RiceKeyConstants.ERROR_CUSTOM, INVALID_PERSON_ERROR);
364                }
365            }
366            if (!GlobalVariables.getMessageMap().hasNoErrors()) {
367                throw new ValidationException("errors in search criteria");
368            }
369        }
370    
371        @Override
372        public Collection performLookup(LookupForm lookupForm,
373                Collection resultTable, boolean bounded) {
374            // TODO jjhanso - THIS METHOD NEEDS JAVADOCS
375            //return super.performLookup(lookupForm, resultTable, bounded);
376            setBackLocation((String) lookupForm.getFieldsForLookup().get(KRADConstants.BACK_LOCATION));
377            setDocFormKey((String) lookupForm.getFieldsForLookup().get(KRADConstants.DOC_FORM_KEY));
378            Collection displayList;
379    
380            // call search method to get results
381            if (bounded) {
382                displayList = getSearchResults(lookupForm.getFieldsForLookup());
383            }
384            else {
385                displayList = getSearchResultsUnbounded(lookupForm.getFieldsForLookup());
386            }
387    
388            HashMap<String,Class> propertyTypes = new HashMap<String, Class>();
389    
390            boolean hasReturnableRow = false;
391    
392            List returnKeys = getReturnKeys();
393            List pkNames = getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(getBusinessObjectClass());
394            Person user = GlobalVariables.getUserSession().getPerson();
395    
396            // iterate through result list and wrap rows with return url and action urls
397            for (Iterator iter = displayList.iterator(); iter.hasNext();) {
398                BusinessObject element = (BusinessObject) iter.next();
399                if(element instanceof PersistableBusinessObject){
400                    lookupForm.setLookupObjectId(((PersistableBusinessObject)element).getObjectId());
401                }
402    
403                BusinessObjectRestrictions businessObjectRestrictions = getBusinessObjectAuthorizationService().getLookupResultRestrictions(element, user);
404    
405                HtmlData returnUrl = getReturnUrl(element, lookupForm, returnKeys, businessObjectRestrictions);
406    
407                String actionUrls = getActionUrls(element, pkNames, businessObjectRestrictions);
408                //Fix for JIRA - KFSMI-2417
409                if("".equals(actionUrls)){
410                    actionUrls = ACTION_URLS_EMPTY;
411                }
412    
413                List<Column> columns = getColumns();
414                for (Object element2 : columns) {
415    
416                    Column col = (Column) element2;
417                    String curPropName = col.getPropertyName();
418                    Formatter formatter = col.getFormatter();
419    
420                    // pick off result column from result list, do formatting
421                    String propValue = KRADConstants.EMPTY_STRING;
422                    Object prop = null;
423                    boolean skipPropTypeCheck = false;
424                    //try to get value elsewhere
425                    if (element instanceof RuleDelegationBo) {
426                        prop = ((RuleDelegationBo)element).getDelegationRule().getFieldValues().get(curPropName);
427                        skipPropTypeCheck = true;
428                    }
429                    if (prop == null) {
430                        prop = ObjectUtils.getPropertyValue(element, curPropName);
431                    }
432    
433                    // set comparator and formatter based on property type
434                    Class propClass = propertyTypes.get(curPropName);
435                    if ( propClass == null && !skipPropTypeCheck) {
436                        try {
437                            propClass = ObjectUtils.getPropertyType( element, curPropName, getPersistenceStructureService() );
438                            propertyTypes.put( curPropName, propClass );
439                        } catch (Exception e) {
440                            throw new RuntimeException("Cannot access PropertyType for property " + "'" + curPropName + "' " + " on an instance of '" + element.getClass().getName() + "'.", e);
441                        }
442                    }
443    
444                    // formatters
445                    if (prop != null) {
446                        // for Booleans, always use BooleanFormatter
447                        if (prop instanceof Boolean) {
448                            formatter = new BooleanFormatter();
449                        }
450    
451                        // for Dates, always use DateFormatter
452                        if (prop instanceof Date) {
453                            formatter = new DateFormatter();
454                        }
455    
456                        // for collection, use the list formatter if a formatter hasn't been defined yet
457                        if (prop instanceof Collection && formatter == null) {
458                        formatter = new CollectionFormatter();
459                        }
460    
461                        if (formatter != null) {
462                            propValue = (String) formatter.format(prop);
463                        }
464                        else {
465                            propValue = prop.toString();
466                        }
467                    }
468    
469                    // comparator
470                    col.setComparator(CellComparatorHelper.getAppropriateComparatorForPropertyClass(propClass));
471                    col.setValueComparator(CellComparatorHelper.getAppropriateValueComparatorForPropertyClass(propClass));
472    
473                    propValue = maskValueIfNecessary(element.getClass(), curPropName, propValue, businessObjectRestrictions);
474    
475                    col.setPropertyValue(propValue);
476    
477                    if (StringUtils.isNotBlank(propValue)) {
478                        col.setColumnAnchor(getInquiryUrl(element, curPropName));
479    
480                    }
481                }
482    
483                ResultRow row = new ResultRow(columns, returnUrl.constructCompleteHtmlTag(), actionUrls);
484                row.setRowId(returnUrl.getName());
485                row.setReturnUrlHtmlData(returnUrl);
486                // because of concerns of the BO being cached in session on the ResultRow,
487                // let's only attach it when needed (currently in the case of export)
488                if (getBusinessObjectDictionaryService().isExportable(getBusinessObjectClass())) {
489                    row.setBusinessObject(element);
490                }
491                if(element instanceof PersistableBusinessObject){
492                    row.setObjectId((((PersistableBusinessObject)element).getObjectId()));
493                }
494    
495    
496                boolean rowReturnable = isResultReturnable(element);
497                row.setRowReturnable(rowReturnable);
498                if (rowReturnable) {
499                    hasReturnableRow = true;
500                }
501                resultTable.add(row);
502            }
503    
504            lookupForm.setHasReturnableRow(hasReturnableRow);
505    
506            return displayList;
507        }
508    
509        @Override
510        public List<Column> getColumns() {
511            List<Column> columns = super.getColumns();
512            for (Row row : rows) {
513                for (Field field : row.getFields()) {
514                    Column newColumn = new Column();
515                    newColumn.setColumnTitle(field.getFieldLabel());
516                    newColumn.setMaxLength(field.getMaxLength());
517                    newColumn.setPropertyName(field.getPropertyName());
518                    columns.add(newColumn);
519                }
520            }
521            return columns;
522        }
523    
524        @Override
525        public List<HtmlData> getCustomActionUrls(BusinessObject businessObject,
526                List pkNames) {
527            RuleDelegationBo ruleDelegation = (RuleDelegationBo)businessObject;
528            List<HtmlData> htmlDataList = new ArrayList<HtmlData>();
529            if (StringUtils.isNotBlank(ruleDelegation.getDelegationRule().getRuleTemplateName()) && StringUtils.isNotBlank(getMaintenanceDocumentTypeName())) {
530                    if (allowsMaintenanceEditAction(businessObject)) {
531                            htmlDataList.add(getUrlData(businessObject, KRADConstants.MAINTENANCE_EDIT_METHOD_TO_CALL, pkNames));
532                    }
533                if (allowsMaintenanceNewOrCopyAction()) {
534                    htmlDataList.add(getUrlData(businessObject, KRADConstants.MAINTENANCE_COPY_METHOD_TO_CALL, pkNames));
535                }
536            }
537                
538            return htmlDataList;
539        }
540    
541    
542    
543    }