View Javadoc

1   /**
2    * Copyright 2005-2012 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.datadictionary.validation;
17  
18  import java.beans.PropertyDescriptor;
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.kuali.rice.krad.datadictionary.AttributeDefinition;
23  import org.kuali.rice.krad.datadictionary.ComplexAttributeDefinition;
24  import org.kuali.rice.krad.datadictionary.DataDictionaryEntry;
25  import org.kuali.rice.krad.datadictionary.DataDictionaryEntryBase;
26  import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException;
27  import org.kuali.rice.krad.datadictionary.validation.capability.Constrainable;
28  import org.springframework.beans.BeanWrapper;
29  import org.springframework.beans.BeanWrapperImpl;
30  import org.springframework.beans.NullValueInNestedPathException;
31  
32  /**
33   * This class allows a dictionary object to expose information about its fields / attributes, including the values of
34   * those fields, with some guidance from the DataDictionaryEntry object. 
35   * 
36   * @author Kuali Rice Team (rice.collab@kuali.org) 
37   */
38  public class DictionaryObjectAttributeValueReader extends BaseAttributeValueReader {
39  
40  	protected Object object;
41  	protected DataDictionaryEntry entry;
42  
43  	protected BeanWrapper beanWrapper;
44  	
45  	private String attributePath;
46  	
47  	public DictionaryObjectAttributeValueReader(Object object, String entryName, DataDictionaryEntry entry) {
48  		this.object = object;
49  		this.entry = entry;
50  		this.entryName = entryName;
51  
52  		if (object != null){
53  			beanWrapper = new BeanWrapperImpl(object);
54              beanWrapper.setAutoGrowNestedPaths(true);
55  		}
56  	}
57  	
58  	public DictionaryObjectAttributeValueReader(Object object, String entryName, DataDictionaryEntry entry, String attributePath) {
59  		this(object, entryName, entry);
60  		this.attributePath = attributePath;
61  	}
62  	
63  	@Override
64  	public Constrainable getDefinition(String attrName) {
65  		return entry != null ? entry.getAttributeDefinition(attrName) : null;
66  	}
67  	
68  	@Override
69  	public List<Constrainable> getDefinitions() {
70  		if (entry instanceof DataDictionaryEntryBase) {
71  			DataDictionaryEntryBase entryBase = (DataDictionaryEntryBase)entry;
72  			List<Constrainable> definitions = new ArrayList<Constrainable>();
73  			List<AttributeDefinition> attributeDefinitions = entryBase.getAttributes();
74  			definitions.addAll(attributeDefinitions);
75  			return definitions;
76  		}
77  		
78  		return null;
79  	}
80  	
81  	@Override
82  	public Constrainable getEntry() {
83  		if (entry instanceof Constrainable)
84  			return (Constrainable) entry;
85  			
86  		return null;
87  	}
88  	
89  	@Override
90  	public String getLabel(String attrName) {
91  		AttributeDefinition attributeDefinition = entry != null ? entry.getAttributeDefinition(attrName) : null;
92  		return attributeDefinition != null ? attributeDefinition.getLabel()  : attrName;
93  	}
94  
95  	@Override
96  	public Object getObject() {
97  		return this.object;
98  	}
99  	
100 	@Override
101 	public String getPath() {
102 		String path = ValidationUtils.buildPath(attributePath, attributeName);
103 		return path != null ? path : "";
104 	}
105 
106 	@Override
107 	public Class<?> getType(String attrName) {
108 		PropertyDescriptor propertyDescriptor = beanWrapper.getPropertyDescriptor(attrName);
109 		
110 		return propertyDescriptor.getPropertyType();
111 	}
112 
113     @Override
114     public boolean isReadable() {
115         return beanWrapper.isReadableProperty(attributeName);
116     }
117 
118     @SuppressWarnings("unchecked")
119 	@Override
120 	public <X> X getValue() throws AttributeValidationException {
121 		Object value = getValue(attributeName);
122 		return (X) value;
123 	}
124 	
125 	@SuppressWarnings("unchecked")
126 	@Override
127 	public <X> X getValue(String attrName) throws AttributeValidationException {
128 		X attributeValue = null;
129 		
130 		Exception e = null;
131 		try {
132 			attributeValue = (X) beanWrapper.getPropertyValue(attrName);
133 
134 		} catch (IllegalArgumentException iae) {
135 			e = iae;
136 		} catch (NullValueInNestedPathException nvinp){
137 			//just return null
138 		}
139 		
140 		if (e != null)
141 			throw new AttributeValidationException("Unable to lookup attribute value by name (" + attrName + ") using introspection", e);
142 		
143 		
144 		//			JLR : KS has code to handle dynamic attributes -- not sure whether this is really needed anymore if we're actually relying on types
145 		//            // Extract dynamic attributes
146 		//            if(DYNAMIC_ATTRIBUTE.equals(propName)) {
147 		//                dataMap.putAll((Map<String, String>)value);
148 		//            } else {
149 		//				dataMap.put(propName, value);
150 		//            }
151 		
152 		return attributeValue;
153 	}
154 	
155 	/**
156 	 * @return false if parent attribute exists and is not null, otherwise returns true.
157 	 */
158 	public boolean isParentAttributeNull(){
159 	    boolean isParentNull = true;
160 	    
161 	    if (isNestedAttribute()){
162 	        String[] pathTokens = attributeName.split("\\.");
163 
164 	        isParentNull = false;
165             String parentPath = "";
166 	        for (int i=0; (i < pathTokens.length - 1) && !isParentNull;i++){
167                 parentPath += pathTokens[i];
168 	            isParentNull = beanWrapper.getPropertyValue(parentPath) == null;
169 	            parentPath += ".";
170 	        }
171 	    }
172 	    
173 	    return isParentNull;
174 	}
175 	
176 	public boolean isNestedAttribute(){
177 	    return (attributePath != null || attributeName.contains("."));
178 	}
179 	
180 	public DictionaryObjectAttributeValueReader clone(){
181 	    DictionaryObjectAttributeValueReader readerClone = 
182 	        new DictionaryObjectAttributeValueReader(this.object, this.entryName, this.entry, this.attributePath);
183 	    readerClone.setAttributeName(this.attributeName);
184 	    
185 	    
186 	    return readerClone;	    
187 	}
188 	
189 }