KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > python > core > PyClass


1 // Copyright (c) Corporation for National Research Initiatives
2
package org.python.core;
3 import java.util.Vector JavaDoc;
4 import java.io.Serializable JavaDoc;
5 import java.lang.reflect.Method JavaDoc;
6
7 /**
8  * A python class.
9  */

10
11 public class PyClass extends PyObject
12 {
13     /**
14      * Holds the namespace for this class
15      **/

16     public PyObject __dict__;
17
18     /**
19      * The base classes of this class
20      **/

21     public PyTuple __bases__;
22
23     /**
24      * The name of this class
25      **/

26     public String JavaDoc __name__;
27
28     // Store these methods for performance optimization
29
// These are only used by PyInstance
30
PyObject __getattr__, __setattr__, __delattr__, __tojava__,
31              __del__, __contains__;
32
33     // Holds the classes for which this is a proxy
34
// Only used when subclassing from a Java class
35
protected Class JavaDoc proxyClass;
36     
37     // xxx map 'super__*' names -> array of methods
38
protected java.util.HashMap JavaDoc super__methods;
39
40     public static PyClass __class__;
41
42     PyClass(boolean fakeArg) { // xxx check
43
super();
44         proxyClass = null;
45     }
46
47     protected PyClass() {
48         proxyClass = null;
49     }
50
51
52     /**
53      * Create a python class.
54      *
55      * @param name name of the class.
56      * @param bases A list of base classes.
57      * @param dict The class dict. Normally this dict is returned by
58      * the class code object.
59      *
60      * @see org.python.core.Py#makeClass(String, PyObject[], PyCode, PyObject)
61      */

62     public PyClass(String JavaDoc name, PyTuple bases, PyObject dict) {
63         this(name, bases, dict, null);
64     }
65
66     /**
67      * Create a python class which inherit from a java class and where
68      * we already have generated a proxyclass. If we do not have a
69      * pre-generated proxyclass, the class initialization method will
70      * create such a proxyclass if bases contain a java class.
71      *
72      * @param name name of the class.
73      * @param bases A list of base classes.
74      * @param dict The class dict. Normally this dict is returned by
75      * the class code object.
76      *
77      * @see org.python.core.Py#makeClass(String, PyObject[], PyCode,
78      * PyObject, Class)
79      */

80     public PyClass(String JavaDoc name, PyTuple bases, PyObject dict,
81                    Class JavaDoc proxyClass)
82     {
83         this.proxyClass = proxyClass;
84         init(name, bases, dict);
85     }
86
87     protected Class JavaDoc getProxyClass() {
88         return proxyClass;
89     }
90
91     void init(String JavaDoc name, PyTuple bases, PyObject dict) {
92         //System.out.println("bases: "+bases+", "+name.string);
93
//System.out.println("init class: "+name);
94
__name__ = name;
95         __bases__ = bases;
96         __dict__ = dict;
97
98         findModule(dict);
99
100         if (proxyClass == null) {
101             Vector JavaDoc interfaces = new Vector JavaDoc();
102             Class JavaDoc baseClass = null;
103             for (int i=0; i<bases.size(); i++) {
104                 Class JavaDoc proxy = ((PyClass)bases.pyget(i)).getProxyClass();
105                 if (proxy != null) {
106                     if (proxy.isInterface()) {
107                         interfaces.addElement(proxy);
108                     } else {
109                         if (baseClass != null) {
110                             throw Py.TypeError("no multiple inheritance "+
111                                                "for Java classes: "+
112                                                proxy.getName()+
113                                                " and "+
114                                                baseClass.getName());
115                         }
116                         // xxx explicitly disable this for now, types will allow this
117
if (PyObject.class.isAssignableFrom(proxy))
118                             throw Py.TypeError("subclassing PyObject subclasses" + " not supported");
119                         baseClass = proxy;
120                     }
121                 }
122             }
123             if (baseClass != null || interfaces.size() != 0) {
124                 String JavaDoc proxyName = __name__;
125                 PyObject module = dict.__finditem__("__module__");
126                 if (module != null)
127                     proxyName = module.toString() + "$" + __name__;
128                 proxyClass = MakeProxies.makeProxy(baseClass, interfaces,
129                                                    __name__, proxyName,
130                                                    __dict__);
131             }
132         }
133
134         if (proxyClass != null) {
135             // xxx more efficient way without going through a PyJavaClass?
136
PyObject superDict =
137                 PyJavaClass.lookup(proxyClass).__findattr__("__dict__"); // xxx getDict perhaps?
138
// This code will add in the needed super__ methods to the class
139
PyObject snames = superDict.__finditem__("__supernames__");
140             if (snames != null) {
141                 PyObject iter = snames.__iter__();
142                 for (PyObject item; (item = iter.__iternext__()) != null; ) {
143                     if (__dict__.__finditem__(item) == null) {
144                         PyObject superFunc = superDict.__finditem__(item);
145                         if (superFunc != null)
146                             __dict__.__setitem__(item, superFunc);
147                     }
148                 }
149             }
150             
151             // xxx populate super__methods, experiment.
152

153             java.lang.reflect.Method JavaDoc proxy_methods[] = proxyClass.getMethods();
154             
155             super__methods = new java.util.HashMap JavaDoc();
156             
157             for(int i = 0; i<proxy_methods.length; i++) {
158                 java.lang.reflect.Method JavaDoc meth = proxy_methods[i];
159                 String JavaDoc meth_name = meth.getName();
160                 if (meth_name.startsWith("super__")) {
161                     java.util.ArrayList JavaDoc samename = (java.util.ArrayList JavaDoc)super__methods.get(meth_name);
162                     if (samename == null) {
163                         samename = new java.util.ArrayList JavaDoc();
164                         super__methods.put(meth_name,samename);
165                     }
166                     samename.add(meth);
167                 }
168             }
169             
170             java.lang.reflect.Method JavaDoc[] empty_methods = new java.lang.reflect.Method JavaDoc[0];
171             for (java.util.Iterator JavaDoc iter = super__methods.entrySet().iterator();
172                  iter.hasNext();) {
173                 java.util.Map.Entry entry = (java.util.Map.Entry)iter.next();
174                 //System.out.println(entry.getKey()); // debug
175
entry.setValue(((java.util.ArrayList JavaDoc)entry.getValue()).toArray(empty_methods));
176             }
177             
178         }
179
180         //System.out.println("proxyClasses: "+proxyClasses+", "+
181
// proxyClasses[0]);
182
if (dict.__finditem__("__doc__") == null) {
183             dict.__setitem__("__doc__", Py.None);
184         }
185
186         // Setup cached references to methods where performance really counts
187
__getattr__ = lookup("__getattr__", false);
188         __setattr__ = lookup("__setattr__", false);
189         __delattr__ = lookup("__delattr__", false);
190         __tojava__ = lookup("__tojava__", false);
191         __del__ = lookup("__del__", false);
192         __contains__ = lookup("__contains__", false);
193     }
194
195     protected void findModule(PyObject dict) {
196         PyObject module = dict.__finditem__("__module__");
197         if (module == null || module == Py.None) {
198             //System.out.println("in PyClass getFrame: "+__name__.string);
199
PyFrame f = Py.getFrame();
200             if (f != null) {
201                 PyObject nm = f.f_globals.__finditem__("__name__");
202                 if (nm != null)
203                     dict.__setitem__("__module__", nm);
204             }
205         }
206     }
207
208     public Object JavaDoc __tojava__(Class JavaDoc c) {
209         if ((c == Object JavaDoc.class || c == Class JavaDoc.class || c == Serializable JavaDoc.class)
210                                       && proxyClass != null) {
211             return proxyClass;
212         }
213         return super.__tojava__(c);
214     }
215
216     // returns [PyObject, PyClass]
217
PyObject[] lookupGivingClass(String JavaDoc name, boolean stop_at_java) {
218         PyObject result = __dict__.__finditem__(name);
219         PyClass resolvedClass = this;
220         if (result == null && __bases__ != null) {
221             int n = __bases__.__len__();
222             for (int i=0; i<n; i++) {
223                 resolvedClass = (PyClass)(__bases__.__getitem__(i));
224                 PyObject[] res = resolvedClass.lookupGivingClass(name,
225                                                                stop_at_java);
226                 if (res[0] != null)
227                     return res;
228             }
229         }
230         return new PyObject[] {result, resolvedClass};
231     }
232
233     PyObject lookup(String JavaDoc name, boolean stop_at_java) {
234         PyObject[] result = lookupGivingClass(name, stop_at_java);
235         return result[0];
236     }
237
238     public PyObject __findattr__(String JavaDoc name) {
239         if (name == "__dict__") return __dict__;
240         if (name == "__name__") return new PyString(__name__);
241         if (name == "__bases__") return __bases__;
242
243         PyObject[] result = lookupGivingClass(name, false);
244
245         if (result[0] == null)
246             return super.__findattr__(name);
247         // xxx do we need to use result[1] (wherefound) for java cases for backw comp?
248
return result[0].__get__(null, this);
249     }
250
251     public void __setattr__(String JavaDoc name, PyObject value) {
252         if (name == "__dict__") {
253             if (!value.isMappingType())
254                 throw Py.TypeError("__dict__ must be a dictionary object");
255             __dict__ = value;
256             return;
257         }
258         if (name == "__name__") {
259             if (!(value instanceof PyString))
260                 throw Py.TypeError("__name__ must be a string object");
261             __name__ = value.toString();
262             return;
263         }
264         if (name == "__bases__") {
265             if (!(value instanceof PyTuple))
266                 throw Py.TypeError("__bases__ must be a tuple object");
267             __bases__ = (PyTuple) value;
268             return;
269         }
270
271         __dict__.__setitem__(name, value);
272     }
273
274     public void __delattr__(String JavaDoc name) {
275         __dict__.__delitem__(name);
276     }
277
278     public void __rawdir__(PyDictionary accum) {
279         addKeys(accum, "__dict__");
280         PyObject[] bases = __bases__.getArray();
281         for (int i=0; i < bases.length; i++)
282             bases[i].__rawdir__(accum);
283     }
284     
285     public PyObject __call__(PyObject[] args, String JavaDoc[] keywords) {
286         PyInstance inst;
287         if (__del__ == null)
288             inst = new PyInstance(this);
289         else
290             // the class defined an __del__ method
291
inst = new PyFinalizableInstance(this);
292
293         inst.__init__(args, keywords);
294
295         // xxx this cannot happen anymore
296
/*if (proxyClass != null &&
297                    PyObject.class.isAssignableFrom(proxyClass)) {
298             // It would be better if we didn't have to create a PyInstance
299             // in the first place.
300             ((PyObject)inst.javaProxy).__class__ = this;
301             return (PyObject)inst.javaProxy;
302         }*/

303
304         return inst;
305     }
306
307     /* PyClass's are compared based on __name__ */
308     public int __cmp__(PyObject other) {
309         if (!(other instanceof PyClass))
310             return -2;
311         int c = __name__.compareTo(((PyClass)other).__name__);
312         return c < 0 ? -1 : c > 0 ? 1 : 0;
313     }
314
315     public PyString __str__() {
316         // Current CPython standard is that str(class) prints as
317
// module.class. If the class has no module, then just the class
318
// name is printed.
319
if (__dict__ == null)
320             return new PyString(__name__);
321         PyObject mod = __dict__.__finditem__("__module__");
322         if (mod == null || !(mod instanceof PyString))
323             return new PyString(__name__);
324         String JavaDoc smod = ((PyString)mod).toString();
325         return new PyString(smod + "." + __name__);
326     }
327
328     public String JavaDoc toString() {
329         PyObject mod = __dict__.__finditem__("__module__");
330         String JavaDoc smod;
331         if (mod == null || !(mod instanceof PyString))
332             smod = "<unknown>";
333         else
334             smod = ((PyString)mod).toString();
335         return "<class "+smod+"."+__name__+" "+Py.idstr(this)+">";
336     }
337     
338     public boolean isSubClass(PyClass superclass) {
339         if (this == superclass)
340             return true;
341         if (this.proxyClass != null && superclass.proxyClass != null) {
342             if (superclass.proxyClass.isAssignableFrom(this.proxyClass))
343                 return true;
344         }
345         if (this.__bases__ == null || superclass.__bases__ == null)
346             return false;
347         PyObject[] bases = this.__bases__.getArray();
348         int n = bases.length;
349         for(int i=0; i<n; i++) {
350             PyClass c = (PyClass)bases[i];
351             if (c.isSubClass(superclass))
352                 return true;
353         }
354         return false;
355     }
356     
357     /**
358      * @see org.python.core.PyObject#safeRepr()
359      */

360     public String JavaDoc safeRepr() throws PyIgnoreMethodTag {
361         return "class '"+__name__+"'";
362     }
363
364 }
365
Popular Tags