1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.uif.service.impl;
17
18 import org.apache.commons.collections.CollectionUtils;
19 import org.apache.commons.lang.StringUtils;
20 import org.kuali.rice.core.api.data.DataType;
21 import org.kuali.rice.kim.api.KimConstants;
22 import org.kuali.rice.krad.data.DataObjectService;
23 import org.kuali.rice.krad.data.metadata.DataObjectAttribute;
24 import org.kuali.rice.krad.data.metadata.DataObjectAttributeRelationship;
25 import org.kuali.rice.krad.data.metadata.DataObjectMetadata;
26 import org.kuali.rice.krad.data.metadata.DataObjectRelationship;
27 import org.kuali.rice.krad.data.provider.annotation.UifDisplayHint;
28 import org.kuali.rice.krad.data.provider.annotation.UifDisplayHintType;
29 import org.kuali.rice.krad.datadictionary.AttributeDefinition;
30 import org.kuali.rice.krad.datadictionary.CollectionDefinition;
31 import org.kuali.rice.krad.datadictionary.DataObjectEntry;
32 import org.kuali.rice.krad.datadictionary.validation.constraint.ValidCharactersConstraint;
33 import org.kuali.rice.krad.lookup.LookupInputField;
34 import org.kuali.rice.krad.lookup.LookupView;
35 import org.kuali.rice.krad.service.DataDictionaryService;
36 import org.kuali.rice.krad.uif.component.Component;
37 import org.kuali.rice.krad.uif.container.CollectionGroup;
38 import org.kuali.rice.krad.uif.container.Group;
39 import org.kuali.rice.krad.uif.control.Control;
40 import org.kuali.rice.krad.uif.control.HiddenControl;
41 import org.kuali.rice.krad.uif.control.TextAreaControl;
42 import org.kuali.rice.krad.uif.control.TextControl;
43 import org.kuali.rice.krad.uif.control.UserControl;
44 import org.kuali.rice.krad.uif.field.DataField;
45 import org.kuali.rice.krad.uif.layout.TableLayoutManager;
46 import org.kuali.rice.krad.uif.service.UifDefaultingService;
47 import org.kuali.rice.krad.uif.util.ComponentFactory;
48 import org.kuali.rice.krad.uif.view.InquiryView;
49 import org.kuali.rice.krad.util.KRADPropertyConstants;
50
51 import java.util.ArrayList;
52 import java.util.Collection;
53 import java.util.HashMap;
54 import java.util.HashSet;
55 import java.util.List;
56 import java.util.Map;
57
58 public class UifDefaultingServiceImpl implements UifDefaultingService {
59 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(UifDefaultingServiceImpl.class);
60
61 protected DataDictionaryService dataDictionaryService;
62 protected DataObjectService dataObjectService;
63
64 protected static final String ANY_CHARACTER_PATTERN_CONSTRAINT = "UTF8AnyCharacterPatternConstraint";
65 protected static final String DATE_PATTERN_CONSTRAINT = "BasicDatePatternConstraint";
66 protected static final String FLOATING_POINT_PATTERN_CONSTRAINT = "FloatingPointPatternConstraintTemplate";
67 protected static final String BIG_DECIMAL_PATTERN_CONSTRAINT = "BigDecimalPatternConstraintTemplate";
68 protected static final String TIMESTAMP_PATTERN_CONSTRAINT = "TimestampPatternConstraint";
69 protected static final String CURRENCY_PATTERN_CONSTRAINT = "CurrencyPatternConstraint";
70
71 @Override
72 public String deriveHumanFriendlyNameFromPropertyName(String camelCasedName) {
73
74 if(StringUtils.isBlank(camelCasedName)) {
75 return camelCasedName;
76 }
77
78
79 if (camelCasedName.contains(".")) {
80 camelCasedName = StringUtils.substringAfterLast(camelCasedName, ".");
81 }
82
83 StringBuilder label = new StringBuilder(camelCasedName);
84
85
86 label.replace(0, 1, label.substring(0, 1).toUpperCase());
87
88
89 for (int i = 0; i < label.length(); i++) {
90 if (Character.isUpperCase(label.charAt(i)) || Character.isDigit(label.charAt(i)) ) {
91 label.insert(i, ' ');
92 i++;
93 }
94 }
95
96 return label.toString().trim();
97 }
98
99
100 protected UifDisplayHint getHintOfType( DataObjectAttribute attr, UifDisplayHintType hintType ) {
101 if ( attr != null && attr.getDisplayHints() != null ) {
102 for ( UifDisplayHint hint : attr.getDisplayHints() ) {
103 if ( hint.value().equals(hintType) ) {
104 return hint;
105 }
106 }
107 }
108
109 return null;
110 }
111
112
113
114
115
116
117
118
119 protected boolean hasHintOfType( DataObjectAttribute attr, UifDisplayHintType hintType ) {
120 return getHintOfType(attr, hintType) != null;
121 }
122
123 protected Control getControlInstance( AttributeDefinition attrDef, DataObjectAttribute dataObjectAttribute ) {
124 Control c = null;
125
126 if ( dataObjectAttribute != null && hasHintOfType(dataObjectAttribute, UifDisplayHintType.HIDDEN) ) {
127 c = ComponentFactory.getHiddenControl();
128 } else if ( attrDef.getOptionsFinder() != null ) {
129
130 if ( dataObjectAttribute != null && hasHintOfType(dataObjectAttribute, UifDisplayHintType.RADIO) ) {
131 c = ComponentFactory.getRadioGroupControl();
132 } else {
133 c = ComponentFactory.getSelectControl();
134 }
135 } else if ( attrDef.getName().endsWith( ".principalName" ) && dataObjectAttribute != null ) {
136
137
138 c = ComponentFactory.getUserControl();
139
140
141 String relationshipName = StringUtils.removeEnd(attrDef.getName(), ".principalName");
142 DataObjectMetadata metadata = dataObjectService.getMetadataRepository().getMetadata(
143 dataObjectAttribute.getOwningType());
144 if ( metadata != null ) {
145 DataObjectRelationship relationship = metadata.getRelationship(relationshipName);
146 if ( relationship != null && CollectionUtils.isNotEmpty(relationship.getAttributeRelationships())) {
147 ((UserControl)c).setPrincipalIdPropertyName(relationship.getAttributeRelationships().get(0).getParentAttributeName());
148 ((UserControl)c).setPersonNamePropertyName(relationshipName + "." + KimConstants.AttributeConstants.NAME);
149 ((UserControl)c).setPersonObjectPropertyName(relationshipName);
150 }
151 } else {
152 LOG.warn( "Attempt to pull relationship name: " + relationshipName + " resulted in missing metadata when looking for: " + dataObjectAttribute.getOwningType() );
153 }
154 } else {
155 switch ( attrDef.getDataType() ) {
156 case STRING :
157
158 if ( attrDef.getMaxLength() != null && attrDef.getMaxLength().intValue() > 200 ) {
159 c = ComponentFactory.getTextAreaControl();
160 } else {
161 c = ComponentFactory.getTextControl();
162 }
163 break;
164 case BOOLEAN:
165 c = ComponentFactory.getCheckboxControl();
166 break;
167 case DATE:
168 case DATETIME:
169 case TRUNCATED_DATE:
170 c = ComponentFactory.getDateControl();
171 break;
172 case CURRENCY:
173 case DOUBLE:
174 case FLOAT:
175 case INTEGER:
176 case LARGE_INTEGER:
177 case LONG:
178 case PRECISE_DECIMAL:
179 c = ComponentFactory.getTextControl();
180 break;
181 case MARKUP:
182 c = ComponentFactory.getTextAreaControl();
183 break;
184 default:
185 c = ComponentFactory.getTextControl();
186 break;
187 }
188 }
189 return c;
190 }
191
192 protected void customizeControlInstance( Control c, AttributeDefinition attrDef, DataObjectAttribute dataObjectAttribute ) {
193 c.setRequired(attrDef.isRequired());
194 if ( c instanceof TextControl ) {
195 if ( attrDef.getMaxLength() != null ) {
196 ((TextControl) c).setMaxLength( attrDef.getMaxLength() );
197 ((TextControl) c).setSize( attrDef.getMaxLength() );
198
199 if ( attrDef.getMaxLength() > 80 ) {
200 ((TextControl) c).setTextExpand(true);
201 }
202 }
203 if ( attrDef.getMinLength() != null ) {
204 ((TextControl) c).setMinLength( attrDef.getMinLength() );
205 }
206 }
207 if ( c instanceof TextAreaControl ) {
208 if ( attrDef.getMaxLength() != null ) {
209 ((TextAreaControl) c).setMaxLength( attrDef.getMaxLength() );
210 ((TextAreaControl) c).setRows(attrDef.getMaxLength()/((TextAreaControl) c).getCols());
211 }
212 if ( attrDef.getMinLength() != null ) {
213 ((TextAreaControl) c).setMinLength( attrDef.getMinLength() );
214 }
215 }
216 }
217
218 @Override
219 public Control deriveControlAttributeFromMetadata( AttributeDefinition attrDef ) {
220 DataObjectAttribute dataObjectAttribute = attrDef.getDataObjectAttribute();
221 Control c = getControlInstance(attrDef, dataObjectAttribute);
222
223 if (c != null) {
224 customizeControlInstance(c, attrDef, dataObjectAttribute);
225 }
226 return c;
227 }
228
229 @Override
230 public ValidCharactersConstraint deriveValidCharactersConstraint(AttributeDefinition attrDef) {
231 ValidCharactersConstraint validCharactersConstraint = null;
232
233
234 if (attrDef.getDataObjectAttribute() != null) {
235 if (StringUtils.isNotBlank(attrDef.getDataObjectAttribute().getValidCharactersConstraintBeanName())) {
236 Object consObj = dataDictionaryService.getDictionaryBean(attrDef.getDataObjectAttribute()
237 .getValidCharactersConstraintBeanName());
238 if (consObj != null && consObj instanceof ValidCharactersConstraint) {
239 validCharactersConstraint = (ValidCharactersConstraint) consObj;
240 }
241 }
242 }
243
244
245 if (validCharactersConstraint == null) {
246 if (attrDef.getDataType() != null) {
247 if (attrDef.getDataType() == DataType.CURRENCY) {
248 validCharactersConstraint = (ValidCharactersConstraint) dataDictionaryService
249 .getDictionaryBean(CURRENCY_PATTERN_CONSTRAINT);
250 }else if (attrDef.getDataType() == DataType.PRECISE_DECIMAL ) {
251 validCharactersConstraint = (ValidCharactersConstraint) dataDictionaryService
252 .getDictionaryBean(BIG_DECIMAL_PATTERN_CONSTRAINT);
253 } else if (attrDef.getDataType().isNumeric()) {
254 validCharactersConstraint = (ValidCharactersConstraint) dataDictionaryService
255 .getDictionaryBean(FLOATING_POINT_PATTERN_CONSTRAINT);
256 } else if (attrDef.getDataType().isTemporal()) {
257 if (attrDef.getDataType() == DataType.DATE) {
258 validCharactersConstraint = (ValidCharactersConstraint) dataDictionaryService
259 .getDictionaryBean(DATE_PATTERN_CONSTRAINT);
260 } else if (attrDef.getDataType() == DataType.TIMESTAMP) {
261 validCharactersConstraint = (ValidCharactersConstraint) dataDictionaryService
262 .getDictionaryBean(TIMESTAMP_PATTERN_CONSTRAINT);
263 }
264 }
265 }
266 }
267
268
269 if (validCharactersConstraint == null) {
270 validCharactersConstraint = (ValidCharactersConstraint) dataDictionaryService
271 .getDictionaryBean(ANY_CHARACTER_PATTERN_CONSTRAINT);
272 }
273
274 return validCharactersConstraint;
275 }
276
277 protected Group createInquirySection( String groupId, String headerText ) {
278 Group group = ComponentFactory.getGroupWithDisclosureGridLayout();
279 group.setId(groupId);
280 group.setHeaderText(headerText);
281 group.setItems(new ArrayList<Component>());
282 return group;
283 }
284
285 protected CollectionGroup createCollectionInquirySection( String groupId, String headerText ) {
286 CollectionGroup group = ComponentFactory.getCollectionWithDisclosureGroupTableLayout();
287 group.setId(groupId);
288 group.setHeaderText(headerText);
289 group.setItems(new ArrayList<Component>());
290 ((TableLayoutManager)group.getLayoutManager()).setRenderSequenceField(false);
291 return group;
292 }
293
294 @SuppressWarnings("unchecked")
295 protected void addAttributeSectionsToInquiryView( InquiryView view, DataObjectEntry dataObjectEntry ) {
296
297 Map<String,Group> inquirySectionsById = new HashMap<String,Group>();
298 Group currentGroup = createInquirySection("default",dataObjectEntry.getObjectLabel());
299 inquirySectionsById.put(currentGroup.getId(), currentGroup);
300 ((List<Group>)view.getItems()).add(currentGroup);
301
302
303
304 List<Component> items = (List<Component>) currentGroup.getItems();
305 for ( AttributeDefinition attr : dataObjectEntry.getAttributes() ) {
306 boolean dontDisplay = hasHintOfType(attr.getDataObjectAttribute(), UifDisplayHintType.NO_INQUIRY);
307 dontDisplay |= (attr.getControlField() instanceof HiddenControl);
308
309
310 UifDisplayHint sectionHint = getHintOfType(attr.getDataObjectAttribute(), UifDisplayHintType.SECTION);
311 if ( sectionHint != null ) {
312 if ( StringUtils.isNotBlank( sectionHint.id() ) ) {
313 currentGroup = inquirySectionsById.get( sectionHint.id() );
314 if ( currentGroup == null ) {
315 String sectionLabel = sectionHint.label();
316 if ( StringUtils.isBlank(sectionLabel) ) {
317 sectionLabel = deriveHumanFriendlyNameFromPropertyName(sectionHint.id() );
318 }
319
320 currentGroup = createInquirySection(sectionHint.id(), sectionHint.label());
321 inquirySectionsById.put(currentGroup.getId(), currentGroup);
322 ((List<Group>)view.getItems()).add(currentGroup);
323 }
324 } else {
325 LOG.warn( "SECTION UifDisplayHint given without an ID - assuming 'default'" );
326 currentGroup = inquirySectionsById.get("default");
327 }
328 items = (List<Component>) currentGroup.getItems();
329 }
330
331
332
333 if ( dontDisplay ) {
334 continue;
335 }
336
337 DataField dataField = ComponentFactory.getDataField();
338 dataField.setPropertyName(attr.getName());
339 dataField.setLabel(attr.getLabel());
340 items.add(dataField);
341 }
342 }
343
344 @SuppressWarnings("unchecked")
345 protected void addCollectionSectionsToInquiryView( InquiryView view, DataObjectEntry dataObjectEntry ) {
346 for ( CollectionDefinition coll : dataObjectEntry.getCollections() ) {
347
348 DataObjectEntry collectionEntry = dataDictionaryService.getDataDictionary().getDataObjectEntry(coll.getDataObjectClass());
349
350
351 Collection<String> collectionFieldsLinkedToParent = new HashSet<String>();
352
353 if ( coll.getDataObjectCollection() != null ) {
354 for ( DataObjectAttributeRelationship rel : coll.getDataObjectCollection().getAttributeRelationships() ) {
355 collectionFieldsLinkedToParent.add(rel.getChildAttributeName());
356 }
357 }
358
359 if ( collectionEntry == null ) {
360 LOG.warn( "Unable to find DataObjectEntry for collection class: " + coll.getDataObjectClass());
361 continue;
362 }
363
364 CollectionGroup section = createCollectionInquirySection(coll.getName(), coll.getLabel());
365 try {
366 section.setCollectionObjectClass(Class.forName(coll.getDataObjectClass()));
367 } catch (ClassNotFoundException e) {
368 LOG.warn( "Unable to set class on collection section - class not found: " + coll.getDataObjectClass());
369 }
370
371 section.setPropertyName(coll.getName());
372
373
374
375 for ( AttributeDefinition attr : collectionEntry.getAttributes() ) {
376 boolean dontDisplay = hasHintOfType(attr.getDataObjectAttribute(), UifDisplayHintType.NO_INQUIRY);
377 dontDisplay |= (attr.getControlField() instanceof HiddenControl);
378
379 dontDisplay |= collectionFieldsLinkedToParent.contains( attr.getName() );
380
381 if ( dontDisplay ) {
382 continue;
383 }
384
385 DataField dataField = ComponentFactory.getDataField();
386 dataField.setPropertyName(attr.getName());
387 ((List<Component>)section.getItems()).add(dataField);
388 }
389 ((List<Group>)view.getItems()).add(section);
390 }
391 }
392
393
394
395 @Override
396 public InquiryView deriveInquiryViewFromMetadata(DataObjectEntry dataObjectEntry) {
397
398 InquiryView view = ComponentFactory.getInquiryView();
399 view.setHeaderText(dataObjectEntry.getObjectLabel());
400 view.setDataObjectClassName(dataObjectEntry.getDataObjectClass());
401
402 addAttributeSectionsToInquiryView(view, dataObjectEntry);
403
404
405
406
407 addCollectionSectionsToInquiryView(view, dataObjectEntry);
408
409 return view;
410 }
411
412 protected void addAttributesToLookupCriteria( LookupView view, DataObjectEntry dataObjectEntry ) {
413 AttributeDefinition activeAttribute = null;
414
415 for ( AttributeDefinition attr : dataObjectEntry.getAttributes() ) {
416
417 boolean dontDisplay = hasHintOfType(attr.getDataObjectAttribute(), UifDisplayHintType.NO_LOOKUP_CRITERIA);
418 dontDisplay |= (attr.getControlField() instanceof HiddenControl);
419
420 if ( dontDisplay ) {
421 continue;
422 }
423
424 if ( attr.getName().equals( KRADPropertyConstants.ACTIVE ) ) {
425 activeAttribute = attr;
426 continue;
427 }
428
429 LookupInputField field = ComponentFactory.getLookupCriteriaInputField();
430 field.setPropertyName(attr.getName());
431 field.setLabel(attr.getLabel());
432 view.getCriteriaFields().add(field);
433 }
434
435
436 if ( activeAttribute != null ) {
437 LookupInputField field = ComponentFactory.getLookupCriteriaInputField();
438 field.setPropertyName(activeAttribute.getName());
439 field.setLabel(activeAttribute.getLabel());
440 view.getCriteriaFields().add(field);
441 }
442 }
443
444 protected void addAttributesToLookupResults( LookupView view, DataObjectEntry dataObjectEntry ) {
445 AttributeDefinition activeAttribute = null;
446
447 for ( AttributeDefinition attr : dataObjectEntry.getAttributes() ) {
448
449 boolean dontDisplay = hasHintOfType(attr.getDataObjectAttribute(), UifDisplayHintType.NO_LOOKUP_RESULT);
450 dontDisplay |= (attr.getControlField() instanceof HiddenControl);
451
452 if ( dontDisplay ) {
453 continue;
454 }
455
456 if ( attr.getName().equals( KRADPropertyConstants.ACTIVE ) ) {
457 activeAttribute = attr;
458 continue;
459 }
460
461 DataField field = ComponentFactory.getDataField();
462 field.setPropertyName(attr.getName());
463 view.getResultFields().add(field);
464 }
465
466
467 if ( activeAttribute != null ) {
468 DataField field = ComponentFactory.getDataField();
469 field.setPropertyName(activeAttribute.getName());
470 view.getResultFields().add(field);
471 }
472 }
473
474
475
476
477 @Override
478 public LookupView deriveLookupViewFromMetadata(DataObjectEntry dataObjectEntry) {
479 LookupView view = ComponentFactory.getLookupView();
480 view.setHeaderText(dataObjectEntry.getObjectLabel() + " Lookup");
481 view.setDataObjectClass(dataObjectEntry.getDataObjectClass());
482 view.setCriteriaFields(new ArrayList<Component>());
483 view.setResultFields(new ArrayList<Component>());
484 view.setDefaultSortAttributeNames(dataObjectEntry.getPrimaryKeys());
485
486 addAttributesToLookupCriteria(view, dataObjectEntry);
487 addAttributesToLookupResults(view, dataObjectEntry);
488
489 return view;
490 }
491
492 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
493 this.dataDictionaryService = dataDictionaryService;
494 }
495
496 public void setDataObjectService(DataObjectService dataObjectService) {
497 this.dataObjectService = dataObjectService;
498 }
499 }