View Javadoc
1   /**
2    * Copyright 2005-2015 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.widget;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.krad.bo.DataObjectRelationship;
20  import org.kuali.rice.krad.bo.ExternalizableBusinessObject;
21  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
22  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
23  import org.kuali.rice.krad.datadictionary.parse.BeanTags;
24  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
25  import org.kuali.rice.krad.service.ModuleService;
26  import org.kuali.rice.krad.uif.UifConstants;
27  import org.kuali.rice.krad.uif.UifParameters;
28  import org.kuali.rice.krad.uif.component.BindingInfo;
29  import org.kuali.rice.krad.uif.component.Component;
30  import org.kuali.rice.krad.uif.component.MethodInvokerConfig;
31  import org.kuali.rice.krad.uif.container.CollectionGroup;
32  import org.kuali.rice.krad.uif.container.DialogGroup;
33  import org.kuali.rice.krad.uif.element.Action;
34  import org.kuali.rice.krad.uif.field.FieldGroup;
35  import org.kuali.rice.krad.uif.field.InputField;
36  import org.kuali.rice.krad.uif.lifecycle.LifecycleEventListener;
37  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
38  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleRestriction;
39  import org.kuali.rice.krad.uif.util.LifecycleElement;
40  import org.kuali.rice.krad.uif.util.ViewModelUtils;
41  import org.kuali.rice.krad.uif.view.View;
42  import org.kuali.rice.krad.util.KRADConstants;
43  import org.kuali.rice.krad.util.KRADUtils;
44  import org.kuali.rice.krad.web.form.UifFormBase;
45  
46  import java.util.ArrayList;
47  import java.util.HashMap;
48  import java.util.List;
49  import java.util.Map;
50  
51  /**
52   * Widget for navigating to a lookup from a field (called a quickfinder).
53   *
54   * @author Kuali Rice Team (rice.collab@kuali.org)
55   */
56  @BeanTags({@BeanTag(name = "quickFinder", parent = "Uif-QuickFinder"),
57          @BeanTag(name = "quickFinderByScript", parent = "Uif-QuickFinderByScript"),
58          @BeanTag(name = "collectionQuickFinder", parent = "Uif-CollectionQuickFinder")})
59  
60  public class QuickFinder extends WidgetBase implements LifecycleEventListener {
61  
62      private static final long serialVersionUID = 3302390972815386785L;
63  
64      // lookup configuration
65      private String baseLookupUrl;
66      private String dataObjectClassName;
67      private String viewName;
68  
69      private boolean returnByScript;
70      private String readOnlyLookupFields;
71      private String referencesToRefresh;
72      private String lookupCollectionName;
73      private String lookupCollectionId;
74  
75      private Map<String, String> fieldConversions;
76      private Map<String, String> lookupParameters;
77      private Map<String, String> additionalLookupParameters;
78  
79      private Action quickfinderAction;
80  
81      private String lookupDialogId;
82      private boolean openInDialog;
83  
84      // lookup view options
85      private Boolean renderReturnLink;
86      private Boolean renderResultActions;
87      private Boolean autoSearch;
88      private Boolean renderLookupCriteria;
89      private Boolean renderCriteriaActions;
90      private Boolean hideCriteriaOnSearch;
91      private Boolean renderMaintenanceLinks;
92      private Boolean multipleValuesSelect;
93  
94      private String callbackMethodToCall;
95      private MethodInvokerConfig callbackMethod;
96      private Map<String, String> callbackContext;
97  
98      public QuickFinder() {
99          super();
100 
101         fieldConversions = new HashMap<String, String>();
102         lookupParameters = new HashMap<String, String>();
103         lookupDialogId = "";
104     }
105 
106     /**
107      * The following initialization is performed:
108      *
109      * <ul>
110      * <li>Registers an event on the quickfinder action</li>
111      * </ul>
112      *
113      * {@inheritDoc}
114      */
115     @Override
116     public void performInitialization(Object model) {
117         super.performInitialization(model);
118 
119         ViewLifecycle viewLifecycle = ViewLifecycle.getActiveLifecycle();
120         viewLifecycle.registerLifecycleCompleteListener(quickfinderAction, this);
121     }
122 
123     /**
124      * Inherits readOnly from parent if not explicitly populated.
125      *
126      * {@inheritDoc}
127      */
128     @Override
129     public void afterEvaluateExpression() {
130         super.afterEvaluateExpression();
131 
132         if (getReadOnly() == null) {
133             Component parent = ViewLifecycle.getPhase().getParent();
134             setReadOnly(parent == null ? null : parent.getReadOnly());
135         }
136     }
137 
138     /**
139      * The following finalization is performed:
140      *
141      * <ul>
142      * <li>Sets up the quickfinder based on whether the parent is an input field or collection group</li>
143      * <li>Adds action parameters to the quickfinder action based on the quickfinder configuration</li>
144      * <li>Adds callback parameters to post data if present</li>
145      * </ul>
146      *
147      * {@inheritDoc}
148      */
149     @Override
150     public void performFinalize(Object model, LifecycleElement parent) {
151         super.performFinalize(model, parent);
152 
153         if (parent instanceof Component && Boolean.TRUE.equals(((Component) parent).getReadOnly())) {
154             setRender(false);
155         }
156 
157         if (!isRender()) {
158             return;
159         }
160 
161         View view = ViewLifecycle.getActiveLifecycle().getView();
162 
163         if (parent instanceof InputField) {
164             setupForInputField(view, model, (InputField) parent);
165 
166             // add field conversions as accessible binding paths
167             if (isRender()) {
168                 for (String toField : fieldConversions.values()) {
169                     ViewLifecycle.getViewPostMetadata().addAccessibleBindingPath(toField);
170                 }
171             }
172         } else if (parent instanceof CollectionGroup) {
173             setupForCollectionGroup(view, model, (CollectionGroup) parent);
174         }
175 
176         setupQuickfinderAction(view, model, parent);
177 
178         addCallbackParametersIfPresent();
179     }
180 
181     /**
182      * If quickfinder not manually configured attempts to find a relationship to build the quickfinder on, then also
183      * adjusts the path for any configured field conversions, lookup parameters, and refresh refreshes.
184      *
185      * @param view view instance the quickfinder is associated with
186      * @param model object containing the view data
187      * @param inputField input field instance the quickfinder should apply to
188      */
189     protected void setupForInputField(View view, Object model, InputField inputField) {
190         // if quickfinder class name not specified, attempt to find a relationship to build the quickfinder from
191         if (StringUtils.isBlank(dataObjectClassName)) {
192             DataObjectRelationship relationship = getRelationshipForField(view, model, inputField);
193 
194             // if no relationship found cannot have a quickfinder
195             if (relationship == null) {
196                 setRender(false);
197 
198                 return;
199             }
200 
201             dataObjectClassName = relationship.getRelatedClass().getName();
202 
203             if ((fieldConversions == null) || fieldConversions.isEmpty()) {
204                 generateFieldConversions(relationship);
205             }
206 
207             if ((lookupParameters == null) || lookupParameters.isEmpty()) {
208                 generateLookupParameters(relationship);
209             }
210         }
211 
212         // adjust paths based on associated attribute field
213         updateFieldConversions(inputField.getBindingInfo());
214         updateLookupParameters(inputField.getBindingInfo());
215         updateReferencesToRefresh(inputField.getBindingInfo());
216 
217         // add the quickfinders action as an input field addon
218         inputField.addPostInputAddon(quickfinderAction);
219     }
220 
221     /**
222      * Retrieves any {@link org.kuali.rice.krad.bo.DataObjectRelationship} that is associated with the given
223      * field and has a configured lookup view.
224      *
225      * @param view view instance the quickfinder is associated with
226      * @param model object containing the view data
227      * @param field input field instance the quickfinder should apply to
228      * @return data object relationship for the field, or null if one could not be found
229      */
230     protected DataObjectRelationship getRelationshipForField(View view, Object model, InputField field) {
231         String propertyName = field.getBindingInfo().getBindingName();
232 
233         // get object instance and class for parent
234         Object parentObject = ViewModelUtils.getParentObjectForMetadata(view, model, field);
235         Class<?> parentObjectClass = null;
236         if (parentObject != null) {
237             parentObjectClass = parentObject.getClass();
238         }
239 
240         // get relationship from metadata service
241         if (parentObjectClass != null) {
242             return KRADServiceLocatorWeb.getLegacyDataAdapter().getDataObjectRelationship(parentObject,
243                     parentObjectClass, propertyName, "", true, true, false);
244         }
245 
246         return null;
247     }
248 
249     /**
250      * Generates the lookup field conversions based on the references from the given relationship.
251      *
252      * @param relationship relationship field conversions will be generated from
253      */
254     protected void generateFieldConversions(DataObjectRelationship relationship) {
255         fieldConversions = new HashMap<String, String>();
256 
257         for (Map.Entry<String, String> entry : relationship.getParentToChildReferences().entrySet()) {
258             String fromField = entry.getValue();
259             String toField = entry.getKey();
260 
261             fieldConversions.put(fromField, toField);
262         }
263     }
264 
265     /**
266      * Generates the lookup parameters based on the references from the given relationship.
267      *
268      * @param relationship relationship lookup parameters will be generated from
269      */
270     protected void generateLookupParameters(DataObjectRelationship relationship) {
271         lookupParameters = new HashMap<String, String>();
272 
273         for (Map.Entry<String, String> entry : relationship.getParentToChildReferences().entrySet()) {
274             String fromField = entry.getKey();
275             String toField = entry.getValue();
276 
277             if (relationship.getUserVisibleIdentifierKey() == null || relationship.getUserVisibleIdentifierKey().equals(
278                     fromField)) {
279                 lookupParameters.put(fromField, toField);
280             }
281         }
282     }
283 
284     /**
285      * Adjusts the path on the field conversion to property to match the binding path prefix of the
286      * given {@link org.kuali.rice.krad.uif.component.BindingInfo}.
287      *
288      * @param bindingInfo binding info instance to copy binding path prefix from
289      */
290     protected void updateFieldConversions(BindingInfo bindingInfo) {
291         Map<String, String> adjustedFieldConversions = new HashMap<String, String>();
292         for (String fromField : fieldConversions.keySet()) {
293             String toField = fieldConversions.get(fromField);
294 
295             if (!StringUtils.startsWith(toField, bindingInfo.getBindingPathPrefix())) {
296                 String adjustedToFieldPath = bindingInfo.getPropertyAdjustedBindingPath(toField);
297                 adjustedFieldConversions.put(fromField, adjustedToFieldPath);
298             } else {
299                 adjustedFieldConversions.put(fromField, toField);
300             }
301         }
302 
303         this.fieldConversions = adjustedFieldConversions;
304     }
305 
306     /**
307      * Adjusts the path on the lookup parameter from property to match the binding path prefix of the
308      * given {@link org.kuali.rice.krad.uif.component.BindingInfo}.
309      *
310      * @param bindingInfo binding info instance to copy binding path prefix from
311      */
312     protected void updateLookupParameters(BindingInfo bindingInfo) {
313         Map<String, String> adjustedLookupParameters = new HashMap<String, String>();
314         for (String fromField : lookupParameters.keySet()) {
315             String toField = lookupParameters.get(fromField);
316             String adjustedFromFieldPath = bindingInfo.getPropertyAdjustedBindingPath(fromField);
317 
318             adjustedLookupParameters.put(adjustedFromFieldPath, toField);
319         }
320 
321         this.lookupParameters = adjustedLookupParameters;
322     }
323 
324     /**
325      * Adjust the path on the referencesToRefresh parameter to match the binding path prefix of the
326      * given {@link org.kuali.rice.krad.uif.component.BindingInfo}.
327      *
328      * @param bindingInfo binding info instance to copy binding path prefix from
329      */
330     protected void updateReferencesToRefresh(BindingInfo bindingInfo) {
331         List<String> adjustedReferencesToRefresh = new ArrayList<String>();
332 
333         if (referencesToRefresh == null) {
334             referencesToRefresh = new String();
335         }
336 
337         for (String reference : StringUtils.split(referencesToRefresh, KRADConstants.REFERENCES_TO_REFRESH_SEPARATOR)) {
338             adjustedReferencesToRefresh.add(bindingInfo.getPropertyAdjustedBindingPath(reference));
339         }
340 
341         this.referencesToRefresh = StringUtils.join(adjustedReferencesToRefresh,
342                 KRADConstants.REFERENCES_TO_REFRESH_SEPARATOR);
343     }
344 
345     /**
346      * Configures the quickfinder for the given collection group instance by setting the data object class,
347      * field conversions, and lookup collection name (if necessary).
348      *
349      * @param view view instance the quickfinder is associated with
350      * @param model object containing the view data
351      * @param collectionGroup collection group instance to build quickfinder for
352      */
353     protected void setupForCollectionGroup(View view, Object model, CollectionGroup collectionGroup) {
354         // check to see if data object class is configured for lookup, if so we will assume it should be enabled
355         // if not and the class configured for the collection group is lookupable, use that
356         if (StringUtils.isBlank(getDataObjectClassName())) {
357             Class<?> collectionObjectClass = collectionGroup.getCollectionObjectClass();
358 
359             boolean isCollectionClassLookupable = KRADServiceLocatorWeb.getViewDictionaryService().isLookupable(
360                     collectionObjectClass);
361             if (isCollectionClassLookupable) {
362                 setDataObjectClassName(collectionObjectClass.getName());
363 
364                 // use PK fields for collection class as default field conversions
365                 if ((fieldConversions == null) || fieldConversions.isEmpty()) {
366                     List<String> collectionObjectPKFields =
367                             KRADServiceLocatorWeb.getLegacyDataAdapter().listPrimaryKeyFieldNames(
368                                     collectionObjectClass);
369 
370                     fieldConversions = new HashMap<String, String>();
371                     for (String pkField : collectionObjectPKFields) {
372                         fieldConversions.put(pkField, pkField);
373                     }
374                 }
375             } else {
376                 // no available data object class to lookup so disable quickfinder
377                 setRender(false);
378             }
379         }
380 
381         // set the lookup return collection name to this collection path
382         if (isRender() && StringUtils.isBlank(getLookupCollectionName())) {
383             setLookupCollectionName(collectionGroup.getBindingInfo().getBindingPath());
384         }
385 
386         if (isRender() && StringUtils.isBlank(getLookupCollectionId())) {
387             setLookupCollectionId(collectionGroup.getId());
388         }
389     }
390 
391     /**
392      * Adjusts the id for the quickfinder action, and then adds action parameters for passing along the
393      * quickfinder configuration to the lookup view.
394      *
395      * @param view view instance the quickfinder is associated with
396      * @param model object containing the view data
397      * @param parent component instance the quickfinder is associated with
398      */
399     protected void setupQuickfinderAction(View view, Object model, LifecycleElement parent) {
400         quickfinderAction.setId(getId() + UifConstants.IdSuffixes.ACTION);
401 
402         if (openInDialog) {
403             String lightboxScript = null;
404             String actionScript = quickfinderAction.getActionScript();
405             if (actionScript == null) {
406                 actionScript = "";
407             }
408             String dialogId = quickfinderAction.getActionParameter(UifParameters.DIALOG_ID);
409 
410             // if the dialog id is still blank, then look in the initial request parameters in case this was
411             // a request from a nested component (i.e., an action invoked as a result of another action)
412             if (StringUtils.isBlank(dialogId)) {
413                 UifFormBase form = (UifFormBase) model;
414                 Map<String, String[]> requestParameters = form.getInitialRequestParameters();
415                 if (requestParameters != null) {
416                     String[] dialogIds = requestParameters.get(UifParameters.DIALOG_ID);
417                     if (dialogIds != null && dialogIds.length > 0) {
418                         dialogId = dialogIds[0];
419                     }
420                 }
421             }
422 
423             // set the quickfinder's dialog id when invoked from within a dialog
424             // this accounts for the quickfinder being on the dialog field in which case the dialog is the parent, and
425             // for the quickfinder being in a nested sub-collection in the dialog in which case the dialog is the
426             // quickfinder's parent's (the nested sub-collection) parent
427             if (StringUtils.isBlank(dialogId)) {
428                 Object superParent = parent.getContext().get(UifConstants.ContextVariableNames.PARENT);
429                 if (superParent != null) {
430                     if (superParent instanceof DialogGroup) {
431                         dialogId = ((DialogGroup) superParent).getId();
432                     } else if (superParent instanceof CollectionGroup) {
433                         CollectionGroup parentCollection = (CollectionGroup) superParent;
434                         superParent = parentCollection.getContext().get(UifConstants.ContextVariableNames.PARENT);
435                         if (superParent instanceof FieldGroup) {
436                             FieldGroup parentFieldGroup = (FieldGroup) superParent;
437                             superParent = parentFieldGroup.getContext().get(UifConstants.ContextVariableNames.PARENT);
438                             if (superParent instanceof DialogGroup) {
439                                 dialogId = ((DialogGroup) superParent).getId();
440                             }
441                         }
442                     }
443                 }
444             }
445 
446             // let lookup know that it's been called from a dialog by passing its dialog id if present
447             if (StringUtils.isBlank(dialogId)) {
448                 lightboxScript = UifConstants.JsFunctions.SHOW_LOOKUP_DIALOG + "(\"" + quickfinderAction.getId() + "\","
449                         + returnByScript + ",\"" + lookupDialogId + "\");";
450             } else {
451                 lightboxScript = UifConstants.JsFunctions.SHOW_LOOKUP_DIALOG + "(\"" + quickfinderAction.getId() + "\","
452                         + returnByScript + ",\"" + lookupDialogId + "\",\"" + dialogId + "\");";
453 
454                 // also add the dialog id to the action parameters so that even other nested components have it
455                 // no matter the depth of the nodes
456                 quickfinderAction.addActionParameter(UifParameters.DIALOG_ID, dialogId);
457             }
458 
459             quickfinderAction.setActionScript(actionScript + lightboxScript);
460         }
461 
462         quickfinderAction.addActionParameter(UifParameters.BASE_LOOKUP_URL, baseLookupUrl);
463 
464         Class dataObjectClass = getDataObjectClass(dataObjectClassName);
465         ModuleService responsibleModuleService =
466                 KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(dataObjectClass);
467         if (responsibleModuleService != null && responsibleModuleService.isExternalizable(dataObjectClass)) {
468             if (ExternalizableBusinessObject.class.isAssignableFrom(dataObjectClass)) {
469                 Class implementationClass = responsibleModuleService.getExternalizableBusinessObjectImplementation(
470                         dataObjectClass.asSubclass(ExternalizableBusinessObject.class));
471                 if (implementationClass != null) {
472                     dataObjectClassName = implementationClass.getName();
473                 }
474             }
475         }
476 
477         quickfinderAction.addActionParameter(UifParameters.DATA_OBJECT_CLASS_NAME, dataObjectClassName);
478 
479         if (!fieldConversions.isEmpty()) {
480             quickfinderAction.addActionParameter(UifParameters.CONVERSION_FIELDS, KRADUtils.buildMapParameterString(
481                     fieldConversions));
482         }
483 
484         if (!lookupParameters.isEmpty()) {
485             quickfinderAction.addActionParameter(UifParameters.LOOKUP_PARAMETERS, KRADUtils.buildMapParameterString(
486                     lookupParameters));
487         }
488 
489         addActionParameterIfNotNull(UifParameters.VIEW_NAME, viewName);
490         addActionParameterIfNotNull(UifParameters.READ_ONLY_FIELDS, readOnlyLookupFields);
491         addActionParameterIfNotNull(UifParameters.RENDER_RETURN_LINK, renderReturnLink);
492         addActionParameterIfNotNull(UifParameters.RENDER_RESULT_ACTIONS, renderResultActions);
493         addActionParameterIfNotNull(UifParameters.REFERENCES_TO_REFRESH, referencesToRefresh);
494         addActionParameterIfNotNull(UifParameters.AUTO_SEARCH, autoSearch);
495         addActionParameterIfNotNull(UifParameters.RENDER_LOOKUP_CRITERIA, renderLookupCriteria);
496         addActionParameterIfNotNull(UifParameters.RENDER_CRITERIA_ACTIONS, renderCriteriaActions);
497         addActionParameterIfNotNull(UifParameters.HIDE_CRITERIA_ON_SEARCH, hideCriteriaOnSearch);
498         addActionParameterIfNotNull(UifParameters.RENDER_MAINTENANCE_LINKS, renderMaintenanceLinks);
499         addActionParameterIfNotNull(UifParameters.MULTIPLE_VALUES_SELECT, multipleValuesSelect);
500         addActionParameterIfNotNull(UifParameters.LOOKUP_COLLECTION_NAME, lookupCollectionName);
501         addActionParameterIfNotNull(UifParameters.LOOKUP_COLLECTION_ID, lookupCollectionId);
502         addActionParameterIfNotNull(UifParameters.QUICKFINDER_ID, getId());
503 
504         //insert additional lookup parameters.
505         if (additionalLookupParameters != null) {
506             //copy additional parameters to actionParameters
507             Map<String, String> actionParameters = quickfinderAction.getActionParameters();
508             actionParameters.putAll(additionalLookupParameters);
509             quickfinderAction.setActionParameters(actionParameters);
510         }
511 
512        quickfinderAction.performFinalize(model, parent);
513     }
514 
515     private Class<?> getDataObjectClass(String className) {
516         Class<?> dataObjectClass;
517 
518         try {
519             dataObjectClass = Class.forName(className);
520         } catch (ClassNotFoundException e) {
521             throw new RuntimeException("Unable to get class for name: " + className, e);
522         }
523 
524         return dataObjectClass;
525     }
526 
527     /**
528      * Utility method to add an action parameter to the quickfinder action if the given parameter value
529      * is non blank.
530      *
531      * @param parameterName name of the parameter to add
532      * @param parameterValue value for the parameter to add
533      */
534     protected void addActionParameterIfNotNull(String parameterName, Object parameterValue) {
535         if ((parameterValue != null) && StringUtils.isNotBlank(parameterValue.toString())) {
536             quickfinderAction.addActionParameter(parameterName, parameterValue.toString());
537         }
538     }
539 
540     /**
541      * Adds post context data for the quickfinder so when the lookup return occurs the focus and jump point
542      * of the quickfinder action can be retrieved.
543      *
544      * {@inheritDoc}
545      */
546     @Override
547     public void processEvent(ViewLifecycle.LifecycleEvent lifecycleEvent, View view, Object model,
548             LifecycleElement eventComponent) {
549         Action finalQuickfinderAction = (Action) eventComponent;
550 
551         // add post metadata for focus point when the associated lookup returns
552         ViewLifecycle.getViewPostMetadata().addComponentPostData(this, UifConstants.PostMetadata.QUICKFINDER_FOCUS_ID,
553                 finalQuickfinderAction.getFocusOnIdAfterSubmit());
554         ViewLifecycle.getViewPostMetadata().addComponentPostData(this, UifConstants.PostMetadata.QUICKFINDER_JUMP_TO_ID,
555                 finalQuickfinderAction.getJumpToIdAfterSubmit());
556     }
557 
558     /**
559      * Adds callback method and its parameters to post data so that when a refresh occurs it knows
560      * which view is returned from and possibly which collection line the quickfinder was on.
561      */
562     protected void addCallbackParametersIfPresent() {
563         if (StringUtils.isNotBlank(callbackMethodToCall)) {
564             ViewLifecycle.getViewPostMetadata().addComponentPostData(this,
565                     UifConstants.PostMetadata.QUICKFINDER_CALLBACK_METHOD_TO_CALL, callbackMethodToCall);
566         }
567 
568         if (callbackMethod != null) {
569             ViewLifecycle.getViewPostMetadata().addComponentPostData(this,
570                     UifConstants.PostMetadata.QUICKFINDER_CALLBACK_METHOD, callbackMethod);
571         }
572 
573         if (callbackContext != null && !callbackContext.isEmpty()) {
574             ViewLifecycle.getViewPostMetadata().addComponentPostData(this,
575                     UifConstants.PostMetadata.QUICKFINDER_CALLBACK_CONTEXT, callbackContext);
576         }
577     }
578 
579     /**
580      * Returns the URL for the lookup for which parameters will be added.
581      *
582      * <p>The base URL includes the domain, context, and controller mapping for the lookup invocation. Parameters are
583      * then added based on configuration to complete the URL. This is generally defaulted to the application URL and
584      * internal KRAD servlet mapping, but can be changed to invoke another application such as the Rice standalone
585      * server</p>
586      *
587      * @return lookup base URL
588      */
589     @BeanTagAttribute
590     public String getBaseLookupUrl() {
591         return this.baseLookupUrl;
592     }
593 
594     /**
595      * @see QuickFinder#getBaseLookupUrl()
596      */
597     public void setBaseLookupUrl(String baseLookupUrl) {
598         this.baseLookupUrl = baseLookupUrl;
599     }
600 
601     /**
602      * Full class name the lookup should be provided for.
603      *
604      * <p>This is passed on to the lookup request for the data object the lookup should be rendered for. This is then
605      * used by the lookup framework to select the lookup view (if more than one lookup view exists for the same
606      * data object class name, the {@link #getViewName()} property should be specified to select the view to
607      * render).</p>
608      *
609      * @return lookup class name
610      */
611     @BeanTagAttribute
612     public String getDataObjectClassName() {
613         return this.dataObjectClassName;
614     }
615 
616     /**
617      * @see QuickFinder#getDataObjectClassName()
618      */
619     public void setDataObjectClassName(String dataObjectClassName) {
620         this.dataObjectClassName = dataObjectClassName;
621     }
622 
623     /**
624      * When multiple target lookup views exists for the same data object class, the view name can be set to
625      * determine which one to use.
626      *
627      * <p>When creating multiple lookup views for the same data object class, the view name can be specified for the
628      * different versions (for example 'simple' and 'advanced'). When multiple lookup views exist the view name must
629      * be sent with the data object class for the request. Note the view id can be alternatively used to uniquely
630      * identify the lookup view</p>
631      *
632      * @return String name of lookup view
633      */
634     @BeanTagAttribute
635     public String getViewName() {
636         return this.viewName;
637     }
638 
639     /**
640      * @see QuickFinder#getViewName()
641      */
642     public void setViewName(String viewName) {
643         this.viewName = viewName;
644     }
645 
646     /**
647      * Indicates whether the lookup return should occur through script, or by refresing the page (making server
648      * request).
649      *
650      * <p>For quickfinders that do not need any additional server side action, return through script can be
651      * much faster and prevents a page refresh.</p>
652      *
653      * @return boolean true if the return should occur through script, false if not (default)
654      */
655     @BeanTagAttribute
656     public boolean isReturnByScript() {
657         return returnByScript;
658     }
659 
660     /**
661      * @see QuickFinder#isReturnByScript()
662      */
663     public void setReturnByScript(boolean returnByScript) {
664         this.returnByScript = returnByScript;
665     }
666 
667     /**
668      * Comma delimited String of property names on the lookup view that should be read only.
669      *
670      * <p>When requesting a lookup view, property names for fields that are rendered as search criteria can be marked
671      * as read-only. This is usually done when a lookup parameter for that property is sent in and the user should
672      * not be allowed to change the value</p>
673      *
674      * @return property names (delimited by a comma) whose criteria fields should be read-only on the
675      * lookup view
676      */
677     @BeanTagAttribute
678     public String getReadOnlyLookupFields() {
679         return this.readOnlyLookupFields;
680     }
681 
682     /**
683      * @see QuickFinder#setReadOnlyLookupFields(java.lang.String)
684      */
685     public void setReadOnlyLookupFields(String readOnlyLookupFields) {
686         this.readOnlyLookupFields = readOnlyLookupFields;
687     }
688 
689     /**
690      * List of property names on the model that should be refreshed when the lookup returns.
691      *
692      * <p>Note this is only relevant when the return by script option is not enabled (meaning the server will be
693      * invoked
694      * on the lookup return call)</p>
695      *
696      * <p>When a lookup return call is made (to return a result value) the controller refresh method will be invoked.
697      * If
698      * refresh properties are configured, a call to refresh those references from the database will be made. This is
699      * useful if the lookup returns a foreign key field and the related record is needed.</p>
700      *
701      * @return list of property names to refresh
702      */
703     @BeanTagAttribute
704     public String getReferencesToRefresh() {
705         return this.referencesToRefresh;
706     }
707 
708     /**
709      * @see QuickFinder#getReferencesToRefresh()
710      */
711     public void setReferencesToRefresh(String referencesToRefresh) {
712         this.referencesToRefresh = referencesToRefresh;
713     }
714 
715     /**
716      * Map that determines what properties from a result lookup row (if selected) will be returned to properties on
717      * the calling view.
718      *
719      * <p>The purpose of using the lookup is to search for a particular value and return that value to the form being
720      * completed. In order for the lookup framework to return the field back to us, we must specify the name of the
721      * field on the data object class whose value we need, and the name of the field on the calling view. Furthermore,
722      * we can choose to have the lookup return additional fields that populate other form fields or informational
723      * properties (see ‘Field Queries and Informational Properties’). These pairs of fields are known as
724      * ‘field conversions’.</p>
725      *
726      * <p>The fieldConversions property is a Map. Each entry represents a field that will be returned back from the
727      * lookup, with the entry key being the field name on the data object class, and the entry value being the field
728      * name on the calling view. It is helpful to think of this as a from-to mapping. Pulling from the data object
729      * field (map key) to the calling view field (map value).</p>
730      *
731      * @return mapping of lookup data object property names to view property names
732      */
733     @BeanTagAttribute
734     public Map<String, String> getFieldConversions() {
735         return this.fieldConversions;
736     }
737 
738     /**
739      * @see QuickFinder#getFieldConversions()
740      */
741     public void setFieldConversions(Map<String, String> fieldConversions) {
742         this.fieldConversions = fieldConversions;
743     }
744 
745     /**
746      * Map that determines what properties from a calling view will be sent to properties on that are rendered
747      * for the lookup view's search fields (they can be hidden).
748      *
749      * <p> When invoking a lookup view, we can pre-populate search fields on the lookup view with data from the view
750      * that called the lookup. The user can then perform the search with these values, or (if edited is allowed or
751      * the fields are not hidden) change the passed in values. When the lookup is invoked, the values for the
752      * properties configured within the lookup parameters Map will be pulled and passed along as values for the
753      * lookup view properties</p>
754      *
755      * @return mapping of calling view properties to lookup view search fields
756      */
757     @BeanTagAttribute
758     public Map<String, String> getLookupParameters() {
759         return this.lookupParameters;
760     }
761 
762     /**
763      * @see QuickFinder#getLookupParameters()
764      */
765     public void setLookupParameters(Map<String, String> lookupParameters) {
766         this.lookupParameters = lookupParameters;
767     }
768 
769     /**
770      * Indicates whether the return links for lookup results should be rendered.
771      *
772      * <p>A lookup view can be invoked to allow the user to select a value (or set of values) to return back to the
773      * calling view. For single value lookups this is done with a return link that is rendered for each row. This
774      * return link can be disabled by setting this property to false</p>
775      *
776      * @return true if the return link should not be shown, false if it should be
777      */
778     @BeanTagAttribute
779     public Boolean getRenderReturnLink() {
780         return this.renderReturnLink;
781     }
782 
783     /**
784      * @see QuickFinder#getRenderReturnLink()
785      */
786     public void setRenderReturnLink(Boolean renderReturnLink) {
787         this.renderReturnLink = renderReturnLink;
788     }
789 
790     /**
791      * Indicates whether the maintenance actions (or others) are rendered on the invoked lookup view.
792      *
793      * <p>By default a lookup view will add an actions column for the result table that display maintenance links (in
794      * addition to a new link at the top of the page) if a maintenance action is available. Custom links can also be
795      * added to the action column as necessary. This flag can be set to true to suppress the rendering of the actions
796      * for the lookup call.</p>
797      *
798      * @return true if actions should be rendered, false if not
799      */
800     @BeanTagAttribute
801     public Boolean getRenderResultActions() {
802         return renderResultActions;
803     }
804 
805     /**
806      * @see QuickFinder#getRenderResultActions()
807      */
808     public void setRenderResultActions(Boolean renderResultActions) {
809         this.renderResultActions = renderResultActions;
810     }
811 
812     /**
813      * Indicates whether the search should be executed when first rendering the lookup view.
814      *
815      * <p>By default the lookup view is rendered, the user enters search values and executes the results. This flag can
816      * be set to true to indicate the search should be performed before showing the screen to the user. This is
817      * generally used when search criteria is being passed in as well</p>
818      *
819      * @return true if the search should be performed initially, false if not
820      */
821     @BeanTagAttribute
822     public Boolean getAutoSearch() {
823         return this.autoSearch;
824     }
825 
826     /**
827      * @see org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute#name()
828      */
829     public void setAutoSearch(Boolean autoSearch) {
830         this.autoSearch = autoSearch;
831     }
832 
833     /**
834      * Indicates whether the lookup criteria (search group) should be enabled on the invoked lookup view.
835      *
836      * <p> Setting the this to false will not display the lookup criteria but only the results. Therefore this is only
837      * useful when setting {@link #getAutoSearch()} to true and passing in criteria</p>
838      *
839      * @return true if lookup criteria should be displayed, false if not
840      */
841     @BeanTagAttribute
842     public Boolean getRenderLookupCriteria() {
843         return this.renderLookupCriteria;
844     }
845 
846     /**
847      * @see QuickFinder#getRenderLookupCriteria()
848      */
849     public void setRenderLookupCriteria(Boolean renderLookupCriteria) {
850         this.renderLookupCriteria = renderLookupCriteria;
851     }
852 
853     /**
854      * Indicates whether the criteria actions (footer) should be rendered on the invoked lookup view.
855      *
856      * @return boolean true if actions should be rendered (default), false if not
857      */
858     @BeanTagAttribute
859     public Boolean getRenderCriteriaActions() {
860         return this.renderCriteriaActions;
861     }
862 
863     /**
864      * @see QuickFinder#getRenderCriteriaActions()
865      */
866     public void setRenderCriteriaActions(Boolean renderCriteriaActions) {
867         this.renderCriteriaActions = renderCriteriaActions;
868     }
869 
870     /**
871      * Indicates whether the lookup criteria should be hidden when a search is executed.
872      *
873      * @return boolean true if criteria should be hidden, false if not
874      */
875     @BeanTagAttribute
876     public Boolean getHideCriteriaOnSearch() {
877         return hideCriteriaOnSearch;
878     }
879 
880     /**
881      * @see QuickFinder#getHideCriteriaOnSearch()
882      */
883     public void setHideCriteriaOnSearch(Boolean hideCriteriaOnSearch) {
884         this.hideCriteriaOnSearch = hideCriteriaOnSearch;
885     }
886 
887     /**
888      * Indicates whether the maintenance action links should be rendered for the invoked lookup view.
889      *
890      * <p>If a maintenance view exists for the data object associated with the lookup view, the framework will add
891      * links to initiate a new maintenance document. This flag can be used to disable the rendering of these links</p>
892      *
893      * <p> Note this serves similar purpose to {@link #getRenderResultActions()} but the intent is to only remove the
894      * maintenance links in this situation, not the complete actions column</p>
895      *
896      * @return true if maintenance links should be shown on the lookup view, false if not
897      */
898     @BeanTagAttribute
899     public Boolean getRenderMaintenanceLinks() {
900         return this.renderMaintenanceLinks;
901     }
902 
903     /**
904      * @see QuickFinder#getRenderMaintenanceLinks()
905      */
906     public void setRenderMaintenanceLinks(Boolean renderMaintenanceLinks) {
907         this.renderMaintenanceLinks = renderMaintenanceLinks;
908     }
909 
910     /**
911      * Action component that is used to rendered for the field for invoking the quickfinder action (bringing up the
912      * lookup).
913      *
914      * <p>Through the action configuration the image (or link, button) rendered for the quickfinder can be modified. In
915      * addition to other action component settings</p>
916      *
917      * @return Action instance rendered for quickfinder
918      */
919     @ViewLifecycleRestriction(exclude=UifConstants.ViewPhases.FINALIZE)
920     @BeanTagAttribute(type = BeanTagAttribute.AttributeType.BYTYPE)
921     public Action getQuickfinderAction() {
922         return this.quickfinderAction;
923     }
924 
925     /**
926      * @see QuickFinder#getQuickfinderAction()
927      */
928     public void setQuickfinderAction(Action quickfinderAction) {
929         this.quickfinderAction = quickfinderAction;
930     }
931 
932     /**
933      * The id of the DialogGroup to use when the openInDialog property is true.
934      *
935      * <p>The DialogGroup should only contain an iframe for its items.  When not set, a default dialog
936      * will be used.</p>
937      *
938      * @return the id of the dialog to use for this quickfinder
939      */
940     @BeanTagAttribute
941     public String getLookupDialogId() {
942         return lookupDialogId;
943     }
944 
945     /**
946      * @see QuickFinder#getLookupDialogId()
947      */
948     public void setLookupDialogId(String lookupDialogId) {
949         this.lookupDialogId = lookupDialogId;
950     }
951 
952     /**
953      * True if the quickfinder's lookup should be opened in a dialog; true is the default setting for the
954      * bean.
955      *
956      * @return true if the lookup should be opened in a dialog, false to open in a new window
957      */
958     @BeanTagAttribute
959     public boolean isOpenInDialog() {
960         return openInDialog;
961     }
962 
963     /**
964      * @see QuickFinder#isOpenInDialog()
965      */
966     public void setOpenInDialog(boolean openInDialog) {
967         this.openInDialog = openInDialog;
968     }
969 
970     /**
971      * Indicates whether the invoked lookup view should allow multiple values to be selected and returned.
972      *
973      * @return true if multi-value lookup should be requested, false for normal lookup
974      */
975     @BeanTagAttribute
976     public Boolean getMultipleValuesSelect() {
977         return multipleValuesSelect;
978     }
979 
980     /**
981      * @see QuickFinder#getMultipleValuesSelect()
982      */
983     public void setMultipleValuesSelect(Boolean multipleValuesSelect) {
984         this.multipleValuesSelect = multipleValuesSelect;
985     }
986 
987     /**
988      * For the case of multi-value lookup, indicates the collection that should be populated with
989      * the return results.
990      *
991      * <p>Note when the quickfinder is associated with a {@link CollectionGroup}, this property is
992      * set automatically from the collection name associated with the group</p>
993      *
994      * @return collection name (must be full binding path)
995      */
996     @BeanTagAttribute
997     public String getLookupCollectionName() {
998         return lookupCollectionName;
999     }
1000 
1001     /**
1002      * @see QuickFinder#getLookupCollectionName()
1003      */
1004     public void setLookupCollectionName(String lookupCollectionName) {
1005         this.lookupCollectionName = lookupCollectionName;
1006     }
1007 
1008     /**
1009      * For the case of multi-value lookup, indicates the collection id that should be populated with
1010      * the return results.
1011      *
1012      * <p>Note when the quickfinder is associated with a {@link CollectionGroup}, this property is
1013      * set automatically from the collection id associated with the group</p>
1014      *
1015      * @return collection id
1016      */
1017     @BeanTagAttribute
1018     public String getLookupCollectionId() {
1019         return lookupCollectionId;
1020     }
1021 
1022     /**
1023      * @see QuickFinder#getLookupCollectionId()
1024      */
1025     public void setLookupCollectionId(String lookupCollectionId) {
1026         this.lookupCollectionId = lookupCollectionId;
1027     }
1028 
1029     /**
1030      * The additional parameters that were passed to the quickFinder.
1031      *
1032      * @return additionalLookupParameters - map of additional lookup parameters
1033      */
1034     @BeanTagAttribute
1035     public Map<String, String> getAdditionalLookupParameters() {
1036         return additionalLookupParameters;
1037     }
1038 
1039     /**
1040      * @see QuickFinder#getAdditionalLookupParameters()
1041      */
1042     public void setAdditionalLookupParameters(Map<String, String> additionalLookupParameters) {
1043         this.additionalLookupParameters = additionalLookupParameters;
1044     }
1045 
1046     /**
1047      * The name of the callback method to invoke in the view helper service that checks
1048      * request parameters to indicate what view is being returned from.
1049      *
1050      * @return callbackMethodToCall - the name of the callback method
1051      */
1052     public String getCallbackMethodToCall() {
1053         return callbackMethodToCall;
1054     }
1055 
1056     /**
1057      * @see QuickFinder#getCallbackMethodToCall()
1058      */
1059     public void setCallbackMethodToCall(String callbackMethodToCall) {
1060         this.callbackMethodToCall = callbackMethodToCall;
1061     }
1062 
1063     /**
1064      * The specific method invoker to use to invoke the callback method to call.
1065      *
1066      * @return callbackMethod - the method invoker
1067      */
1068     public MethodInvokerConfig getCallbackMethod() {
1069         return callbackMethod;
1070     }
1071 
1072     /**
1073      * @see QuickFinder#getCallbackMethod()
1074      */
1075     public void setCallbackMethod(MethodInvokerConfig callbackMethod) {
1076         this.callbackMethod = callbackMethod;
1077     }
1078 
1079     /**
1080      * The context of parameters to be provided to the callback method to call.
1081      *
1082      * @return callbackContext - map of parameters
1083      */
1084     public Map<String, String> getCallbackContext() {
1085         return callbackContext;
1086     }
1087 
1088     /**
1089      * @see QuickFinder#getCallbackContext()
1090      */
1091     public void setCallbackContext(Map<String, String> callbackContext) {
1092         this.callbackContext = callbackContext;
1093     }
1094 }