KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > groovy > runtime > GroovyCategorySupport


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 JavaDoc;
40 import java.lang.reflect.Modifier JavaDoc;
41 import java.util.ArrayList JavaDoc;
42 import java.util.Collections JavaDoc;
43 import java.util.HashMap JavaDoc;
44 import java.util.Iterator JavaDoc;
45 import java.util.List JavaDoc;
46 import java.util.Map JavaDoc;
47 import java.util.WeakHashMap JavaDoc;
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 JavaDoc getCategoryMethods(Class JavaDoc categorizedClass, String JavaDoc name) {
63         Map JavaDoc properties = getProperties();
64         List JavaDoc methodList = new ArrayList JavaDoc();
65         for (Iterator JavaDoc i = properties.keySet().iterator(); i.hasNext(); ) {
66             Class JavaDoc current = (Class JavaDoc) i.next();
67             if (current.isAssignableFrom(categorizedClass)) {
68                 Map JavaDoc metaMethodsMap = (Map JavaDoc) properties.get(current);
69                 List JavaDoc newMethodList = (List JavaDoc) 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 JavaDoc categoryClass) {
87         Map JavaDoc 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 JavaDoc[] paramTypes = method.getParameterTypes();
93                 if (paramTypes.length > 0) {
94                     Class JavaDoc metaClass = paramTypes[0];
95                     Map JavaDoc metaMethodsMap = getMetaMethods(properties, metaClass);
96                     List JavaDoc 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 JavaDoc 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 JavaDoc classes, Closure closure) {
125         newScope();
126         try {
127             for (Iterator JavaDoc i = classes.iterator(); i.hasNext(); ) {
128                 Class JavaDoc clazz = (Class JavaDoc) i.next();
129                 use(clazz);
130             }
131             closure.call();
132         } finally {
133             endScope();
134         }
135     }
136
137     private static ThreadLocal JavaDoc local = new ThreadLocal JavaDoc() {
138         protected Object JavaDoc initialValue() {
139                 List JavaDoc stack = new ArrayList JavaDoc();
140                 stack.add(Collections.EMPTY_MAP);
141                 return stack;
142             }
143     };
144     
145     private static void newScope() {
146         List JavaDoc stack = (List JavaDoc) local.get();
147         Map JavaDoc properties = new WeakHashMap JavaDoc(getProperties());
148         stack.add(properties);
149     }
150     
151     private static void endScope() {
152         List JavaDoc stack = (List JavaDoc) local.get();
153         stack.remove(stack.size() - 1);
154     }
155     
156     private static Map JavaDoc getProperties() {
157         List JavaDoc stack = (List JavaDoc) local.get();
158         Map JavaDoc properties = (Map JavaDoc) stack.get(stack.size() - 1);
159         return properties;
160     }
161     
162     /**
163      * @param method
164      * @param metaMethodsMap
165      * @return
166      */

167     private static List JavaDoc getMethodList(Map JavaDoc metaMethodsMap, String JavaDoc name) {
168         List JavaDoc methodList = (List JavaDoc) metaMethodsMap.get(name);
169         if (methodList == null) {
170             methodList = new ArrayList JavaDoc(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 JavaDoc getMetaMethods(Map JavaDoc properties, Class JavaDoc metaClass) {
182         Map JavaDoc metaMethodsMap = (Map JavaDoc) properties.get(metaClass);
183         if (metaMethodsMap == null) {
184             metaMethodsMap = new HashMap JavaDoc();
185             properties.put(metaClass, metaMethodsMap);
186         }
187         return metaMethodsMap;
188     }
189
190 }
191
Popular Tags