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 }