Package org.springmodules.aop.framework

Source Code of org.springmodules.aop.framework.TouchingAfterReturningAdvice

package org.springmodules.aop.framework;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import ognl.Ognl;
import ognl.OgnlException;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;
import org.springframework.util.MethodInvoker;

/**
* <p>Touches configurable properties on the return value of a method invocation.
* This approach is an alternative to the open session in view pattern.
*
* <p>If the return value is a single object the properties are touched on this
* object. If the return value is an instance of java.util.Collection or Object[]
* the properties are touched on every element.
*
* <p>If no properties are specified collections will still be iterated entirely.
*
* <p>Property values can be either property names or maps containing property names
* as keys and lists containing property names as values. Maps entries represent bean
* properties (the key of the map entries) that are collections. All elements of those collection will
* be touched by the properties (the values of the map entries). This construct can
* be cascaded.
*
* <p>OGNL expressions are also supported. These expression will be executed after the properties
* have been executed on the return value of the method invocation. To support the evaluation of collections
* you can use the <code>#returned</code> variable in the OGNL context which holds the return value.
*
* <p>To load all elements of a returned collection instance use OGNL's pseudo-property size:
*
* <pre>
* #returned.size
* </pre>
*
* @author Steven Devijver
* @since 20-06-2005
*
*/
public class TouchingAfterReturningAdvice implements AfterReturningAdvice {

  private Object[] properties = null;
  private String[] ognlExpressions = null;
 
  /**
   * <p>The [properties] properties takes a list of property strings.
   * The return value of the method invocation will be touched with these
   * properties.
   *
   * @param properties the property strings
   */
  public void setProperties(Object[] properties) {
    this.properties = properties;
  }
 
  /**
   * <p>The [ognl] property takes a list of OGNL expressions that will be
   * evaluated on the return value of the method invocation.
   *
   * @param ognlExpressions the OGNL expressions
   */
  public void setOgnl(String[] ognlExpressions) {
    this.ognlExpressions = ognlExpressions;
  }
 
  public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    if (returnValue == null) {
      return;
    }
   
    if (returnValue instanceof Void) {
      return;
    } else if (returnValue instanceof Collection) {
      touch(((Collection)returnValue).toArray(), properties);
    } else if (returnValue instanceof Object[]) {
      touch((Object[])returnValue, properties);
    } else {
      touch(returnValue, properties);
    }
    touchOgnl(returnValue, ognlExpressions);
   
  }
 
  private static void touch(Object[] objects, Object[] properties) {
    for (int i = 0; objects != null && properties != null && i < objects.length; i++) {
      Object target = objects[i];
      touch(target, properties);
    }
  }
 
  private static void touch(Object target, Object[] properties) {
    BeanWrapper beanWrapper = new BeanWrapperImpl(target);
    for (int x = 0; properties != null && x < properties.length; x++) {
      Object property = properties[x];
      if (property instanceof String) {
        Object result = beanWrapper.getPropertyValue((String)property);
        if (result instanceof Collection) {
          ((Collection)result).size();
        }
      } else if (property instanceof Map) {
        for (Iterator iter = ((Map)property).keySet().iterator(); iter.hasNext();) {
          Object key = iter.next();
          Object tmpProperties = ((Map)property).get(key);
          if (!(key instanceof String)) {
            throw new IllegalArgumentException("Maps configured in the [properties] property should have a string key!");
          }
          if (!(tmpProperties instanceof Collection)) {
            throw new IllegalArgumentException("Maps configured in the [properties] property should have a list value!");
          }
          Object result = beanWrapper.getPropertyValue((String)key);
          if (result instanceof Collection) {
            touch(((Collection)result).toArray(), ((Collection)tmpProperties).toArray());
          } else if (result instanceof Object[]) {
            touch((Object[])result, ((Collection)tmpProperties).toArray());
          } else {
            touch(result, ((Collection)tmpProperties).toArray());
          }
        }
      } else {
        throw new IllegalArgumentException("[properties] property should only contain string and map instances!");
      }
    }
  }
 
  private static void touchOgnl(Object target, String[] ognlExpressions) {
    for (int i = 0; ognlExpressions != null && i < ognlExpressions.length; i++) {
      String ognlExpression = ognlExpressions[i];
      try {
        Map context = new HashMap();
        context.put("returned", target);
        Ognl.getValue(ognlExpression, context, target);
      } catch (OgnlException e) {
        throw new BeansException("Error occured while evaluating OGNL expression [" + ognlExpression + "]!", e) {};
      }
    }
  }
}
TOP

Related Classes of org.springmodules.aop.framework.TouchingAfterReturningAdvice

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.