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
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
38
39
40
41
42
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
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
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
87 linkObjectsWithCircularReferenceCheck(referenceObject, referenceSet);
88
89
90
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
98
99
100
101
102
103
104
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
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
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
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
140 if (fkValue != null) {
141
142
143
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 }