Coverage Report - org.kuali.rice.krad.uif.container.CollectionGroupBuilder
 
Classes in this File Line Coverage Branch Coverage Complexity
CollectionGroupBuilder
0%
0/153
0%
0/92
5.6
 
 1  
 /**
 2  
  * Copyright 2005-2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.krad.uif.container;
 17  
 
 18  
 import org.apache.commons.collections.ListUtils;
 19  
 import org.apache.commons.lang.StringUtils;
 20  
 import org.kuali.rice.core.api.mo.common.active.Inactivatable;
 21  
 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
 22  
 import org.kuali.rice.krad.uif.UifConstants;
 23  
 import org.kuali.rice.krad.uif.UifParameters;
 24  
 import org.kuali.rice.krad.uif.UifPropertyPaths;
 25  
 import org.kuali.rice.krad.uif.control.Control;
 26  
 import org.kuali.rice.krad.uif.component.DataBinding;
 27  
 import org.kuali.rice.krad.uif.field.ActionField;
 28  
 import org.kuali.rice.krad.uif.field.InputField;
 29  
 import org.kuali.rice.krad.uif.field.Field;
 30  
 import org.kuali.rice.krad.uif.field.FieldGroup;
 31  
 import org.kuali.rice.krad.uif.layout.CollectionLayoutManager;
 32  
 import org.kuali.rice.krad.uif.service.ExpressionEvaluatorService;
 33  
 import org.kuali.rice.krad.uif.util.ComponentUtils;
 34  
 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
 35  
 import org.kuali.rice.krad.uif.view.View;
 36  
 import org.kuali.rice.krad.util.KRADUtils;
 37  
 import org.kuali.rice.krad.util.ObjectUtils;
 38  
 import org.kuali.rice.krad.web.form.UifFormBase;
 39  
 
 40  
 import java.io.Serializable;
 41  
 import java.util.ArrayList;
 42  
 import java.util.Collection;
 43  
 import java.util.HashMap;
 44  
 import java.util.List;
 45  
 import java.util.Map;
 46  
 
 47  
 /**
 48  
  * Builds out the <code>Field</code> instances for a collection group with a
 49  
  * series of steps that interact with the configured
 50  
  * <code>CollectionLayoutManager</code> to assemble the fields as necessary for
 51  
  * the layout
 52  
  * 
 53  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 54  
  */
 55  0
 public class CollectionGroupBuilder implements Serializable {
 56  
         private static final long serialVersionUID = -4762031957079895244L;
 57  
 
 58  
         /**
 59  
          * Creates the <code>Field</code> instances that make up the table
 60  
          * 
 61  
          * <p>
 62  
          * The corresponding collection is retrieved from the model and iterated
 63  
          * over to create the necessary fields. The binding path for fields that
 64  
          * implement <code>DataBinding</code> is adjusted to point to the collection
 65  
          * line it is apart of. For example, field 'number' of collection 'accounts'
 66  
          * for line 1 will be set to 'accounts[0].number', and for line 2
 67  
          * 'accounts[1].number'. Finally parameters are set on the line's action
 68  
          * fields to indicate what collection and line they apply to.
 69  
          * </p>
 70  
          * 
 71  
          * @param view
 72  
          *            - View instance the collection belongs to
 73  
          * @param model
 74  
          *            - Top level object containing the data
 75  
          * @param collectionGroup
 76  
          *            - CollectionGroup component for the collection
 77  
          */
 78  
     public void build(View view, Object model, CollectionGroup collectionGroup) {
 79  
         // create add line
 80  0
         if (collectionGroup.isRenderAddLine() && !collectionGroup.isReadOnly()) {
 81  0
             buildAddLine(view, model, collectionGroup);
 82  
         }
 83  
 
 84  
         // get the collection for this group from the model
 85  0
         List<Object> modelCollection = ObjectPropertyUtils.getPropertyValue(model, ((DataBinding) collectionGroup)
 86  
                 .getBindingInfo().getBindingPath());
 87  
 
 88  0
         if (modelCollection != null) {
 89  
             // filter inactive model
 90  0
             List<Integer> showIndexes = performCollectionFiltering(view, model, collectionGroup, modelCollection);
 91  
 
 92  
             // for each collection row build the line fields
 93  0
             for (int index = 0; index < modelCollection.size(); index++) {
 94  
                 // display only records that passed filtering
 95  0
                 if (showIndexes.contains(index)) {
 96  0
                     String bindingPathPrefix = collectionGroup.getBindingInfo().getBindingName() + "[" + index + "]";
 97  0
                     if (StringUtils.isNotBlank(collectionGroup.getBindingInfo().getBindByNamePrefix())) {
 98  0
                         bindingPathPrefix =
 99  
                                 collectionGroup.getBindingInfo().getBindByNamePrefix() + "." + bindingPathPrefix;
 100  
                     }
 101  
 
 102  0
                     Object currentLine = modelCollection.get(index);
 103  
 
 104  0
                     List<ActionField> actions = getLineActions(view, model, collectionGroup, currentLine, index);
 105  0
                     buildLine(view, model, collectionGroup, bindingPathPrefix, actions, false, currentLine, index);
 106  
                 }
 107  
             }
 108  
         }
 109  0
     }
 110  
 
 111  
     /**
 112  
      * Performs any filtering necessary on the collection before building the collection fields
 113  
      *
 114  
      * <p>
 115  
      * If showInactive is set to false and the collection line type implements <code>Inactivatable</code>,
 116  
      * invokes the active collection filter. Then any {@link CollectionFilter} instances configured for the collection
 117  
      * group are invoked to filter the collection. Collections lines must pass all filters in order to be
 118  
      * displayed
 119  
      * </p>
 120  
      *
 121  
      * @param view - view instance that contains the collection
 122  
      * @param model - object containing the views data
 123  
      * @param collectionGroup - collection group component instance that will display the collection
 124  
      * @param collection - collection instance that will be filtered
 125  
      */
 126  
     protected List<Integer> performCollectionFiltering(View view, Object model, CollectionGroup collectionGroup,
 127  
             Collection<?> collection) {
 128  0
         List<Integer> filteredIndexes = new ArrayList<Integer>();
 129  0
         for (int i = 0; i < collection.size(); i++) {
 130  0
             filteredIndexes.add(new Integer(i));
 131  
         }
 132  
 
 133  0
         if (Inactivatable.class.isAssignableFrom(collectionGroup.getCollectionObjectClass()) && !collectionGroup
 134  
                 .isShowInactive()) {
 135  0
             List<Integer> activeIndexes = collectionGroup.getActiveCollectionFilter().filter(view, model,
 136  
                     collectionGroup);
 137  0
             filteredIndexes = ListUtils.intersection(filteredIndexes, activeIndexes);
 138  
         }
 139  
 
 140  0
         for (CollectionFilter collectionFilter : collectionGroup.getFilters()) {
 141  0
             List<Integer> indexes = collectionFilter.filter(view, model, collectionGroup);
 142  0
             filteredIndexes = ListUtils.intersection(filteredIndexes, indexes);
 143  0
             if (filteredIndexes.isEmpty()) {
 144  0
                 break;
 145  
             }
 146  0
         }
 147  
 
 148  0
         return filteredIndexes;
 149  
     }
 150  
 
 151  
         /**
 152  
          * Builds the fields for holding the collection add line and if necessary
 153  
          * makes call to setup the new line instance
 154  
          * 
 155  
          * @param view
 156  
          *            - view instance the collection belongs to
 157  
          * @param collectionGroup
 158  
          *            - collection group the layout manager applies to
 159  
          * @param model
 160  
          *            - Object containing the view data, should extend UifFormBase
 161  
          *            if using framework managed new lines
 162  
          */
 163  
     protected void buildAddLine(View view, Object model, CollectionGroup collectionGroup) {
 164  0
         boolean addLineBindsToForm = false;
 165  
 
 166  
         // initialize new line if one does not already exist
 167  0
         initializeNewCollectionLine(view, model, collectionGroup, false);
 168  
 
 169  
         // determine whether the add line binds to the generic form map or a
 170  
         // specified property
 171  0
         if (StringUtils.isBlank(collectionGroup.getAddLinePropertyName())) {
 172  0
             addLineBindsToForm = true;
 173  
         }
 174  
 
 175  0
         String addLineBindingPath = collectionGroup.getAddLineBindingInfo().getBindingPath();
 176  0
         List<ActionField> actions = getAddLineActions(view, model, collectionGroup);
 177  
 
 178  0
         Object addLine = ObjectPropertyUtils.getPropertyValue(model, addLineBindingPath);
 179  0
         buildLine(view, model, collectionGroup, addLineBindingPath, actions, addLineBindsToForm, addLine, -1);
 180  0
     }
 181  
 
 182  
         /**
 183  
          * Builds the field instances for the collection line. A copy of the
 184  
          * configured items on the <code>CollectionGroup</code> is made and adjusted
 185  
          * for the line (id and binding). Then a call is made to the
 186  
          * <code>CollectionLayoutManager</code> to assemble the line as necessary
 187  
          * for the layout
 188  
          * 
 189  
          * @param view
 190  
          *            - view instance the collection belongs to
 191  
          * @param model
 192  
          *            - top level object containing the data
 193  
          * @param collectionGroup
 194  
          *            - collection group component for the collection
 195  
          * @param bindingPath
 196  
          *            - binding path for the line fields (if DataBinding)
 197  
          * @param actions
 198  
          *            - List of actions to set in the lines action column
 199  
          * @param bindToForm
 200  
          *            - whether the bindToForm property on the items bindingInfo
 201  
          *            should be set to true (needed for add line)
 202  
          * @param currentLine
 203  
          *            - object instance for the current line, or null if add line
 204  
          * @param lineIndex
 205  
          *            - index of the line in the collection, or -1 if we are
 206  
          *            building the add line
 207  
          */
 208  
         @SuppressWarnings("unchecked")
 209  
         protected void buildLine(View view, Object model, CollectionGroup collectionGroup, String bindingPath,
 210  
                         List<ActionField> actions, boolean bindToForm, Object currentLine, int lineIndex) {
 211  0
                 CollectionLayoutManager layoutManager = (CollectionLayoutManager) collectionGroup.getLayoutManager();
 212  
 
 213  
                 // copy group items for new line
 214  0
         List<Field> lineFields = (List<Field>) collectionGroup.getItems();
 215  0
         String lineSuffix = UifConstants.IdSuffixes.LINE + Integer.toString(lineIndex);
 216  0
         if (lineIndex == -1) {
 217  0
             lineFields = (List<Field>) collectionGroup.getAddLineFields();
 218  0
             lineSuffix = UifConstants.IdSuffixes.ADD_LINE;
 219  
         }
 220  0
         if (StringUtils.isNotBlank(collectionGroup.getSubCollectionSuffix())) {
 221  0
             lineSuffix = collectionGroup.getSubCollectionSuffix() + lineSuffix;
 222  
         }
 223  
 
 224  0
         lineFields = (List<Field>) ComponentUtils.copyFieldList(lineFields, bindingPath, lineSuffix);
 225  
 
 226  0
                 if(lineIndex == -1 && !lineFields.isEmpty()){
 227  0
                     for(Field f: lineFields){
 228  0
                         if(f instanceof InputField){
 229  
                             //sets up - skipping these fields in add area during standard form validation calls
 230  
                             //custom addLineToCollection js call will validate these fields manually on an add
 231  0
                                 Control control = ((InputField) f).getControl();
 232  0
                                 if (control != null) {
 233  0
                                     control.addStyleClass(collectionGroup.getFactoryId() + "-addField");
 234  0
                                         control.addStyleClass("ignoreValid");
 235  
                                 }
 236  0
                         }
 237  
                     }
 238  0
                     for(ActionField action: actions){
 239  0
                         if(action.getActionParameter(UifParameters.ACTION_TYPE).equals(UifParameters.ADD_LINE)){
 240  0
                             action.setFocusOnAfterSubmit(lineFields.get(0).getId());
 241  
                         }
 242  
                     }
 243  
                 }
 244  
                 
 245  0
                 ComponentUtils.updateContextsForLine(lineFields, currentLine, lineIndex);
 246  
 
 247  0
                 if (bindToForm) {
 248  0
                         ComponentUtils.setComponentsPropertyDeep(lineFields, UifPropertyPaths.BIND_TO_FORM, new Boolean(true));
 249  
                 }                
 250  
                 
 251  
         // remove fields from the line that have render false
 252  0
         lineFields = removeNonRenderLineFields(view, model, collectionGroup, lineFields, currentLine, lineIndex);
 253  
 
 254  
                 // if not add line build sub-collection field groups
 255  0
                 List<FieldGroup> subCollectionFields = new ArrayList<FieldGroup>();
 256  0
         if ((lineIndex != -1) && (collectionGroup.getSubCollections() != null)) {
 257  0
             for (int subLineIndex = 0; subLineIndex < collectionGroup.getSubCollections().size(); subLineIndex++) {
 258  0
                 CollectionGroup subCollectionPrototype = collectionGroup.getSubCollections().get(subLineIndex);
 259  0
                 CollectionGroup subCollectionGroup = ComponentUtils.copy(subCollectionPrototype, lineSuffix);
 260  
 
 261  
                 // verify the sub-collection should be rendered
 262  0
                 boolean renderSubCollection = checkSubCollectionRender(view, model, collectionGroup,
 263  
                         subCollectionGroup);
 264  0
                 if (!renderSubCollection) {
 265  0
                     continue;
 266  
                 }
 267  
 
 268  0
                 subCollectionGroup.getBindingInfo().setBindByNamePrefix(bindingPath);
 269  0
                 if (subCollectionGroup.isRenderAddLine()) {
 270  0
                     subCollectionGroup.getAddLineBindingInfo().setBindByNamePrefix(bindingPath);
 271  
                 }
 272  
 
 273  
                 // set sub-collection suffix on group so it can be used for generated groups
 274  0
                 String subCollectionSuffix = lineSuffix;
 275  0
                 if (StringUtils.isNotBlank(subCollectionGroup.getSubCollectionSuffix())) {
 276  0
                     subCollectionSuffix = subCollectionGroup.getSubCollectionSuffix() + lineSuffix;
 277  
                 }
 278  0
                 subCollectionGroup.setSubCollectionSuffix(subCollectionSuffix);
 279  
 
 280  0
                 FieldGroup fieldGroupPrototype = layoutManager.getSubCollectionFieldGroupPrototype();
 281  0
                 FieldGroup subCollectionFieldGroup = ComponentUtils.copy(fieldGroupPrototype,
 282  
                         lineSuffix + UifConstants.IdSuffixes.SUB + subLineIndex);
 283  0
                 subCollectionFieldGroup.setGroup(subCollectionGroup);
 284  
 
 285  0
                 subCollectionFields.add(subCollectionFieldGroup);
 286  
             }
 287  
         }
 288  
 
 289  
                 // invoke layout manager to build the complete line
 290  0
                 layoutManager.buildLine(view, model, collectionGroup, lineFields, subCollectionFields, bindingPath, actions,
 291  
                                 lineSuffix, currentLine, lineIndex);
 292  0
         }
 293  
 
 294  
         
 295  
     /**
 296  
      * Evaluates the render property for the given list of <code>Field</code>
 297  
      * instances for the line and removes any fields from the returned list that
 298  
      * have render false. The conditional render string is also taken into
 299  
      * account. This needs to be done here as opposed to during the normal
 300  
      * condition evaluation so the the fields are not used while building the
 301  
      * collection lines
 302  
      * 
 303  
      * @param view
 304  
      *            - view instance the collection group belongs to
 305  
      * @param model
 306  
      *            - object containing the view data
 307  
      * @param collectionGroup
 308  
      *            - collection group for the line fields
 309  
      * @param lineFields
 310  
      *            - list of fields configured for the line
 311  
      * @param currentLine
 312  
      *            - object containing the line data
 313  
      * @param lineIndex
 314  
      *            - index of the line in the collection
 315  
      * @return List<Field> list of field instances that should be rendered
 316  
      */
 317  
     protected List<Field> removeNonRenderLineFields(View view, Object model, CollectionGroup collectionGroup,
 318  
             List<Field> lineFields, Object currentLine, int lineIndex) {
 319  0
         List<Field> fields = new ArrayList<Field>();
 320  
 
 321  0
         for (Field lineField : lineFields) {
 322  0
             String conditionalRender = lineField.getPropertyExpression("render");
 323  
 
 324  
             // evaluate conditional render string if set
 325  0
             if (StringUtils.isNotBlank(conditionalRender)) {
 326  0
                 Map<String, Object> context = new HashMap<String, Object>();
 327  0
                 context.putAll(view.getContext());
 328  0
                 context.put(UifConstants.ContextVariableNames.PARENT, collectionGroup);
 329  0
                 context.put(UifConstants.ContextVariableNames.COMPONENT, lineField);
 330  0
                 context.put(UifConstants.ContextVariableNames.LINE, currentLine);
 331  0
                 context.put(UifConstants.ContextVariableNames.INDEX, new Integer(lineIndex));
 332  0
                 context.put(UifConstants.ContextVariableNames.IS_ADD_LINE, new Boolean(lineIndex == -1));
 333  
 
 334  0
                 Boolean render = (Boolean) getExpressionEvaluatorService().evaluateExpression(model, context,
 335  
                         conditionalRender);
 336  0
                 lineField.setRender(render);
 337  
             }
 338  
 
 339  
             // only add line field if set to render or if it is hidden by progressive render
 340  0
             if (lineField.isRender() || StringUtils.isNotBlank(lineField.getProgressiveRender())) {
 341  0
                 fields.add(lineField);
 342  
             }
 343  0
         }
 344  
 
 345  0
         return fields;
 346  
     }
 347  
     
 348  
     /**
 349  
      * Checks whether the given sub-collection should be rendered, any
 350  
      * conditional render string is evaluated
 351  
      * 
 352  
      * @param view
 353  
      *            - view instance the sub collection belongs to
 354  
      * @param model
 355  
      *            - object containing the view data
 356  
      * @param collectionGroup
 357  
      *            - collection group the sub collection belongs to
 358  
      * @param subCollectionGroup
 359  
      *            - sub collection group to check render status for
 360  
      * @return boolean true if sub collection should be rendered, false if it
 361  
      *         should not be rendered
 362  
      */
 363  
     protected boolean checkSubCollectionRender(View view, Object model, CollectionGroup collectionGroup,
 364  
             CollectionGroup subCollectionGroup) {
 365  0
         String conditionalRender = subCollectionGroup.getPropertyExpression("render");
 366  
 
 367  
         // evaluate conditional render string if set
 368  0
         if (StringUtils.isNotBlank(conditionalRender)) {
 369  0
             Map<String, Object> context = new HashMap<String, Object>();
 370  0
             context.putAll(view.getContext());
 371  0
             context.put(UifConstants.ContextVariableNames.PARENT, collectionGroup);
 372  0
             context.put(UifConstants.ContextVariableNames.COMPONENT, subCollectionGroup);
 373  
 
 374  0
             Boolean render = (Boolean) getExpressionEvaluatorService().evaluateExpression(model, context,
 375  
                     conditionalRender);
 376  0
             subCollectionGroup.setRender(render);
 377  
         }
 378  
 
 379  0
         return subCollectionGroup.isRender();
 380  
     }
 381  
 
 382  
         /**
 383  
          * Creates new <code>ActionField</code> instances for the line
 384  
          * 
 385  
          * <p>
 386  
          * Adds context to the action fields for the given line so that the line the
 387  
          * action was performed on can be determined when that action is selected
 388  
          * </p>
 389  
          * 
 390  
          * @param view
 391  
          *            - view instance the collection belongs to
 392  
          * @param model
 393  
          *            - top level object containing the data
 394  
          * @param collectionGroup
 395  
          *            - collection group component for the collection
 396  
          * @param collectionLine
 397  
          *            - object instance for the current line
 398  
          * @param lineIndex
 399  
          *            - index of the line the actions should apply to
 400  
          */
 401  
         protected List<ActionField> getLineActions(View view, Object model, CollectionGroup collectionGroup,
 402  
                         Object collectionLine, int lineIndex) {
 403  0
                 List<ActionField> lineActions = ComponentUtils.copyFieldList(collectionGroup.getActionFields(), Integer.toString(lineIndex));
 404  0
                 for (ActionField actionField : lineActions) {
 405  0
                         actionField.addActionParameter(UifParameters.SELLECTED_COLLECTION_PATH, collectionGroup.getBindingInfo()
 406  
                                         .getBindingPath());
 407  0
                         actionField.addActionParameter(UifParameters.SELECTED_LINE_INDEX, Integer.toString(lineIndex));
 408  0
                         actionField.setJumpToIdAfterSubmit(collectionGroup.getId() + "_div");
 409  
 
 410  0
             actionField.setClientSideJs("performCollectionAction('"+collectionGroup.getId()+"');");
 411  
                 }
 412  
 
 413  0
                 ComponentUtils.updateContextsForLine(lineActions, collectionLine, lineIndex);
 414  
 
 415  0
                 return lineActions;
 416  
         }
 417  
 
 418  
         /**
 419  
          * Creates new <code>ActionField</code> instances for the add line
 420  
          * 
 421  
          * <p>
 422  
          * Adds context to the action fields for the add line so that the collection
 423  
          * the action was performed on can be determined
 424  
          * </p>
 425  
          * 
 426  
          * @param view
 427  
          *            - view instance the collection belongs to
 428  
          * @param model
 429  
          *            - top level object containing the data
 430  
          * @param collectionGroup
 431  
          *            - collection group component for the collection
 432  
          */
 433  
         protected List<ActionField> getAddLineActions(View view, Object model, CollectionGroup collectionGroup) {
 434  0
                 List<ActionField> lineActions = ComponentUtils.copyFieldList(collectionGroup.getAddLineActionFields(), "_add");
 435  0
                 for (ActionField actionField : lineActions) {
 436  0
                         actionField.addActionParameter(UifParameters.SELLECTED_COLLECTION_PATH, collectionGroup.getBindingInfo()
 437  
                                         .getBindingPath());
 438  
                         //actionField.addActionParameter(UifParameters.COLLECTION_ID, collectionGroup.getId());
 439  0
                         actionField.setJumpToIdAfterSubmit(collectionGroup.getId() + "_div");
 440  0
                         actionField.addActionParameter(UifParameters.ACTION_TYPE, UifParameters.ADD_LINE);
 441  
 
 442  0
             String baseId = collectionGroup.getFactoryId();
 443  0
             if (StringUtils.isNotBlank(collectionGroup.getSubCollectionSuffix())) {
 444  0
                 baseId += collectionGroup.getSubCollectionSuffix();
 445  
             }
 446  
 
 447  0
             actionField.setClientSideJs("addLineToCollection('"+collectionGroup.getId()+"', '"+ baseId +"');");
 448  0
                 }
 449  
 
 450  
                 // get add line for context
 451  0
                 String addLinePath = collectionGroup.getAddLineBindingInfo().getBindingPath();
 452  0
                 Object addLine = ObjectPropertyUtils.getPropertyValue(model, addLinePath);
 453  
 
 454  0
                 ComponentUtils.updateContextsForLine(lineActions, addLine, -1);
 455  
 
 456  0
                 return lineActions;
 457  
         }
 458  
 
 459  
     /**
 460  
      * Initializes a new instance of the collection class
 461  
      * 
 462  
      * <p>
 463  
      * If the add line property was not specified for the collection group the
 464  
      * new lines will be added to the generic map on the
 465  
      * <code>UifFormBase</code>, else it will be added to the property given by
 466  
      * the addLineBindingInfo
 467  
      * </p>
 468  
      * 
 469  
      * <p>
 470  
      * New line will only be created if the current line property is null or
 471  
      * clearExistingLine is true. In the case of a new line default values are
 472  
      * also applied
 473  
      * </p>
 474  
      * 
 475  
      * @see org.kuali.rice.krad.uif.container.CollectionGroup#
 476  
      *      initializeNewCollectionLine(View, Object, CollectionGroup, boolean)
 477  
      */
 478  
     public void initializeNewCollectionLine(View view, Object model, CollectionGroup collectionGroup,
 479  
             boolean clearExistingLine) {
 480  0
         Object newLine = null;
 481  
 
 482  
         // determine if we are binding to generic form map or a custom property
 483  0
         if (StringUtils.isBlank(collectionGroup.getAddLinePropertyName())) {
 484  
             // bind to form map
 485  0
             if (!(model instanceof UifFormBase)) {
 486  0
                 throw new RuntimeException("Cannot create new collection line for group: "
 487  
                         + collectionGroup.getPropertyName() + ". Model does not extend " + UifFormBase.class.getName());
 488  
             }
 489  
 
 490  
             // get new collection line map from form
 491  0
             Map<String, Object> newCollectionLines = ObjectPropertyUtils.getPropertyValue(model,
 492  
                     UifPropertyPaths.NEW_COLLECTION_LINES);
 493  0
             if (newCollectionLines == null) {
 494  0
                 newCollectionLines = new HashMap<String, Object>();
 495  0
                 ObjectPropertyUtils.setPropertyValue(model, UifPropertyPaths.NEW_COLLECTION_LINES, newCollectionLines);
 496  
             }
 497  
             
 498  
             // set binding path for add line
 499  0
             String newCollectionLineKey = KRADUtils
 500  
                     .translateToMapSafeKey(collectionGroup.getBindingInfo().getBindingPath());
 501  0
             String addLineBindingPath = UifPropertyPaths.NEW_COLLECTION_LINES + "['" + newCollectionLineKey + "']";
 502  0
             collectionGroup.getAddLineBindingInfo().setBindingPath(addLineBindingPath);
 503  
 
 504  
             // if there is not an instance available or we need to clear create
 505  
             // a new instance
 506  0
             if (!newCollectionLines.containsKey(newCollectionLineKey)
 507  
                     || (newCollectionLines.get(newCollectionLineKey) == null) || clearExistingLine) {
 508  
                 // create new instance of the collection type for the add line
 509  0
                 newLine = ObjectUtils.newInstance(collectionGroup.getCollectionObjectClass());
 510  0
                 newCollectionLines.put(newCollectionLineKey, newLine);
 511  
             }
 512  0
         } else {
 513  
             // bind to custom property
 514  0
             Object addLine = ObjectPropertyUtils.getPropertyValue(model, collectionGroup.getAddLineBindingInfo()
 515  
                     .getBindingPath());
 516  0
             if ((addLine == null) || clearExistingLine) {
 517  0
                 newLine = ObjectUtils.newInstance(collectionGroup.getCollectionObjectClass());
 518  0
                 ObjectPropertyUtils.setPropertyValue(model, collectionGroup.getAddLineBindingInfo().getBindingPath(),
 519  
                         newLine);
 520  
             }
 521  
         }
 522  
 
 523  
         // apply default values if a new line was created
 524  0
         if (newLine != null) {
 525  0
             view.getViewHelperService().applyDefaultValuesForCollectionLine(view, model, collectionGroup, newLine);
 526  
         }
 527  0
     }
 528  
     
 529  
     protected ExpressionEvaluatorService getExpressionEvaluatorService() {
 530  0
         return KRADServiceLocatorWeb.getExpressionEvaluatorService();
 531  
     }
 532  
 
 533  
 }