# Copyright (c) Corporation for National Research Initiatives from types import TupleType, IntType import jast from java.lang.reflect.Modifier import * from java.lang.reflect import Modifier from java.lang import * import org, java def aget(dict, key, default): if dict.has_key(key): return dict[key] else: ret = {} dict[key] = ret return ret #Utility functions for converting between java and python types def typeName(cls): if Class.isArray(cls): return typeName(Class.getComponentType(cls))+"[]" else: if '$' in cls.__name__: outer = cls.getDeclaringClass() if outer: l = len(outer.__name__) return "%s.%s" % (typeName(outer), cls.__name__[l+1:]) return cls.__name__ def nullReturn(ret): if ret == Void.TYPE: return jast.Return() if Class.isPrimitive(ret): if ret.__name__ == 'boolean': value = jast.False elif ret.__name__ == 'char': value = jast.CharacterConstant('x') else: value = jast.IntegerConstant(0) else: value = jast.Null return jast.Return(value) def makeReturn(code, ret): if ret == Void.TYPE: return code if Class.isPrimitive(ret): r = jast.InvokeStatic("Py", "py2"+ret.__name__, [code]) else: typname = typeName(ret) r = jast.InvokeStatic("Py", "tojava", [code, jast.GetStaticAttribute(typname,'class')]) r = jast.Cast(typname, r) return jast.Return(r) def makeObject(code, c): if c in [Integer.TYPE, Byte.TYPE, Short.TYPE, Long.TYPE]: mname = "newInteger" elif c in [Character.TYPE]: mname = "newString" elif c in [Float.TYPE, Double.TYPE]: mname = "newFloat" elif c in [Boolean.TYPE]: mname = "newBoolean" else: return code return jast.InvokeStatic("Py", mname, [code]) def filterThrows(throws): ret = [] for throwc in throws: #might want to remove subclasses of Error and RuntimeException here ret.append(throwc.__name__) return ret def wrapThrows(stmt, throws, retType): if len(throws) == 0: return stmt catches = [] throwableFound = 0 for i in range(len(throws)): throw = throws[i] exctype = throw excname = jast.Identifier("exc%d" % i) body = jast.Block([jast.Throw(excname)]) catches.append( (exctype, excname, body) ) if throw == "java.lang.Throwable": throwableFound = 1 if not throwableFound: body = jast.Block([jast.Invoke(jast.Identifier("inst"), "_jthrow", [jast.Identifier("t")]), nullReturn(retType)]) catches.append( ("java.lang.Throwable", jast.Identifier("t"), body) ) return jast.TryCatches(jast.Block([stmt]), catches) class JavaProxy: def __init__(self, name, supername, bases, methods, module=None, issuperproxy = 1): self.bases = bases self.name = name self.supername, self.pySupername = supername self.methods = methods self.issuperproxy = 0 #issuperproxy self.packages = self.properties = jast.Null self.modname = "foo" self.modifier = "public" self.initsigs = None self.package = None self.module = module if module is not None: self.packages = module.getPackages(qual=1) self.properties = module.getProxyProperties(qual=1) self.modname = module.name if module.package is not None: self.modname = module.package+'.'+self.modname self.modules = module.modules.keys() self.isAdapter = 0 self.frozen = 1 self.superclass = Object self.interfaces = [] self.jmethods = {} self.jabstract = {} self.supermethods = {} for base in bases: self.addMethods(base) if base.isInterface(): self.interfaces.append(base) else: self.superclass = base self.cleanMethods() if self.supername is None: self.supername = self.superclass.__name__ self.jconstructors = [] self.addConstructors(self.superclass) self.innerClasses = [] # gather info about methods, and methods requiring a super__foo counterpart self.superproxy = self self.myCandSupermethods = [] self.candSupermethods = None self.methodsMemo = [] self.prepMethods() def __repr__(self): return "" % (self.modname,self.name) def getSuperproxy(self): if self.superproxy is not self: return self.superproxy supername = self.pySupername if supername is None: return None modules = self.module.modules parts = supername.split('.') modname = '.'.join(parts[0:-1]) dmodname = parts[-2] supername = parts[-1] superproxy = None if modules.has_key(modname): mod = modules[modname] if dmodname == supername: superproxy = getattr(mod,'javaproxy',None) else: for px in getattr(mod,'innerClasses',[]): if isinstance(px,JavaProxy) and px.name == supername: superproxy = px break self.superproxy = superproxy return superproxy def getCandSupermethods(self,incl): if incl and self.candSupermethods is not None: return self.candSupermethods px = self.getSuperproxy() if px is not None: cands = px.getCandSupermethods(incl = 1)[:] else: cands = [] if incl: cands.extend(self.myCandSupermethods) self.candSupermethods = cands return cands def dumpAll(self): self.statements = [] self.dumpInnerClasses() self.dumpMethods() self.dumpConstructors() self.addPyProxyInterface() self.addClassDictInit() return self.statements def dumpInnerClasses(self): for ic in self.innerClasses: self.statements.append(ic) def prepMethods(self): names = self.jmethods.keys() names.sort() #print 'preparing adding methods', self.name, names pymethods = {} for name, args, sigs in self.methods: pymethods[name] = 1 #print name, args, sig if sigs is not None: if name == "__init__": self.initsigs = sigs continue #print sigs for access, ret, sig, throws in sigs: dosuper = 0 if self.jmethods.has_key(name): x = filter(lambda c: isinstance(c, TupleType), sig) x = tuple(map(lambda c: c[0], x)) if self.jmethods[name].has_key(x): del self.jmethods[name][x] if not self.jabstract[name][x]: dosuper = 1 self.myCandSupermethods.append(name) self.methodsMemo.append(('n',name, access, ret, sig, throws, dosuper)) for name in names: for sig, (access, ret, throws) in self.jmethods[name].items(): #print name, access, isProtected(access), isFinal(access) if isProtected(access): supername = name if isFinal(access): access = access & ~FINAL access = access & ~PROTECTED | PUBLIC self.methodsMemo.append(('s',name, "super__" + name, access, ret, sig, throws)) continue elif isFinal(access): continue if self.jabstract[name][sig]: #isAbstract(access): access = access & ~PROTECTED | PUBLIC self.methodsMemo.append(('n',name, access, ret, sig, throws, 0)) elif pymethods.has_key(name): access = access & ~PROTECTED | PUBLIC self.methodsMemo.append(('n',name, access, ret, sig, throws, 1)) self.myCandSupermethods.append(name) elif isProtected(access): access = access & ~PROTECTED | PUBLIC self.methodsMemo.append(('s',name, name, access, ret, sig, throws)) def dumpMethods(self): # use info gathered by prepMethods dispatch = { 's': self.callSuperMethod, 'n': self.callMethod } for m in self.methodsMemo: apply(dispatch[m[0]],m[1:]) def dumpConstructors(self): if self.initsigs is not None: #print self.initsigs for access, ret, sig, throws in self.initsigs: self.callConstructor(access, sig, throws, 0) else: for access, sig, throws in self.jconstructors: self.callConstructor(access, sig, throws, 1) def cleanMethods(self): for name, value in self.jmethods.items(): if len(value) == 0: del self.jmethods[name] del self.jabstract[name] def addMethods(self, c): #print 'adding', c.__name__, c.getDeclaredMethods() for method in c.getDeclaredMethods(): #Check that it's not already included name = method.name sig = tuple(method.parameterTypes) ret = method.returnType mdict = aget(self.jmethods, name, {}) absdict = aget(self.jabstract, name, {}) access = method.modifiers if mdict.has_key(sig): if not isAbstract(access): absdict[sig] = 0 continue if isPrivate(access) or isStatic(access): continue if isNative(access): access = access & ~NATIVE if isProtected(access): #access = access & ~PROTECTED | PUBLIC if isFinal(access): pass #addSuperMethod(method, access) #elif isFinal(access): # continue throws = method.exceptionTypes mdict[sig] = access, ret, throws absdict[sig] = isAbstract(access) sc = c.getSuperclass() if sc is not None: self.addMethods(sc) for interface in c.getInterfaces(): self.addMethods(interface) def addConstructors(self, c): for constructor in c.getDeclaredConstructors(): access = constructor.modifiers if isPrivate(access): continue if isNative(access): access = access & ~NATIVE if isProtected(access): access = access & ~PROTECTED | PUBLIC parameters = tuple(constructor.parameterTypes) throws = constructor.exceptionTypes self.jconstructors.append( (access, parameters, throws) ) def callSuperMethod(self, name, supername, access, ret, sig, throws=[]): if self.issuperproxy: return self.supermethods[supername] = supername args = [typeName(ret)] argids = [] throws = filterThrows(throws) for c in sig: if isinstance(c, TupleType): argname = c[1] c = c[0] else: argname = "arg"+str(len(argids)) args.append( (typeName(c), argname) ) argid = jast.Identifier(argname) argids.append(argid) supercall = jast.Invoke(jast.Identifier("super"), name, argids) if ret != Void.TYPE: supercall = jast.Return(supercall) supermethod = jast.Method(supername, jast.Modifier.ModifierString(access), args, jast.Block([supercall]), throws) self.statements.append(supermethod) return def callMethod(self, name, access, ret, sig, throws=[], dosuper=1): args = [typeName(ret)] argids = [] objects = [] throws = filterThrows(throws) for c in sig: if isinstance(c, TupleType): argname = c[1] c = c[0] else: argname = "arg"+str(len(argids)) args.append( (typeName(c), argname) ) argid = jast.Identifier(argname) argids.append(argid) objects.append(makeObject(argid, c)) objects = jast.FilledArray("Object", objects) stmts = [] this = jast.Identifier("this") if isinstance(access, IntType) and isAbstract(access): dosuper = 0 access = access & ~ABSTRACT if not dosuper and not self.isAdapter: getattr = jast.InvokeStatic("Py", "jgetattr", [this, jast.StringConstant(name)]) else: getattr = jast.InvokeStatic("Py", "jfindattr", [this, jast.StringConstant(name)]) inst = jast.Identifier("inst") if len(throws) == 0: jcall = "_jcall" else: jcall = "_jcallexc" jcall = makeReturn(jast.Invoke(inst, jcall, [objects]), ret) jcall = wrapThrows(jcall, throws, ret) if dosuper: supercall = jast.Invoke(jast.Identifier("super"), name, argids) if ret != Void.TYPE: supercall = jast.Return(supercall) supermethod = None if not self.issuperproxy and name not in self.getCandSupermethods(incl=0): supermethod = jast.Method("super__"+name, jast.Modifier.ModifierString(access), args, jast.Block([supercall]), throws) self.supermethods["super__"+name] = "super__"+name else: if self.isAdapter: supercall = nullReturn(ret) else: supercall = None supermethod = None if not dosuper and not self.isAdapter: test = jcall else: test = jast.If(jast.Operation("!=", inst, jast.Null), jcall, supercall) code = jast.Block([jast.Declare("PyObject", inst, getattr), test]) meth = jast.Method(name, jast.Modifier.ModifierString(access), args, code, throws) if supermethod is not None: self.statements.append(supermethod) self.statements.append(meth) def callConstructor(self, access, sig, throws=[], dosuper=1): args = [] argids = [] objects = [] throws = filterThrows(throws) for c in sig: if isinstance(c, TupleType): argname = c[1] c = c[0] else: argname = "arg"+str(len(argids)) args.append( (typeName(c), argname) ) argid = jast.Identifier(argname) argids.append(argid) objects.append(makeObject(argid, c)) objects = jast.FilledArray("Object", objects) stmts = [] this = jast.Identifier("this") if dosuper: supercall = jast.InvokeLocal("super", argids) else: supercall = jast.InvokeLocal("super", []) ## for saccess, ssig in self.jconstructors: ## if len(ssig) == len(sig): ## supercall = jast.InvokeLocal("super", argids) ## break ## else: ## supercall = jast.InvokeLocal("super", []) frozen = self.module.getFrozen() initargs = [objects] initproxy = jast.InvokeLocal("__initProxy__", initargs) code = jast.Block([supercall, initproxy]) self.statements.append(jast.Constructor( self.name, jast.Modifier.ModifierString(access), args, code, throws)) def addPyProxyInterface(self): self.statements.append(jast.Declare('private PyInstance', jast.Identifier('__proxy'))) code = jast.Set(jast.Identifier("__proxy"), jast.Identifier("inst")) code = jast.Block( [code] ) self.statements.append(jast.Method("_setPyInstance", "public", ["void", ("PyInstance", "inst")], code)) code = jast.Block([jast.Return(jast.Identifier("__proxy"))]) self.statements.append(jast.Method("_getPyInstance", "public", ["PyInstance"], code)) self.statements.append(jast.Declare('private PySystemState', jast.Identifier('__sysstate'))) code = jast.Set(jast.Identifier("__sysstate"), jast.Identifier("inst")) code = jast.Block( [code] ) self.statements.append(jast.Method("_setPySystemState", "public", ["void", ("PySystemState", "inst")], code)) code = jast.Block([jast.Return(jast.Identifier("__sysstate"))]) self.statements.append(jast.Method("_getPySystemState", "public", ["PySystemState"], code)) frozen = self.module.getFrozen() this = jast.Identifier("this") initargs = [this, jast.StringConstant(self.modname), jast.StringConstant(self.name), jast.Identifier("args"), self.packages, self.properties, frozen, jast.StringArray(self.modules)] initproxy = jast.InvokeStatic("Py", "initProxy", initargs) code = jast.Block([initproxy]) self.statements.append(jast.Method("__initProxy__", "public", ["void", ("Object[]", "args")], code)) self.interfaces.append(org.python.core.PyProxy) def addClassDictInit(self): self.interfaces.append(org.python.core.ClassDictInit) namelist = jast.InvokeStatic("Py", "java2py", [ jast.StringArray(self.supermethods.keys()) ]); code = jast.Invoke(jast.Identifier("dict"), "__setitem__", [ jast.StringConstant("__supernames__"), namelist]); code = jast.Block([code]) self.statements.append(jast.Method("classDictInit", "static public", ["void", ("PyObject", "dict")], code)) def makeClass(self): mycode = self.dumpAll() body = jast.Block(mycode) return jast.Class(self.name, self.modifier, self.supername, map(lambda i: i.__name__, self.interfaces), body) def getDescription(self): COMMASPACE = ', ' ret = self.name+' extends '+self.supername if len(self.interfaces) > 0: ret = ret + ' implements ' + \ COMMASPACE.join(map(lambda i: i.__name__, self.interfaces)) return ret if __name__ == '__main__': import java methods = [("init", None, None), ("enable", None, ("public", Void.TYPE, [(java.awt.Event, 'event')] )) ] jp = JavaProxy("Foo", [java.util.Random], methods) #applet.Applet], methods) print jast.Block(jp.dumpAll())