#2857: AdminPage.java
projectforge-wicket/src/main/java/org/projectforge/web/admin/AdminPage.java Apache Wicket page — system administration dashboard. Source: projectforge-wicket/src/main/java/org/projectforge/web/admin/AdminPage.java · ~590 lines 590 lines · 502 code · 43 comments · 45 blank
The central administration page accessible only to users with admin privileges. Provides system-level operations grouped into five menu categories: Configuration (re-read config XML, export config, export 2FA settings), Caches (refresh all caches), Database Actions (update user preferences, create missing indices, dump database, schema export, optimize address images), System Check (integrity verification), and Development (i18n key validation, UserGroupCache debug, Hibernate Search reindexing, test data generation, system alerts). The Development menu is only visible when SystemStatus.isDevelopmentMode() is true.
Architecture
Extends AbstractStandardFormPage and implements ISelectCallerPage (for calendar-based date selection). The page uses ProjectForge's content menu pattern: each action group is a ContentMenuEntryPanel with sub-menu entries, each containing a Wicket Link whose onClick() delegates to a private method.
The page also contains an AdminForm component (the body of the page) which provides additional UI elements like the system info panel, update checker, and log viewer.
Static endpoint injection via set(IProjectForgeEndpoints) — not constructor injection but a static setter. This is a legacy pattern: the projectForgeEndpoints field provides access to system info (version, build date, memory stats) that is displayed on the admin form. The static setter is called by the Wicket application initializer.
Menu Groups
| Group | Actions | Requires |
| Configuration | Re-read config XML from disk, export config as properties, export 2FA configuration | Admin access |
| Caches | Refresh all caches (address, user, group, i18n, system info, etc.) | Admin access |
| Database Actions | Update all user XML preferences, create missing DB indices, dump database, schema export, optimize address images (shrink + recreate previews) | Admin access |
| System Check | Run integrity check (validates DB consistency, foreign keys, orphaned records) | Admin access |
| Development | i18n key validation, UserGroupCache JSON debug export, DatabaseTester, Hibernate Search reindex, create test data (100 BookDO objects), system alert message, dump system config, show database updates | Admin + SystemStatus.isDevelopmentMode() |
Access Control
The page overrides onBeforeRender() to call checkAccess() — a method inherited from AbstractStandardFormPage that verifies the current user has the ADMIN role. If not, the user is redirected to an access-denied page. This is the only authorization check — there is no fine-grained per-action authorization; any admin can perform any operation on this page.
The Development menu has an additional guard: if (SystemStatus.isDevelopmentMode() == false) return; at the end of addDevelopmentMenu(). This means development actions are not just hidden — their menu entries are never added to the page at all when not in dev mode.
Key Dependencies
| Import | Role |
ConfigXml, Configuration | Read/write system configuration (reread, export) |
SystemService | Cache refresh, system integrity check |
DatabaseService | Create indices, dump DB, schema export |
DatabaseTester | Development: test database operations |
AddressImageDao | Database: shrink and recreate address images |
UserXmlPreferencesCache, UserXmlPreferencesMigrationDao | Database: update user preferences XML |
HibernateSearchReindexer | Development: rebuild Lucene search index |
BookDao, BookDO | Development: create test book objects |
I18nHelper | Development: validate i18n key usage |
CronSanityCheckJob | Development: trigger nightly sanity check manually |
SystemAlertMessage, SystemStatus | Development: set/check system-wide alert banner |
WicketUtils, DownloadUtils | UI: JavaScript confirm dialogs, file download triggers |
Design Patterns
Content Menu Pattern: Instead of a flat list of buttons, the admin page uses a hierarchical menu structure. Each group (ContentMenuEntryPanel) contains sub-menu entries, each with a Wicket Link. This allows organizing 20+ admin actions into logical categories without overwhelming the user.
Anonymous inner class Links: Each action is a new Link<Void>() { onClick() { ... } } — anonymous inner classes that delegate to private methods. This is standard Wicket pre-Java-8 style. A modern rewrite would use lambda expressions (Link<Void> link = new Link<>(id) { ... } can't be a lambda because Link is a class, not a functional interface).
Static endpoint injection: projectForgeEndpoints is a static field set via a static setter. This is unusual in a Spring-managed application and exists because AdminPage is a Wicket page (not a Spring bean) and needs access to system-level information that's normally provided by Spring services. The static setter is called from the Wicket application init.
Git History
| Commit | What changed |
868d6abb7 | Copyright 2025→2026. |
eeaafe0df | Added address image optimization menu. New "Optimize address images" action in Database menu. Minimizes address image file sizes (JPEG compression ~100KB) and recalculates preview thumbnails. Includes JavaScript confirmation dialog. |
ab200b126 | Auto-shrink address images. The optimization action now automatically shrinks images that are too large, not just offers the option. |
5b042ab5f | Added UserGroupCache debug export and DatabaseTester. New "Debug UserGroupCache" action in Development menu — exports cache state as JSON for offline analysis. New DatabaseTester action for development stress-testing. Added Jackson Hibernate6 module registration for JSON serialization of Hibernate proxies. |
b309e9be9 | Mail attachment improvements (BirthdayButler, Polls). Automatic email notification when nightly sanity check finds errors. |
092dbf9c5 | SystemService migrated to Kotlin. Package renamed from systeminfo to system. |
619985f48 | Release 8.1 preparations — PR #247 merge, various stabilizations. |
1b50060c3 | BaseDao method rename: get→find, save→insert, getList→select, load→select. All callers updated — AdminPage's DAO calls use the new names. |
a72903e36 | StringBuffer→StringBuilder migration across all Java/Kotlin files. Performance: StringBuilder is not synchronized, StringBuffer is. |
3aeda5ef5 | Transaction handling refactored. *InTrans suffix removed from DAO methods. PfPersistenceContext no longer passed as parameter — uses ThreadLocal instead. |
b095e6f7d | Major transaction handling change. Reuses PfPersistenceContext. Tests were broken at this point (not yet fixed). |
Caution: This page has no per-action authorization. Any user with admin access can trigger database dumps, schema exports, Hibernate reindexing, and test data creation — all on the production database. The Development menu is gated by SystemStatus.isDevelopmentMode() but that's a single boolean flag with no further granularity.
Migration path: This is one of the oldest pages still on Wicket. The REST API equivalents for these admin operations are being built in projectforge-rest (see SystemAdminPageRest). Once the REST layer covers all admin operations, this page can be replaced with a React-based admin dashboard.