View Javadoc
1   /**
2    * Copyright 2005-2015 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.krad.data.metadata.impl;
17  
18  import java.beans.PropertyEditor;
19  import java.util.Collections;
20  import java.util.Set;
21  
22  import org.apache.commons.lang.StringUtils;
23  import org.kuali.rice.core.api.data.DataType;
24  import org.kuali.rice.krad.data.metadata.DataObjectAttribute;
25  import org.kuali.rice.krad.data.provider.annotation.UifDisplayHint;
26  import org.kuali.rice.krad.keyvalues.KeyValuesFinder;
27  
28  import com.google.common.annotations.Beta;
29  
30  /**
31   * Base implementation class for attribute metadata for data object classes.
32   *
33   * <p>
34   * This implementation supports "chaining" for most attributes. That is, if the value for a property is defined locally,
35   * it will me used. If unset (null) it will, if there is an {@link #embeddedAttribute}, request it from that
36   * DataObjectAttribute. (This could be a recursive operation if multiple metadata providers are chained.)
37   * </p>
38   * <p>
39   * If the value is unset and there is no embedded attribute, most methods will return a non-null default value.
40   * </p>
41   *
42   * @author Kuali Rice Team (rice.collab@kuali.org)
43   */
44  public class DataObjectAttributeImpl extends MetadataCommonBase implements DataObjectAttributeInternal {
45  	private static final long serialVersionUID = -5241499559388935579L;
46  	private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DataObjectAttributeImpl.class);
47  
48  	protected DataObjectAttribute embeddedAttribute;
49  
50  	protected Class<?> owningType;
51  
52  	// These are temporary placeholders for the source property from which a property was inherited when
53  	// it "lives" on a related object. E.g., accountType.codeAndDescription
54  	// After all metadata has been imported, this information will be used to "embed" the parent
55  	// DataObjectAttribute so that properties (E.g., label) are inherited from there
56  	protected Class<?> inheritedFromType;
57  	protected String inheritedFromAttributeName;
58  	protected String inheritedFromParentAttributeName;
59  	protected String displayAttributeName;
60  	protected Boolean caseInsensitive;
61  	protected Boolean forceUppercase;
62  	protected Boolean required;
63  	protected Boolean persisted;
64  	protected Boolean sensitive;
65  	protected Long maxLength;
66  	protected Long minLength;
67  	protected String validCharactersConstraintBeanName;
68  
69  	protected PropertyEditor propertyEditor;
70  	protected KeyValuesFinder validValues;
71  	protected DataType dataType;
72  	protected Class<?> type;
73  	
74  	protected Set<UifDisplayHint> displayHints;
75  
76      /**
77       * {@inheritDoc}
78       */
79  	@Override
80  	public String getDisplayAttributeName() {
81  		if (displayAttributeName != null) {
82  			return displayAttributeName;
83  		}
84  
85  		if (embeddedAttribute != null) {
86  			return embeddedAttribute.getDisplayAttributeName();
87  		}
88  
89  		return getName();
90  	}
91  
92      /**
93      * Sets the attribute display name.
94      *
95      * @param displayAttributeName the attribute name.
96      */
97  	public void setDisplayAttributeName(String displayAttributeName) {
98  		if (StringUtils.isBlank(displayAttributeName)) {
99  			displayAttributeName = null;
100 		}
101 
102 		this.displayAttributeName = displayAttributeName;
103 	}
104 
105     /**
106      * {@inheritDoc}
107      */
108 	@Override
109 	public boolean isCaseInsensitive() {
110 		if (caseInsensitive != null) {
111 			return caseInsensitive;
112 		}
113 
114 		if (embeddedAttribute != null) {
115 			return embeddedAttribute.isCaseInsensitive();
116 		}
117 
118 		return false;
119 	}
120 
121     /**
122     * Sets value that determines whether attribute is case insensitive.
123     *
124     * @param caseInsensitive whether attribute is case insensitive.
125     */
126 	public void setCaseInsensitive(boolean caseInsensitive) {
127 		this.caseInsensitive = caseInsensitive;
128 	}
129 
130     /**
131      * {@inheritDoc}
132      */
133 	@Override
134 	public boolean isForceUppercase() {
135 		if (forceUppercase != null) {
136 			return forceUppercase;
137 		}
138 
139 		if (embeddedAttribute != null) {
140 			return embeddedAttribute.isForceUppercase();
141 		}
142 
143 		return false;
144 	}
145 
146 
147     /**
148     * Determines if attribute should be forced to upper case.
149     *
150     * @param forceUppercase whether attribute should be forced to upper.
151     */
152 	public void setForceUppercase(boolean forceUppercase) {
153 		this.forceUppercase = forceUppercase;
154 	}
155 
156     /**
157      * {@inheritDoc}
158      */
159 	@Override
160 	public PropertyEditor getPropertyEditor() {
161 		if (propertyEditor != null) {
162 			return propertyEditor;
163 		}
164 
165 		if (embeddedAttribute != null) {
166 			return embeddedAttribute.getPropertyEditor();
167 		}
168 
169 		return null;
170 	}
171 
172     /**
173      * Sets the property editor used when loading data.
174      *
175      * @param propertyEditor determines formats when loading data.
176      */
177 	public void setPropertyEditor(PropertyEditor propertyEditor) {
178 		this.propertyEditor = propertyEditor;
179 	}
180 
181     /**
182      * {@inheritDoc}
183      */
184 	@Override
185 	public KeyValuesFinder getValidValues() {
186 		if (validValues != null) {
187 			return validValues;
188 		}
189 
190 		if (embeddedAttribute != null) {
191 			return embeddedAttribute.getValidValues();
192 		}
193 
194 		return null;
195 	}
196 
197     /**
198     * Sets keyValueFinder used for dropdown.
199     *
200     * @param validValues dropdown keyValueFinder.
201     */
202 	public void setValidValues(KeyValuesFinder validValues) {
203 		this.validValues = validValues;
204 	}
205 
206     /**
207      * {@inheritDoc}
208      */
209 	@Override
210 	public DataType getDataType() {
211 		if (dataType != null) {
212 			return dataType;
213 		}
214 
215 		if (embeddedAttribute != null) {
216 			return embeddedAttribute.getDataType();
217 		}
218 
219 		return DataType.STRING;
220 	}
221 
222     /**
223     * Sets KRAD data type.
224     *
225     * @param dataType KRAD derived data type.
226     */
227 	public void setDataType(DataType dataType) {
228 		this.dataType = dataType;
229 	}
230 
231     /**
232      * {@inheritDoc}
233      */
234 	@Override
235 	public String toString() {
236 		StringBuilder builder = new StringBuilder();
237 		builder.append("DataObjectAttribute [");
238 		builder.append("name=").append(name);
239 		if (label != null) {
240 			builder.append(", ").append("label=").append(label);
241 		}
242 		if (backingObjectName != null) {
243 			builder.append(", ").append("backingObjectName=").append(backingObjectName);
244 		}
245 		if (dataType != null) {
246 			builder.append(", ").append("dataType=").append(dataType);
247 		}
248 		if (type != null) {
249 			builder.append(", ").append("type=").append(type.getName());
250 		}
251 		if (caseInsensitive != null) {
252 			builder.append(", ").append("caseInsensitive=").append(caseInsensitive);
253 		}
254 		if (propertyEditor != null) {
255 			builder.append(", ").append("propertyEditor=").append(propertyEditor);
256 		}
257 		if (sensitive != null && sensitive) {
258 			builder.append(", ").append("sensitive=").append(sensitive);
259 		}
260 		if (validValues != null) {
261 			builder.append(", ").append("validValues=").append(validValues);
262 		}
263 		if (inheritedFromType != null) {
264 			builder.append(", ").append("inheritedFromType=").append(inheritedFromType);
265 		}
266 		if (inheritedFromAttributeName != null) {
267 			builder.append(", ").append("inheritedFromAttributeName=").append(inheritedFromAttributeName);
268 		}
269 		builder.append(", ").append("mergeAction=").append(mergeAction);
270 		builder.append("]");
271 		return builder.toString();
272 	}
273 
274     /**
275      * {@inheritDoc}
276      */
277 	@Override
278 	public Long getMaxLength() {
279 		if (maxLength != null) {
280 			return maxLength;
281 		}
282 
283 		if (embeddedAttribute != null) {
284 			return embeddedAttribute.getMaxLength();
285 		}
286 
287 		return null;
288 	}
289 
290     /**
291     * Sets max length of attribute.
292     *
293     * @param maxLength attribute max length.
294     */
295 	public void setMaxLength(Long maxLength) {
296 		this.maxLength = maxLength;
297 	}
298 
299     /**
300      * {@inheritDoc}
301      */
302 	@Override
303 	public DataObjectAttribute getEmbeddedAttribute() {
304 		return embeddedAttribute;
305 	}
306 
307     /**
308      * {@inheritDoc}
309      */
310 	@Override
311 	public void setEmbeddedAttribute(DataObjectAttribute embeddedAttribute) {
312 		// protect against embedding itself
313 		if (embeddedAttribute == this) {
314 			LOG.warn(
315 					"ERROR!!!!  Attempt to embed a DataObjectAttribute into itself.  You must really want a stack overflow!  Trace: ",
316 					new Throwable("Throw-away Throwable for tracing purposes."));
317 			return;
318 		}
319 
320 		this.embeddedAttribute = embeddedAttribute;
321 		setEmbeddedCommonMetadata(embeddedAttribute);
322 	}
323 
324     /**
325      * {@inheritDoc}
326      */
327 	@Override
328 	public boolean isRequired() {
329 		if (required != null) {
330 			return required;
331 		}
332 
333 		if (embeddedAttribute != null) {
334 			return embeddedAttribute.isRequired();
335 		}
336 
337 		return false;
338 	}
339 
340     /**
341     * Set whether attribute is required.
342     *
343     * @param required attribute required flag.
344     */
345 	public void setRequired(boolean required) {
346 		this.required = required;
347 	}
348 
349     /**
350      * {@inheritDoc}
351      */
352 	@Override
353     @Beta
354 	public String getValidCharactersConstraintBeanName() {
355 		if (validCharactersConstraintBeanName != null) {
356 			return validCharactersConstraintBeanName;
357 		}
358 
359 		if (embeddedAttribute != null) {
360 			return embeddedAttribute.getValidCharactersConstraintBeanName();
361 		}
362 
363 		return validCharactersConstraintBeanName;
364 	}
365 
366     /**
367      * BETA: Sets valid character constraint bean name.
368      *
369      * @param validCharactersConstraintBeanName character constraint bean name.
370      */
371     @Beta
372 	public void setValidCharactersConstraintBeanName(String validCharactersConstraintBeanName) {
373 		this.validCharactersConstraintBeanName = validCharactersConstraintBeanName;
374 	}
375 
376     /**
377      * {@inheritDoc}
378      */
379 	@Override
380 	public Class<?> getOwningType() {
381 		if (owningType != null) {
382 			return owningType;
383 		}
384 
385 		if (embeddedAttribute != null) {
386 			return embeddedAttribute.getOwningType();
387 		}
388 
389 		return null;
390 	}
391 
392     /**
393     * Sets the data object type to which this attribute belongs.
394     *
395     * @param owningType data object type to which this attribute belongs.
396     */
397 	public void setOwningType(Class<?> owningType) {
398 		this.owningType = owningType;
399 	}
400 
401     /**
402      * {@inheritDoc}
403      */
404 	@Override
405 	public boolean isPersisted() {
406 		if (persisted != null) {
407 			return persisted;
408 		}
409 
410 		if (embeddedAttribute != null) {
411 			return embeddedAttribute.isPersisted();
412 		}
413 
414 		return true;
415 	}
416 
417     /**
418     * Sets flag whether object is persisted.
419     *
420     * @param persisted flag whether object is persisted.
421     */
422 	public void setPersisted(boolean persisted) {
423 		this.persisted = persisted;
424 	}
425 
426     /**
427     * Determines type of class.
428     *
429     */
430 	public Class<?> getType() {
431 		if (type != null) {
432             return type;
433         }
434 
435 		return String.class;
436 	}
437 
438     /**
439     * Sets unknown class in order to determine type.
440     *
441     * @param javaType unknown class.
442     */
443 	public void setType(Class<?> javaType) {
444 		this.type = javaType;
445 	}
446 
447     /**
448      * {@inheritDoc}
449      */
450 	@Override
451 	public Class<?> getInheritedFromType() {
452 		if (inheritedFromType != null) {
453 			return inheritedFromType;
454 		}
455 
456 		if (embeddedAttribute != null) {
457 			return embeddedAttribute.getInheritedFromType();
458 		}
459 
460 		return null;
461 	}
462 
463     /**
464     * Sets unknown class to determine if inherited.
465     *
466     * @param inheritedFromType unknown class.
467     */
468 	public void setInheritedFromType(Class<?> inheritedFromType) {
469 		this.inheritedFromType = inheritedFromType;
470 	}
471 
472     /**
473      * {@inheritDoc}
474      */
475 	@Override
476 	public String getInheritedFromAttributeName() {
477 		if (inheritedFromAttributeName != null) {
478 			return inheritedFromAttributeName;
479 		}
480 
481 		if (embeddedAttribute != null) {
482 			return embeddedAttribute.getInheritedFromAttributeName();
483 		}
484 
485 		return null;
486 	}
487 
488     /**
489     * Sets data object name to determine if inherited.
490     *
491     * @param inheritedFromAttributeName name of attribute.
492     */
493 	public void setInheritedFromAttributeName(String inheritedFromAttributeName) {
494 		this.inheritedFromAttributeName = inheritedFromAttributeName;
495 	}
496 
497     /**
498      * {@inheritDoc}
499      */
500 	@Override
501 	public String getInheritedFromParentAttributeName() {
502 		if (inheritedFromParentAttributeName != null) {
503 			return inheritedFromParentAttributeName;
504 		}
505 
506 		if (embeddedAttribute != null) {
507 			return embeddedAttribute.getInheritedFromParentAttributeName();
508 		}
509 
510 		return null;
511 	}
512 
513     /**
514     * Sets parent data object name to determine if inherited.
515     *
516     * @param inheritedFromParentAttributeName name of attribute.
517     */
518 	public void setInheritedFromParentAttributeName(String inheritedFromParentAttributeName) {
519 		this.inheritedFromParentAttributeName = inheritedFromParentAttributeName;
520 	}
521 
522     /**
523      * {@inheritDoc}
524      */
525 	@Override
526 	public boolean isInherited() {
527 		return getInheritedFromAttributeName() != null;
528 	}
529 
530     /**
531      * {@inheritDoc}
532      */
533 	@Override
534 	public DataObjectAttribute getOriginalDataObjectAttribute() {
535 		if (embeddedAttribute == null) {
536 			return this;
537 		}
538 		return embeddedAttribute.getOriginalDataObjectAttribute();
539 	}
540 
541     /**
542      * {@inheritDoc}
543      */
544 	@Override
545 	public Long getMinLength() {
546 		if (minLength != null) {
547 			return minLength;
548 		}
549 		if (embeddedAttribute != null) {
550 			return embeddedAttribute.getMinLength();
551 		}
552 		return null;
553 	}
554 
555     /**
556     * Sets minimum length of attribute.
557     *
558     * @param minLength minimum length value.
559     */
560 	public void setMinLength(Long minLength) {
561 		this.minLength = minLength;
562 	}
563 
564     /**
565      * {@inheritDoc}
566      */
567 	@Override
568 	public boolean isSensitive() {
569 		if (sensitive != null) {
570 			return sensitive;
571 		}
572 
573 		if (embeddedAttribute != null) {
574 			return embeddedAttribute.isSensitive();
575 		}
576 
577 		return false;
578 	}
579 
580     /**
581     * Sets whether sensitive.
582     *
583     * @param sensitive whether attribute is sensitive.
584     */
585 	public void setSensitive(boolean sensitive) {
586 		this.sensitive = sensitive;
587 	}
588 
589     /**
590      * {@inheritDoc}
591      */
592     @Override
593     @Beta
594 	public Set<UifDisplayHint> getDisplayHints() {
595 		if (displayHints != null) {
596 			return displayHints;
597 		}
598 
599 		if (embeddedAttribute != null) {
600 			return embeddedAttribute.getDisplayHints();
601 		}
602 
603 		return Collections.emptySet();
604 	}
605 
606     /**
607     * BETA: Sets UIF display hints.
608     *
609     * @param displayHints UIF display hints.
610     */
611     @Beta
612 	public void setDisplayHints(Set<UifDisplayHint> displayHints) {
613 		this.displayHints = displayHints;
614 	}
615 }