1 package org.kuali.rice.krad.data.provider.impl;
2
3 import java.util.Set;
4
5 import org.kuali.rice.core.api.criteria.QueryByCriteria;
6 import org.kuali.rice.core.api.criteria.QueryResults;
7 import org.kuali.rice.krad.data.CompoundKey;
8 import org.kuali.rice.krad.data.CopyOption;
9 import org.kuali.rice.krad.data.DataObjectService;
10 import org.kuali.rice.krad.data.DataObjectWrapper;
11 import org.kuali.rice.krad.data.PersistenceOption;
12 import org.kuali.rice.krad.data.metadata.DataObjectAttributeRelationship;
13 import org.kuali.rice.krad.data.metadata.DataObjectMetadata;
14 import org.kuali.rice.krad.data.metadata.DataObjectRelationship;
15 import org.kuali.rice.krad.data.metadata.MetadataChild;
16 import org.kuali.rice.krad.data.metadata.MetadataRepository;
17 import org.kuali.rice.krad.data.provider.PersistenceProvider;
18 import org.kuali.rice.krad.data.provider.ProviderRegistry;
19 import org.kuali.rice.krad.data.util.ReferenceLinker;
20 import org.springframework.beans.factory.annotation.Required;
21 import org.springframework.dao.IncorrectResultSizeDataAccessException;
22
23 import com.google.common.collect.Sets;
24
25
26
27
28
29
30
31
32 public class ProviderBasedDataObjectService implements DataObjectService {
33 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
34 .getLogger(ProviderBasedDataObjectService.class);
35
36
37
38
39 protected ProviderRegistry providerRegistry;
40
41
42
43
44 protected MetadataRepository metadataRepository;
45
46
47
48
49 protected ReferenceLinker referenceLinker;
50
51
52
53
54 @Override
55 public <T> T find(Class<T> type, Object id) {
56 return persistenceProviderForType(type).find(type, reduceCompoundKey(id));
57 }
58
59
60
61
62
63
64
65
66
67 protected Object reduceCompoundKey(Object id) {
68
69
70
71
72
73
74
75
76
77 return id;
78 }
79
80
81
82
83 @Override
84 public <T> QueryResults<T> findMatching(Class<T> type, QueryByCriteria queryByCriteria) {
85 return persistenceProviderForType(type).findMatching(type, queryByCriteria);
86 }
87
88
89
90
91 @Override
92 public <T> QueryResults<T> findAll(Class<T> type) {
93 return persistenceProviderForType(type).findAll(type);
94 }
95
96
97
98
99 @Override
100 public <T> T findUnique(Class<T> type, QueryByCriteria queryByCriteria) {
101 QueryResults<T> results = findMatching(type, queryByCriteria);
102 if (results.getResults().isEmpty()) {
103 return null;
104 } else if (results.getResults().size() > 1) {
105 throw new IncorrectResultSizeDataAccessException("Attempted to find single result but found more than "
106 + "one for class " + type + " and criteria " + queryByCriteria, 1, results.getResults().size());
107 } else {
108 return results.getResults().get(0);
109 }
110 }
111
112
113
114
115 @Override
116 public void delete(Object dataObject) {
117 persistenceProviderForObject(dataObject).delete(dataObject);
118 }
119
120
121
122
123 @Override
124 public <T> void deleteMatching(Class<T> type, QueryByCriteria queryByCriteria) {
125 persistenceProviderForType(type).deleteMatching(type, queryByCriteria);
126 }
127
128
129
130
131
132 @Override
133 public <T> void deleteAll(Class<T> type) {
134 persistenceProviderForType(type).deleteAll(type);
135 }
136
137
138
139
140 @Override
141 public <T> T save(T dataObject, PersistenceOption... options) {
142 Set<PersistenceOption> optionSet = Sets.newHashSet(options);
143 pushOneToOneKeysToChildObjects(dataObject);
144 T saved = persistenceProviderForObject(dataObject).save(dataObject, options);
145 if (optionSet.contains(PersistenceOption.LINK_KEYS)) {
146 DataObjectWrapper<T> wrapper = wrap(saved);
147 wrapper.linkForeignKeys(true);
148 }
149 return saved;
150 }
151
152 protected void pushOneToOneKeysToChildObjects(Object dataObject) {
153 DataObjectWrapper<Object> wrappedParent = wrap(dataObject);
154 if (wrappedParent.getMetadata() == null) {
155 return;
156 }
157
158 for (DataObjectRelationship rel : wrappedParent.getMetadata().getRelationships()) {
159
160 if (rel.isSavedWithParent() && rel.isDeletedWithParent()) {
161 Object child = wrappedParent.getPropertyValueNullSafe(rel.getName());
162
163 if (child == null) {
164 continue;
165 }
166 DataObjectWrapper<Object> wrappedChild = wrap(child);
167
168
169
170
171
172
173
174
175 MetadataChild inverseRelationship = rel.getInverseRelationship();
176 if (inverseRelationship != null && inverseRelationship instanceof DataObjectRelationship) {
177 try {
178 wrappedChild.setPropertyValue(inverseRelationship.getName(), dataObject);
179 for (DataObjectAttributeRelationship attr : inverseRelationship.getAttributeRelationships()) {
180
181
182
183 wrappedChild.setPropertyValue(attr.getParentAttributeName(),
184 wrappedParent.getPropertyValueNullSafe(attr.getChildAttributeName()));
185 }
186 } catch (Exception ex) {
187 LOG.warn("Unable to set 1:1 child keys. Persistance of child object may not be correct. Parent Object.property: "
188 + dataObject.getClass().getName()
189 + "."
190 + rel.getName()
191 + " / Child Type: "
192 + child.getClass().getName(), ex);
193 }
194 }
195 }
196 }
197
198 }
199
200
201
202
203 @Override
204 public MetadataRepository getMetadataRepository() {
205 return metadataRepository;
206 }
207
208
209
210
211 @Override
212 public <T> T copyInstance(T dataObject, CopyOption... options) {
213 return persistenceProviderForObject(dataObject).copyInstance(dataObject, options);
214 }
215
216
217
218
219 @Override
220 public <T> DataObjectWrapper<T> wrap(T dataObject) {
221 if (dataObject == null) {
222 throw new IllegalArgumentException("data object was null");
223 }
224 DataObjectMetadata metadata = getMetadataRepository().getMetadata(dataObject.getClass());
225
226
227 if (metadata == null) {
228 LOG.warn("Non KRAD Data object passed - no metadata found for: " + dataObject.getClass());
229
230
231 }
232 return new DataObjectWrapperImpl<T>(dataObject, metadata, this, referenceLinker);
233 }
234
235
236
237
238 @Override
239 public <T> boolean supports(Class<T> type) {
240 return providerRegistry.getPersistenceProvider(type) != null;
241 }
242
243
244
245
246
247
248
249
250 protected PersistenceProvider persistenceProviderForType(Class<?> type) {
251 PersistenceProvider provider = providerRegistry.getPersistenceProvider(type);
252 if (provider == null) {
253 throw new RuntimeException("No PersistenceProvider handles type: " + type);
254 }
255 return provider;
256 }
257
258
259
260
261
262
263
264
265
266 protected PersistenceProvider persistenceProviderForObject(Object object) {
267 if (object == null) {
268 throw new IllegalArgumentException("data object was null");
269 }
270 return persistenceProviderForType(object.getClass());
271 }
272
273
274
275
276 @Override
277 public void flush(Class<?> type){
278 PersistenceProvider persistenceProvider = persistenceProviderForType(type);
279 if (persistenceProvider == null) {
280 throw new RuntimeException("No PersistenceProvider handles type: " + type);
281 }
282 persistenceProvider.flush(type);
283 }
284
285
286
287
288
289
290 @Required
291 public void setProviderRegistry(ProviderRegistry providerRegistry) {
292 this.providerRegistry = providerRegistry;
293 }
294
295
296
297
298
299
300 @Required
301 public void setMetadataRepository(MetadataRepository metadataRepository) {
302 this.metadataRepository = metadataRepository;
303 }
304
305
306
307
308
309
310 public ReferenceLinker getReferenceLinker() {
311 return referenceLinker;
312 }
313
314
315
316
317
318
319 @Required
320 public void setReferenceLinker(ReferenceLinker referenceLinker) {
321 this.referenceLinker = referenceLinker;
322 }
323
324
325
326
327
328 private static final class DataObjectWrapperImpl<T> extends DataObjectWrapperBase<T> {
329
330
331
332
333
334
335
336
337
338 private DataObjectWrapperImpl(T dataObject, DataObjectMetadata metadata, DataObjectService dataObjectService,
339 ReferenceLinker referenceLinker) {
340 super(dataObject, metadata, dataObjectService, referenceLinker);
341 }
342 }
343
344 }