1 /**
2 * Copyright 2005-2011 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;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.kuali.rice.krad.bo.BusinessObject;
20 import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException;
21
22 import java.util.ArrayList;
23 import java.util.List;
24
25 /**
26 * A single Relationship definition in the DataDictionary, which contains information concerning which primitive attributes of this
27 * class can be used to retrieve an instance of some related Object instance
28 *
29 The relationship element defines how primitive attributes of this
30 class can be used to retrieve an instance of some related Object instance
31 DD: See RelationshipDefinition.java.
32
33 JSTL: relationship is a Map which is accessed using a key which is the
34 objectAttributeName of a relationship. The map contains a single entry
35 with a key of "primitiveAttributes" and value which is an attributesMap ExportMap.
36
37 The attributesMap ExportMap contains the following keys:
38 * 0 (for first primitiveAttribute)
39 * 1 (for second primitiveAttribute)
40 etc.
41 The corresponding value for each entry is an primitiveAttribute ExportMap
42 which contains the following keys:
43 * "sourceName"
44 * "targetName"
45 *
46 */
47 public class RelationshipDefinition extends DataDictionaryDefinitionBase {
48 private static final long serialVersionUID = 2946722646095412576L;
49
50 protected String objectAttributeName; //Same as parentAttributeName of DataObjectRelationship
51 protected Class<?> sourceClass; //parentClass
52
53 /**
54 * 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
55 * of the collection
56 */
57 protected Class<?> targetClass; //relatedClass
58
59 protected List<PrimitiveAttributeDefinition> primitiveAttributes = new ArrayList<PrimitiveAttributeDefinition>(); //parentToChildReferences
60 protected List<SupportAttributeDefinition> supportAttributes = new ArrayList<SupportAttributeDefinition>(); //parentToChildReferences
61
62
63 public RelationshipDefinition() {}
64
65 public String getObjectAttributeName() {
66 return objectAttributeName;
67 }
68
69 public Class<?> getSourceClass() {
70 return sourceClass;
71 }
72
73 /**
74 * Returns the {@link #targetClass}
75 */
76 public Class<?> getTargetClass() {
77 if (targetClass == null) {
78 Class propertyClass = DataDictionary.getAttributeClass(sourceClass, objectAttributeName);
79 if (propertyClass == null) {
80 throw new AttributeValidationException("cannot get valid class for property '" + objectAttributeName + "' as an attribute of '" + sourceClass + "'");
81 }
82
83 targetClass = propertyClass;
84 }
85 return targetClass;
86 }
87
88 /**
89 * Sets the {@link #targetClass}
90 *
91 * @param targetClass
92 */
93 public void setTargetClass(Class<?> targetClass) {
94 this.targetClass = targetClass;
95 }
96
97 /**
98 * Name of the business object property on the containing business object that is linked
99 * 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