001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.datadictionary.validation; 017 018import java.beans.PropertyDescriptor; 019import java.util.ArrayList; 020import java.util.List; 021 022import org.kuali.rice.krad.datadictionary.AttributeDefinition; 023import org.kuali.rice.krad.datadictionary.DataDictionaryEntry; 024import org.kuali.rice.krad.datadictionary.DataDictionaryEntryBase; 025import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException; 026import org.kuali.rice.krad.datadictionary.validation.capability.Constrainable; 027import org.springframework.beans.BeanWrapper; 028import org.springframework.beans.BeanWrapperImpl; 029import org.springframework.beans.InvalidPropertyException; 030 031/** 032 * This class allows a dictionary object to expose information about its fields / attributes, including the values of 033 * those fields, with some guidance from the DataDictionaryEntry object. 034 * 035 * @author Kuali Rice Team (rice.collab@kuali.org) 036 */ 037public class DictionaryObjectAttributeValueReader extends BaseAttributeValueReader { 038 039 protected Object object; 040 protected DataDictionaryEntry entry; 041 042 protected BeanWrapper beanWrapper; 043 044 private String attributePath; 045 046 public DictionaryObjectAttributeValueReader(Object object, String entryName, DataDictionaryEntry entry) { 047 this.object = object; 048 this.entry = entry; 049 this.entryName = entryName; 050 051 if (object != null){ 052 beanWrapper = new BeanWrapperImpl(object); 053 } 054 } 055 056 public DictionaryObjectAttributeValueReader(Object object, String entryName, DataDictionaryEntry entry, String attributePath) { 057 this(object, entryName, entry); 058 this.attributePath = attributePath; 059 } 060 061 @Override 062 public Constrainable getDefinition(String attrName) { 063 return entry != null ? entry.getAttributeDefinition(attrName) : null; 064 } 065 066 @Override 067 public List<Constrainable> getDefinitions() { 068 if (entry instanceof DataDictionaryEntryBase) { 069 DataDictionaryEntryBase entryBase = (DataDictionaryEntryBase)entry; 070 List<Constrainable> definitions = new ArrayList<Constrainable>(); 071 List<AttributeDefinition> attributeDefinitions = entryBase.getAttributes(); 072 definitions.addAll(attributeDefinitions); 073 return definitions; 074 } 075 076 return null; 077 } 078 079 @Override 080 public Constrainable getEntry() { 081 if (entry instanceof Constrainable) 082 return (Constrainable) entry; 083 084 return null; 085 } 086 087 @Override 088 public String getLabel(String attrName) { 089 AttributeDefinition attributeDefinition = entry != null ? entry.getAttributeDefinition(attrName) : null; 090 return attributeDefinition != null ? attributeDefinition.getLabel() : attrName; 091 } 092 093 @Override 094 public Object getObject() { 095 return this.object; 096 } 097 098 @Override 099 public String getPath() { 100 String path = ValidationUtils.buildPath(attributePath, attributeName); 101 return path != null ? path : ""; 102 } 103 104 @Override 105 public Class<?> getType(String attrName) { 106 PropertyDescriptor propertyDescriptor = beanWrapper.getPropertyDescriptor(attrName); 107 108 return propertyDescriptor.getPropertyType(); 109 } 110 111 @Override 112 public boolean isReadable() { 113 return beanWrapper.isReadableProperty(attributeName); 114 } 115 116 @SuppressWarnings("unchecked") 117 @Override 118 public <X> X getValue() throws AttributeValidationException { 119 Object value = getValue(attributeName); 120 return (X) value; 121 } 122 123 @SuppressWarnings("unchecked") 124 @Override 125 public <X> X getValue(String attrName) throws AttributeValidationException { 126 X attributeValue = null; 127 128 Exception e = null; 129 try { 130 attributeValue = (X) beanWrapper.getPropertyValue(attrName); 131 } catch (IllegalArgumentException iae) { 132 e = iae; 133 } catch (InvalidPropertyException ipe){ 134 //just return null 135 } 136 137 if (e != null) 138 throw new AttributeValidationException("Unable to lookup attribute value by name (" + attrName + ") using introspection", e); 139 140 141 // JLR : KS has code to handle dynamic attributes -- not sure whether this is really needed anymore if we're actually relying on types 142 // // Extract dynamic attributes 143 // if(DYNAMIC_ATTRIBUTE.equals(propName)) { 144 // dataMap.putAll((Map<String, String>)value); 145 // } else { 146 // dataMap.put(propName, value); 147 // } 148 149 return attributeValue; 150 } 151 152 /** 153 * @return false if parent attribute exists and is not null, otherwise returns true. 154 */ 155 public boolean isParentAttributeNull(){ 156 boolean isParentNull = true; 157 158 if (isNestedAttribute()){ 159 String[] pathTokens = attributeName.split("\\."); 160 161 isParentNull = false; 162 String parentPath = ""; 163 for (int i=0; (i < pathTokens.length - 1) && !isParentNull;i++){ 164 parentPath += pathTokens[i]; 165 isParentNull = beanWrapper.getPropertyValue(parentPath) == null; 166 parentPath += "."; 167 } 168 } 169 170 return isParentNull; 171 } 172 173 public boolean isNestedAttribute(){ 174 return (attributePath != null || attributeName.contains(".")); 175 } 176 177 @Override 178 public AttributeValueReader clone(){ 179 DictionaryObjectAttributeValueReader readerClone = 180 new DictionaryObjectAttributeValueReader(this.object, this.entryName, this.entry, this.attributePath); 181 readerClone.setAttributeName(this.attributeName); 182 183 184 return readerClone; 185 } 186 187}