1 #!/usr/bin/env python 2 3 """ 4 Wrap Java packages, converting the skeleton Java classes to Python modules which 5 connect to concrete Python implementation classes. 6 7 Copyright (C) 2004, 2005, 2006, 2011 Paul Boddie <paul@boddie.org.uk> 8 9 This program is free software; you can redistribute it and/or modify it under 10 the terms of the GNU Lesser General Public License as published by the Free 11 Software Foundation; either version 3 of the License, or (at your option) any 12 later version. 13 14 This program is distributed in the hope that it will be useful, but WITHOUT 15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 16 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 17 details. 18 19 You should have received a copy of the GNU Lesser General Public License along 20 with this program. If not, see <http://www.gnu.org/licenses/>. 21 """ 22 23 import javaclass.classfile 24 import glob 25 import sys 26 import os 27 28 if __name__ == "__main__": 29 if len(sys.argv) < 2: 30 print "wrap.py <package directory> <wrapped package>" 31 print "For example:" 32 print "wrap.py qtjava qt" 33 sys.exit(1) 34 35 # Process all directories in the list, producing for each a Python source 36 # file containing the classes found in the given directory. 37 38 directory, package = sys.argv[1:3] 39 f = open(os.path.join(directory, "__init__.py"), "w") 40 f.write("import %s\n" % package) 41 f.write("import java.lang\n") 42 43 # Process each class file. 44 45 for filename in glob.glob(os.path.join(directory, "*.class")): 46 print "Processing", filename 47 cf = open(filename, "rb") 48 c = javaclass.classfile.ClassFile(cf.read()) 49 cf.close() 50 51 # Write the class into the source file. 52 53 full_name = c.this_class.get_python_name() 54 class_name = full_name.split(".")[-1] 55 f.write("class %s(%s.%s, java.lang.Object):\n" % (class_name, package, class_name)) 56 57 # Process methods in the class, writing wrapper code. 58 59 method_names = [] 60 for method in c.methods: 61 wrapped_method_name = method.get_unqualified_python_name() 62 63 # Find out more about the parameters, introducing special 64 # conversions where appropriate. 65 66 parameter_names = ["self"] 67 parameter_index = 1 68 conversions = [] 69 70 for parameter in method.get_descriptor()[0]: 71 parameter_name = "p" + str(parameter_index) 72 base_type, object_type, array_type = parameter 73 74 # Special cases. 75 76 if object_type == "java/lang/String": 77 conversions.append("%s = unicode(%s)" % (parameter_name, parameter_name)) 78 # elif object_type == "java/util/Map": 79 # NOTE: Using special private interface. 80 # conversions.append("%s = %s.as_dict()" % (parameter_name, parameter_name)) 81 82 parameter_names.append(parameter_name) 83 parameter_index += 1 84 85 # Write the signature. 86 87 f.write(" def %s(%s):\n" % (wrapped_method_name, ", ".join(parameter_names))) 88 89 # Write any conversions. 90 91 for conversion in conversions: 92 f.write(" %s\n" % conversion) 93 94 # Write the call to the wrapped method. 95 96 f.write(" return %s.%s.%s(%s)\n" % (package, class_name, wrapped_method_name, ", ".join(parameter_names))) 97 98 # Record the correspondence between the Java-accessible and wrapped 99 # method names. 100 101 method_name = method.get_python_name() 102 method_names.append((method_name, wrapped_method_name)) 103 104 # Produce method entries for the specially named methods. 105 106 for method_name, wrapped_method_name in method_names: 107 f.write("setattr(%s, '%s', %s.%s)\n" % (class_name, method_name, class_name, wrapped_method_name)) 108 109 # Remove the original class. 110 111 print "Removing", filename 112 os.remove(filename) 113 114 f.close() 115 116 # vim: tabstop=4 expandtab shiftwidth=4