1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.data.jpa;
17
18 import org.kuali.rice.core.api.data.DataType;
19 import org.kuali.rice.krad.data.metadata.DataObjectAttribute;
20 import org.kuali.rice.krad.data.metadata.DataObjectAttributeRelationship;
21 import org.kuali.rice.krad.data.metadata.DataObjectCollection;
22 import org.kuali.rice.krad.data.metadata.DataObjectMetadata;
23 import org.kuali.rice.krad.data.metadata.DataObjectRelationship;
24 import org.kuali.rice.krad.data.metadata.impl.DataObjectAttributeImpl;
25 import org.kuali.rice.krad.data.metadata.impl.DataObjectAttributeRelationshipImpl;
26 import org.kuali.rice.krad.data.metadata.impl.DataObjectCollectionImpl;
27 import org.kuali.rice.krad.data.metadata.impl.DataObjectMetadataImpl;
28 import org.kuali.rice.krad.data.metadata.impl.DataObjectRelationshipImpl;
29 import org.kuali.rice.krad.data.provider.annotation.ExtensionFor;
30 import org.kuali.rice.krad.data.provider.impl.MetadataProviderBase;
31
32 import javax.persistence.EntityManager;
33 import javax.persistence.metamodel.Attribute.PersistentAttributeType;
34 import javax.persistence.metamodel.EmbeddableType;
35 import javax.persistence.metamodel.EntityType;
36 import javax.persistence.metamodel.IdentifiableType;
37 import javax.persistence.metamodel.PluralAttribute;
38 import javax.persistence.metamodel.SingularAttribute;
39 import java.lang.reflect.Field;
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.Collections;
43 import java.util.HashMap;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Set;
47
48
49
50
51
52
53
54
55
56
57
58 public abstract class JpaMetadataProviderImpl extends MetadataProviderBase implements JpaMetadataProvider {
59 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(JpaMetadataProviderImpl.class);
60
61
62
63
64 protected EntityManager entityManager;
65
66
67
68
69
70
71
72
73 protected abstract void populateImplementationSpecificEntityLevelMetadata(DataObjectMetadataImpl metadata,
74 EntityType<?> entityType);
75
76
77
78
79
80
81
82
83 protected abstract void populateImplementationSpecificAttributeLevelMetadata(DataObjectAttributeImpl attribute,
84 SingularAttribute<?, ?> attr);
85
86
87
88
89
90
91
92
93 protected abstract void populateImplementationSpecificCollectionLevelMetadata(DataObjectCollectionImpl collection,
94 PluralAttribute<?, ?, ?> cd);
95
96
97
98
99
100
101
102
103 protected abstract void populateImplementationSpecificRelationshipLevelMetadata(
104 DataObjectRelationshipImpl relationship, SingularAttribute<?, ?> rd);
105
106
107
108
109 @Override
110 public abstract DataObjectRelationship addExtensionRelationship(Class<?> entityClass, String extensionPropertyName,
111 Class<?> extensionEntity);
112
113
114
115
116 @Override
117 protected synchronized void initializeMetadata(Collection<Class<?>> types) {
118 LOG.info("Initializing JPA Metadata from " + entityManager);
119
120 masterMetadataMap.clear();
121
122
123
124 for ( IdentifiableType<?> identifiableType : entityManager.getMetamodel().getEntities() ) {
125
126 if(identifiableType instanceof EntityType<?>){
127 EntityType<?> type = (EntityType<?>)identifiableType;
128 try {
129 masterMetadataMap.put(type.getBindableJavaType(), getMetadataForClass(type.getBindableJavaType()));
130 if (LOG.isDebugEnabled()) {
131 LOG.debug("Added Metadata For: " + type.getBindableJavaType());
132 }
133 } catch (Exception ex) {
134 LOG.error("Error obtaining JPA metadata for type: " + type.getJavaType(), ex);
135 }
136 }
137 }
138 }
139
140
141
142
143
144
145
146 @SuppressWarnings("unchecked")
147 public DataObjectMetadata getMetadataForClass(Class<?> persistableClass) {
148
149 List<DataObjectRelationship> relationships = new ArrayList<DataObjectRelationship>();
150 Map<Class<?>, Class<?>> extensionMap = new HashMap<Class<?>, Class<?>>();
151 for (EntityType<?> entityType : getEntityManager().getMetamodel().getEntities()) {
152 if (entityType.getJavaType().isAnnotationPresent(ExtensionFor.class)) {
153 ExtensionFor extensionFor = entityType.getJavaType().getAnnotation(ExtensionFor.class);
154 if (extensionFor.value().equals(persistableClass)) {
155 DataObjectRelationship relationship =
156 addExtensionRelationship(persistableClass, extensionFor.extensionPropertyName(), entityType.getJavaType());
157
158
159 relationships.add(relationship);
160 }
161 }
162 }
163
164 DataObjectMetadataImpl metadata = new DataObjectMetadataImpl();
165 EntityType<?> entityType = entityManager.getMetamodel().entity(persistableClass);
166 metadata.setProviderName(this.getClass().getSimpleName());
167 metadata.setType(persistableClass);
168 metadata.setName(persistableClass.getSimpleName());
169 metadata.setReadOnly(false);
170
171 metadata.setSupportsOptimisticLocking(entityType.hasVersionAttribute());
172 populateImplementationSpecificEntityLevelMetadata(metadata, entityType);
173
174
175 try {
176 metadata.setPrimaryKeyAttributeNames(getPrimaryKeyAttributeNames(entityType));
177 } catch (RuntimeException ex) {
178 LOG.error("Error processing PK metadata for " + entityType.getBindableJavaType().getName());
179 throw new RuntimeException(
180 "Error processing PK metadata for " + entityType.getBindableJavaType().getName(), ex);
181 }
182
183
184 try {
185 List<DataObjectAttribute> attributes = getSingularAttributes(persistableClass,
186 entityType.getSingularAttributes(), metadata.getPrimaryKeyAttributeNames());
187 for (DataObjectAttribute attr : attributes) {
188 metadata.getOrderedAttributeList().add(attr.getName());
189 }
190 metadata.setAttributes(attributes);
191 } catch (RuntimeException ex) {
192 LOG.error("Error processing attribute metadata for " + entityType.getBindableJavaType().getName());
193 throw ex;
194 }
195
196
197 try {
198 metadata.setCollections(getCollectionsFromMetadata((Set) entityType.getPluralAttributes()));
199 } catch (RuntimeException ex) {
200 LOG.error("Error processing collection metadata for " + entityType.getBindableJavaType().getName());
201 throw ex;
202 }
203
204
205 try {
206 relationships.addAll(getRelationships(entityType.getSingularAttributes()));
207 metadata.setRelationships(relationships);
208 } catch (RuntimeException ex) {
209 LOG.error("Error processing relationship metadata for " + entityType.getBindableJavaType().getName());
210 throw ex;
211 }
212
213 return metadata;
214 }
215
216
217
218
219
220
221
222 protected List<String> getPrimaryKeyAttributeNames(EntityType<?> entityType) {
223 List<String> primaryKeyAttributeNames = new ArrayList<String>();
224
225
226
227
228
229
230
231 if (entityType.getIdType() instanceof EmbeddableType) {
232 for (Field pkField : entityType.getIdType().getJavaType().getDeclaredFields()) {
233 primaryKeyAttributeNames.add(pkField.getName());
234 }
235 } else {
236
237 List<String> unsortedPkFields = new ArrayList<String>();
238 for (SingularAttribute attr : entityType.getSingularAttributes()) {
239 if (attr.isId()) {
240 unsortedPkFields.add(attr.getName());
241 }
242 }
243
244 getPrimaryKeyNamesInOrder(primaryKeyAttributeNames, unsortedPkFields, entityType.getJavaType().getDeclaredFields(), entityType.getJavaType());
245 }
246 return primaryKeyAttributeNames;
247 }
248
249
250
251
252
253
254
255
256
257 private void getPrimaryKeyNamesInOrder(List<String> pkFieldNames, List<String> unsortedPks, Field[] fields, Class<?> type) {
258 for (Field field : type.getDeclaredFields()) {
259 if (unsortedPks.contains(field.getName())) {
260 pkFieldNames.add(field.getName());
261 }
262 }
263
264 if (pkFieldNames.isEmpty() && type.getSuperclass() != null) {
265 getPrimaryKeyNamesInOrder(pkFieldNames, unsortedPks, type.getSuperclass().getDeclaredFields(), type.getSuperclass());
266 }
267 }
268
269
270
271
272
273
274
275
276
277 protected List<DataObjectAttribute> getSingularAttributes(Class<?> persistableClass, Collection<?> fields,
278 List<String> primaryKeyAttributes) {
279 if (fields == null) {
280 fields = Collections.emptySet();
281 }
282
283
284 Map<String, SingularAttribute> attrs = new HashMap<String, SingularAttribute>(fields.size());
285 for (SingularAttribute attr : (Collection<SingularAttribute>) fields) {
286 if (!attr.isAssociation()) {
287 attrs.put(attr.getName(), attr);
288 }
289 }
290 List<DataObjectAttribute> attributes = new ArrayList<DataObjectAttribute>(fields.size());
291
292 for (Field f : persistableClass.getDeclaredFields()) {
293 SingularAttribute attr = attrs.get(f.getName());
294 if (attr != null) {
295 attributes.add(getAttributeMetadata(persistableClass, attr, primaryKeyAttributes));
296 attrs.remove(f.getName());
297 }
298 }
299
300 for (SingularAttribute attr : attrs.values()) {
301 attributes.add(getAttributeMetadata(persistableClass, attr, primaryKeyAttributes));
302 }
303 return attributes;
304 }
305
306
307
308
309
310
311
312
313
314 protected DataObjectAttribute getAttributeMetadata(Class<?> persistableClass, SingularAttribute<?, ?> attr,
315 List<String> primaryKeyAttributes) {
316 DataObjectAttributeImpl attribute = new DataObjectAttributeImpl();
317
318 attribute.setOwningType(persistableClass);
319 attribute.setName(attr.getName());
320 Class<?> propertyType = attr.getJavaType();
321 attribute.setType(propertyType);
322 DataType dataType = DataType.getDataTypeFromClass(propertyType);
323 if (dataType == null) {
324 dataType = DataType.STRING;
325 }
326 attribute.setDataType(dataType);
327 attribute.setRequired(!attr.isOptional() && !attr.isId() && !primaryKeyAttributes.contains(attr.getName()));
328
329 populateImplementationSpecificAttributeLevelMetadata(attribute, attr);
330
331 return attribute;
332 }
333
334
335
336
337
338
339
340 protected List<DataObjectCollection> getCollectionsFromMetadata(Set<PluralAttribute> collections) {
341 List<DataObjectCollection> colls = new ArrayList<DataObjectCollection>(collections.size());
342 for (PluralAttribute cd : collections) {
343 colls.add(getCollectionMetadataFromCollectionAttribute(cd));
344 }
345 return colls;
346 }
347
348
349
350
351
352
353
354 protected DataObjectCollection getCollectionMetadataFromCollectionAttribute(PluralAttribute cd) {
355 try {
356 DataObjectCollectionImpl collection = new DataObjectCollectionImpl();
357
358
359 Class<?> collectionElementClass = cd.getElementType().getJavaType();
360 EntityType<?> elementEntityType = entityManager.getMetamodel().entity(collectionElementClass);
361 collection.setName(cd.getName());
362 collection.setRelatedType(collectionElementClass);
363 populateImplementationSpecificCollectionLevelMetadata(collection, cd);
364
365
366 PersistentAttributeType persistentAttributeType = cd.getPersistentAttributeType();
367
368
369 if (persistentAttributeType == PersistentAttributeType.ONE_TO_MANY) {
370
371
372
373 if (collection.getAttributeRelationships().isEmpty()) {
374
375 List<String> pkFields = getPrimaryKeyAttributeNames((EntityType<?>) cd.getDeclaringType());
376 List<String> fkFields = getPrimaryKeyAttributeNames(elementEntityType);
377 List<DataObjectAttributeRelationship> attributeRelationships = new ArrayList<DataObjectAttributeRelationship>();
378 for (int i = 0; i < pkFields.size(); i++) {
379 attributeRelationships.add(new DataObjectAttributeRelationshipImpl(pkFields.get(i), fkFields
380 .get(i)));
381 }
382 collection.setAttributeRelationships(attributeRelationships);
383 }
384 } else if ( persistentAttributeType == PersistentAttributeType.MANY_TO_MANY ) {
385
386 collection.setIndirectCollection( true );
387
388
389 collection.setAttributeRelationships(null);
390 }
391
392 return collection;
393 } catch (RuntimeException ex) {
394 LOG.error("Unable to process Collection metadata: " + cd);
395 throw ex;
396 }
397 }
398
399
400
401
402
403
404
405 protected List<DataObjectRelationship> getRelationships(Set<?> references) {
406 List<DataObjectRelationship> rels = new ArrayList<DataObjectRelationship>(references.size());
407 for (SingularAttribute rd : (Set<SingularAttribute>) references) {
408 if (rd.isAssociation()) {
409 rels.add(getRelationshipMetadata(rd));
410 }
411 }
412 return rels;
413 }
414
415
416
417
418
419
420
421 protected DataObjectRelationship getRelationshipMetadata(SingularAttribute rd) {
422 try {
423 DataObjectRelationshipImpl relationship = new DataObjectRelationshipImpl();
424
425
426 Class<?> referencedClass = rd.getBindableJavaType();
427 EntityType<?> referencedEntityType = entityManager.getMetamodel().entity(referencedClass);
428 relationship.setName(rd.getName());
429 relationship.setRelatedType(referencedClass);
430 populateImplementationSpecificRelationshipLevelMetadata(relationship, rd);
431
432 return relationship;
433 } catch (RuntimeException ex) {
434 LOG.error("Unable to process Relationship metadata: " + rd);
435 throw ex;
436 }
437 }
438
439
440
441
442 @Override
443 public boolean isClassPersistable(Class<?> type) {
444 return handles(type);
445 }
446
447
448
449
450
451
452 public void setEntityManager(EntityManager entityManager) {
453 this.entityManager = entityManager;
454 }
455
456
457
458
459
460
461 public EntityManager getEntityManager() {
462 return entityManager;
463 }
464 }