This comprehensive checklist helps prevent 500 Internal Server Errors and Java exceptions in the IoTBay web application. Use this checklist during pre-deployment QA and CI/CD pipeline validation.
Quick Start - Automated Validation:
.\scripts\validate-500-prevention.ps1 -VerboseThis will automatically check many items in this checklist. See scripts/README.md for details.
Priority Levels:
- 🔴 Critical: Must be checked before any deployment
- 🟠High: Should be verified in most deployments
- 🟡 Medium: Recommended for production deployments
- 🟢 Low: Best practice improvements
- 🔴 All method parameters are null-checked before use
- 🔴 All database query results are null-checked before accessing fields
- 🔴 Session attributes are null-checked before casting (e.g.,
session.getAttribute("user")) - 🔴 Request parameters are validated before use (use
SecurityUtil.getValidatedStringParameter()) - 🔴 Collection operations check for null collections before iteration
- 🟠Optional values use
Optional<T>or explicit null checks - 🟡 String operations check for null/empty before
equals(),contains(), etc.
Example Pattern:
User user = (User) session.getAttribute("user");
if (user == null) {
response.sendRedirect("/login.jsp");
return;
}- 🔴 All database connections use try-with-resources or are properly closed in finally blocks
- 🔴 PreparedStatement objects are closed (preferably via try-with-resources)
- 🔴 ResultSet objects are closed (preferably via try-with-resources)
- 🔴 File streams (InputStream, OutputStream) are closed properly
- 🔴 Connection pool connections are returned to pool after use
- 🟠Verify ConnectionPool.releaseConnection() is called in all code paths
- 🟡 Check for connection leaks in long-running operations
Current Pattern (Good):
try (PreparedStatement statement = connection.prepareStatement(query)) {
// ... operations
}- 🔴 All user inputs are validated using
SecurityUtil.getValidatedStringParameter() - 🔴 Numeric inputs use
SecurityUtil.getValidatedIntParameter()orgetValidatedDoubleParameter() - 🔴 Input length limits are enforced (e.g., email max 100 chars, name max 50 chars)
- 🔴 Email format validation using
ValidationUtil.validateEmail() - 🔴 Password strength validation using
SecurityUtil.isStrongPassword() - 🔴 Date format validation with proper exception handling
- 🟠Input sanitization using
SecurityUtil.sanitizeInput()for display - 🟡 SQL injection prevention: all queries use PreparedStatement (never string concatenation)
Example Pattern:
String email = SecurityUtil.getValidatedStringParameter(request, "email", 100);
if (email == null) {
ErrorAction.handleValidationError(request, response, "Email is required", "ControllerName");
return;
}- 🔴 All casts are checked with
instanceofbefore casting - 🔴 Session attribute casts are validated (e.g.,
Userfrom session) - 🔴 Number parsing (Integer.parseInt, Double.parseDouble) wrapped in try-catch
- 🟠Generic types are properly parameterized (no raw types)
- 🟡 Avoid unsafe casts; use type-safe alternatives where possible
Example Pattern:
Object userObj = session.getAttribute("user");
if (userObj instanceof User) {
User user = (User) userObj;
// ... use user
}- 🔴 Collections are initialized before use (avoid NullPointerException)
- 🔴 Iteration checks for null elements in collections
- 🔴 ConcurrentModificationException prevention: use iterator or concurrent collections
- 🟠Empty collections return empty list/map, not null
- 🟡 Large collections use pagination to prevent memory issues
- 🟠Shared mutable state is synchronized or uses thread-safe collections
- 🟠Static variables are thread-safe or properly synchronized
- 🟡 ConnectionPool singleton pattern is thread-safe (verified)
- 🔴 All database operations wrapped in try-catch blocks
- 🔴 All servlet doGet/doPost methods have catch-all exception handlers
- 🔴 File I/O operations have exception handling
- 🔴 JSON parsing operations (Gson) have exception handling
- 🟠Network operations (if any) have timeout and exception handling
- 🟡 All public methods that can throw checked exceptions document them
Example Pattern:
try {
// ... operation
} catch (SQLException e) {
ErrorAction.handleDatabaseError(request, response, e, "ControllerName.methodName");
} catch (Exception e) {
ErrorAction.handleServerError(request, response, e, "ControllerName.methodName");
}- 🟡 Custom exceptions extend appropriate base exceptions
- 🟡 Exceptions include contextual information (user ID, operation, etc.)
- 🟢 Exception messages don't expose sensitive information
- 🔴 All errors use
ErrorActionutility methods (not direct error responses) - 🔴 Generic error messages returned to clients (no stack traces)
- 🔴 Proper HTTP status codes set (400, 401, 403, 500, etc.)
- 🔴 Error page forwarding has fallback to
sendError()if forwarding fails - 🟠JSON API endpoints return consistent error format
- 🟡 Error responses include request ID for tracking (if implemented)
Current Pattern (Good):
ErrorAction.handleDatabaseError(request, response, e, "ControllerName.methodName");- 🟠Non-critical operations fail gracefully without breaking main flow
- 🟠Access log failures don't prevent user operations
- 🟡 Feature flags or fallbacks for optional features
- 🔴 Database errors use
ErrorAction.handleDatabaseError() - 🔴 Validation errors use
ErrorAction.handleValidationError() - 🔴 Authentication errors use
ErrorAction.handleAuthenticationError() - 🔴 Authorization errors use
ErrorAction.handleAuthorizationError() - 🔴 Server errors use
ErrorAction.handleServerError() - 🟠Missing parameters use
ErrorAction.handleMissingParameterError() - 🟠Invalid input uses
ErrorAction.handleInvalidInputError()
- 🔴 ConnectionPool is properly initialized before use
- 🔴 Connections are obtained from pool (not direct DriverManager)
- 🔴 Connections are returned to pool in finally blocks
- 🔴 Connection pool size is appropriate for expected load (currently 10)
- 🟠Connection pool monitoring/logging for pool exhaustion
- 🟡 Connection pool configuration is externalized (not hardcoded)
Current Implementation:
- ConnectionPool with size 10
- DBConnection for direct connections (verify usage)
- 🔴 All SQL queries use PreparedStatement (never string concatenation)
- 🔴 All user inputs are parameterized (no direct SQL string building)
- 🔴 Dynamic SQL queries (if any) use whitelist validation
- 🟡 SQL query patterns reviewed for injection vulnerabilities
Current Pattern (Good):
String query = "SELECT * FROM Users WHERE email = ?";
try (PreparedStatement statement = connection.prepareStatement(query)) {
statement.setString(1, email);
// ...
}- 🟠Multi-step operations use transactions where appropriate
- 🟠Transaction rollback on errors
- 🟡 Transaction timeout configuration
- 🔴 All ResultSet objects use try-with-resources
- 🔴 All PreparedStatement objects use try-with-resources
- 🔴 Nested try-with-resources properly structured
- 🟠ResultSet iteration checks
rs.next()before accessing columns
Current Pattern (Good):
try (PreparedStatement statement = connection.prepareStatement(query);
ResultSet rs = statement.executeQuery()) {
while (rs.next()) {
// ... process results
}
}- 🟠Connection timeout configured in connection string or properties
- 🟠Query timeout set on PreparedStatement for long-running queries
- 🟡 Connection retry logic for transient failures
- 🔴 SQLite database file path is correct and writable
- 🔴 SQLite database file permissions are set correctly
- 🟠SQLite WAL mode enabled for better concurrency (if needed)
- 🟠SQLite connection limits understood (SQLite has limited concurrent writes)
- 🟡 Database file backup strategy in place
- 🟡 Database file size monitoring (SQLite can grow large)
Current Configuration:
- Database:
jdbc:sqlite:iotbay.db - Driver:
org.sqlite.JDBC
- 🔴 All classes use
Logger.getLogger(ClassName.class.getName()) - 🔴 Logger instances are static final
- 🟠Logging configuration file (logging.properties) exists and is configured
- 🟡 Log levels appropriate for production (INFO/WARNING/SEVERE, not FINE/FINER)
Current Pattern:
private static final Logger logger = Logger.getLogger(ClassName.class.getName());- 🔴 SEVERE: Used for exceptions and critical errors
- 🟠WARNING: Used for validation errors, security events, recoverable issues
- 🟠INFO: Used for important business events (user login, order creation)
- 🟡 FINE/FINER: Used for debugging (disabled in production)
Example Pattern:
logger.log(Level.SEVERE, "Database error in context", e);
logger.warning("Validation error: " + errorMessage);
logger.info("User logged in: " + email);- 🔴 All caught exceptions log full stack trace with
logger.log(Level.SEVERE, message, exception) - 🔴 Contextual information included in log messages (IP, user, operation)
- 🟠ErrorAction methods log detailed information for administrators
- 🟡 Stack traces never exposed to end users (only in logs)
Current Pattern (Good):
logger.log(Level.SEVERE,
String.format("[DATABASE_ERROR] Context: %s, IP: %s", logContext, getClientIP(request)),
e);- 🟠Logs include request context (IP address, user, endpoint)
- 🟠Logs include operation context (method name, parameters)
- 🟡 Request ID or correlation ID for tracing (if implemented)
- 🟡 User ID included in security-relevant logs
- 🟡 Log file rotation configured (size-based or time-based)
- 🟡 Log file retention policy defined
- 🟡 Log file location is writable and has sufficient disk space
- 🟢 Log aggregation/monitoring tool configured (if available)
- 🟡 Development: More verbose logging enabled
- 🟡 Production: Sensitive information not logged (passwords, tokens)
- 🟡 Production: Log levels set to INFO/WARNING/SEVERE
- 🟢 Environment-specific logging configuration
- 🔴
mvn clean compilesucceeds without errors - 🔴
mvn clean packagecreates valid WAR file - 🔴 No compilation warnings (or warnings are acceptable and documented)
- ðŸŸ
mvn testpasses all unit tests - 🟡 Dependency versions are compatible (no conflicts)
- 🟡 Maven build is reproducible (same output on different machines)
Current Configuration:
- Java 8 (1.8)
- Maven compiler plugin 3.11.0
- WAR packaging
- 🔴 WAR file is properly structured (WEB-INF/classes, WEB-INF/lib, etc.)
- 🔴 All required classes are included in WAR
- 🔴 All dependencies are included in WEB-INF/lib
- 🔴 web.xml is valid and properly formatted
- 🟠WAR file size is reasonable (check for unnecessary files)
- 🟡 WAR file can be extracted and inspected
- 🔴
application.propertiesexists and is readable - 🔴 Database connection properties are correct
- 🔴 All required properties have values (no null/empty)
- 🟠Environment-specific properties validated (dev/staging/prod)
- 🟡 Configuration file encoding is UTF-8
Current Properties:
db.url,db.driversecurity.session.timeout,security.password.min.length,security.max.login.attemptsapp.name,app.version,app.environment
- 🟠Database URL points to correct environment
- 🟠Log levels appropriate for environment
- 🟠Error page behavior appropriate (dev shows details, prod generic)
- 🟡 Feature flags set correctly per environment
- 🟡 All dependencies are compatible with Java 8
- 🟡 Servlet API version compatible with server (3.1.0)
- 🟡 JSTL version compatible (1.2)
- 🟡 SQLite JDBC driver version is stable (3.49.1.0)
- 🟢 No known security vulnerabilities in dependencies
Current Dependencies:
- javax.servlet-api 3.1.0
- sqlite-jdbc 3.49.1.0
- gson 2.10.1
- JSTL 1.2
- 🔴 application.properties is in classpath (src/main/resources)
- 🔴 JSP files are in correct location (src/main/webapp)
- 🔴 Static resources (CSS, JS, images) are accessible
- 🟠Resource files use UTF-8 encoding
- 🟡 External resources (if any) are accessible from server
- 🔴 Heap size configured appropriately (-Xmx, -Xms)
- 🔴 Metaspace/PermGen configured for Java 8 (-XX:MetaspaceSize, -XX:MaxMetaspaceSize)
- 🟠OutOfMemoryError handling strategy defined
- 🟡 Heap dump configuration for OOM debugging
- 🟡 Memory monitoring enabled
Recommended Settings:
-Xmx512m -Xms256m(adjust based on application needs)-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m(Java 8)
- 🟠Max threads configured appropriately for expected load
- 🟠Min spare threads configured
- 🟡 Thread timeout configured
- 🟡 Thread pool monitoring enabled
Jetty Configuration (Development):
- Port: 8080
- Context path: /
- 🟠Connection timeout configured (default 20000ms)
- 🟠Keep-alive timeout configured
- 🟡 Request timeout configured for long-running requests
- 🔴 Session timeout configured (currently 30 minutes from application.properties)
- 🔴 Session persistence configured (if needed)
- 🟠Session cookie security settings (HttpOnly, Secure in production)
- 🟡 Session size monitoring (prevent memory issues)
Current Configuration:
security.session.timeout=30(minutes)
- 🔴 Error pages configured in web.xml (400, 404, 500, Exception)
- 🔴 Error pages exist and are accessible
- 🔴 Error pages don't expose sensitive information
- 🟠Custom error pages for different error types (if needed)
Current Configuration:
<error-page>
<error-code>500</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/error.jsp</location>
</error-page>- 🔴 Context path is correct (currently
/) - 🔴 WAR file name matches expected deployment name
- 🟠Auto-deploy settings appropriate for environment
- 🟡 Deployment descriptor (web.xml) is valid
- 🔴 Java version matches build target (Java 8 / 1.8)
- 🔴 Server Java version is compatible with application
- 🟠Java version is stable (not EOL or beta)
- 🟡 JAVA_HOME is set correctly on server
Current Target:
- Java 8 (1.8)
- Maven compiler: release 8
- 🟠GC algorithm selected appropriately (G1GC recommended for Java 8+)
- 🟠GC logging enabled for production monitoring
- 🟡 JVM tuning based on application profiling
- 🟢 JVM crash logs location configured
Recommended JVM Args:
-XX:+UseG1GC(G1 Garbage Collector)-XX:+PrintGCDetails -Xloggc:/path/to/gc.log(GC logging)
- 🟡 GC pause time targets set (if using G1GC)
- 🟡 GC heap regions configured (if using G1GC)
- 🟢 GC monitoring and alerting configured
- 🟠ClassNotFoundException/NoClassDefFoundError prevention
- 🟠Classpath is correct and complete
- 🟡 Class loading order issues resolved
- 🟢 Class loader leaks monitored
- 🟡 Reflection usage is safe (no arbitrary code execution)
- 🟡 Security manager policies configured (if enabled)
- 🟢 Reflection performance impact assessed
- 🔴 All critical and high-priority items from above sections checked
- 🔴 Code review completed by at least one other developer
- 🟠Security review completed (especially for authentication/authorization)
- 🟡 Code style and best practices followed
- 🟡 No TODO/FIXME comments in critical paths
- 🔴 Unit tests pass (if available)
- 🔴 Integration tests pass (if available)
- 🔴 Manual testing of critical user flows completed
- 🔴 Error scenarios tested (invalid input, missing data, etc.)
- 🟠Performance testing completed (if applicable)
- 🟠Load testing completed (if applicable)
- 🟡 Edge cases tested
- 🟠Response times meet requirements
- 🟠Database query performance acceptable
- 🟠Memory usage within limits
- 🟡 No memory leaks detected
- 🟡 Connection pool sizing validated under load
- 🔴 SQL injection prevention verified
- 🔴 XSS prevention verified (input sanitization)
- 🔴 Authentication and authorization working correctly
- 🔴 Session management secure
- 🟠Password handling secure (hashing, not plaintext)
- 🟡 CSRF protection (if implemented)
- 🟡 Rate limiting working (if implemented)
- 🔴 All configuration files reviewed
- 🔴 Environment-specific settings verified
- 🟠Configuration values are reasonable (timeouts, limits, etc.)
- 🟡 Configuration is externalized (not hardcoded)
- 🟡 Configuration changes documented
- 🔴 Unit tests run automatically in CI pipeline
- 🔴 Integration tests run automatically in CI pipeline
- 🟠Test failures block deployment
- 🟡 Test coverage meets minimum threshold (if defined)
- 🟡 Test results are reported and visible
- 🔴 Maven build runs successfully in CI environment
- 🔴 WAR file is created and validated
- 🟠Build artifacts are stored/archived
- 🟡 Build time is acceptable
- 🟡 Build is reproducible
- 🟠Static analysis tools run (FindBugs, PMD, Checkstyle, SonarQube)
- 🟠Critical and high-severity issues resolved
- 🟡 Code quality metrics meet thresholds
- 🟡 Technical debt tracked
- 🟠Dependency vulnerability scan runs (OWASP Dependency-Check, Snyk)
- 🟠High/critical vulnerabilities resolved or documented
- 🟡 Dependency updates reviewed regularly
- 🟡 Security advisories monitored
- 🔴 Application starts successfully after deployment
- 🔴 Health check endpoint responds (if available)
- 🔴 Database connection works
- 🔴 Critical endpoints are accessible
- 🟠Error pages work correctly
- 🟡 Logging is working
- 🟡 Performance is acceptable
Suggested Smoke Test Endpoints:
/(home page)/api/login(authentication)/error.jsp(error handling)
- 🟡 Health check endpoint implemented (if applicable)
- 🟡 Health check verifies database connectivity
- 🟡 Health check verifies critical dependencies
- 🟢 Health check used by load balancer/monitoring
- 🟠500 error rate is monitored
- 🟠Error rate alerts configured (threshold-based)
- 🟡 Error trends tracked over time
- 🟡 Error categorization (database, validation, server, etc.)
- 🟠Response time monitoring enabled
- 🟠Request throughput monitoring
- 🟡 Database query performance monitored
- 🟡 Memory usage monitored
- 🟡 CPU usage monitored
- 🟠Alert thresholds defined for critical metrics
- 🟠Alert recipients configured
- 🟡 Alert escalation process defined
- 🟡 False positive reduction (alert tuning)
Suggested Alert Thresholds:
- 500 error rate > 1% of requests
- Response time > 2 seconds (p95)
- Memory usage > 80%
- Database connection pool exhaustion
- SQLException: Check connection, query syntax, database availability
- NullPointerException in DAO: Check null handling for query results
- Connection pool exhaustion: Check connection release in finally blocks
- NullPointerException: Check session attributes, request parameters
- ClassCastException: Check instanceof before casting session attributes
- ServletException: Check servlet initialization, web.xml configuration
- Missing configuration properties: Check application.properties
- Invalid database URL: Check db.url property
- Missing dependencies: Check WEB-INF/lib in WAR file
- OutOfMemoryError: Check JVM heap settings, memory leaks
- FileNotFoundException: Check file paths, permissions
- IOException: Check file I/O operations, network operations
Quick Start:
# Run automated validation script
.\scripts\validate-500-prevention.ps1 -VerboseThe automated validation script checks many items automatically:
- Null pointer prevention patterns
- Resource management (try-with-resources)
- Error handling patterns
- SQL injection prevention
- Logging configuration
- Configuration file validation
- Build configuration
- Error page configuration
See scripts/README.md for details.
- Run automated validation script (see above)
- Review all Critical (🔴) items manually
- Review all High (🟠) items relevant to your changes
- Complete manual testing
- Run automated tests
- Verify configuration
- Add validation script to pipeline (see scripts/README.md)
- Automate Critical items where possible
- Include High-priority checks in pipeline
- Generate reports from checklist results
Example CI/CD Integration:
- name: Validate 500 Error Prevention
run: pwsh -File scripts/validate-500-prevention.ps1 -Verbose- Use checklist to identify root cause
- Add new items based on incident learnings
- Update priorities based on actual issues
- Update validation script with new patterns
- This checklist is specific to the IoTBay application architecture
- Update checklist as application evolves
- Share learnings and improvements with team
- Regular review and update of checklist items
Last Updated: 2025-01-XX Application Version: 1.0.0 Java Version: 8 (1.8) Server: Jetty (dev) / Tomcat (prod)
Document Version: 1.0.0 Status: Published Last Updated: 12¿ù 3, 2025 Audience: Developers, Stakeholders Maintained By: IoT Bay Documentation Team