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.control;
17  
18  import java.io.Serializable;
19  import java.util.Collections;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.apache.commons.lang.StringUtils;
25  import org.kuali.rice.kim.api.KimConstants;
26  import org.kuali.rice.kim.api.identity.Person;
27  import org.kuali.rice.kim.api.identity.PersonService;
28  import org.kuali.rice.kim.api.identity.principal.Principal;
29  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
30  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
31  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
32  import org.kuali.rice.krad.uif.UifConstants;
33  import org.kuali.rice.krad.uif.component.MethodInvokerConfig;
34  import org.kuali.rice.krad.uif.field.AttributeQuery;
35  import org.kuali.rice.krad.uif.field.InputField;
36  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
37  import org.kuali.rice.krad.uif.util.ComponentFactory;
38  import org.kuali.rice.krad.uif.util.LifecycleElement;
39  import org.kuali.rice.krad.uif.util.ScriptUtils;
40  import org.kuali.rice.krad.uif.widget.QuickFinder;
41  
42  /**
43   * Represents a user control, which is a special control to handle the input of a Person.
44   *
45   * @author Kuali Rice Team (rice.collab@kuali.org)
46   */
47  @BeanTag(name = "kimPersonControl", parent = "Uif-KimPersonControl")
48  public class UserControl extends TextControlBase implements FilterableLookupCriteriaControl {
49      private static final long serialVersionUID = 7468340793076585869L;
50  
51      private String principalIdPropertyName;
52      private String personNamePropertyName;
53      private String personObjectPropertyName;
54  
55      public UserControl() {
56          super();
57      }
58  
59      /**
60       * {@inheritDoc}
61       */
62      @Override
63      public void performApplyModel(Object model, LifecycleElement parent) {
64          super.performApplyModel(model, parent);
65  
66          if (!(parent instanceof InputField)) {
67              return;
68          }
69  
70          InputField field = (InputField) parent;
71          field.getAdditionalHiddenPropertyNames().add(principalIdPropertyName);
72  
73          if (isRender() && !isHidden() && !Boolean.TRUE.equals(getReadOnly())) {
74              ViewLifecycle.getViewPostMetadata().addAccessibleBindingPath(principalIdPropertyName);
75          }
76  
77          if (!Boolean.TRUE.equals(field.getReadOnly())) {
78              // add information fields
79              if (StringUtils.isNotBlank(personNamePropertyName)) {
80                  field.getPropertyNamesForAdditionalDisplay().add(personNamePropertyName);
81              } else {
82                  field.getPropertyNamesForAdditionalDisplay().add(
83                          personObjectPropertyName + "." + KimConstants.AttributeConstants.NAME);
84              }
85  
86              // setup script to clear id field when name is modified
87              String idPropertyPath = field.getBindingInfo().getPropertyAdjustedBindingPath(principalIdPropertyName);
88              String onChangeScript = UifConstants.JsFunctions.SET_VALUE
89                      + "('"
90                      + ScriptUtils.escapeName(idPropertyPath)
91                      + "','');";
92  
93              if (StringUtils.isNotBlank(getOnChangeScript())) {
94                  onChangeScript = getOnChangeScript() + onChangeScript;
95              }
96              setOnChangeScript(onChangeScript);
97          }
98  
99          if (Boolean.TRUE.equals(field.getReadOnly()) && StringUtils.isBlank(field.getReadOnlyDisplaySuffixPropertyName())) {
100             if (StringUtils.isNotBlank(personNamePropertyName)) {
101                 field.setReadOnlyDisplaySuffixPropertyName(personNamePropertyName);
102             } else {
103                 field.setReadOnlyDisplaySuffixPropertyName(
104                         personObjectPropertyName + "." + KimConstants.AttributeConstants.NAME);
105             }
106         }
107 
108         // setup field query for displaying name
109         AttributeQuery attributeQuery = new AttributeQuery();
110 
111         MethodInvokerConfig methodInvokerConfig = new MethodInvokerConfig();
112         PersonService personService = KimApiServiceLocator.getPersonService();
113         methodInvokerConfig.setTargetObject(personService);
114 
115         attributeQuery.setQueryMethodInvokerConfig(methodInvokerConfig);
116         attributeQuery.setQueryMethodToCall("getPersonByPrincipalName");
117         attributeQuery.getQueryMethodArgumentFieldList().add(field.getPropertyName());
118         attributeQuery.getReturnFieldMapping().put(KimConstants.AttributeConstants.PRINCIPAL_ID,
119                 principalIdPropertyName);
120 
121         if (StringUtils.isNotBlank(personNamePropertyName)) {
122             attributeQuery.getReturnFieldMapping().put(KimConstants.AttributeConstants.NAME, personNamePropertyName);
123         } else {
124             attributeQuery.getReturnFieldMapping().put(KimConstants.AttributeConstants.NAME,
125                     personObjectPropertyName + "." + KimConstants.AttributeConstants.NAME);
126         }
127         field.setAttributeQuery(attributeQuery);
128 
129         buildUserQuickfinder(model, field);
130     }
131 
132     /**
133      * {@inheritDoc}
134      */
135     @Override
136     public Map<String, String> filterSearchCriteria(String propertyName, Map<String, String> searchCriteria,
137             FilterableLookupCriteriaControlPostData postData) {
138         Map<String, String> filteredSearchCriteria = new HashMap<String, String>(searchCriteria);
139 
140         UserControlPostData userControlPostData = (UserControlPostData) postData;
141 
142         // check valid principalName
143         // ToDo: move the principalId check and setting to the validation stage.  At that point the personName should
144         // be set as well or an error be displayed to the user that the principalName is invalid.
145         String principalName = searchCriteria.get(propertyName);
146         if (StringUtils.isNotBlank(principalName)) {
147             if (!StringUtils.contains(principalName, "*")) {
148                 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(
149                         principalName);
150                 if (principal == null) {
151                     return null;
152                 } else {
153                     filteredSearchCriteria.put(userControlPostData.getPrincipalIdPropertyName(),
154                             principal.getPrincipalId());
155                 }
156             } else {
157                 List<Person> people = KimApiServiceLocator.getPersonService().findPeople(Collections.singletonMap(
158                         KimConstants.AttributeConstants.PRINCIPAL_NAME, principalName));
159                 if (people != null && people.size() == 0) {
160                     return null;
161                 }
162             }
163         }
164 
165         if (!StringUtils.contains(principalName, "*")) {
166             // filter
167             filteredSearchCriteria.remove(propertyName);
168             filteredSearchCriteria.remove(userControlPostData.getPersonNamePropertyName());
169         }
170 
171         return filteredSearchCriteria;
172     }
173 
174     /**
175      * Configures the field's quickfinder for a user lookup
176      *
177      * @param model object containing the view's data
178      * @param field field instance the quickfinder should be associated with
179      */
180     protected void buildUserQuickfinder(Object model, InputField field) {
181         QuickFinder quickFinder = field.getQuickfinder();
182 
183         // don't build quickfinder if explicitly turned off
184         if (!field.isEnableAutoQuickfinder()) {
185             return;
186         }
187 
188         if (quickFinder == null) {
189             quickFinder = ComponentFactory.getQuickFinder();
190             field.setQuickfinder(quickFinder);
191         }
192 
193         if (StringUtils.isBlank(quickFinder.getDataObjectClassName())) {
194             quickFinder.setDataObjectClassName(Person.class.getName());
195         }
196 
197         if (quickFinder.getFieldConversions().isEmpty()) {
198             quickFinder.getFieldConversions().put(KimConstants.AttributeConstants.PRINCIPAL_ID,
199                     principalIdPropertyName);
200 
201             if (StringUtils.isNotBlank(personNamePropertyName)) {
202                 quickFinder.getFieldConversions().put(KimConstants.AttributeConstants.NAME, personNamePropertyName);
203             } else {
204                 quickFinder.getFieldConversions().put(KimConstants.AttributeConstants.NAME,
205                         personObjectPropertyName + "." + KimConstants.AttributeConstants.NAME);
206             }
207 
208             quickFinder.getFieldConversions().put(KimConstants.AttributeConstants.PRINCIPAL_NAME,
209                     field.getPropertyName());
210         }
211     }
212 
213     /**
214      * The name of the property on the parent object that holds the principal id
215      *
216      * @return principalIdPropertyName
217      */
218     @BeanTagAttribute
219     public String getPrincipalIdPropertyName() {
220         return principalIdPropertyName;
221     }
222 
223     /**
224      * Setter for the name of the property on the parent object that holds the principal id
225      *
226      * @param principalIdPropertyName
227      */
228     public void setPrincipalIdPropertyName(String principalIdPropertyName) {
229         this.principalIdPropertyName = principalIdPropertyName;
230     }
231 
232     /**
233      * The name of the property on the parent object that holds the person name
234      *
235      * @return personNamePropertyName
236      */
237     @BeanTagAttribute
238     public String getPersonNamePropertyName() {
239         return personNamePropertyName;
240     }
241 
242     /**
243      * Setter for the name of the property on the parent object that holds the person name
244      *
245      * @param personNamePropertyName
246      */
247     public void setPersonNamePropertyName(String personNamePropertyName) {
248         this.personNamePropertyName = personNamePropertyName;
249     }
250 
251     /**
252      * The name of the property on the parent object that holds the person object
253      *
254      * @return personObjectPropertyName
255      */
256     @BeanTagAttribute
257     public String getPersonObjectPropertyName() {
258         return personObjectPropertyName;
259     }
260 
261     /**
262      * Setter for the name of the property on the parent object that holds the person object
263      *
264      * @param personObjectPropertyName
265      */
266     public void setPersonObjectPropertyName(String personObjectPropertyName) {
267         this.personObjectPropertyName = personObjectPropertyName;
268     }
269 
270     /**
271      * {@inheritDoc}
272      */
273     @Override
274     public UserControlPostData getPostData(String propertyName) {
275         return new UserControlPostData(propertyName, this);
276     }
277 
278     /**
279      * Holds post data for the {@link UserControl}.
280      */
281     public static class UserControlPostData implements FilterableLookupCriteriaControlPostData, Serializable {
282 
283         private static final long serialVersionUID = 3895010942559014164L;
284 
285         private String propertyName;
286 
287         private String principalIdPropertyName;
288         private String personNamePropertyName;
289         private String personObjectPropertyName;
290 
291         /**
292          * Constructs the post data from the property name and the {@link UserControl}.
293          *
294          * @param propertyName the name of the property to filter
295          * @param userControl the control to pull data from
296          */
297         public UserControlPostData(String propertyName, UserControl userControl) {
298             this.propertyName = propertyName;
299             this.principalIdPropertyName = userControl.getPrincipalIdPropertyName();
300             this.personNamePropertyName = userControl.getPersonNamePropertyName();
301             this.personObjectPropertyName = userControl.getPersonObjectPropertyName();
302         }
303 
304         /**
305          * {@inheritDoc}
306          */
307         @Override
308         public Class<? extends FilterableLookupCriteriaControl> getControlClass() {
309             return UserControl.class;
310         }
311 
312         /**
313          * {@inheritDoc}
314          */
315         @Override
316         public String getPropertyName() {
317             return propertyName;
318         }
319 
320         /**
321          * @see UserControl#getPrincipalIdPropertyName()
322          */
323         public String getPrincipalIdPropertyName() {
324             return principalIdPropertyName;
325         }
326 
327         /**
328          * @see UserControl#getPersonNamePropertyName()
329          */
330         public String getPersonNamePropertyName() {
331             return personNamePropertyName;
332         }
333 
334         /**
335          * @see UserControl#getPersonObjectPropertyName()
336          */
337         public String getPersonObjectPropertyName() {
338             return personObjectPropertyName;
339         }
340 
341     }
342 
343 }