Coverage Report - org.kuali.rice.krad.uif.service.impl.ViewHelperServiceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
ViewHelperServiceImpl
0%
0/314
0%
0/160
3.378
 
 1  
 /*
 2  
  * Copyright 2007 The Kuali Foundation Licensed under the Educational Community
 3  
  * License, Version 1.0 (the "License"); you may not use this file except in
 4  
  * compliance with the License. You may obtain a copy of the License at
 5  
  * http://www.opensource.org/licenses/ecl1.php Unless required by applicable law
 6  
  * or agreed to in writing, software distributed under the License is
 7  
  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 8  
  * KIND, either express or implied. See the License for the specific language
 9  
  * governing permissions and limitations under the License.
 10  
  */
 11  
 package org.kuali.rice.krad.uif.service.impl;
 12  
 
 13  
 import org.apache.commons.lang.StringUtils;
 14  
 import org.kuali.rice.kim.bo.Person;
 15  
 import org.kuali.rice.krad.datadictionary.AttributeDefinition;
 16  
 import org.kuali.rice.krad.inquiry.Inquirable;
 17  
 import org.kuali.rice.krad.valuefinder.ValueFinder;
 18  
 import org.kuali.rice.krad.service.DataDictionaryService;
 19  
 import org.kuali.rice.krad.service.KRADServiceLocator;
 20  
 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
 21  
 import org.kuali.rice.krad.uif.UifConstants;
 22  
 import org.kuali.rice.krad.uif.authorization.Authorizer;
 23  
 import org.kuali.rice.krad.uif.authorization.PresentationController;
 24  
 import org.kuali.rice.krad.uif.container.CollectionGroup;
 25  
 import org.kuali.rice.krad.uif.container.Container;
 26  
 import org.kuali.rice.krad.uif.container.View;
 27  
 import org.kuali.rice.krad.uif.core.BindingInfo;
 28  
 import org.kuali.rice.krad.uif.core.Component;
 29  
 import org.kuali.rice.krad.uif.core.DataBinding;
 30  
 import org.kuali.rice.krad.uif.core.PropertyReplacer;
 31  
 import org.kuali.rice.krad.uif.core.RequestParameter;
 32  
 import org.kuali.rice.krad.uif.field.AttributeField;
 33  
 import org.kuali.rice.krad.uif.layout.LayoutManager;
 34  
 import org.kuali.rice.krad.uif.modifier.ComponentModifier;
 35  
 import org.kuali.rice.krad.uif.service.ExpressionEvaluatorService;
 36  
 import org.kuali.rice.krad.uif.service.ViewDictionaryService;
 37  
 import org.kuali.rice.krad.uif.service.ViewHelperService;
 38  
 import org.kuali.rice.krad.uif.util.BooleanMap;
 39  
 import org.kuali.rice.krad.uif.util.CloneUtils;
 40  
 import org.kuali.rice.krad.uif.util.ComponentFactory;
 41  
 import org.kuali.rice.krad.uif.util.ComponentUtils;
 42  
 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
 43  
 import org.kuali.rice.krad.uif.util.ViewModelUtils;
 44  
 import org.kuali.rice.krad.uif.widget.Inquiry;
 45  
 import org.kuali.rice.krad.util.GlobalVariables;
 46  
 import org.kuali.rice.krad.util.KRADConstants;
 47  
 import org.kuali.rice.krad.util.ObjectUtils;
 48  
 import org.kuali.rice.krad.web.form.UifFormBase;
 49  
 import org.springframework.util.MethodInvoker;
 50  
 
 51  
 import java.lang.reflect.Field;
 52  
 import java.util.ArrayList;
 53  
 import java.util.Collection;
 54  
 import java.util.HashMap;
 55  
 import java.util.HashSet;
 56  
 import java.util.List;
 57  
 import java.util.Map;
 58  
 import java.util.Map.Entry;
 59  
 import java.util.Properties;
 60  
 import java.util.Set;
 61  
 
 62  
 /**
 63  
  * Default Implementation of <code>ViewHelperService</code>
 64  
  * 
 65  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 66  
  */
 67  0
 public class ViewHelperServiceImpl implements ViewHelperService {
 68  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ViewHelperServiceImpl.class);
 69  
 
 70  
     private transient DataDictionaryService dataDictionaryService;
 71  
     private transient ExpressionEvaluatorService expressionEvaluatorService;
 72  
     private transient ViewDictionaryService viewDictionaryService;
 73  
 
 74  
     /**
 75  
      * Uses reflection to find all fields defined on the <code>View</code>
 76  
      * instance that have the <code>RequestParameter</code> annotation (which
 77  
      * indicates the field may be populated by the request). For each field
 78  
      * found, if there is a corresponding key/value pair in the request
 79  
      * parameters, the value is used to populate the field. In addition, any
 80  
      * conditional properties of <code>PropertyReplacers</code> configured for
 81  
      * the field are cleared so that the request parameter value does not get
 82  
      * overridden by the dictionary conditional logic
 83  
      * 
 84  
      * @see org.kuali.rice.krad.uif.service.ViewHelperService#populateViewFromRequestParameters(org.kuali.rice.krad.uif.container.View,
 85  
      *      java.util.Map)
 86  
      */
 87  
     @Override
 88  
     public void populateViewFromRequestParameters(View view, Map<String, String> parameters) {
 89  
         // build set of view properties that can be populated
 90  0
         Set<String> fieldNamesToPopulate = new HashSet<String>();
 91  
 
 92  0
         Field[] fields = CloneUtils.getFields(view.getClass(), true);
 93  0
         for (int i = 0; i < fields.length; i++) {
 94  0
             Field field = fields[i];
 95  
 
 96  0
             RequestParameter requestParameter = field.getAnnotation(RequestParameter.class);
 97  0
             if (requestParameter != null) {
 98  
                 // use specified parameter name if given, else use field name
 99  0
                 if (StringUtils.isNotBlank(requestParameter.parameterName())) {
 100  0
                     fieldNamesToPopulate.add(requestParameter.parameterName());
 101  
                 } else {
 102  0
                     fieldNamesToPopulate.add(field.getName());
 103  
                 }
 104  
             }
 105  
         }
 106  
 
 107  
         // build Map of property replacers by property name
 108  0
         Map<String, Set<PropertyReplacer>> viewPropertyReplacers = new HashMap<String, Set<PropertyReplacer>>();
 109  0
         for (PropertyReplacer replacer : view.getPropertyReplacers()) {
 110  0
             Set<PropertyReplacer> propertyReplacers = new HashSet<PropertyReplacer>();
 111  0
             if (viewPropertyReplacers.containsKey(replacer.getPropertyName())) {
 112  0
                 propertyReplacers = viewPropertyReplacers.get(replacer.getPropertyName());
 113  
             }
 114  0
             propertyReplacers.add(replacer);
 115  
 
 116  0
             viewPropertyReplacers.put(replacer.getPropertyName(), propertyReplacers);
 117  0
         }
 118  
 
 119  
         // build map of view parameter key/values and populate view fields
 120  0
         Map<String, String> viewRequestParameters = new HashMap<String, String>();
 121  0
         for (String fieldToPopulate : fieldNamesToPopulate) {
 122  0
             if (parameters.containsKey(fieldToPopulate)) {
 123  0
                 String fieldValue = parameters.get(fieldToPopulate);
 124  
 
 125  0
                 if (StringUtils.isNotBlank(fieldValue)) {
 126  0
                     viewRequestParameters.put(fieldToPopulate, fieldValue);
 127  0
                     ObjectPropertyUtils.setPropertyValue(view, fieldToPopulate, fieldValue);
 128  
 
 129  
                     // remove any conditional configuration so value is not
 130  
                     // overridden later during the apply model phase
 131  0
                     String conditionalProperty = StringUtils.substring(fieldToPopulate, 0, 1).toLowerCase()
 132  
                             + StringUtils.substring(fieldToPopulate, 1, fieldToPopulate.length());
 133  0
                     conditionalProperty = UifConstants.EL_CONDITIONAL_PROPERTY_PREFIX + conditionalProperty;
 134  0
                     ObjectPropertyUtils.setPropertyValue(view, conditionalProperty, fieldValue, true);
 135  
 
 136  0
                     if (viewPropertyReplacers.containsKey(fieldToPopulate)) {
 137  0
                         Set<PropertyReplacer> propertyReplacers = viewPropertyReplacers.get(fieldToPopulate);
 138  0
                         for (PropertyReplacer replacer : propertyReplacers) {
 139  0
                             view.getPropertyReplacers().remove(replacer);
 140  
                         }
 141  
                     }
 142  
                 }
 143  0
             }
 144  
         }
 145  
 
 146  0
         view.setViewRequestParameters(viewRequestParameters);
 147  0
     }
 148  
 
 149  
     /**
 150  
      * @see org.kuali.rice.krad.uif.service.ViewHelperService#performInitialization(org.kuali.rice.krad.uif.container.View,
 151  
      *      java.util.Map)
 152  
      */
 153  
     @Override
 154  
     public void performInitialization(View view) {
 155  
         // process component ids for duplicates
 156  0
         ComponentUtils.processIds(view, new HashMap<String, Integer>());
 157  
 
 158  0
         performComponentInitialization(view, view);
 159  0
     }
 160  
     
 161  
     /**
 162  
      * Performs the complete component lifecycle on the component passed in, in this order:
 163  
      * performComponentInitialization, performComponentApplyModel, and performComponentFinalize.
 164  
      * 
 165  
      * @see {@link #performComponentInitialization(View, Component)}
 166  
      * @see {@link #performComponentApplyModel(View, Component, Object)}
 167  
      * @see {@link #performComponentFinalize(View, Component, Object, Component)}
 168  
      * @param form
 169  
      * @param component
 170  
      */
 171  
     public void performComponentLifecycle(UifFormBase form, Component component, String origId){
 172  0
         Component origComponent = form.getView().getViewIndex().getComponentById(origId);
 173  
         
 174  0
         Component parent = (Component) origComponent.getContext().get(UifConstants.ContextVariableNames.PARENT);
 175  0
         component.getContext().putAll(origComponent.getContext());
 176  
 
 177  0
         performComponentInitialization(form.getView(), component);
 178  0
         performComponentApplyModel(form.getView(), component, form);
 179  0
         performComponentFinalize(form.getView(), component, form, parent);
 180  
         
 181  0
         component.setId(origId);
 182  0
     }
 183  
 
 184  
     /**
 185  
      * Performs initialization of a component by these steps:
 186  
      * 
 187  
      * <ul>
 188  
      * <li>For <code>AttributeField</code> instances, set defaults from the data
 189  
      * dictionary.</li>
 190  
      * <li>Invoke the initialize method on the component. Here the component can
 191  
      * setup defaults and do other initialization that is specific to that
 192  
      * component.</li>
 193  
      * <li>Invoke any configured <code>ComponentModifier</code> instances for
 194  
      * the component.</li>
 195  
      * <li>Call the component to get the List of components that are nested
 196  
      * within and recursively call this method to initialize those components.</li>
 197  
      * <li>Call custom initialize hook for service overrides</li>
 198  
      * </ul>
 199  
      * 
 200  
      * <p>
 201  
      * Note the order various initialize points are called, this can sometimes
 202  
      * be an important factor to consider when initializing a component
 203  
      * </p>
 204  
      * 
 205  
      * @see org.kuali.rice.krad.uif.service.ViewHelperService#performComponentInitialization(org.kuali.rice.krad.uif.container.View,
 206  
      *      org.kuali.rice.krad.uif.core.Component)
 207  
      */
 208  
     public void performComponentInitialization(View view, Component component) {
 209  0
         if (component == null) {
 210  0
             return;
 211  
         }
 212  
 
 213  0
         LOG.debug("Initializing component: " + component.getId() + " with type: " + component.getClass());
 214  
 
 215  
         // invoke component to initialize itself after properties have been set
 216  0
         component.performInitialization(view);
 217  
 
 218  
         // for attribute fields, set defaults from dictionary entry
 219  0
         if (component instanceof AttributeField) {
 220  0
             initializeAttributeFieldFromDataDictionary(view, (AttributeField) component);
 221  
         }
 222  
 
 223  
         // for collection groups set defaults from dictionary entry
 224  0
         if (component instanceof CollectionGroup) {
 225  
             // TODO: initialize from dictionary
 226  
         }
 227  
 
 228  
         // invoke component initializers setup to run in the initialize phase
 229  0
         runComponentModifiers(view, component, null, UifConstants.ViewPhases.INITIALIZE);
 230  
 
 231  
         // initialize nested components
 232  0
         for (Component nestedComponent : component.getNestedComponents()) {
 233  0
             performComponentInitialization(view, nestedComponent);
 234  
         }
 235  
 
 236  
         // initialize property replacements (if components)
 237  0
         for (PropertyReplacer replacer : component.getPropertyReplacers()) {
 238  0
             if (Component.class.isAssignableFrom(replacer.getReplacement().getClass())) {
 239  0
                 performComponentInitialization(view, (Component) replacer.getReplacement());
 240  
             }
 241  
         }
 242  
 
 243  
         // invoke initialize service hook
 244  0
         performCustomInitialization(view, component);
 245  0
     }
 246  
 
 247  
     /**
 248  
      * Sets properties of the <code>AttributeField</code> (if blank) to the
 249  
      * corresponding attribute entry in the data dictionary
 250  
      * 
 251  
      * @param view
 252  
      *            - view instance containing the field
 253  
      * @param field
 254  
      *            - field instance to initialize
 255  
      */
 256  
     protected void initializeAttributeFieldFromDataDictionary(View view, AttributeField field) {
 257  0
         AttributeDefinition attributeDefinition = null;
 258  
 
 259  0
         String dictionaryAttributeName = field.getDictionaryAttributeName();
 260  0
         String dictionaryObjectEntry = field.getDictionaryObjectEntry();
 261  
 
 262  
         // if entry given but not attribute name, use field name as attribute
 263  
         // name
 264  0
         if (StringUtils.isNotBlank(dictionaryObjectEntry) && StringUtils.isBlank(dictionaryAttributeName)) {
 265  0
             dictionaryAttributeName = field.getPropertyName();
 266  
         }
 267  
 
 268  
         // if dictionary entry and attribute set, attempt to find definition
 269  0
         if (StringUtils.isNotBlank(dictionaryAttributeName) && StringUtils.isNotBlank(dictionaryObjectEntry)) {
 270  0
             attributeDefinition = getDataDictionaryService().getAttributeDefinition(dictionaryObjectEntry,
 271  
                     dictionaryAttributeName);
 272  
         }
 273  
 
 274  
         // if definition not found, recurse through path
 275  0
         if (attributeDefinition == null) {
 276  0
             String propertyPath = field.getBindingInfo().getBindingPath();
 277  0
             if (StringUtils.isNotBlank(field.getBindingInfo().getCollectionPath())) {
 278  0
                 propertyPath = field.getBindingInfo().getCollectionPath();
 279  0
                 if (StringUtils.isNotBlank(field.getBindingInfo().getBindByNamePrefix())) {
 280  0
                     propertyPath += "." + field.getBindingInfo().getBindByNamePrefix();
 281  
                 }
 282  0
                 propertyPath += "." + field.getBindingInfo().getBindingName();
 283  
             }
 284  
             
 285  0
             attributeDefinition = findNestedDictionaryAttribute(view, field, null, propertyPath);
 286  
         }
 287  
 
 288  
         // if a definition was found, initialize field from definition
 289  0
         if (attributeDefinition != null) {
 290  0
             field.copyFromAttributeDefinition(attributeDefinition);
 291  
         }
 292  
 
 293  0
         if (field.getControl() == null) {
 294  0
             field.setControl(ComponentFactory.getTextControl());
 295  
         }
 296  0
     }
 297  
     
 298  
     /**
 299  
      * Recursively drills down the property path (if nested) to find an
 300  
      * AttributeDefinition, the first attribute definition found will be
 301  
      * returned
 302  
      * 
 303  
      * <p>
 304  
      * e.g. suppose parentPath is 'document' and propertyPath is
 305  
      * 'account.subAccount.name', first the property type for document will be
 306  
      * retrieved using the view metadata and used as the dictionary entry, with
 307  
      * the propertyPath as the dictionary attribute, if an attribute definition
 308  
      * exists it will be returned. Else, the first part of the property path is
 309  
      * added to the parent, making the parentPath 'document.account' and the
 310  
      * propertyPath 'subAccount.name', the method is then called again to
 311  
      * perform the process with those parameters. The recursion continues until
 312  
      * an attribute field is found, or the propertyPath is no longer nested
 313  
      * </p>
 314  
      * 
 315  
      * @param view
 316  
      *            - view instance containing the field
 317  
      * @param field
 318  
      *            - field we are attempting to find a supporting attribute
 319  
      *            definition for
 320  
      * @param parentPath
 321  
      *            - parent path to use for getting the dictionary entry
 322  
      * @param propertyPath
 323  
      *            - path of the property relative to the parent, to use as
 324  
      *            dictionary attribute and to drill down on
 325  
      * @return AttributeDefinition if found, or Null
 326  
      */
 327  
     protected AttributeDefinition findNestedDictionaryAttribute(View view, AttributeField field, String parentPath,
 328  
             String propertyPath) {
 329  0
         AttributeDefinition attributeDefinition = null;
 330  
 
 331  
         // attempt to find definition for parent and property
 332  0
         String dictionaryAttributeName = propertyPath;
 333  0
         String dictionaryObjectEntry = null;
 334  
         
 335  0
         if (field.getBindingInfo().isBindToMap()) {
 336  0
             parentPath = "";
 337  0
             if (!field.getBindingInfo().isBindToForm() && StringUtils.isNotBlank(field.getBindingInfo().getBindingObjectPath())) {
 338  0
                 parentPath = field.getBindingInfo().getBindingObjectPath();
 339  
             }
 340  0
             if (StringUtils.isNotBlank(field.getBindingInfo().getBindByNamePrefix())) {
 341  0
                 if (StringUtils.isNotBlank(parentPath)) {
 342  0
                     parentPath += "." + field.getBindingInfo().getBindByNamePrefix();
 343  
                 }
 344  
                 else {
 345  0
                     parentPath = field.getBindingInfo().getBindByNamePrefix();
 346  
                 }
 347  
             }
 348  
             
 349  0
             dictionaryAttributeName = field.getBindingInfo().getBindingName();
 350  
         }
 351  
 
 352  0
         if (StringUtils.isNotBlank(parentPath)) {
 353  0
             Class<?> dictionaryModelClass = ViewModelUtils.getPropertyType(view, parentPath);
 354  0
             if (dictionaryModelClass != null) {
 355  0
                 dictionaryObjectEntry = dictionaryModelClass.getName();
 356  
 
 357  0
                 attributeDefinition = getDataDictionaryService().getAttributeDefinition(dictionaryObjectEntry,
 358  
                         dictionaryAttributeName);
 359  
             }
 360  
         }
 361  
 
 362  
         // if definition not found and property is still nested, recurse down
 363  
         // one level
 364  0
         if ((attributeDefinition == null) && StringUtils.contains(propertyPath, ".")) {
 365  0
             String nextParentPath = StringUtils.substringBefore(propertyPath, ".");
 366  0
             if (StringUtils.isNotBlank(parentPath)) {
 367  0
                 nextParentPath = parentPath + "." + nextParentPath;
 368  
             }
 369  0
             String nextPropertyPath = StringUtils.substringAfter(propertyPath, ".");
 370  
 
 371  0
             return findNestedDictionaryAttribute(view, field, nextParentPath, nextPropertyPath);
 372  
         }
 373  
 
 374  
         // if a definition was found, update the fields dictionary properties
 375  0
         if (attributeDefinition != null) {
 376  0
             field.setDictionaryAttributeName(dictionaryAttributeName);
 377  0
             field.setDictionaryObjectEntry(dictionaryObjectEntry);
 378  
         }
 379  
 
 380  0
         return attributeDefinition;
 381  
     }
 382  
 
 383  
     /**
 384  
      * Determines the dictionary class that is associated with the given
 385  
      * <code>AttributeField</code>
 386  
      * 
 387  
      * @param view
 388  
      *            - view instance for field
 389  
      * @param field
 390  
      *            - field instance to determine dictionary class for
 391  
      * @return Class<?> dictionary class or null if not found
 392  
      */
 393  
     protected Class<?> getDictionaryModelClass(View view, AttributeField field) {
 394  0
         return ViewModelUtils.getParentObjectClassForMetadata(view, field);
 395  
     }
 396  
 
 397  
     /**
 398  
      * @see org.kuali.rice.krad.uif.service.ViewHelperService#performApplyModel(org.kuali.rice.krad.uif.container.View,
 399  
      *      java.lang.Object)
 400  
      */
 401  
     @Override
 402  
     public void performApplyModel(View view, Object model) {
 403  
         // get action flag and edit modes from authorizer/presentation
 404  
         // controller
 405  0
         invokeAuthorizerPresentationController(view, (UifFormBase) model);
 406  
 
 407  
         // set view context for conditional expressions
 408  0
         setViewContext(view, model);
 409  
 
 410  0
         performComponentApplyModel(view, view, model);
 411  0
     }
 412  
 
 413  
     /**
 414  
      * Invokes the configured <code>PresentationController</code> and
 415  
      * </code>Authorizer</code> for the view to get the exported action flags
 416  
      * and edit modes that can be used in conditional logic
 417  
      * 
 418  
      * @param view
 419  
      *            - view instance that is being built and
 420  
      *            presentation/authorizer pulled for
 421  
      * @param model
 422  
      *            - Object that contains the model data
 423  
      */
 424  
     protected void invokeAuthorizerPresentationController(View view, UifFormBase model) {
 425  0
         PresentationController presentationController = ObjectUtils.newInstance(view.getPresentationControllerClass());
 426  0
         Authorizer authorizer = ObjectUtils.newInstance(view.getAuthorizerClass());
 427  
 
 428  0
         Person user = GlobalVariables.getUserSession().getPerson();
 429  
 
 430  0
         Set<String> actionFlags = presentationController.getActionFlags(model);
 431  0
         actionFlags = authorizer.getActionFlags(model, user, actionFlags);
 432  
         
 433  0
         view.setActionFlags(new BooleanMap(actionFlags));
 434  
 
 435  0
         Set<String> editModes = presentationController.getEditModes(model);
 436  0
         editModes = authorizer.getEditModes(model, user, editModes);
 437  
         
 438  0
         view.setEditModes(new BooleanMap(editModes));
 439  0
     }
 440  
 
 441  
     /**
 442  
      * Sets up the view context which will be available to other components
 443  
      * through their context for conditional logic evaluation
 444  
      * 
 445  
      * @param view
 446  
      *            - view instance to set context for
 447  
      * @param model
 448  
      *            - object containing the view data
 449  
      */
 450  
     protected void setViewContext(View view, Object model) {
 451  0
         view.getContext().putAll(getPreModelContext(view));
 452  
 
 453  
         // evaluate view expressions for further context
 454  0
         for (Entry<String, String> variableExpression : view.getExpressionVariables().entrySet()) {
 455  0
             String variableName = variableExpression.getKey();
 456  0
             Object value = getExpressionEvaluatorService().evaluateExpression(model, view.getContext(),
 457  
                     variableExpression.getValue());
 458  0
             view.pushObjectToContext(variableName, value);
 459  0
         }
 460  0
     }
 461  
     
 462  
     /**
 463  
      * Returns the general context that is available before the apply model
 464  
      * phase (during the initialize phase)
 465  
      * 
 466  
      * @param view
 467  
      *            - view instance for context
 468  
      * @return Map<String, Object> context map
 469  
      */
 470  
     protected Map<String, Object> getPreModelContext(View view) {
 471  0
         Map<String, Object> context = new HashMap<String, Object>();
 472  
 
 473  0
         context.put(UifConstants.ContextVariableNames.VIEW, view);
 474  0
         context.put(UifConstants.ContextVariableNames.VIEW_HELPER, this);
 475  
 
 476  0
         Properties properties = KRADServiceLocator.getKualiConfigurationService().getAllProperties();
 477  0
         context.put(UifConstants.ContextVariableNames.CONFIG_PROPERTIES, properties);
 478  0
         context.put(UifConstants.ContextVariableNames.CONSTANTS, KRADConstants.class);
 479  
 
 480  0
         return context;
 481  
     }
 482  
 
 483  
     /**
 484  
      * Applies the model data to a component of the View instance
 485  
      * 
 486  
      * <p>
 487  
      * The component is invoked to to apply the model data. Here the component
 488  
      * can generate any additional fields needed or alter the configured fields.
 489  
      * After the component is invoked a hook for custom helper service
 490  
      * processing is invoked. Finally the method is recursively called for all
 491  
      * the component children
 492  
      * </p>
 493  
      * 
 494  
      * @param view
 495  
      *            - view instance the component belongs to
 496  
      * @param component
 497  
      *            - the component instance the model should be applied to
 498  
      * @param model
 499  
      *            - top level object containing the data
 500  
      */
 501  
     protected void performComponentApplyModel(View view, Component component, Object model) {
 502  0
         if (component == null) {
 503  0
             return;
 504  
         }
 505  
 
 506  
         // evaluate expressions on properties
 507  0
         component.getContext().putAll(getCommonContext(view, component));
 508  0
         getExpressionEvaluatorService().evaluateObjectProperties(component, model, component.getContext());
 509  
 
 510  0
         if (component instanceof Container) {
 511  0
             LayoutManager layoutManager = ((Container) component).getLayoutManager();
 512  
 
 513  0
             if (layoutManager != null) {
 514  0
                 layoutManager.getContext().putAll(getCommonContext(view, component));
 515  0
                 layoutManager.pushObjectToContext(UifConstants.ContextVariableNames.PARENT, component);
 516  0
                 layoutManager.pushObjectToContext(UifConstants.ContextVariableNames.MANAGER, layoutManager);
 517  0
                 getExpressionEvaluatorService().evaluateObjectProperties(layoutManager, model,
 518  
                         layoutManager.getContext());
 519  
             }
 520  
         }
 521  
 
 522  0
         if (component instanceof DataBinding) {
 523  0
             BindingInfo bindingInfo = ((DataBinding) component).getBindingInfo();
 524  0
             getExpressionEvaluatorService().evaluateObjectProperties(bindingInfo, model, component.getContext());
 525  
         }
 526  
 
 527  
         // invoke component to perform its conditional logic
 528  0
         Component parent = (Component) component.getContext().get(UifConstants.ContextVariableNames.PARENT);
 529  0
         component.performApplyModel(view, model, parent);
 530  
 
 531  
         // invoke service override hook
 532  0
         performCustomApplyModel(view, component, model);
 533  
 
 534  
         // invoke component modifiers configured to run in the apply model phase
 535  0
         runComponentModifiers(view, component, model, UifConstants.ViewPhases.APPLY_MODEL);
 536  
 
 537  
         // get children and recursively perform conditional logic
 538  0
         for (Component nestedComponent : component.getNestedComponents()) {
 539  0
             if (nestedComponent != null) {
 540  0
                 nestedComponent.pushObjectToContext(UifConstants.ContextVariableNames.PARENT, component);
 541  
             }
 542  
 
 543  0
             performComponentApplyModel(view, nestedComponent, model);
 544  
         }
 545  0
     }
 546  
 
 547  
     /**
 548  
      * Runs any configured <code>ComponentModifiers</code> for the given
 549  
      * component that match the given run phase and who run condition evaluation
 550  
      * succeeds
 551  
      * 
 552  
      * @param view
 553  
      *            - view instance for context
 554  
      * @param component
 555  
      *            - component instance whose modifiers should be run
 556  
      * @param model
 557  
      *            - model object for context
 558  
      * @param runPhase
 559  
      *            - current phase to match on
 560  
      */
 561  
     protected void runComponentModifiers(View view, Component component, Object model, String runPhase) {
 562  0
         for (ComponentModifier modifier : component.getComponentModifiers()) {
 563  
             // check run phase matches
 564  0
             if (StringUtils.equals(modifier.getRunPhase(), runPhase)) {
 565  
                 // check condition (if set) evaluates to true
 566  0
                 boolean runModifier = true;
 567  0
                 if (StringUtils.isNotBlank(modifier.getRunCondition())) {
 568  0
                     Map<String, Object> context = new HashMap<String, Object>();
 569  0
                     context.put(UifConstants.ContextVariableNames.COMPONENT, component);
 570  0
                     context.put(UifConstants.ContextVariableNames.VIEW, view);
 571  
 
 572  0
                     String conditionEvaluation = getExpressionEvaluatorService().evaluateExpressionTemplate(model,
 573  
                             context, modifier.getRunCondition());
 574  0
                     runModifier = Boolean.parseBoolean(conditionEvaluation);
 575  
                 }
 576  
 
 577  0
                 if (runModifier) {
 578  0
                     if (StringUtils.equals(runPhase, UifConstants.ViewPhases.APPLY_MODEL)
 579  
                             || StringUtils.equals(runPhase, UifConstants.ViewPhases.FINALIZE)) {
 580  0
                         modifier.performModification(view, model, component);
 581  
                     } else {
 582  0
                         modifier.performModification(view, component);
 583  
                     }
 584  
                 }
 585  0
             }
 586  
         }
 587  0
     }
 588  
 
 589  
     /**
 590  
      * Gets global objects for the context map and pushes them to the context
 591  
      * for the component
 592  
      * 
 593  
      * @param view
 594  
      *            - view instance for component
 595  
      * @param component
 596  
      *            - component instance to push context to
 597  
      */
 598  
     protected Map<String, Object> getCommonContext(View view, Component component) {
 599  0
         Map<String, Object> context = new HashMap<String, Object>();
 600  
 
 601  0
         context.putAll(view.getContext());
 602  0
         context.put(UifConstants.ContextVariableNames.COMPONENT, component);
 603  
 
 604  0
         return context;
 605  
     }
 606  
 
 607  
     /**
 608  
      * @see org.kuali.rice.krad.uif.service.ViewHelperService#performFinalize(org.kuali.rice.krad.uif.container.View,
 609  
      *      java.lang.Object)
 610  
      */
 611  
     @Override
 612  
     public void performFinalize(View view, Object model) {
 613  0
         performComponentFinalize(view, view, model, null);
 614  0
     }
 615  
 
 616  
     /**
 617  
      * Update state of the given component and does final preparation for
 618  
      * rendering
 619  
      * 
 620  
      * @param view
 621  
      *            - view instance the component belongs to
 622  
      * @param component
 623  
      *            - the component instance that should be updated
 624  
      * @param model
 625  
      *            - top level object containing the data
 626  
      * @param parent
 627  
      *            - Parent component for the component being finalized
 628  
      */
 629  
     protected void performComponentFinalize(View view, Component component, Object model, Component parent) {
 630  0
         if (component == null) {
 631  0
             return;
 632  
         }
 633  
         
 634  
         // invoke configured method finalizers
 635  0
         invokeMethodFinalizer(view, component, model);
 636  
         
 637  
         // invoke component to update its state
 638  0
         component.performFinalize(view, model, parent);
 639  
 
 640  
         // invoke service override hook
 641  0
         performCustomFinalize(view, component, model, parent);
 642  
 
 643  
         // invoke component initializers setup to run in the finalize phase
 644  0
         runComponentModifiers(view, component, model, UifConstants.ViewPhases.FINALIZE);
 645  
 
 646  
         // get components children and recursively update state
 647  0
         for (Component nestedComponent : component.getNestedComponents()) {
 648  0
             performComponentFinalize(view, nestedComponent, model, component);
 649  
         }
 650  0
     }
 651  
     
 652  
     /**
 653  
      * Invokes the finalize method for the component (if configured) and sets
 654  
      * the render output for the component to the returned method string (if
 655  
      * method is not a void type)
 656  
      * 
 657  
      * @param view
 658  
      *            - view instance that contains the component
 659  
      * @param component
 660  
      *            - component to run finalize method for
 661  
      * @param model
 662  
      *            - top level object containing the data
 663  
      *
 664  
      */
 665  
     protected void invokeMethodFinalizer(View view, Component component, Object model) {
 666  0
         String finalizeMethodToCall = component.getFinalizeMethodToCall();
 667  0
         MethodInvoker finalizeMethodInvoker = component.getFinalizeMethodInvoker();
 668  
 
 669  0
         if (StringUtils.isBlank(finalizeMethodToCall) && (finalizeMethodInvoker == null)) {
 670  0
             return;
 671  
         }
 672  
 
 673  0
         if (finalizeMethodInvoker == null) {
 674  0
             finalizeMethodInvoker = new MethodInvoker();
 675  
         }
 676  
 
 677  
         // if method not set on invoker, use renderingMethodToCall, note staticMethod could be set(don't know since
 678  
         // there is not a getter), if so it will override the target method in prepare
 679  0
         if (StringUtils.isBlank(finalizeMethodInvoker.getTargetMethod())) {
 680  0
             finalizeMethodInvoker.setTargetMethod(finalizeMethodToCall);
 681  
         }
 682  
 
 683  
         // if target class or object not set, use view helper service
 684  0
         if ((finalizeMethodInvoker.getTargetClass() == null) && (finalizeMethodInvoker.getTargetObject() == null)) {
 685  0
             finalizeMethodInvoker.setTargetObject(view.getViewHelperService());
 686  
         }
 687  
 
 688  
         // setup arguments for method
 689  0
         List<Object> additionalArguments = component.getFinalizeMethodAdditionalArguments();
 690  0
         if (additionalArguments == null) {
 691  0
             additionalArguments = new ArrayList<Object>();
 692  
         }
 693  
 
 694  0
         Object[] arguments = new Object[2 + additionalArguments.size()];
 695  0
         arguments[0] = component;
 696  0
         arguments[1] = model;
 697  
 
 698  0
         int argumentIndex = 1;
 699  0
         for (Object argument : additionalArguments) {
 700  0
             argumentIndex++;
 701  0
             arguments[argumentIndex] = argument;
 702  
         }
 703  0
         finalizeMethodInvoker.setArguments(arguments);
 704  
 
 705  
         // invoke method and get render output
 706  
         try {
 707  0
             LOG.debug("Invoking render method: " + finalizeMethodInvoker.getTargetMethod() + " for component: "
 708  
                     + component.getId());
 709  0
             finalizeMethodInvoker.prepare();
 710  
 
 711  0
             Class<?> methodReturnType = finalizeMethodInvoker.getPreparedMethod().getReturnType();
 712  0
             if (StringUtils.equals("void", methodReturnType.getName())) {
 713  0
                 finalizeMethodInvoker.invoke();
 714  
             } else {
 715  0
                 String renderOutput = (String) finalizeMethodInvoker.invoke();
 716  
 
 717  0
                 component.setSelfRendered(true);
 718  0
                 component.setRenderOutput(renderOutput);
 719  
             }
 720  0
         } catch (Exception e) {
 721  0
             LOG.error("Error invoking rendering method for component: " + component.getId(), e);
 722  0
             throw new RuntimeException("Error invoking rendering method for component: " + component.getId(), e);
 723  0
         }
 724  0
     }
 725  
 
 726  
     /**
 727  
      * @see org.kuali.rice.krad.uif.service.ViewHelperService#processCollectionAddLine(org.kuali.rice.krad.uif.container.View,
 728  
      *      java.lang.Object, java.lang.String)
 729  
      */
 730  
     @Override
 731  
     public void processCollectionAddLine(View view, Object model, String collectionPath) {
 732  
         // get the collection group from the view
 733  0
         CollectionGroup collectionGroup = view.getViewIndex().getCollectionGroupByPath(collectionPath);
 734  0
         if (collectionGroup == null) {
 735  0
             logAndThrowRuntime("Unable to get collection group component for path: " + collectionPath);
 736  
         }
 737  
 
 738  
         // get the collection instance for adding the new line
 739  0
         Collection<Object> collection = ObjectPropertyUtils.getPropertyValue(model, collectionPath);
 740  0
         if (collection == null) {
 741  0
             logAndThrowRuntime("Unable to get collection property from model for path: " + collectionPath);
 742  
         }
 743  
 
 744  
         // now get the new line we need to add
 745  0
         String addLinePath = collectionGroup.getAddLineBindingInfo().getBindingPath();
 746  0
         Object addLine = ObjectPropertyUtils.getPropertyValue(model, addLinePath);
 747  0
         if (addLine == null) {
 748  0
             logAndThrowRuntime("Add line instance not found for path: " + addLinePath);
 749  
         }
 750  
 
 751  0
         processBeforeAddLine(view, collectionGroup, model, addLine);
 752  
 
 753  
         // validate the line to make sure it is ok to add
 754  0
         boolean isValidLine = performAddLineValidation(view, collectionGroup, model, addLine);
 755  0
         if (isValidLine) {
 756  
             // TODO: should check to see if there is an add line method on the
 757  
             // collection parent and if so call that instead of just adding to
 758  
             // the collection (so that sequence can be set)
 759  0
             collection.add(addLine);
 760  
 
 761  
             // make a new instance for the add line
 762  0
             collectionGroup.initializeNewCollectionLine(view, model, collectionGroup, true);
 763  
         }
 764  
 
 765  0
         processAfterAddLine(view, collectionGroup, model, addLine);
 766  0
     }
 767  
 
 768  
     /**
 769  
      * Performs validation on the new collection line before it is added to the
 770  
      * corresponding collection
 771  
      * 
 772  
      * @param view
 773  
      *            - view instance that the action was taken on
 774  
      * @param collectionGroup
 775  
      *            - collection group component for the collection
 776  
      * @param addLine
 777  
      *            - new line instance to validate
 778  
      * @param model
 779  
      *            - object instance that contain's the views data
 780  
      * @return boolean true if the line is valid and it should be added to the
 781  
      *         collection, false if it was not valid and should not be added to
 782  
      *         the collection
 783  
      */
 784  
     protected boolean performAddLineValidation(View view, CollectionGroup collectionGroup, Object model, Object addLine) {
 785  0
         boolean isValid = true;
 786  
 
 787  
         // TODO: this should invoke rules, sublclasses like the document view
 788  
         // should create the document add line event
 789  
 
 790  0
         return isValid;
 791  
     }
 792  
 
 793  
     /**
 794  
      * @see org.kuali.rice.krad.uif.service.ViewHelperService#processCollectionDeleteLine(org.kuali.rice.krad.uif.container.View,
 795  
      *      java.lang.Object, java.lang.String, int)
 796  
      */
 797  
     public void processCollectionDeleteLine(View view, Object model, String collectionPath, int lineIndex) {
 798  
         // get the collection group from the view
 799  0
         CollectionGroup collectionGroup = view.getViewIndex().getCollectionGroupByPath(collectionPath);
 800  0
         if (collectionGroup == null) {
 801  0
             logAndThrowRuntime("Unable to get collection group component for path: " + collectionPath);
 802  
         }
 803  
 
 804  
         // get the collection instance for adding the new line
 805  0
         Collection<Object> collection = ObjectPropertyUtils.getPropertyValue(model, collectionPath);
 806  0
         if (collection == null) {
 807  0
             logAndThrowRuntime("Unable to get collection property from model for path: " + collectionPath);
 808  
         }
 809  
 
 810  
         // TODO: look into other ways of identifying a line so we can deal with
 811  
         // unordered collections
 812  0
         if (collection instanceof List) {
 813  0
             Object deleteLine = ((List<Object>) collection).get(lineIndex);
 814  
 
 815  
             // validate the delete action is allowed for this line
 816  0
             boolean isValid = performDeleteLineValidation(view, collectionGroup, deleteLine);
 817  0
             if (isValid) {
 818  0
                 ((List<Object>) collection).remove(lineIndex);
 819  
             }
 820  0
         } else {
 821  0
             logAndThrowRuntime("Only List collection implementations are supported for the delete by index method");
 822  
         }
 823  0
     }
 824  
 
 825  
     /**
 826  
      * Performs validation on the collection line before it is removed from the
 827  
      * corresponding collection
 828  
      * 
 829  
      * @param view
 830  
      *            - view instance that the action was taken on
 831  
      * @param collectionGroup
 832  
      *            - collection group component for the collection
 833  
      * @param deleteLine
 834  
      *            - line that will be removed
 835  
      * @return boolean true if the action is allowed and the line should be
 836  
      *         removed, false if the line should not be removed
 837  
      */
 838  
     protected boolean performDeleteLineValidation(View view, CollectionGroup collectionGroup, Object deleteLine) {
 839  0
         boolean isValid = true;
 840  
 
 841  
         // TODO: this should invoke rules, sublclasses like the document view
 842  
         // should create the document delete line event
 843  
 
 844  0
         return isValid;
 845  
     }
 846  
 
 847  
     /**
 848  
      * Finds the <code>Inquirable</code> configured for the given data object
 849  
      * class and delegates to it for building the inquiry URL
 850  
      * 
 851  
      * @see org.kuali.rice.krad.uif.service.ViewHelperService#buildInquiryLink(java.lang.Object,
 852  
      *      java.lang.String, org.kuali.rice.krad.uif.widget.Inquiry)
 853  
      */
 854  
     public void buildInquiryLink(Object dataObject, String propertyName, Inquiry inquiry) {
 855  0
         Inquirable inquirable = getViewDictionaryService().getInquirable(dataObject.getClass(), inquiry.getViewName());
 856  0
         if (inquirable != null) {
 857  0
             inquirable.buildInquirableLink(dataObject, propertyName, inquiry);
 858  
         } else {
 859  
             // inquirable not found, no inquiry link can be set
 860  0
             inquiry.setRender(false);
 861  
         }
 862  0
     }
 863  
 
 864  
     /**
 865  
      * @see org.kuali.rice.krad.uif.service.ViewHelperService#applyDefaultValues(org.kuali.rice.krad.uif.container.View,
 866  
      *      org.kuali.rice.krad.web.form.UifFormBase)
 867  
      */
 868  
     public void applyDefaultValues(View view, UifFormBase model) {
 869  
         // retrieve all attribute fields for the view and apply their configured
 870  
         // default value to the model
 871  0
         Map<String, AttributeField> attributeFields = view.getViewIndex().getAttributeFieldIndex();
 872  0
         for (Entry<String, AttributeField> attributeFieldEntry : attributeFields.entrySet()) {
 873  0
             String bindingPath = attributeFieldEntry.getKey();
 874  0
             AttributeField attributeField = attributeFieldEntry.getValue();
 875  
 
 876  0
             populateDefaultValueForField(view, model, attributeField, bindingPath);
 877  0
         }
 878  
         
 879  
         // update form indicator
 880  0
         model.setDefaultsApplied(true);
 881  0
     }
 882  
     
 883  
     /**
 884  
      * @see org.kuali.rice.krad.uif.service.ViewHelperService#applyDefaultValuesForCollectionLine(org.kuali.rice.krad.uif.container.View,
 885  
      *      java.lang.Object, org.kuali.rice.krad.uif.container.CollectionGroup,
 886  
      *      java.lang.Object)
 887  
      */
 888  
     public void applyDefaultValuesForCollectionLine(View view, Object model, CollectionGroup collectionGroup,
 889  
             Object line) {
 890  
         // retrieve all attribute fields for the collection line
 891  0
         List<AttributeField> attributeFields = ComponentUtils.getComponentsOfTypeDeep(collectionGroup.getAddLineFields(),
 892  
                 AttributeField.class);
 893  0
         for (AttributeField attributeField : attributeFields) {
 894  0
             String bindingPath = "";
 895  0
             if (StringUtils.isNotBlank(attributeField.getBindingInfo().getBindByNamePrefix())) {
 896  0
                 bindingPath = attributeField.getBindingInfo().getBindByNamePrefix() + ".";
 897  
             }
 898  0
             bindingPath += attributeField.getBindingInfo().getBindingName();
 899  
 
 900  0
             populateDefaultValueForField(view, line, attributeField, bindingPath);
 901  0
         }
 902  0
     }
 903  
 
 904  
     /**
 905  
      * Applies the default value configured for the given field (if any) to the
 906  
      * line given object property that is determined by the given binding path
 907  
      * 
 908  
      * <p>
 909  
      * Checks for a configured default value or default value class for the
 910  
      * field. If both are given, the configured static default value will win.
 911  
      * In addition, if the default value contains an el expression it is
 912  
      * evaluated against the initial context
 913  
      * </p>
 914  
      * 
 915  
      * @param view
 916  
      *            - view instance the field belongs to
 917  
      * @param model
 918  
      *            - object that should be populated
 919  
      * @param attributeField
 920  
      *            - field to check for configured default value
 921  
      * @param bindingPath
 922  
      *            - path to the property on the object that should be populated
 923  
      */
 924  
     protected void populateDefaultValueForField(View view, Object object, AttributeField attributeField,
 925  
             String bindingPath) {
 926  
         // check for configured default value
 927  0
         String defaultValue = attributeField.getDefaultValue();
 928  0
         if (StringUtils.isBlank(defaultValue) && (attributeField.getDefaultValueFinderClass() != null)) {
 929  0
             ValueFinder defaultValueFinder = ObjectUtils.newInstance(attributeField.getDefaultValueFinderClass());
 930  0
             defaultValue = defaultValueFinder.getValue();
 931  
         }
 932  
 
 933  
         // populate default value if given and path is valid
 934  0
         if (StringUtils.isNotBlank(defaultValue) && ObjectPropertyUtils.isWritableProperty(object, bindingPath)) {
 935  0
             if (getExpressionEvaluatorService().containsElPlaceholder(defaultValue)) {
 936  0
                 Map<String, Object> context = getPreModelContext(view);
 937  0
                 defaultValue = getExpressionEvaluatorService().evaluateExpressionTemplate(null, context, defaultValue);
 938  
             }
 939  
 
 940  
             // TODO: this should go through our formatters
 941  0
             ObjectPropertyUtils.setPropertyValue(object, bindingPath, defaultValue);
 942  
         }
 943  0
     }
 944  
 
 945  
     /**
 946  
      * Hook for service overrides to perform custom initialization on the
 947  
      * component
 948  
      * 
 949  
      * @param view
 950  
      *            - view instance containing the component
 951  
      * @param component
 952  
      *            - component instance to initialize
 953  
      */
 954  
     protected void performCustomInitialization(View view, Component component) {
 955  
 
 956  0
     }
 957  
 
 958  
     /**
 959  
      * Hook for service overrides to perform custom apply model logic on the
 960  
      * component
 961  
      * 
 962  
      * @param view
 963  
      *            - view instance containing the component
 964  
      * @param component
 965  
      *            - component instance to apply model to
 966  
      * @param model
 967  
      *            - Top level object containing the data (could be the form or a
 968  
      *            top level business object, dto)
 969  
      */
 970  
     protected void performCustomApplyModel(View view, Component component, Object model) {
 971  
 
 972  0
     }
 973  
 
 974  
     /**
 975  
      * Hook for service overrides to perform custom component finalization
 976  
      * 
 977  
      * @param view
 978  
      *            - view instance containing the component
 979  
      * @param component
 980  
      *            - component instance to update
 981  
      * @param model
 982  
      *            - Top level object containing the data
 983  
      * @param parent
 984  
      *            - Parent component for the component being finalized
 985  
      */
 986  
     protected void performCustomFinalize(View view, Component component, Object model, Component parent) {
 987  
 
 988  0
     }
 989  
 
 990  
     /**
 991  
      * Hook for service overrides to process the new collection line before it
 992  
      * is added to the collection
 993  
      * 
 994  
      * @param view
 995  
      *            - view instance that is being presented (the action was taken
 996  
      *            on)
 997  
      * @param collectionGroup
 998  
      *            - collection group component for the collection the line will
 999  
      *            be added to
 1000  
      * @param model
 1001  
      *            - object instance that contain's the views data
 1002  
      * @param addLine
 1003  
      *            - the new line instance to be processed
 1004  
      */
 1005  
     protected void processBeforeAddLine(View view, CollectionGroup collectionGroup, Object model, Object addLine) {
 1006  
 
 1007  0
     }
 1008  
 
 1009  
     /**
 1010  
      * Hook for service overrides to process the new collection line after it
 1011  
      * has been added to the collection
 1012  
      * 
 1013  
      * @param view
 1014  
      *            - view instance that is being presented (the action was taken
 1015  
      *            on)
 1016  
      * @param collectionGroup
 1017  
      *            - collection group component for the collection the line that
 1018  
      *            was added
 1019  
      * @param model
 1020  
      *            - object instance that contain's the views data
 1021  
      * @param addLine
 1022  
      *            - the new line that was added
 1023  
      */
 1024  
     protected void processAfterAddLine(View view, CollectionGroup collectionGroup, Object model, Object addLine) {
 1025  
 
 1026  0
     }
 1027  
 
 1028  
     protected void logAndThrowRuntime(String message) {
 1029  0
         LOG.error(message);
 1030  0
         throw new RuntimeException(message);
 1031  
     }
 1032  
 
 1033  
     protected DataDictionaryService getDataDictionaryService() {
 1034  0
         if (this.dataDictionaryService == null) {
 1035  0
             this.dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
 1036  
         }
 1037  
 
 1038  0
         return this.dataDictionaryService;
 1039  
     }
 1040  
 
 1041  
     public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
 1042  0
         this.dataDictionaryService = dataDictionaryService;
 1043  0
     }
 1044  
 
 1045  
     protected ExpressionEvaluatorService getExpressionEvaluatorService() {
 1046  0
         if (this.expressionEvaluatorService == null) {
 1047  0
             this.expressionEvaluatorService = KRADServiceLocatorWeb.getExpressionEvaluatorService();
 1048  
         }
 1049  
 
 1050  0
         return this.expressionEvaluatorService;
 1051  
     }
 1052  
 
 1053  
     public void setExpressionEvaluatorService(ExpressionEvaluatorService expressionEvaluatorService) {
 1054  0
         this.expressionEvaluatorService = expressionEvaluatorService;
 1055  0
     }
 1056  
 
 1057  
     public ViewDictionaryService getViewDictionaryService() {
 1058  0
         if (this.viewDictionaryService == null) {
 1059  0
             this.viewDictionaryService = KRADServiceLocatorWeb.getViewDictionaryService();
 1060  
         }
 1061  0
         return this.viewDictionaryService;
 1062  
     }
 1063  
 
 1064  
     public void setViewDictionaryService(ViewDictionaryService viewDictionaryService) {
 1065  0
         this.viewDictionaryService = viewDictionaryService;
 1066  0
     }
 1067  
 }