1 #!/usr/bin/env python 2 3 import ihooks 4 import os, glob 5 from imp import PY_SOURCE, PKG_DIRECTORY, C_BUILTIN 6 import classfile, bytecode 7 import new 8 9 JAVA_PACKAGE = 20041113 10 JAVA_CLASS = 20041114 11 12 class ClassHooks(ihooks.Hooks): 13 14 "A filesystem hooks class providing information about supported files." 15 16 def get_suffixes(self): 17 18 "Return the recognised suffixes." 19 20 return ihooks.Hooks.get_suffixes(self) + [("", "", JAVA_PACKAGE), (os.extsep + "class", "r", JAVA_CLASS)] 21 22 class ClassLoader(ihooks.ModuleLoader): 23 24 "A class providing support for searching directories for supported files." 25 26 def find_module_in_dir(self, name, dir, allow_packages=1): 27 28 """ 29 Find the module with the given 'name' in the given directory 'dir'. 30 Since Java packages/modules are directories containing class files, 31 return the required information tuple only when the path constructed 32 from 'dir' and 'name' refers to a directory containing class files. 33 """ 34 35 result = ihooks.ModuleLoader.find_module_in_dir(self, name, dir, allow_packages) 36 if result is not None: 37 return result 38 39 # Provide a special name for the current directory. 40 41 if name == "__this__": 42 path = "." 43 elif dir is None: 44 return None 45 else: 46 path = os.path.join(dir, name) 47 48 #print "Processing name", name, "in", dir, "producing", path 49 50 if self._find_module_at_path(path): 51 return (None, path, ("", "", JAVA_PACKAGE)) 52 else: 53 return None 54 55 def _find_module_at_path(self, path): 56 if os.path.isdir(path): 57 58 # Look for classes in the directory. 59 60 if len(glob.glob(os.path.join(path, "*" + os.extsep + "class"))) != 0: 61 return 1 62 63 # Otherwise permit importing where directories containing classes exist. 64 65 for filename in os.listdir(path): 66 pathname = os.path.join(path, filename) 67 result = self._find_module_at_path(pathname) 68 if result is not None: 69 return result 70 71 return None 72 73 def load_module(self, name, stuff): 74 75 """ 76 Load the module with the given 'name', whose 'stuff' which describes the 77 location of the module is a tuple of the form (file, filename, (suffix, 78 mode, data type)). Return a module object or raise an ImportError if a 79 problem occurred in the import operation. 80 """ 81 82 # Just go into the directory and find the class files. 83 84 file, filename, info = stuff 85 suffix, mode, datatype = info 86 if datatype != JAVA_PACKAGE: 87 return ihooks.ModuleLoader.load_module(self, name, stuff) 88 89 print "Loading", file, filename, info 90 91 # Set up the module. 92 93 module = self.hooks.add_module(name) 94 module.__path__ = [filename] 95 96 # Prepare a dictionary of globals. 97 98 global_names = module.__dict__ 99 global_names["__builtins__"] = __builtins__ 100 101 # Process each class file, producing a genuine Python class. 102 103 class_files = [] 104 classes = [] 105 106 # Load the class files. 107 108 class_files = {} 109 for class_filename in glob.glob(os.path.join(filename, "*" + os.extsep + "class")): 110 print "Loading class", class_filename 111 f = open(class_filename, "rb") 112 s = f.read() 113 f.close() 114 class_file = classfile.ClassFile(s) 115 class_files[str(class_file.this_class.get_name())] = class_file 116 117 # Get an index of the class files. 118 119 class_file_index = class_files.keys() 120 121 # NOTE: Unnecessary sorting for test purposes. 122 123 class_file_index.sort() 124 125 # Now go through the classes arranging them in a safe loading order. 126 127 position = 0 128 while position < len(class_file_index): 129 class_name = class_file_index[position] 130 super_class_name = str(class_files[class_name].super_class.get_name()) 131 132 # Discover whether the superclass appears later. 133 134 try: 135 super_class_position = class_file_index.index(super_class_name) 136 if super_class_position > position: 137 138 # If the superclass appears later, swap this class and the 139 # superclass, then process the superclass. 140 141 class_file_index[position] = super_class_name 142 class_file_index[super_class_position] = class_name 143 continue 144 145 except ValueError: 146 pass 147 148 position += 1 149 150 class_files = [class_files[class_name] for class_name in class_file_index] 151 152 for class_file in class_files: 153 translator = bytecode.ClassTranslator(class_file) 154 cls, external_names = translator.process(global_names) 155 module.__dict__[cls.__name__] = cls 156 classes.append((cls, class_file)) 157 158 # Import the local names. 159 160 for external_name in external_names: 161 external_name_parts = external_name.split(".") 162 if len(external_name_parts) > 1: 163 external_module_name = ".".join(external_name_parts[:-1]) 164 print "* Importing", external_module_name 165 obj = __import__(external_module_name, global_names, {}, []) 166 global_names[external_name_parts[0]] = obj 167 168 # Finally, call __clinit__ methods for all relevant classes. 169 170 for cls, class_file in classes: 171 print "**", cls, class_file 172 if hasattr(cls, "__clinit__"): 173 eval(cls.__clinit__.func_code, global_names) 174 175 return module 176 177 importer = ihooks.ModuleImporter(loader=ClassLoader(hooks=ClassHooks())) 178 importer.install() 179 180 # vim: tabstop=4 expandtab shiftwidth=4