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 }