001: // Copyright (c) Corporation for National Research Initiatives
002: package org.python.core;
003:
004: import java.lang.reflect.Constructor;
005: import java.lang.reflect.Field;
006: import java.lang.reflect.Method;
007: import java.lang.reflect.Modifier;
008:
009: /**
010: * A wrapper around a java class.
011: */
012:
013: public class PyJavaClass extends PyClass {
014: public PyReflectedConstructor __init__;
015:
016: public PackageManager __mgr__;
017:
018: private static InternalTables tbl;
019:
020: public synchronized final static InternalTables getInternalTables() {
021: if (tbl == null)
022: tbl = InternalTables.createInternalTables();
023: return tbl;
024: }
025:
026: public final boolean isLazy() {
027: return proxyClass == null;
028: }
029:
030: public static final PyJavaClass lookup(String name,
031: PackageManager mgr) {
032: if (tbl.queryCanonical(name)) {
033: Class c = mgr.findClass(null, name, "forced java class");
034: check_lazy_allowed(c); // xxx
035: return lookup(c);
036: }
037: PyJavaClass ret = new PyJavaClass(name, mgr);
038: tbl.putLazyCanonical(name, ret);
039: return ret;
040: }
041:
042: public synchronized static final PyJavaClass lookup(Class c) {
043: if (tbl == null) {
044: tbl = InternalTables.createInternalTables();
045: PyJavaClass jc = new PyJavaClass(true);
046: jc.init(PyJavaClass.class);
047: tbl.putCanonical(PyJavaClass.class, jc);
048: }
049: PyJavaClass ret = tbl.getCanonical(c);
050: if (ret != null)
051: return ret;
052: PyJavaClass lazy = tbl.getLazyCanonical(c.getName());
053: if (lazy != null) {
054: initLazy(lazy);
055: if (lazy.proxyClass == c)
056: return lazy;
057: }
058:
059: Class parent = c.getDeclaringClass();
060: if (parent == null)
061: ret = new PyJavaClass(c);
062: else
063: ret = new PyJavaInnerClass(c, lookup(parent));
064: tbl.putCanonical(c, ret);
065:
066: return ret;
067: }
068:
069: private PyJavaClass(boolean fakeArg) {
070: super (true);
071: }
072:
073: protected PyJavaClass(Class c) {
074: init(c);
075: }
076:
077: protected PyJavaClass(String name, PackageManager mgr) {
078: __name__ = name;
079: this .__mgr__ = mgr;
080: }
081:
082: protected void findModule(PyObject dict) {
083: }
084:
085: protected Class getProxyClass() {
086: initialize();
087: return proxyClass;
088: }
089:
090: // for the moment trying to lazily load a PyObject subclass
091: // is not allowed, (because of the PyJavaClass vs PyType class mismatch)
092: // pending PyJavaClass becoming likely a subclass of PyType
093: private static final void check_lazy_allowed(Class c) {
094: if (PyObject.class.isAssignableFrom(c)) { // xxx
095: throw Py.TypeError("cannot lazy load PyObject subclass");
096: }
097: }
098:
099: private static final void initLazy(PyJavaClass jc) {
100: Class c = jc.__mgr__.findClass(null, jc.__name__,
101: "lazy java class");
102: check_lazy_allowed(c); // xxx
103: jc.init(c);
104: tbl.putCanonical(jc.proxyClass, jc);
105: jc.__mgr__ = null;
106: }
107:
108: private boolean initialized = false;
109:
110: // Prevent recursive calls to initialize()
111: private boolean initializing = false;
112:
113: private synchronized void initialize() {
114: if (initialized || initializing)
115: return;
116: initializing = true;
117: synchronized (PyJavaClass.class) {
118: if (proxyClass == null) {
119: initLazy(this );
120: }
121: }
122: init__bases__(proxyClass);
123: init__dict__();
124:
125: if (ClassDictInit.class.isAssignableFrom(proxyClass)
126: && proxyClass != ClassDictInit.class) {
127: try {
128: Method m = proxyClass.getMethod("classDictInit",
129: new Class[] { PyObject.class });
130: m.invoke(null, new Object[] { __dict__ });
131: } catch (Exception exc) {
132: // System.err.println("Got exception: " + exc + " " +
133: // proxyClass);
134: throw Py.JavaError(exc);
135: }
136: }
137:
138: if (InitModule.class.isAssignableFrom(proxyClass)) {
139: try {
140: InitModule m = (InitModule) proxyClass.newInstance();
141: m.initModule(__dict__);
142: } catch (Exception exc) {
143: // System.err.println("Got exception: " + exc);
144: throw Py.JavaError(exc);
145: }
146: }
147:
148: initialized = true;
149: initializing = false;
150: }
151:
152: private synchronized void init__dict__() {
153: if (__dict__ != null)
154: return;
155: PyStringMap d = new PyStringMap();
156: // d.__setitem__("__module__", Py.None);
157: __dict__ = d;
158: try {
159: Method[] methods = getAccessibleMethods(proxyClass);
160: setBeanInfoCustom(proxyClass, methods);
161: setFields(proxyClass);
162: setMethods(proxyClass, methods);
163: } catch (SecurityException se) {
164: }
165: }
166:
167: private synchronized void init__class__(Class c) {
168: /* xxx disable opt, will need similar opt for types
169: if (!PyObject.class.isAssignableFrom(c))
170: return;
171: try {
172: Field field = c.getField("__class__");
173: if (Modifier.isStatic(field.getModifiers()) &&
174: field.getType().isAssignableFrom(PyJavaClass.class) &&
175: field.getDeclaringClass() == c)
176: {
177: field.set(null, this);
178: }
179: }
180: catch (NoSuchFieldException exc) {}
181: catch (IllegalAccessException exc1) {} */
182: }
183:
184: private synchronized void init__bases__(Class c) {
185: if (__bases__ != null)
186: return;
187:
188: Class interfaces[] = getAccessibleInterfaces(c);
189: int nInterfaces = interfaces.length;
190: int nBases = 0;
191: int i;
192: for (i = 0; i < nInterfaces; i++) {
193: Class inter = interfaces[i];
194: if (inter == InitModule.class || inter == PyProxy.class
195: || inter == ClassDictInit.class)
196: continue;
197: nBases++;
198: }
199:
200: Class super class = c.getSuperclass();
201: int index = 0;
202: PyObject[] bases;
203: PyJavaClass tmp;
204: if (super class == null || super class == PyObject.class) {
205: bases = new PyObject[nBases];
206: } else {
207: bases = new PyObject[nBases + 1];
208: tmp = PyJavaClass.lookup(super class);
209: bases[0] = tmp;
210: tmp.initialize();
211: index++;
212: }
213:
214: for (i = 0; i < nInterfaces; i++) {
215: Class inter = interfaces[i];
216: if (inter == InitModule.class || inter == PyProxy.class
217: || inter == ClassDictInit.class)
218: continue;
219: tmp = PyJavaClass.lookup(inter);
220: tmp.initialize();
221: bases[index++] = tmp;
222: }
223:
224: __bases__ = new PyTuple(bases);
225: }
226:
227: private void init(Class c) {
228: init__class__(c);
229: proxyClass = c;
230: __name__ = c.getName();
231: }
232:
233: /**
234: * Return the list of all accessible interfaces for a class. This will
235: * only the public interfaces. Since we can't set accessibility on
236: * interfaces, the Options.respectJavaAccessibility is not honored.
237: */
238: private static Class[] getAccessibleInterfaces(Class c) {
239: // can't modify accessibility of interfaces in Java2
240: // thus get only public interfaces
241: Class[] in = c.getInterfaces();
242: java.util.Vector v = new java.util.Vector();
243: for (int i = 0; i < in.length; i++) {
244: if (!Modifier.isPublic(in[i].getModifiers()))
245: continue;
246: v.addElement(in[i]);
247: }
248: if (v.size() == in.length)
249: return in;
250: Class[] ret = new Class[v.size()];
251: v.copyInto(ret);
252: return ret;
253: }
254:
255: /**
256: * Return the list of all accessible fields for a class. This will
257: * only be the public fields unless Options.respectJavaAccessibility is
258: * false, in which case all fields are returned.
259: */
260: private static Field[] getAccessibleFields(Class c) {
261: if (!JavaAccessibility.accessIsMutable())
262: // returns just the public fields
263: return c.getFields();
264: java.util.ArrayList fields = new java.util.ArrayList();
265: while (c != null) {
266: // get all declared fields for this class, mutate their
267: // accessibility and pop it into the array for later
268: Field[] declared = c.getDeclaredFields();
269: for (int i = 0; i < declared.length; i++) {
270: // TBD: this is a permanent change. Should we provide a
271: // way to restore the original accessibility flag?
272: JavaAccessibility.setAccessible(declared[i], true);
273: fields.add(declared[i]);
274: }
275: // walk down superclass chain. no need to deal specially with
276: // interfaces...
277: c = c.getSuperclass();
278: }
279: // return (Field[])fields.toArray(new Field[fields.size()]);
280: Field[] ret = new Field[fields.size()];
281: ret = (Field[]) fields.toArray(ret);
282: return ret;
283: }
284:
285: private void setFields(Class c) {
286: Field[] fields = getAccessibleFields(c);
287: for (int i = 0; i < fields.length; i++) {
288: Field field = fields[i];
289: if (field.getDeclaringClass() != c)
290: continue;
291:
292: String name = getName(field.getName());
293: boolean isstatic = Modifier.isStatic(field.getModifiers());
294:
295: if (isstatic) {
296: if (name.startsWith("__doc__") && name.length() > 7)
297: continue;
298: PyObject prop = lookup(name, false);
299: if (prop != null && prop instanceof PyBeanProperty) {
300: PyBeanProperty beanProp = ((PyBeanProperty) prop)
301: .copy();
302: beanProp.field = field;
303: __dict__.__setitem__(name, beanProp);
304: continue;
305: }
306: }
307: __dict__.__setitem__(name, new PyReflectedField(field));
308: }
309: }
310:
311: /* Produce a good Python name for a Java method. If the Java method
312: ends in '$', strip it (this handles reserved Java keywords) Don't
313: make any changes to keywords since this is now handled by parser
314: */
315:
316: private String getName(String name) {
317: if (name.endsWith("$"))
318: name = name.substring(0, name.length() - 1);
319: return name.intern();
320: }
321:
322: private void addMethod(Method meth) {
323: String name = getName(meth.getName());
324: if (name == "_getPyInstance" || name == "_setPyInstance"
325: || name == "_getPySystemState"
326: || name == "_setPySystemState") {
327: return;
328: }
329:
330: // Special case to handle a few troublesome methods in java.awt.*.
331: // These methods are all deprecated and interfere too badly with
332: // bean properties to be tolerated. This is totally a hack, but a
333: // lot of code that uses java.awt will break without it.
334: String classname = proxyClass.getName();
335: if (classname.startsWith("java.awt.")
336: && classname.indexOf('.', 9) == -1) {
337: if (name == "layout" || name == "insets" || name == "size"
338: || name == "minimumSize" || name == "preferredSize"
339: || name == "maximumSize" || name == "bounds"
340: || name == "enable") {
341: return;
342: }
343: }
344:
345: // See if any of my superclasses are using 'name' for something
346: // else. Or if I'm already using it myself
347: PyObject o = lookup(name, false);
348: // If it's being used as a function, then things get more
349: // interesting...
350: PyReflectedFunction func;
351: if (o != null && o instanceof PyReflectedFunction) {
352: func = (PyReflectedFunction) o;
353:
354: PyObject o1 = __dict__.__finditem__(name);
355:
356: /* If this function already exists, add this method to the
357: signature. If this alters the signature of the function in
358: some significant way, then return a duplicate and stick it in
359: the __dict__ */
360: if (o1 != o) {
361: if (func.handles(meth)) {
362: return;
363: }
364: func = func.copy();
365: }
366: func.addMethod(meth);
367: } else {
368: func = new PyReflectedFunction(meth);
369: try {
370: Field docField = proxyClass.getField("__doc__" + name);
371: int mods = docField.getModifiers();
372: if (docField.getType() == PyString.class
373: && Modifier.isPublic(mods)
374: && Modifier.isStatic(mods))
375: ;
376: func.__doc__ = (PyString) docField.get(null);
377: } catch (NoSuchFieldException ex) {
378: } catch (SecurityException ex) {
379: } catch (IllegalAccessException ex) {
380: }
381: }
382: __dict__.__setitem__(name, func);
383: }
384:
385: /**
386: * Return the list of all accessible methods for a class. This will
387: * only the public methods unless Options.respectJavaAccessibility is
388: * false, in which case all methods are returned.
389: */
390: private static Method[] getAccessibleMethods(Class c) {
391: if (!JavaAccessibility.accessIsMutable())
392: // returns just the public methods
393: return c.getMethods();
394: Method[] declared = c.getDeclaredMethods();
395: for (int i = 0; i < declared.length; i++) {
396: // TBD: this is a permanent change. Should we provide a way to
397: // restore the original accessibility flag?
398: JavaAccessibility.setAccessible(declared[i], true);
399: }
400: return declared;
401: }
402:
403: private boolean ignoreMethod(Method method) {
404: Class[] exceptions = method.getExceptionTypes();
405: for (int j = 0; j < exceptions.length; j++) {
406: if (exceptions[j] == PyIgnoreMethodTag.class) {
407: return true;
408: }
409: }
410: return false;
411: }
412:
413: /* Add all methods declared by this class */
414: private void setMethods(Class c, Method[] methods) {
415: for (int i = 0; i < methods.length; i++) {
416: Method method = methods[i];
417: Class dc = method.getDeclaringClass();
418: if (dc != c)
419: continue;
420: if (isPackagedProtected(dc)
421: && Modifier.isPublic(method.getModifiers())) {
422: /*
423: * Set public methods on package protected classes accessible so
424: * that reflected calls to the method in subclasses of the
425: * package protected class will succeed. Yes, it's convoluted.
426: *
427: * This fails when done through reflection due to Sun JVM bug
428: * 4071957(http://tinyurl.com/le9vo). 4533479 actually describes
429: * the problem we're seeing, but there are a bevy of reflection
430: * bugs that stem from 4071957. Supposedly it'll be fixed in
431: * Dolphin but it's been promised in every version since Tiger
432: * so don't hold your breath.
433: *
434: */
435: try {
436: method.setAccessible(true);
437: } catch (SecurityException se) {
438: }
439: }
440: if (ignoreMethod(method))
441: continue;
442: addMethod(method);
443: }
444: }
445:
446: public static boolean isPackagedProtected(Class c) {
447: int mods = c.getModifiers();
448: return !(Modifier.isPublic(mods) || Modifier.isPrivate(mods) || Modifier
449: .isProtected(mods));
450: }
451:
452: /* Adds a bean property to this class */
453: void addProperty(String name, Class propClass, Method getMethod,
454: Method setMethod) {
455: // This will skip indexed property types
456: if (propClass == null)
457: return;
458:
459: boolean set = true;
460: name = getName(name);
461:
462: PyBeanProperty prop = new PyBeanProperty(name, propClass,
463: getMethod, setMethod);
464:
465: // Check to see if this name is already being used...
466: PyObject o = lookup(name, false);
467:
468: if (o != null) {
469: if (!(o instanceof PyReflectedField))
470: return;
471:
472: if (o instanceof PyBeanProperty) {
473: PyBeanProperty oldProp = (PyBeanProperty) o;
474: if (prop.myType == oldProp.myType) {
475: // If this adds nothing over old property, do nothing
476: if ((prop.getMethod == null || oldProp.getMethod != null)
477: && (prop.setMethod == null || oldProp.setMethod != null)) {
478: set = false;
479: }
480:
481: // Add old get/set methods to current prop
482: // Handles issues with private classes
483: if (oldProp.getMethod != null) {
484: prop.getMethod = oldProp.getMethod;
485: }
486: if (oldProp.setMethod != null) {
487: prop.setMethod = oldProp.setMethod;
488: }
489: }
490: }
491: // This is now handled in setFields which gets called after
492: // setBeanProperties
493: // else {
494: // // Keep static fields around...
495: // PyReflectedField field = (PyReflectedField)o;
496: // if (Modifier.isStatic(field.field.getModifiers())) {
497: // prop.field = field.field;
498: // } else {
499: // // If the field is not static (and thus subsumable)
500: // // don't overwrite
501: // return;
502: // }
503: // }
504: }
505: if (set)
506: __dict__.__setitem__(name, prop);
507: }
508:
509: /* Adds a bean event to this class */
510: void addEvent(String name, Class eventClass, Method addMethod,
511: Method[] meths) {
512: String eventName = eventClass.getName();
513:
514: for (int i = 0; i < meths.length; i++) {
515: PyBeanEventProperty prop;
516: prop = new PyBeanEventProperty(name, eventClass, addMethod,
517: meths[i]);
518: __dict__.__setitem__(prop.__name__, prop);
519: }
520: PyBeanEvent event = new PyBeanEvent(name, eventClass, addMethod);
521: __dict__.__setitem__(event.__name__, event);
522: }
523:
524: /* A reimplementation of java.beans.Introspector.decapitalize.
525: This is needed due to bugs in Netscape Navigator
526: */
527: private static String decapitalize(String s) {
528: //return java.beans.Introspector.decapitalize(s);
529: if (s.length() == 0)
530: return s;
531: char c0 = s.charAt(0);
532: if (Character.isUpperCase(c0)) {
533: if (s.length() > 1 && Character.isUpperCase(s.charAt(1)))
534: return s;
535: char[] cs = s.toCharArray();
536: cs[0] = Character.toLowerCase(c0);
537: return new String(cs);
538: } else {
539: return s;
540: }
541: }
542:
543: // This method is a workaround for Netscape's stupid security bug!
544: private void setBeanInfoCustom(Class c, Method[] meths) {
545: //try {
546: int i;
547: int n = meths.length;
548: for (i = 0; i < n; i++) {
549: Method method = meths[i];
550:
551: if (ignoreMethod(method))
552: continue;
553: if (method.getDeclaringClass() != c
554: || Modifier.isStatic(method.getModifiers())) {
555: continue;
556: }
557:
558: String name = method.getName();
559: Method getter = null;
560: Method setter = null;
561: Class[] args = method.getParameterTypes();
562: Class ret = method.getReturnType();
563: Class myType = null;
564:
565: String pname = "";
566:
567: if (name.startsWith("get")) {
568: if (args.length != 0)
569: continue;
570: getter = method;
571: pname = decapitalize(name.substring(3));
572: myType = ret;
573: } else {
574: if (name.startsWith("is")) {
575: if (args.length != 0 || ret != Boolean.TYPE)
576: continue;
577: getter = method;
578: pname = decapitalize(name.substring(2));
579: myType = ret;
580: } else {
581: if (name.startsWith("set")) {
582: if (args.length != 1)
583: continue;
584: setter = method;
585: pname = decapitalize(name.substring(3));
586: myType = args[0];
587: } else {
588: continue;
589: }
590: }
591: }
592:
593: PyObject o = __dict__.__finditem__(new PyString(pname));
594: PyBeanProperty prop;
595: if (o == null || !(o instanceof PyBeanProperty)) {
596: addProperty(pname, myType, getter, setter);
597: } else {
598: prop = (PyBeanProperty) o;
599: if (prop.myType != myType) {
600: if (getter != null) {
601: addProperty(pname, myType, getter, setter);
602: }
603: } else {
604: if (getter != null)
605: prop.getMethod = getter;
606: if (setter != null
607: && (ret == Void.TYPE || prop.setMethod == null))
608: prop.setMethod = setter;
609:
610: }
611: }
612: }
613:
614: for (i = 0; i < n; i++) {
615: Method method = meths[i];
616:
617: if (method.getDeclaringClass() != c
618: || Modifier.isStatic(method.getModifiers())) {
619: continue;
620: }
621:
622: String mname = method.getName();
623:
624: if (!(mname.startsWith("add") || mname.startsWith("set"))
625: || !mname.endsWith("Listener")) {
626: continue;
627: }
628:
629: Class[] args = method.getParameterTypes();
630: Class ret = method.getReturnType();
631: String pname = "";
632:
633: if (args.length != 1 || ret != Void.TYPE)
634: continue;
635:
636: Class eClass = args[0];
637:
638: // This test and call of getClassLoader() function as a
639: // workaround for a bug in MRJ2.2.4. The bug occured when
640: // this program was compiled with jythonc:
641: // import java
642: // print dir(java.awt.Button)
643: // The 'actionPerformed' attributed would be missing.
644: if (eClass.getInterfaces().length > 0)
645: eClass.getInterfaces()[0].getClassLoader();
646: // And of Mac workaround
647:
648: if (!(java.util.EventListener.class
649: .isAssignableFrom(eClass)))
650: continue;
651:
652: String name = eClass.getName();
653: int idot = name.lastIndexOf('.');
654: if (idot != -1)
655: name = decapitalize(name.substring(idot + 1));
656:
657: addEvent(name, eClass, method, eClass.getMethods());
658: }
659: /*} catch (Throwable t) {
660: System.err.println("Custom Bean error: "+t);
661: t.printStackTrace();
662: }*/
663: }
664:
665: /**
666: * Return the list of all accessible constructors for a class. This
667: * will only the public constructors unless
668: * Options.respectJavaAccessibility is false, in which case all
669: * constructors are returned. Note that constructors are not
670: * inherited like methods or fields.
671: */
672: private static Constructor[] getAccessibleConstructors(Class c) {
673: if (!JavaAccessibility.accessIsMutable())
674: // returns just the public fields
675: return c.getConstructors();
676: // return all constructors
677:
678: Constructor[] declared = c.getDeclaredConstructors();
679: for (int i = 0; i < declared.length; i++) {
680: // TBD: this is a permanent change. Should we provide a way to
681: // restore the original accessibility flag?
682: JavaAccessibility.setAccessible(declared[i], true);
683: }
684: return declared;
685: }
686:
687: private boolean ignoreConstructor(Constructor method) {
688: Class[] exceptions = method.getExceptionTypes();
689: for (int j = 0; j < exceptions.length; j++) {
690: if (exceptions[j] == PyIgnoreMethodTag.class) {
691: return true;
692: }
693: }
694: return false;
695: }
696:
697: private void setConstructors(Class c) {
698: if (Modifier.isInterface(c.getModifiers())) {
699: __init__ = null;
700: } else {
701: Constructor[] constructors = getAccessibleConstructors(c);
702: for (int i = 0; i < constructors.length; i++) {
703: if (ignoreConstructor(constructors[i])) {
704: continue;
705: }
706: if (__init__ == null) {
707: __init__ = new PyReflectedConstructor(
708: constructors[i]);
709: } else {
710: __init__.addConstructor(constructors[i]);
711: }
712: }
713: if (__init__ != null) {
714: __dict__.__setitem__("__init__", __init__);
715: }
716: }
717: }
718:
719: private boolean constructorsInitialized = false;
720:
721: synchronized void initConstructors() {
722: if (constructorsInitialized)
723: return;
724: initialize();
725: setConstructors(proxyClass);
726: constructorsInitialized = true;
727: }
728:
729: /*
730: If the new name conflicts with a Python keyword, add an '_'
731: */
732: private static java.util.Hashtable keywords = null;
733:
734: private static String unmangleKeyword(String name) {
735: if (keywords == null) {
736: keywords = new java.util.Hashtable();
737: String[] words = new String[] { "or", "and", "not", "is",
738: "in", "lambda", "if", "else", "elif", "while",
739: "for", "try", "except", "def", "class", "finally",
740: "print", "pass", "break", "continue", "return",
741: "import", "from", "del", "raise", "global", "exec",
742: "assert" };
743: for (int i = 0; i < words.length; i++) {
744: keywords.put(words[i] + "_", words[i].intern());
745: }
746: }
747: return (String) keywords.get(name);
748: }
749:
750: PyObject[] lookupGivingClass(String name, boolean stop_at_java) {
751: if (stop_at_java)
752: return new PyObject[] { null, null };
753: if (!initialized)
754: initialize();
755: if (name == "__init__") {
756: initConstructors();
757: return new PyObject[] { __init__, null };
758: }
759:
760: // For backwards compatibilty, support keyword_ as a substitute for
761: // keyword. An improved parser makes this no longer necessary.
762: if (Options.deprecatedKeywordMangling && name.endsWith("_")) {
763: String newName = unmangleKeyword(name);
764: if (newName != null)
765: name = newName;
766: }
767: return super .lookupGivingClass(name, stop_at_java);
768: }
769:
770: public PyObject __dir__() {
771: initialize();
772: if (__dict__ instanceof PyStringMap) {
773: return ((PyStringMap) __dict__).keys();
774: } else {
775: return __dict__.invoke("keys");
776: }
777: }
778:
779: private PyStringMap missingAttributes = null;
780:
781: public PyObject __findattr__(String name) {
782: if (name == "__dict__") {
783: if (__dict__ == null)
784: initialize();
785: return __dict__;
786: }
787: if (name == "__name__")
788: return new PyString(__name__);
789: if (name == "__bases__") {
790: if (__bases__ == null)
791: initialize();
792: return __bases__;
793: }
794: if (name == "__init__") {
795: initConstructors();
796: if (__init__ == null)
797: return super .lookupGivingClass(name, false)[0];
798: return __init__;
799: }
800:
801: PyObject result = lookup(name, false);
802: if (result != null)
803: return result.__get__(null, null); // xxx messy
804:
805: // A cache of missing attributes to short-circuit later tests
806: if (missingAttributes != null
807: && missingAttributes.__finditem__(name) != null) {
808: return null;
809: }
810:
811: // These two tests can be expensive, see above for short-circuiting
812: result = findClassAttr(name);
813: if (result != null)
814: return result;
815:
816: result = findInnerClass(name);
817: if (result != null)
818: return result;
819:
820: // Add this attribute to missing attributes cache
821: if (missingAttributes == null) {
822: missingAttributes = new PyStringMap();
823: }
824: missingAttributes.__setitem__(name, this );
825: return null;
826: }
827:
828: private PyJavaInstance classInstance;
829:
830: private PyObject findClassAttr(String name) {
831: if (classInstance == null) {
832: classInstance = new PyJavaInstance(proxyClass);
833: }
834: PyObject result = classInstance.__findattr__(name);
835: return result;
836: //if (result == null) return null;
837: //__dict__.__setitem__(name, result);
838: //return result;
839: }
840:
841: private PyObject findInnerClass(String name) {
842: Class p = getProxyClass();
843: Class innerClass = Py.relFindClass(p, p.getName() + "$" + name);
844: if (innerClass == null)
845: return null;
846:
847: PyObject jinner = Py.java2py(innerClass); // xxx lookup(innerClass);
848: __dict__.__setitem__(name, jinner);
849: return jinner;
850: }
851:
852: public void __setattr__(String name, PyObject value) {
853: PyObject field = lookup(name, false);
854: if (field != null) {
855: if (field.jtryset(null, value))
856: return;
857: }
858: __dict__.__setitem__(name, value);
859: }
860:
861: public void __delattr__(String name) {
862: PyObject field = lookup(name, false);
863: if (field == null) {
864: throw Py.NameError("attribute not found: " + name);
865: }
866:
867: if (!field.jdontdel()) {
868: __dict__.__delitem__(name);
869: }
870: }
871:
872: public PyObject __call__(PyObject[] args, String[] keywords) {
873: if (!constructorsInitialized)
874: initConstructors();
875:
876: // xxx instantiation of PyObject subclass, still needed?
877: if (PyObject.class.isAssignableFrom(proxyClass)) {
878: if (Modifier.isAbstract(proxyClass.getModifiers())) {
879: throw Py.TypeError("can't instantiate abstract class ("
880: + __name__ + ")");
881: }
882: if (__init__ == null) {
883: throw Py.TypeError("no public constructors for "
884: + __name__);
885: }
886: return __init__.make(args, keywords);
887: }
888:
889: PyInstance inst = new PyJavaInstance(this );
890: inst.__init__(args, keywords);
891:
892: /*if (proxyClass != null &&
893: PyObject.class.isAssignableFrom(proxyClass)) {
894: // It would be better if we didn't have to create a PyInstance
895: // in the first place.
896: ((PyObject)inst.javaProxy).__class__ = this;
897: return (PyObject)inst.javaProxy;
898: }*/
899:
900: return inst;
901: }
902:
903: public Object __tojava__(Class c) {
904: initialize();
905: return super .__tojava__(c);
906: }
907:
908: public String toString() {
909: return "<jclass " + __name__ + " " + Py.idstr(this ) + ">";
910: }
911: }
|