1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.data.provider.util;
17
18 import java.util.Collection;
19 import java.util.HashSet;
20 import java.util.List;
21 import java.util.Set;
22
23 import org.apache.commons.lang.ObjectUtils;
24 import org.apache.commons.lang.StringUtils;
25 import org.kuali.rice.krad.data.DataObjectService;
26 import org.kuali.rice.krad.data.DataObjectUtils;
27 import org.kuali.rice.krad.data.DataObjectWrapper;
28 import org.kuali.rice.krad.data.metadata.DataObjectAttributeRelationship;
29 import org.kuali.rice.krad.data.metadata.DataObjectCollection;
30 import org.kuali.rice.krad.data.metadata.DataObjectMetadata;
31 import org.kuali.rice.krad.data.metadata.DataObjectRelationship;
32 import org.kuali.rice.krad.data.metadata.MetadataRepository;
33
34
35
36
37 public class ReferenceLinker {
38 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ReferenceLinker.class);
39
40 private DataObjectService dataObjectService;
41
42 public ReferenceLinker(DataObjectService dataObjectService) {
43 this.dataObjectService = dataObjectService;
44 }
45
46 protected DataObjectService getDataObjectService() {
47 return dataObjectService;
48 }
49
50 protected MetadataRepository getMetadataRepository() {
51 return getDataObjectService().getMetadataRepository();
52 }
53
54
55
56
57
58
59
60
61
62 public void linkObjects(Object persistableObject) {
63 linkObjectsWithCircularReferenceCheck(persistableObject, new HashSet<Object>());
64 }
65
66 protected void linkObjectsWithCircularReferenceCheck(Object persistableObject, Set<Object> referenceSet) {
67 if (referenceSet.contains(persistableObject) || DataObjectUtils.isNull(persistableObject)) {
68 return;
69 }
70 if (LOG.isDebugEnabled()) {
71 LOG.debug("Attempting to link reference objects on " + persistableObject);
72 }
73 referenceSet.add(persistableObject);
74 DataObjectMetadata metadata = getMetadataRepository().getMetadata(persistableObject.getClass());
75
76 if (metadata == null) {
77 LOG.warn("Unable to find metadata for "
78 + persistableObject.getClass()
79 + " when linking references, skipping");
80 return;
81 }
82
83 linkRelationships(metadata, persistableObject, referenceSet);
84 linkCollections(metadata, persistableObject, referenceSet);
85 }
86
87 protected void linkRelationships(DataObjectMetadata metadata, Object persistableObject, Set<Object> referenceSet) {
88
89 List<DataObjectRelationship> objectReferences = metadata.getRelationships();
90 if (LOG.isDebugEnabled()) {
91 LOG.debug("Obtained relationships for linking: " + objectReferences);
92 }
93 DataObjectWrapper<?> parentWrap = getDataObjectService().wrap(persistableObject);
94 for (DataObjectRelationship referenceDescriptor : objectReferences) {
95
96 String fieldName = referenceDescriptor.getName();
97 Object childObject = parentWrap.getPropertyValue(fieldName);
98 boolean updatableRelationship = referenceDescriptor.isSavedWithParent();
99 if (childObject == null) {
100 if (LOG.isDebugEnabled()) {
101 LOG.debug("Referenced object for field " + fieldName + " is null, skipping");
102 }
103 continue;
104 }
105
106
107 linkObjectsWithCircularReferenceCheck(childObject, referenceSet);
108
109
110
111 List<DataObjectAttributeRelationship> refAttrs = referenceDescriptor.getAttributeRelationships();
112 DataObjectMetadata refCld = getMetadataRepository().getMetadata(referenceDescriptor.getRelatedType());
113 if (refCld == null) {
114 LOG.warn("No metadata found in repository for referenced object: " + referenceDescriptor);
115 continue;
116 }
117
118
119 if (LOG.isDebugEnabled()) {
120 LOG.debug("Linking Referenced fields with parent's FK fields:" + "\n***Refs: " + refAttrs);
121 }
122
123
124
125
126
127
128
129
130
131 DataObjectWrapper<?> childWrap = getDataObjectService().wrap(childObject);
132 if (updatableRelationship) {
133 linkUpdatableChild(parentWrap, childWrap, referenceDescriptor.getName(), refAttrs);
134 } else {
135 linkNonUpdatableChild(parentWrap, childWrap, referenceDescriptor.getName(), refAttrs);
136 }
137 }
138 }
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154 protected void linkUpdatableChild(DataObjectWrapper<?> parentWrap, DataObjectWrapper<?> childWrap,
155 String childObjectPropertyName, List<DataObjectAttributeRelationship> refAttrs) {
156 DataObjectMetadata referenceMetadata = childWrap.getMetadata();
157 List<String> childPkAttributes = referenceMetadata.getPrimaryKeyAttributeNames();
158 List<String> parentPkAttributes = parentWrap.getMetadata().getPrimaryKeyAttributeNames();
159 for (DataObjectAttributeRelationship attrRel : refAttrs) {
160 Object parentPropertyValue = parentWrap.getPropertyValue(attrRel.getParentAttributeName());
161 Object childPropertyValue = childWrap.getPropertyValueNullSafe(attrRel.getChildAttributeName());
162
163
164 if (parentPropertyValue != null && StringUtils.isNotBlank(parentPropertyValue.toString())) {
165
166
167
168 if (childPkAttributes.contains(attrRel.getChildAttributeName()) && childPropertyValue != null
169 && StringUtils.isNotBlank(childPropertyValue.toString())) {
170 if (LOG.isDebugEnabled()) {
171 LOG.debug("Relationship is to PK value on updatable child object - it may not be changed. Skipping: "
172 + childWrap.getWrappedClass().getName() + "." + attrRel.getChildAttributeName());
173 }
174 continue;
175 }
176 if (LOG.isDebugEnabled()) {
177 LOG.debug("Parent Object Of Updateable Child has FK value set (" + attrRel.getParentAttributeName()
178 + "="
179 + parentPropertyValue + "): using that");
180 }
181 childWrap.setPropertyValue(attrRel.getChildAttributeName(), parentPropertyValue);
182 } else {
183
184
185
186
187
188
189 if (childPropertyValue != null && StringUtils.isNotBlank(childPropertyValue.toString())) {
190 if (parentPkAttributes.contains(attrRel.getParentAttributeName())) {
191 if (LOG.isDebugEnabled()) {
192 LOG.debug("Relationship is to PK value on parent object - it may not be changed. Skipping: "
193 + parentWrap.getWrappedClass().getName() + "." + attrRel.getParentAttributeName());
194 }
195 continue;
196 }
197 if (LOG.isDebugEnabled()) {
198 LOG.debug("Updatable Child Object has FK value set (" + attrRel.getChildAttributeName() + "="
199 + childPropertyValue + "): using that");
200 }
201 parentWrap.setPropertyValue(attrRel.getParentAttributeName(), childPropertyValue);
202 }
203 }
204 }
205 }
206
207 protected void linkNonUpdatableChild(DataObjectWrapper<?> parentWrap, DataObjectWrapper<?> childWrap,
208 String childObjectPropertyName, List<DataObjectAttributeRelationship> refAttrs) {
209 for (DataObjectAttributeRelationship attrRel : refAttrs) {
210 Object parentPropertyValue = parentWrap.getPropertyValueNullSafe(attrRel.getParentAttributeName());
211 Object childPropertyValue = childWrap.getPropertyValueNullSafe(attrRel.getChildAttributeName());
212
213
214
215
216 if (ObjectUtils.notEqual(parentPropertyValue, childPropertyValue)) {
217 parentWrap.setPropertyValue(childObjectPropertyName, null);
218 break;
219
220
221 }
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237 }
238 }
239
240 protected void linkCollections(DataObjectMetadata metadata, Object persistableObject, Set<Object> referenceSet) {
241 List<DataObjectCollection> collections = metadata.getCollections();
242 if (LOG.isDebugEnabled()) {
243 LOG.debug("Obtained collections for linking: " + collections);
244 }
245
246 for (DataObjectCollection collectionMetadata : collections) {
247
248 if (!collectionMetadata.isSavedWithParent()) {
249 continue;
250 }
251
252 String fieldName = collectionMetadata.getName();
253 DataObjectWrapper<?> parentObjectWrapper = getDataObjectService().wrap(persistableObject);
254 Collection<?> collection = (Collection<?>) parentObjectWrapper.getPropertyValue(fieldName);
255 if (collection == null) {
256 if (LOG.isDebugEnabled()) {
257 LOG.debug("Referenced collection for field " + fieldName + " is null, skipping");
258 }
259 continue;
260 } else if (referenceSet.contains(collection)) {
261 if (LOG.isDebugEnabled()) {
262 LOG.debug("We've previously linked the object assigned to " + fieldName + ", skipping");
263 }
264 continue;
265 }
266 List<DataObjectAttributeRelationship> collectionAttributeRelationships = collectionMetadata
267 .getAttributeRelationships();
268
269
270
271 for (Object collectionItem : collection) {
272
273 linkObjectsWithCircularReferenceCheck(collectionItem, referenceSet);
274
275 DataObjectWrapper<Object> collItemWrapper = getDataObjectService().wrap(collectionItem);
276
277
278
279
280
281
282 for (DataObjectAttributeRelationship rel : collectionAttributeRelationships) {
283 if(rel.getChildAttributeName() != null && rel.getParentAttributeName() != null){
284 collItemWrapper.setPropertyValue(rel.getChildAttributeName(),
285 parentObjectWrapper.getPropertyValueNullSafe(rel.getParentAttributeName()));
286 }
287 }
288 }
289 }
290 }
291
292 }