1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
84
85
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
123
124
125
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
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
143
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
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
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
229
230
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
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
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
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
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
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
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);
333 prop = ((GroupBo)element).getGroupAttributeValueById(id);
334 }
335 if (prop == null) {
336 prop = ObjectUtils.getPropertyValue(element, col.getPropertyName());
337 } else {
338 }
339
340
341 Class propClass = propertyTypes.get(col.getPropertyName());
342 if ( propClass == null
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
352 if (prop != null) {
353
354 if (prop instanceof Boolean) {
355 formatter = new BooleanFormatter();
356 }
357
358
359 if (prop instanceof Date) {
360 formatter = new DateFormatter();
361 }
362
363
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
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
397
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
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
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
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 }