001/** 002 * Copyright 2005-2018 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.uif.control; 017 018import java.io.Serializable; 019import java.util.Collections; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023 024import org.apache.commons.lang.StringUtils; 025import org.kuali.rice.kim.api.KimConstants; 026import org.kuali.rice.kim.api.identity.Person; 027import org.kuali.rice.kim.api.identity.PersonService; 028import org.kuali.rice.kim.api.identity.principal.Principal; 029import org.kuali.rice.kim.api.services.KimApiServiceLocator; 030import org.kuali.rice.krad.datadictionary.parse.BeanTag; 031import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute; 032import org.kuali.rice.krad.uif.UifConstants; 033import org.kuali.rice.krad.uif.component.MethodInvokerConfig; 034import org.kuali.rice.krad.uif.field.AttributeQuery; 035import org.kuali.rice.krad.uif.field.InputField; 036import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle; 037import org.kuali.rice.krad.uif.util.ComponentFactory; 038import org.kuali.rice.krad.uif.util.LifecycleElement; 039import org.kuali.rice.krad.uif.util.ScriptUtils; 040import org.kuali.rice.krad.uif.widget.QuickFinder; 041 042/** 043 * Represents a user control, which is a special control to handle the input of a Person. 044 * 045 * @author Kuali Rice Team (rice.collab@kuali.org) 046 */ 047@BeanTag(name = "kimPersonControl", parent = "Uif-KimPersonControl") 048public class UserControl extends TextControlBase implements FilterableLookupCriteriaControl { 049 private static final long serialVersionUID = 7468340793076585869L; 050 051 private String principalIdPropertyName; 052 private String personNamePropertyName; 053 private String personObjectPropertyName; 054 055 public UserControl() { 056 super(); 057 } 058 059 /** 060 * {@inheritDoc} 061 */ 062 @Override 063 public void performApplyModel(Object model, LifecycleElement parent) { 064 super.performApplyModel(model, parent); 065 066 if (!(parent instanceof InputField)) { 067 return; 068 } 069 070 InputField field = (InputField) parent; 071 field.getAdditionalHiddenPropertyNames().add(principalIdPropertyName); 072 073 if (isRender() && !isHidden() && !Boolean.TRUE.equals(getReadOnly())) { 074 ViewLifecycle.getViewPostMetadata().addAccessibleBindingPath(principalIdPropertyName); 075 } 076 077 if (!Boolean.TRUE.equals(field.getReadOnly())) { 078 // add information fields 079 if (StringUtils.isNotBlank(personNamePropertyName)) { 080 field.getPropertyNamesForAdditionalDisplay().add(personNamePropertyName); 081 } else { 082 field.getPropertyNamesForAdditionalDisplay().add( 083 personObjectPropertyName + "." + KimConstants.AttributeConstants.NAME); 084 } 085 086 // setup script to clear id field when name is modified 087 String idPropertyPath = field.getBindingInfo().getPropertyAdjustedBindingPath(principalIdPropertyName); 088 String onChangeScript = UifConstants.JsFunctions.SET_VALUE 089 + "('" 090 + ScriptUtils.escapeName(idPropertyPath) 091 + "','');"; 092 093 if (StringUtils.isNotBlank(getOnChangeScript())) { 094 onChangeScript = getOnChangeScript() + onChangeScript; 095 } 096 setOnChangeScript(onChangeScript); 097 } 098 099 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}