Package com.oorian

Class Application

java.lang.Object
com.oorian.Application
All Implemented Interfaces:
jakarta.servlet.ServletContextListener, EventListener

public abstract class Application extends Object implements jakarta.servlet.ServletContextListener
The Application class serves as the main entry point and configuration hub for the Oorian web framework. It provides automatic discovery and registration of page classes and CSS files using annotation-based configuration.

This abstract class must be extended by applications using the Oorian framework to provide custom initialization and destruction logic. It handles the registration of servlets, scanning of packages for annotated classes, and management of page routing.

Since:
2020
Version:
1.0
Author:
Marvin P. Warble Jr.
  • Field Details

    • PAGE_STORE

      public static final String PAGE_STORE
      The servlet context attribute key for storing page information.
      See Also:
  • Constructor Details

    • Application

      protected Application()
      Protected constructor for Application. Subclasses should call this constructor to initialize the application.
  • Method Details

    • getInstance

      public static Application getInstance()
      Gets the singleton instance of the Application.
      Returns:
      the current Application instance
    • contextInitialized

      public final void contextInitialized(jakarta.servlet.ServletContextEvent sce)
      Called when the servlet context is initialized. This method performs automatic discovery and registration of page and CSS classes.
      Specified by:
      contextInitialized in interface jakarta.servlet.ServletContextListener
      Parameters:
      sce - the ServletContextEvent containing the servlet context
    • contextDestroyed

      public final void contextDestroyed(jakarta.servlet.ServletContextEvent sce)
      Called when the servlet context is destroyed. This method performs cleanup by calling the destroy method.
      Specified by:
      contextDestroyed in interface jakarta.servlet.ServletContextListener
      Parameters:
      sce - the ServletContextEvent containing the servlet context
    • getPages

      public static List<PageInfo> getPages()
      Gets the list of all registered page information.
      Returns:
      list of PageInfo objects for all registered pages
    • getPageInfo

      public static PageInfo getPageInfo(Class pageClass)
      Gets the PageInfo object for a specific page class.
      Parameters:
      pageClass - the page class to get information for
      Returns:
      the PageInfo object for the specified class, or null if not found
    • initialize

      protected abstract void initialize(AppContext appContext)
      Called during application initialization to perform custom setup. Subclasses must implement this method to provide application-specific initialization.
      Parameters:
      appContext - the application context
    • destroy

      protected abstract void destroy(AppContext appContext)
      Called during application destruction to perform custom cleanup. Subclasses must implement this method to provide application-specific cleanup.
      Parameters:
      appContext - the application context
    • registerPackage

      protected final void registerPackage(String packageName)
      Registers a package to be scanned for annotated classes.
      Parameters:
      packageName - the name of the package to register
    • setTempFilePath

      protected void setTempFilePath(String path)
      Sets the temporary file path for file uploads and processing.
      Parameters:
      path - the path to use for temporary files
    • setDefaultCommunicationMode

      protected void setDefaultCommunicationMode(CommunicationMode mode)
      Sets the default communication mode for all pages in the application.

      Individual pages can override this default by calling HtmlPage.setCommunicationMode(CommunicationMode).

      Parameters:
      mode - The default communication mode to use (cannot be APP_DEFAULT).
    • getDefaultCommunicationMode

      public CommunicationMode getDefaultCommunicationMode()
      Gets the default communication mode for all pages in the application.
      Returns:
      The default communication mode.
    • setDefaultPollInterval

      protected void setDefaultPollInterval(long interval)
      Sets the default poll interval for AJAX_ONLY mode.

      When the communication mode is AJAX_ONLY, this interval determines how often the client will poll the server for pending updates. A value of 0 disables polling.

      Individual pages can override this default by calling HtmlPage.setPollInterval(long).

      Parameters:
      interval - The default polling interval in milliseconds (0 = disabled).
      See Also:
    • getDefaultPollInterval

      public long getDefaultPollInterval()
      Gets the default poll interval for AJAX_ONLY mode.
      Returns:
      The default polling interval in milliseconds (0 = disabled).
    • setCsrfProtectionEnabled

      protected void setCsrfProtectionEnabled(boolean enabled)
      Enables or disables CSRF (Cross-Site Request Forgery) protection for the entire application.

      When enabled (the default), all AJAX and WebSocket requests must include a valid CSRF token that matches the token stored in the user's session. This prevents malicious websites from making unauthorized requests on behalf of authenticated users.

      CSRF protection is enabled by default. You should only disable it if you have implemented an alternative protection mechanism or if your application does not require it (e.g., public read-only APIs).

      Usage:

      
       public class MyApplication extends Application {
           @Override
           protected void initialize(AppContext appContext) {
               // Disable CSRF protection (not recommended for production)
               setCsrfProtectionEnabled(false);
      
               registerPackage("com.mycompany.pages");
           }
       }
       
      Parameters:
      enabled - true to enable CSRF protection (default), false to disable.
      See Also:
    • isCsrfProtectionEnabled

      public boolean isCsrfProtectionEnabled()
      Checks whether CSRF protection is enabled for the application.
      Returns:
      true if CSRF protection is enabled, false otherwise.
    • setAccessLoggingEnabled

      protected void setAccessLoggingEnabled(boolean enabled)
      Enables or disables HTTP access logging.

      When enabled, every HTTP request processed by the framework is logged in the configured format (Common Log Format or Combined Log Format). Output is directed through the JDK System.Logger SPI under the logger name com.oorian.access.

      Usage:

      
       setAccessLoggingEnabled(true);
       setAccessLogFormat(AccessLogFormat.COMBINED);
       
      Parameters:
      enabled - true to enable access logging, false to disable.
      See Also:
    • setAccessLogFormat

      protected void setAccessLogFormat(AccessLogFormat format)
      Sets the format for HTTP access logging.

      The default format is AccessLogFormat.COMBINED.

      Parameters:
      format - the log format to use
      See Also:
    • setSecurityAuditLoggingEnabled

      protected void setSecurityAuditLoggingEnabled(boolean enabled)
      Enables or disables security audit logging.

      When enabled, security-related events (authentication, authorization, session lifecycle, rate limiting, etc.) are logged through the JDK System.Logger SPI under the logger name com.oorian.security.audit.

      Usage:

      
       setSecurityAuditLoggingEnabled(true);
       
      Parameters:
      enabled - true to enable security audit logging, false to disable.
      See Also:
    • setBruteForceProtection

      protected void setBruteForceProtection(BruteForceConfig config)
      Configures brute-force protection for the application.

      When enabled, failed authentication attempts can be tracked per username or IP address. After the configured number of failed attempts, the key is locked out for the specified duration. Optionally, progressive delays (exponential backoff) can be applied between attempts.

      Usage:

      
       setBruteForceProtection(BruteForceConfig.create()
           .maxAttempts(5)
           .lockoutDurationMillis(15 * 60 * 1000)
           .progressiveDelay(true));
       

      Once configured, use BruteForceProtection.getInstance() to access the protection instance from your authentication logic.

      Parameters:
      config - the brute-force configuration
      See Also:
    • setUrlSecurityKey

      protected void setUrlSecurityKey(String key)
      Sets the secret key used for URL signing and encryption.

      This key is used by UrlSecurity for both HMAC-based URL signing and AES-GCM URL encryption. The key string is hashed with SHA-256 to derive a consistent 256-bit key, so the input can be any length.

      Usage:

      
       setUrlSecurityKey("my-application-secret-key");
       
      Parameters:
      key - the secret key string (must not be null or empty)
      See Also:
    • setFileUploadConfig

      protected void setFileUploadConfig(FileUploadConfig config)
      Sets the file upload security configuration.

      When configured, uploaded files are validated against the specified policies including file size limits, allowed extensions, allowed MIME types, and optional magic number (file signature) validation.

      Usage:

      
       setFileUploadConfig(FileUploadConfig.create()
           .maxFileSize(10 * 1024 * 1024)         // 10 MB
           .allowExtensions("jpg", "png", "pdf")
           .allowMimeTypes("image/jpeg", "image/png", "application/pdf")
           .validateMagicNumbers(true));
       
      Parameters:
      config - the file upload security configuration
      See Also:
    • setSecurityHeaders

      protected void setSecurityHeaders(SecurityHeaders securityHeaders)
      Sets the security response headers that will be applied to every HTTP response.

      Use SecurityHeaders.production() for OWASP-recommended defaults, or build a custom configuration:

      
       // Production defaults
       setSecurityHeaders(SecurityHeaders.production());
      
       // Custom configuration
       setSecurityHeaders(new SecurityHeaders()
           .contentTypeOptions()
           .frameOptions(SecurityHeaders.FrameOption.SAMEORIGIN)
           .hstsMaxAge(31536000, true)
           .referrerPolicy(SecurityHeaders.ReferrerPolicy.STRICT_ORIGIN));
       
      Parameters:
      securityHeaders - the security headers configuration
      See Also:
    • setDefaultIdleTimeout

      protected void setDefaultIdleTimeout(long millis)
      Sets the application-wide idle session timeout.

      Sessions with no activity for longer than this duration are considered expired. A value of 0 disables idle timeout (the default), deferring to the servlet container's session timeout configuration.

      Expired sessions are checked on each request in the Oorian filter. When a session is found to be expired, it is invalidated and the request receives a 401 response.

      Parameters:
      millis - the idle timeout in milliseconds (0 = disabled)
      See Also:
    • setDefaultAbsoluteTimeout

      protected void setDefaultAbsoluteTimeout(long millis)
      Sets the application-wide absolute session timeout.

      Sessions older than this duration are considered expired regardless of activity. A value of 0 disables absolute timeout (the default).

      Parameters:
      millis - the absolute timeout in milliseconds (0 = disabled)
      See Also:
    • setMaxConcurrentSessions

      protected void setMaxConcurrentSessions(int max)
      Sets the maximum number of concurrent sessions allowed per user.

      When a user exceeds this limit, the oldest session is automatically invalidated. A value of 0 means unlimited (the default).

      Users are identified by the user ID set via OorianSession.setUserId(String). Concurrent session control only takes effect after a user ID is assigned.

      Parameters:
      max - the maximum concurrent sessions per user (0 = unlimited)
      See Also:
    • setDefaultRateLimit

      protected void setDefaultRateLimit(int maxRequests, long windowMillis)
      Sets the application-wide default rate limit for requests per session.

      When enabled, each session is limited to the specified number of requests within the given time window. Requests exceeding the limit receive HTTP 429 (Too Many Requests) for page requests, or have their WebSocket messages dropped.

      Rate limiting is disabled by default (maxRequests = 0).

      Usage:

      
       // Allow 100 requests per minute
       setDefaultRateLimit(100, 60000);
       
      Parameters:
      maxRequests - the maximum number of requests per window (0 = disabled)
      windowMillis - the time window duration in milliseconds
    • setMaxConnectionsPerSession

      protected void setMaxConnectionsPerSession(int max)
      Sets the maximum number of concurrent WebSocket connections allowed per session.

      When a user attempts to open more WebSocket connections than the limit, the new connection is rejected. A value of 0 means unlimited (the default).

      Parameters:
      max - the maximum connections per session (0 = unlimited)
    • setMaxConnectionsPerIp

      protected void setMaxConnectionsPerIp(int max)
      Sets the maximum number of concurrent WebSocket connections allowed per IP address.

      When connections from a single IP address exceed this limit, new connections are rejected. A value of 0 means unlimited (the default).

      Note: Users behind NAT or shared networks may share an IP address, so this limit should be set generously.

      Parameters:
      max - the maximum connections per IP (0 = unlimited)
    • setMaxRequestBodySize

      protected void setMaxRequestBodySize(long maxBytes)
      Sets the maximum request body size in bytes.

      HTTP requests with a Content-Length exceeding this value are rejected with HTTP 413 (Payload Too Large). A value of 0 means unlimited (the default).

      Usage:

      
       // Limit request bodies to 10 MB
       setMaxRequestBodySize(10 * 1024 * 1024);
       
      Parameters:
      maxBytes - the maximum request body size in bytes (0 = unlimited)
    • setHttpsRequired

      protected void setHttpsRequired(boolean required)
      Enables or disables HTTPS enforcement for the entire application.

      When enabled, all HTTP requests are automatically redirected to their HTTPS equivalent using a 301 (Moved Permanently) response. This ensures all traffic is encrypted in transit.

      The redirect logic handles the following scenarios:

      • Direct HTTPS: Checks request.isSecure()
      • Behind a load balancer/proxy: Checks the X-Forwarded-Proto header
      • Localhost exception: Requests to localhost and 127.0.0.1 are never redirected, allowing local development without HTTPS

      Usage:

      
       @Override
       protected void initialize(AppContext appContext) {
           setHttpsRequired(true);
           registerPackage("com.mycompany.pages");
       }
       
      Parameters:
      required - true to enforce HTTPS (redirect HTTP to HTTPS), false to allow HTTP (default).
    • isHttpsRequired

      public boolean isHttpsRequired()
      Checks whether HTTPS enforcement is enabled for the application.
      Returns:
      true if HTTPS is required, false otherwise.
    • setSecureCookieDefaults

      protected void setSecureCookieDefaults(CookieDefaults defaults)
      Configures application-wide secure cookie defaults for session cookies and application cookies.

      When set, the servlet container's session cookie is automatically configured with the specified attributes (HttpOnly, Secure, SameSite), and all new OorianCookie instances inherit these defaults.

      Usage:

      
       // In Application.initialize() — enable with defaults (HttpOnly=true, Secure=false, SameSite=Lax)
       setSecureCookieDefaults(new CookieDefaults());
      
       // Or customize
       CookieDefaults defaults = new CookieDefaults();
       defaults.setSecure(true);
       defaults.setSameSite(CookieDefaults.SameSite.STRICT);
       setSecureCookieDefaults(defaults);
       
      Parameters:
      defaults - The cookie defaults configuration, or null to disable.
      See Also:
    • getSecureCookieDefaults

      public CookieDefaults getSecureCookieDefaults()
      Gets the application-wide secure cookie defaults.
      Returns:
      The cookie defaults configuration, or null if not configured.
    • addAllowedOrigin

      protected void addAllowedOrigin(String origin)
      Adds an allowed origin for WebSocket connections.

      When at least one origin is configured, the framework validates the Origin header during the WebSocket handshake and rejects connections from unlisted origins. This prevents cross-site WebSocket hijacking attacks.

      Supports exact matches and wildcard subdomain patterns:

      
       addAllowedOrigin("https://myapp.com");
       addAllowedOrigin("https://*.myapp.com");
       
      Parameters:
      origin - the allowed origin URL
    • setMaxWebSocketMessageSize

      protected void setMaxWebSocketMessageSize(int size)
      Sets the maximum WebSocket text message size in bytes.

      Messages exceeding this size will be rejected by the WebSocket container. The default is 1,000,000 bytes (approximately 1 MB).

      Parameters:
      size - the maximum message size in bytes
    • setContentSecurityPolicy

      protected void setContentSecurityPolicy(ContentSecurityPolicy csp)
      Sets an application-wide Content Security Policy that is applied as an HTTP response header to every request.

      This enforces the policy by sending the Content-Security-Policy header. Browsers will block any content that violates the policy.

      Usage:

      
       ContentSecurityPolicy csp = new ContentSecurityPolicy();
       csp.addDefaultSrc(ContentSecurityPolicy.SELF);
       csp.addScriptSrc(ContentSecurityPolicy.SELF, "https://cdn.example.com");
       csp.addStyleSrc(ContentSecurityPolicy.SELF, ContentSecurityPolicy.UNSAFE_INLINE);
       setContentSecurityPolicy(csp);
       
      Parameters:
      csp - The Content Security Policy configuration, or null to disable.
      See Also:
    • setContentSecurityPolicy

      protected void setContentSecurityPolicy(ContentSecurityPolicy csp, boolean reportOnly)
      Sets an application-wide Content Security Policy with the option to use report-only mode.

      When reportOnly is true, the policy is sent via the Content-Security-Policy-Report-Only header. Violations are reported but not blocked, which is useful for testing a policy before enforcing it.

      Parameters:
      csp - The Content Security Policy configuration, or null to disable.
      reportOnly - true to report violations without blocking, false to enforce the policy (default).
      See Also:
    • getContentSecurityPolicy

      public ContentSecurityPolicy getContentSecurityPolicy()
      Gets the application-wide Content Security Policy.
      Returns:
      The Content Security Policy configuration, or null if not configured.
    • setSecurityHandler

      protected void setSecurityHandler(SecurityHandler handler)
      Sets the security handler for authentication and authorization checks.

      The security handler is invoked when pages are annotated with RequiresAuth, RequiresRole, or RequiresPermission. If no security handler is set but security annotations are used, access will be denied with a 403 response.

      Parameters:
      handler - the security handler implementation
      See Also:
    • setAuthenticator

      protected void setAuthenticator(OorianAuthenticator authenticator)
      Sets the authenticator used for credential verification.

      The authenticator is called when the application needs to verify user credentials during login. Register it during application initialization.

      Usage:

      
       @Override
       protected void initialize(AppContext appContext)
       {
           setAuthenticator(new MyAuthenticator());
           setLoginPage("/login");
           registerPackage("com.mycompany.pages");
       }
       
      Parameters:
      authenticator - the authenticator implementation
      See Also:
    • getAuthenticator

      public static OorianAuthenticator getAuthenticator()
      Returns the configured authenticator.
      Returns:
      the authenticator, or null if none is configured
    • setLoginPage

      protected void setLoginPage(String path)
      Sets the login page path for authentication redirects.

      When an unauthenticated user accesses a page annotated with RequiresAuth, they are redirected to this path. The original URL is appended as a redirect query parameter so the application can redirect the user back after successful authentication.

      Parameters:
      path - the URL path of the login page (e.g., "/login")
    • getLoginPage

      public static String getLoginPage()
      Returns the configured login page path.
      Returns:
      the login page path, or null if none is configured
    • setErrorPage

      protected void setErrorPage(int statusCode, Class pageClass)
      Registers a custom error page for a specific HTTP status code.

      When the framework encounters an error with the specified status code, it will render the registered page instead of the default behavior. The error page can access error details via ErrorContext.current().

      Usage:

      
       @Override
       protected void initialize(AppContext appContext) {
           setErrorPage(404, NotFoundPage.class);
           setErrorPage(500, ServerErrorPage.class);
           registerPackage("com.mycompany.pages");
       }
       
      Parameters:
      statusCode - the HTTP status code (e.g., 400, 401, 403, 404, 500, 503)
      pageClass - the error page class to render for this status code
      See Also:
    • setDefaultErrorPage

      protected void setDefaultErrorPage(Class pageClass)
      Registers a default error page used when no status-code-specific error page is found.

      This catch-all error page is rendered for any error status code that does not have a specific error page registered via setErrorPage(int, Class).

      Parameters:
      pageClass - the default error page class
      See Also:
    • setExceptionHandler

      protected void setExceptionHandler(ExceptionHandler handler)
      Registers a centralized exception handler for the application.

      The handler is invoked whenever an uncaught exception occurs during page creation (createHead(), createBody()), event handler processing, or background worker thread execution. After the handler is invoked, the framework continues with its default error behavior.

      Usage:

      
       @Override
       protected void initialize(AppContext appContext) {
           setExceptionHandler((exception, page) -> {
               MonitoringService.reportError(exception);
           });
           registerPackage("com.mycompany.pages");
       }
       
      Parameters:
      handler - the exception handler
      See Also:
    • setDevMode

      protected void setDevMode(boolean enabled)
      Enables or disables development mode for the application.

      In development mode, the built-in error pages display detailed diagnostic information including stack traces, exception class names, request paths, and other internal details to help with debugging. In production mode (the default), only user-friendly messages are shown to avoid leaking internal details.

      Dev mode can also be activated via the system property oorian.mode=dev, which takes effect at class loading time. Calling this method overrides the system property setting.

      Usage:

      
       @Override
       protected void initialize(AppContext appContext) {
           setDevMode(true);
           registerPackage("com.mycompany.pages");
       }
       
      Parameters:
      enabled - true to enable development mode, false for production mode.
    • setOorianScript

      protected void setOorianScript(String path)
      Sets the application-wide path to the Oorian client-side JavaScript file.

      By default, Oorian loads /oorian.min.js. Call this method in

      invalid reference
      #initialize(jakarta.servlet.ServletContext)
      to use a versioned or relocated filename instead. The path should be the full path including the filename, relative to the application context root.

      Individual pages can override this default via HtmlPage.setOorianScriptPath(String).

      Usage:

      
       @Override
       protected void initialize(AppContext appContext) {
           setOorianScript("/oorian-core-2.0.500.js");
           registerPackage("com.mycompany.pages");
       }
       
      Parameters:
      path - the path to the Oorian JavaScript file (e.g., "/oorian-core-2.0.500.js").
    • isDevMode

      public boolean isDevMode()
      Checks whether development mode is enabled.
      Returns:
      true if development mode is active, false otherwise.
    • setProfile

      protected void setProfile(String profile)
      Sets the active configuration profile for the application.

      The profile determines which profile-specific configuration file is loaded (e.g., oorian-dev.properties for the "dev" profile). Profile-specific properties override values from the base oorian.properties.

      This method must be called early in initialize(AppContext), before any configuration values are accessed. The profile can also be set via the system property oorian.profile or the environment variable OORIAN_PROFILE.

      Usage:

      
       @Override
       protected void initialize(AppContext appContext) {
           setProfile("dev");
           registerPackage("com.mycompany.pages");
       }
       
      Parameters:
      profile - the profile name (e.g., "dev", "staging", "prod")
      See Also:
    • getConfig

      public static OorianConfig getConfig()
      Returns the application configuration loaded from oorian.properties.

      This is a convenience method equivalent to OorianConfig.get(). The configuration is loaded from the classpath before initialize(AppContext) is called, so it is safe to use config values during initialization.

      Returns:
      the application configuration
      See Also: