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.component; 12 13 import org.apache.commons.lang.StringUtils; 14 import org.kuali.rice.krad.uif.UifConstants; 15 import org.kuali.rice.krad.uif.view.View; 16 import org.kuali.rice.krad.util.ObjectUtils; 17 18 import java.io.Serializable; 19 20 /** 21 * Provides binding configuration for an DataBinding component (attribute or 22 * collection) 23 * 24 * <p> 25 * From the binding configuration the binding path is determined (if not 26 * manually set) and used to set the path in the UI or to get the value from the 27 * model 28 * </p> 29 * 30 * @author Kuali Rice Team (rice.collab@kuali.org) 31 */ 32 public class BindingInfo extends ConfigurableBase implements Serializable { 33 private static final long serialVersionUID = -7389398061672136091L; 34 35 private boolean bindToForm; 36 private boolean bindToMap; 37 38 private String bindingName; 39 private String bindByNamePrefix; 40 private String bindingObjectPath; 41 42 private String collectionPath; 43 44 private String bindingPath; 45 46 public BindingInfo() { 47 super(); 48 49 bindToForm = false; 50 bindToMap = false; 51 } 52 53 /** 54 * Sets up some default binding properties based on the view configuration 55 * and the component's property name 56 * 57 * <p> 58 * Sets the bindingName (if not set) to the given property name, and if the 59 * binding object path has not been set uses the default binding object path 60 * setup for the view 61 * </p> 62 * 63 * @param view 64 * - the view instance the component belongs to 65 * @param propertyName 66 * - name of the property (relative to the parent object) the 67 * component binds to 68 */ 69 public void setDefaults(View view, String propertyName) { 70 if (StringUtils.isBlank(bindingName)) { 71 bindingName = propertyName; 72 } 73 74 if (StringUtils.isBlank(bindingObjectPath)) { 75 bindingObjectPath = view.getDefaultBindingObjectPath(); 76 } 77 } 78 79 /** 80 * Path to the property on the model the component binds to. Uses standard 81 * dot notation for nested properties. If the binding path was manually set 82 * it will be returned as it is, otherwise the path will be formed by using 83 * the binding object path and the bind prefix 84 * 85 * <p> 86 * e.g. Property name 'foo' on a model would have binding path "foo", while 87 * property name 'name' of the nested model property 'account' would have 88 * binding path "account.name" 89 * </p> 90 * 91 * @return String binding path 92 */ 93 public String getBindingPath() { 94 if (StringUtils.isNotBlank(bindingPath)) { 95 return bindingPath; 96 } 97 98 String formedBindingPath = ""; 99 100 if (!bindToForm && StringUtils.isNotBlank(bindingObjectPath)) { 101 formedBindingPath = bindingObjectPath; 102 } 103 104 if (StringUtils.isNotBlank(bindByNamePrefix)) { 105 if (!bindByNamePrefix.startsWith("[") && StringUtils.isNotBlank(formedBindingPath)) { 106 formedBindingPath += "."; 107 } 108 formedBindingPath += bindByNamePrefix; 109 } 110 111 if (bindToMap) { 112 formedBindingPath += "['" + bindingName + "']"; 113 } else { 114 if (StringUtils.isNotBlank(formedBindingPath)) { 115 formedBindingPath += "."; 116 } 117 formedBindingPath += bindingName; 118 } 119 120 return formedBindingPath; 121 } 122 123 /** 124 * Returns the binding prefix string that can be used to setup the binding 125 * on <code>DataBinding</code> components that are children of the component 126 * that contains the <code>BindingInfo</code>. The binding prefix is formed 127 * like the binding path but without including the object path 128 * 129 * @return String binding prefix for nested components 130 */ 131 public String getBindingPrefixForNested() { 132 String bindingPrefix = ""; 133 134 if (StringUtils.isNotBlank(bindByNamePrefix)) { 135 bindingPrefix = bindByNamePrefix; 136 } 137 138 if (bindToMap) { 139 bindingPrefix += "['" + bindingName + "']"; 140 } else { 141 if (StringUtils.isNotBlank(bindingPrefix)) { 142 bindingPrefix += "."; 143 } 144 bindingPrefix += bindingName; 145 } 146 147 return bindingPrefix; 148 } 149 150 /** 151 * Returns the binding path that is formed by taking the binding configuration 152 * of this <code>BindingInfo</code> instance with the given property path as the 153 * binding name. This can be used to get the binding path when just a property 154 * name is given that is assumed to be on the same parent object of the field with 155 * the configured binding info 156 * 157 * <p> 158 * Special check is done for org.kuali.rice.krad.uif.UifConstants#NO_BIND_ADJUST_PREFIX prefix 159 * on the property name which indicates the property path is the full path and should 160 * not be adjusted. Also, if the property is prefixed with 161 * org.kuali.rice.krad.uif.UifConstants#DATA_OBJECT_BIND_ADJUST_PREFIX, this indicates we should only append the 162 * binding object path 163 * </p> 164 * 165 * @param propertyPath - path for property to return full binding path for 166 * @return String full binding path 167 */ 168 public String getPropertyAdjustedBindingPath(String propertyPath) { 169 if (propertyPath.startsWith(UifConstants.NO_BIND_ADJUST_PREFIX)) { 170 propertyPath = StringUtils.removeStart(propertyPath, UifConstants.NO_BIND_ADJUST_PREFIX); 171 return propertyPath; 172 } 173 174 BindingInfo bindingInfoCopy = (BindingInfo) ObjectUtils.deepCopy(this); 175 176 if (propertyPath.startsWith(UifConstants.DATA_OBJECT_BIND_ADJUST_PREFIX)) { 177 bindingInfoCopy.setBindByNamePrefix(""); 178 propertyPath = StringUtils.removeStart(propertyPath, UifConstants.DATA_OBJECT_BIND_ADJUST_PREFIX); 179 } 180 bindingInfoCopy.setBindingName(propertyPath); 181 182 return bindingInfoCopy.getBindingPath(); 183 } 184 185 /** 186 * Setter for the binding path. Can be left blank in which the path will be 187 * determined from the binding configuration 188 * 189 * @param bindingPath 190 */ 191 public void setBindingPath(String bindingPath) { 192 this.bindingPath = bindingPath; 193 } 194 195 /** 196 * Indicates whether the component binds directly to the form (that is its 197 * bindingName gives a property available through the form), or whether is 198 * binds through a nested form object. If bindToForm is false, it is assumed 199 * the component binds to the object given by the form property whose path 200 * is configured by bindingObjectPath. 201 * 202 * @return boolean true if component binds directly to form, false if it 203 * binds to a nested object 204 */ 205 public boolean isBindToForm() { 206 return this.bindToForm; 207 } 208 209 /** 210 * Setter for the bind to form indicator 211 * 212 * @param bindToForm 213 */ 214 public void setBindToForm(boolean bindToForm) { 215 this.bindToForm = bindToForm; 216 } 217 218 /** 219 * Gives the name of the property that the component binds to. The name can 220 * be nested but not the full path, just from the parent object or in the 221 * case of binding directly to the form from the form object 222 * 223 * <p> 224 * If blank this will be set from the name field of the component 225 * </p> 226 * 227 * @return String name of the bind property 228 */ 229 public String getBindingName() { 230 return this.bindingName; 231 } 232 233 /** 234 * Setter for the bind property name 235 * 236 * @param bindingName 237 */ 238 public void setBindingName(String bindingName) { 239 this.bindingName = bindingName; 240 } 241 242 /** 243 * Prefix that will be used to form the binding path from the component 244 * name. Typically used for nested collection properties 245 * 246 * @return String binding prefix 247 */ 248 public String getBindByNamePrefix() { 249 return this.bindByNamePrefix; 250 } 251 252 /** 253 * Setter for the prefix to use for forming the binding path by name 254 * 255 * @param bindByNamePrefix 256 */ 257 public void setBindByNamePrefix(String bindByNamePrefix) { 258 this.bindByNamePrefix = bindByNamePrefix; 259 } 260 261 /** 262 * If field is part of a collection field, gives path to collection 263 * 264 * <p> 265 * This is used for metadata purposes when getting finding the attribute 266 * definition from the dictionary and is not used in building the final 267 * binding path 268 * </p> 269 * 270 * @return String path to collection 271 */ 272 public String getCollectionPath() { 273 return this.collectionPath; 274 } 275 276 /** 277 * Setter for the field's collection path (if part of a collection) 278 * 279 * @param collectionPath 280 */ 281 public void setCollectionPath(String collectionPath) { 282 this.collectionPath = collectionPath; 283 } 284 285 /** 286 * For attribute fields that do not belong to the default form object (given 287 * by the view), this field specifies the path to the object (on the form) 288 * the attribute does belong to. 289 * 290 * <p> 291 * e.g. Say we have an attribute field with property name 'number', that 292 * belongs to the object given by the 'account' property on the form. The 293 * form object path would therefore be set to 'account'. If the property 294 * belonged to the object given by the 'document.header' property of the 295 * form, the binding object path would be set to 'document.header'. Note if 296 * the binding object path is not set for an attribute field (or any 297 * <code>DataBinding</code> component), the binding object path configured 298 * on the <code>View</code> will be used (unless bindToForm is set to true, 299 * where is assumed the property is directly available from the form). 300 * </p> 301 * 302 * @return String path to object from form 303 */ 304 public String getBindingObjectPath() { 305 return this.bindingObjectPath; 306 } 307 308 /** 309 * Setter for the object path on the form 310 * 311 * @param bindingObjectPath 312 */ 313 public void setBindingObjectPath(String bindingObjectPath) { 314 this.bindingObjectPath = bindingObjectPath; 315 } 316 317 /** 318 * Indicates whether the parent object for the property that we are binding 319 * to is a Map. If true the binding path will be adjusted to use the map key 320 * syntax 321 * 322 * @return boolean true if the property binds to a map, false if it does not 323 */ 324 public boolean isBindToMap() { 325 return this.bindToMap; 326 } 327 328 /** 329 * Setter for the bind to map indicator 330 * 331 * @param bindToMap 332 */ 333 public void setBindToMap(boolean bindToMap) { 334 this.bindToMap = bindToMap; 335 } 336 337 }