View Javadoc

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 }