125 lines
3.8 KiB
Python
125 lines
3.8 KiB
Python
#!/usr/bin/env python3.9
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
JFinal ProxyClassLoader - Dynamic Proxy Class Loader
|
|
"""
|
|
|
|
import importlib
|
|
import sys
|
|
from typing import Dict, Optional, Type
|
|
from .ProxyClass import ProxyClass
|
|
|
|
class ProxyClassLoader:
|
|
"""Dynamic proxy class loader"""
|
|
|
|
def __init__(self):
|
|
"""Initialize proxy class loader"""
|
|
self._byte_code_map: Dict[str, bytes] = {}
|
|
|
|
def load_proxy_class(self, proxy_class: ProxyClass) -> Type:
|
|
"""
|
|
Load proxy class from byte code
|
|
|
|
Args:
|
|
proxyClass: ProxyClass object with byte code
|
|
|
|
Returns:
|
|
Loaded proxy class
|
|
"""
|
|
# Add byte code to map
|
|
if proxy_class.byte_code:
|
|
for class_name, byte_code in proxy_class.byte_code.items():
|
|
if class_name not in self._byte_code_map:
|
|
self._byte_code_map[class_name] = byte_code
|
|
|
|
# Try to load the class
|
|
class_name = proxy_class.full_name
|
|
|
|
# Check if already loaded
|
|
if class_name in sys.modules:
|
|
return sys.modules[class_name]
|
|
|
|
try:
|
|
# For Python, we'll use dynamic import
|
|
# In a real implementation, this would use importlib or similar
|
|
loaded_class = self._dynamic_import(class_name, proxy_class)
|
|
return loaded_class
|
|
except (ImportError, AttributeError) as e:
|
|
raise RuntimeError(f"Error loading proxy class {class_name}: {e}")
|
|
|
|
def _dynamic_import(self, class_name: str, proxy_class: ProxyClass) -> Type:
|
|
"""
|
|
Dynamically import and create class from proxy class
|
|
|
|
Args:
|
|
class_name: Full class name
|
|
proxyClass: ProxyClass object
|
|
|
|
Returns:
|
|
Dynamically created class
|
|
"""
|
|
# In Python, we can execute the source code and get the class
|
|
if proxy_class.source_code:
|
|
# Create a module
|
|
module_name = proxy_class.pkg
|
|
module_code = proxy_class.source_code
|
|
|
|
# Execute the code in a new namespace
|
|
namespace = {}
|
|
try:
|
|
exec(module_code, namespace)
|
|
|
|
# Find the class in the namespace
|
|
for name, obj in namespace.items():
|
|
if isinstance(obj, type) and name == proxy_class.name:
|
|
return obj
|
|
|
|
raise RuntimeError(f"Class {proxy_class.name} not found in generated code")
|
|
except Exception as e:
|
|
raise RuntimeError(f"Error executing generated code: {e}")
|
|
else:
|
|
raise RuntimeError("No source code available for proxy class")
|
|
|
|
def find_class(self, name: str) -> Optional[bytes]:
|
|
"""
|
|
Find class byte code by name
|
|
|
|
Args:
|
|
name: Full class name
|
|
|
|
Returns:
|
|
Byte code or None if not found
|
|
"""
|
|
return self._byte_code_map.get(name)
|
|
|
|
def add_byte_code(self, name: str, byte_code: bytes):
|
|
"""
|
|
Add byte code to the loader
|
|
|
|
Args:
|
|
name: Full class name
|
|
byte_code: Class byte code
|
|
"""
|
|
self._byte_code_map[name] = byte_code
|
|
|
|
def remove_byte_code(self, name: str) -> Optional[bytes]:
|
|
"""
|
|
Remove and return byte code
|
|
|
|
Args:
|
|
name: Full class name
|
|
|
|
Returns:
|
|
Removed byte code or None
|
|
"""
|
|
return self._byte_code_map.pop(name, None)
|
|
|
|
def clear(self):
|
|
"""Clear all cached byte code"""
|
|
self._byte_code_map.clear()
|
|
|
|
@property
|
|
def byte_code_count(self) -> int:
|
|
"""Get number of cached byte codes"""
|
|
return len(self._byte_code_map)
|