View Javadoc

1   /**
2    * Copyright 2005-2013 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.field;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.krad.uif.component.BindingInfo;
20  import org.kuali.rice.krad.uif.component.MethodInvokerConfig;
21  
22  import java.io.Serializable;
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.Map;
27  
28  /**
29   * Holds configuration for executing a dynamic query on an <code>InputField</code> to
30   * pull data for updating the UI
31   *
32   * <p>
33   * There are two types of query types that can be configured and executed. The first is provided
34   * completely by the framework using the <code>LookupService</code> and will perform a query
35   * against the configured dataObjectClassName using the query parameters and return field mapping.
36   * The second type will invoke a method that will perform the query. This can be configured using the
37   * queryMethodToCall (if the method is on the view helper service), or using the queryMethodInvoker if
38   * the method is on another class or object.
39   * </p>
40   *
41   * @author Kuali Rice Team (rice.collab@kuali.org)
42   */
43  public class AttributeQuery implements Serializable {
44      private static final long serialVersionUID = -4569905665441735255L;
45  
46      private String dataObjectClassName;
47  
48      private boolean renderNotFoundMessage;
49      private String returnMessageText;
50      private String returnMessageStyleClasses;
51  
52      private Map<String, String> queryFieldMapping;
53      private Map<String, String> returnFieldMapping;
54      private Map<String, String> additionalCriteria;
55  
56      private List<String> sortPropertyNames;
57  
58      private String queryMethodToCall;
59      private List<String> queryMethodArgumentFieldList;
60      private MethodInvokerConfig queryMethodInvokerConfig;
61  
62      public AttributeQuery() {
63          renderNotFoundMessage = true;
64          queryFieldMapping = new HashMap<String, String>();
65          returnFieldMapping = new HashMap<String, String>();
66          additionalCriteria = new HashMap<String, String>();
67          sortPropertyNames = new ArrayList<String>();
68          queryMethodArgumentFieldList = new ArrayList<String>();
69      }
70  
71      /**
72       * Adjusts the path on the query field mapping from property to match the binding
73       * path prefix of the given <code>BindingInfo</code>
74       *
75       * @param bindingInfo - binding info instance to copy binding path prefix from
76       */
77      public void updateQueryFieldMapping(BindingInfo bindingInfo) {
78          Map<String, String> adjustedQueryFieldMapping = new HashMap<String, String>();
79          for (String fromFieldPath : getQueryFieldMapping().keySet()) {
80              String toField = getQueryFieldMapping().get(fromFieldPath);
81              String adjustedFromFieldPath = bindingInfo.getPropertyAdjustedBindingPath(fromFieldPath);
82  
83              adjustedQueryFieldMapping.put(adjustedFromFieldPath, toField);
84          }
85  
86          this.queryFieldMapping = adjustedQueryFieldMapping;
87      }
88  
89      /**
90       * Adjusts the path on the return field mapping to property to match the binding
91       * path prefix of the given <code>BindingInfo</code>
92       *
93       * @param bindingInfo - binding info instance to copy binding path prefix from
94       */
95      public void updateReturnFieldMapping(BindingInfo bindingInfo) {
96          Map<String, String> adjustedReturnFieldMapping = new HashMap<String, String>();
97          for (String fromFieldPath : getReturnFieldMapping().keySet()) {
98              String toFieldPath = getReturnFieldMapping().get(fromFieldPath);
99              String adjustedToFieldPath = bindingInfo.getPropertyAdjustedBindingPath(toFieldPath);
100 
101             adjustedReturnFieldMapping.put(fromFieldPath, adjustedToFieldPath);
102         }
103 
104         this.returnFieldMapping = adjustedReturnFieldMapping;
105     }
106 
107     /**
108      * Adjusts the path on the query method arguments field list to match the binding
109      * path prefix of the given <code>BindingInfo</code>
110      *
111      * @param bindingInfo - binding info instance to copy binding path prefix from
112      */
113     public void updateQueryMethodArgumentFieldList(BindingInfo bindingInfo) {
114         List<String> adjustedArgumentFieldList = new ArrayList<String>();
115         for (String argumentFieldPath : getQueryMethodArgumentFieldList()) {
116             String adjustedFieldPath = bindingInfo.getPropertyAdjustedBindingPath(argumentFieldPath);
117             adjustedArgumentFieldList.add(adjustedFieldPath);
118         }
119 
120         this.queryMethodArgumentFieldList = adjustedArgumentFieldList;
121     }
122 
123     /**
124      * Builds String for passing the queryFieldMapping Map as a Javascript object
125      * parameter
126      *
127      * @return String js parameter string
128      */
129     public String getQueryFieldMappingJsString() {
130         String queryFieldMappingJs = "{";
131 
132         for (String queryField : queryFieldMapping.keySet()) {
133             if (!StringUtils.equals(queryFieldMappingJs, "{")) {
134                 queryFieldMappingJs += ",";
135             }
136 
137             queryFieldMappingJs += "\"" + queryField + "\":\"" + queryFieldMapping.get(queryField) + "\"";
138         }
139 
140         queryFieldMappingJs += "}";
141 
142         return queryFieldMappingJs;
143     }
144 
145     /**
146      * Builds String for passing the returnFieldMapping Map as a Javascript object
147      * parameter
148      *
149      * @return String js parameter string
150      */
151     public String getReturnFieldMappingJsString() {
152         String returnFieldMappingJs = "{";
153 
154         for (String fromField : returnFieldMapping.keySet()) {
155             if (!StringUtils.equals(returnFieldMappingJs, "{")) {
156                 returnFieldMappingJs += ",";
157             }
158 
159             returnFieldMappingJs += "\"" + returnFieldMapping.get(fromField) + "\":\"" + fromField + "\"";
160         }
161 
162         returnFieldMappingJs += "}";
163 
164         return returnFieldMappingJs;
165     }
166 
167     /**
168      * Builds String for passing the queryMethodArgumentFieldList as a Javascript array
169      *
170      * @return String js parameter string
171      */
172     public String getQueryMethodArgumentFieldsJsString() {
173         String queryMethodArgsJs = "[";
174 
175         for (String methodArg : queryMethodArgumentFieldList) {
176             if (!StringUtils.equals(queryMethodArgsJs, "{")) {
177                 queryMethodArgsJs += ",";
178             }
179             queryMethodArgsJs += "\"" + methodArg + "\"";
180         }
181 
182         queryMethodArgsJs += "]";
183 
184         return queryMethodArgsJs;
185     }
186 
187     /**
188      * Indicates whether this attribute query is configured to invoke a custom
189      * method as opposed to running the general object query. If either the query method
190      * to call is given, or the query method invoker is not null it is assumed the
191      * intention is to call a custom method
192      *
193      * @return boolean true if a custom method is configured, false if not
194      */
195     public boolean hasConfiguredMethod() {
196         boolean configuredMethod = false;
197 
198         if (StringUtils.isNotBlank(getQueryMethodToCall())) {
199             configuredMethod = true;
200         } else if (getQueryMethodInvokerConfig() != null) {
201             configuredMethod = true;
202         }
203 
204         return configuredMethod;
205     }
206 
207     /**
208      * Class name for the data object the query should be performed against
209      *
210      * @return String data object class name
211      */
212     public String getDataObjectClassName() {
213         return dataObjectClassName;
214     }
215 
216     /**
217      * Setter for the query data object class name
218      *
219      * @param dataObjectClassName
220      */
221     public void setDataObjectClassName(String dataObjectClassName) {
222         this.dataObjectClassName = dataObjectClassName;
223     }
224 
225     /**
226      * Configures the query parameters by mapping fields in the view
227      * to properties on the data object class for the query
228      *
229      * <p>
230      * Each map entry configures one parameter for the query, where
231      * the map key is the field name to pull the value from, and the
232      * map value is the property name on the object the parameter should
233      * populate.
234      * </p>
235      *
236      * @return Map<String, String> mapping of query parameters
237      */
238     public Map<String, String> getQueryFieldMapping() {
239         return queryFieldMapping;
240     }
241 
242     /**
243      * Setter for the query parameter mapping
244      *
245      * @param queryFieldMapping
246      */
247     public void setQueryFieldMapping(Map<String, String> queryFieldMapping) {
248         this.queryFieldMapping = queryFieldMapping;
249     }
250 
251     /**
252      * Maps properties from the result object of the query to
253      * fields in the view
254      *
255      * <p>
256      * Each map entry configures one return mapping, where the map
257      * key is the field name for the field to populate, and the map
258      * values is the name of the property on the result object to
259      * pull the value from
260      * </p>
261      *
262      * @return Map<String, String> return field mapping
263      */
264     public Map<String, String> getReturnFieldMapping() {
265         return returnFieldMapping;
266     }
267 
268     /**
269      * Setter for the return field mapping
270      *
271      * @param returnFieldMapping
272      */
273     public void setReturnFieldMapping(Map<String, String> returnFieldMapping) {
274         this.returnFieldMapping = returnFieldMapping;
275     }
276 
277     /**
278      * Fixed criteria that will be appended to the dynamic criteria generated
279      * for the query. Map key gives name of the property the criteria should
280      * apply to, and the map value is the value (literal) for the criteria. Standard
281      * lookup wildcards are allowed
282      *
283      * @return Map<String, String> field name/value pairs for query criteria
284      */
285     public Map<String, String> getAdditionalCriteria() {
286         return additionalCriteria;
287     }
288 
289     /**
290      * Setter for the query's additional criteria map
291      *
292      * @param additionalCriteria
293      */
294     public void setAdditionalCriteria(Map<String, String> additionalCriteria) {
295         this.additionalCriteria = additionalCriteria;
296     }
297 
298     /**
299      * List of property names to sort the query results by. The sort
300      * will be performed on each property in the order they are contained
301      * within the list. Each property must be a valid property of the
302      * return query object (the data object in case of the general query)
303      *
304      * @return List<String> property names
305      */
306     public List<String> getSortPropertyNames() {
307         return sortPropertyNames;
308     }
309 
310     /**
311      * Setter for the list of property names to sort results by
312      *
313      * @param sortPropertyNames
314      */
315     public void setSortPropertyNames(List<String> sortPropertyNames) {
316         this.sortPropertyNames = sortPropertyNames;
317     }
318 
319     /**
320      * Indicates whether a message should be added to the query result
321      * object and displayed when the query return object is null
322      *
323      * @return boolean true if not found message should be added, false otherwise
324      */
325     public boolean isRenderNotFoundMessage() {
326         return renderNotFoundMessage;
327     }
328 
329     /**
330      * Setter for the render not found message indicator
331      *
332      * @param renderNotFoundMessage
333      */
334     public void setRenderNotFoundMessage(boolean renderNotFoundMessage) {
335         this.renderNotFoundMessage = renderNotFoundMessage;
336     }
337 
338     /**
339      * Message text to display along with the query result
340      *
341      * @return String literal message text
342      */
343     public String getReturnMessageText() {
344         return returnMessageText;
345     }
346 
347     /**
348      * Setter for the return message text
349      *
350      * @param returnMessageText
351      */
352     public void setReturnMessageText(String returnMessageText) {
353         this.returnMessageText = returnMessageText;
354     }
355 
356     /**
357      * CSS Style classes that should be applied to the return message.
358      * Multiple style classes should be delimited by a space
359      *
360      * @return String style classes
361      */
362     public String getReturnMessageStyleClasses() {
363         return returnMessageStyleClasses;
364     }
365 
366     /**
367      * Setter for the return messages style classes
368      *
369      * @param returnMessageStyleClasses
370      */
371     public void setReturnMessageStyleClasses(String returnMessageStyleClasses) {
372         this.returnMessageStyleClasses = returnMessageStyleClasses;
373     }
374 
375     /**
376      * Configures the name of the method that should be invoked to perform
377      * the query
378      *
379      * <p>
380      * Should contain only the method name (no parameters or return type). If only
381      * the query method name is configured it is assumed to be on the <code>ViewHelperService</code>
382      * for the contained view.
383      * </p>
384      *
385      * @return String query method name
386      */
387     public String getQueryMethodToCall() {
388         return queryMethodToCall;
389     }
390 
391     /**
392      * Setter for the query method name
393      *
394      * @param queryMethodToCall
395      */
396     public void setQueryMethodToCall(String queryMethodToCall) {
397         this.queryMethodToCall = queryMethodToCall;
398     }
399 
400     /**
401      * List of field names that should be passed as arguments to the query method
402      *
403      * <p>
404      * Each entry in the list maps to a method parameter, in the other contained within
405      * the list. The value for the field within the view will be pulled and passed
406      * to the query method as an argument
407      * </p>
408      *
409      * @return List<String> query method argument list
410      */
411     public List<String> getQueryMethodArgumentFieldList() {
412         return queryMethodArgumentFieldList;
413     }
414 
415     /**
416      * Setter for the query method argument list
417      *
418      * @param queryMethodArgumentFieldList
419      */
420     public void setQueryMethodArgumentFieldList(List<String> queryMethodArgumentFieldList) {
421         this.queryMethodArgumentFieldList = queryMethodArgumentFieldList;
422     }
423 
424     /**
425      * Configures the query method target class/object and method name
426      *
427      * <p>
428      * When the query method is not contained on the <code>ViewHelperService</code>, this
429      * can be configured for declaring the target class/object and method. The target class
430      * can be set in which case a new instance will be created and the given method invoked.
431      * Alternatively, the target object instance for the invocation can be given. Or finally
432      * a static method can be configured
433      * </p>
434      *
435      * @return MethodInvokerConfig query method config
436      */
437     public MethodInvokerConfig getQueryMethodInvokerConfig() {
438         return queryMethodInvokerConfig;
439     }
440 
441     /**
442      * Setter for the query method config
443      *
444      * @param queryMethodInvokerConfig
445      */
446     public void setQueryMethodInvokerConfig(MethodInvokerConfig queryMethodInvokerConfig) {
447         this.queryMethodInvokerConfig = queryMethodInvokerConfig;
448     }
449 }