Author: simoneg
Date: Thu May 10 16:40:38 2012
New Revision: 1336781

URL: http://svn.apache.org/viewvc?rev=1336781&view=rev
Log:
Added JPA annotation parsing integrated with BeanData, since it's useful in 
many places

Added:
    
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/BeanDataAdditions.aj
    
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/JpaRelations.java
    
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/PropertyInfoAdditions.aj
Modified:
    
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/AddDefaultJPAValidation.aj

Modified: 
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/AddDefaultJPAValidation.aj
URL: 
http://svn.apache.org/viewvc/labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/AddDefaultJPAValidation.aj?rev=1336781&r1=1336780&r2=1336781&view=diff
==============================================================================
--- 
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/AddDefaultJPAValidation.aj
 (original)
+++ 
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/AddDefaultJPAValidation.aj
 Thu May 10 16:40:38 2012
@@ -31,28 +31,22 @@ import org.apache.magma.validation.Valid
 
 public aspect AddDefaultJPAValidation {
 
-       declare precedence : AddDefaultJPAValidation, 
AddValidatorInPropertyInfo;
+       declare precedence : PropertyInfoAdditions, AddDefaultJPAValidation, 
AddValidatorInPropertyInfo;
 
-       private boolean PropertyInfo.jpaTransient = false;
-       
-       public boolean PropertyInfo.isJpaTransient() {
-               return jpaTransient;
-       }
-       
        public static final String MagDefaultLayers.DATABASE = "database";
        
        after(PropertyInfo info, PropertyDescriptor desc, Class beanClass) : 
                execution(* PropertyInfo.init(PropertyDescriptor, Class)) && 
this(info) && args(desc, beanClass) {
                
                if (info.getType() == null) return;
-               if (info.isReadable() && 
desc.getReadMethod().isAnnotationPresent(Transient.class)) info.jpaTransient = 
true;
                
                if (!info.getType().equals(String.class)) return;
                if (!info.isWriteable() || !info.isReadable()) return;
 
                CompoundValidator val = info.getValidator();
                if (val != null && val.getValidator(DatabaseValidator.class) != 
null) return;
-               
+
+               // Need this, at this stage we don't yet have a fully 
initialized BeanData, we are right in the middle of it
                boolean isjpa = false;
                isjpa |= beanClass.isAnnotationPresent(Entity.class);
                isjpa |= beanClass.isAnnotationPresent(Embeddable.class);

Added: 
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/BeanDataAdditions.aj
URL: 
http://svn.apache.org/viewvc/labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/BeanDataAdditions.aj?rev=1336781&view=auto
==============================================================================
--- 
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/BeanDataAdditions.aj
 (added)
+++ 
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/BeanDataAdditions.aj
 Thu May 10 16:40:38 2012
@@ -0,0 +1,173 @@
+package org.apache.magma.database;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.Entity;
+import javax.persistence.PostLoad;
+import javax.persistence.PostPersist;
+import javax.persistence.PostRemove;
+import javax.persistence.PostUpdate;
+import javax.persistence.PrePersist;
+import javax.persistence.PreRemove;
+import javax.persistence.PreUpdate;
+
+import org.apache.magma.beans.BeanData;
+import org.apache.magma.beans.MagmaBeanSupport;
+import org.apache.magma.beans.PropertyInfo;
+import org.apache.magma.database.DatabasePersisted;
+
+public aspect BeanDataAdditions {
+       
+       private List<PropertyInfo> BeanData.jpaBasicFields = null;
+       private List<PropertyInfo> BeanData.jpaRelationFields = null;
+       private PropertyInfo BeanData.jpaIdField = null;
+       private PropertyInfo BeanData.jpaVersionField = null;
+       
+       private boolean BeanData.jpaClass = false;
+       private String BeanData.jpaTableName = null;
+       private Class<? extends DatabasePersisted> BeanData.jpaSuper = null;
+       
+       private Map<Class<? extends Annotation>, List<Method>> 
BeanData.jpaCallbacks = null;
+       
+       
+       private void BeanData.buildJpaFieldList() {
+               List<String> flds = new ArrayList<String>(getPropertyNames());
+               Collections.sort(flds);
+               jpaBasicFields = new ArrayList<PropertyInfo>();
+               jpaRelationFields = new ArrayList<PropertyInfo>();
+               for (String name : flds) {
+                       PropertyInfo info = getProperty(name);
+                       if (info.isJpaTransient()) continue;
+                       if (info.isJpaId()) {
+                               jpaIdField = info;
+                       } else if (info.isJpaVersion()) {
+                               jpaVersionField = info;
+                       } else {
+                               if (!info.isReadable()) continue;
+                               if (info.isBasicType()) {
+                                       if (!info.isWriteable()) continue;
+                                       jpaBasicFields.add(info);
+                               } else if (info.getJpaRelation() != null || 
info.isMap()) {
+                                       jpaRelationFields.add(info);
+                               }
+                       }
+               }
+       }
+       
+       public List<PropertyInfo> BeanData.getJpaBasicFields() {
+               if (jpaBasicFields == null) buildJpaFieldList();
+               return jpaBasicFields;
+       }
+
+       public List<PropertyInfo> BeanData.getJpaRelationFields() {
+               if (jpaRelationFields == null) buildJpaFieldList();
+               return jpaRelationFields;
+       }
+       
+       public PropertyInfo BeanData.getJpaIdField() {
+               if (jpaIdField == null) buildJpaFieldList();
+               return jpaIdField;
+       }
+       
+       public PropertyInfo BeanData.getJpaVersionField() {
+               if (jpaVersionField == null) buildJpaFieldList();
+               return jpaVersionField;
+       }
+       
+       public boolean BeanData.isJpaClass() {
+               return this.jpaClass;
+       }
+       
+       public String BeanData.getJpaTableName() {
+               return this.jpaTableName;
+       }
+       
+       public Class<? extends DatabasePersisted> BeanData.getJpaSuper() {
+               return this.jpaSuper;
+       }
+       
+       public List<Method> BeanData.getJpaHandlers(Class<? extends Annotation> 
annotation) {
+               if (this.jpaCallbacks == null) return null;
+               return this.jpaCallbacks.get(annotation);
+       }
+       
+       after(BeanData bd) :
+               execution(BeanData.new(..)) 
+               && this(bd) {
+               
+               Class<? extends MagmaBeanSupport> clzz = bd.getBeanClass();
+               if (!DatabasePersisted.class.isAssignableFrom(clzz)) return;
+
+               scanCallbacks(bd,clzz);
+               Class sup = clzz.getSuperclass();
+               BeanData supbd = null;
+               while (sup != null) {
+                       BeanData sbd = BeanData.getFor(sup);
+                       if (sbd.jpaClass) {
+                               bd.jpaSuper = sup;
+                               supbd = sbd;
+                               scanCallbacks(sbd, sup);
+                       }
+                       sup = sup.getSuperclass();
+               }
+
+               Entity ent = clzz.getAnnotation(Entity.class);
+               if (ent != null) {
+                       bd.jpaClass = true;
+                       bd.jpaTableName = ent.name();
+               }
+               
+               if (!bd.jpaClass) return;
+               
+               if (bd.jpaTableName == null || bd.jpaTableName.length() == 0) {
+                       if (supbd != null) {
+                               bd.jpaTableName = supbd.jpaTableName;
+                       } else {
+                               bd.jpaTableName = 
clzz.getSimpleName().toLowerCase();
+                       }
+               }
+               
+       }
+       
+       private static List<Class<? extends Annotation>> callbacks = new 
ArrayList<Class<? extends Annotation>>();
+       
+       static {
+               callbacks.add(PrePersist.class);
+               callbacks.add(PostPersist.class);
+               
+               callbacks.add(PreUpdate.class);
+               callbacks.add(PostUpdate.class);
+       
+               callbacks.add(PreRemove.class);
+               callbacks.add(PostRemove.class);
+               
+               callbacks.add(PostLoad.class);
+       }
+
+       private static void scanCallbacks(BeanData bd, Class clzz) {
+               Method[] meths = clzz.getDeclaredMethods();
+               for (Method m : meths) {
+                       for (Class<? extends Annotation> ann : callbacks) {
+                               if (m.isAnnotationPresent(ann)) {
+                                       if (!m.isAccessible()) {
+                                               m.setAccessible(true);
+                                       }
+                                       if (bd.jpaCallbacks == null)
+                                               bd.jpaCallbacks = new 
HashMap<Class<? extends Annotation>, List<Method>>();
+                                       List<Method> mlist = 
bd.jpaCallbacks.get(ann);
+                                       if (mlist == null) {
+                                               mlist = new ArrayList<Method>();
+                                               bd.jpaCallbacks.put(ann, mlist);
+                                       }
+                                       mlist.add(m);
+                               }
+                       }
+               }
+       }
+}

Added: 
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/JpaRelations.java
URL: 
http://svn.apache.org/viewvc/labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/JpaRelations.java?rev=1336781&view=auto
==============================================================================
--- 
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/JpaRelations.java
 (added)
+++ 
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/JpaRelations.java
 Thu May 10 16:40:38 2012
@@ -0,0 +1,10 @@
+package org.apache.magma.database;
+
+public enum JpaRelations {
+
+       OneToOne,
+       OneToMany,
+       ManyToMany,
+       ManyToOne
+       
+}

Added: 
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/PropertyInfoAdditions.aj
URL: 
http://svn.apache.org/viewvc/labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/PropertyInfoAdditions.aj?rev=1336781&view=auto
==============================================================================
--- 
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/PropertyInfoAdditions.aj
 (added)
+++ 
labs/magma/trunk/foundation-database/src/main/java/org/apache/magma/database/PropertyInfoAdditions.aj
 Thu May 10 16:40:38 2012
@@ -0,0 +1,172 @@
+package org.apache.magma.database;
+
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Id;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Transient;
+import javax.persistence.Version;
+
+import org.apache.magma.beans.PropertyInfo;
+
+public aspect PropertyInfoAdditions {
+
+       private String PropertyInfo.jpaColName = null;
+       private boolean PropertyInfo.jpaEmbedded = false;
+       private boolean PropertyInfo.jpaId = false;
+       private boolean PropertyInfo.jpaVersion = false;
+       private boolean PropertyInfo.jpaTransient = false;
+               
+       private JpaRelations PropertyInfo.jpaRelation = null;
+       private CascadeType[] PropertyInfo.jpaCascade = null;
+       private boolean PropertyInfo.jpaDeleteOrphans = false;
+       private String PropertyInfo.jpaMappedBy = null;
+       
+       
+       
+       public boolean PropertyInfo.isJpaTransient() {
+               return this.jpaTransient;
+       }
+       
+       public String PropertyInfo.getJpaColName() {
+               return this.jpaColName;
+       }
+       
+       public boolean PropertyInfo.isJpaEmbedded() {
+               return this.jpaEmbedded;
+       }
+       
+       public boolean PropertyInfo.isJpaVersion() {
+               return this.jpaVersion;
+       }
+       
+       public boolean PropertyInfo.isJpaId() {
+               return this.jpaId;
+       }
+       
+       public CascadeType[] PropertyInfo.getJpaCascadeType() {
+               return this.jpaCascade;
+       }
+       
+       public JpaRelations PropertyInfo.getJpaRelation() {
+               return this.jpaRelation;
+       }
+       
+       public boolean PropertyInfo.isJpaDeleteOrphans() {
+               return this.jpaDeleteOrphans;
+       }
+       
+       
+       after(PropertyInfo info, PropertyDescriptor desc, Class beanClass) : 
+               execution(* PropertyInfo.init(PropertyDescriptor, Class)) 
+               && this(info) 
+               && args(desc, beanClass) {
+       
+               Method rm = desc.getReadMethod();
+               if (rm == null) return;
+               
+               Column col = rm.getAnnotation(Column.class);
+               if (col != null) {
+                       info.jpaColName = col.name();
+               }
+               if (info.jpaColName == null || info.jpaColName.length() == 0) {
+                       info.jpaColName = info.getName();
+               }
+               
+               Embedded emb = rm.getAnnotation(Embedded.class);
+               if (emb != null) {
+                       info.jpaEmbedded = true;
+               }
+               
+               Id id = rm.getAnnotation(Id.class);
+               if (id != null)
+                       info.jpaId = true;
+               
+               Version ver = rm.getAnnotation(Version.class);
+               if (ver != null)
+                       info.jpaVersion = true;
+               
+               if (rm.isAnnotationPresent(Transient.class)) 
+                       info.jpaTransient = true;
+               
+               
+               {
+                       OneToOne assoc = rm.getAnnotation(OneToOne.class);
+                       if (assoc != null) {
+                               info.jpaCascade = assoc.cascade();
+                               info.jpaRelation = JpaRelations.OneToOne;
+                               info.jpaMappedBy = assoc.mappedBy();
+                               info.jpaDeleteOrphans |= 
checkOrphanRemoval(assoc);
+                       }
+               }
+
+               {
+                       OneToMany assoc = rm.getAnnotation(OneToMany.class);
+                       if (assoc != null) {
+                               info.jpaCascade = assoc.cascade();
+                               info.jpaRelation = JpaRelations.OneToMany;
+                               info.jpaMappedBy = assoc.mappedBy();
+                               info.jpaDeleteOrphans |= 
checkOrphanRemoval(assoc);
+                       }
+               }
+       
+               {
+                       ManyToOne assoc = rm.getAnnotation(ManyToOne.class);
+                       if (assoc != null) {
+                               info.jpaCascade = assoc.cascade();
+                               info.jpaRelation = JpaRelations.ManyToMany;     
                        
+                               info.jpaDeleteOrphans |= 
checkOrphanRemoval(assoc);
+                       }
+               }
+
+               {
+                       ManyToMany assoc = rm.getAnnotation(ManyToMany.class);
+                       if (assoc != null) {
+                               info.jpaCascade = assoc.cascade();
+                               info.jpaRelation = JpaRelations.ManyToOne;      
                        
+                               info.jpaMappedBy = assoc.mappedBy();
+                               info.jpaDeleteOrphans |= 
checkOrphanRemoval(assoc);
+                       }
+               }
+               
+               if (!info.jpaDeleteOrphans) {
+                       Annotation[] anns = rm.getAnnotations();
+                       for (Annotation ann : anns) {
+                               info.jpaDeleteOrphans |= 
ann.annotationType().getName().equals("org.apache.openjpa.persistence.ElementDependent");
+                               // TODO eventually parse also other old ORM 
specific options
+                       }
+               }
+       }
+       
+       private boolean checkOrphanRemoval(Annotation a) {
+               Method meth = null;
+               try {
+                       meth = a.getClass().getMethod("orphanRemoval");
+               } catch (SecurityException e) {
+                       // TODO maybe we should warn for this one?
+                       return false;
+               } catch (NoSuchMethodException e) {
+                       return false;
+               }
+               if (meth == null) return false;
+               if (!meth.getReturnType().equals(Boolean.TYPE)) return false;
+               try {
+                       return (Boolean)meth.invoke(a);
+               } catch (IllegalAccessException e) {
+                       // TODO maybe we should warn for this one?
+                       return false;
+               } catch (Exception e) {
+                       return false;
+               }
+       }
+       
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to