[seam-commits] Seam SVN: r11897 - in modules/remoting/trunk/src/main/java/org/jboss/seam/remoting: wrapper and 1 other directory.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Sat Jan 2 06:04:40 EST 2010


Author: shane.bryzak at jboss.com
Date: 2010-01-02 06:04:40 -0500 (Sat, 02 Jan 2010)
New Revision: 11897

Modified:
   modules/remoting/trunk/src/main/java/org/jboss/seam/remoting/model/ModelHandler.java
   modules/remoting/trunk/src/main/java/org/jboss/seam/remoting/wrapper/BagWrapper.java
   modules/remoting/trunk/src/main/java/org/jboss/seam/remoting/wrapper/BeanWrapper.java
Log:
support for updating bag and map model properties


Modified: modules/remoting/trunk/src/main/java/org/jboss/seam/remoting/model/ModelHandler.java
===================================================================
--- modules/remoting/trunk/src/main/java/org/jboss/seam/remoting/model/ModelHandler.java	2010-01-01 04:42:31 UTC (rev 11896)
+++ modules/remoting/trunk/src/main/java/org/jboss/seam/remoting/model/ModelHandler.java	2010-01-02 11:04:40 UTC (rev 11897)
@@ -4,7 +4,12 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.StringReader;
+import java.lang.reflect.Array;
+import java.lang.reflect.Type;
+import java.util.Collection;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import javax.enterprise.context.Conversation;
 import javax.enterprise.inject.spi.BeanManager;
@@ -22,6 +27,7 @@
 import org.jboss.seam.remoting.RequestHandler;
 import org.jboss.seam.remoting.wrapper.BagWrapper;
 import org.jboss.seam.remoting.wrapper.BeanWrapper;
+import org.jboss.seam.remoting.wrapper.MapWrapper;
 import org.jboss.seam.remoting.wrapper.Wrapper;
 import org.jboss.weld.Container;
 import org.jboss.weld.context.ContextLifecycle;
@@ -32,7 +38,7 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * Handles incoming model fetch/applyUpdate requests
+ * Handles incoming model fetch/apply requests
  *  
  * @author Shane Bryzak
  */
@@ -45,7 +51,6 @@
    @Inject ModelRegistry registry;
    @Inject Conversation conversation;
    
-   @SuppressWarnings("unchecked")
    public void handle(HttpServletRequest request, HttpServletResponse response)
          throws Exception
    {
@@ -154,10 +159,10 @@
       }
       
       // TODO Unmarshal expressions - don't support this until security implications investigated
-      for (Element exprElement : (List<Element>) modelElement.elements("expression"))
-      {
+      //for (Element exprElement : (List<Element>) modelElement.elements("expression"))
+      //{
          
-      }
+      //}
       
       if (model.getAction() != null)
       {
@@ -228,38 +233,79 @@
             
             if (changeset.elements("member").size() > 0)
             {
+               Wrapper target = model.getCallContext().getOutRefs().get(refId);
+               if (!(target instanceof BeanWrapper))
+               {
+                  throw new IllegalStateException("Changeset for refId [" +
+                        refId + "] does not reference a valid bean object");                     
+               }
+               
                for (Element member : (List<Element>) changeset.elements("member"))
                {
                   String name = member.attributeValue("name");
                   
-                  Wrapper w = model.getCallContext().createWrapperFromElement(
+                  Wrapper source = model.getCallContext().createWrapperFromElement(
                         (Element) member.elementIterator().next());
-                  
-                  if (w instanceof BagWrapper)
-                  {
-                     // TODO process collection updates
+                                                      
+                  if (source instanceof BagWrapper)
+                  {                  
+                     Object targetBag = ((BeanWrapper) target).getBeanProperty(name);
+                     if (targetBag == null)
+                     {
+                        ((BeanWrapper) target).setBeanProperty(name, source);
+                     }
+                     else
+                     {
+                        Type t = ((BeanWrapper) target).getBeanPropertyType(name);
+                        if (!cloneBagContents(source.convert(t), targetBag))
+                        {
+                           ((BeanWrapper) target).setBeanProperty(name, source);
+                        }
+                     }
                   }
-                  else
+                  else if (source instanceof MapWrapper)
                   {                     
-                     Wrapper ref = model.getCallContext().getOutRefs().get(refId);
-                     if (ref instanceof BeanWrapper)
+                     Object targetMap = ((BeanWrapper) target).getBeanProperty(name);
+                     if (!Map.class.isAssignableFrom(targetMap.getClass()))
                      {
-                        ((BeanWrapper) ref).setBeanProperty(name, w);
+                        throw new IllegalStateException("Cannot assign Map value " +
+                              "to non Map property [" + target.getClass().getName() +
+                              "." + name + "]");
                      }
-                     else
+                     
+                     if (targetMap == null)
                      {
-                        throw new IllegalStateException("Changeset for refId [" +
-                              refId + "] does not reference a valid bean object");
+                        ((BeanWrapper) target).setBeanProperty(name, source);
                      }
+                     else
+                     {                        
+                        Type t = ((BeanWrapper) target).getBeanPropertyType(name);                        
+                        cloneMapContents((Map) source.convert(t), (Map) targetMap);
+                     }
+                  }                  
+                  else
+                  {                                          
+                     ((BeanWrapper) target).setBeanProperty(name, source);
                   }
-                  
                }
             }
             
             if (changeset.elements("bag").size() > 0)
             {
-               // TODO process root node collection updates
+               Wrapper target = model.getCallContext().getOutRefs().get(refId);               
+               Wrapper source = model.getCallContext().createWrapperFromElement(
+                     (Element) changeset.element("bag"));
+               cloneBagContents(source.convert(target.getValue().getClass()), 
+                     target.getValue());
             }            
+            else if (changeset.elements("map").size() > 0)
+            {
+               Wrapper target = model.getCallContext().getOutRefs().get(refId);
+               Wrapper source = model.getCallContext().createWrapperFromElement(
+                     (Element) changeset.element("map"));
+               cloneMapContents((Map) source.convert(target.getValue().getClass()),
+                     (Map) target.getValue());
+            }
          }
       }
       
@@ -276,6 +322,98 @@
       return model;
    }
    
+   /**
+    * Clones the contents of the specified source bag into the specified target
+    * bag. If the contents can be cloned, this method returns true, otherwise it
+    * returns false.
+    *  
+    * @param sourceBag
+    * @param targetBag
+    * @return
+    */
+   @SuppressWarnings("unchecked")
+   private boolean cloneBagContents(Object sourceBag, Object targetBag)
+   {
+      Class<?> cls = sourceBag.getClass();
+      if (cls.isArray())
+      {
+         int sourceLen = Array.getLength(sourceBag);
+         int targetLen = Array.getLength(targetBag);
+         if (targetLen != sourceLen) return false;
+         for (int i = 0; i < sourceLen; i++)
+         {
+            Array.set(targetBag, i, Array.get(sourceBag, i));
+         }
+         return true;
+      }
+      else if (List.class.isAssignableFrom(cls))
+      {
+         List sourceList = (List) sourceBag;
+         List targetList = (List) targetBag;
+         
+         while (targetList.size() > sourceList.size())
+         {
+            targetList.remove(targetList.size() - 1);
+         }
+         
+         for (int i = 0; i < sourceList.size(); i++)
+         {
+            targetList.set(i, sourceList.get(i));
+         }
+         return true;        
+      }
+      else if (Set.class.isAssignableFrom(cls))
+      {
+         Set sourceSet = (Set) sourceBag;
+         Set targetSet = (Set) targetBag;
+         
+         for (Object e : sourceSet)
+         {
+            if (!targetSet.contains(e))
+            {
+               targetSet.add(e);
+            }
+         }
+         
+         for (Object e : targetSet)
+         {
+            if (!sourceSet.contains(e))
+            {
+               targetSet.remove(e);
+            }
+         }         
+         return true;
+      }
+      
+      return false;
+   }
+   
+   /**
+    * Clones the contents of one Map into another
+    * 
+    * @param sourceMap
+    * @param targetMap
+    */
+   @SuppressWarnings("unchecked")
+   private void cloneMapContents(Map sourceMap, Map targetMap)
+   {
+      for (Object key : sourceMap.keySet())
+      {
+         if (!targetMap.containsKey(key))
+         {
+            targetMap.put(key, sourceMap.get(key));
+         }
+      }
+      
+      for (Object key : targetMap.keySet())
+      {
+         if (!sourceMap.containsKey(key))
+         {
+            targetMap.remove(key);
+         }
+      }      
+   }
+   
    private void marshalResponse(Model model, RequestContext ctx, 
          OutputStream out) throws IOException
    {

Modified: modules/remoting/trunk/src/main/java/org/jboss/seam/remoting/wrapper/BagWrapper.java
===================================================================
--- modules/remoting/trunk/src/main/java/org/jboss/seam/remoting/wrapper/BagWrapper.java	2010-01-01 04:42:31 UTC (rev 11896)
+++ modules/remoting/trunk/src/main/java/org/jboss/seam/remoting/wrapper/BagWrapper.java	2010-01-02 11:04:40 UTC (rev 11897)
@@ -58,12 +58,19 @@
       {
          vals = new ArrayList<Object>();
          for (int i = 0; i < Array.getLength(value); i++)
+         {
             vals.add(Array.get(value, i));
-      } else if (Collection.class.isAssignableFrom(value.getClass()))
+         }
+      } 
+      else if (Collection.class.isAssignableFrom(value.getClass()))
+      {
          vals = (Collection) value;
+      }
       else
+      {
          throw new RuntimeException(String.format(
                "Can not marshal object as bag: [%s]", value));
+      }
 
       for (Object val : vals)
       {
@@ -82,32 +89,39 @@
       List<Wrapper> vals = new ArrayList<Wrapper>();
 
       for (Element e : (List<Element>) element.elements("element"))
-         vals.add(context.createWrapperFromElement((Element) e.elements()
-               .get(0)));
+      {
+         vals.add(context.createWrapperFromElement((Element) e.elements().get(0)));
+      }
 
       if (type instanceof Class && ((Class) type).isArray())
       {
          Class arrayType = ((Class) type).getComponentType();
          value = Array.newInstance(arrayType, vals.size()); // Fix this
          for (int i = 0; i < vals.size(); i++)
+         {
             Array.set(value, i, vals.get(i).convert(arrayType));
-      } else if (type instanceof Class
-            && Collection.class.isAssignableFrom((Class) type))
+         }
+      } 
+      else if (type instanceof Class && 
+            Collection.class.isAssignableFrom((Class) type))
       {
          try
          {
             value = getConcreteClass((Class) type).newInstance();
-         } catch (Exception ex)
+         } 
+         catch (Exception ex)
          {
             throw new ConversionException(String.format(
                   "Could not create instance of target type [%s].", type));
          }
+         
          for (Wrapper w : vals)
+         {
             ((Collection) value).add(w.convert(Object.class));
-      } else if (type instanceof ParameterizedType
-            && Collection.class
-                  .isAssignableFrom((Class) ((ParameterizedType) type)
-                        .getRawType()))
+         }
+      } 
+      else if (type instanceof ParameterizedType && 
+            Collection.class.isAssignableFrom((Class) ((ParameterizedType) type).getRawType()))
       {
          Class rawType = (Class) ((ParameterizedType) type).getRawType();
          Type genType = Object.class;
@@ -121,14 +135,17 @@
          try
          {
             value = getConcreteClass(rawType).newInstance();
-         } catch (Exception ex)
+         } 
+         catch (Exception ex)
          {
             throw new ConversionException(String.format(
                   "Could not create instance of target type [%s].", rawType));
          }
 
          for (Wrapper w : vals)
+         {
             ((Collection) value).add(w.convert(genType));
+         }
       }
 
       return value;
@@ -140,13 +157,22 @@
       {
          // Support Set, Queue and (by default, and as a last resort) List
          if (Set.class.isAssignableFrom(c))
+         {
             return HashSet.class;
+         }
          else if (Queue.class.isAssignableFrom(c))
+         {
             return LinkedList.class;
+         }
          else
+         {
             return ArrayList.class;
-      } else
+         }
+      } 
+      else
+      {
          return c;
+      }
    }
 
    /**
@@ -158,18 +184,14 @@
    public ConversionScore conversionScore(Class<?> cls)
    {
       // There's no such thing as an exact match for a bag, so we'll just look
-      // for
-      // a compatible match
-
-      if (cls.isArray())
+      // for a compatible match
+      if (cls.isArray() || cls.equals(Object.class) || Collection.class.isAssignableFrom(cls))
+      {
          return ConversionScore.compatible;
-
-      if (cls.equals(Object.class))
-         return ConversionScore.compatible;
-
-      if (Collection.class.isAssignableFrom(cls))
-         return ConversionScore.compatible;
-
-      return ConversionScore.nomatch;
+      }
+      else
+      {
+         return ConversionScore.nomatch;
+      }
    }
 }

Modified: modules/remoting/trunk/src/main/java/org/jboss/seam/remoting/wrapper/BeanWrapper.java
===================================================================
--- modules/remoting/trunk/src/main/java/org/jboss/seam/remoting/wrapper/BeanWrapper.java	2010-01-01 04:42:31 UTC (rev 11896)
+++ modules/remoting/trunk/src/main/java/org/jboss/seam/remoting/wrapper/BeanWrapper.java	2010-01-02 11:04:40 UTC (rev 11897)
@@ -50,20 +50,19 @@
       }
       return metadataCache;
    }
-
+   
+   @Override
    @SuppressWarnings("unchecked")
-   @Override
    public void setElement(Element element)
    {
       super.setElement(element);
 
       String beanType = element.attributeValue("type");
 
-      // TODO do it this way, it might not be a managed bean...
-      Bean bean = beanManager.getBeans(beanType).iterator().next();
-
-      if (bean != null)
+      Set<Bean<?>> beans = beanManager.getBeans(beanType); 
+      if (beans.size() > 0)
       {
+         Bean bean = beans.iterator().next();
          value = bean.create(beanManager.createCreationalContext(bean));
       }
       else
@@ -80,12 +79,113 @@
       }
    }
    
+   public Type getBeanPropertyType(String propertyName)
+   {
+      Class<?> cls = value.getClass();
+      
+      String getter = "get" + Character.toUpperCase(propertyName.charAt(0)) +
+          propertyName.substring(1);
+      
+      for (Method m : cls.getMethods())
+      {
+         if (getter.equals(m.getName())) return m.getGenericReturnType(); 
+      }
+      
+      Field field = null;
+      while (field == null && !cls.equals(Object.class))
+      {
+         try
+         {
+            field = cls.getDeclaredField(propertyName);
+         }
+         catch (NoSuchFieldException e)
+         {
+            cls = cls.getSuperclass();
+         }
+      }
+      
+      if (field == null)
+      {
+         throw new IllegalArgumentException("Invalid property name [" + propertyName +
+               "] specified for target class [" + value.getClass() + "]");
+      }
+      
+      return field.getGenericType();
+   }
+   
+   public Wrapper getBeanProperty(String propertyName)
+   {
+      Class<?> cls = value.getClass();
+      
+      Field f = null;
+      try
+      {
+         f = cls.getField(propertyName);
+      }
+      catch (NoSuchFieldException ex) { }
+
+      boolean accessible = false;
+      try
+      {
+         // Temporarily set the field's accessibility so we can read it
+         if (f != null)
+         {
+            accessible = f.isAccessible();
+            f.setAccessible(true);
+            return context.createWrapperFromObject(f.get(value), null);
+         }
+         else
+         {
+            Method accessor = null;
+            try
+            {
+               accessor = cls.getMethod(String.format("get%s%s",
+                     Character.toUpperCase(propertyName.charAt(0)),
+                     propertyName.substring(1)));
+            }
+            catch (NoSuchMethodException ex)
+            {
+               try
+               {
+                  accessor = cls.getMethod(String.format("is%s%s",
+                        Character.toUpperCase(propertyName.charAt(0)),
+                        propertyName.substring(1)));
+               }
+               catch (NoSuchMethodException ex2)
+               {
+                  // uh oh... continue with the next one
+                  return null;
+               }
+            }
+
+            try
+            {
+               return context.createWrapperFromObject(accessor.invoke(value), null);
+            }
+            catch (InvocationTargetException ex)
+            {
+               throw new RuntimeException(String.format(
+                     "Failed to read property [%s] for object [%s]",
+                     propertyName, value));
+            }
+         }
+      }
+      catch (IllegalAccessException ex)
+      {
+         throw new RuntimeException("Error reading value from field.");
+      }
+      finally
+      {
+         if (f != null)
+            f.setAccessible(accessible);
+      }      
+   }
+   
    public void setBeanProperty(String propertyName, Wrapper valueWrapper)
    {
       Class<?> cls = value.getClass();
 
       // We're going to try a combination of ways to set the property value
-      // here
       Method method = null;
       Field field = null;
 
@@ -164,8 +264,7 @@
          boolean accessible = field.isAccessible();
          try
          {
-            if (!accessible)
-               field.setAccessible(true);
+            if (!accessible) field.setAccessible(true);
             field.set(value, fieldValue);
          }
          catch (Exception ex)
@@ -210,14 +309,15 @@
       }
    }
 
+   /**
+    * Writes the object reference ID to the specified OutputStream
+    */
    public void marshal(OutputStream out) throws IOException
    {
       context.addOutRef(this);
 
       out.write(REF_START_TAG_OPEN);
-      out
-            .write(Integer.toString(context.getOutRefs().indexOf(this))
-                  .getBytes());
+      out.write(Integer.toString(context.getOutRefs().indexOf(this)).getBytes());
       out.write(REF_START_TAG_END);
    }
 
@@ -227,6 +327,14 @@
       serialize(out, null);
    }
 
+   /**
+    * Writes a serialized representation of the object's properties to the specified
+    * OutputStream.
+    * 
+    * @param out
+    * @param constraints
+    * @throws IOException
+    */
    public void serialize(OutputStream out, List<String> constraints)
          throws IOException
    {
@@ -275,81 +383,20 @@
                componentName != null ? componentName : cls.getName(),
                propertyName);
 
-         if (constraints == null
-               || (!constraints.contains(fieldPath) && !constraints
-                     .contains(wildCard)))
+         if (constraints == null || (!constraints.contains(fieldPath) && 
+               !constraints.contains(wildCard)))
          {
             out.write(MEMBER_START_TAG_OPEN);
             out.write(propertyName.getBytes());
             out.write(MEMBER_START_TAG_CLOSE);
 
-            Field f = null;
-            try
+            Wrapper w = getBeanProperty(propertyName);
+            if (w != null)
             {
-               f = cls.getField(propertyName);
+               w.setPath(fieldPath);
+               w.marshal(out);
             }
-            catch (NoSuchFieldException ex)
-            {
-            }
 
-            boolean accessible = false;
-            try
-            {
-               // Temporarily set the field's accessibility so we can read it
-               if (f != null)
-               {
-                  accessible = f.isAccessible();
-                  f.setAccessible(true);
-                  context.createWrapperFromObject(f.get(value), fieldPath)
-                        .marshal(out);
-               }
-               else
-               {
-                  Method accessor = null;
-                  try
-                  {
-                     accessor = cls.getMethod(String.format("get%s%s",
-                           Character.toUpperCase(propertyName.charAt(0)),
-                           propertyName.substring(1)));
-                  }
-                  catch (NoSuchMethodException ex)
-                  {
-                     try
-                     {
-                        accessor = cls.getMethod(String.format("is%s%s",
-                              Character.toUpperCase(propertyName.charAt(0)),
-                              propertyName.substring(1)));
-                     }
-                     catch (NoSuchMethodException ex2)
-                     {
-                        // uh oh... continue with the next one
-                        continue;
-                     }
-                  }
-
-                  try
-                  {
-                     context.createWrapperFromObject(accessor.invoke(value),
-                           fieldPath).marshal(out);
-                  }
-                  catch (InvocationTargetException ex)
-                  {
-                     throw new RuntimeException(String.format(
-                           "Failed to read property [%s] for object [%s]",
-                           propertyName, value));
-                  }
-               }
-            }
-            catch (IllegalAccessException ex)
-            {
-               throw new RuntimeException("Error reading value from field.");
-            }
-            finally
-            {
-               if (f != null)
-                  f.setAccessible(accessible);
-            }
-
             out.write(MEMBER_CLOSE_TAG);
          }
       }



More information about the seam-commits mailing list