001 /* 002 * Copyright 2006-2007 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 */ 016 017 package org.kuali.rice.kns.datadictionary; 018 019 import java.util.ArrayList; 020 import java.util.List; 021 022 import org.apache.commons.lang.StringUtils; 023 import org.kuali.rice.kns.bo.BusinessObject; 024 import org.kuali.rice.kns.datadictionary.exception.AttributeValidationException; 025 026 /** 027 * A single Relationship definition in the DataDictionary, which contains information concerning which primitive attributes of this 028 * class can be used to retrieve an instance of some related Object instance 029 * 030 The relationship element defines how primitive attributes of this 031 class can be used to retrieve an instance of some related Object instance 032 DD: See RelationshipDefinition.java. 033 034 JSTL: relationship is a Map which is accessed using a key which is the 035 objectAttributeName of a relationship. The map contains a single entry 036 with a key of "primitiveAttributes" and value which is an attributesMap ExportMap. 037 038 The attributesMap ExportMap contains the following keys: 039 * 0 (for first primitiveAttribute) 040 * 1 (for second primitiveAttribute) 041 etc. 042 The corresponding value for each entry is an primitiveAttribute ExportMap 043 which contains the following keys: 044 * "sourceName" 045 * "targetName" 046 * 047 */ 048 public class RelationshipDefinition extends DataDictionaryDefinitionBase { 049 private static final long serialVersionUID = 2946722646095412576L; 050 051 protected String objectAttributeName; //Same as parentAttributeName of BusinessObjectRelationship 052 protected Class<? extends BusinessObject> sourceClass; //parentClass 053 /** 054 * For 1:1 relationships, this class represents the type of the reference class. For 1:n references, this class represents the type of the element 055 * of the collection 056 */ 057 protected Class<? extends BusinessObject> targetClass; //relatedClass 058 059 protected List<PrimitiveAttributeDefinition> primitiveAttributes = new ArrayList<PrimitiveAttributeDefinition>(); //parentToChildReferences 060 protected List<SupportAttributeDefinition> supportAttributes = new ArrayList<SupportAttributeDefinition>(); //parentToChildReferences 061 062 063 public RelationshipDefinition() {} 064 065 public String getObjectAttributeName() { 066 return objectAttributeName; 067 } 068 069 public Class<? extends BusinessObject> getSourceClass() { 070 return sourceClass; 071 } 072 073 /** 074 * Returns the {@link #targetClass} 075 * 076 * @param targetClass 077 */ 078 public Class<? extends BusinessObject> getTargetClass() { 079 if (targetClass == null) { 080 Class propertyClass = DataDictionary.getAttributeClass(sourceClass, objectAttributeName); 081 if (propertyClass == null) { 082 throw new AttributeValidationException("cannot get valid class for property '" + objectAttributeName + "' as an attribute of '" + sourceClass + "'"); 083 } 084 if (!BusinessObject.class.isAssignableFrom(propertyClass)) { 085 throw new AttributeValidationException("property '" + objectAttributeName + "' is not a BusinessObject (" + propertyClass.getName() + ")"); 086 } 087 088 089 targetClass = propertyClass; 090 } 091 return targetClass; 092 } 093 094 /** 095 * Sets the {@link #targetClass} 096 * 097 * @param targetClass 098 */ 099 public void setTargetClass(Class<? extends BusinessObject> targetClass) { 100 this.targetClass = targetClass; 101 } 102 103 /** 104 * Name of the business object property on the containing business object that is linked 105 * by the contained PrimitiveAttributeDefinition objects. 106 */ 107 public void setObjectAttributeName(String objectAttributeName) { 108 if (StringUtils.isBlank(objectAttributeName)) { 109 throw new IllegalArgumentException("invalid (blank) objectAttributeName"); 110 } 111 112 this.objectAttributeName = objectAttributeName; 113 } 114 115 public List<PrimitiveAttributeDefinition> getPrimitiveAttributes() { 116 return primitiveAttributes; 117 } 118 119 public List<SupportAttributeDefinition> getSupportAttributes() { 120 return supportAttributes; 121 } 122 123 public boolean hasIdentifier() { 124 for (SupportAttributeDefinition supportAttributeDefinition : supportAttributes) { 125 if ( supportAttributeDefinition.isIdentifier() ) { 126 return true; 127 } 128 } 129 return false; 130 } 131 132 public SupportAttributeDefinition getIdentifier() { 133 for (SupportAttributeDefinition supportAttributeDefinition : supportAttributes) { 134 if ( supportAttributeDefinition.isIdentifier() ) { 135 return supportAttributeDefinition; 136 } 137 } 138 return null; 139 } 140 141 /** 142 * Directly validate simple fields, call completeValidation on Definition fields. 143 * 144 * @see org.kuali.rice.kns.datadictionary.DataDictionaryEntry#completeValidation() 145 */ 146 public void completeValidation(Class rootBusinessObjectClass, Class otherBusinessObjectClass) { 147 String propertyName = objectAttributeName; 148 if (!DataDictionary.isPropertyOf(rootBusinessObjectClass, propertyName)) { 149 throw new AttributeValidationException("property '" + propertyName + "' is not an attribute of class '" + rootBusinessObjectClass + "' (" + "" + ")"); 150 } 151 152 getTargetClass(); // performs validation when this is called the first time 153 154 for (PrimitiveAttributeDefinition primitiveAttributeDefinition : primitiveAttributes) { 155 primitiveAttributeDefinition.completeValidation(rootBusinessObjectClass, targetClass); 156 } 157 for (SupportAttributeDefinition supportAttributeDefinition : supportAttributes) { 158 supportAttributeDefinition.completeValidation(rootBusinessObjectClass, targetClass); 159 } 160 } 161 162 163 /** 164 * @see java.lang.Object#toString() 165 */ 166 @Override 167 public String toString() { 168 return "RelationshipDefinition for relationship " + getObjectAttributeName(); 169 } 170 171 /** 172 * 173 The primitiveAttribute element identifies one pair of 174 corresponding fields in the primary business object and 175 the related business object. 176 177 JSTL: primitiveAttribute is a Map which is accessed by the 178 sequential key of "0", "1", etc. Each entry contains the following 179 keys: 180 * sourceName (String) 181 * targetName (String) 182 The value corresponding to the sourceName key is the attribute name defined 183 for the primary business object. 184 The value corresponding to the targetName key is the attribute name for 185 the object being referenced by objectAttributeName. 186 */ 187 public void setPrimitiveAttributes(List<PrimitiveAttributeDefinition> primitiveAttributes) { 188 this.primitiveAttributes = primitiveAttributes; 189 } 190 191 /** 192 Support attributes define additional attributes that can be used to generate 193 lookup field conversions and lookup parameters. 194 195 Field conversions and lookup parameters are normally generated using foreign key relationships 196 defined within OJB and the DD. Because Person objects are linked in a special way (i.e. they may 197 come from an external data source and not from the DB, such as LDAP), it is often necessary to define 198 extra fields that are related to each other, sort of like a supplemental foreign key. 199 200 sourceName is the name of the POJO property of the business object 201 targetName is the name of attribute that corresponds to the sourceName in the looked up BO 202 identifier when true, only the field marked as an identifier will be passed in as a lookup parameter 203 at most one supportAttribute for each relationship should be defined as identifier="true" 204 */ 205 public void setSupportAttributes(List<SupportAttributeDefinition> supportAttributes) { 206 this.supportAttributes = supportAttributes; 207 } 208 209 /** 210 * @param sourceClass the sourceClass to set 211 */ 212 public void setSourceClass(Class<? extends BusinessObject> sourceClass) { 213 this.sourceClass = sourceClass; 214 } 215 } 216