001: // Copyright (c) Corporation for National Research Initiatives
002: package org.python.core;
003:
004: import java.util.Vector;
005: import java.io.Serializable;
006:
007: /**
008: * A python class.
009: */
010:
011: public class PyClass extends PyObject {
012: /**
013: * Holds the namespace for this class
014: */
015: public PyObject __dict__;
016:
017: /**
018: * The base classes of this class
019: */
020: public PyTuple __bases__;
021:
022: /**
023: * The name of this class
024: */
025: public String __name__;
026:
027: // Store these methods for performance optimization
028: // These are only used by PyInstance
029: PyObject __getattr__, __setattr__, __delattr__, __tojava__,
030: __del__, __contains__;
031:
032: // Holds the classes for which this is a proxy
033: // Only used when subclassing from a Java class
034: protected Class proxyClass;
035:
036: // xxx map 'super__*' names -> array of methods
037: protected java.util.HashMap super __methods;
038:
039: public static PyClass __class__;
040:
041: PyClass(boolean fakeArg) { // xxx check
042: super ();
043: proxyClass = null;
044: }
045:
046: protected PyClass() {
047: proxyClass = null;
048: }
049:
050: /**
051: * Create a python class.
052: *
053: * @param name name of the class.
054: * @param bases A list of base classes.
055: * @param dict The class dict. Normally this dict is returned by the class
056: * code object.
057: *
058: * @see org.python.core.Py#makeClass(String, PyObject[], PyCode, PyObject)
059: */
060: public PyClass(String name, PyTuple bases, PyObject dict) {
061: this (name, bases, dict, null);
062: }
063:
064: /**
065: * Create a python class which inherits from a java class and where we
066: * already have generated a proxyclass. If we do not have a pre-generated
067: * proxyclass, the class initialization method will create such a proxyclass
068: * if bases contain a java class.
069: *
070: * @param name name of the class.
071: * @param bases A list of base classes.
072: * @param dict The class dict. Normally this dict is returned by the class
073: * code object.
074: *
075: * @see org.python.core.Py#makeClass(String, PyObject[], PyCode, PyObject,
076: * Class)
077: */
078: public PyClass(String name, PyTuple bases, PyObject dict,
079: Class proxyClass) {
080: this .proxyClass = proxyClass;
081: init(name, bases, dict);
082: }
083:
084: protected Class getProxyClass() {
085: return proxyClass;
086: }
087:
088: void init(String name, PyTuple bases, PyObject dict) {
089: // System.out.println("bases: "+bases+", "+name.string);
090: // System.out.println("init class: "+name);
091: __name__ = name;
092: __bases__ = bases;
093: __dict__ = dict;
094:
095: findModule(dict);
096:
097: if (proxyClass == null) {
098: Vector interfaces = new Vector();
099: Class baseClass = null;
100: for (int i = 0; i < bases.size(); i++) {
101: Class proxy = ((PyClass) bases.pyget(i))
102: .getProxyClass();
103: if (proxy != null) {
104: if (proxy.isInterface()) {
105: interfaces.addElement(proxy);
106: } else {
107: if (baseClass != null) {
108: throw Py
109: .TypeError("no multiple inheritance "
110: + "for Java classes: "
111: + proxy.getName()
112: + " and "
113: + baseClass.getName());
114: }
115: // xxx explicitly disable this for now, types will allow
116: // this
117: if (PyObject.class.isAssignableFrom(proxy)) {
118: throw Py
119: .TypeError("subclassing PyObject subclasses"
120: + " not supported");
121: }
122: baseClass = proxy;
123: }
124: }
125: }
126: if (baseClass != null || interfaces.size() != 0) {
127: String proxyName = __name__;
128: PyObject module = dict.__finditem__("__module__");
129: if (module != null) {
130: proxyName = module.toString() + "$" + __name__;
131: }
132: proxyClass = MakeProxies.makeProxy(baseClass,
133: interfaces, __name__, proxyName, __dict__);
134: }
135: }
136:
137: if (proxyClass != null) {
138: // xxx more efficient way without going through a PyJavaClass?
139: PyObject super Dict = PyJavaClass.lookup(proxyClass)
140: .__findattr__("__dict__"); // xxx getDict perhaps?
141: // This code will add in the needed super__ methods to the class
142: PyObject snames = super Dict.__finditem__("__supernames__");
143: if (snames != null) {
144: PyObject iter = snames.__iter__();
145: for (PyObject item; (item = iter.__iternext__()) != null;) {
146: if (__dict__.__finditem__(item) == null) {
147: PyObject super Func = super Dict
148: .__finditem__(item);
149: if (super Func != null) {
150: __dict__.__setitem__(item, super Func);
151: }
152: }
153: }
154: }
155:
156: // xxx populate super__methods, experiment.
157:
158: java.lang.reflect.Method proxy_methods[] = proxyClass
159: .getMethods();
160:
161: super __methods = new java.util.HashMap();
162:
163: for (int i = 0; i < proxy_methods.length; i++) {
164: java.lang.reflect.Method meth = proxy_methods[i];
165: String meth_name = meth.getName();
166: if (meth_name.startsWith("super__")) {
167: java.util.ArrayList samename = (java.util.ArrayList) super __methods
168: .get(meth_name);
169: if (samename == null) {
170: samename = new java.util.ArrayList();
171: super __methods.put(meth_name, samename);
172: }
173: samename.add(meth);
174: }
175: }
176:
177: java.lang.reflect.Method[] empty_methods = new java.lang.reflect.Method[0];
178: for (java.util.Iterator iter = super __methods.entrySet()
179: .iterator(); iter.hasNext();) {
180: java.util.Map.Entry entry = (java.util.Map.Entry) iter
181: .next();
182: // System.out.println(entry.getKey()); // debug
183: entry.setValue(((java.util.ArrayList) entry.getValue())
184: .toArray(empty_methods));
185: }
186: }
187:
188: // System.out.println("proxyClasses: "+proxyClasses+", "+
189: // proxyClasses[0]);
190: if (dict.__finditem__("__doc__") == null) {
191: dict.__setitem__("__doc__", Py.None);
192: }
193:
194: // Setup cached references to methods where performance really counts
195: __getattr__ = lookup("__getattr__", false);
196: __setattr__ = lookup("__setattr__", false);
197: __delattr__ = lookup("__delattr__", false);
198: __tojava__ = lookup("__tojava__", false);
199: __del__ = lookup("__del__", false);
200: __contains__ = lookup("__contains__", false);
201: }
202:
203: protected void findModule(PyObject dict) {
204: PyObject module = dict.__finditem__("__module__");
205: if (module == null || module == Py.None) {
206: // System.out.println("in PyClass getFrame: "+__name__.string);
207: PyFrame f = Py.getFrame();
208: if (f != null) {
209: PyObject nm = f.f_globals.__finditem__("__name__");
210: if (nm != null) {
211: dict.__setitem__("__module__", nm);
212: }
213: }
214: }
215: }
216:
217: public Object __tojava__(Class c) {
218: if ((c == Object.class || c == Class.class || c == Serializable.class)
219: && proxyClass != null) {
220: return proxyClass;
221: }
222: return super .__tojava__(c);
223: }
224:
225: // returns [PyObject, PyClass]
226: PyObject[] lookupGivingClass(String name, boolean stop_at_java) {
227: PyObject result = __dict__.__finditem__(name);
228: PyClass resolvedClass = this ;
229: if (result == null && __bases__ != null) {
230: int n = __bases__.__len__();
231: for (int i = 0; i < n; i++) {
232: resolvedClass = (PyClass) (__bases__.__getitem__(i));
233: PyObject[] res = resolvedClass.lookupGivingClass(name,
234: stop_at_java);
235: if (res[0] != null) {
236: return res;
237: }
238: }
239: }
240: return new PyObject[] { result, resolvedClass };
241: }
242:
243: public PyObject fastGetDict() {
244: return __dict__;
245: }
246:
247: PyObject lookup(String name, boolean stop_at_java) {
248: PyObject[] result = lookupGivingClass(name, stop_at_java);
249: return result[0];
250: }
251:
252: public PyObject __findattr__(String name) {
253: if (name == "__dict__") {
254: return __dict__;
255: }
256: if (name == "__name__") {
257: return new PyString(__name__);
258: }
259: if (name == "__bases__") {
260: return __bases__;
261: }
262:
263: PyObject[] result = lookupGivingClass(name, false);
264:
265: if (result[0] == null) {
266: return super .__findattr__(name);
267: }
268: // xxx do we need to use result[1] (wherefound) for java cases for backw
269: // comp?
270: return result[0].__get__(null, this );
271: }
272:
273: public void __setattr__(String name, PyObject value) {
274: if (name == "__dict__") {
275: if (!value.isMappingType())
276: throw Py
277: .TypeError("__dict__ must be a dictionary object");
278: __dict__ = value;
279: return;
280: }
281: if (name == "__name__") {
282: if (!(value instanceof PyString)) {
283: throw Py.TypeError("__name__ must be a string object");
284: }
285: __name__ = value.toString();
286: return;
287: }
288: if (name == "__bases__") {
289: if (!(value instanceof PyTuple)) {
290: throw Py.TypeError("__bases__ must be a tuple object");
291: }
292: __bases__ = (PyTuple) value;
293: return;
294: }
295:
296: __dict__.__setitem__(name, value);
297: }
298:
299: public void __delattr__(String name) {
300: __dict__.__delitem__(name);
301: }
302:
303: public void __rawdir__(PyDictionary accum) {
304: addKeys(accum, "__dict__");
305: PyObject[] bases = __bases__.getArray();
306: for (int i = 0; i < bases.length; i++) {
307: bases[i].__rawdir__(accum);
308: }
309: }
310:
311: public PyObject __call__(PyObject[] args, String[] keywords) {
312: PyInstance inst;
313: if (__del__ == null) {
314: inst = new PyInstance(this );
315: } else {
316: // the class defined an __del__ method
317: inst = new PyFinalizableInstance(this );
318: }
319: inst.__init__(args, keywords);
320:
321: // xxx this cannot happen anymore
322: /*
323: * if (proxyClass != null &&
324: * PyObject.class.isAssignableFrom(proxyClass)) { // It would be better
325: * if we didn't have to create a PyInstance // in the first place.
326: * ((PyObject)inst.javaProxy).__class__ = this; return
327: * (PyObject)inst.javaProxy; }
328: */
329:
330: return inst;
331: }
332:
333: /* PyClass's are compared based on __name__ */
334: public int __cmp__(PyObject other) {
335: if (!(other instanceof PyClass)) {
336: return -2;
337: }
338: int c = __name__.compareTo(((PyClass) other).__name__);
339: return c < 0 ? -1 : c > 0 ? 1 : 0;
340: }
341:
342: public PyString __str__() {
343: // Current CPython standard is that str(class) prints as
344: // module.class. If the class has no module, then just the class
345: // name is printed.
346: if (__dict__ == null) {
347: return new PyString(__name__);
348: }
349: PyObject mod = __dict__.__finditem__("__module__");
350: if (mod == null || !(mod instanceof PyString)) {
351: return new PyString(__name__);
352: }
353: String smod = ((PyString) mod).toString();
354: return new PyString(smod + "." + __name__);
355: }
356:
357: public String toString() {
358: PyObject mod = __dict__.__finditem__("__module__");
359: String smod;
360: if (mod == null || !(mod instanceof PyString)) {
361: smod = "<unknown>";
362: } else {
363: smod = ((PyString) mod).toString();
364: }
365: return "<class " + smod + "." + __name__ + " " + Py.idstr(this )
366: + ">";
367: }
368:
369: public boolean isSubClass(PyClass super class) {
370: if (this == super class) {
371: return true;
372: }
373: if (getProxyClass() != null
374: && super class.getProxyClass() != null) {
375: if (super class.proxyClass.isAssignableFrom(this .proxyClass)) {
376: return true;
377: }
378: }
379: if (this .__bases__ == null || super class.__bases__ == null) {
380: return false;
381: }
382: PyObject[] bases = this .__bases__.getArray();
383: int n = bases.length;
384: for (int i = 0; i < n; i++) {
385: PyClass c = (PyClass) bases[i];
386: if (c.isSubClass(super class)) {
387: return true;
388: }
389: }
390: return false;
391: }
392:
393: /**
394: * @see org.python.core.PyObject#safeRepr()
395: */
396: public String safeRepr() throws PyIgnoreMethodTag {
397: return "class '" + __name__ + "'";
398: }
399: }
|