""" WorkerPoolMixin - Mixin für Worker-Pool-Verwaltung. Dieses Mixin enthält alle Methoden zur Verwaltung der Saxon- und FOP-Worker-Pools für das MainWindow. """ import logging from PySide6.QtWidgets import QMessageBox from conf import app_settings, XsltVersion from transform import TransformationJob, get_saxon_worker_pool, set_saxon_worker_pool, get_fop_worker_pool, set_fop_worker_pool from saxon_pool import SaxonWorkerPool from saxon_pool_s9api import SaxonWorkerPoolS9Api logger = logging.getLogger(__name__) class WorkerPoolMixin: """ Mixin für Worker-Pool-Verwaltung. Dieses Mixin wird von MainWindow verwendet und erwartet folgende Attribute: - self.project: Das aktuelle Projekt """ def _initialize_saxon_worker_pool(self): """Initialisiert den Saxon-Worker-Pool für schnelle Transformationen.""" try: # Shutdown vorherigen Pool falls vorhanden self._shutdown_saxon_worker_pool() # Prüfe ob SaxonWorkerPool aktiviert ist if not app_settings.use_saxon_worker_pool: logger.info("SaxonWorkerPool deaktiviert - Verwende Fallback-Modus (subprocess)") return if not self.project: logger.warning("Kein Projekt geladen, Saxon-Worker-Pool nicht initialisiert") return # Hole Tool-Konfigurationen java_vm = next((vm for vm in app_settings.java_vms if vm.id == self.project.java_vm_id), None) saxon_jar = next((jar for jar in app_settings.saxon_jars if jar.id == self.project.saxon_jar_id), None) if not java_vm or not saxon_jar: logger.warning("Java VM oder Saxon JAR nicht gefunden, Pool nicht initialisiert") return # Erstelle Worker-Pool (wähle richtige Variante basierend auf XSLT-Version) num_workers = app_settings.max_workers log_dir = self.project.project_dir / "tmp" # Wähle die richtige Worker-Pool-Implementierung if app_settings.saxon_xslt_version == XsltVersion.XSLT_1_0: # JAXP-basierte Variante für XSLT 1.0 pool = SaxonWorkerPool( num_workers=num_workers, java_vm_path=java_vm.path_to_binary_file, saxon_jar_path=saxon_jar.path_to_jar_file, classpath_cache=TransformationJob._classpath_cache, log_dir=log_dir, ) pool_type = "JAXP (XSLT 1.0)" else: # s9api-basierte Variante für XSLT 2.0/3.0 pool = SaxonWorkerPoolS9Api( num_workers=num_workers, java_vm_path=java_vm.path_to_binary_file, saxon_jar_path=saxon_jar.path_to_jar_file, classpath_cache=TransformationJob._classpath_cache, log_dir=log_dir, ) pool_type = "s9api (XSLT 2.0/3.0)" # Setze globalen Pool set_saxon_worker_pool(pool) logger.info( f"Saxon-Worker-Pool initialisiert: {num_workers} Worker mit {pool_type} " f"(erwartet: {num_workers}x schneller für Saxon-Transformationen)" ) except Exception as e: logger.error(f"Fehler beim Initialisieren des Saxon-Worker-Pools: {e}") logger.info("Fallback auf subprocess-Modus") # Kein Pool ist OK - Fallback auf subprocess def _shutdown_saxon_worker_pool(self): """Beendet den Saxon-Worker-Pool sauber.""" try: pool = get_saxon_worker_pool() if pool: logger.info("Beende Saxon-Worker-Pool...") pool.shutdown() set_saxon_worker_pool(None) logger.info("Saxon-Worker-Pool beendet") except Exception as e: logger.error(f"Fehler beim Beenden des Saxon-Worker-Pools: {e}") def _initialize_fop_worker_pool(self): """Initialisiert den FOP-Worker-Pool für schnelle PDF-Generierung.""" try: # Shutdown vorherigen Pool falls vorhanden self._shutdown_fop_worker_pool() # Prüfe ob FopWorkerPool aktiviert ist if not app_settings.use_fop_worker_pool: logger.info("FopWorkerPool deaktiviert - Verwende Fallback-Modus (subprocess)") return if not self.project: logger.warning("Kein Projekt geladen, FOP-Worker-Pool nicht initialisiert") return # Hole Tool-Konfigurationen java_vm = next((vm for vm in app_settings.java_vms if vm.id == self.project.java_vm_id), None) apache_fop = next((fop for fop in app_settings.apache_fops if fop.id == self.project.apache_fop_id), None) if not java_vm or not apache_fop: logger.warning("Java VM oder Apache FOP nicht gefunden, Pool nicht initialisiert") return # FOP-Konfigurationsdatei (falls vorhanden) fop_config_file = None if self.project.fop_config_dir: fop_config_file = self.project.fop_config_dir / "fop.xconf" else: default_config = apache_fop.path_to_dir / "conf" / "fop.xconf" if default_config.exists(): fop_config_file = default_config # Importiere FopWorkerPool from fop_pool import FopWorkerPool # Erstelle Worker-Pool num_workers = app_settings.max_workers log_dir = self.project.project_dir / "tmp" pool = FopWorkerPool( num_workers=num_workers, java_vm_path=java_vm.path_to_binary_file, apache_fop_dir=apache_fop.path_to_dir, fop_config_file=fop_config_file, log_dir=log_dir, ) # Setze globalen Pool set_fop_worker_pool(pool) logger.info( f"FOP-Worker-Pool initialisiert: {num_workers} Worker " f"(erwartet: {num_workers}x schneller für PDF-Generierung)" ) except Exception as e: logger.error(f"Fehler beim Initialisieren des FOP-Worker-Pools: {e}") logger.info("Fallback auf subprocess-Modus") # Kein Pool ist OK - Fallback auf subprocess def _shutdown_fop_worker_pool(self): """Beendet den FOP-Worker-Pool sauber.""" try: pool = get_fop_worker_pool() if pool: logger.info("Beende FOP-Worker-Pool...") pool.shutdown() set_fop_worker_pool(None) logger.info("FOP-Worker-Pool beendet") except Exception as e: logger.error(f"Fehler beim Beenden des FOP-Worker-Pools: {e}") def _show_worker_pool_metrics(self): """Zeigt den Worker-Pool-Metriken-Dialog an.""" try: from ui.WorkerPoolMetricsDialog import WorkerPoolMetricsDialog dialog = WorkerPoolMetricsDialog(self) dialog.exec() except Exception as e: logger.error(f"Fehler beim Öffnen des Metriken-Dialogs: {e}") QMessageBox.critical(self, "Fehler", f"Fehler beim Öffnen des Metriken-Dialogs:\n{str(e)}")