View Javadoc

1   package org.kuali.rice.krad.data.provider.util;
2   
3   import java.util.HashSet;
4   import java.util.List;
5   import java.util.Set;
6   
7   import org.apache.commons.lang.StringUtils;
8   import org.kuali.rice.krad.data.DataObjectService;
9   import org.kuali.rice.krad.data.DataObjectUtils;
10  import org.kuali.rice.krad.data.DataObjectWrapper;
11  import org.kuali.rice.krad.data.metadata.DataObjectAttributeRelationship;
12  import org.kuali.rice.krad.data.metadata.DataObjectMetadata;
13  import org.kuali.rice.krad.data.metadata.DataObjectRelationship;
14  import org.kuali.rice.krad.data.metadata.MetadataRepository;
15  
16  /**
17   * Links parent-child object references
18   */
19  public class ReferenceLinker {
20  	private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ReferenceLinker.class);
21  
22      private DataObjectService dataObjectService;
23  
24      public ReferenceLinker(DataObjectService dataObjectService) {
25          this.dataObjectService = dataObjectService;
26      }
27  
28      protected DataObjectService getDataObjectService() {
29          return dataObjectService;
30      }
31  
32      protected MetadataRepository getMetadataRepository() {
33          return getDataObjectService().getMetadataRepository();
34      }
35  
36      /**
37       * For each reference object to the parent persistableObject, sets the key
38       * values for that object. First, if the reference object already has a
39       * value for the key, the value is left unchanged. Otherwise, for
40       * non-anonymous keys, the value is taken from the parent object. For
41       * anonymous keys, all other persistableObjects are checked until a value
42       * for the key is found.
43       */
44      public void linkObjects(Object persistableObject) {
45          linkObjectsWithCircularReferenceCheck(persistableObject, new HashSet<Object>());
46      }
47  
48      protected void linkObjectsWithCircularReferenceCheck(Object persistableObject, Set<Object> referenceSet) {
49          if (referenceSet.contains(persistableObject) || DataObjectUtils.isNull(persistableObject)) {
50              return;
51          }
52  		if (LOG.isDebugEnabled()) {
53  			LOG.debug("Attempting to link reference objects on " + persistableObject);
54  		}
55          referenceSet.add(persistableObject);
56          DataObjectMetadata metadata = getMetadataRepository().getMetadata(persistableObject.getClass());
57  
58          if (metadata == null) {
59              LOG.warn("Unable to find metadata for "
60                      + persistableObject.getClass()
61                      + " when linking references, skipping");
62              return;
63          }
64  
65          DataObjectWrapper<?> wrap = getDataObjectService().wrap(persistableObject);
66          // iterate through all object references for the persistableObject
67          List<DataObjectRelationship> objectReferences = metadata.getRelationships();
68  		if (LOG.isDebugEnabled()) {
69  			LOG.debug("Obtained relationships for linking: " + objectReferences);
70  		}
71          for (DataObjectRelationship referenceDescriptor : objectReferences) {
72              // get the actual reference object
73              String fieldName = referenceDescriptor.getName();
74              Object referenceObject = wrap.getPropertyValue(fieldName);
75  			if (referenceObject == null) {
76  				if (LOG.isDebugEnabled()) {
77  					LOG.debug("Referenced object for field " + fieldName + " is null, skipping");
78  				}
79  			} else if (referenceSet.contains(referenceObject)) {
80  				if (LOG.isDebugEnabled()) {
81  					LOG.debug("We've previously linked the object assigned to " + fieldName + ", skipping");
82  				}
83                  continue;
84              }
85  
86              // recursively link object
87              linkObjectsWithCircularReferenceCheck(referenceObject, referenceSet);
88  
89              // iterate through the keys for the reference object and set
90              // value
91  			List<DataObjectAttributeRelationship> refAttrs = referenceDescriptor.getAttributeRelationships();
92              DataObjectMetadata refCld = getMetadataRepository().getMetadata(referenceDescriptor.getRelatedType());
93              if (refCld == null) {
94                  LOG.warn("No metadata found in repository for referenced object: " + referenceDescriptor);
95                  continue;
96              }
97  			// List<String> refPkNames = refCld.getPrimaryKeyAttributeNames();
98  
99  			// Get the relationship FK field name -> value as a Map
100 			// This pulls the *values* from the referenced object but is indexed by the parent object
101 			// Map<String, Object> childObjectFkValues = new HashMap<String, Object>();
102 			// for (DataObjectAttributeRelationship attrRel : refAttrs) {
103 			// childObjectFkValues.put(attrRel.getParentAttributeName(),
104 			// referenceWrap.getPropertyValue(attrRel.getChildAttributeName()));
105 			// }
106 
107 			if (LOG.isDebugEnabled()) {
108 				LOG.debug("Linking Referenced fields with parent's FK fields:" + "\n***Refs: " + refAttrs);
109 			}
110 
111 			for (DataObjectAttributeRelationship attrRel : refAttrs) {
112 				String fkPropertyName = attrRel.getParentAttributeName();
113 				Object parentObjectFkValue = wrap.getPropertyValue(fkPropertyName);
114                 Object fkValue = null;
115 
116                 // if fk is set in main object, take value from there
117 				if (parentObjectFkValue != null && StringUtils.isNotBlank(parentObjectFkValue.toString())) {
118 					fkValue = parentObjectFkValue;
119 					if (LOG.isDebugEnabled()) {
120 						LOG.debug("Parent Object has FK value set (" + fkPropertyName + "=" + fkValue + "): using that");
121                     }
122 				} else {
123 					// get the FK value from the linked object
124 					if (referenceObject != null) {
125 						DataObjectWrapper<?> referenceWrap = getDataObjectService().wrap(referenceObject);
126 						fkValue = referenceWrap.getPropertyValue(attrRel.getChildAttributeName());
127 					}
128 					if (fkValue == null || StringUtils.isBlank(fkValue.toString())) {
129 						// find the value from one of the other reference objects
130 						for (DataObjectRelationship checkDescriptor : objectReferences) {
131 							fkValue = getReferenceFKValue(persistableObject, wrap, checkDescriptor, fkPropertyName);
132 							if (fkValue != null && StringUtils.isNotBlank(fkValue.toString())) {
133 								break;
134 							}
135 						}
136 					}
137                 }
138 
139                 // set the fk value
140 				if (fkValue != null) {
141 					// fieldName = attrRel.getChildAttributeName();
142 					// referenceWrap.setPropertyValue(fieldName, fkValue);
143                     // set fk in main object
144 					if (parentObjectFkValue == null) {
145 						wrap.setPropertyValue(fkPropertyName, fkValue);
146                     }
147                 }
148             }
149         }
150 
151     }
152 
153     private Object getReferenceFKValue(Object persistableObject, DataObjectWrapper<?> wrap, DataObjectRelationship chkRefCld, String fkName) {
154         DataObjectMetadata classDescriptor = getMetadataRepository().getMetadata(persistableObject.getClass());
155         Object referenceObject = wrap.getPropertyValue(chkRefCld.getName());
156 
157         if (referenceObject == null) {
158             return null;
159         }
160 
161         List<DataObjectAttributeRelationship> refFkNames = chkRefCld.getAttributeRelationships();
162         DataObjectMetadata refCld = getMetadataRepository().getMetadata(chkRefCld.getRelatedType());
163         List<String> refPkNames = refCld.getPrimaryKeyAttributeNames();
164 
165         DataObjectWrapper<?> referenceWrap = getDataObjectService().wrap(referenceObject);
166         Object fkValue = null;
167         for (int i = 0; i < refFkNames.size(); i++) {
168             DataObjectAttributeRelationship fkField = refFkNames.get(i);
169 
170             if (fkField.getParentAttributeName().equals(fkName)) {
171                 fkValue = referenceWrap.getPropertyValueNullSafe(refPkNames.get(i));
172                 break;
173             }
174         }
175 
176         return fkValue;
177     }
178 }