View Javadoc
1   /*
2    * Copyright 2008 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.ole.sys.document.authorization;
17  
18  import java.text.MessageFormat;
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import org.apache.commons.lang.StringUtils;
27  import org.kuali.ole.sys.OLEConstants;
28  import org.kuali.ole.sys.OLEKeyConstants;
29  import org.kuali.ole.sys.businessobject.AccountingLine;
30  import org.kuali.ole.sys.businessobject.FinancialSystemDocumentHeader;
31  import org.kuali.ole.sys.context.SpringContext;
32  import org.kuali.ole.sys.document.AccountingDocument;
33  import org.kuali.ole.sys.document.Correctable;
34  import org.kuali.ole.sys.document.web.AccountingLineRenderingContext;
35  import org.kuali.ole.sys.document.web.AccountingLineViewAction;
36  import org.kuali.ole.sys.document.web.AccountingLineViewField;
37  import org.kuali.ole.sys.identity.OleKimAttributes;
38  import org.kuali.rice.core.api.config.property.ConfigurationService;
39  import org.kuali.rice.kew.api.WorkflowDocument;
40  import org.kuali.rice.kim.api.KimConstants;
41  import org.kuali.rice.kim.api.identity.Person;
42  import org.kuali.rice.kns.document.authorization.DocumentAuthorizer;
43  import org.kuali.rice.kns.service.DocumentHelperService;
44  import org.kuali.rice.krad.util.GlobalVariables;
45  import org.kuali.rice.krad.util.KRADConstants;
46  import org.kuali.rice.krad.util.ObjectUtils;
47  
48  /**
49   * The default implementation of AccountingLineAuthorizer
50   */
51  public class AccountingLineAuthorizerBase implements AccountingLineAuthorizer {
52      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AccountingLineAuthorizerBase.class);
53  
54      private static ConfigurationService kualiConfigurationService;
55      protected static String riceImagePath;
56      protected static String kfsImagePath;
57  
58      /**
59       * Returns the basic actions - add for new lines, delete and balance inquiry for existing lines
60       * 
61       * @see org.kuali.ole.sys.document.authorization.AccountingLineAuthorizer#getActions(org.kuali.ole.sys.document.AccountingDocument,
62       *      org.kuali.ole.sys.businessobject.AccountingLine, java.lang.String, java.lang.Integer, org.kuali.rice.kim.api.identity.Person,
63       *      java.lang.String)
64       */
65      public List<AccountingLineViewAction> getActions(AccountingDocument accountingDocument, AccountingLineRenderingContext accountingLineRenderingContext, String accountingLinePropertyName, Integer accountingLineIndex, Person currentUser, String groupTitle) {
66          List<AccountingLineViewAction> actions = new ArrayList<AccountingLineViewAction>();
67  
68          if (accountingLineRenderingContext.isEditableLine() || isMessageMapContainingErrorsOnLine(accountingLinePropertyName)) {
69              Map<String, AccountingLineViewAction> actionMap = this.getActionMap(accountingLineRenderingContext, accountingLinePropertyName, accountingLineIndex, groupTitle);
70              actions.addAll(actionMap.values());
71          }
72  
73          return actions;
74      }
75      
76      /**
77       * Determines if the error map contains any errors which exist on the currently rendered accounting line
78       * @param accountingLinePropertyName the property name of the accounting line
79       * @return true if there are errors on the line, false otherwise
80       */
81      protected boolean isMessageMapContainingErrorsOnLine(String accountingLinePropertyName) {
82          for (Object errorKeyAsObject : GlobalVariables.getMessageMap().getPropertiesWithErrors()) {
83              if (((String)errorKeyAsObject).startsWith(accountingLinePropertyName)) return true;
84          }
85          return false;
86      }
87  
88      /**
89       * Returns a new empty HashSet
90       * 
91       * @see org.kuali.ole.sys.document.authorization.AccountingLineAuthorizer#getUnviewableBlocks(org.kuali.ole.sys.document.AccountingDocument,
92       *      org.kuali.ole.sys.businessobject.AccountingLine, java.lang.String, boolean)
93       */
94      public Set<String> getUnviewableBlocks(AccountingDocument accountingDocument, AccountingLine accountingLine, boolean newLine, Person currentUser) {
95          return new HashSet<String>();
96      }
97  
98      /**
99       * @see org.kuali.ole.sys.document.authorization.AccountingLineAuthorizer#renderNewLine(org.kuali.ole.sys.document.AccountingDocument,
100      *      java.lang.String)
101      */
102     public boolean renderNewLine(AccountingDocument accountingDocument, String accountingGroupProperty) {
103         return (accountingDocument.getDocumentHeader().getWorkflowDocument().isInitiated() || accountingDocument.getDocumentHeader().getWorkflowDocument().isSaved());
104     }
105 
106     /**
107      * @see org.kuali.ole.sys.document.authorization.AccountingLineAuthorizer#isGroupEditable(org.kuali.ole.sys.document.AccountingDocument,
108      *      java.lang.String, org.kuali.rice.kim.api.identity.Person)
109      */
110     public boolean isGroupEditable(AccountingDocument accountingDocument, List<? extends AccountingLineRenderingContext> accountingLineRenderingContexts, Person currentUser) {
111         WorkflowDocument workflowDocument = accountingDocument.getDocumentHeader().getWorkflowDocument();
112         if (workflowDocument.isInitiated() || workflowDocument.isSaved()) {
113             return StringUtils.equalsIgnoreCase( workflowDocument.getInitiatorPrincipalId(), currentUser.getPrincipalId() );
114         }
115         
116         for (AccountingLineRenderingContext renderingContext : accountingLineRenderingContexts) {
117             if (renderingContext.isEditableLine()) return true;
118         }
119 
120         return false;
121     }
122 
123     /**
124      * collection the actions that are allowed for the given accounting line
125      * 
126      * @param accountingLine the given accounting line
127      * @param accountingLinePropertyName the property name of the given account line, typically, the form name
128      * @param accountingLineIndex the index of the given accounting line in its accounting line group
129      * @param groupTitle the title of the accounting line group
130      * @return the actions that are allowed for the given accounting line
131      */
132     protected Map<String, AccountingLineViewAction> getActionMap(AccountingLineRenderingContext accountingLineRenderingContext, String accountingLinePropertyName, Integer accountingLineIndex, String groupTitle) {
133         Map<String, AccountingLineViewAction> actionMap = new HashMap<String, AccountingLineViewAction>();
134 
135         if (accountingLineIndex == null || accountingLineIndex < 0) {
136             AccountingLineViewAction addAction = this.getAddAction(accountingLineRenderingContext.getAccountingLine(), accountingLinePropertyName, groupTitle);
137             actionMap.put(OLEConstants.INSERT_METHOD, addAction);
138         }
139         else {
140             if (accountingLineRenderingContext.allowDelete()) {
141                 AccountingLineViewAction deleteAction = this.getDeleteAction(accountingLineRenderingContext.getAccountingLine(), accountingLinePropertyName, accountingLineIndex, groupTitle);
142                 actionMap.put(KRADConstants.DELETE_METHOD, deleteAction);
143             }
144 
145             AccountingLineViewAction balanceInquiryAction = this.getBalanceInquiryAction(accountingLineRenderingContext.getAccountingLine(), accountingLinePropertyName, accountingLineIndex, groupTitle);
146             actionMap.put(OLEConstants.PERFORMANCE_BALANCE_INQUIRY_FOR_METHOD, balanceInquiryAction);
147         }
148 
149         return actionMap;
150     }
151 
152     /**
153      * determine whether the current user has permission to edit the given field in the given accounting line
154      * 
155      * @param accountingDocument the given accounting document
156      * @param accountingLine the given accounting line in the document
157      * @param fieldName the name of a field in the given accounting line
158      * @param editableLine whether the parent line of this field is editable
159      * @param editablePage whether the parent page of this field is editable
160      * @param currentUser the current user
161      * @return true if the the current user has permission to edit the given field in the given accounting line; otherwsie, false
162      */
163     public final boolean hasEditPermissionOnField(AccountingDocument accountingDocument, AccountingLine accountingLine, String accountingLineCollectionProperty, String fieldName, boolean editableLine, boolean editablePage, Person currentUser) {
164         if (accountingDocument.getDocumentHeader() != null && accountingDocument.getDocumentHeader().getWorkflowDocument() != null && accountingDocument.getDocumentHeader().getWorkflowDocument().getDocumentTypeName().equalsIgnoreCase(OLEConstants.FinancialDocumentTypeCodes.PURCHASE_ORDER_AMENDMENT) && accountingDocument.getDocumentHeader().getWorkflowDocument().isInitiated()) {
165             return true;
166         }
167         if (!determineEditPermissionOnField(accountingDocument, accountingLine, accountingLineCollectionProperty, fieldName, editablePage)) {
168             return false;
169         }
170         
171         // the fields in a new line should be always editable
172         if (accountingLine.getSequenceNumber() == null) {
173             return true;
174         }
175 
176         // examine whether the given field can be editable
177         boolean hasEditPermissionOnField = editableLine || this.determineEditPermissionByFieldName(accountingDocument, accountingLine, getKimHappyPropertyNameForField(accountingLineCollectionProperty+"."+fieldName), currentUser);
178         if (hasEditPermissionOnField == false) {
179             // kim check shows field should not be editable based on contents of field - check if line error message occurred on this line
180             // if error message shows up, then the value must have changed recently so - we make it editable to allow user to correct it
181             WorkflowDocument workflowDocument = accountingDocument.getDocumentHeader().getWorkflowDocument();
182             if (workflowDocument.isEnroute() && isMessageMapContainingErrorsOnLine(accountingLineCollectionProperty)) return true;
183          }
184         return hasEditPermissionOnField;
185     }
186  
187     /**
188      * Allows the overriding of whether a field on an accounting line is editable or not
189      * @param accountingDocument the accounting document the line to test is on
190      * @param accountingLine the accounting line to test
191      * @param accountingLineCollectionProperty the property that the accounting line lives in
192      * @param fieldName the name of the field we are testing
193      * @param editableLine whether the parent line of this field is editable
194      * @param editablePage whether the parent page of this field is editable
195      * @return true if the field can be edited (subject to subsequence KIM check); false otherwise
196      */
197     public boolean determineEditPermissionOnField(AccountingDocument accountingDocument, AccountingLine accountingLine, String accountingLineCollectionProperty, String fieldName, boolean editablePage) {
198         if (!editablePage) return false; // no edits by default on non editable pages
199         
200         final FinancialSystemDocumentHeader documentHeader = (FinancialSystemDocumentHeader) accountingDocument.getDocumentHeader();
201         final WorkflowDocument workflowDocument = documentHeader.getWorkflowDocument();
202 
203         // if a document is cancelled or in error, all of its fields cannot be editable
204         if (workflowDocument.isCanceled() || ObjectUtils.isNotNull(documentHeader.getFinancialDocumentInErrorNumber())) {
205             return false;
206         }
207 
208         return true;
209     }
210 
211     /**
212      * Determine whether the current user has permission to edit the given accounting line as a whole
213      * 
214      * @param accountingDocument the given accounting document
215      * @param accountingLine the given accounting line in the document
216      * @param currentUser the current user
217      * @return true if the the current user has permission to edit the given accounting line; otherwsie, false
218      */
219     public final boolean hasEditPermissionOnAccountingLine(AccountingDocument accountingDocument, AccountingLine accountingLine, String accountingLineCollectionProperty, Person currentUser, boolean pageIsEditable) {        
220         if (determineEditPermissionOnLine(accountingDocument, accountingLine, accountingLineCollectionProperty, StringUtils.equalsIgnoreCase( accountingDocument.getDocumentHeader().getWorkflowDocument().getInitiatorPrincipalId(), currentUser.getPrincipalId() ), pageIsEditable)) {
221             
222             if (approvedForUnqualifiedEditing(accountingDocument, accountingLine, accountingLineCollectionProperty, StringUtils.equalsIgnoreCase( accountingDocument.getDocumentHeader().getWorkflowDocument().getInitiatorPrincipalId(), currentUser.getPrincipalId() ))) {
223                 return true;  // don't do the KIM check, we're good
224             }
225             
226             // examine whether the whole line can be editable via KIM check
227             final String lineFieldName = getKimHappyPropertyNameForField(accountingLineCollectionProperty);
228             return this.determineEditPermissionByFieldName(accountingDocument, accountingLine, lineFieldName, currentUser);
229         }
230         return false;
231     }
232  
233     /**
234      * A hook to decide, pre-KIM check, if there's an edit permission on the given accounting line
235      * @param accountingDocument the accounting document the line is or wants to be associated with
236      * @param accountingLine the accounting line itself
237      * @param accountingLineCollectionProperty the collection the accounting line is or would be part of
238      * @param currentUserIsDocumentInitiator is the current user the initiator of the document?
239      * @return true if the line as a whole can be edited, false otherwise
240      */
241     public boolean determineEditPermissionOnLine(AccountingDocument accountingDocument, AccountingLine accountingLine, String accountingLineCollectionProperty, boolean currentUserIsDocumentInitiator, boolean pageIsEditable) {
242         if (accountingDocument instanceof Correctable) {
243             String errorDocumentNumber = ((FinancialSystemDocumentHeader)accountingDocument.getDocumentHeader()).getFinancialDocumentInErrorNumber();
244             if (StringUtils.isNotBlank(errorDocumentNumber))
245                 return false;
246         }
247         
248         return true;
249     }
250     
251     /**
252      * Determines if the given line is editable, no matter what a KIM check would say about line editability.  In the default case,
253      * any accounting line is editable - minus KIM check - when the document is PreRoute, or if the line is a new line
254      * @param accountingDocument the accounting document the line is or wants to be associated with
255      * @param accountingLine the accounting line itself
256      * @param accountingLineCollectionProperty the collection the accounting line is or would be part of
257      * @param currentUserIsDocumentInitiator is the current user the initiator of the document?
258      * @return true if the line as a whole can be edited without the KIM check, false otherwise
259      */
260     protected boolean approvedForUnqualifiedEditing(AccountingDocument accountingDocument, AccountingLine accountingLine, String accountingLineCollectionProperty, boolean currentUserIsDocumentInitiator) {
261         // the fields in a new line should be always editable
262         if (accountingLine.getSequenceNumber() == null) {
263             return true;
264         }
265         
266         // check the initiation permission on the document if it is in the state of preroute
267         WorkflowDocument workflowDocument = accountingDocument.getDocumentHeader().getWorkflowDocument();
268         if (workflowDocument.isInitiated() || workflowDocument.isSaved()) {
269             return currentUserIsDocumentInitiator;
270         }
271         return false;
272     }
273 
274     /**
275      * determine whether the current user has permission to edit the given field in the given accounting line
276      * 
277      * @param accountingDocument the given accounting document
278      * @param accountingLine the given accounting line in the document
279      * @param fieldName the name of a field in the given accounting line
280      * @param currentUser the current user
281      * @return true if the the current user has permission to edit the given field in the given accounting line; otherwsie, false
282      */    
283     protected boolean determineEditPermissionByFieldName(AccountingDocument accountingDocument, AccountingLine accountingLine, String fieldName, Person currentUser) {        
284         final Map<String,String> roleQualifiers = this.getRoleQualifiers(accountingDocument, accountingLine);
285         final String documentTypeName = accountingDocument.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
286         final Map<String,String> permissionDetail = this.getPermissionDetails(documentTypeName, fieldName);
287 
288         return this.hasEditPermission(accountingDocument, currentUser, permissionDetail, roleQualifiers);       
289     }
290 
291     /**
292      * determine whether the current user has modification permission on an accounting line with the given qualifications. The
293      * permission template and namespace have been setup in the method.
294      * 
295      * @param currentUser the current user
296      * @param permissionDetails the given permission details
297      * @param roleQualifiers the given role qualifications
298      * @return true if the user has edit permission on an accounting line with the given qualifications; otherwise, false
299      */
300     protected boolean hasEditPermission(AccountingDocument accountingDocument, Person currentUser, Map<String,String> permissionDetails, Map<String,String> roleQualifiers) {
301         String pricipalId = currentUser.getPrincipalId();
302         DocumentAuthorizer accountingDocumentAuthorizer = this.getDocumentAuthorizer(accountingDocument);
303         
304         return accountingDocumentAuthorizer.isAuthorizedByTemplate(accountingDocument, OLEConstants.ParameterNamespaces.OLE, OLEConstants.PermissionTemplate.MODIFY_ACCOUNTING_LINES.name, pricipalId, permissionDetails, roleQualifiers);
305     }
306 
307     /**
308      * Gathers together all the information for a permission detail attribute set
309      * 
310      * @param documentTypeName the document
311      * @param fieldName the given field name
312      * @return all the information for a permission detail attribute set
313      */
314     protected Map<String,String> getPermissionDetails(String documentTypeName, String fieldName) {
315         Map<String,String> permissionDetails = new HashMap<String,String>();
316 
317         if (StringUtils.isNotBlank(documentTypeName)) {
318             permissionDetails.put(KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME, documentTypeName);
319         }
320 
321         if (StringUtils.isNotBlank(fieldName)) {
322             permissionDetails.put(KimConstants.AttributeConstants.PROPERTY_NAME, fieldName);
323         }
324 
325         return permissionDetails;
326     }
327 
328     /**
329      * Gathers together the role qualifiers for the KIM perm call
330      * 
331      * @param accountingLine the accounting line to get role qualifiers from
332      * @return the gathered Map<String,String> of role qualifiers
333      */
334     protected final Map<String,String> getRoleQualifiers(AccountingDocument accountingDocument, AccountingLine accountingLine) {
335         Map<String,String> roleQualifiers = new HashMap<String,String>();
336 
337         if (accountingLine != null) {
338             roleQualifiers.put(OleKimAttributes.CHART_OF_ACCOUNTS_CODE, accountingLine.getChartOfAccountsCode());
339             roleQualifiers.put(OleKimAttributes.ACCOUNT_NUMBER, accountingLine.getAccountNumber());
340         }
341 
342         return roleQualifiers;
343     }
344 
345     /**
346      * @param field AccountingLineViewField to find KIM-happy property name for
347      * @return a property name that KIM will like
348      */
349     protected String getKimHappyPropertyNameForField(String convertedName) {
350         convertedName = stripDocumentPrefixFromName(convertedName);
351 
352         return replaceCollectionElementsWithPlurals(convertedName);
353     }
354 
355     /**
356      * get the full property name of the given field
357      * 
358      * @param field the field to get the name from
359      * @return the full property name of the given field, typically, a combination of property prefix and simple property name
360      */
361     protected String getFieldName(AccountingLineViewField field) {
362         String propertyPrefix = field.getField().getPropertyPrefix();
363         String propertyName = field.getField().getPropertyName();
364 
365         return StringUtils.isNotBlank(propertyPrefix) ? (propertyPrefix + "." + propertyName) : propertyName;
366     }
367 
368     /**
369      * Strips "document." and everything before from the property name
370      * 
371      * @param name the property name to strip the document portion off of
372      * @return the stripped name
373      */
374     protected String stripDocumentPrefixFromName(String name) {
375         return name.replaceFirst("(.)*document\\.", StringUtils.EMPTY);
376     }
377 
378     /**
379      * Replaces references to collection elements to their respective plural names WARNING: this method is totally lame and I for
380      * one wished it didn't have to exist
381      * 
382      * @param name the property name with perhaps collection elements in
383      * @return the corrected name
384      */
385     protected String replaceCollectionElementsWithPlurals(String name) {
386         String temp = name.replaceAll("\\[\\d+\\]", "s");
387         // now - need to check if the property name ends with a double "s", which is incorrect
388         if ( temp.endsWith( "ss" ) ) {
389             temp = StringUtils.chop(temp);
390         }
391         return temp;
392     }
393 
394     /**
395      * construct the balance inquiry action for the given accounting line
396      * 
397      * @param accountingLine the given accounting line
398      * @param accountingLinePropertyName the property name of the given account line, typically, the form name
399      * @param accountingLineIndex the index of the given accounting line in its accounting line group
400      * @param groupTitle the title of the accounting line group
401      * @return the balance inquiry action for the given accounting line
402      */
403     protected AccountingLineViewAction getBalanceInquiryAction(AccountingLine accountingLine, String accountingLinePropertyName, Integer accountingLineIndex, String groupTitle) {
404         String actionMethod = this.getBalanceInquiryMethod(accountingLine, accountingLinePropertyName, accountingLineIndex);
405         String actionLabel = this.getActionLabel(OLEKeyConstants.AccountingLineViewRendering.ACCOUNTING_LINE_BALANCE_INQUIRY_ACTION_LABEL, groupTitle, accountingLineIndex + 1);
406 
407         String actionImageName = getKFSImagePath() + "tinybutton-balinquiry.gif";
408 
409         return new AccountingLineViewAction(actionMethod, actionLabel, actionImageName);
410     }
411 
412     /**
413      * construct the delete action for the given accounting line
414      * 
415      * @param accountingLine the given accounting line
416      * @param accountingLinePropertyName the property name of the given account line, typically, the form name
417      * @param accountingLineIndex the index of the given accounting line in its accounting line group
418      * @param groupTitle the title of the accounting line group
419      * @return the delete action for the given accounting line
420      */
421     protected AccountingLineViewAction getDeleteAction(AccountingLine accountingLine, String accountingLinePropertyName, Integer accountingLineIndex, String groupTitle) {
422         String actionMethod = this.getDeleteLineMethod(accountingLine, accountingLinePropertyName, accountingLineIndex);
423         String actionLabel = this.getActionLabel(OLEKeyConstants.AccountingLineViewRendering.ACCOUNTING_LINE_DELETE_ACTION_LABEL, groupTitle, accountingLineIndex + 1);
424 
425         String actionImageName = getRiceImagePath() + "tinybutton-delete1.gif";
426 
427         return new AccountingLineViewAction(actionMethod, actionLabel, actionImageName);
428     }
429 
430     /**
431      * construct the add action for the given accounting line, typically, a new accounting line
432      * 
433      * @param accountingLine the given accounting line
434      * @param accountingLinePropertyName the property name of the given account line, typically, the form name
435      * @param accountingLineIndex the index of the given accounting line in its accounting line group
436      * @param groupTitle the title of the accounting line group
437      * @return the add action for the given accounting line
438      */
439     protected AccountingLineViewAction getAddAction(AccountingLine accountingLine, String accountingLinePropertyName, String groupTitle) {
440         String actionMethod = this.getAddMethod(accountingLine, accountingLinePropertyName);
441         String actionLabel = this.getActionLabel(OLEKeyConstants.AccountingLineViewRendering.ACCOUNTING_LINE_ADD_ACTION_LABEL, groupTitle);
442 
443         String actionImageName = getRiceImagePath() + "tinybutton-add1.gif";
444 
445         return new AccountingLineViewAction(actionMethod, actionLabel, actionImageName);
446     }
447 
448     /**
449      * get a label for an action with the specified message key and values
450      * 
451      * @param messageKey the given message key that points to the label
452      * @param values the given values that would be displayed in label
453      * @return a label for an action with the specified message key and values
454      */
455     protected String getActionLabel(String messageKey, Object... values) {
456         String messageBody = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(messageKey);
457 
458         return MessageFormat.format(messageBody, values);
459     }
460 
461     /**
462      * Builds the action method name of the method that adds accounting lines for this group
463      * 
464      * @param accountingLine the accounting line an action is being checked for
465      * @param accountingLinePropertyName the property name of the accounting line
466      * @return the action method name of the method that adds accounting lines for this group
467      */
468     protected String getAddMethod(AccountingLine accountingLine, String accountingLineProperty) {
469         final String infix = getActionInfixForNewAccountingLine(accountingLine, accountingLineProperty);
470         return OLEConstants.INSERT_METHOD + infix + "Line.anchoraccounting" + infix + "Anchor";
471     }
472 
473     /**
474      * Builds the action method name of the method that deletes accounting lines for this group
475      * 
476      * @param accountingLine the accounting line an action is being checked for
477      * @param accountingLinePropertyName the property name of the accounting line
478      * @param accountingLineIndex the index of the given accounting line within the the group being rendered
479      * @return the action method name of the method that deletes accounting lines for this group
480      */
481     protected String getDeleteLineMethod(AccountingLine accountingLine, String accountingLineProperty, Integer accountingLineIndex) {
482         final String infix = getActionInfixForExtantAccountingLine(accountingLine, accountingLineProperty);
483         return KRADConstants.DELETE_METHOD + infix + "Line.line" + accountingLineIndex + ".anchoraccounting" + infix + "Anchor";
484     }
485 
486     /**
487      * Builds the action method name of the method that performs a balance inquiry on accounting lines for this group
488      * 
489      * @param accountingLine the accounting line an action is being checked for
490      * @param accountingLinePropertyName the property name of the accounting line
491      * @param accountingLineIndex the index of the given accounting line within the the group being rendered
492      * @return the action method name of the method that performs a balance inquiry on accounting lines for this group
493      */
494     protected String getBalanceInquiryMethod(AccountingLine accountingLine, String accountingLineProperty, Integer accountingLineIndex) {
495         final String infix = getActionInfixForExtantAccountingLine(accountingLine, accountingLineProperty);
496         return OLEConstants.PERFORMANCE_BALANCE_INQUIRY_FOR_METHOD + infix + "Line.line" + accountingLineIndex + ".anchoraccounting" + infix + "existingLineLineAnchor" + accountingLineIndex;
497     }
498 
499     /**
500      * Gets the "action infix" for the given accounting line, so that the action knows it is supposed to add to source vs. target
501      * 
502      * @param accountingLine the accounting line an action is being checked for
503      * @param accountingLinePropertyName the property name of the accounting line
504      * @return the name of the action infix
505      */
506     protected String getActionInfixForNewAccountingLine(AccountingLine accountingLine, String accountingLinePropertyName) {
507         if (accountingLine.isSourceAccountingLine()) {
508             return OLEConstants.SOURCE;
509         }
510 
511         if (accountingLine.isTargetAccountingLine()) {
512             return OLEConstants.TARGET;
513         }
514 
515         return OLEConstants.EMPTY_STRING;
516     }
517 
518     /**
519      * Gets the "action infix" for the given accounting line which already exists on the document, so that the action knows it is
520      * supposed to add to source vs. target
521      * 
522      * @param accountingLine the accounting line an action is being checked for
523      * @param accountingLinePropertyName the property name of the accounting line
524      * @return the name of the action infix
525      */
526     protected String getActionInfixForExtantAccountingLine(AccountingLine accountingLine, String accountingLinePropertyName) {
527         if (accountingLine.isSourceAccountingLine()) {
528             return OLEConstants.SOURCE;
529         }
530 
531         if (accountingLine.isTargetAccountingLine()) {
532             return OLEConstants.TARGET;
533         }
534 
535         return OLEConstants.EMPTY_STRING;
536     }
537 
538     /**
539      * get the document authorizer of the given accounting document
540      * 
541      * @param accountingDocument the given accounting document
542      * @return the document authorizer of the given accounting document
543      */
544     protected DocumentAuthorizer getDocumentAuthorizer(AccountingDocument accountingDocument) {
545         return SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(accountingDocument);
546     }
547     
548     /**
549      * @return the path to rice images
550      */
551     protected String getRiceImagePath() {
552         if (riceImagePath == null) {
553             riceImagePath = getConfigurationService().getPropertyValueAsString(KRADConstants.EXTERNALIZABLE_IMAGES_URL_KEY);
554         }
555         return riceImagePath;
556     }
557     
558     /**
559      * @return the path to OLE images
560      */
561     protected String getKFSImagePath() {
562         if (kfsImagePath == null) {
563             kfsImagePath = getConfigurationService().getPropertyValueAsString(KRADConstants.APPLICATION_EXTERNALIZABLE_IMAGES_URL_KEY);
564         }
565         return kfsImagePath;
566     }
567     
568     protected ConfigurationService getConfigurationService() {
569         if ( kualiConfigurationService == null ) {
570             kualiConfigurationService = SpringContext.getBean(ConfigurationService.class);
571         }
572         return kualiConfigurationService;
573     }
574 }