2.1 --- a/javaclass/bytecode.py Sun Feb 13 01:33:26 2005 +0100
2.2 +++ b/javaclass/bytecode.py Sun Feb 13 01:35:44 2005 +0100
2.3 @@ -2041,13 +2041,13 @@
2.4 translator.process(method, writer)
2.5 return translator, writer
2.6
2.7 - def make_method(self, real_method_name, methods, global_names, namespace):
2.8 + def make_method(self, real_method_name, methods, global_names):
2.9
2.10 """
2.11 Make a dispatcher method with the given 'real_method_name', providing
2.12 dispatch to the supplied type-sensitive 'methods', accessing the given
2.13 'global_names' where necessary, and storing the new method in the
2.14 - 'namespace' provided.
2.15 + class's namespace.
2.16 """
2.17
2.18 if real_method_name == "<init>":
2.19 @@ -2059,7 +2059,7 @@
2.20
2.21 if len(methods) == 1:
2.22 method, fn = methods[0]
2.23 - namespace[method_name] = fn
2.24 + self.namespace[method_name] = fn
2.25 return
2.26
2.27 # Write a simple bytecode dispatching mechanism.
2.28 @@ -2224,28 +2224,27 @@
2.29 if method_is_static:
2.30 fn = staticmethod(fn)
2.31
2.32 - namespace[method_name] = fn
2.33 + self.namespace[method_name] = fn
2.34
2.35 def process(self, global_names):
2.36
2.37 """
2.38 Process the class, storing it in the 'global_names' dictionary provided.
2.39 - Return a tuple containing the class and a list of external names
2.40 - referenced by the class's methods.
2.41 + Return a list of external names referenced by the class's methods.
2.42 """
2.43
2.44 - namespace = {}
2.45 + self.namespace = {}
2.46
2.47 # Make the fields.
2.48
2.49 for field in self.class_file.fields:
2.50 if classfile.has_flags(field.access_flags, [classfile.STATIC]):
2.51 field_name = str(field.get_python_name())
2.52 - namespace[field_name] = None
2.53 + self.namespace[field_name] = None
2.54
2.55 # Make the methods.
2.56
2.57 - real_methods = {}
2.58 + self.real_methods = {}
2.59 external_names = []
2.60
2.61 for method in self.class_file.methods:
2.62 @@ -2287,13 +2286,27 @@
2.63
2.64 # Remember the real method name and the corresponding methods produced.
2.65
2.66 - if not real_methods.has_key(real_method_name):
2.67 - real_methods[real_method_name] = []
2.68 - real_methods[real_method_name].append((method, fn))
2.69 + if not self.real_methods.has_key(real_method_name):
2.70 + self.real_methods[real_method_name] = []
2.71 + self.real_methods[real_method_name].append((method, fn))
2.72
2.73 # Add the method to the class's namespace.
2.74
2.75 - namespace[method_name] = fn
2.76 + self.namespace[method_name] = fn
2.77 +
2.78 + # Add the super class as an external name, if appropriate.
2.79 +
2.80 + if self.class_file.super_class is not None:
2.81 + external_names.append(self.class_file.super_class.get_python_name())
2.82 +
2.83 + return external_names
2.84 +
2.85 + def get_class(self, global_names):
2.86 +
2.87 + """
2.88 + Get the Python class representing the underlying Java class, using the
2.89 + given 'global_names' to define dispatcher methods.
2.90 + """
2.91
2.92 # Define superclasses.
2.93
2.94 @@ -2301,18 +2314,18 @@
2.95
2.96 # Define method dispatchers.
2.97
2.98 - for real_method_name, methods in real_methods.items():
2.99 + for real_method_name, methods in self.real_methods.items():
2.100 if real_method_name != "<clinit>":
2.101 - self.make_method(real_method_name, methods, global_names, namespace)
2.102 + self.make_method(real_method_name, methods, global_names)
2.103
2.104 # Use only the last part of the fully qualified name.
2.105
2.106 full_class_name = str(self.class_file.this_class.get_python_name())
2.107 class_name = full_class_name.split(".")[-1]
2.108 - cls = new.classobj(class_name, bases, namespace)
2.109 + cls = new.classobj(class_name, bases, self.namespace)
2.110 global_names[cls.__name__] = cls
2.111
2.112 - return cls, external_names
2.113 + return cls
2.114
2.115 def get_base_classes(self, global_names):
2.116
2.117 @@ -2323,27 +2336,20 @@
2.118 tuple).
2.119 """
2.120
2.121 - original_name = str(self.class_file.super_class.get_name())
2.122 - full_this_class_name = str(self.class_file.this_class.get_python_name())
2.123 - this_class_name_parts = full_this_class_name.split(".")
2.124 - this_class_module_name = ".".join(this_class_name_parts[:-1])
2.125 - full_super_class_name = str(self.class_file.super_class.get_python_name())
2.126 - super_class_name_parts = full_super_class_name.split(".")
2.127 - super_class_name = super_class_name_parts[-1]
2.128 - super_class_module_name = ".".join(super_class_name_parts[:-1])
2.129 - if super_class_module_name == "":
2.130 - obj = global_names[super_class_name]
2.131 - elif super_class_module_name == this_class_module_name:
2.132 - obj = global_names[super_class_name]
2.133 - else:
2.134 - #print "Importing", super_class_module_name, super_class_name
2.135 - obj = __import__(super_class_module_name, global_names, {}, [])
2.136 - for super_class_name_part in super_class_name_parts[1:] or [super_class_name]:
2.137 - #print "*", obj, super_class_name_part
2.138 - try:
2.139 - obj = getattr(obj, super_class_name_part)
2.140 - except AttributeError:
2.141 - raise AttributeError, "Cannot find class '%s' in Java package '%s'" % (super_class_name_part, super_class_module_name)
2.142 + super_class = self.class_file.super_class
2.143 + if super_class is None:
2.144 + return ()
2.145 +
2.146 + super_class_name = super_class.get_python_name()
2.147 + super_class_name_parts = super_class_name.split(".")
2.148 + obj = global_names
2.149 + for super_class_name_part in super_class_name_parts[:-1]:
2.150 + try:
2.151 + obj = obj[super_class_name_part].__dict__
2.152 + except KeyError:
2.153 + raise AttributeError, "Cannot find '%s' when referencing Java class '%s'" % (
2.154 + super_class_name_part, super_class_name)
2.155 + obj = obj[super_class_name_parts[-1]]
2.156 return (obj,)
2.157
2.158 def make_varnames(self, nlocals, method_is_static=0):
2.159 @@ -2378,6 +2384,7 @@
2.160 if __name__ == "__main__":
2.161 import sys
2.162 import dis
2.163 + import java.lang
2.164 global_names = globals()
2.165 #global_names["isinstance"] = _isinstance
2.166 #global_names["map"] = _map
2.167 @@ -2385,6 +2392,7 @@
2.168 f = open(filename, "rb")
2.169 c = classfile.ClassFile(f.read())
2.170 translator = ClassTranslator(c)
2.171 - cls, external_names = translator.process(global_names)
2.172 + external_names = translator.process(global_names)
2.173 + cls = translator.get_class(global_names)
2.174
2.175 # vim: tabstop=4 expandtab shiftwidth=4
3.1 --- a/javaclass/classhook.py Sun Feb 13 01:33:26 2005 +0100
3.2 +++ b/javaclass/classhook.py Sun Feb 13 01:35:44 2005 +0100
3.3 @@ -5,6 +5,7 @@
3.4 from imp import PY_SOURCE, PKG_DIRECTORY, C_BUILTIN # import machinery magic
3.5 import classfile, bytecode # Java class support
3.6 import zipfile # for Java archive inspection
3.7 +import sys
3.8
3.9 # NOTE: Arbitrary constants pulled from thin air.
3.10
3.11 @@ -236,14 +237,52 @@
3.12 find_module method produces such a list.
3.13 """
3.14
3.15 + loaded_module_names = []
3.16 + loaded_classes = {}
3.17 + main_module = self._load_module(name, stuff, loaded_module_names, loaded_classes)
3.18 +
3.19 + # Initialise the loaded classes.
3.20 +
3.21 + for module, classes in loaded_classes.items():
3.22 + self._init_classes(module, classes)
3.23 +
3.24 + return main_module
3.25 +
3.26 + def _filter_names(self, module_names, loaded_module_names):
3.27 + for module_name in loaded_module_names:
3.28 + try:
3.29 + i = module_names.index(module_name)
3.30 + del module_names[i]
3.31 + except ValueError:
3.32 + pass
3.33 +
3.34 + def _load_module(self, name, stuff, loaded_module_names, loaded_classes):
3.35 + #print "_load_module", name, loaded_module_names
3.36 + loaded_module_names.append(name)
3.37 +
3.38 + # Detect non-Java modules.
3.39 +
3.40 + for stuff_item in stuff:
3.41 + archive, filename, info = stuff_item
3.42 + suffix, mode, datatype = info
3.43 + if datatype not in (JAVA_PACKAGE, JAVA_ARCHIVE):
3.44 + return ihooks.ModuleLoader.load_module(self, name, stuff_item)
3.45 +
3.46 # Set up the module.
3.47 # A union of all locations is placed in the module's path.
3.48
3.49 + external_names = []
3.50 module = self.hooks.add_module(name)
3.51 module.__path__ = [item_filename for (item_archive, item_filename, item_info) in stuff]
3.52
3.53 + # Prepare a dictionary of globals.
3.54 +
3.55 + global_names = module.__dict__
3.56 + global_names["__builtins__"] = __builtins__
3.57 +
3.58 # Just go into each package and find the class files.
3.59
3.60 + classes = {}
3.61 for stuff_item in stuff:
3.62
3.63 # Extract the details, delegating loading responsibility to the
3.64 @@ -253,16 +292,8 @@
3.65
3.66 archive, filename, info = stuff_item
3.67 suffix, mode, datatype = info
3.68 - if datatype not in (JAVA_PACKAGE, JAVA_ARCHIVE):
3.69 - return ihooks.ModuleLoader.load_module(self, name, stuff_item)
3.70 -
3.71 #print "Loading", archive, filename, info
3.72
3.73 - # Prepare a dictionary of globals.
3.74 -
3.75 - global_names = module.__dict__
3.76 - global_names["__builtins__"] = __builtins__
3.77 -
3.78 # Get the real filename.
3.79
3.80 filename = self._get_path_in_archive(filename)
3.81 @@ -270,115 +301,111 @@
3.82
3.83 # Load the class files.
3.84
3.85 - class_files = {}
3.86 for class_filename in self.hooks.matching(filename, os.extsep + "class", archive):
3.87 #print "Loading class", class_filename
3.88 s = self.hooks.read(class_filename, archive)
3.89 class_file = classfile.ClassFile(s)
3.90 - class_files[str(class_file.this_class.get_name())] = class_file
3.91 -
3.92 - # Get an index of the class files.
3.93 -
3.94 - class_file_index = class_files.keys()
3.95 -
3.96 - # NOTE: Unnecessary sorting for test purposes.
3.97 -
3.98 - class_file_index.sort()
3.99 -
3.100 - # Now go through the classes arranging them in a safe loading order.
3.101 -
3.102 - position = 0
3.103 - while position < len(class_file_index):
3.104 - class_name = class_file_index[position]
3.105 - super_class_name = str(class_files[class_name].super_class.get_name())
3.106 -
3.107 - # Discover whether the superclass appears later.
3.108 -
3.109 - try:
3.110 - super_class_position = class_file_index.index(super_class_name)
3.111 - if super_class_position > position:
3.112 + translator = bytecode.ClassTranslator(class_file)
3.113 + classes[str(class_file.this_class.get_name())] = translator
3.114 + external_names += translator.process(global_names)
3.115
3.116 - # If the superclass appears later, swap this class and the
3.117 - # superclass, then process the superclass.
3.118 -
3.119 - class_file_index[position] = super_class_name
3.120 - class_file_index[super_class_position] = class_name
3.121 - continue
3.122 -
3.123 - except ValueError:
3.124 - pass
3.125 -
3.126 - position += 1
3.127 + # Record the classes found under the current module.
3.128
3.129 - # Process each class file, producing a genuine Python class.
3.130 - # Create the classes, but establish a proper initialisation order.
3.131 -
3.132 - class_file_init_index = []
3.133 - class_file_init = {}
3.134 + loaded_classes[module] = classes
3.135
3.136 - for class_name in class_file_index:
3.137 - #print "* Class", class_name
3.138 - class_file = class_files[class_name]
3.139 - translator = bytecode.ClassTranslator(class_file)
3.140 - cls, external_names = translator.process(global_names)
3.141 - module.__dict__[cls.__name__] = cls
3.142 -
3.143 - # Process external names.
3.144 + # Return modules used by external names.
3.145
3.146 - this_class_name_parts = class_file.this_class.get_python_name().split(".")
3.147 - this_class_module, this_class_name = this_class_name_parts[:-1], this_class_name_parts[-1]
3.148 -
3.149 - for external_name in external_names:
3.150 - #print "* Name", external_name
3.151 - external_name_parts = external_name.split(".")
3.152 - external_class_module, external_class_name = external_name_parts[:-1], external_name_parts[-1]
3.153 -
3.154 - # Names not local to this package need importing.
3.155 -
3.156 - if len(external_name_parts) > 1 and this_class_module != external_class_module:
3.157 + external_module_names = self._get_external_module_names(external_names)
3.158
3.159 - external_module_name = ".".join(external_class_module)
3.160 - #print "* Importing", external_module_name
3.161 - obj = __import__(external_module_name, global_names, {}, [])
3.162 - global_names[external_name_parts[0]] = obj
3.163 -
3.164 - # Names local to this package may affect initialisation order.
3.165 -
3.166 - elif external_class_name not in class_file_init_index:
3.167 - try:
3.168 - this_class_name_index = class_file_init_index.index(this_class_name)
3.169 -
3.170 - # Either insert this name before the current class's
3.171 - # name.
3.172 + # Repeatedly load classes from referenced modules.
3.173
3.174 - #print "* Inserting", external_class_name
3.175 - class_file_init_index.insert(this_class_name_index, external_class_name)
3.176 -
3.177 - except ValueError:
3.178 -
3.179 - # Or add this name in anticipation of the current
3.180 - # class's name appearing.
3.181 -
3.182 - #print "* Including", external_class_name
3.183 - class_file_init_index.append(external_class_name)
3.184 -
3.185 - # Add this class name to the initialisation index.
3.186 + self._filter_names(external_module_names, loaded_module_names)
3.187 + for module_name in external_module_names:
3.188 + if module_name not in loaded_module_names:
3.189
3.190 - if class_name not in class_file_init_index:
3.191 - class_file_init_index.append(this_class_name)
3.192 - class_file_init[this_class_name] = (cls, class_file)
3.193 -
3.194 - # Finally, call __clinit__ methods for all relevant classes.
3.195 + # Emulate the __import__ function, loading the requested module
3.196 + # but returning the top-level module.
3.197
3.198 - #print "** Initialisation order", class_file_init_index
3.199 - for class_name in class_file_init_index:
3.200 - cls, class_file = class_file_init[class_name]
3.201 - #print "**", cls, class_file
3.202 - if hasattr(cls, "__clinit__"):
3.203 - eval(cls.__clinit__.func_code, global_names)
3.204 + self._import(module_name, global_names, loaded_module_names, loaded_classes)
3.205
3.206 return module
3.207
3.208 + def _import(self, module_name, parent, loaded_module_names, loaded_classes):
3.209 +
3.210 + # Where no Java-based submodules can be found, look for
3.211 + # Python modules instead.
3.212 +
3.213 + new_stuff = self.find_module(module_name)
3.214 + #print "_", new_stuff
3.215 + if not new_stuff:
3.216 + new_module = __import__(module_name, parent)
3.217 + #print "P", new_module
3.218 + parent[module_name.split(".")[0]] = new_module
3.219 + return new_module
3.220 +
3.221 + module_name_parts = module_name.split(".")
3.222 + path = []
3.223 + for module_name_part in module_name_parts:
3.224 + path.append(module_name_part)
3.225 + path_str = ".".join(path)
3.226 + if self.modules_dict().has_key(path_str):
3.227 +
3.228 + # Add submodules to existing modules.
3.229 +
3.230 + new_module = self.modules_dict()[path_str]
3.231 + parent = new_module.__dict__
3.232 + #print "-", path_str
3.233 +
3.234 + else:
3.235 +
3.236 + # Find submodules.
3.237 +
3.238 + new_stuff = self.find_module(path_str)
3.239 + new_module = self._load_module(path_str, new_stuff, loaded_module_names, loaded_classes)
3.240 + #print "J", new_module
3.241 + #print "+", path_str, new_module
3.242 + parent[module_name_part] = new_module
3.243 + parent = new_module.__dict__
3.244 +
3.245 + #print "->", new_module.__dict__.keys()
3.246 + return new_module
3.247 +
3.248 + def _get_external_module_names(self, names):
3.249 + groups = self._get_names_grouped_by_module(names)
3.250 + if groups.has_key(""):
3.251 + del groups[""]
3.252 + return groups.keys()
3.253 +
3.254 + def _get_names_grouped_by_module(self, names):
3.255 + groups = {}
3.256 + for name in names:
3.257 + module_name, class_name = self._get_module_and_class_names(name)
3.258 + if not groups.has_key(module_name):
3.259 + groups[module_name] = []
3.260 + groups[module_name].append(class_name)
3.261 + return groups
3.262 +
3.263 + def _get_module_and_class_names(self, full_name):
3.264 + full_name_parts = full_name.split(".")
3.265 + class_name = full_name_parts[-1]
3.266 + module_name = ".".join(full_name_parts[:-1])
3.267 + return module_name, class_name
3.268 +
3.269 + def _init_classes(self, module, classes):
3.270 + global_names = module.__dict__
3.271 +
3.272 + # First, create the classes.
3.273 +
3.274 + real_classes = []
3.275 + for name, translator in classes.items():
3.276 + real_classes.append(translator.get_class(global_names))
3.277 +
3.278 + # Finally, call __clinit__ methods for all relevant classes.
3.279 +
3.280 + for cls in real_classes:
3.281 + if hasattr(cls, "__clinit__"):
3.282 + eval(cls.__clinit__.func_code, global_names)
3.283 +
3.284 ihooks.ModuleImporter(loader=ClassLoader(hooks=ClassHooks())).install()
3.285
3.286 # vim: tabstop=4 expandtab shiftwidth=4