View Javadoc

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<? extends BusinessObject> 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       * @param targetClass
77       */
78      public Class<? extends BusinessObject> getTargetClass() {
79          if (targetClass == null) {
80  	        Class propertyClass = DataDictionary.getAttributeClass(sourceClass, objectAttributeName);
81  	        if (propertyClass == null) {
82  	            throw new AttributeValidationException("cannot get valid class for property '" + objectAttributeName + "' as an attribute of '" + sourceClass + "'");
83  	        }
84  	        if (!BusinessObject.class.isAssignableFrom(propertyClass)) {
85                  throw new AttributeValidationException("property '" + objectAttributeName + "' is not a BusinessObject (" + propertyClass.getName() + ") on sourceClass (" + sourceClass +")");
86  	        }
87  	
88  	
89  	        targetClass = propertyClass;
90          }
91          return targetClass;
92      }
93  
94      /**
95       * Sets the {@link #targetClass}
96       * 
97       * @param targetClass
98       */
99      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.krad.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<?> sourceClass) {
213 		this.sourceClass = sourceClass;
214 	}
215 }
216