/* ArrayPT 1.0 - Join Points for Array Element Access in AspectJ 
 * Copyright (C) 2006 Chin-Hung Chien, Kung Chen
 *
 * This abc extension is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This abc extension is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this abc extension, in the file LESSER-GPL;
 * if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/*
 * Created on Dec 21, 2006
 *
 */
import java.lang.reflect.Field;
import org.aspectj.lang.JoinPoint;
import org.aspectbench.ajex.lang.reflect.ArrayGetSignature;
import org.aspectbench.ajex.lang.reflect.ArraySetSignature;

/**
 * @author Chin-Hung Chien
 * @description This sample program demonstrates the use of ArrayPT, which is comprised of two
 *              new pointcuts: arrayget and arrayset, by using two separate aspects to intercept
 *              access to array elements and then take appropriate actions such as trimming a
 *              string, checking the range of value change, and so on.
 */
public class ArrayPTDemo
{
	
  public static void main(String[] args)
  {  
    x = new int[2][2];
    try
    {
      x[0][1]=50;
      x[0][1]=550;  // This assignment will cause the value change to exceed the allowed range. 
    }
    catch(Exception e)
    {
      System.out.println(e);	
    }
    
    
    s = new String[2];
    try
    {      
      s[0] = new String(" this is a string with white space at both ends   ");            
      System.out.println(s[0]);
    }
    catch(Exception e)
    {
      System.out.println(e);	
    }  
    
  }

  static int x[][];
  static String s[];
  
}


/**
 * The purpose of aspect GuardedX is to ensure that any value change made to the element of ArrayPTDemo.x
 * does not exceed the allowed range, namely MAX_CHANGE. In case the value change exceeds MAX_CHANGE, a 
 * runtime exception will be thrown.
 */
aspect GuardedX
{
  static final int MAX_CHANGE = 100;	

  before(int index1, int index2, int newval): arrayset(* ArrayPTDemo.x) && args(index1, index2, newval)
  {
    int [][]ar = (int[][])ArrayPTHelper.getField(thisJoinPoint);
    	
    if (Math.abs(newval - ar[index1][index2]) > MAX_CHANGE)
    {
      ArrayPTHelper.printContextInfo(thisJoinPoint);	
      throw new RuntimeException("value change exceeds MAX_CHANGE");	
    }    
  }  
  
}


/**
 * The main purpose of aspect GuardedS is to trim the white space at the both ends of a string being
 * assigned to the element of ArrayPTDemo.x. In addition, aspect GuardedS keeps track of references
 * to the element of ArrayPTDemo.x.
 */
aspect GuardedS
{

  void around(int index1, String newval) : arrayset(* ArrayPTDemo.s) && args(index1, newval)
  {       
    try
    {      
      proceed(index1, newval.trim());
    }   	
    catch(Exception e) {}
  }
  
  
  after(int index1) returning(String val) : arrayget(* ArrayPTDemo.s) && args(index1)
  {     	
    ArrayPTHelper.printContextInfo(thisJoinPoint);
    
    // There are two ways to obtain the value being retrieved. One is through the bounded variable "val" exposed
    // to the advice body;
    System.out.println("[1] value being retrieved: " + val);
    
    // the other is to obtain the array instance of interest using the helper function, getField().     
    String []ar = (String[])ArrayPTHelper.getField(thisJoinPoint);
    System.out.println("[2] value being retrieved: " + ar[index1]);
  }    	
  
}


/**
 * Class ArrayPTHelper provides two helper functions: getField() and printContextInfo(); the former is
 * for facilitating obtaining the array instance embodied in the given join point object, and the latter
 * is useful for printing the context information for arrayget join points or arrayset join points.
 */
class ArrayPTHelper
{
	
  public static Object getField(JoinPoint jp)
  {
    try
    {	
      Class c = jp.getSignature().getDeclaringType();
      Field f = c.getDeclaredField(jp.getSignature().getName());	
      return f.get(null);
    }
    catch(Exception e)
    {
      return null;	
    } 	  	
  }		


  public static void printContextInfo(JoinPoint jp)
  {

    if (jp.getSignature() instanceof ArrayGetSignature)
    {        
      System.out.println("*********** arrayget Join Point Context Info ***********");

      ArrayGetSignature sig = (ArrayGetSignature)jp.getSignature();
      System.out.println("Field Name:\t\t" + sig.getName());
      System.out.println("Field Type:\t\t" + sig.getFieldType());

      Object[] args = jp.getArgs();
      System.out.print("Index Values:\t\t");

      for (int i=0; i<args.length; i++)
        if (i == 0)
          System.out.print(args[i]);
      else
        System.out.print(", " + args[i]);

      System.out.println("\nSource Location:\t" + jp.getSourceLocation());

      System.out.println("********************************************************\n");   
    } 
    else if (jp.getSignature() instanceof ArraySetSignature)
    {
      System.out.println("*********** arrayset Join Point Context Info ***********");

      ArraySetSignature sig = (ArraySetSignature)jp.getSignature();
      System.out.println("Field Name:\t\t" + sig.getName());
      System.out.println("Field Type:\t\t" + sig.getFieldType());

      Object[] args = jp.getArgs();
      System.out.print("Index Values:\t\t");

      for (int i=0; i<args.length-1; i++)
        if (i == 0)
          System.out.print(args[i]);
      else
        System.out.print(", " + args[i]);

      System.out.println("\nAssigned Value:\t\t" + args[args.length-1]);   
      System.out.println("Source Location:\t" + jp.getSourceLocation());

      System.out.println("********************************************************\n");
    }

  }

}