Skip to content

Commit 8cfe287

Browse files
Adding web server is a software application designed to handle HTTP requests and responses
1 parent af61b2a commit 8cfe287

File tree

1 file changed

+2
-0
lines changed

1 file changed

+2
-0
lines changed

src/main/java/WebServer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import com.sun.net.httpserver.HttpExchange;import com.sun.net.httpserver.HttpHandler;import com.sun.net.httpserver.HttpServer;import java.io.IOException;import java.io.OutputStream;import java.net.InetSocketAddress;import java.nio.charset.StandardCharsets;import java.util.List;import java.util.stream.Collectors;public class WebServer {private final TaskManager taskManager;private final int port;private HttpServer server;public WebServer(TaskManager taskManager, int port) throws IOException {this.taskManager = taskManager;this.port = port;this.server = HttpServer.create(new InetSocketAddress(port), 0);registerRoutes();}private void registerRoutes() {server.createContext("/", this::handleIndex);server.createContext("/api/tasks", this::handleTasks);server.createContext("/api/tasks/", this::handleTaskByIndex);}public void start() {server.start();System.out.println("✅ Web server started at http://localhost:" + port + "/");}private void handleIndex(HttpExchange exchange) throws IOException {if (!"GET".equalsIgnoreCase(exchange.getRequestMethod())) {sendText(exchange, 405, "Method Not Allowed");return;}String html = "<!doctype html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>AI To-Do</title><style>body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;margin:20px}input,button{font-size:16px;padding:8px}ul{padding-left:18px}li{margin:6px 0}button.act{margin-left:8px;font-size:12px;padding:4px 8px}</style></head><body><h2>🧠 AI-Powered To-Do Manager (Web)</h2><div><input id=\"title\" placeholder=\"Add a task...\"/><button onclick=\"addTask()\">Add</button></div><p><button onclick=\"load()\">Refresh</button></p><ul id=\"list\"></ul><script>async function load(){const r=await fetch('/api/tasks');const d=await r.json();const ul=document.getElementById('list');ul.innerHTML='';d.forEach((t,i)=>{const li=document.createElement('li');const text=document.createElement('span');text.textContent=(i+1)+'. '+t.title+' ['+t.category+'] '+(t.completed?'✅':'');li.appendChild(text);const btnC=document.createElement('button');btnC.className='act';btnC.textContent='Complete';btnC.disabled=t.completed;btnC.onclick=()=>completeTask(i+1);li.appendChild(btnC);const btnD=document.createElement('button');btnD.className='act';btnD.textContent='Delete';btnD.onclick=()=>deleteTask(i+1);li.appendChild(btnD);ul.appendChild(li);});}async function addTask(){const v=document.getElementById('title').value.trim();if(!v)return;await fetch('/api/tasks',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({title:v})});document.getElementById('title').value='';load();}async function completeTask(idx){const r=await fetch('/api/tasks/'+idx+'/complete',{method:'PUT'});if(r.ok){load();}else{const e=await r.text();alert('Failed to complete: '+e);} }async function deleteTask(idx){const r=await fetch('/api/tasks/'+idx,{method:'DELETE'});if(r.ok){load();}else{const e=await r.text();alert('Failed to delete: '+e);} }load();</script></body></html>";sendHtml(exchange, 200, html);}private void handleTasks(HttpExchange exchange) throws IOException {switch (exchange.getRequestMethod()) {case "GET":List<Task> tasks = getTasksSnapshot();String json = toJson(tasks);sendJson(exchange, 200, json);break;case "POST":String body = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);String title = parseTitle(body);if (title == null || title.isBlank()) {sendJson(exchange, 400, "{\"error\":\"Title is required\"}");return;}try {taskManager.addTask(title);sendJson(exchange, 201, "{\"status\":\"created\"}");} catch (Exception e) {sendJson(exchange, 500, "{\"error\":\"" + escape(e.getMessage()) + "\"}");}break;default:sendText(exchange, 405, "Method Not Allowed");}}private void handleTaskByIndex(HttpExchange exchange) throws IOException {String path = exchange.getRequestURI().getPath(); // expected /api/tasks/{index} or /api/tasks/{index}/complete
2+
String[] parts = path.split("/");if (parts.length < 4) {sendText(exchange, 404, "Not Found");return;}String idxStr = parts[3];int index;try {index = Integer.parseInt(idxStr);} catch (NumberFormatException e) {sendText(exchange, 400, "Invalid index");return;}String method = exchange.getRequestMethod().toUpperCase();boolean isCompletePath = parts.length >= 5 && "complete".equalsIgnoreCase(parts[4]);try {if ("DELETE".equals(method) && parts.length==4){boolean ok = taskManager.deleteTask(index);if (ok) {sendJson(exchange, 200, "{\"status\":\"deleted\"}");} else {sendJson(exchange, 400, "{\"error\":\"Delete failed\"}");}} else if ("PUT".equals(method) && isCompletePath){boolean ok = taskManager.completeTask(index);if (ok) {sendJson(exchange, 200, "{\"status\":\"completed\"}");} else {sendJson(exchange, 400, "{\"error\":\"Complete failed\"}");}} else {sendText(exchange, 405, "Method Not Allowed");}} catch (Exception e){sendJson(exchange, 500, "{\"error\":\""+escape(e.getMessage())+"\"}");}}private List<Task> getTasksSnapshot() {try {java.lang.reflect.Field f = TaskManager.class.getDeclaredField("tasks");f.setAccessible(true);@SuppressWarnings("unchecked")List<Task> list = (List<Task>) f.get(taskManager);return List.copyOf(list);} catch (Exception e) {return List.of();}}private String toJson(List<Task> tasks) {String items = tasks.stream().map(t -> "{" +"\"title\":\"" + escape(t.getTitle()) + "\"," +"\"category\":\"" + escape(t.getCategory()) + "\"," +"\"completed\":" + (t.isCompleted() ? "true" : "false") +"}").collect(Collectors.joining(","));return "[" + items + "]";}private String parseTitle(String body) {try {int i = body.indexOf("\"title\"");if (i < 0) return null;int c = body.indexOf(':', i);if (c < 0) return null;int q1 = body.indexOf('"', c+1);if (q1 < 0) return null;int q2 = body.indexOf('"', q1+1);if (q2 < 0) return null;return body.substring(q1+1, q2);} catch (Exception e) {return null;}}private void sendHtml(HttpExchange ex, int code, String html) throws IOException {byte[] b = html.getBytes(StandardCharsets.UTF_8);ex.getResponseHeaders().set("Content-Type", "text/html; charset=utf-8");ex.sendResponseHeaders(code, b.length);try (OutputStream os = ex.getResponseBody()) { os.write(b); }}private void sendJson(HttpExchange ex, int code, String json) throws IOException {byte[] b = json.getBytes(StandardCharsets.UTF_8);ex.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8");ex.sendResponseHeaders(code, b.length);try (OutputStream os = ex.getResponseBody()) { os.write(b); }}private void sendText(HttpExchange ex, int code, String text) throws IOException {byte[] b = text.getBytes(StandardCharsets.UTF_8);ex.getResponseHeaders().set("Content-Type", "text/plain; charset=utf-8");ex.sendResponseHeaders(code, b.length);try (OutputStream os = ex.getResponseBody()) { os.write(b); }}private String escape(String s) { return s == null ? "" : s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n"); }}

0 commit comments

Comments
 (0)