1.1 --- a/javaclass/classhook.py Sun Feb 13 01:33:26 2005 +0100
1.2 +++ b/javaclass/classhook.py Sun Feb 13 01:35:44 2005 +0100
1.3 @@ -5,6 +5,7 @@
1.4 from imp import PY_SOURCE, PKG_DIRECTORY, C_BUILTIN # import machinery magic
1.5 import classfile, bytecode # Java class support
1.6 import zipfile # for Java archive inspection
1.7 +import sys
1.8
1.9 # NOTE: Arbitrary constants pulled from thin air.
1.10
1.11 @@ -236,14 +237,52 @@
1.12 find_module method produces such a list.
1.13 """
1.14
1.15 + loaded_module_names = []
1.16 + loaded_classes = {}
1.17 + main_module = self._load_module(name, stuff, loaded_module_names, loaded_classes)
1.18 +
1.19 + # Initialise the loaded classes.
1.20 +
1.21 + for module, classes in loaded_classes.items():
1.22 + self._init_classes(module, classes)
1.23 +
1.24 + return main_module
1.25 +
1.26 + def _filter_names(self, module_names, loaded_module_names):
1.27 + for module_name in loaded_module_names:
1.28 + try:
1.29 + i = module_names.index(module_name)
1.30 + del module_names[i]
1.31 + except ValueError:
1.32 + pass
1.33 +
1.34 + def _load_module(self, name, stuff, loaded_module_names, loaded_classes):
1.35 + #print "_load_module", name, loaded_module_names
1.36 + loaded_module_names.append(name)
1.37 +
1.38 + # Detect non-Java modules.
1.39 +
1.40 + for stuff_item in stuff:
1.41 + archive, filename, info = stuff_item
1.42 + suffix, mode, datatype = info
1.43 + if datatype not in (JAVA_PACKAGE, JAVA_ARCHIVE):
1.44 + return ihooks.ModuleLoader.load_module(self, name, stuff_item)
1.45 +
1.46 # Set up the module.
1.47 # A union of all locations is placed in the module's path.
1.48
1.49 + external_names = []
1.50 module = self.hooks.add_module(name)
1.51 module.__path__ = [item_filename for (item_archive, item_filename, item_info) in stuff]
1.52
1.53 + # Prepare a dictionary of globals.
1.54 +
1.55 + global_names = module.__dict__
1.56 + global_names["__builtins__"] = __builtins__
1.57 +
1.58 # Just go into each package and find the class files.
1.59
1.60 + classes = {}
1.61 for stuff_item in stuff:
1.62
1.63 # Extract the details, delegating loading responsibility to the
1.64 @@ -253,16 +292,8 @@
1.65
1.66 archive, filename, info = stuff_item
1.67 suffix, mode, datatype = info
1.68 - if datatype not in (JAVA_PACKAGE, JAVA_ARCHIVE):
1.69 - return ihooks.ModuleLoader.load_module(self, name, stuff_item)
1.70 -
1.71 #print "Loading", archive, filename, info
1.72
1.73 - # Prepare a dictionary of globals.
1.74 -
1.75 - global_names = module.__dict__
1.76 - global_names["__builtins__"] = __builtins__
1.77 -
1.78 # Get the real filename.
1.79
1.80 filename = self._get_path_in_archive(filename)
1.81 @@ -270,115 +301,111 @@
1.82
1.83 # Load the class files.
1.84
1.85 - class_files = {}
1.86 for class_filename in self.hooks.matching(filename, os.extsep + "class", archive):
1.87 #print "Loading class", class_filename
1.88 s = self.hooks.read(class_filename, archive)
1.89 class_file = classfile.ClassFile(s)
1.90 - class_files[str(class_file.this_class.get_name())] = class_file
1.91 -
1.92 - # Get an index of the class files.
1.93 -
1.94 - class_file_index = class_files.keys()
1.95 -
1.96 - # NOTE: Unnecessary sorting for test purposes.
1.97 -
1.98 - class_file_index.sort()
1.99 -
1.100 - # Now go through the classes arranging them in a safe loading order.
1.101 -
1.102 - position = 0
1.103 - while position < len(class_file_index):
1.104 - class_name = class_file_index[position]
1.105 - super_class_name = str(class_files[class_name].super_class.get_name())
1.106 -
1.107 - # Discover whether the superclass appears later.
1.108 -
1.109 - try:
1.110 - super_class_position = class_file_index.index(super_class_name)
1.111 - if super_class_position > position:
1.112 + translator = bytecode.ClassTranslator(class_file)
1.113 + classes[str(class_file.this_class.get_name())] = translator
1.114 + external_names += translator.process(global_names)
1.115
1.116 - # If the superclass appears later, swap this class and the
1.117 - # superclass, then process the superclass.
1.118 -
1.119 - class_file_index[position] = super_class_name
1.120 - class_file_index[super_class_position] = class_name
1.121 - continue
1.122 -
1.123 - except ValueError:
1.124 - pass
1.125 -
1.126 - position += 1
1.127 + # Record the classes found under the current module.
1.128
1.129 - # Process each class file, producing a genuine Python class.
1.130 - # Create the classes, but establish a proper initialisation order.
1.131 -
1.132 - class_file_init_index = []
1.133 - class_file_init = {}
1.134 + loaded_classes[module] = classes
1.135
1.136 - for class_name in class_file_index:
1.137 - #print "* Class", class_name
1.138 - class_file = class_files[class_name]
1.139 - translator = bytecode.ClassTranslator(class_file)
1.140 - cls, external_names = translator.process(global_names)
1.141 - module.__dict__[cls.__name__] = cls
1.142 -
1.143 - # Process external names.
1.144 + # Return modules used by external names.
1.145
1.146 - this_class_name_parts = class_file.this_class.get_python_name().split(".")
1.147 - this_class_module, this_class_name = this_class_name_parts[:-1], this_class_name_parts[-1]
1.148 -
1.149 - for external_name in external_names:
1.150 - #print "* Name", external_name
1.151 - external_name_parts = external_name.split(".")
1.152 - external_class_module, external_class_name = external_name_parts[:-1], external_name_parts[-1]
1.153 -
1.154 - # Names not local to this package need importing.
1.155 -
1.156 - if len(external_name_parts) > 1 and this_class_module != external_class_module:
1.157 + external_module_names = self._get_external_module_names(external_names)
1.158
1.159 - external_module_name = ".".join(external_class_module)
1.160 - #print "* Importing", external_module_name
1.161 - obj = __import__(external_module_name, global_names, {}, [])
1.162 - global_names[external_name_parts[0]] = obj
1.163 -
1.164 - # Names local to this package may affect initialisation order.
1.165 -
1.166 - elif external_class_name not in class_file_init_index:
1.167 - try:
1.168 - this_class_name_index = class_file_init_index.index(this_class_name)
1.169 -
1.170 - # Either insert this name before the current class's
1.171 - # name.
1.172 + # Repeatedly load classes from referenced modules.
1.173
1.174 - #print "* Inserting", external_class_name
1.175 - class_file_init_index.insert(this_class_name_index, external_class_name)
1.176 -
1.177 - except ValueError:
1.178 -
1.179 - # Or add this name in anticipation of the current
1.180 - # class's name appearing.
1.181 -
1.182 - #print "* Including", external_class_name
1.183 - class_file_init_index.append(external_class_name)
1.184 -
1.185 - # Add this class name to the initialisation index.
1.186 + self._filter_names(external_module_names, loaded_module_names)
1.187 + for module_name in external_module_names:
1.188 + if module_name not in loaded_module_names:
1.189
1.190 - if class_name not in class_file_init_index:
1.191 - class_file_init_index.append(this_class_name)
1.192 - class_file_init[this_class_name] = (cls, class_file)
1.193 -
1.194 - # Finally, call __clinit__ methods for all relevant classes.
1.195 + # Emulate the __import__ function, loading the requested module
1.196 + # but returning the top-level module.
1.197
1.198 - #print "** Initialisation order", class_file_init_index
1.199 - for class_name in class_file_init_index:
1.200 - cls, class_file = class_file_init[class_name]
1.201 - #print "**", cls, class_file
1.202 - if hasattr(cls, "__clinit__"):
1.203 - eval(cls.__clinit__.func_code, global_names)
1.204 + self._import(module_name, global_names, loaded_module_names, loaded_classes)
1.205
1.206 return module
1.207
1.208 + def _import(self, module_name, parent, loaded_module_names, loaded_classes):
1.209 +
1.210 + # Where no Java-based submodules can be found, look for
1.211 + # Python modules instead.
1.212 +
1.213 + new_stuff = self.find_module(module_name)
1.214 + #print "_", new_stuff
1.215 + if not new_stuff:
1.216 + new_module = __import__(module_name, parent)
1.217 + #print "P", new_module
1.218 + parent[module_name.split(".")[0]] = new_module
1.219 + return new_module
1.220 +
1.221 + module_name_parts = module_name.split(".")
1.222 + path = []
1.223 + for module_name_part in module_name_parts:
1.224 + path.append(module_name_part)
1.225 + path_str = ".".join(path)
1.226 + if self.modules_dict().has_key(path_str):
1.227 +
1.228 + # Add submodules to existing modules.
1.229 +
1.230 + new_module = self.modules_dict()[path_str]
1.231 + parent = new_module.__dict__
1.232 + #print "-", path_str
1.233 +
1.234 + else:
1.235 +
1.236 + # Find submodules.
1.237 +
1.238 + new_stuff = self.find_module(path_str)
1.239 + new_module = self._load_module(path_str, new_stuff, loaded_module_names, loaded_classes)
1.240 + #print "J", new_module
1.241 + #print "+", path_str, new_module
1.242 + parent[module_name_part] = new_module
1.243 + parent = new_module.__dict__
1.244 +
1.245 + #print "->", new_module.__dict__.keys()
1.246 + return new_module
1.247 +
1.248 + def _get_external_module_names(self, names):
1.249 + groups = self._get_names_grouped_by_module(names)
1.250 + if groups.has_key(""):
1.251 + del groups[""]
1.252 + return groups.keys()
1.253 +
1.254 + def _get_names_grouped_by_module(self, names):
1.255 + groups = {}
1.256 + for name in names:
1.257 + module_name, class_name = self._get_module_and_class_names(name)
1.258 + if not groups.has_key(module_name):
1.259 + groups[module_name] = []
1.260 + groups[module_name].append(class_name)
1.261 + return groups
1.262 +
1.263 + def _get_module_and_class_names(self, full_name):
1.264 + full_name_parts = full_name.split(".")
1.265 + class_name = full_name_parts[-1]
1.266 + module_name = ".".join(full_name_parts[:-1])
1.267 + return module_name, class_name
1.268 +
1.269 + def _init_classes(self, module, classes):
1.270 + global_names = module.__dict__
1.271 +
1.272 + # First, create the classes.
1.273 +
1.274 + real_classes = []
1.275 + for name, translator in classes.items():
1.276 + real_classes.append(translator.get_class(global_names))
1.277 +
1.278 + # Finally, call __clinit__ methods for all relevant classes.
1.279 +
1.280 + for cls in real_classes:
1.281 + if hasattr(cls, "__clinit__"):
1.282 + eval(cls.__clinit__.func_code, global_names)
1.283 +
1.284 ihooks.ModuleImporter(loader=ClassLoader(hooks=ClassHooks())).install()
1.285
1.286 # vim: tabstop=4 expandtab shiftwidth=4