View Javadoc

1   package org.kuali.rice.krad.uif.service.impl;
2   
3   import org.apache.commons.lang.StringUtils;
4   import org.kuali.rice.core.api.config.property.ConfigurationService;
5   import org.kuali.rice.krad.service.KRADServiceLocator;
6   import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
7   import org.kuali.rice.krad.service.LookupService;
8   import org.kuali.rice.krad.uif.UifConstants;
9   import org.kuali.rice.krad.uif.view.View;
10  import org.kuali.rice.krad.uif.component.MethodInvokerConfig;
11  import org.kuali.rice.krad.uif.field.AttributeField;
12  import org.kuali.rice.krad.uif.field.AttributeQuery;
13  import org.kuali.rice.krad.uif.field.AttributeQueryResult;
14  import org.kuali.rice.krad.uif.service.AttributeQueryService;
15  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
16  import org.kuali.rice.krad.uif.widget.Suggest;
17  import org.kuali.rice.krad.util.BeanPropertyComparator;
18  
19  import java.text.MessageFormat;
20  import java.util.ArrayList;
21  import java.util.Collection;
22  import java.util.Collections;
23  import java.util.HashMap;
24  import java.util.List;
25  import java.util.Map;
26  
27  /**
28   * Implementation of <code>AttributeQueryService</code> that prepares the attribute queries and
29   * delegates to the <code>LookupService</code>
30   *
31   * @author Kuali Rice Team (rice.collab@kuali.org)
32   */
33  public class AttributeQueryServiceImpl implements AttributeQueryService {
34  
35      private LookupService lookupService;
36      private ConfigurationService configurationService;
37  
38      /**
39       * @see org.kuali.rice.krad.uif.service.AttributeQueryService#performFieldSuggestQuery(
40       *org.kuali.rice.krad.uif.view.View, java.lang.String, java.lang.String, java.util.Map<java.lang.String,
41       *      java.lang.String>)
42       */
43      @Override
44      public AttributeQueryResult performFieldSuggestQuery(View view, String fieldId, String fieldTerm,
45              Map<String, String> queryParameters) {
46          AttributeQueryResult queryResult = new AttributeQueryResult();
47  
48          // retrieve attribute field from view index
49          AttributeField attributeField = (AttributeField) view.getViewIndex().getComponentById(fieldId);
50          if (attributeField == null) {
51              throw new RuntimeException("Unable to find attribute field instance for id: " + fieldId);
52          }
53  
54          Suggest fieldSuggest = attributeField.getFieldSuggest();
55          AttributeQuery suggestQuery = fieldSuggest.getSuggestQuery();
56  
57          // add term as a like criteria
58          Map<String, String> additionalCriteria = new HashMap<String, String>();
59          additionalCriteria.put(fieldSuggest.getSourcePropertyName(), fieldTerm + "*");
60  
61          // execute suggest query
62          Collection<?> results = null;
63          if (suggestQuery.hasConfiguredMethod()) {
64              Object queryMethodResult = executeAttributeQueryMethod(view, suggestQuery, queryParameters);
65              if ((queryMethodResult != null) && (queryMethodResult instanceof Collection<?>)) {
66                  results = (Collection<?>) queryMethodResult;
67              }
68          } else {
69              results = executeAttributeQueryCriteria(suggestQuery, queryParameters, additionalCriteria);
70          }
71  
72          // build list of suggest data from result records
73          if (results != null) {
74              List<String> suggestData = new ArrayList<String>();
75              for (Object result : results) {
76                  Object suggestFieldValue =
77                          ObjectPropertyUtils.getPropertyValue(result, fieldSuggest.getSourcePropertyName());
78                  if (suggestFieldValue != null) {
79                      // TODO: need to apply formatter for field or have method in object property utils
80                      suggestData.add(suggestFieldValue.toString());
81                  }
82              }
83  
84              queryResult.setResultData(suggestData);
85          }
86  
87          return queryResult;
88      }
89  
90      /**
91       * @see org.kuali.rice.krad.uif.service.AttributeQueryService#performFieldQuery(org.kuali.rice.krad.uif.view.View,
92       *      java.lang.String, java.util.Map<java.lang.String,java.lang.String>)
93       */
94      @Override
95      public AttributeQueryResult performFieldQuery(View view, String fieldId, Map<String, String> queryParameters) {
96          AttributeQueryResult queryResult = new AttributeQueryResult();
97  
98          // retrieve attribute field from view index
99          AttributeField attributeField = (AttributeField) view.getViewIndex().getComponentById(fieldId);
100         if (attributeField == null) {
101             throw new RuntimeException("Unable to find attribute field instance for id: " + fieldId);
102         }
103 
104         AttributeQuery fieldQuery = attributeField.getFieldAttributeQuery();
105         if (fieldQuery == null) {
106             throw new RuntimeException("Field query not defined for field instance with id: " + fieldId);
107         }
108 
109         // execute query and get result
110         Object resultObject = null;
111         if (fieldQuery.hasConfiguredMethod()) {
112             Object queryMethodResult = executeAttributeQueryMethod(view, fieldQuery, queryParameters);
113             if (queryMethodResult != null) {
114                 // if method returned the result then no further processing needed
115                 if (queryMethodResult instanceof AttributeQueryResult) {
116                     return (AttributeQueryResult) queryMethodResult;
117                 }
118 
119                 // if method returned collection, take first record
120                 if (queryMethodResult instanceof Collection<?>) {
121                     Collection<?> methodResultCollection = (Collection<?>) queryMethodResult;
122                     if (!methodResultCollection.isEmpty()) {
123                         resultObject = methodResultCollection.iterator().next();
124                     }
125                 } else {
126                     resultObject = queryMethodResult;
127                 }
128             }
129         } else {
130             // execute field query as object lookup
131             Collection<?> results = executeAttributeQueryCriteria(fieldQuery, queryParameters, null);
132 
133             if ((results != null) && !results.isEmpty()) {
134                 // expect only one returned row for field query
135                 if (results.size() > 1) {
136                     throw new RuntimeException("");
137                 }
138 
139                 resultObject = results.iterator().next();
140             }
141         }
142 
143         if (resultObject != null) {
144             // build result field data map
145             Map<String, String> resultFieldData = new HashMap<String, String>();
146             for (String fromField : fieldQuery.getReturnFieldMapping().keySet()) {
147                 String returnField = fieldQuery.getReturnFieldMapping().get(fromField);
148 
149                 String fieldValueStr = "";
150                 Object fieldValue = ObjectPropertyUtils.getPropertyValue(resultObject, fromField);
151                 if (fieldValue != null) {
152                     fieldValueStr = fieldValue.toString();
153                 }
154                 resultFieldData.put(returnField, fieldValueStr);
155             }
156             queryResult.setResultFieldData(resultFieldData);
157 
158             fieldQuery.setReturnMessageText("");
159         } else {
160             // add data not found message
161             if (fieldQuery.isRenderNotFoundMessage()) {
162                 String messageTemplate =
163                         getConfigurationService().getPropertyValueAsString(
164                                 UifConstants.MessageKeys.QUERY_DATA_NOT_FOUND);
165                 String message = MessageFormat.format(messageTemplate, attributeField.getLabel());
166                 fieldQuery.setReturnMessageText(message.toLowerCase());
167             }
168         }
169 
170         // set message and message style classes on query result
171         queryResult.setResultMessage(fieldQuery.getReturnMessageText());
172         queryResult.setResultMessageStyleClasses(fieldQuery.getReturnMessageStyleClasses());
173 
174         return queryResult;
175     }
176 
177     /**
178      * Prepares the method configured on the attribute query then performs the method invocation
179      *
180      * @param view - view instance the field is contained within
181      * @param attributeQuery - attribute query instance to execute
182      * @param queryParameters - map of query parameters that provide values for the method arguments
183      * @return Object type depends on method being invoked, could be AttributeQueryResult in which
184      *         case the method has prepared the return result, or an Object that needs to be parsed for the result
185      */
186     protected Object executeAttributeQueryMethod(View view, AttributeQuery attributeQuery,
187             Map<String, String> queryParameters) {
188         String queryMethodToCall = attributeQuery.getQueryMethodToCall();
189         MethodInvokerConfig queryMethodInvoker = attributeQuery.getQueryMethodInvokerConfig();
190 
191         if (queryMethodInvoker == null) {
192             queryMethodInvoker = new MethodInvokerConfig();
193         }
194 
195         // if method not set on invoker, use queryMethodToCall, note staticMethod could be set(don't know since
196         // there is not a getter), if so it will override the target method in prepare
197         if (StringUtils.isBlank(queryMethodInvoker.getTargetMethod())) {
198             queryMethodInvoker.setTargetMethod(queryMethodToCall);
199         }
200 
201         // if target class or object not set, use view helper service
202         if ((queryMethodInvoker.getTargetClass() == null) && (queryMethodInvoker.getTargetObject() == null)) {
203             queryMethodInvoker.setTargetObject(view.getViewHelperService());
204         }
205 
206         // setup query method arguments
207         Object[] arguments = null;
208         if ((attributeQuery.getQueryMethodArgumentFieldList() != null) &&
209                 (!attributeQuery.getQueryMethodArgumentFieldList().isEmpty())) {
210             // retrieve argument types for conversion
211             Class[] argumentTypes = queryMethodInvoker.getArgumentTypes();
212             if ((argumentTypes == null) ||
213                     (argumentTypes.length != attributeQuery.getQueryMethodArgumentFieldList().size())) {
214                 throw new RuntimeException(
215                         "Query method argument field list size does not match found method argument list size");
216             }
217 
218             arguments = new Object[attributeQuery.getQueryMethodArgumentFieldList().size()];
219             for (int i = 0; i < attributeQuery.getQueryMethodArgumentFieldList().size(); i++) {
220                 String methodArgumentFromField = attributeQuery.getQueryMethodArgumentFieldList().get(i);
221                 if (queryParameters.containsKey(methodArgumentFromField)) {
222                     arguments[i] = queryParameters.get(methodArgumentFromField);
223                 } else {
224                     arguments[i] = null;
225                 }
226             }
227         }
228         queryMethodInvoker.setArguments(arguments);
229 
230         try {
231             queryMethodInvoker.prepare();
232 
233             return queryMethodInvoker.invoke();
234         } catch (Exception e) {
235             throw new RuntimeException("Unable to invoke query method: " + queryMethodInvoker.getTargetMethod(), e);
236         }
237     }
238 
239     /**
240      * Prepares a query using the configured data object, parameters, and criteria, then executes
241      * the query and returns the result Collection
242      *
243      * @param attributeQuery - attribute query instance to perform query for
244      * @param queryParameters - map of parameters that will be used in the query criteria
245      * @param additionalCriteria - map of additional name/value pairs to add to the critiera
246      * @return Collection<?> results of query
247      */
248     protected Collection<?> executeAttributeQueryCriteria(AttributeQuery attributeQuery,
249             Map<String, String> queryParameters, Map<String, String> additionalCriteria) {
250         Collection<?> results = null;
251 
252         // build criteria for query
253         Map<String, String> queryCriteria = new HashMap<String, String>();
254         for (String fieldName : attributeQuery.getQueryFieldMapping().keySet()) {
255             if (queryParameters.containsKey(fieldName) && StringUtils.isNotBlank(queryParameters.get(fieldName))) {
256                 queryCriteria.put(fieldName, queryParameters.get(fieldName));
257             }
258         }
259 
260         // add any static criteria
261         for (String fieldName : attributeQuery.getAdditionalCriteria().keySet()) {
262             queryCriteria.put(fieldName, attributeQuery.getAdditionalCriteria().get(fieldName));
263         }
264 
265         // add additional criteria
266         if (additionalCriteria != null) {
267             queryCriteria.putAll(additionalCriteria);
268         }
269 
270         Class<?> queryClass = null;
271         try {
272             queryClass = Class.forName(attributeQuery.getDataObjectClassName());
273         } catch (ClassNotFoundException e) {
274             throw new RuntimeException(
275                     "Invalid data object class given for suggest query: " + attributeQuery.getDataObjectClassName(), e);
276         }
277 
278         // run query
279         results = getLookupService().findCollectionBySearchUnbounded(queryClass, queryCriteria);
280 
281         // sort results
282         if (!attributeQuery.getSortPropertyNames().isEmpty() && (results != null) && (results.size() > 1)) {
283             Collections.sort((List<?>) results, new BeanPropertyComparator(attributeQuery.getSortPropertyNames()));
284         }
285 
286         return results;
287     }
288 
289     protected LookupService getLookupService() {
290         if (lookupService == null) {
291             lookupService = KRADServiceLocatorWeb.getLookupService();
292         }
293 
294         return lookupService;
295     }
296 
297     public void setLookupService(LookupService lookupService) {
298         this.lookupService = lookupService;
299     }
300 
301     protected ConfigurationService getConfigurationService() {
302         if (configurationService == null) {
303             configurationService = KRADServiceLocator.getKualiConfigurationService();
304         }
305 
306         return configurationService;
307     }
308 
309     public void setConfigurationService(ConfigurationService configurationService) {
310         this.configurationService = configurationService;
311     }
312 }