View Javadoc

1   /**
2    * Copyright 2005-2012 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.kim.lookup;
17  
18  import org.apache.commons.collections.CollectionUtils;
19  import org.apache.commons.lang.StringUtils;
20  import org.kuali.rice.core.api.criteria.Predicate;
21  import org.kuali.rice.core.api.criteria.PredicateUtils;
22  import org.kuali.rice.core.api.criteria.QueryByCriteria;
23  import org.kuali.rice.core.api.util.ClassLoaderUtils;
24  import org.kuali.rice.core.api.util.ConcreteKeyValue;
25  import org.kuali.rice.core.api.util.KeyValue;
26  import org.kuali.rice.core.web.format.BooleanFormatter;
27  import org.kuali.rice.core.web.format.CollectionFormatter;
28  import org.kuali.rice.core.web.format.DateFormatter;
29  import org.kuali.rice.core.web.format.Formatter;
30  import org.kuali.rice.kew.api.KewApiConstants;
31  import org.kuali.rice.kim.api.KimConstants;
32  import org.kuali.rice.kim.api.group.Group;
33  import org.kuali.rice.kim.api.group.GroupQueryResults;
34  import org.kuali.rice.kim.api.identity.Person;
35  import org.kuali.rice.kim.api.identity.principal.Principal;
36  import org.kuali.rice.kim.api.identity.principal.PrincipalQueryResults;
37  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
38  import org.kuali.rice.kim.api.type.KimAttributeField;
39  import org.kuali.rice.kim.api.type.KimType;
40  import org.kuali.rice.kim.framework.services.KimFrameworkServiceLocator;
41  import org.kuali.rice.kim.framework.type.KimTypeService;
42  import org.kuali.rice.kim.impl.KIMPropertyConstants;
43  import org.kuali.rice.kim.impl.group.GroupBo;
44  import org.kuali.rice.kim.impl.type.KimTypeLookupableHelperServiceImpl;
45  import org.kuali.rice.kim.util.KimCommonUtilsInternal;
46  import org.kuali.rice.kns.document.authorization.BusinessObjectRestrictions;
47  import org.kuali.rice.kns.kim.type.DataDictionaryTypeServiceHelper;
48  import org.kuali.rice.kns.lookup.HtmlData;
49  import org.kuali.rice.kns.web.comparator.CellComparatorHelper;
50  import org.kuali.rice.kns.web.struts.form.LookupForm;
51  import org.kuali.rice.kns.web.ui.Column;
52  import org.kuali.rice.kns.web.ui.Field;
53  import org.kuali.rice.kns.web.ui.ResultRow;
54  import org.kuali.rice.kns.web.ui.Row;
55  import org.kuali.rice.krad.bo.BusinessObject;
56  import org.kuali.rice.krad.bo.PersistableBusinessObject;
57  import org.kuali.rice.krad.datadictionary.AttributeDefinition;
58  import org.kuali.rice.krad.keyvalues.IndicatorValuesFinder;
59  import org.kuali.rice.krad.keyvalues.KeyValuesFinder;
60  import org.kuali.rice.krad.keyvalues.KimAttributeValuesFinder;
61  import org.kuali.rice.krad.util.GlobalVariables;
62  import org.kuali.rice.krad.util.KRADConstants;
63  import org.kuali.rice.krad.util.ObjectUtils;
64  import org.kuali.rice.krad.util.UrlFactory;
65  
66  import java.sql.Date;
67  import java.sql.Timestamp;
68  import java.util.ArrayList;
69  import java.util.Calendar;
70  import java.util.Collection;
71  import java.util.Collections;
72  import java.util.Comparator;
73  import java.util.HashMap;
74  import java.util.Iterator;
75  import java.util.List;
76  import java.util.Map;
77  import java.util.Properties;
78  
79  import static org.kuali.rice.core.api.criteria.PredicateFactory.*;
80  
81  public class GroupLookupableHelperServiceImpl  extends KimLookupableHelperServiceImpl {
82  
83  	// need this so kimtypeId value can be retained in 'rows'
84  	// 1st pass populate the grprows
85  	// 2nd pass for jsp, no populate, so return the existing one.
86      private static final String KIM_TYPE_ID_PROPERTY_NAME = "kimTypeId";
87  	private List<Row> grpRows = new ArrayList<Row>();
88  	private List<Row> attrRows = new ArrayList<Row>();
89  	private String typeId = "";
90  	private List<KimAttributeField> attrDefinitions;
91  	private final Map<String, String> groupTypeValuesCache = new HashMap<String, String>();
92  
93      @Override
94      public List<HtmlData> getCustomActionUrls(BusinessObject bo, List pkNames) {
95      	GroupBo groupImpl = (GroupBo) bo;
96          List<HtmlData> anchorHtmlDataList = new ArrayList<HtmlData>();
97          if(allowsNewOrCopyAction(KimConstants.KimUIConstants.KIM_GROUP_DOCUMENT_TYPE_NAME)){
98          	anchorHtmlDataList.add(getEditGroupUrl(groupImpl));	
99          }
100     	return anchorHtmlDataList;
101     }
102     
103     protected HtmlData getEditGroupUrl(GroupBo groupBo) {
104     	String href = "";
105 
106         Properties parameters = new Properties();
107         parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, KRADConstants.DOC_HANDLER_METHOD);
108         parameters.put(KRADConstants.PARAMETER_COMMAND, KewApiConstants.INITIATE_COMMAND);
109         parameters.put(KRADConstants.DOCUMENT_TYPE_NAME, KimConstants.KimUIConstants.KIM_GROUP_DOCUMENT_TYPE_NAME);
110         parameters.put(KimConstants.PrimaryKeyConstants.GROUP_ID, groupBo.getId());
111         if (StringUtils.isNotBlank(getReturnLocation())) {
112         	parameters.put(KRADConstants.RETURN_LOCATION_PARAMETER, getReturnLocation());
113 		}
114         href = UrlFactory.parameterizeUrl(KimCommonUtilsInternal.getKimBasePath()+KimConstants.KimUIConstants.KIM_GROUP_DOCUMENT_ACTION, parameters);
115         
116         HtmlData.AnchorHtmlData anchorHtmlData = new HtmlData.AnchorHtmlData(href,
117         		KRADConstants.DOC_HANDLER_METHOD, KRADConstants.MAINTENANCE_EDIT_METHOD_TO_CALL);
118         return anchorHtmlData;
119     }
120 
121     /**
122      * Converts GroupInfo objects to GroupBo objects.
123      * 
124      * @param  fieldValues  names and values returned by the Group Lookup screen
125      * @return  groupImplList  a list of GroupImpl objects
126      */
127     @Override
128     public List<GroupBo> getSearchResults(java.util.Map<String,String> fieldValues)  {
129         Map<String, String> criteriaMap = new HashMap<String, String>(fieldValues);
130         QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create();
131         criteriaMap.remove(KRADConstants.DOC_FORM_KEY);
132         criteriaMap.remove(KRADConstants.BACK_LOCATION);
133         criteriaMap.remove(KRADConstants.DOC_NUM);
134 
135         if (!criteriaMap.isEmpty()) {
136             List<Predicate> predicates = new ArrayList<Predicate>();
137             //principalId doesn't exist on 'Group'.  Lets do this predicate conversion separately
138             if (StringUtils.isNotBlank(criteriaMap.get(KimConstants.UniqueKeyConstants.PRINCIPAL_NAME))) {
139                 QueryByCriteria.Builder principalCriteria = QueryByCriteria.Builder.create();
140                 Predicate principalPred = like("principalName", criteriaMap.get(KimConstants.UniqueKeyConstants.PRINCIPAL_NAME));
141                 principalCriteria.setPredicates(principalPred);
142                 //String principalId = KimApiServiceLocator.getIdentityService()
143                 //        .getPrincipalByPrincipalName(criteriaMap.get(KimConstants.UniqueKeyConstants.PRINCIPAL_NAME)).getPrincipalId();
144                 PrincipalQueryResults principals = KimApiServiceLocator.getIdentityService()
145                         .findPrincipals(principalCriteria.build());
146                 List<String> principalIds = new ArrayList<String>();
147                 for (Principal principal : principals.getResults()) {
148                     principalIds.add(principal.getPrincipalId());
149                 }
150                 if (CollectionUtils.isNotEmpty(principalIds)) {
151                     Timestamp currentTime = new Timestamp(Calendar.getInstance().getTimeInMillis());
152                     predicates.add( and(
153                                     in("members.memberId", principalIds.toArray(
154                                             new String[principalIds.size()])),
155                                     equal("members.typeCode", KimConstants.KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE.getCode()),
156                                     and(
157                                         or(isNull("members.activeFromDateValue"), greaterThanOrEqual("members.activeFromDateValue", currentTime)),
158                                         or(isNull("members.activeToDateValue"), lessThan("members.activeToDateValue", currentTime))
159                                     )
160                                 ));
161                 }
162 
163             }
164             criteriaMap.remove(KimConstants.UniqueKeyConstants.PRINCIPAL_NAME);
165 
166             predicates.add(PredicateUtils.convertMapToPredicate(criteriaMap));
167             criteria.setPredicates(and(predicates.toArray(new Predicate[predicates.size()])));
168         }
169     	GroupQueryResults groupResults = KimApiServiceLocator.getGroupService().findGroups(criteria.build());
170     	List<Group> groups = groupResults.getResults();
171 
172         //have to convert back to Bos :(
173         Map<String, GroupBo> groupBos = new HashMap<String, GroupBo>(groups.size());
174         for (Group group : groups) {
175             if (groupBos.get(group.getId()) == null) {
176                 groupBos.put(group.getId(), GroupBo.from(group));
177             }
178         }
179 
180 
181     	return new ArrayList<GroupBo>(groupBos.values());
182     }
183 
184     @Override
185     public boolean checkForAdditionalFields(Map<String, String> fieldValues) {
186         List<Row> attributeRows = setupAttributeRows(fieldValues);
187         if (attributeRows.isEmpty()) {
188             setAttrRows(attributeRows);
189         } else if (CollectionUtils.isEmpty(getAttrRows())) {
190             setAttrRows(attributeRows);
191         }
192         if (getAttrRows().size() > 0) {
193             return true;
194         }
195         return false;
196     }
197 
198 
199 	@Override
200 	public List<Row> getRows() {
201 		if (getGrpRows().isEmpty()) {
202 			List<Row> rows = super.getRows();
203 			List<Row> returnRows = new ArrayList<Row>();
204 			for (Row row : rows) {
205 				for (int i = row.getFields().size() - 1; i >= 0; i--) {
206 					Field field = row.getFields().get(i);
207 					if (field.getPropertyName().equals(KIM_TYPE_ID_PROPERTY_NAME)) {
208 						Field typeField = new Field();
209 						typeField.setFieldLabel("Type");
210 						typeField.setPropertyName(KIM_TYPE_ID_PROPERTY_NAME);
211 						typeField.setFieldValidValues(getGroupTypeOptions());
212 						typeField.setFieldType(Field.DROPDOWN);
213 						row.getFields().set(i, typeField);
214 					}
215 				}
216 				returnRows.add(row);
217 			}
218 			// principalName
219 			Field typeField = new Field();
220 			typeField.setFieldLabel("Principal Name");
221 			typeField.setPropertyName(KIMPropertyConstants.Person.PRINCIPAL_NAME);
222 			typeField.setFieldType(Field.TEXT);
223 			typeField.setMaxLength(40);
224 			typeField.setSize(20);
225 			typeField.setQuickFinderClassNameImpl("org.kuali.rice.kim.api.identity.Person");
226 			typeField.setFieldConversions( "principalName:principalName" );
227 			typeField.setLookupParameters( "principalName:principalName" );
228 			// Identify the best spot to insert the "Principal Name" search field. Note that the code below assumes that the final row of the
229 			// group search fields is not a row with hidden fields; if this ever becomes the case in the future, this fix may need to
230 			// be modified accordingly.
231 			List<Field> fields = (returnRows.isEmpty()) ? new ArrayList<Field>() : returnRows.get(returnRows.size() - 1).getFields();
232 			if (!fields.isEmpty() && fields.get(fields.size() - 1).getFieldType().equals(Field.BLANK_SPACE)) {
233 				// If the last row in the list has a BLANK_SPACE field coming after any non-BLANK_SPACE fields, add the new field to that row.
234 				int insertLoc = fields.size() - 1;
235 				while (insertLoc >= 0 && fields.get(insertLoc).getFieldType().equals(Field.BLANK_SPACE)) {
236 					insertLoc--;
237 				}
238 				fields.set(insertLoc + 1, typeField);
239 				returnRows.get(returnRows.size() - 1).setFields(fields);
240 			} else {
241 				// Otherwise, add a new row containing that field.
242 				int fieldLen = fields.size();
243 				fields = new ArrayList<Field>();
244 				fields.add(typeField);
245 				for (int i = 1; i < fieldLen; i++) {
246 					Field blankSpace = new Field();
247 					blankSpace.setFieldType(Field.BLANK_SPACE);
248 					blankSpace.setPropertyName(Field.BLANK_SPACE);
249 					fields.add(blankSpace);
250 				}
251 				returnRows.add(new Row(fields));
252 			}
253 			
254 			setGrpRows(returnRows);
255 		}
256 		if (getAttrRows().isEmpty()) {
257 			setAttrDefinitions(Collections.<KimAttributeField>emptyList());
258 			return getGrpRows();
259 		} 
260 		List<Row> fullRows = new ArrayList<Row>();
261 		fullRows.addAll(getGrpRows());
262 		fullRows.addAll(getAttrRows());
263 		return fullRows;
264 	}
265 
266 
267 	@Override
268 	public List<Column> getColumns() {
269 		List<Column> columns =  super.getColumns();
270         for (Row row : attrRows) {
271             for (Field field : row.getFields()) {
272                 Column newColumn = new Column();
273                 newColumn.setColumnTitle(field.getFieldLabel());
274                 newColumn.setMaxLength(getColumnMaxLength(field.getPropertyName()));
275                 newColumn.setPropertyName(field.getPropertyName());
276                 newColumn.setFormatter(field.getFormatter());
277                 columns.add(newColumn);
278             }
279         }
280         return columns;
281 	}
282 
283     @Override
284 	public Collection<GroupBo> performLookup(LookupForm lookupForm, Collection resultTable, boolean bounded) {
285         setBackLocation((String) lookupForm.getFieldsForLookup().get(KRADConstants.BACK_LOCATION));
286         setDocFormKey((String) lookupForm.getFieldsForLookup().get(KRADConstants.DOC_FORM_KEY));
287         List<GroupBo> displayList;
288 
289         // call search method to get results
290         if (bounded) {
291             displayList = getSearchResults(lookupForm.getFieldsForLookup());
292         }
293         else {
294             displayList = (List<GroupBo>)getSearchResultsUnbounded(lookupForm.getFieldsForLookup());
295         }
296 
297         HashMap<String,Class> propertyTypes = new HashMap<String, Class>();
298 
299         boolean hasReturnableRow = false;
300 
301         List returnKeys = getReturnKeys();
302         List pkNames = getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(getBusinessObjectClass());
303         Person user = GlobalVariables.getUserSession().getPerson();
304 
305         // iterate through result list and wrap rows with return url and action urls
306         for (Iterator iter = displayList.iterator(); iter.hasNext();) {
307             BusinessObject element = (BusinessObject) iter.next();
308             if(element instanceof PersistableBusinessObject){
309                 lookupForm.setLookupObjectId(((PersistableBusinessObject)element).getObjectId());
310             }
311 
312             BusinessObjectRestrictions businessObjectRestrictions = getBusinessObjectAuthorizationService().getLookupResultRestrictions(element, user);
313 
314             HtmlData returnUrl = getReturnUrl(element, lookupForm, returnKeys, businessObjectRestrictions);
315 
316             String actionUrls = getActionUrls(element, pkNames, businessObjectRestrictions);
317             //Fix for JIRA - KFSMI-2417
318             if("".equals(actionUrls)){
319                 actionUrls = ACTION_URLS_EMPTY;
320             }
321 
322             List<Column> columns = getColumns();
323             for (Object element2 : columns) {
324 
325                 Column col = (Column) element2;
326                 Formatter formatter = col.getFormatter();
327 
328                 // pick off result column from result list, do formatting
329                 String propValue = KRADConstants.EMPTY_STRING;
330                 Object prop = null;
331                 if (col.getPropertyName().matches("\\w+\\.\\d+$")) {
332                     String id = col.getPropertyName().substring(col.getPropertyName().lastIndexOf('.') + 1); //.split("\\d+$"))[1];
333                     prop = ((GroupBo)element).getGroupAttributeValueById(id);
334                 }
335                 if (prop == null) {
336                     prop = ObjectUtils.getPropertyValue(element, col.getPropertyName());
337                 } else {
338                 }
339 
340                 // set comparator and formatter based on property type
341                 Class propClass = propertyTypes.get(col.getPropertyName());
342                 if ( propClass == null /*&& !skipPropTypeCheck*/) {
343                     try {
344                         propClass = ObjectUtils.getPropertyType( element, col.getPropertyName(), getPersistenceStructureService() );
345                         propertyTypes.put( col.getPropertyName(), propClass );
346                     } catch (Exception e) {
347                         throw new RuntimeException("Cannot access PropertyType for property " + "'" + col.getPropertyName() + "' " + " on an instance of '" + element.getClass().getName() + "'.", e);
348                     }
349                 }
350 
351                 // formatters
352                 if (prop != null) {
353                     // for Booleans, always use BooleanFormatter
354                     if (prop instanceof Boolean) {
355                         formatter = new BooleanFormatter();
356                     }
357 
358                     // for Dates, always use DateFormatter
359                     if (prop instanceof Date) {
360                         formatter = new DateFormatter();
361                     }
362 
363                     // for collection, use the list formatter if a formatter hasn't been defined yet
364                     if (prop instanceof Collection && formatter == null) {
365                     formatter = new CollectionFormatter();
366                     }
367 
368                     if (formatter != null) {
369                         propValue = (String) formatter.format(prop);
370                     }
371                     else {
372                         propValue = prop.toString();
373                         if (col.getPropertyName().equals(KIM_TYPE_ID_PROPERTY_NAME)) {
374                             propValue = groupTypeValuesCache.get(prop.toString());
375                         }
376                     }
377                 }
378 
379                 // comparator
380                 col.setComparator(CellComparatorHelper.getAppropriateComparatorForPropertyClass(propClass));
381                 col.setValueComparator(CellComparatorHelper.getAppropriateValueComparatorForPropertyClass(propClass));
382 
383                 propValue = maskValueIfNecessary(element.getClass(), col.getPropertyName(), propValue, businessObjectRestrictions);
384 
385                 col.setPropertyValue(propValue);
386 
387                 if (StringUtils.isNotBlank(propValue)) {
388                     col.setColumnAnchor(getInquiryUrl(element, col.getPropertyName()));
389 
390                 }
391             }
392 
393             ResultRow row = new ResultRow(columns, returnUrl.constructCompleteHtmlTag(), actionUrls);
394             row.setRowId(returnUrl.getName());
395             row.setReturnUrlHtmlData(returnUrl);
396             // because of concerns of the BO being cached in session on the ResultRow,
397             // let's only attach it when needed (currently in the case of export)
398             if (getBusinessObjectDictionaryService().isExportable(getBusinessObjectClass())) {
399                 row.setBusinessObject(element);
400             }
401             if(element instanceof PersistableBusinessObject){
402                 row.setObjectId((((PersistableBusinessObject)element).getObjectId()));
403             }
404 
405 
406             boolean rowReturnable = isResultReturnable(element);
407             row.setRowReturnable(rowReturnable);
408             if (rowReturnable) {
409                 hasReturnableRow = true;
410             }
411             resultTable.add(row);
412         }
413 
414         lookupForm.setHasReturnableRow(hasReturnableRow);
415 
416         return displayList;
417     }
418 
419 
420 	private List<KeyValue> getGroupTypeOptions() {
421 		List<KeyValue> options = new ArrayList<KeyValue>();
422 		options.add(new ConcreteKeyValue("", ""));
423 
424 		Collection<KimType> kimGroupTypes = KimApiServiceLocator.getKimTypeInfoService().findAllKimTypes();
425 		// get the distinct list of type IDs from all groups in the system
426         for (KimType kimType : kimGroupTypes) {
427             if (KimTypeLookupableHelperServiceImpl.hasGroupTypeService(kimType) && groupTypeValuesCache.get(kimType.getId()) == null) {
428                 String value = kimType.getNamespaceCode().trim() + KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR + kimType.getName().trim();
429                 options.add(new ConcreteKeyValue(kimType.getId(), value));
430             }
431         }
432         Collections.sort(options, new Comparator<KeyValue>() {
433            @Override
434            public int compare(KeyValue k1, KeyValue k2) {
435                return k1.getValue().compareTo(k2.getValue());
436            }
437         });
438 		return options;
439 	}
440 
441 	private List<Row> setupAttributeRows(Map fieldValues) {
442 		List<Row> returnRows = new ArrayList<Row>();
443 		for (Row row : getGrpRows()) {
444 			Field field = row.getFields().get(0);
445 			if (field.getPropertyName().equals(KIM_TYPE_ID_PROPERTY_NAME) && StringUtils.isNotBlank(field.getPropertyValue())) {
446 				if (!StringUtils.isBlank(getTypeId()) || !getTypeId().equals(field.getPropertyValue())) {
447 					setTypeId(field.getPropertyValue());
448 					setAttrRows(new ArrayList<Row>());
449 					KimType kimType = getTypeInfoService().getKimType( field.getPropertyValue() );
450 					KimTypeService kimTypeService = KimFrameworkServiceLocator.getKimTypeService(kimType);
451 			        List<KimAttributeField> definitions = kimTypeService.getAttributeDefinitions(kimType.getId());
452 			        setAttrDefinitions(definitions);
453 		            for (KimAttributeField d  : definitions) {
454 				        final AttributeDefinition definition  = DataDictionaryTypeServiceHelper
455                                 .toKimAttributeDefinition(d);
456                         List<Field> fields = new ArrayList<Field>();
457 						Field typeField = new Field();
458 
459 						String attrDefnId = d.getId();
460 						typeField.setFieldLabel(definition.getLabel());
461 						typeField.setPropertyName(definition.getName()+"."+attrDefnId);
462 						typeField.setPropertyValue(fieldValues.get(typeField.getPropertyName()));
463 						if (definition.getControl().isSelect()) {
464 					        try {
465 					            KeyValuesFinder finder = (KeyValuesFinder) ClassLoaderUtils.getClass(definition.getControl().getValuesFinderClass()).newInstance();
466 					            // need to initialize KIM Values Finder before retrieving values
467 					            if (finder instanceof KimAttributeValuesFinder) {
468 					            	((KimAttributeValuesFinder) finder).setKimTypeId(field.getPropertyValue());
469 					            	((KimAttributeValuesFinder) finder).setKimAttributeName(definition.getName());
470 					            }
471 						        typeField.setFieldValidValues(finder.getKeyValues());
472 						        typeField.setFieldType(Field.DROPDOWN);
473 					        }
474 					        catch (InstantiationException e) {
475 					            throw new RuntimeException(e.getMessage());
476 					        }
477 					        catch (IllegalAccessException e) {
478 					            throw new RuntimeException(e.getMessage());
479 					        }
480 						} else if (definition.getControl().isText()){
481 							typeField.setMaxLength(definition.getMaxLength());
482 							if (definition.getControl().getSize() != null) {
483 							    typeField.setSize(definition.getControl().getSize());
484 							}
485 						    typeField.setFieldType(Field.TEXT);
486 						} else if (definition.getControl().isRadio()) {
487 						    try {
488                                 KeyValuesFinder finder = (KeyValuesFinder) ClassLoaderUtils.getClass(definition.getControl().getValuesFinderClass()).newInstance();
489                                 typeField.setFieldValidValues(finder.getKeyValues());
490                                 typeField.setFieldType(Field.RADIO);
491                             }
492                             catch (InstantiationException e) {
493                                 throw new RuntimeException(e.getMessage());
494                             }
495                             catch (IllegalAccessException e) {
496                                 throw new RuntimeException(e.getMessage());
497                             }
498 						} else if (definition.getControl().isCheckbox()) {
499 						    KeyValuesFinder finder = new IndicatorValuesFinder();
500                             typeField.setFieldValidValues(finder.getKeyValues());
501                             typeField.setFieldType(Field.RADIO);
502 						    //typeField.setFieldType(Field.CHECKBOX);
503 						} else if (definition.getControl().isHidden()) {
504 						    typeField.setFieldType(Field.HIDDEN);
505 						} else if (definition.getControl().isLookupReadonly()) {
506 						    typeField.setFieldType(Field.LOOKUP_READONLY);
507 						} else if (definition.getControl().isTextarea()) {
508 						    typeField.setMaxLength(definition.getMaxLength());
509                             if (definition.getControl().getSize() != null) {
510                                 typeField.setSize(definition.getControl().getSize());
511                             }
512                             typeField.setFieldType(Field.TEXT_AREA);
513 						}
514 						fields.add(typeField);
515 						returnRows.add(new Row(fields));
516 		            }
517 				} else {
518 					return getAttrRows();
519 				}
520 			} else if (field.getPropertyName().equals(KIM_TYPE_ID_PROPERTY_NAME) && StringUtils.isBlank(field.getPropertyValue())) {
521 				setTypeId("");
522 			}
523 		}
524 		return returnRows;
525 	}
526 
527 	public List<Row> getGrpRows() {
528 		return this.grpRows;
529 	}
530 
531 	public void setGrpRows(List<Row> grpRows) {
532 		this.grpRows = grpRows;
533 	}
534 
535 	public List<KimAttributeField> getAttrDefinitions() {
536 		return this.attrDefinitions;
537 	}
538 
539 	public void setAttrDefinitions(List<KimAttributeField> attrDefinitions) {
540 		this.attrDefinitions = attrDefinitions;
541 	}
542 
543 	public List<Row> getAttrRows() {
544 		return this.attrRows;
545 	}
546 
547 	public void setAttrRows(List<Row> attrRows) {
548 		this.attrRows = attrRows;
549 	}
550 
551 	public String getTypeId() {
552 		return this.typeId;
553 	}
554 
555 	public void setTypeId(String typeId) {
556 		this.typeId = typeId;
557 	}
558 
559     @Override
560     public void performClear(LookupForm lookupForm) {
561         super.performClear(lookupForm);
562         this.attrRows = new ArrayList<Row>();
563     }
564 
565 }