View Javadoc

    1   /*
    2    * $Id: GroovyCategorySupport.java,v 1.6 2004/07/10 03:31:42 bran Exp $version Apr 26, 2004 4:22:50 PM $user Exp $
    3    *
    4    * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
    5    *
    6    * Redistribution and use of this software and associated documentation
    7    * ("Software"), with or without modification, are permitted provided that the
    8    * following conditions are met: 1. Redistributions of source code must retain
    9    * copyright statements and notices. Redistributions must also contain a copy
    10   * of this document. 2. Redistributions in binary form must reproduce the above
    11   * copyright notice, this list of conditions and the following disclaimer in
    12   * the documentation and/or other materials provided with the distribution. 3.
    13   * The name "groovy" must not be used to endorse or promote products derived
    14   * from this Software without prior written permission of The Codehaus. For
    15   * written permission, please contact info@codehaus.org. 4. Products derived
    16   * from this Software may not be called "groovy" nor may "groovy" appear in
    17   * their names without prior written permission of The Codehaus. "groovy" is a
    18   * registered trademark of The Codehaus. 5. Due credit should be given to The
    19   * Codehaus - http://groovy.codehaus.org/
    20   *
    21   * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
    22   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    23   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    24   * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
    25   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    27   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    28   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    29   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    30   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
    31   * DAMAGE.
    32   *
    33   */
    34   package> org.codehaus.groovy.runtime;
    35
    36  import groovy.lang.Closure;
    37  import groovy.lang.MetaMethod;
    38
    39  import java.lang.reflect.Method;
    40  import java.lang.reflect.Modifier;
    41  import java.util.ArrayList;
    42  import java.util.Collections;
    43  import java.util.HashMap;
    44  import java.util.Iterator;
    45  import java.util.List;
    46  import java.util.Map;
    47  import java.util.WeakHashMap;
    48
    49
    50  /***
    51   * @author sam
    52   */
    53  public class GroovyCategorySupport {
    54
    55      /***
    56       * This method is used to pull all the new methods out of the local thread context with a particular name.
    57       *
    58       * @param categorizedClass
    59       * @param name
    60       * @return
    61       */
    62      public static List getCategoryMethods(Class categorizedClass, String name) {
    63          Map properties = getProperties();
    64          List methodList = new ArrayList();
    65          for (Iterator i = properties.keySet().iterator(); i.hasNext(); ) {
    66              Class current = (Class) i.next();
    67              if (current.isAssignableFrom(categorizedClass)) {
    68                  Map metaMethodsMap = (Map) properties.get(current);
    69                  List newMethodList = (List) metaMethodsMap.get(name);
    70                  if (newMethodList != null) {
    71                      methodList.addAll(newMethodList);
    72                  }
    73              }
    74          }
    75          if (methodList.size() == 0) return null;
    76          return methodList;
    77      }
    78
    79      /***
    80       * This method is delegated to from the global use(CategoryClass) method.  It scans the Category class for static methods
    81       * that take 1 or more parameters.  The first parameter is the class you are adding the category method to, additional parameters
    82       * are those paramteres needed by that method.  A use statement cannot be undone and is valid only for the current thread.
    83       *
    84       * @param categoryClass
    85       */
    86      private static void use(Class categoryClass) {
    87          Map properties = getProperties();
    88          Method[] methods = categoryClass.getMethods();
    89          for (int i = 0; i < methods.length; i++) {
    90              Method method = methods[i];
    91              if (Modifier.isStatic(method.getModifiers())) {
    92                  Class[] paramTypes = method.getParameterTypes();
    93                  if (paramTypes.length > 0) {
    94                      Class metaClass = paramTypes[0];
    95                      Map metaMethodsMap = getMetaMethods(properties, metaClass);
    96                      List methodList = getMethodList(metaMethodsMap, method.getName());
    97                      MetaMethod mmethod = new NewInstanceMetaMethod(new MetaMethod(method)) {
    98                          public boolean isCacheable() { return false; }
    99                      };
    100                     methodList.add(mmethod);
    101                 }
    102             }
    103         }
    104     }
    105
    106 	/***
    107 	 * @param clazz
    108 	 * @param closure
    109 	 */
    110 	public static void use(Class clazz, Closure closure) {
    111 		newScope();
    112 		try {
    113 			use(clazz);
    114 			closure.call();
    115 		} finally {
    116 			endScope();
    117 		}
    118 	}
    119
    120 	/***
    121 	 * @param classes
    122 	 * @param closure
    123 	 */
    124 	public static void use(List classes, Closure closure) {
    125 		newScope();
    126 		try {
    127 			for (Iterator i = classes.iterator(); i.hasNext(); ) {
    128 				Class clazz = (Class) i.next();
    129 				use(clazz);
    130 			}
    131 			closure.call();
    132 		} finally {
    133 			endScope();
    134 		}
    135 	}
    136
    137     private static ThreadLocal local = new ThreadLocal() {
    138         protected Object initialValue() {
    139         		List stack = new ArrayList();
    140         		stack.add(Collections.EMPTY_MAP);
    141         		return stack;
    142         	}
    143     };
    144
    145     private static void newScope() {
    146         List stack = (List) local.get();
    147     	Map properties = new WeakHashMap(getProperties());
    148     	stack.add(properties);
    149     }
    150
    151     private static void endScope() {
    152         List stack = (List) local.get();
    153     	stack.remove(stack.size() - 1);
    154     }
    155
    156     private static Map getProperties() {
    157         List stack = (List) local.get();
    158         Map properties = (Map) stack.get(stack.size() - 1);
    159         return properties;
    160     }
    161
    162     /***
    163      * @param method
    164      * @param metaMethodsMap
    165      * @return
    166      */
    167     private static List getMethodList(Map metaMethodsMap, String name) {
    168         List methodList = (List) metaMethodsMap.get(name);
    169         if (methodList == null) {
    170             methodList = new ArrayList(1);
    171             metaMethodsMap.put(name, methodList);
    172         }
    173         return methodList;
    174     }
    175
    176     /***
    177      * @param properties
    178      * @param metaClass
    179      * @return
    180      */
    181     private static Map getMetaMethods(Map properties, Class metaClass) {
    182         Map metaMethodsMap = (Map) properties.get(metaClass);
    183         if (metaMethodsMap == null) {
    184             metaMethodsMap = new HashMap();
    185             properties.put(metaClass, metaMethodsMap);
    186         }
    187         return metaMethodsMap;
    188     }
    189
    190 }