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