Apply.java :  » UnTagged » preflect » com » ryanm » preflect » Android Open Source

Android Open Source » UnTagged » preflect 
preflect » com » ryanm » preflect » Apply.java

package com.ryanm.preflect;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.json.JSONObject;

import android.util.Log;

import com.ryanm.preflect.annote.DirtyFlag;

/**
 * Methods for applying JSON to an object tree
 * 
 * @author ryanm
 */
class Apply
{
  private static final int NO_CHANGE = 0;

  private static final int SUB_CHANGE = 1;

  private static final int LOCAL_CHANGE = 2;

  private Apply()
  {
  }

  static void apply( JSONObject json, Object... roots )
  {
    if( roots.length == 1 )
    {
      apply( json, roots[ 0 ] );
    }
    else
    {
      for( Object root : roots )
      {
        if( root != null )
        {
          String name = Util.getName( root );
          JSONObject oc = json.optJSONObject( name );
          apply( oc, root );
        }
      }
    }
  }

  private static int apply( JSONObject json, Object o )
  {
    int result = NO_CHANGE;

    for( Field f : o.getClass().getFields() )
    {
      JSONObject fc = json.optJSONObject( Util.getName( f ) );
      if( fc != null )
      {
        int r = apply( o, f, fc );

        result = Math.max( result, r );
      }
    }

    for( Method m : o.getClass().getMethods() )
    {
      JSONObject mc = json.optJSONObject( Util.getName( m ) );
      if( mc != null && m.getReturnType() == void.class )
      {
        int r = apply( o, m, mc );

        result = Math.max( result, r );
      }
    }

    if( result != NO_CHANGE )
    {
      setDirtyFlags( result, o );
    }

    return result;
  }

  private static void setDirtyFlags( int result, Object o )
  {
    for( Field f : o.getClass().getFields() )
    {
      DirtyFlag df = f.getAnnotation( DirtyFlag.class );
      if( df != null )
      {
        if( f.getType() != boolean.class )
        {
          throw new StructuralError(
              "DirtyFlag can only be applied to boolean fields. Remove it from "
                  + o.getClass().getName() + "." + f.getName() );
        }
        else
        {
          if( result == LOCAL_CHANGE || result == SUB_CHANGE && df.watchTree() )
          {
            try
            {
              f.set( o, new Boolean( true ) );
            }
            catch( Exception e )
            {
              throw new RuntimeException( "Problem setting dirty flag "
                  + o.getClass() + "." + f.getName(), e );
            }
          }
        }
      }
    }

    for( Method m : o.getClass().getMethods() )
    {
      DirtyFlag df = m.getAnnotation( DirtyFlag.class );
      if( df != null )
      {
        if( m.getReturnType() != void.class && m.getParameterTypes().length != 0 )
        {
          throw new StructuralError(
              "DirtyFlag can only be applied to void-return/no-arg methods. Remove it from "
                  + o.getClass().getName() + "." + m.getName() );
        }
        else
        {
          if( result == LOCAL_CHANGE || result == SUB_CHANGE && df.watchTree() )
          {
            try
            {
              m.invoke( o );
            }
            catch( Exception e )
            {
              throw new RuntimeException( "Problem calling dirty flag method"
                  + o.getClass() + "." + m.getName(), e );
            }
          }
        }
      }
    }
  }

  private static int apply( Object owner, Field field, JSONObject json )
  {
    VariableType codec = VariableType.get( field.getType() );
    if( codec != null )
    {
      String valueString = json.optString( Util.VALUE );
      try
      {
        Object newValue = codec.decode( valueString, field.getType() );
        Object current = field.get( owner );

        if( !current.equals( newValue ) )
        {
          field.set( owner, newValue );

          return LOCAL_CHANGE;
        }
      }
      catch( Exception e )
      {
        Log.e( Preflect.LOG_TAG, "Trouble applying value \"" + valueString + "\" to "
            + owner.getClass() + "." + field.getName(), e );
      }
    }
    else
    {
      // subconf
      try
      {
        Object sub = field.get( owner );
        int result = apply( json, sub );

        if( result != NO_CHANGE )
        {
          return SUB_CHANGE;
        }
      }
      catch( Exception e )
      {
        Log.e( Preflect.LOG_TAG, "Trouble getting subconf " + owner.getClass() + "."
            + field.getName(), e );
      }
    }

    return NO_CHANGE;
  }

  /**
   * @param owner
   * @param setter
   * @param json
   * @return The change type that occurred
   */
  private static int apply( Object owner, Method setter, JSONObject json )
  {
    String valueString = json.optString( Util.VALUE );

    // is action?
    if( setter.getParameterTypes().length == 0 )
    {
      if( "true".equals( valueString ) )
      {
        try
        {
          setter.invoke( owner );

          return LOCAL_CHANGE;
        }
        catch( Exception e )
        {
          Log.e(
              Preflect.LOG_TAG,
              "Problem invoking action method " + owner.getClass() + "."
                  + setter.getName(), e );
        }
      }
    }
    else
    { // must be a setter
      VariableType codec = VariableType.get( setter.getParameterTypes()[ 0 ] );
      Method getter = findGetter( owner.getClass(), Util.getName( setter ) );

      try
      {
        Object current = getter.invoke( owner );

        if( codec != null )
        {
          try
          {
            Object newValue =
                codec.decode( valueString, setter.getParameterTypes()[ 0 ] );

            if( !newValue.equals( current ) )
            {
              setter.invoke( owner, newValue );
              return LOCAL_CHANGE;
            }
          }
          catch( Exception e )
          {
            Log.e( Preflect.LOG_TAG,
                "Problem invoking setter method " + owner.getClass() + "."
                    + setter.getName() + " with \"" + valueString + "\" ", e );
          }
        }
        else
        { // subconfigurable
          // need to get the object, apply the config to
          // that, then set
          if( current != null )
          {
            int change = apply( json, current );
            setter.invoke( owner, current );

            if( change != NO_CHANGE )
            {
              return SUB_CHANGE;
            }
          }
        }
      }
      catch( Exception e )
      {
        Log.e( Preflect.LOG_TAG, "Problem invoking getter " + owner.getClass() + "."
            + getter + " or setter " + setter, e );
      }
    }

    return NO_CHANGE;
  }

  static final Method findGetter( Class c, String name )
  {
    for( Method m : c.getMethods() )
    {
      if( name.equals( Util.getName( m ) ) && m.getReturnType() != void.class
          && m.getParameterTypes().length == 0 )
      {
        return m;
      }
    }

    return null;
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.