[seam-commits] Seam SVN: r9220 - in trunk/src/main/org/jboss/seam: util and 1 other directory.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Tue Oct 7 23:50:09 EDT 2008


Author: shane.bryzak at jboss.com
Date: 2008-10-07 23:50:08 -0400 (Tue, 07 Oct 2008)
New Revision: 9220

Added:
   trunk/src/main/org/jboss/seam/util/TypedBeanProperty.java
Modified:
   trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java
   trunk/src/main/org/jboss/seam/util/AnnotatedBeanProperty.java
Log:
JBSEAM-3466

Modified: trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java	2008-10-07 21:08:44 UTC (rev 9219)
+++ trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java	2008-10-08 03:50:08 UTC (rev 9220)
@@ -4,6 +4,8 @@
 import static org.jboss.seam.annotations.Install.BUILT_IN;
 
 import java.io.Serializable;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
@@ -36,6 +38,7 @@
 import org.jboss.seam.log.Logging;
 import org.jboss.seam.security.Identity;
 import org.jboss.seam.util.AnnotatedBeanProperty;
+import org.jboss.seam.util.TypedBeanProperty;
 
 /**
  * The default identity store implementation, uses JPA as its persistence mechanism.
@@ -54,6 +57,8 @@
    public static final String EVENT_PRE_PERSIST_USER = "org.jboss.seam.security.management.prePersistUser";
    public static final String EVENT_USER_AUTHENTICATED = "org.jboss.seam.security.management.userAuthenticated";
    
+   public static final String EVENT_PRE_PERSIST_USER_ROLE = "org.jboss.seam.security.management.prePersistUserRole";
+   
    private static final LogProvider log = Logging.getLogProvider(JpaIdentityStore.class);    
    
    protected FeatureSet featureSet;
@@ -62,6 +67,9 @@
    
    private Class userClass;
    private Class roleClass;   
+   private Class xrefClass;
+   private TypedBeanProperty xrefUserProperty;
+   private TypedBeanProperty xrefRoleProperty;
    
    private AnnotatedBeanProperty<UserPrincipal> userPrincipalProperty;
    private AnnotatedBeanProperty<UserPassword> userPasswordProperty;
@@ -119,14 +127,7 @@
       userEnabledProperty = new AnnotatedBeanProperty(userClass, UserEnabled.class);
       userFirstNameProperty = new AnnotatedBeanProperty(userClass, UserFirstName.class);
       userLastNameProperty = new AnnotatedBeanProperty(userClass, UserLastName.class);
-       
-      if (roleClass != null)
-      {
-         roleNameProperty = new AnnotatedBeanProperty(roleClass, RoleName.class);
-         roleGroupsProperty = new AnnotatedBeanProperty(roleClass, RoleGroups.class);
-         roleConditionalProperty = new AnnotatedBeanProperty(roleClass, RoleConditional.class);
-      }
-      
+             
       if (!userPrincipalProperty.isSet()) 
       {
          throw new IdentityManagementException("Invalid userClass " + userClass.getName() + 
@@ -137,12 +138,53 @@
       {
          throw new IdentityManagementException("Invalid userClass " + userClass.getName() + 
          " - required annotation @UserRoles not found on any Field or Method.");         
-      }
+      }      
       
-      if (roleClass != null && !roleNameProperty.isSet())
+      if (roleClass != null)
       {
-         throw new IdentityManagementException("Invalid roleClass " + roleClass.getName() + 
-         " - required annotation @RoleName not found on any Field or Method.");         
+         if (!roleNameProperty.isSet())
+         {
+            throw new IdentityManagementException("Invalid roleClass " + roleClass.getName() + 
+            " - required annotation @RoleName not found on any Field or Method.");         
+         }
+         
+         roleNameProperty = new AnnotatedBeanProperty(roleClass, RoleName.class);
+         roleGroupsProperty = new AnnotatedBeanProperty(roleClass, RoleGroups.class);
+         roleConditionalProperty = new AnnotatedBeanProperty(roleClass, RoleConditional.class);
+                 
+         Type type = userRolesProperty.getPropertyType();
+         if (type instanceof ParameterizedType && 
+               Collection.class.isAssignableFrom((Class) ((ParameterizedType) type).getRawType()))
+         {
+            Type genType = Object.class;
+
+            for (Type t : ((ParameterizedType) type).getActualTypeArguments())
+            {
+               genType = t;
+               break;
+            }                 
+         
+            // If the @UserRoles property isn't a collection of <roleClass>, then assume the relationship
+            // is going through a cross-reference table            
+            if (!genType.equals(roleClass))
+            {
+               xrefClass = (Class) genType;
+               xrefUserProperty = new TypedBeanProperty(xrefClass, userClass);
+               xrefRoleProperty = new TypedBeanProperty(xrefClass, roleClass);
+               
+               if (!xrefUserProperty.isSet())
+               {
+                  throw new IdentityManagementException("Error configuring JpaIdentityStore - it looks like " +
+                        "you're using a cross-reference table, however the user property cannot be determined.");
+               }
+               
+               if (!xrefRoleProperty.isSet())
+               {
+                  throw new IdentityManagementException("Error configuring JpaIdentityStore - it looks like " +
+                  "you're using a cross-reference table, however the role property cannot be determined.");                  
+               }
+            }
+         }
       }
    }
    
@@ -259,11 +301,11 @@
       if (userRoles == null)
       {
          // This should either be a Set, or a List...
-         if (Set.class.isAssignableFrom(userRolesProperty.getPropertyClass()))
+         if (Set.class.isAssignableFrom((Class) userRolesProperty.getPropertyType()))
          {
             userRoles = new HashSet();
          }
-         else if (List.class.isAssignableFrom(userRolesProperty.getPropertyClass()))
+         else if (List.class.isAssignableFrom((Class) userRolesProperty.getPropertyType()))
          {
             userRoles = new ArrayList();
          }
@@ -275,7 +317,30 @@
          return false;
       }
 
-      ((Collection) userRolesProperty.getValue(user)).add(roleToGrant);
+      if (xrefClass == null)
+      {
+         // If this is a Many-To-Many relationship, simply add the role 
+         ((Collection) userRolesProperty.getValue(user)).add(roleToGrant);
+      }
+      else
+      {
+         // Otherwise we need to insert a cross-reference entity instance
+         try
+         {
+            Object xref = xrefClass.newInstance();            
+            xrefUserProperty.setValue(xref, user);
+            xrefRoleProperty.setValue(xref, roleToGrant);
+            
+            Events.instance().raiseEvent(EVENT_PRE_PERSIST_USER_ROLE, xref);
+            
+            ((Collection) userRolesProperty.getValue(user)).add(mergeEntity(xref));
+         }
+         catch (Exception ex)
+         {
+            throw new IdentityManagementException("Error creating cross-reference role record.", ex);
+         }
+      }
+      
       mergeEntity(user);
       
       return true;
@@ -294,9 +359,27 @@
       {
          throw new NoSuchRoleException("Could not revoke role, role '" + role + "' does not exist");
       }      
-       
-      boolean success = ((Collection) userRolesProperty.getValue(user)).remove(roleToRevoke);
+             
+      boolean success = false;
       
+      if (xrefClass == null)
+      {
+         success = ((Collection) userRolesProperty.getValue(user)).remove(roleToRevoke);
+      }
+      else
+      {
+         Collection roles = ((Collection) userRolesProperty.getValue(user));
+
+         for (Object xref : roles)
+         {
+            if (xrefRoleProperty.getValue(xref).equals(roleToRevoke))
+            {
+               success = roles.remove(xref);
+               break;
+            }
+         }
+      }
+      
       if (success) mergeEntity(user);
       return success;
    }
@@ -322,11 +405,11 @@
       if (roleGroups == null)
       {
          // This should either be a Set, or a List...
-         if (Set.class.isAssignableFrom(roleGroupsProperty.getPropertyClass()))
+         if (Set.class.isAssignableFrom((Class) roleGroupsProperty.getPropertyType()))
          {
             roleGroups = new HashSet();
          }
-         else if (List.class.isAssignableFrom(roleGroupsProperty.getPropertyClass()))
+         else if (List.class.isAssignableFrom((Class) roleGroupsProperty.getPropertyType()))
          {
             roleGroups = new ArrayList();
          }

Modified: trunk/src/main/org/jboss/seam/util/AnnotatedBeanProperty.java
===================================================================
--- trunk/src/main/org/jboss/seam/util/AnnotatedBeanProperty.java	2008-10-07 21:08:44 UTC (rev 9219)
+++ trunk/src/main/org/jboss/seam/util/AnnotatedBeanProperty.java	2008-10-08 03:50:08 UTC (rev 9220)
@@ -4,6 +4,7 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.lang.reflect.Type;
 
 /**
  * A convenience class for working with an annotated property (either a field or method) of
@@ -17,7 +18,7 @@
    private Method propertyGetter;
    private Method propertySetter;
    private String name;
-   private Class propertyClass;
+   private Type propertyType;
    private T annotation;
    
    private boolean isFieldProperty;
@@ -70,7 +71,7 @@
             {
                this.propertyGetter = Reflections.getGetterMethod(cls, this.name);
                this.propertySetter = Reflections.getSetterMethod(cls, this.name);
-               this.propertyClass = this.propertyGetter.getReturnType();
+               this.propertyType = this.propertyGetter.getGenericReturnType();
                isFieldProperty = false;               
                set = true;
             }
@@ -88,7 +89,7 @@
       this.propertyField = propertyField;
       isFieldProperty = true;
       this.name = propertyField.getName();
-      this.propertyClass = propertyField.getDeclaringClass();
+      this.propertyType = propertyField.getGenericType();
    }
 
    public void setValue(Object bean, Object value)
@@ -125,9 +126,9 @@
       return annotation;
    }
    
-   public Class getPropertyClass()
+   public Type getPropertyType()
    {
-      return propertyClass;
+      return propertyType;
    }
    
    public boolean isSet()

Added: trunk/src/main/org/jboss/seam/util/TypedBeanProperty.java
===================================================================
--- trunk/src/main/org/jboss/seam/util/TypedBeanProperty.java	                        (rev 0)
+++ trunk/src/main/org/jboss/seam/util/TypedBeanProperty.java	2008-10-08 03:50:08 UTC (rev 9220)
@@ -0,0 +1,109 @@
+package org.jboss.seam.util;
+
+import java.beans.Introspector;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public class TypedBeanProperty
+{
+   private Field propertyField;
+   private Method propertyGetter;
+   private Method propertySetter;
+   
+   private String name;
+   
+   private boolean isFieldProperty;
+   private boolean set = false;
+   
+   public TypedBeanProperty(Class<?> cls, Class type)
+   {      
+      // First check declared fields
+      for (Field f : cls.getDeclaredFields())
+      {
+         if (f.getGenericType().equals(type)) 
+         {
+            setupFieldProperty(f);           
+            set = true;
+            return;
+         }
+      }      
+      
+      // Then check public fields, in case it's inherited
+      for (Field f : cls.getFields())
+      {
+         if (f.getGenericType().equals(type)) 
+         {
+            setupFieldProperty(f);
+            set = true;
+            return;
+         }
+      }
+      
+      // Then check public methods (we ignore private methods)
+      for (Method m : cls.getMethods())
+      {
+         if (m.getGenericReturnType().equals(type))
+         {
+            String methodName = m.getName();
+            
+            if ( m.getName().startsWith("get") )
+            {
+               this.name = Introspector.decapitalize( m.getName().substring(3) );
+            }
+            else if ( methodName.startsWith("is") )
+            {
+               this.name = Introspector.decapitalize( m.getName().substring(2) );
+            }            
+            
+            if (this.name != null)
+            {
+               this.propertyGetter = Reflections.getGetterMethod(cls, this.name);
+               this.propertySetter = Reflections.getSetterMethod(cls, this.name);
+               isFieldProperty = false;               
+               set = true;
+            }
+            else
+            {
+               throw new IllegalStateException("Invalid accessor method, must start with 'get' or 'is'.  " +
+                     "Method: " + m + " in class: " + cls);
+            }
+         }
+      }      
+   }
+   
+   private void setupFieldProperty(Field propertyField)
+   {
+      this.propertyField = propertyField;
+      isFieldProperty = true;
+      this.name = propertyField.getName();
+   }   
+   
+   public void setValue(Object bean, Object value)
+   {
+      if (isFieldProperty)
+      {
+         Reflections.setAndWrap(propertyField, bean, value);         
+      }
+      else
+      {
+         Reflections.invokeAndWrap(propertySetter, bean, value);
+      }
+   }
+   
+   public Object getValue(Object bean)
+   {
+      if (isFieldProperty)
+      {
+         return Reflections.getAndWrap(propertyField, bean);  
+      }
+      else
+      {
+         return Reflections.invokeAndWrap(propertyGetter, bean);
+      }
+   }   
+   
+   public boolean isSet()
+   {
+      return set;
+   }
+}




More information about the seam-commits mailing list