001/** 002 * Copyright 2005-2015 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 org.kuali.rice.krad.datadictionary.AttributeDefinition; 019import org.kuali.rice.krad.datadictionary.DataDictionaryEntry; 020import org.kuali.rice.krad.datadictionary.DataDictionaryEntryBase; 021import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException; 022import org.kuali.rice.krad.datadictionary.validation.capability.Constrainable; 023import org.springframework.beans.BeanWrapper; 024import org.springframework.beans.BeanWrapperImpl; 025import org.springframework.beans.InvalidPropertyException; 026 027import java.beans.PropertyDescriptor; 028import java.util.ArrayList; 029import java.util.List; 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, 057 String attributePath) { 058 this(object, entryName, entry); 059 this.attributePath = attributePath; 060 } 061 062 @Override 063 public Constrainable getDefinition(String attrName) { 064 return entry != null ? entry.getAttributeDefinition(attrName) : null; 065 } 066 067 @Override 068 public List<Constrainable> getDefinitions() { 069 if (entry instanceof DataDictionaryEntryBase) { 070 DataDictionaryEntryBase entryBase = (DataDictionaryEntryBase) entry; 071 List<Constrainable> definitions = new ArrayList<Constrainable>(); 072 List<AttributeDefinition> attributeDefinitions = entryBase.getAttributes(); 073 definitions.addAll(attributeDefinitions); 074 return definitions; 075 } 076 077 return null; 078 } 079 080 @Override 081 public Constrainable getEntry() { 082 if (entry instanceof Constrainable) { 083 return (Constrainable) entry; 084 } 085 086 return null; 087 } 088 089 @Override 090 public String getLabel(String attrName) { 091 AttributeDefinition attributeDefinition = entry != null ? entry.getAttributeDefinition(attrName) : null; 092 return attributeDefinition != null ? attributeDefinition.getLabel() : attrName; 093 } 094 095 @Override 096 public Object getObject() { 097 return this.object; 098 } 099 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 } catch (IllegalArgumentException iae) { 134 e = iae; 135 } catch (InvalidPropertyException ipe) { 136 //just return null 137 } 138 139 if (e != null) { 140 throw new AttributeValidationException( 141 "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 @Override 181 public AttributeValueReader clone() { 182 DictionaryObjectAttributeValueReader readerClone = new DictionaryObjectAttributeValueReader(this.object, 183 this.entryName, this.entry, this.attributePath); 184 readerClone.setAttributeName(this.attributeName); 185 186 return readerClone; 187 } 188 189}