KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > bsh > ClassGeneratorImpl


1 package bsh;
2
3 import java.io.*;
4 import java.util.*;
5 import java.lang.reflect.InvocationTargetException JavaDoc;
6 import java.lang.reflect.Method JavaDoc;
7
8 /**
9     
10     @author Pat Niemeyer (pat@pat.net)
11 */

12 public class ClassGeneratorImpl extends ClassGenerator
13 {
14     public Class JavaDoc generateClass(
15         String JavaDoc name, Modifiers modifiers,
16         Class JavaDoc [] interfaces, Class JavaDoc superClass, BSHBlock block,
17         boolean isInterface, CallStack callstack, Interpreter interpreter
18     )
19         throws EvalError
20     {
21         // Delegate to the static method
22
return generateClassImpl( name, modifiers, interfaces, superClass,
23             block, isInterface, callstack, interpreter );
24     }
25
26     public Object JavaDoc invokeSuperclassMethod(
27         BshClassManager bcm, Object JavaDoc instance, String JavaDoc methodName, Object JavaDoc [] args
28     )
29         throws UtilEvalError, ReflectError, InvocationTargetException JavaDoc
30     {
31         // Delegate to the static method
32
return invokeSuperclassMethodImpl( bcm, instance, methodName, args );
33     }
34
35     /**
36         Change the parent of the class instance namespace.
37         This is currently used for inner class support.
38         Note: This method will likely be removed in the future.
39     */

40     // This could be static
41
public void setInstanceNameSpaceParent(
42         Object JavaDoc instance, String JavaDoc className, NameSpace parent )
43     {
44         This ithis =
45             ClassGeneratorUtil.getClassInstanceThis( instance, className );
46         ithis.getNameSpace().setParent( parent );
47     }
48
49     /**
50         Parse the BSHBlock for for the class definition and generate the class
51         using ClassGenerator.
52     */

53     public static Class JavaDoc generateClassImpl(
54         String JavaDoc name, Modifiers modifiers,
55         Class JavaDoc [] interfaces, Class JavaDoc superClass, BSHBlock block,
56         boolean isInterface, CallStack callstack, Interpreter interpreter
57     )
58         throws EvalError
59     {
60         // Scripting classes currently requires accessibility
61
// This can be eliminated with a bit more work.
62
try {
63             Capabilities.setAccessibility( true );
64         } catch ( Capabilities.Unavailable e )
65         {
66             throw new EvalError(
67                 "Defining classes currently requires reflective Accessibility.",
68                 block, callstack );
69         }
70
71         NameSpace enclosingNameSpace = callstack.top();
72         String JavaDoc packageName = enclosingNameSpace.getPackage();
73         String JavaDoc className = enclosingNameSpace.isClass ?
74             ( enclosingNameSpace.getName()+"$"+name ) : name;
75         String JavaDoc fqClassName =
76             packageName == null ? className : packageName + "." + className;
77
78         BshClassManager bcm = interpreter.getClassManager();
79         // Race condition here...
80
bcm.definingClass( fqClassName );
81
82         // Create the class static namespace
83
NameSpace classStaticNameSpace =
84             new NameSpace( enclosingNameSpace, className);
85         classStaticNameSpace.isClass = true;
86
87         callstack.push( classStaticNameSpace );
88
89         // Evaluate any inner class class definitions in the block
90
// effectively recursively call this method for contained classes first
91
block.evalBlock(
92             callstack, interpreter, true/*override*/,
93             ClassNodeFilter.CLASSCLASSES );
94
95         // Generate the type for our class
96
Variable [] variables =
97             getDeclaredVariables( block, callstack, interpreter, packageName );
98         DelayedEvalBshMethod [] methods =
99             getDeclaredMethods( block, callstack, interpreter, packageName );
100
101         ClassGeneratorUtil classGenerator = new ClassGeneratorUtil(
102             modifiers, className, packageName, superClass, interfaces,
103             variables, methods, classStaticNameSpace, isInterface );
104         byte [] code = classGenerator.generateClass();
105
106         // if debug, write out the class file to debugClasses directory
107
String JavaDoc dir = System.getProperty("debugClasses");
108         if ( dir != null )
109         try {
110             FileOutputStream out=
111                 new FileOutputStream( dir+"/"+className+".class" );
112             out.write(code);
113             out.close();
114         } catch ( IOException e ) { }
115
116         // Define the new class in the classloader
117
Class JavaDoc genClass = bcm.defineClass( fqClassName, code );
118
119         // import the unq name into parent
120
enclosingNameSpace.importClass( fqClassName.replace('$','.') );
121
122         try {
123             classStaticNameSpace.setLocalVariable(
124                 ClassGeneratorUtil.BSHINIT, block, false/*strictJava*/ );
125         } catch ( UtilEvalError e ) {
126             throw new InterpreterError("unable to init static: "+e );
127         }
128
129         // Give the static space its class static import
130
// important to do this after all classes are defined
131
classStaticNameSpace.setClassStatic( genClass );
132
133         // evaluate the static portion of the block in the static space
134
block.evalBlock(
135             callstack, interpreter, true/*override*/,
136             ClassNodeFilter.CLASSSTATIC );
137
138         callstack.pop();
139
140         if ( !genClass.isInterface() )
141         {
142         // Set the static bsh This callback
143
String JavaDoc bshStaticFieldName = ClassGeneratorUtil.BSHSTATIC+className;
144         try {
145             LHS lhs = Reflect.getLHSStaticField( genClass, bshStaticFieldName );
146             lhs.assign(
147                 classStaticNameSpace.getThis( interpreter ), false/*strict*/ );
148         } catch ( Exception JavaDoc e ) {
149             throw new InterpreterError("Error in class gen setup: "+e );
150         }
151         }
152
153         bcm.doneDefiningClass( fqClassName );
154         return genClass;
155     }
156
157     static Variable [] getDeclaredVariables(
158         BSHBlock body, CallStack callstack, Interpreter interpreter,
159         String JavaDoc defaultPackage
160     )
161     {
162         List vars = new ArrayList();
163         for( int child=0; child<body.jjtGetNumChildren(); child++ )
164         {
165             SimpleNode node = (SimpleNode)body.jjtGetChild(child);
166             if ( node instanceof BSHTypedVariableDeclaration )
167             {
168                 BSHTypedVariableDeclaration tvd =
169                     (BSHTypedVariableDeclaration)node;
170                 Modifiers modifiers = tvd.modifiers;
171
172                 String JavaDoc type = tvd.getTypeDescriptor(
173                     callstack, interpreter, defaultPackage );
174
175                 BSHVariableDeclarator [] vardec = tvd.getDeclarators();
176                 for( int i = 0; i< vardec.length; i++)
177                 {
178                     String JavaDoc name = vardec[i].name;
179                     try {
180                         Variable var = new Variable(
181                             name, type, null/*value*/, modifiers );
182                         vars.add( var );
183                     } catch ( UtilEvalError e ) {
184                         // value error shouldn't happen
185
}
186                 }
187             }
188         }
189
190         return (Variable [])vars.toArray( new Variable[0] );
191     }
192
193     static DelayedEvalBshMethod [] getDeclaredMethods(
194         BSHBlock body, CallStack callstack, Interpreter interpreter,
195         String JavaDoc defaultPackage
196     )
197         throws EvalError
198     {
199         List methods = new ArrayList();
200         for( int child=0; child<body.jjtGetNumChildren(); child++ )
201         {
202             SimpleNode node = (SimpleNode)body.jjtGetChild(child);
203             if ( node instanceof BSHMethodDeclaration )
204             {
205                 BSHMethodDeclaration md = (BSHMethodDeclaration)node;
206                 md.insureNodesParsed();
207                 Modifiers modifiers = md.modifiers;
208                 String JavaDoc name = md.name;
209                 String JavaDoc returnType = md.getReturnTypeDescriptor(
210                     callstack, interpreter, defaultPackage );
211                 BSHReturnType returnTypeNode = md.getReturnTypeNode();
212                 BSHFormalParameters paramTypesNode = md.paramsNode;
213                 String JavaDoc [] paramTypes = paramTypesNode.getTypeDescriptors(
214                     callstack, interpreter, defaultPackage );
215
216                 DelayedEvalBshMethod bm = new DelayedEvalBshMethod(
217                     name,
218                     returnType, returnTypeNode,
219                     md.paramsNode.getParamNames(),
220                     paramTypes, paramTypesNode,
221                     md.blockNode, null/*declaringNameSpace*/,
222                     modifiers, callstack, interpreter
223                 );
224
225                 methods.add( bm );
226             }
227         }
228
229         return (DelayedEvalBshMethod [])methods.toArray(
230             new DelayedEvalBshMethod[0] );
231     }
232
233     /**
234         A node filter that filters nodes for either a class body static
235         initializer or instance initializer. In the static case only static
236         members are passed, etc.
237     */

238     static class ClassNodeFilter implements BSHBlock.NodeFilter
239     {
240         public static final int STATIC=0, INSTANCE=1, CLASSES=2;
241
242         public static ClassNodeFilter CLASSSTATIC =
243             new ClassNodeFilter( STATIC );
244         public static ClassNodeFilter CLASSINSTANCE =
245             new ClassNodeFilter( INSTANCE );
246         public static ClassNodeFilter CLASSCLASSES =
247             new ClassNodeFilter( CLASSES );
248
249         int context;
250
251         private ClassNodeFilter( int context ) { this.context = context; }
252
253         public boolean isVisible( SimpleNode node )
254         {
255             if ( context == CLASSES )
256                 return node instanceof BSHClassDeclaration;
257
258             // Only show class decs in CLASSES
259
if ( node instanceof BSHClassDeclaration )
260                 return false;
261
262             if ( context == STATIC )
263                 return isStatic( node );
264
265             if ( context == INSTANCE )
266                 return !isStatic( node );
267
268             // ALL
269
return true;
270         }
271
272         boolean isStatic( SimpleNode node )
273         {
274             if ( node instanceof BSHTypedVariableDeclaration )
275                 return ((BSHTypedVariableDeclaration)node).modifiers != null
276                     && ((BSHTypedVariableDeclaration)node).modifiers
277                         .hasModifier("static");
278
279             if ( node instanceof BSHMethodDeclaration )
280                 return ((BSHMethodDeclaration)node).modifiers != null
281                     && ((BSHMethodDeclaration)node).modifiers
282                         .hasModifier("static");
283
284             // need to add static block here
285
if ( node instanceof BSHBlock)
286                 return false;
287
288             return false;
289         }
290     }
291
292     public static Object JavaDoc invokeSuperclassMethodImpl(
293         BshClassManager bcm, Object JavaDoc instance, String JavaDoc methodName, Object JavaDoc [] args
294     )
295         throws UtilEvalError, ReflectError, InvocationTargetException JavaDoc
296     {
297         String JavaDoc superName = ClassGeneratorUtil.BSHSUPER+methodName;
298         
299         // look for the specially named super delegate method
300
Class JavaDoc clas = instance.getClass();
301         Method JavaDoc superMethod = Reflect.resolveJavaMethod(
302             bcm, clas, superName, Types.getTypes(args), false/*onlyStatic*/ );
303         if ( superMethod != null )
304             return Reflect.invokeMethod(
305                 superMethod, instance, args );
306
307         // No super method, try to invoke regular method
308
// could be a superfluous "super." which is legal.
309
Class JavaDoc superClass = clas.getSuperclass();
310         superMethod = Reflect.resolveExpectedJavaMethod(
311             bcm, superClass, instance, methodName, args,
312             false/*onlyStatic*/ );
313         return Reflect.invokeMethod( superMethod, instance, args );
314     }
315
316 }
317
Popular Tags