EN · DE · RU · FR · ES

#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

GroupActionsRequires
ConfigurationRe-read config XML from disk, export config as properties, export 2FA configurationAdmin access
CachesRefresh all caches (address, user, group, i18n, system info, etc.)Admin access
Database ActionsUpdate all user XML preferences, create missing DB indices, dump database, schema export, optimize address images (shrink + recreate previews)Admin access
System CheckRun integrity check (validates DB consistency, foreign keys, orphaned records)Admin access
Developmenti18n key validation, UserGroupCache JSON debug export, DatabaseTester, Hibernate Search reindex, create test data (100 BookDO objects), system alert message, dump system config, show database updatesAdmin + 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

ImportRole
ConfigXml, ConfigurationRead/write system configuration (reread, export)
SystemServiceCache refresh, system integrity check
DatabaseServiceCreate indices, dump DB, schema export
DatabaseTesterDevelopment: test database operations
AddressImageDaoDatabase: shrink and recreate address images
UserXmlPreferencesCache, UserXmlPreferencesMigrationDaoDatabase: update user preferences XML
HibernateSearchReindexerDevelopment: rebuild Lucene search index
BookDao, BookDODevelopment: create test book objects
I18nHelperDevelopment: validate i18n key usage
CronSanityCheckJobDevelopment: trigger nightly sanity check manually
SystemAlertMessage, SystemStatusDevelopment: set/check system-wide alert banner
WicketUtils, DownloadUtilsUI: 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

CommitWhat changed
868d6abb7Copyright 2025→2026.
eeaafe0dfAdded 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.
ab200b126Auto-shrink address images. The optimization action now automatically shrinks images that are too large, not just offers the option.
5b042ab5fAdded 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.
b309e9be9Mail attachment improvements (BirthdayButler, Polls). Automatic email notification when nightly sanity check finds errors.
092dbf9c5SystemService migrated to Kotlin. Package renamed from systeminfo to system.
619985f48Release 8.1 preparations — PR #247 merge, various stabilizations.
1b50060c3BaseDao method rename: getfind, saveinsert, getListselect, loadselect. All callers updated — AdminPage's DAO calls use the new names.
a72903e36StringBufferStringBuilder migration across all Java/Kotlin files. Performance: StringBuilder is not synchronized, StringBuffer is.
3aeda5ef5Transaction handling refactored. *InTrans suffix removed from DAO methods. PfPersistenceContext no longer passed as parameter — uses ThreadLocal instead.
b095e6f7dMajor 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.