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