#2857: AdminPage.java
projectforge-wicket/src/main/java/org/projectforge/web/admin/AdminPage.java Página Apache Wicket — panel de administración del sistema. Fuente: projectforge-wicket/src/main/java/org/projectforge/web/admin/AdminPage.java · ~590 líneas 590 líneas · 502 código · 43 comentarios · 45 en blanco
La página de administración central accesible solo para usuarios con privilegios de administrador. Proporciona operaciones a nivel de sistema agrupadas en cinco categorías de menú: Configuración (releer config XML, exportar config, exportar ajustes 2FA), Cachés (refrescar todas las cachés), Acciones de Base de Datos (actualizar preferencias de usuario, crear índices faltantes, volcar base de datos, exportar esquema, optimizar imágenes de direcciones), Verificación del Sistema (verificación de integridad) y Desarrollo (validación de claves i18n, depuración de UserGroupCache, reindexación de Hibernate Search, generación de datos de prueba, alertas del sistema). El menú de Desarrollo solo es visible cuando SystemStatus.isDevelopmentMode() es verdadero.
Arquitectura
Extiende AbstractStandardFormPage e implementa ISelectCallerPage (para selección de fechas basada en calendario). La página utiliza el patrón de menú de contenido de ProjectForge: cada grupo de acciones es un ContentMenuEntryPanel con entradas de submenú, cada una contiene un Link de Wicket cuyo onClick() delega a un método privado.
La página también contiene un componente AdminForm (el cuerpo de la página) que proporciona elementos de UI adicionales como el panel de información del sistema, el verificador de actualizaciones y el visor de registros.
Inyección de endpoint estático mediante set(IProjectForgeEndpoints) — no es inyección por constructor sino un setter estático. Este es un patrón heredado: el campo projectForgeEndpoints proporciona acceso a información del sistema (versión, fecha de compilación, estadísticas de memoria) que se muestra en el formulario de administración. El setter estático es llamado por el inicializador de la aplicación Wicket.
Grupos de Menú
| Grupo | Acciones | Requiere |
| Configuración | Releer config XML desde disco, exportar config como propiedades, exportar configuración 2FA | Acceso admin |
| Cachés | Refrescar todas las cachés (direcciones, usuario, grupo, i18n, información del sistema, etc.) | Acceso admin |
| Acciones de Base de Datos | Actualizar todas las preferencias XML de usuario, crear índices de BD faltantes, volcar base de datos, exportar esquema, optimizar imágenes de direcciones (reducir + recrear vistas previas) | Acceso admin |
| Verificación del Sistema | Ejecutar verificación de integridad (valida consistencia de BD, claves foráneas, registros huérfanos) | Acceso admin |
| Desarrollo | Validación de claves i18n, exportación de depuración JSON de UserGroupCache, DatabaseTester, reindexación de Hibernate Search, crear datos de prueba (100 objetos BookDO), mensaje de alerta del sistema, volcar configuración del sistema, mostrar actualizaciones de BD | Admin + SystemStatus.isDevelopmentMode() |
Control de Acceso
La página sobrescribe onBeforeRender() para llamar a checkAccess() — un método heredado de AbstractStandardFormPage que verifica que el usuario actual tenga el rol ADMIN. Si no, el usuario es redirigido a una página de acceso denegado. Esta es la única verificación de autorización — no hay autorización detallada por acción; cualquier administrador puede realizar cualquier operación en esta página.
El menú de Desarrollo tiene una protección adicional: if (SystemStatus.isDevelopmentMode() == false) return; al final de addDevelopmentMenu(). Esto significa que las acciones de desarrollo no solo están ocultas — sus entradas de menú nunca se agregan a la página cuando no está en modo de desarrollo.
Dependencias Clave
| Importación | Rol |
ConfigXml, Configuration | Leer/escribir configuración del sistema (releer, exportar) |
SystemService | Refresco de caché, verificación de integridad del sistema |
DatabaseService | Crear índices, volcar BD, exportar esquema |
DatabaseTester | Desarrollo: probar operaciones de base de datos |
AddressImageDao | Base de datos: reducir y recrear imágenes de direcciones |
UserXmlPreferencesCache, UserXmlPreferencesMigrationDao | Base de datos: actualizar XML de preferencias de usuario |
HibernateSearchReindexer | Desarrollo: reconstruir índice de búsqueda Lucene |
BookDao, BookDO | Desarrollo: crear objetos de libro de prueba |
I18nHelper | Desarrollo: validar uso de claves i18n |
CronSanityCheckJob | Desarrollo: activar verificación nocturna manualmente |
SystemAlertMessage, SystemStatus | Desarrollo: establecer/verificar banner de alerta del sistema |
WicketUtils, DownloadUtils | UI: diálogos de confirmación JavaScript, disparadores de descarga de archivos |
Patrones de Diseño
Patrón de Menú de Contenido: En lugar de una lista plana de botones, la página de administración utiliza una estructura de menú jerárquica. Cada grupo (ContentMenuEntryPanel) contiene entradas de submenú, cada una con un Link de Wicket. Esto permite organizar más de 20 acciones de administración en categorías lógicas sin abrumar al usuario.
Links con clases internas anónimas: Cada acción es un new Link<Void>() { onClick() { ... } } — clases internas anónimas que delegan a métodos privados. Este es el estilo estándar de Wicket anterior a Java 8. Una reescritura moderna usaría expresiones lambda (Link<Void> link = new Link<>(id) { ... } no puede ser lambda porque Link es una clase, no una interfaz funcional).
Inyección de endpoint estático: projectForgeEndpoints es un campo estático establecido mediante un setter estático. Esto es inusual en una aplicación gestionada por Spring y existe porque AdminPage es una página de Wicket (no un bean de Spring) y necesita acceso a información a nivel de sistema que normalmente proporcionan los servicios de Spring. El setter estático se llama desde el init de la aplicación Wicket.
Historial Git
| Commit | Qué cambió |
868d6abb7 | Copyright 2025→2026. |
eeaafe0df | Se agregó menú de optimización de imágenes de direcciones. Nueva acción "Optimizar imágenes de direcciones" en el menú de Base de Datos. Minimiza el tamaño de archivo de las imágenes de direcciones (compresión JPEG ~100KB) y recalcula las miniaturas de vista previa. Incluye diálogo de confirmación JavaScript. |
ab200b126 | Reducción automática de imágenes de direcciones. La acción de optimización ahora reduce automáticamente las imágenes que son demasiado grandes, no solo ofrece la opción. |
5b042ab5f | Se agregaron exportación de depuración de UserGroupCache y DatabaseTester. Nueva acción "Depurar UserGroupCache" en el menú de Desarrollo — exporta el estado de la caché como JSON para análisis fuera de línea. Nueva acción DatabaseTester para pruebas de estrés en desarrollo. Se agregó registro del módulo Jackson Hibernate6 para serialización JSON de proxies de Hibernate. |
b309e9be9 | Mejoras en adjuntos de correo (BirthdayButler, Polls). Notificación automática por correo electrónico cuando la verificación nocturna encuentra errores. |
092dbf9c5 | SystemService migrado a Kotlin. Paquete renombrado de systeminfo a system. |
619985f48 | Preparativos para la versión 8.1 — fusión de PR #247, varias estabilizaciones. |
1b50060c3 | Renombrado de métodos en BaseDao: get→find, save→insert, getList→select, load→select. Todos los llamantes actualizados — las llamadas DAO de AdminPage usan los nuevos nombres. |
a72903e36 | Migración de StringBuffer→StringBuilder en todos los archivos Java/Kotlin. Rendimiento: StringBuilder no está sincronizado, StringBuffer sí. |
3aeda5ef5 | Manejo de transacciones refactorizado. Se eliminó el sufijo *InTrans de los métodos DAO. PfPersistenceContext ya no se pasa como parámetro — usa ThreadLocal en su lugar. |
b095e6f7d | Cambio importante en el manejo de transacciones. Reutiliza PfPersistenceContext. Las pruebas estaban rotas en este punto (aún no corregidas). |
Precaución: Esta página no tiene autorización por acción. Cualquier usuario con acceso de administrador puede activar volcados de base de datos, exportaciones de esquema, reindexación de Hibernate y creación de datos de prueba — todo en la base de datos de producción. El menú de Desarrollo está protegido por SystemStatus.isDevelopmentMode() pero eso es una única bandera booleana sin más granularidad.
Ruta de migración: Esta es una de las páginas más antiguas que aún están en Wicket. Los equivalentes de API REST para estas operaciones de administración se están construyendo en projectforge-rest (ver SystemAdminPageRest). Una vez que la capa REST cubra todas las operaciones de administración, esta página puede ser reemplazada por un panel de administración basado en React.