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 (!determineEditPermissionOnField(accountingDocument, accountingLine, accountingLineCollectionProperty, fieldName, editablePage)) {
165             return false;
166         }
167         
168         // the fields in a new line should be always editable
169         if (accountingLine.getSequenceNumber() == null) {
170             return true;
171         }
172 
173         // examine whether the given field can be editable
174         boolean hasEditPermissionOnField = editableLine || this.determineEditPermissionByFieldName(accountingDocument, accountingLine, getKimHappyPropertyNameForField(accountingLineCollectionProperty+"."+fieldName), currentUser);
175         if (hasEditPermissionOnField == false) {
176             // kim check shows field should not be editable based on contents of field - check if line error message occurred on this line
177             // if error message shows up, then the value must have changed recently so - we make it editable to allow user to correct it
178             WorkflowDocument workflowDocument = accountingDocument.getDocumentHeader().getWorkflowDocument();
179             if (workflowDocument.isEnroute() && isMessageMapContainingErrorsOnLine(accountingLineCollectionProperty)) return true;
180          }
181         return hasEditPermissionOnField;
182     }
183  
184     /**
185      * Allows the overriding of whether a field on an accounting line is editable or not
186      * @param accountingDocument the accounting document the line to test is on
187      * @param accountingLine the accounting line to test
188      * @param accountingLineCollectionProperty the property that the accounting line lives in
189      * @param fieldName the name of the field we are testing
190      * @param editableLine whether the parent line of this field is editable
191      * @param editablePage whether the parent page of this field is editable
192      * @return true if the field can be edited (subject to subsequence KIM check); false otherwise
193      */
194     public boolean determineEditPermissionOnField(AccountingDocument accountingDocument, AccountingLine accountingLine, String accountingLineCollectionProperty, String fieldName, boolean editablePage) {
195         if (!editablePage) return false; // no edits by default on non editable pages
196         
197         //final FinancialSystemDocumentHeader documentHeader = (FinancialSystemDocumentHeader) accountingDocument.getDocumentHeader();
198         final FinancialSystemDocumentHeader documentHeader = (FinancialSystemDocumentHeader) accountingDocument;
199         final WorkflowDocument workflowDocument = documentHeader.getWorkflowDocument();
200 
201         // if a document is cancelled or in error, all of its fields cannot be editable
202         if (workflowDocument.isCanceled() || ObjectUtils.isNotNull(documentHeader.getFinancialDocumentInErrorNumber())) {
203             return false;
204         }
205 
206         return true;
207     }
208 
209     /**
210      * Determine whether the current user has permission to edit the given accounting line as a whole
211      * 
212      * @param accountingDocument the given accounting document
213      * @param accountingLine the given accounting line in the document
214      * @param currentUser the current user
215      * @return true if the the current user has permission to edit the given accounting line; otherwsie, false
216      */
217     public final boolean hasEditPermissionOnAccountingLine(AccountingDocument accountingDocument, AccountingLine accountingLine, String accountingLineCollectionProperty, Person currentUser, boolean pageIsEditable) {        
218         if (determineEditPermissionOnLine(accountingDocument, accountingLine, accountingLineCollectionProperty, StringUtils.equalsIgnoreCase( accountingDocument.getDocumentHeader().getWorkflowDocument().getInitiatorPrincipalId(), currentUser.getPrincipalId() ), pageIsEditable)) {
219             
220             if (approvedForUnqualifiedEditing(accountingDocument, accountingLine, accountingLineCollectionProperty, StringUtils.equalsIgnoreCase( accountingDocument.getDocumentHeader().getWorkflowDocument().getInitiatorPrincipalId(), currentUser.getPrincipalId() ))) {
221                 return true;  // don't do the KIM check, we're good
222             }
223             
224             // examine whether the whole line can be editable via KIM check
225             final String lineFieldName = getKimHappyPropertyNameForField(accountingLineCollectionProperty);
226             return this.determineEditPermissionByFieldName(accountingDocument, accountingLine, lineFieldName, currentUser);
227         }
228         return false;
229     }
230  
231     /**
232      * A hook to decide, pre-KIM check, if there's an edit permission on the given accounting line
233      * @param accountingDocument the accounting document the line is or wants to be associated with
234      * @param accountingLine the accounting line itself
235      * @param accountingLineCollectionProperty the collection the accounting line is or would be part of
236      * @param currentUserIsDocumentInitiator is the current user the initiator of the document?
237      * @return true if the line as a whole can be edited, false otherwise
238      */
239     public boolean determineEditPermissionOnLine(AccountingDocument accountingDocument, AccountingLine accountingLine, String accountingLineCollectionProperty, boolean currentUserIsDocumentInitiator, boolean pageIsEditable) {
240         if (accountingDocument instanceof Correctable) {
241             //String errorDocumentNumber = ((FinancialSystemDocumentHeader)accountingDocument.getDocumentHeader()).getFinancialDocumentInErrorNumber();
242             String errorDocumentNumber = ((FinancialSystemDocumentHeader)accountingDocument).getFinancialDocumentInErrorNumber();
243             if (StringUtils.isNotBlank(errorDocumentNumber))
244                 return false;
245         }
246         
247         return true;
248     }
249     
250     /**
251      * Determines if the given line is editable, no matter what a KIM check would say about line editability.  In the default case,
252      * any accounting line is editable - minus KIM check - when the document is PreRoute, or if the line is a new line
253      * @param accountingDocument the accounting document the line is or wants to be associated with
254      * @param accountingLine the accounting line itself
255      * @param accountingLineCollectionProperty the collection the accounting line is or would be part of
256      * @param currentUserIsDocumentInitiator is the current user the initiator of the document?
257      * @return true if the line as a whole can be edited without the KIM check, false otherwise
258      */
259     protected boolean approvedForUnqualifiedEditing(AccountingDocument accountingDocument, AccountingLine accountingLine, String accountingLineCollectionProperty, boolean currentUserIsDocumentInitiator) {
260         // the fields in a new line should be always editable
261         if (accountingLine.getSequenceNumber() == null) {
262             return true;
263         }
264         
265         // check the initiation permission on the document if it is in the state of preroute
266         WorkflowDocument workflowDocument = accountingDocument.getDocumentHeader().getWorkflowDocument();
267         if (workflowDocument.isInitiated() || workflowDocument.isSaved()) {
268             return currentUserIsDocumentInitiator;
269         }
270         return false;
271     }
272 
273     /**
274      * determine whether the current user has permission to edit the given field in the given accounting line
275      * 
276      * @param accountingDocument the given accounting document
277      * @param accountingLine the given accounting line in the document
278      * @param fieldName the name of a field in the given accounting line
279      * @param currentUser the current user
280      * @return true if the the current user has permission to edit the given field in the given accounting line; otherwsie, false
281      */    
282     protected boolean determineEditPermissionByFieldName(AccountingDocument accountingDocument, AccountingLine accountingLine, String fieldName, Person currentUser) {        
283         final Map<String,String> roleQualifiers = this.getRoleQualifiers(accountingDocument, accountingLine);
284         final String documentTypeName = accountingDocument.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
285         final Map<String,String> permissionDetail = this.getPermissionDetails(documentTypeName, fieldName);
286 
287         return this.hasEditPermission(accountingDocument, currentUser, permissionDetail, roleQualifiers);       
288     }
289 
290     /**
291      * determine whether the current user has modification permission on an accounting line with the given qualifications. The
292      * permission template and namespace have been setup in the method.
293      * 
294      * @param currentUser the current user
295      * @param permissionDetails the given permission details
296      * @param roleQualifiers the given role qualifications
297      * @return true if the user has edit permission on an accounting line with the given qualifications; otherwise, false
298      */
299     protected boolean hasEditPermission(AccountingDocument accountingDocument, Person currentUser, Map<String,String> permissionDetails, Map<String,String> roleQualifiers) {
300         String pricipalId = currentUser.getPrincipalId();
301         DocumentAuthorizer accountingDocumentAuthorizer = this.getDocumentAuthorizer(accountingDocument);
302         
303         return accountingDocumentAuthorizer.isAuthorizedByTemplate(accountingDocument, OLEConstants.ParameterNamespaces.OLE, OLEConstants.PermissionTemplate.MODIFY_ACCOUNTING_LINES.name, pricipalId, permissionDetails, roleQualifiers);
304     }
305 
306     /**
307      * Gathers together all the information for a permission detail attribute set
308      * 
309      * @param documentTypeName the document
310      * @param fieldName the given field name
311      * @return all the information for a permission detail attribute set
312      */
313     protected Map<String,String> getPermissionDetails(String documentTypeName, String fieldName) {
314         Map<String,String> permissionDetails = new HashMap<String,String>();
315 
316         if (StringUtils.isNotBlank(documentTypeName)) {
317             permissionDetails.put(KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME, documentTypeName);
318         }
319 
320         if (StringUtils.isNotBlank(fieldName)) {
321             permissionDetails.put(KimConstants.AttributeConstants.PROPERTY_NAME, fieldName);
322         }
323 
324         return permissionDetails;
325     }
326 
327     /**
328      * Gathers together the role qualifiers for the KIM perm call
329      * 
330      * @param accountingLine the accounting line to get role qualifiers from
331      * @return the gathered Map<String,String> of role qualifiers
332      */
333     protected final Map<String,String> getRoleQualifiers(AccountingDocument accountingDocument, AccountingLine accountingLine) {
334         Map<String,String> roleQualifiers = new HashMap<String,String>();
335 
336         if (accountingLine != null) {
337             roleQualifiers.put(OleKimAttributes.CHART_OF_ACCOUNTS_CODE, accountingLine.getChartOfAccountsCode());
338             roleQualifiers.put(OleKimAttributes.ACCOUNT_NUMBER, accountingLine.getAccountNumber());
339         }
340 
341         return roleQualifiers;
342     }
343 
344     /**
345      * @param field AccountingLineViewField to find KIM-happy property name for
346      * @return a property name that KIM will like
347      */
348     protected String getKimHappyPropertyNameForField(String convertedName) {
349         convertedName = stripDocumentPrefixFromName(convertedName);
350 
351         return replaceCollectionElementsWithPlurals(convertedName);
352     }
353 
354     /**
355      * get the full property name of the given field
356      * 
357      * @param field the field to get the name from
358      * @return the full property name of the given field, typically, a combination of property prefix and simple property name
359      */
360     protected String getFieldName(AccountingLineViewField field) {
361         String propertyPrefix = field.getField().getPropertyPrefix();
362         String propertyName = field.getField().getPropertyName();
363 
364         return StringUtils.isNotBlank(propertyPrefix) ? (propertyPrefix + "." + propertyName) : propertyName;
365     }
366 
367     /**
368      * Strips "document." and everything before from the property name
369      * 
370      * @param name the property name to strip the document portion off of
371      * @return the stripped name
372      */
373     protected String stripDocumentPrefixFromName(String name) {
374         return name.replaceFirst("(.)*document\\.", StringUtils.EMPTY);
375     }
376 
377     /**
378      * Replaces references to collection elements to their respective plural names WARNING: this method is totally lame and I for
379      * one wished it didn't have to exist
380      * 
381      * @param name the property name with perhaps collection elements in
382      * @return the corrected name
383      */
384     protected String replaceCollectionElementsWithPlurals(String name) {
385         String temp = name.replaceAll("\\[\\d+\\]", "s");
386         // now - need to check if the property name ends with a double "s", which is incorrect
387         if ( temp.endsWith( "ss" ) ) {
388             temp = StringUtils.chop(temp);
389         }
390         return temp;
391     }
392 
393     /**
394      * construct the balance inquiry action for the given accounting line
395      * 
396      * @param accountingLine the given accounting line
397      * @param accountingLinePropertyName the property name of the given account line, typically, the form name
398      * @param accountingLineIndex the index of the given accounting line in its accounting line group
399      * @param groupTitle the title of the accounting line group
400      * @return the balance inquiry action for the given accounting line
401      */
402     protected AccountingLineViewAction getBalanceInquiryAction(AccountingLine accountingLine, String accountingLinePropertyName, Integer accountingLineIndex, String groupTitle) {
403         String actionMethod = this.getBalanceInquiryMethod(accountingLine, accountingLinePropertyName, accountingLineIndex);
404         String actionLabel = this.getActionLabel(OLEKeyConstants.AccountingLineViewRendering.ACCOUNTING_LINE_BALANCE_INQUIRY_ACTION_LABEL, groupTitle, accountingLineIndex + 1);
405 
406         String actionImageName = getKFSImagePath() + "tinybutton-balinquiry.gif";
407 
408         return new AccountingLineViewAction(actionMethod, actionLabel, actionImageName);
409     }
410 
411     /**
412      * construct the delete action for the given accounting line
413      * 
414      * @param accountingLine the given accounting line
415      * @param accountingLinePropertyName the property name of the given account line, typically, the form name
416      * @param accountingLineIndex the index of the given accounting line in its accounting line group
417      * @param groupTitle the title of the accounting line group
418      * @return the delete action for the given accounting line
419      */
420     protected AccountingLineViewAction getDeleteAction(AccountingLine accountingLine, String accountingLinePropertyName, Integer accountingLineIndex, String groupTitle) {
421         String actionMethod = this.getDeleteLineMethod(accountingLine, accountingLinePropertyName, accountingLineIndex);
422         String actionLabel = this.getActionLabel(OLEKeyConstants.AccountingLineViewRendering.ACCOUNTING_LINE_DELETE_ACTION_LABEL, groupTitle, accountingLineIndex + 1);
423 
424         String actionImageName = getRiceImagePath() + "tinybutton-delete1.gif";
425 
426         return new AccountingLineViewAction(actionMethod, actionLabel, actionImageName);
427     }
428 
429     /**
430      * construct the add action for the given accounting line, typically, a new accounting line
431      * 
432      * @param accountingLine the given accounting line
433      * @param accountingLinePropertyName the property name of the given account line, typically, the form name
434      * @param accountingLineIndex the index of the given accounting line in its accounting line group
435      * @param groupTitle the title of the accounting line group
436      * @return the add action for the given accounting line
437      */
438     protected AccountingLineViewAction getAddAction(AccountingLine accountingLine, String accountingLinePropertyName, String groupTitle) {
439         String actionMethod = this.getAddMethod(accountingLine, accountingLinePropertyName);
440         String actionLabel = this.getActionLabel(OLEKeyConstants.AccountingLineViewRendering.ACCOUNTING_LINE_ADD_ACTION_LABEL, groupTitle);
441 
442         String actionImageName = getRiceImagePath() + "tinybutton-add1.gif";
443 
444         return new AccountingLineViewAction(actionMethod, actionLabel, actionImageName);
445     }
446 
447     /**
448      * get a label for an action with the specified message key and values
449      * 
450      * @param messageKey the given message key that points to the label
451      * @param values the given values that would be displayed in label
452      * @return a label for an action with the specified message key and values
453      */
454     protected String getActionLabel(String messageKey, Object... values) {
455         String messageBody = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(messageKey);
456 
457         return MessageFormat.format(messageBody, values);
458     }
459 
460     /**
461      * Builds the action method name of the method that adds accounting lines for this group
462      * 
463      * @param accountingLine the accounting line an action is being checked for
464      * @param accountingLinePropertyName the property name of the accounting line
465      * @return the action method name of the method that adds accounting lines for this group
466      */
467     protected String getAddMethod(AccountingLine accountingLine, String accountingLineProperty) {
468         final String infix = getActionInfixForNewAccountingLine(accountingLine, accountingLineProperty);
469         return OLEConstants.INSERT_METHOD + infix + "Line.anchoraccounting" + infix + "Anchor";
470     }
471 
472     /**
473      * Builds the action method name of the method that deletes accounting lines for this group
474      * 
475      * @param accountingLine the accounting line an action is being checked for
476      * @param accountingLinePropertyName the property name of the accounting line
477      * @param accountingLineIndex the index of the given accounting line within the the group being rendered
478      * @return the action method name of the method that deletes accounting lines for this group
479      */
480     protected String getDeleteLineMethod(AccountingLine accountingLine, String accountingLineProperty, Integer accountingLineIndex) {
481         final String infix = getActionInfixForExtantAccountingLine(accountingLine, accountingLineProperty);
482         return KRADConstants.DELETE_METHOD + infix + "Line.line" + accountingLineIndex + ".anchoraccounting" + infix + "Anchor";
483     }
484 
485     /**
486      * Builds the action method name of the method that performs a balance inquiry on accounting lines for this group
487      * 
488      * @param accountingLine the accounting line an action is being checked for
489      * @param accountingLinePropertyName the property name of the accounting line
490      * @param accountingLineIndex the index of the given accounting line within the the group being rendered
491      * @return the action method name of the method that performs a balance inquiry on accounting lines for this group
492      */
493     protected String getBalanceInquiryMethod(AccountingLine accountingLine, String accountingLineProperty, Integer accountingLineIndex) {
494         final String infix = getActionInfixForExtantAccountingLine(accountingLine, accountingLineProperty);
495         return OLEConstants.PERFORMANCE_BALANCE_INQUIRY_FOR_METHOD + infix + "Line.line" + accountingLineIndex + ".anchoraccounting" + infix + "existingLineLineAnchor" + accountingLineIndex;
496     }
497 
498     /**
499      * Gets the "action infix" for the given accounting line, so that the action knows it is supposed to add to source vs. target
500      * 
501      * @param accountingLine the accounting line an action is being checked for
502      * @param accountingLinePropertyName the property name of the accounting line
503      * @return the name of the action infix
504      */
505     protected String getActionInfixForNewAccountingLine(AccountingLine accountingLine, String accountingLinePropertyName) {
506         if (accountingLine.isSourceAccountingLine()) {
507             return OLEConstants.SOURCE;
508         }
509 
510         if (accountingLine.isTargetAccountingLine()) {
511             return OLEConstants.TARGET;
512         }
513 
514         return OLEConstants.EMPTY_STRING;
515     }
516 
517     /**
518      * Gets the "action infix" for the given accounting line which already exists on the document, so that the action knows it is
519      * supposed to add to source vs. target
520      * 
521      * @param accountingLine the accounting line an action is being checked for
522      * @param accountingLinePropertyName the property name of the accounting line
523      * @return the name of the action infix
524      */
525     protected String getActionInfixForExtantAccountingLine(AccountingLine accountingLine, String accountingLinePropertyName) {
526         if (accountingLine.isSourceAccountingLine()) {
527             return OLEConstants.SOURCE;
528         }
529 
530         if (accountingLine.isTargetAccountingLine()) {
531             return OLEConstants.TARGET;
532         }
533 
534         return OLEConstants.EMPTY_STRING;
535     }
536 
537     /**
538      * get the document authorizer of the given accounting document
539      * 
540      * @param accountingDocument the given accounting document
541      * @return the document authorizer of the given accounting document
542      */
543     protected DocumentAuthorizer getDocumentAuthorizer(AccountingDocument accountingDocument) {
544         return SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(accountingDocument);
545     }
546     
547     /**
548      * @return the path to rice images
549      */
550     protected String getRiceImagePath() {
551         if (riceImagePath == null) {
552             riceImagePath = getConfigurationService().getPropertyValueAsString(KRADConstants.EXTERNALIZABLE_IMAGES_URL_KEY);
553         }
554         return riceImagePath;
555     }
556     
557     /**
558      * @return the path to OLE images
559      */
560     protected String getKFSImagePath() {
561         if (kfsImagePath == null) {
562             kfsImagePath = getConfigurationService().getPropertyValueAsString(KRADConstants.APPLICATION_EXTERNALIZABLE_IMAGES_URL_KEY);
563         }
564         return kfsImagePath;
565     }
566     
567     protected ConfigurationService getConfigurationService() {
568         if ( kualiConfigurationService == null ) {
569             kualiConfigurationService = SpringContext.getBean(ConfigurationService.class);
570         }
571         return kualiConfigurationService;
572     }
573 }