Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ Thumbs.db

# Logs
*.log
/.classpath
/.project
/.settings/
2 changes: 1 addition & 1 deletion src/main/java/brendanddev/client/MainClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static void main(String[] args) {
}

String host = props.getProperty("server.host", "localhost");
int port = Integer.parseInt(props.getProperty("server.port", "8080"));
int port = Integer.parseInt(props.getProperty("server.port", "9080"));

// Create instance of HttpClient with the loaded properties
HttpClient client = new HttpClient(host, port);
Expand Down
57 changes: 57 additions & 0 deletions src/main/java/brendanddev/routing/Route.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package brendanddev.routing;

import brendanddev.server.HttpHandler;


/**
*
* @author albanna
*/


/**
* Represents a single route in the HTTP server.
*/
public class Route {

private final String method;
private final String path;
private final HttpHandler handler;
private final String description;

public Route(String method, String path, HttpHandler handler) {
this(method, path, handler, "");
}

public Route(String method, String path, HttpHandler handler, String description) {
this.method = method.toUpperCase();
this.path = path;
this.handler = handler;
this.description = description;
}

public String getMethod() {
return method;
}

public String getPath() {
return path;
}

public HttpHandler getHandler() {
return handler;
}

public String getDescription() {
return description;
}

public String getRouteKey() {
return method + " " + path;
}

@Override
public String toString() {
return String.format("%s %s - %s", method, path, description);
}
}
133 changes: 133 additions & 0 deletions src/main/java/brendanddev/routing/RouteRegistry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package brendanddev.routing;

import brendanddev.server.HttpHandler;
import brendanddev.server.HttpResponse;
import brendanddev.tools.Logger;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
*
* @author albanna
*/

/**
* Centralized route registry for managing HTTP routes. Provides a clean way to
* register, organize, and document API endpoints.
*/
public class RouteRegistry {

private final Map<String, Route> routes = new HashMap<>();
private final Logger logger = Logger.getInstance();

/**
* Registers a new route with the registry.
*/
public RouteRegistry register(String method, String path, HttpHandler handler) {
return register(method, path, handler, "");
}

/**
* Registers a new route with description.
*/
public RouteRegistry register(String method, String path, HttpHandler handler, String description) {
Route route = new Route(method, path, handler, description);
routes.put(route.getRouteKey(), route);
logger.info("Registered route: " + route);
return this; // For method chaining
}

/**
* Registers a GET route.
*/
public RouteRegistry get(String path, HttpHandler handler) {
return register("GET", path, handler);
}

/**
* Registers a GET route with description.
*/
public RouteRegistry get(String path, HttpHandler handler, String description) {
return register("GET", path, handler, description);
}

/**
* Registers a POST route.
*/
public RouteRegistry post(String path, HttpHandler handler) {
return register("POST", path, handler);
}

/**
* Registers a POST route with description.
*/
public RouteRegistry post(String path, HttpHandler handler, String description) {
return register("POST", path, handler, description);
}

/**
* Registers a PUT route.
*/
public RouteRegistry put(String path, HttpHandler handler) {
return register("PUT", path, handler);
}

/**
* Registers a DELETE route.
*/
public RouteRegistry delete(String path, HttpHandler handler) {
return register("DELETE", path, handler);
}

/**
* Gets a route handler for the given method and path.
*/
public HttpHandler getHandler(String method, String path) {
Route route = routes.get(method.toUpperCase() + " " + path);
return route != null ? route.getHandler() : null;
}

/**
* Gets all registered routes.
*/
public List<Route> getAllRoutes() {
return new ArrayList<>(routes.values());
}

/**
* Creates an API documentation handler that lists all routes.
*/
public HttpHandler createApiDocsHandler() {
return (request, body) -> {
StringBuilder html = new StringBuilder();
html.append("<html><head><title>API Documentation</title></head><body>");
html.append("<h1>API Endpoints</h1>");
html.append("<table border='1' style='border-collapse: collapse; width: 100%;'>");
html.append("<tr><th>Method</th><th>Path</th><th>Description</th></tr>");

getAllRoutes().forEach(route -> {
html.append("<tr>");
html.append("<td>").append(route.getMethod()).append("</td>");
html.append("<td>").append(route.getPath()).append("</td>");
html.append("<td>").append(route.getDescription()).append("</td>");
html.append("</tr>");
});

html.append("</table></body></html>");
return new HttpResponse(html.toString(), 200, "OK");
};
}

/**
* Applies all registered routes to an HttpServer.
*/
public void applyTo(brendanddev.server.HttpServer server) {
routes.values().forEach(route -> {
server.addRoute(route.getMethod(), route.getPath(), route.getHandler());
});
logger.info("Applied " + routes.size() + " routes to server");
}
}
114 changes: 114 additions & 0 deletions src/main/java/brendanddev/server/EnhancedMainServer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package brendanddev.server;

import brendanddev.routing.RouteRegistry;
import brendanddev.tools.ConfigManager;
import brendanddev.tools.Logger;
import brendanddev.tools.RequestMetrics;

/**
* @author albanna
*/

/**
* Enhanced main server class demonstrating the new tools and routing features.
* This shows how to use the new packages without modifying existing code.
*/
public class EnhancedMainServer {

public static void main(String[] args) {
// Initialize logging
Logger logger = Logger.getInstance();
logger.setLogLevel(Logger.LogLevel.DEBUG);
logger.setFileLogging(true, "enhanced-server.log");
logger.info("Starting Enhanced HTTP Server...");

// Load configuration
ConfigManager config = ConfigManager.getInstance();
int port = config.getIntProperty("server.properties", "server.port", 9090);
boolean enableMetrics = config.getBooleanProperty("server.properties", "metrics.enabled", true);

// Create server
HttpServer server = new HttpServer(port);

// Initialize metrics if enabled
RequestMetrics metrics = RequestMetrics.getInstance();

// Create centralized route registry
RouteRegistry routes = new RouteRegistry();

// Register existing routes with descriptions
routes.get("/", (request, body) -> {
long startTime = System.currentTimeMillis();
HttpResponse response = new HttpResponse(ServerUtils.loadTemplate("index.html"), 200, "OK");
if (enableMetrics) {
metrics.recordRequest("GET", "/", System.currentTimeMillis() - startTime);
}
return response;
}, "Home page");

routes.get("/about", (request, body) -> {
long startTime = System.currentTimeMillis();
HttpResponse response = new HttpResponse(ServerUtils.loadTemplate("about.html"), 200, "OK");
if (enableMetrics) {
metrics.recordRequest("GET", "/about", System.currentTimeMillis() - startTime);
}
return response;
}, "About page");

routes.post("/submit", (request, body) -> {
long startTime = System.currentTimeMillis();
logger.info("Received POST data: " + body);
HttpResponse response = new HttpResponse(
ServerUtils.loadTemplate("submit.html").replace("{{message}}", body), 200, "OK");
if (enableMetrics) {
metrics.recordRequest("POST", "/submit", System.currentTimeMillis() - startTime);
}
return response;
}, "Submit form data");

// Register new utility routes
routes.get("/api/docs", routes.createApiDocsHandler(), "API Documentation");

routes.get("/api/metrics", (request, body) -> {
if (!enableMetrics) {
return new HttpResponse("Metrics disabled", 404, "Not Found");
}

StringBuilder html = new StringBuilder();
html.append("<html><head><title>Server Metrics</title></head><body>");
html.append("<h1>Server Metrics</h1>");
html.append("<p>Total Requests: ").append(metrics.getTotalRequests()).append("</p>");
html.append("<h2>Endpoint Statistics:</h2>");
html.append("<table border='1' style='border-collapse: collapse;'>");
html.append("<tr><th>Endpoint</th><th>Count</th><th>Avg Response Time (ms)</th></tr>");

routes.getAllRoutes().forEach(route -> {
long count = metrics.getRequestCount(route.getMethod(), route.getPath());
double avgTime = metrics.getAverageResponseTime(route.getMethod(), route.getPath());
html.append("<tr>");
html.append("<td>").append(route.getRouteKey()).append("</td>");
html.append("<td>").append(count).append("</td>");
html.append("<td>").append(String.format("%.2f", avgTime)).append("</td>");
html.append("</tr>");
});

html.append("</table></body></html>");
return new HttpResponse(html.toString(), 200, "OK");
}, "Server metrics and statistics");

routes.get("/api/health", (request, body) -> {
return new HttpResponse("{\"status\":\"OK\",\"timestamp\":" + System.currentTimeMillis() + "}", 200, "OK");
}, "Health check endpoint");

// Apply all routes to the server
routes.applyTo(server);

// Print registered routes
logger.info("Registered " + routes.getAllRoutes().size() + " routes:");
routes.getAllRoutes().forEach(route -> logger.info(" " + route));

// Start server
logger.info("Server starting on port " + port);
server.start();
}
}
Loading