Coverage Report - org.kuali.rice.core.jpa.metadata.MetadataManager
 
Classes in this File Line Coverage Branch Coverage Complexity
MetadataManager
0%
0/228
0%
0/108
8.625
 
 1  
 /*
 2  
  * Copyright 2007-2008 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.core.jpa.metadata;
 17  
 
 18  
 import org.apache.commons.lang.StringUtils;
 19  
 import org.kuali.rice.core.jpa.annotations.Sequence;
 20  
 
 21  
 import javax.persistence.*;
 22  
 import java.lang.reflect.Field;
 23  
 import java.lang.reflect.Modifier;
 24  
 import java.lang.reflect.ParameterizedType;
 25  
 import java.util.*;
 26  
 
 27  
 /**
 28  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 29  
  */
 30  
 public class MetadataManager {
 31  
 
 32  0
         private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(MetadataManager.class);
 33  
         
 34  0
         private static Map<Class, EntityDescriptor> entitesByClass = Collections.synchronizedMap( new HashMap<Class, EntityDescriptor>() );
 35  0
         private static Map<String, EntityDescriptor> entitesByName = Collections.synchronizedMap( new HashMap<String, EntityDescriptor>() );
 36  
         
 37  0
         private MetadataManager() {}
 38  
 
 39  
         public static EntityDescriptor getEntityDescriptor(Class clazz) {
 40  0
                 if (clazz != null && clazz.getName().contains("$$EnhancerByCGLIB")) {
 41  
                         try {
 42  0
                                 clazz = Class.forName(clazz.getName().substring(0, clazz.getName().indexOf("$$EnhancerByCGLIB")));
 43  0
                         } catch (Exception e) {
 44  0
                                 LOG.error(e.getMessage(), e);
 45  0
                         }
 46  
                 }
 47  
 
 48  0
                 EntityDescriptor entityDescriptor = addEntity(clazz);
 49  0
                 return entityDescriptor;
 50  
         }
 51  
         
 52  
         public static Map<String, Object> getPersistableBusinessObjectPrimaryKeyValuePairs(Object object) {
 53  0
                 Map<String, Object> pks = new HashMap<String, Object>();
 54  0
                 EntityDescriptor descriptor = getEntityDescriptor(object.getClass());
 55  0
                 for (FieldDescriptor fieldDescriptor : descriptor.getPrimaryKeys()) {
 56  
                         try {
 57  0
                                 Field field = getField(object.getClass(), fieldDescriptor.getName());
 58  0
                                 field.setAccessible(true);
 59  0
                                 pks.put(fieldDescriptor.getName(), field.get(object));
 60  0
                         } catch (Exception e) {
 61  0
                                 LOG.error(e.getMessage(), e);
 62  0
                         }
 63  
                 }
 64  0
                 return pks;
 65  
         }
 66  
         
 67  
         private static Field getField(Class clazz, String name) throws NoSuchFieldException {
 68  0
                 if (clazz.equals(Object.class)) {
 69  0
                         throw new NoSuchFieldException(name);
 70  
                 }
 71  0
                 Field field = null;
 72  
                 try {
 73  0
                         field = clazz.getDeclaredField(name);
 74  0
                 } catch (Exception e) {}
 75  0
                 if (field == null) {
 76  0
                         field = getField(clazz.getSuperclass(), name);
 77  
                 }
 78  0
                 return field;
 79  
         }
 80  
         
 81  
         private static EntityDescriptor addEntity(Class clazz) {
 82  0
                 EntityDescriptor entity = entitesByClass.get(clazz); 
 83  0
                 if (entity == null) {
 84  0
                         entity = construct(clazz);
 85  0
                         if (entity != null) {
 86  0
                                 entitesByClass.put(entity.getClazz(), entity);
 87  0
                                 entitesByName.put(entity.getName(), entity);
 88  
                         }
 89  
                 }
 90  0
                 return entity;
 91  
         }
 92  
 
 93  
         @SuppressWarnings("unchecked")
 94  
         private static EntityDescriptor construct(Class clazz) {
 95  0
                 if (!clazz.isAnnotationPresent(Entity.class)) {
 96  0
                         return null;
 97  
                 }
 98  
                 
 99  
                 // Determine the base entity metadata
 100  0
                 EntityDescriptor entityDescriptor = new EntityDescriptor();
 101  0
                 entityDescriptor.setClazz(clazz);
 102  0
                 String defaultName = clazz.getName().substring(clazz.getName().lastIndexOf(".") + 1);
 103  0
                 Entity entity = (Entity) clazz.getAnnotation(Entity.class);
 104  0
                 if (StringUtils.isBlank(entity.name())) {
 105  0
                         entityDescriptor.setName(defaultName);
 106  
                 } else {
 107  0
                         entityDescriptor.setName(entity.name());
 108  
                 }
 109  0
                 if (clazz.isAnnotationPresent(Table.class)) {
 110  0
                         Table table = (Table) clazz.getAnnotation(Table.class);
 111  0
                         entityDescriptor.setTable(table.name());
 112  0
                 } else {
 113  0
                         entityDescriptor.setTable(defaultName);
 114  
                 }
 115  0
                 if (clazz.isAnnotationPresent(IdClass.class)) {
 116  0
                         entityDescriptor.setIdClass(clazz.getAnnotation(IdClass.class).getClass());
 117  
                 }
 118  0
                 if (clazz.isAnnotationPresent(Sequence.class)) {
 119  0
                         entityDescriptor.setSequence((Sequence)clazz.getAnnotation(Sequence.class));
 120  
                 }                
 121  
                 
 122  
                 // Check for an "extension"
 123  
                 try {
 124  0
                         Class extensionClass = Class.forName(clazz.getName() + "Extension");
 125  0
                         OneToOneDescriptor descriptor = new OneToOneDescriptor();
 126  0
                         descriptor.setCascade(new CascadeType[] { CascadeType.PERSIST });
 127  0
                         descriptor.setAttributeName("extension");
 128  0
                         descriptor.setTargetEntity(extensionClass);
 129  0
                         descriptor.setMappedBy("extension");
 130  0
                         EntityDescriptor extensionDescriptor = MetadataManager.getEntityDescriptor(extensionClass);
 131  0
                         for (FieldDescriptor fd : extensionDescriptor.getPrimaryKeys()) {
 132  0
                                 descriptor.addFkField(fd.getName());
 133  
                         }
 134  0
                         entityDescriptor.add(descriptor);
 135  0
                         FieldDescriptor extension = new FieldDescriptor();
 136  0
                         extension.setName("extension");
 137  0
                         extension.setClazz(extensionClass);
 138  0
                         entityDescriptor.add(extension);
 139  0
                 } catch (Exception e) {}
 140  
                 
 141  
                 
 142  0
                 List<Class> classes = new ArrayList<Class>();
 143  0
                 classes.add(clazz);
 144  0
                 Class c = clazz;
 145  0
                 while (!c.getSuperclass().equals(Object.class)) {
 146  0
                         c = c.getSuperclass();
 147  0
                         classes.add(c);
 148  
                 }
 149  0
                 Collections.reverse(classes);
 150  
                 
 151  
                 // Determine the field/relationship metadata for all classes in the clazz hierarchy
 152  0
                 for (Class temp : classes) {
 153  0
                         extractFieldMetadata(temp, entityDescriptor);
 154  0
                         if (temp.isAnnotationPresent(AttributeOverrides.class)) {
 155  0
                                 for (AttributeOverride override : ((AttributeOverrides)temp.getAnnotation(AttributeOverrides.class)).value()) {
 156  0
                                         entityDescriptor.getFieldByName(override.name()).setColumn(override.column().name());
 157  
                                 }
 158  
                         }
 159  0
                         if (temp.isAnnotationPresent(AttributeOverride.class)) {
 160  0
                                 AttributeOverride override = (AttributeOverride) temp.getAnnotation(AttributeOverride.class);
 161  0
                                 entityDescriptor.getFieldByName(override.name()).setColumn(override.column().name());                                        
 162  0
                         }
 163  
                 }
 164  
                                 
 165  0
                 return entityDescriptor;
 166  
         }
 167  
 
 168  
         private static void extractFieldMetadata(Class clazz, EntityDescriptor entityDescriptor) {
 169  
             // Don't want to get parent fields if overridden in children since we are walking the tree from child to parent
 170  0
                 Set<String> cachedFields = new HashSet<String>(); 
 171  
                 do {
 172  0
                         for (Field field : clazz.getDeclaredFields()) {
 173  0
                                 if (cachedFields.contains(field.getName())) {
 174  0
                                         continue;
 175  
                                 }
 176  0
                                 cachedFields.add(field.getName());
 177  
                                 
 178  0
                                 int mods = field.getModifiers();
 179  0
                                 if (Modifier.isFinal(mods) || Modifier.isStatic(mods) || Modifier.isTransient(mods) || field.isAnnotationPresent(Transient.class)) {
 180  0
                                         continue;
 181  
                                 }
 182  
 
 183  
                                 // Basic Fields
 184  0
                                 FieldDescriptor fieldDescriptor = new FieldDescriptor();
 185  0
                                 fieldDescriptor.setClazz(field.getType());
 186  0
                                 fieldDescriptor.setName(field.getName());
 187  0
                                 if (field.isAnnotationPresent(Id.class)) {
 188  0
                                         fieldDescriptor.setId(true);
 189  
                                 }
 190  0
                                 if (field.isAnnotationPresent(Column.class)) {
 191  0
                                         Column column = field.getAnnotation(Column.class);
 192  0
                                         fieldDescriptor.setColumn(column.name());
 193  0
                                         fieldDescriptor.setInsertable(column.insertable());
 194  0
                                         fieldDescriptor.setLength(column.length());
 195  0
                                         fieldDescriptor.setNullable(column.nullable());
 196  0
                                         fieldDescriptor.setPrecision(column.precision());
 197  0
                                         fieldDescriptor.setScale(column.scale());
 198  0
                                         fieldDescriptor.setUnique(column.unique());
 199  0
                                         fieldDescriptor.setUpdateable(column.updatable());
 200  0
                                 } else {
 201  0
                                         fieldDescriptor.setColumn(field.getName());
 202  
                                 }
 203  0
                                 if (field.isAnnotationPresent(Version.class)) {
 204  0
                                         fieldDescriptor.setVersion(true);
 205  
                                 }
 206  0
                                 if (field.isAnnotationPresent(Lob.class)) {
 207  0
                                         fieldDescriptor.setLob(true);
 208  
                                 }
 209  0
                                 if (field.isAnnotationPresent(Temporal.class)) {
 210  0
                                         fieldDescriptor.setTemporal(true);
 211  0
                                         fieldDescriptor.setTemporalType(field.getAnnotation(Temporal.class).value());
 212  
                                 }                                
 213  
 
 214  
                                 // Relationships
 215  0
                                 if (field.isAnnotationPresent(OneToOne.class)) {
 216  0
                                         OneToOneDescriptor descriptor = new OneToOneDescriptor();
 217  0
                                         OneToOne relation = field.getAnnotation(OneToOne.class);
 218  0
                                         descriptor.setAttributeName(field.getName());
 219  0
                                         if (relation.targetEntity().equals(void.class)) {
 220  0
                                                 descriptor.setTargetEntity(field.getType());
 221  
                                         } else {
 222  0
                                                 descriptor.setTargetEntity(relation.targetEntity());
 223  
                                         }
 224  0
                                         descriptor.setCascade(relation.cascade());
 225  0
                                         descriptor.setFetch(relation.fetch());
 226  0
                                         descriptor.setMappedBy(relation.mappedBy());
 227  0
                                         descriptor.setOptional(relation.optional());
 228  0
                                         if (field.isAnnotationPresent(JoinColumn.class)) {
 229  0
                                                 JoinColumn jc = field.getAnnotation(JoinColumn.class);
 230  0
                                                 descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
 231  0
                                                 descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
 232  0
                                                 descriptor.setInsertable(jc.insertable());
 233  0
                                                 descriptor.setUpdateable(jc.updatable());                                        
 234  
                                         }
 235  0
                                         if (field.isAnnotationPresent(JoinColumns.class)) {
 236  0
                                                 JoinColumns jcs = field.getAnnotation(JoinColumns.class);
 237  0
                                                 for (JoinColumn jc : jcs.value()) {
 238  0
                                                         descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
 239  0
                                                         descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
 240  0
                                                         descriptor.setInsertable(jc.insertable());
 241  0
                                                         descriptor.setUpdateable(jc.updatable());
 242  
                                                 } 
 243  
                                         }
 244  0
                                         entityDescriptor.add(descriptor);
 245  
                                 }
 246  
 
 247  0
                                 if (field.isAnnotationPresent(OneToMany.class)) {
 248  0
                                         OneToManyDescriptor descriptor = new OneToManyDescriptor();
 249  0
                                         OneToMany relation = field.getAnnotation(OneToMany.class);
 250  0
                                         descriptor.setAttributeName(field.getName());
 251  0
                                         if (relation.targetEntity().equals(void.class)) {
 252  0
                                                 descriptor.setTargetEntity((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]);
 253  
                                         } else {
 254  0
                                                 descriptor.setTargetEntity(relation.targetEntity());
 255  
                                         }
 256  0
                                         descriptor.setCascade(relation.cascade());
 257  0
                                         descriptor.setFetch(relation.fetch());
 258  0
                                         descriptor.setMappedBy(relation.mappedBy());
 259  0
                                         EntityDescriptor mappedBy = MetadataManager.getEntityDescriptor(descriptor.getTargetEntity());
 260  0
                                         ObjectDescriptor od = mappedBy.getObjectDescriptorByName(descriptor.getMappedBy());
 261  0
                                         if (od != null) {
 262  0
                                                 for (String fk : od.getForeignKeyFields()) {                                
 263  0
                                                         descriptor.addFkField(fk);
 264  
                                                 }
 265  
                                         }
 266  0
                                         if (field.isAnnotationPresent(JoinTable.class)) {
 267  0
                                                 JoinTable jt = field.getAnnotation(JoinTable.class);
 268  0
                                                 for (JoinColumn jc : jt.joinColumns()) {
 269  0
                                                         descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
 270  0
                                                         descriptor.setInsertable(jc.insertable());
 271  0
                                                         descriptor.setUpdateable(jc.updatable());
 272  
                                                 } 
 273  0
                                                 for (JoinColumn jc : jt.inverseJoinColumns()) {
 274  0
                                                         descriptor.setInsertable(jc.insertable());
 275  0
                                                         descriptor.setUpdateable(jc.updatable());
 276  
                                                         // TODO: Should we add inverse join columns?
 277  
                                                 } 
 278  
                                         }
 279  0
                                         entityDescriptor.add(descriptor);
 280  
                                 }
 281  
 
 282  0
                                 if (field.isAnnotationPresent(ManyToOne.class)) {
 283  0
                                         ManyToOne relation = field.getAnnotation(ManyToOne.class);
 284  0
                                         ManyToOneDescriptor descriptor = new ManyToOneDescriptor();
 285  0
                                         descriptor.setAttributeName(field.getName());
 286  0
                                         if (relation.targetEntity().equals(void.class)) {
 287  0
                                                 descriptor.setTargetEntity(field.getType());
 288  
                                         } else {
 289  0
                                                 descriptor.setTargetEntity(relation.targetEntity());
 290  
                                         }
 291  0
                                         descriptor.setCascade(relation.cascade());
 292  0
                                         descriptor.setFetch(relation.fetch());
 293  0
                                         descriptor.setOptional(relation.optional());
 294  0
                                         if (field.isAnnotationPresent(JoinColumn.class)) {
 295  0
                                                 JoinColumn jc = field.getAnnotation(JoinColumn.class);
 296  0
                                                 descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
 297  0
                                                 descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
 298  0
                                                 descriptor.setInsertable(jc.insertable());
 299  0
                                                 descriptor.setUpdateable(jc.updatable());
 300  
                                         }
 301  0
                                         if (field.isAnnotationPresent(JoinColumns.class)) {
 302  0
                                                 JoinColumns jcs = field.getAnnotation(JoinColumns.class);
 303  0
                                                 for (JoinColumn jc : jcs.value()) {
 304  0
                                                         descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
 305  0
                                                         descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
 306  0
                                                         descriptor.setInsertable(jc.insertable());
 307  0
                                                         descriptor.setUpdateable(jc.updatable());
 308  
                                                 } 
 309  
                                         }
 310  0
                                         entityDescriptor.add(descriptor);
 311  
                                 }
 312  
 
 313  0
                                 if (field.isAnnotationPresent(ManyToMany.class)) {
 314  0
                                         ManyToManyDescriptor descriptor = new ManyToManyDescriptor();
 315  0
                                         ManyToMany relation = field.getAnnotation(ManyToMany.class);
 316  0
                                         descriptor.setAttributeName(field.getName());
 317  0
                                         if (relation.targetEntity().equals(void.class)) {
 318  0
                                                 descriptor.setTargetEntity((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]);
 319  
                                         } else {
 320  0
                                                 descriptor.setTargetEntity(relation.targetEntity());
 321  
                                         }
 322  0
                                         descriptor.setCascade(relation.cascade());
 323  0
                                         descriptor.setFetch(relation.fetch());
 324  0
                                         descriptor.setMappedBy(relation.mappedBy());
 325  0
                                         if (field.isAnnotationPresent(JoinTable.class)) {
 326  0
                                                 JoinTable jt = field.getAnnotation(JoinTable.class);
 327  0
                                                 descriptor.setJoinTableName(jt.name());
 328  0
                                                 for (JoinColumn jc : jt.joinColumns()) {
 329  0
                                                         descriptor.addJoinColumnDescriptor(constructJoinDescriptor(jc));
 330  0
                                                         descriptor.addFkField(entityDescriptor.getFieldByColumnName(jc.name()).getName());
 331  0
                                                         descriptor.setInsertable(jc.insertable());
 332  0
                                                         descriptor.setUpdateable(jc.updatable());
 333  
                                                 } 
 334  0
                                                 for (JoinColumn jc : jt.inverseJoinColumns()) {
 335  0
                                                         descriptor.addInverseJoinColumnDescriptor(constructJoinDescriptor(jc));
 336  0
                                                         descriptor.setInsertable(jc.insertable());
 337  0
                                                         descriptor.setUpdateable(jc.updatable());
 338  
                                                         // TODO: Should we add inverse join columns?
 339  
                                                 } 
 340  
                                         }
 341  0
                                         entityDescriptor.add(descriptor);                                                
 342  
                                 }
 343  
 
 344  
                                 // Add the field to the entity
 345  0
                                 entityDescriptor.add(fieldDescriptor);
 346  
                         }
 347  0
                         clazz = clazz.getSuperclass();
 348  0
                 } while (clazz != null && !(clazz.equals(Object.class)));
 349  0
         }
 350  
 
 351  
         private static JoinColumnDescriptor constructJoinDescriptor(JoinColumn jc) {
 352  0
                 JoinColumnDescriptor join = new JoinColumnDescriptor();
 353  0
                 if (StringUtils.isBlank(jc.name())) {
 354  
                         // TODO: Implement default name
 355  
                         // See: http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#JoinColumn
 356  0
                         throw new RuntimeException("Default name for Join Column not yet implemented!");
 357  
                 } else {
 358  0
                         join.setName(jc.name());
 359  
                 }
 360  0
                 join.setInsertable(jc.insertable());
 361  0
                 join.setNullable(jc.nullable());
 362  0
                 join.setUnique(jc.unique());
 363  0
                 join.setUpdateable(jc.updatable());
 364  0
                 return join;
 365  
         }
 366  
         
 367  
 }