javaclass

classhook.py

70:c086884f142c
2004-11-21 Paul Boddie Added importing of external names. Changed the invocation of class initialisation functions to occur within the current global namespace.
     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