View Javadoc

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