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