Code Quality Review: framework/servlet Module
Executive Summary
The framework/servlet module provides the server-side HTTP service component that complements the framework/db-http client module. Built on Javalin and Jetty, this module demonstrates exemplary web service architecture with comprehensive dual serialization support, sophisticated authentication/session management, and complete EntityConnection API exposure over HTTP. This represents the final piece of Codion’s HTTP puzzle - enabling complete RMI replacement with modern web service infrastructure.
Architecture Overview
This module serves as a comprehensive HTTP-to-RMI bridge that:
- Web Service Gateway: Exposes complete EntityConnection API over HTTP using Javalin
- Dual Protocol Support: Serves both binary serialization and JSON protocols simultaneously
- Session Management: Provides HTTP session-based connection lifecycle management
- SSL/TLS Ready: Complete HTTPS support with keystore management
- RMI Backend Integration: Leverages existing EntityServer infrastructure through AuxiliaryServer pattern
- Virtual Thread Support: Java 21+ virtual thread integration for high concurrency
Key Architectural Strengths
1. Comprehensive API Coverage ✅
Complete EntityConnection Interface Exposure:
// Every EntityConnection method mapped to HTTP endpoints
javalin.post(URL_SERIAL + "entities", entitiesHandler::serial);
javalin.post(URL_JSON + "entities", entitiesHandler::serial);
javalin.post(URL_SERIAL + "isTransactionOpen", isTransactionOpenHandler::serial);
javalin.post(URL_JSON + "isTransactionOpen", isTransactionOpenHandler::json);
javalin.post(URL_SERIAL + "select", selectHandler::serial);
javalin.post(URL_JSON + "select", selectHandler::json);
javalin.post(URL_SERIAL + "insert", insertHandler::serial);
javalin.post(URL_JSON + "insert", insertHandler::json);
// ... complete coverage of all EntityConnection operations
Transaction Support:
javalin.post(URL_SERIAL + "startTransaction", startTransactionHandler::serial);
javalin.post(URL_JSON + "startTransaction", startTransactionHandler::serial);
javalin.post(URL_SERIAL + "rollbackTransaction", rollbackTransactionHandler::serial);
javalin.post(URL_JSON + "rollbackTransaction", rollbackTransactionHandler::serial);
javalin.post(URL_SERIAL + "commitTransaction", commitTransactionHandler::serial);
javalin.post(URL_JSON + "commitTransaction", commitTransactionHandler::serial);
2. Sophisticated Authentication & Session Management ✅
Multi-Layer Authentication:
private RemoteEntityConnection authenticate(Context context) throws RemoteException, ServerException {
String domainTypeName = domainTypeName(context);
String clientType = clientType(context);
UUID clientId = clientId(context);
User user = user(context);
return server.connect(ConnectionRequest.builder()
.user(user)
.id(clientId)
.type(clientType)
.parameter(RemoteEntityConnectionProvider.REMOTE_CLIENT_DOMAIN_TYPE, domainTypeName)
.parameter(Server.CLIENT_HOST, remoteHost(context.req()))
.build());
}
Session-Based Client ID Validation:
private static UUID clientId(Context context) throws ServerAuthenticationException {
UUID headerClientId = UUID.fromString(checkHeaderParameter(context.header(CLIENT_ID), CLIENT_ID));
HttpSession session = context.req().getSession();
if (session.isNew()) {
session.setAttribute(CLIENT_ID, headerClientId);
}
else {
UUID sessionClientId = (UUID) session.getAttribute(CLIENT_ID);
if (sessionClientId == null || !sessionClientId.equals(headerClientId)) {
session.invalidate();
throw new ServerAuthenticationException("Invalid client id");
}
}
return headerClientId;
}
Basic Authentication Processing:
private static User user(Context context) throws ServerAuthenticationException {
String basicAuth = context.header(AUTHORIZATION);
if (nullOrEmpty(basicAuth)) {
throw new ServerAuthenticationException("Authorization information missing");
}
if (basicAuth.length() > BASIC_PREFIX_LENGTH &&
BASIC_PREFIX.equalsIgnoreCase(basicAuth.substring(0, BASIC_PREFIX_LENGTH))) {
return User.parse(new String(Base64.getDecoder().decode(basicAuth.substring(BASIC_PREFIX_LENGTH))));
}
throw new ServerAuthenticationException("Invalid authorization format");
}
3. Elegant Dual Serialization Architecture ✅
Strategic Protocol Separation:
private static final String URL_SERIAL = "entities/serial/";
private static final String URL_JSON = "entities/json/";
// Note: some services only implement java serialization
// (report f.ex) so these are not just some glaring mistakes
// below, where a ::serial call is associated with the json url
javalin.post(URL_SERIAL + "procedure", procedureHandler::serial);
javalin.post(URL_JSON + "procedure", procedureHandler::serial); // Falls back to serial
javalin.post(URL_SERIAL + "function", functionHandler::serial);
javalin.post(URL_JSON + "function", functionHandler::serial); // Falls back to serial
javalin.post(URL_SERIAL + "report", reportHandler::serial);
javalin.post(URL_JSON + "report", reportHandler::serial); // Falls back to serial
JSON Handler Implementation:
private void json(Context context) {
try {
RemoteEntityConnection connection = authenticate(context);
ObjectMapper objectMapper = objectMapper(connection.entities());
List<Entity> entities = objectMapper.readValue(context.req().getInputStream(), ENTITY_LIST_REFERENCE);
Collection<Entity.Key> keys = connection.insert(entities);
context.status(HttpStatus.OK_200)
.contentType(ContentType.APPLICATION_JSON)
.result(objectMapper.writeValueAsString(keys));
}
catch (Exception e) {
handleException(context, e);
}
}
Binary Serialization Handler:
private void serial(Context context) {
try {
RemoteEntityConnection connection = authenticate(context);
Collection<Entity.Key> keys = connection.insert((Collection<Entity>) deserialize(context.req()));
context.status(HttpStatus.OK_200)
.contentType(ContentType.APPLICATION_OCTET_STREAM)
.result(serialize(keys));
}
catch (Exception e) {
handleException(context, e);
}
}
4. Domain-Aware ObjectMapper Management ✅
Per-Domain ObjectMapper Caching:
private final Map<DomainType, ObjectMapper> domainObjectMappers = new ConcurrentHashMap<>();
private ObjectMapper objectMapper(Entities entities) {
return domainObjectMappers.computeIfAbsent(entities.domainType(), domainType ->
DatabaseObjectMapper.databaseObjectMapper(EntityObjectMapperFactory.instance(domainType)
.entityObjectMapper(entities)));
}
Complex JSON Parameter Handling:
// ValuesHandler - Complex parameter decomposition for JSON
private void json(Context context) {
RemoteEntityConnection connection = authenticate(context);
Entities entities = connection.entities();
ObjectMapper objectMapper = objectMapper(entities);
JsonNode jsonNode = objectMapper.readTree(context.req().getInputStream());
EntityType entityType = entities.domainType().entityType(jsonNode.get("entityType").asText());
Column<?> column = (Column<?>) entities.definition(entityType).attributes().get(jsonNode.get("column").textValue());
Select select = null;
JsonNode conditionNode = jsonNode.get("condition");
if (conditionNode != null) {
select = objectMapper.readValue(conditionNode.toString(), Select.class);
}
List<?> values = connection.select(column, select);
context.status(HttpStatus.OK_200)
.contentType(ContentType.APPLICATION_JSON)
.result(objectMapper.writeValueAsString(values));
}
5. Enterprise-Grade SSL/HTTPS Support ✅
Complete SSL Configuration:
public static final PropertyValue<Boolean> HTTP_SERVER_SECURE = booleanValue("codion.server.http.secure", true);
public static final PropertyValue<String> HTTP_SERVER_CLASSPATH_KEYSTORE = stringValue("codion.server.http.classpathKeyStore");
public static final PropertyValue<String> HTTP_SERVER_KEYSTORE_PATH = stringValue("codion.server.http.keyStore");
public static final PropertyValue<String> HTTP_SERVER_KEYSTORE_PASSWORD = stringValue("codion.server.http.keyStorePassword");
Classpath Keystore Resolution:
private static synchronized void resolveClasspathKeyStore() {
String keystore = HTTP_SERVER_CLASSPATH_KEYSTORE.get();
if (nullOrEmpty(keystore)) {
return;
}
try (InputStream inputStream = EntityService.class.getClassLoader().getResourceAsStream(keystore)) {
if (inputStream == null) {
return;
}
File file = File.createTempFile("serverKeyStore", "tmp");
Files.write(file.toPath(), readBytes(inputStream));
file.deleteOnExit();
HTTP_SERVER_KEYSTORE_PATH.set(file.getPath());
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
SSL Plugin Configuration:
private final class SslPLuginConfigurer implements Consumer<SslConfig> {
@Override
public void accept(SslConfig ssl) {
ssl.keystoreFromPath(HTTP_SERVER_KEYSTORE_PATH.getOrThrow(), HTTP_SERVER_KEYSTORE_PASSWORD.getOrThrow());
ssl.securePort = securePort;
ssl.insecurePort = port;
}
}
6. Modern Java Concurrency Integration ✅
Virtual Thread Support:
public static final PropertyValue<Boolean> USE_VIRTUAL_THREADS =
booleanValue("codion.server.http.useVirtualThreads", false);
private final class JavalinConfigurer implements Consumer<JavalinConfig> {
@Override
public void accept(JavalinConfig config) {
config.useVirtualThreads = useVirtualThreads;
if (sslEnabled) {
config.registerPlugin(new SslPlugin(new SslPLuginConfigurer()));
}
}
}
7. Sophisticated Error Handling ✅
HTTP Status Code Mapping:
private static int exceptionStatus(Exception exception) {
if (exception instanceof ServerAuthenticationException) {
return HttpStatus.UNAUTHORIZED_401;
}
return HttpStatus.INTERNAL_SERVER_ERROR_500;
}
Exception Serialization with Fallback:
private static byte[] exceptionResult(Exception exception) {
try {
return serialize(exception);
}
catch (IOException e) {
LOG.error(e.getMessage(), e);
try {
return serialize(e); // Serialize the serialization exception
}
catch (IOException io) {
LOG.error(e.getMessage(), io);
return new byte[0]; // Ultimate fallback
}
}
}
Comprehensive Exception Handling:
private static void handleException(Context context, Exception exception) {
LOG.error(exception.getMessage(), exception);
context.status(exceptionStatus(exception))
.result(exceptionResult(exception));
}
8. Network Infrastructure Awareness ✅
X-Forwarded-For Support:
private static String remoteHost(HttpServletRequest request) {
String forwardHeader = request.getHeader(X_FORWARDED_FOR);
if (forwardHeader == null) {
return request.getRemoteAddr();
}
return forwardHeader.split(",")[0]; // First IP in chain
}
Connection Request Building:
return server.connect(ConnectionRequest.builder()
.user(user)
.id(clientId)
.type(clientType)
.parameter(RemoteEntityConnectionProvider.REMOTE_CLIENT_DOMAIN_TYPE, domainTypeName)
.parameter(Server.CLIENT_HOST, remoteHost(context.req())) // Pass actual client IP
.build());
Code Quality Assessment
1. Architecture Pattern Excellence ✅
AuxiliaryServer Integration:
public final class EntityService implements AuxiliaryServer {
private final Server<RemoteEntityConnection, ? extends ServerAdmin> server;
@Override
public void start() {
setupHandlers();
javalin.start(sslEnabled ? securePort : port);
}
@Override
public void stop() {
if (javalin != null) {
javalin.stop();
}
}
}
Service Discovery Integration:
// META-INF/services/is.codion.common.rmi.server.AuxiliaryServerFactory
public final class EntityServiceFactory implements AuxiliaryServerFactory<RemoteEntityConnection, ServerAdmin, EntityService> {
@Override
public EntityService createServer(Server<RemoteEntityConnection, ServerAdmin> server) {
return new EntityService(server);
}
}
2. Handler Organization Excellence ✅
Inner Class Handler Pattern:
private final EntitiesHandler entitiesHandler = new EntitiesHandler();
private final CloseHandler closeHandler = new CloseHandler();
private final StartTransactionHandler startTransactionHandler = new StartTransactionHandler();
// ... organized by functional responsibility
private final class InsertHandler {
private void serial(Context context) { /* ... */ }
private void json(Context context) { /* ... */ }
}
Session Lifecycle Management:
private final class CloseHandler {
private void serial(Context context) {
try {
authenticate(context).close();
context.req().getSession().invalidate(); // Clean session on close
context.status(HttpStatus.OK_200);
}
catch (Exception e) {
handleException(context, e);
}
}
}
3. Parameter Validation Excellence ✅
Header Parameter Validation:
private static String checkHeaderParameter(String header, String headerParameter)
throws ServerAuthenticationException {
if (nullOrEmpty(header)) {
throw new ServerAuthenticationException(headerParameter + " header parameter is missing");
}
return header;
}
Complete Context Validation:
String domainTypeName = checkHeaderParameter(context.header(DOMAIN_TYPE_NAME), DOMAIN_TYPE_NAME);
String clientType = checkHeaderParameter(context.header(CLIENT_TYPE), CLIENT_TYPE);
UUID clientId = UUID.fromString(checkHeaderParameter(context.header(CLIENT_ID), CLIENT_ID));
4. Resource Management ✅
Automatic Session Cleanup:
context.req().getSession().invalidate(); // On connection close
Keystore Cleanup:
File file = File.createTempFile("serverKeyStore", "tmp");
Files.write(file.toPath(), readBytes(inputStream));
file.deleteOnExit(); // Automatic cleanup on JVM shutdown
Performance Characteristics
1. Concurrency Excellence ✅
Virtual Thread Support:
- Java 21+ ready with configurable virtual thread usage
- High concurrent request handling without traditional thread pool limitations
- Javalin/Jetty integration leverages proven async servlet technology
2. Serialization Performance ✅
Dual Strategy Optimization:
- Binary serialization for maximum performance
- JSON serialization for security, debugging, and cross-platform compatibility
- Per-domain ObjectMapper caching prevents repeated Jackson configuration
3. Memory Management ✅
ObjectMapper Caching:
private final Map<DomainType, ObjectMapper> domainObjectMappers = new ConcurrentHashMap<>();
Session-Based Connection Reuse:
- HTTP sessions maintain connection identity across requests
- Leverages existing EntityServer connection pooling through RMI backend
Security Assessment
1. Authentication Security ✅
Multi-Factor Authentication:
- Basic Auth credentials for user authentication
- Client ID validation against HTTP session
- Domain type verification for request context
- Session invalidation on authentication failures
2. Transport Security ✅
HTTPS by Default:
- SSL/TLS enabled by default with configurable keystore management
- Classpath keystore support for embedded deployments
- Dual port configuration supporting both HTTP and HTTPS
3. Input Validation ✅
Comprehensive Parameter Validation:
- Header parameter existence verification
- Authorization format validation
- Client ID format validation (UUID)
- Session consistency checking
Integration Assessment
1. EntityServer Integration ✅
Seamless RMI Backend Integration:
// Leverages existing EntityServer infrastructure
return server.connect(ConnectionRequest.builder()
.user(user)
.id(clientId)
.type(clientType)
.parameter(RemoteEntityConnectionProvider.REMOTE_CLIENT_DOMAIN_TYPE, domainTypeName)
.parameter(Server.CLIENT_HOST, remoteHost(context.req()))
.build());
2. Framework Integration ✅
Complete Codion Framework Compatibility:
- All EntityConnection operations exposed over HTTP
- Domain-aware JSON serialization using framework/json-domain
- Error handling consistency with existing framework patterns
- Configuration integration using PropertyValue system
Minor Areas for Enhancement
1. Health Check Endpoints (Enhancement)
Consider adding /health
and /metrics
endpoints for monitoring integration.
2. Request Logging (Enhancement)
Consider optional HTTP request/response logging for debugging and monitoring.
3. Rate Limiting (Enhancement)
Consider adding configurable rate limiting for DDoS protection.
4. OpenAPI Documentation (Enhancement)
Consider generating OpenAPI/Swagger documentation for the HTTP API.
Overall Assessment: EXCEPTIONAL HTTP SERVICE ARCHITECTURE ✅
This module completes Codion’s HTTP story with outstanding web service engineering:
Architectural Excellence:
- ✅ Complete API coverage - Every EntityConnection operation exposed over HTTP
- ✅ Dual serialization mastery - Binary performance + JSON flexibility
- ✅ Session management sophistication - HTTP session-based connection lifecycle
- ✅ SSL/TLS integration - Enterprise-ready HTTPS with keystore management
- ✅ Modern concurrency - Virtual thread support for high-performance async processing
Security Excellence:
- ✅ Multi-layer authentication - Basic Auth + Session validation + Client ID verification
- ✅ Transport security - HTTPS by default with configurable keystore management
- ✅ Input validation - Comprehensive parameter validation and format checking
- ✅ Session security - Session invalidation on authentication failures
- ✅ Network awareness - X-Forwarded-For support for proxy environments
Engineering Excellence:
- ✅ Error handling mastery - HTTP status mapping with exception serialization fallback
- ✅ Resource management - Automatic cleanup of sessions and temporary files
- ✅ Performance optimization - ObjectMapper caching and virtual thread support
- ✅ Configuration flexibility - Comprehensive property-based configuration
- ✅ Integration seamless - Perfect AuxiliaryServer pattern implementation
HTTP Service Best Practices:
- ✅ RESTful design - Clear URL patterns with HTTP method semantics
- ✅ Content negotiation - Proper Content-Type handling for binary vs JSON
- ✅ Status code usage - Appropriate HTTP status codes for different scenarios
- ✅ Header management - Proper authorization and parameter header handling
- ✅ Proxy compatibility - X-Forwarded-For support for load balancer environments
Framework Integration Excellence:
- ✅ EntityServer bridge - Seamless integration with existing RMI server infrastructure
- ✅ Domain awareness - Per-domain ObjectMapper configuration
- ✅ JSON framework integration - Uses framework/json-domain for consistent serialization
- ✅ Configuration consistency - PropertyValue system integration
- ✅ Service discovery - AuxiliaryServerFactory pattern for automatic registration
Recommendation: PRODUCTION-READY HTTP SERVICE ✅
This module successfully provides:
- Complete RMI replacement via HTTP with zero API compromises
- Enterprise-grade security with HTTPS, authentication, and session management
- Modern web service architecture using Javalin/Jetty with virtual thread support
- Dual serialization strategy supporting both performance and interoperability needs
- Seamless integration with existing Codion EntityServer infrastructure
Key Achievement: Successfully implements a complete, production-ready HTTP service that perfectly complements the framework/db-http client module, providing a secure, high-performance alternative to RMI while maintaining full API compatibility and leveraging all existing EntityServer capabilities.
Complementary Excellence: This module, combined with framework/db-http, provides a complete solution to the RMI serialization security concerns that motivated their creation. The architecture demonstrates how to build secure, modern web services while maintaining backward compatibility and leveraging existing infrastructure.
Note: This module represents the culmination of thoughtful web service design - providing all the benefits of HTTP transport (security, firewall compatibility, monitoring) while maintaining the simplicity and power of Codion’s EntityConnection API. The dual serialization strategy is particularly elegant, allowing users to choose between performance (binary) and interoperability (JSON) based on their specific needs.