// Copyright (c) Corporation for National Research Initiatives package org.python.core; import java.lang.reflect.*; import java.beans.*; /** * A wrapper around a java class. */ public class PyJavaClass extends PyClass { public PyReflectedConstructor __init__; public PackageManager __mgr__; private static InternalTables tbl; public synchronized final static InternalTables getInternalTables() { if(tbl == null) tbl = InternalTables.createInternalTables(); return tbl; } public final boolean isLazy() { return proxyClass == null; } public static final PyJavaClass lookup(String name,PackageManager mgr) { if (tbl.queryCanonical(name)) { return lookup(mgr.findClass(null,name,"forced java class")); } PyJavaClass ret = new PyJavaClass(name, mgr); tbl.putLazyCanonical(name, ret); return ret; } public synchronized static final PyJavaClass lookup(Class c) { if (tbl == null) { tbl = InternalTables.createInternalTables(); PyJavaClass jc = new PyJavaClass(true); jc.init(PyJavaClass.class); tbl.putCanonical(PyJavaClass.class,jc); } PyJavaClass ret = tbl.getCanonical(c); if (ret != null) return ret; PyJavaClass lazy = tbl.getLazyCanonical(c.getName()); if (lazy != null) { initLazy(lazy); if (lazy.proxyClass == c) return lazy; } Class parent = c.getDeclaringClass(); if (parent == null) ret = new PyJavaClass(c); else ret = new PyJavaInnerClass(c, lookup(parent)); tbl.putCanonical(c,ret); return ret; } public static PyClass __class__; private PyJavaClass(boolean fakeArg) { super(true); } protected PyJavaClass(Class c) { super(__class__); init(c); } protected PyJavaClass(String name,PackageManager mgr) { super(__class__); __name__ = name; this.__mgr__ = mgr; } protected void findModule(PyObject dict) {} protected Class getProxyClass() { initialize(); return proxyClass; } private static final void initLazy(PyJavaClass jc) { jc.init(jc.__mgr__.findClass(null,jc.__name__,"lazy java class")); tbl.putCanonical(jc.proxyClass,jc); jc.__mgr__ = null; } private boolean initialized=false; // Prevent recursive calls to initialize() private boolean initializing=false; private synchronized void initialize() { if (initialized || initializing) return; initializing = true; synchronized(PyJavaClass.class) { if (proxyClass == null) { initLazy(this); } } init__bases__(proxyClass); init__dict__(); if (ClassDictInit.class.isAssignableFrom(proxyClass) && proxyClass != ClassDictInit.class) { try { Method m = proxyClass.getMethod("classDictInit", new Class[] { PyObject.class }); m.invoke(null, new Object[] { __dict__ }); } catch (Exception exc) { // System.err.println("Got exception: " + exc + " " + // proxyClass); throw Py.JavaError(exc); } } if (InitModule.class.isAssignableFrom(proxyClass)) { try { InitModule m = (InitModule)proxyClass.newInstance(); m.initModule(__dict__); } catch (Exception exc) { // System.err.println("Got exception: " + exc); throw Py.JavaError(exc); } } initialized = true; initializing = false; } private synchronized void init__dict__() { if (__dict__ != null) return; PyStringMap d = new PyStringMap(); // d.__setitem__("__module__", Py.None); __dict__ = d; try { Method[] methods = getAccessibleMethods(proxyClass); setBeanInfoCustom(proxyClass, methods); setFields(proxyClass); setMethods(proxyClass, methods); } catch (SecurityException se) {} } private synchronized void init__class__(Class c) { if (!PyObject.class.isAssignableFrom(c)) return; try { Field field = c.getField("__class__"); if (Modifier.isStatic(field.getModifiers()) && field.getType().isAssignableFrom(PyJavaClass.class) && field.getDeclaringClass() == c) { field.set(null, this); } } catch (NoSuchFieldException exc) {} catch (IllegalAccessException exc1) {} } private synchronized void init__bases__(Class c) { if (__bases__ != null) return; Class interfaces[] = getAccessibleInterfaces(c); int nInterfaces = interfaces.length; int nBases = 0; int i; for (i=0; i 7) continue; PyObject prop = lookup(name, false); if (prop != null && prop instanceof PyBeanProperty) { PyBeanProperty beanProp = ((PyBeanProperty)prop).copy(); beanProp.field = field; __dict__.__setitem__(name, beanProp); continue; } } __dict__.__setitem__(name, new PyReflectedField(field)); } } /* Produce a good Python name for a Java method. If the Java method ends in '$', strip it (this handles reserved Java keywords) Don't make any changes to keywords since this is now handled by parser */ private String getName(String name) { if (name.endsWith("$")) name = name.substring(0, name.length()-1); return name.intern(); } private void addMethod(Method meth) { String name = getName(meth.getName()); if (name == "_getPyInstance" || name == "_setPyInstance" || name == "_getPySystemState" || name == "_setPySystemState") { return; } // Special case to handle a few troublesome methods in java.awt.*. // These methods are all deprecated and interfere too badly with // bean properties to be tolerated. This is totally a hack, but a // lot of code that uses java.awt will break without it. String classname = proxyClass.getName(); if (classname.startsWith("java.awt.") && classname.indexOf('.', 9) == -1) { if (name == "layout" || name == "insets" || name == "size" || name == "minimumSize" || name == "preferredSize" || name == "maximumSize" || name == "bounds" || name == "enable") { return; } } // See if any of my superclasses are using 'name' for something // else. Or if I'm already using it myself PyObject o = lookup(name, false); // If it's being used as a function, then things get more // interesting... PyReflectedFunction func; if (o != null && o instanceof PyReflectedFunction) { func = (PyReflectedFunction)o; PyObject o1 = __dict__.__finditem__(name); /* If this function already exists, add this method to the signature. If this alters the signature of the function in some significant way, then return a duplicate and stick it in the __dict__ */ if (o1 != o) { if (func.handles(meth)) return; func = func.copy(); } func.addMethod(meth); } else { func = new PyReflectedFunction(meth); try { Field docField = proxyClass.getField("__doc__" + name); int mods = docField.getModifiers(); if (docField.getType() == PyString.class && Modifier.isPublic(mods) && Modifier.isStatic(mods)); func.__doc__ = (PyString) docField.get(null); } catch (NoSuchFieldException ex) { } catch (SecurityException ex) { } catch (IllegalAccessException ex) {} } __dict__.__setitem__(name, func); } /** * Return the list of all accessible methods for a class. This will * only the public methods unless Options.respectJavaAccessibility is * false, in which case all methods are returned. */ private static Method[] getAccessibleMethods(Class c) { if (!JavaAccessibility.accessIsMutable()) // returns just the public methods return c.getMethods(); Method[] declared = c.getDeclaredMethods(); for (int i=0; i < declared.length; i++) { // TBD: this is a permanent change. Should we provide a way to // restore the original accessibility flag? JavaAccessibility.setAccessible(declared[i], true); } return declared; } private boolean ignoreMethod(Method method) { Class[] exceptions = method.getExceptionTypes(); for (int j = 0; j < exceptions.length; j++) { if (exceptions[j] == PyIgnoreMethodTag.class) { return true; } } return false; } /* Add all methods declared by this class */ private void setMethods(Class c, Method[] methods) { for (int i=0; i 1 && Character.isUpperCase(s.charAt(1))) return s; char[] cs = s.toCharArray(); cs[0] = Character.toLowerCase(c0); return new String(cs); } else { return s; } } // This method is a workaround for Netscape's stupid security bug! private void setBeanInfoCustom(Class c, Method[] meths) { //try { int i; int n = meths.length; for (i=0; i 0) eClass.getInterfaces()[0].getClassLoader(); // And of Mac workaround if (!(java.util.EventListener.class.isAssignableFrom(eClass))) continue; String name = eClass.getName(); int idot = name.lastIndexOf('.'); if (idot != -1) name = decapitalize(name.substring(idot+1)); addEvent(name, eClass, method, eClass.getMethods()); } /*} catch (Throwable t) { System.err.println("Custom Bean error: "+t); t.printStackTrace(); }*/ } /** * Return the list of all accessible constructors for a class. This * will only the public constructors unless * Options.respectJavaAccessibility is false, in which case all * constructors are returned. Note that constructors are not * inherited like methods or fields. */ private static Constructor[] getAccessibleConstructors(Class c) { if (!JavaAccessibility.accessIsMutable()) // returns just the public fields return c.getConstructors(); // return all constructors Constructor[] declared = c.getDeclaredConstructors(); for (int i=0; i < declared.length; i++) { // TBD: this is a permanent change. Should we provide a way to // restore the original accessibility flag? JavaAccessibility.setAccessible(declared[i], true); } return declared; } private boolean ignoreConstructor(Constructor method) { Class[] exceptions = method.getExceptionTypes(); for (int j = 0; j < exceptions.length; j++) { if (exceptions[j] == PyIgnoreMethodTag.class) { return true; } } return false; } private void setConstructors(Class c) { if (Modifier.isInterface(c.getModifiers())) { __init__ = null; } else { Constructor[] constructors = getAccessibleConstructors(c); for (int i = 0; i < constructors.length; i++) { if (ignoreConstructor(constructors[i])) { continue; } if (__init__ == null) { __init__ = new PyReflectedConstructor(constructors[i]); } else { __init__.addConstructor(constructors[i]); } } if (__init__ != null) { __dict__.__setitem__("__init__", __init__); } } } private boolean constructorsInitialized=false; synchronized void initConstructors() { if (constructorsInitialized) return; initialize(); setConstructors(proxyClass); constructorsInitialized = true; } /* If the new name conflicts with a Python keyword, add an '_' */ private static java.util.Hashtable keywords=null; private static String unmangleKeyword(String name) { if (keywords == null) { keywords = new java.util.Hashtable(); String[] words = new String[] {"or", "and", "not", "is", "in", "lambda", "if", "else", "elif", "while", "for", "try", "except", "def", "class", "finally", "print", "pass", "break", "continue", "return", "import", "from", "del", "raise", "global", "exec", "assert"}; for (int i=0; i"; } }