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 }