Browse Source

Refactor server loading, roll logs at midnight, adding admin endpoints.

Matt Clark 1 year ago
parent
commit
d3483695e5

+ 1 - 0
authlist.conf

@@ -0,0 +1 @@
+admin:password

+ 1 - 1
resources/blacklist.conf → blacklist.conf

@@ -1,2 +1,2 @@
-^__tstblk$
+^__tstblk$
 ^_tstblk_$

+ 45 - 117
src/main/java/org/barcodeapi/core/ServerLoader.java

@@ -3,16 +3,21 @@ package org.barcodeapi.core;
 import java.util.Timer;
 import java.util.concurrent.TimeUnit;
 
+import org.barcodeapi.server.admin.CacheClearHandler;
+import org.barcodeapi.server.admin.CacheDumpHandler;
+import org.barcodeapi.server.admin.SessionClearHandler;
+import org.barcodeapi.server.admin.SessionDumpHandler;
+import org.barcodeapi.server.admin.StatsDumpHandler;
 import org.barcodeapi.server.api.BarcodeAPIHandler;
 import org.barcodeapi.server.api.BulkHandler;
-import org.barcodeapi.server.api.CacheHandler;
 import org.barcodeapi.server.api.SessionHandler;
 import org.barcodeapi.server.api.StaticHandler;
-import org.barcodeapi.server.api.StatsHandler;
 import org.barcodeapi.server.api.TypesHandler;
 import org.barcodeapi.server.core.Log;
 import org.barcodeapi.server.core.Log.LOG;
+import org.barcodeapi.server.core.RestHandler;
 import org.barcodeapi.server.tasks.BarcodeCleanupTask;
+import org.barcodeapi.server.tasks.LogRotateTask;
 import org.barcodeapi.server.tasks.SessionCleanupTask;
 import org.barcodeapi.server.tasks.StatsDumpTask;
 import org.barcodeapi.server.tasks.WatchdogTask;
@@ -33,12 +38,9 @@ public class ServerLoader {
 	// Background task timer
 	private final Timer timer = new Timer();
 
-	// The port for the API server to bind to.
+	// The port for the servers to bind to.
 	private int serverPort = 8080;
 
-	// Whether static resources should be served.
-	private boolean serverStatic = true;
-
 	// Report usage statistics by default
 	private boolean telemetry = true;
 
@@ -66,21 +68,7 @@ public class ServerLoader {
 	 */
 	public void launch() throws Exception {
 
-		initJetty();
-
-		initStatsHandler();
-
-		initSessionHandler();
-
-		initCacheHandler();
-
-		initTypesHandler();
-
-		initBulkHandler();
-
-		initApiHandler();
-
-		initResourceHandler();
+		initApiServer();
 
 		initSystemTasks();
 
@@ -109,10 +97,6 @@ public class ServerLoader {
 				serverPort = Integer.parseInt(args[++x]);
 				break;
 
-			case "--no-web":
-				serverStatic = false;
-				break;
-
 			case "--no-telemetry":
 				telemetry = false;
 				break;
@@ -126,113 +110,52 @@ public class ServerLoader {
 	}
 
 	/**
-	 * Initialize the Jetty server.
+	 * Initialize the API REST server.
 	 */
-	private void initJetty() {
-
-		Log.out(LOG.SERVER, "Initializing Jetty");
-
-		// initialize handler collection
-		handlers = new HandlerCollection();
+	private void initApiServer() throws Exception {
 
 		// initialize API server
+		Log.out(LOG.SERVER, "Initializing Jetty API Server");
+		handlers = new HandlerCollection();
 		server = new Server(serverPort);
 		server.setHandler(handlers);
-	}
-
-	/**
-	 * Initialize the statistics end-point.
-	 */
-	private void initStatsHandler() {
-
-		// setup statistics handler
-		Log.out(LOG.SERVER, "Initializing handler: /stats");
-		ContextHandler statsHandler = new ContextHandler();
-		statsHandler.setHandler(new StatsHandler());
-		statsHandler.setContextPath("/stats");
-		handlers.addHandler(statsHandler);
-	}
-
-	/**
-	 * Initialize the session end-point.
-	 */
-	private void initSessionHandler() {
-
-		// setup statistics handler
-		Log.out(LOG.SERVER, "Initializing handler: /session");
-		ContextHandler sessionHandler = new ContextHandler();
-		sessionHandler.setHandler(new SessionHandler());
-		sessionHandler.setContextPath("/session");
-		handlers.addHandler(sessionHandler);
-	}
 
-	/**
-	 * Initialize the cache end-point.
-	 */
-	private void initCacheHandler() {
-
-		// setup statistics handler
-		Log.out(LOG.SERVER, "Initializing handler: /cache");
-		ContextHandler cacheHandler = new ContextHandler();
-		cacheHandler.setHandler(new CacheHandler());
-		cacheHandler.setContextPath("/cache");
-		handlers.addHandler(cacheHandler);
-	}
+		// setup rest handlers
+		initHandler("/session", SessionHandler.class);
+		initHandler("/types", TypesHandler.class);
+		initHandler("/bulk", BulkHandler.class);
+		initHandler("/api", BarcodeAPIHandler.class);
 
-	/**
-	 * Initialize the types end-point.
-	 */
-	private void initTypesHandler() {
-
-		// setup statistics handler
-		Log.out(LOG.SERVER, "Initializing handler: /types");
-		ContextHandler typesHandler = new ContextHandler();
-		typesHandler.setHandler(new TypesHandler());
-		typesHandler.setContextPath("/types");
-		handlers.addHandler(typesHandler);
-	}
+		// setup admin handlers
+		initHandler("/admin/stats", StatsDumpHandler.class);
+		initHandler("/admin/cache/dump", CacheDumpHandler.class);
+		initHandler("/admin/cache/clear", CacheClearHandler.class);
+		initHandler("/admin/session/dump", SessionDumpHandler.class);
+		initHandler("/admin/session/clear", SessionClearHandler.class);
 
-	/**
-	 * Initialize the bulk-download end-point.
-	 */
-	private void initBulkHandler() {
-
-		// setup statistics handler
-		Log.out(LOG.SERVER, "Initializing handler: /bulk");
-		ContextHandler bulkHandler = new ContextHandler();
-		bulkHandler.setHandler(new BulkHandler());
-		bulkHandler.setContextPath("/bulk");
-		handlers.addHandler(bulkHandler);
+		// Instantiate the static resource handler and add it to the collection
+		Log.out(LOG.SERVER, "Initializing static resource handler");
+		ContextHandler resourceHandler = new ContextHandler();
+		resourceHandler.setHandler(new StaticHandler(server));
+		resourceHandler.setContextPath("/");
+		handlers.addHandler(resourceHandler);
 	}
 
 	/**
-	 * Initialize the main API handler.
+	 * Initialize a new handler to be served by Jetty
 	 */
-	private void initApiHandler() {
-
-		// setup API handler
-		Log.out(LOG.SERVER, "Initializing handler: /api");
-		ContextHandler apiHandler = new ContextHandler();
-		apiHandler.setHandler(new BarcodeAPIHandler());
-		apiHandler.setContextPath("/api");
-		handlers.addHandler(apiHandler);
-	}
+	private void initHandler(String path, Class<? extends RestHandler> clazz) throws Exception {
 
-	/**
-	 * Initialize the resource handler.
-	 */
-	private void initResourceHandler() throws Exception {
+		Log.out(LOG.SERVER, "Initializing handler: " + path);
 
-		if (!serverStatic) {
-			return;
-		}
+		// Instantiate the handler
+		RestHandler handler = clazz.getConstructor().newInstance();
 
-		// Instantiate the static resource handler and add it to the collection
-		Log.out(LOG.SERVER, "Initializing static resource handler");
-		ContextHandler apiHandler = new ContextHandler();
-		apiHandler.setHandler(new StaticHandler(server));
-		apiHandler.setContextPath("/");
-		handlers.addHandler(apiHandler);
+		// Add it to the handler collection
+		ContextHandler statsHandler = new ContextHandler();
+		statsHandler.setHandler(handler);
+		statsHandler.setContextPath(path);
+		handlers.addHandler(statsHandler);
 	}
 
 	/**
@@ -259,6 +182,11 @@ public class ServerLoader {
 		BarcodeCleanupTask barcodeCleanup = new BarcodeCleanupTask();
 		timer.schedule(barcodeCleanup, 0, //
 				TimeUnit.MILLISECONDS.convert(1, TimeUnit.HOURS));
+
+		// rotate logs every 24h
+		LogRotateTask logRotate = new LogRotateTask();
+		timer.schedule(logRotate, Log.timeTillRotate(), //
+				TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS));
 	}
 
 	/**

+ 29 - 0
src/main/java/org/barcodeapi/server/admin/CacheClearHandler.java

@@ -0,0 +1,29 @@
+package org.barcodeapi.server.admin;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.barcodeapi.server.cache.BarcodeCache;
+import org.barcodeapi.server.core.RestHandler;
+import org.barcodeapi.server.gen.CodeType;
+import org.eclipse.jetty.server.Request;
+
+public class CacheClearHandler extends RestHandler {
+
+	public CacheClearHandler() {
+		super();
+	}
+
+	@Override
+	public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
+			throws IOException, ServletException {
+		super.handle(target, baseRequest, request, response);
+
+		for (CodeType type : CodeType.values()) {
+			BarcodeCache.getCache(type).clearCache();
+		}
+	}
+}

+ 36 - 0
src/main/java/org/barcodeapi/server/admin/CacheDumpHandler.java

@@ -0,0 +1,36 @@
+package org.barcodeapi.server.admin;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.barcodeapi.server.cache.BarcodeCache;
+import org.barcodeapi.server.core.RestHandler;
+import org.barcodeapi.server.gen.CodeType;
+import org.eclipse.jetty.server.Request;
+
+public class CacheDumpHandler extends RestHandler {
+
+	public CacheDumpHandler() {
+		super();
+	}
+
+	@Override
+	public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
+			throws IOException, ServletException {
+		super.handle(target, baseRequest, request, response);
+
+		// loop all caches
+		String output = "";
+		for (CodeType type : CodeType.values()) {
+			for (String key : BarcodeCache.getCache(type).getKeys()) {
+				output += type.toString() + ":" + key + "\n";
+			}
+		}
+
+		// write to client
+		response.getOutputStream().println(output);
+	}
+}

+ 26 - 0
src/main/java/org/barcodeapi/server/admin/SessionClearHandler.java

@@ -0,0 +1,26 @@
+package org.barcodeapi.server.admin;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.barcodeapi.server.core.RestHandler;
+import org.barcodeapi.server.session.SessionCache;
+import org.eclipse.jetty.server.Request;
+
+public class SessionClearHandler extends RestHandler {
+
+	public SessionClearHandler() {
+		super();
+	}
+
+	@Override
+	public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
+			throws IOException, ServletException {
+		super.handle(target, baseRequest, request, response);
+
+		SessionCache.getCache().clearCache();
+	}
+}

+ 32 - 0
src/main/java/org/barcodeapi/server/admin/SessionDumpHandler.java

@@ -0,0 +1,32 @@
+package org.barcodeapi.server.admin;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.barcodeapi.server.core.RestHandler;
+import org.barcodeapi.server.session.SessionCache;
+import org.eclipse.jetty.server.Request;
+
+public class SessionDumpHandler extends RestHandler {
+
+	public SessionDumpHandler() {
+		super();
+	}
+
+	@Override
+	public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
+			throws IOException, ServletException {
+		super.handle(target, baseRequest, request, response);
+
+		String output = "";
+		for (String key : SessionCache.getCache().getKeys()) {
+			output += key + "\n";
+		}
+
+		// write to client
+		response.getOutputStream().println(output);
+	}
+}

+ 4 - 3
src/main/java/org/barcodeapi/server/api/StatsHandler.java → src/main/java/org/barcodeapi/server/admin/StatsDumpHandler.java

@@ -1,4 +1,4 @@
-package org.barcodeapi.server.api;
+package org.barcodeapi.server.admin;
 
 import java.io.IOException;
 
@@ -9,9 +9,10 @@ import javax.servlet.http.HttpServletResponse;
 import org.barcodeapi.server.core.RestHandler;
 import org.eclipse.jetty.server.Request;
 
-public class StatsHandler extends RestHandler {
+public class StatsDumpHandler extends RestHandler {
 
-	public StatsHandler() {
+	public StatsDumpHandler() {
+		super();
 	}
 
 	@Override

+ 1 - 0
src/main/java/org/barcodeapi/server/api/BarcodeAPIHandler.java

@@ -21,6 +21,7 @@ public class BarcodeAPIHandler extends RestHandler {
 	private final CachedBarcode BLK;
 
 	public BarcodeAPIHandler() {
+		super();
 
 		try {
 

+ 1 - 0
src/main/java/org/barcodeapi/server/api/BulkHandler.java

@@ -18,6 +18,7 @@ public class BulkHandler extends RestHandler {
 	private static final MultipartConfigElement MULTI_PART_CONFIG = new MultipartConfigElement("./");
 
 	public BulkHandler() {
+		super();
 	}
 
 	@Override

+ 1 - 0
src/main/java/org/barcodeapi/server/api/CacheHandler.java

@@ -14,6 +14,7 @@ import org.eclipse.jetty.server.Request;
 public class CacheHandler extends RestHandler {
 
 	public CacheHandler() {
+		super();
 	}
 
 	@Override

+ 1 - 0
src/main/java/org/barcodeapi/server/api/SessionHandler.java

@@ -12,6 +12,7 @@ import org.eclipse.jetty.server.Request;
 public class SessionHandler extends RestHandler {
 
 	public SessionHandler() {
+		super();
 	}
 
 	@Override

+ 1 - 0
src/main/java/org/barcodeapi/server/api/TypesHandler.java

@@ -15,6 +15,7 @@ import org.json.JSONObject;
 public class TypesHandler extends RestHandler {
 
 	public TypesHandler() {
+		super();
 	}
 
 	@Override

+ 26 - 0
src/main/java/org/barcodeapi/server/core/Authlist.java

@@ -0,0 +1,26 @@
+package org.barcodeapi.server.core;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+
+public class Authlist {
+
+	private static final List<String> authlist;
+
+	static {
+
+		try {
+
+			authlist = Files.readAllLines(Paths.get("authlist.conf"));
+		} catch (Exception e) {
+
+			throw new RuntimeException("Failed to initialize authlist.");
+		}
+	}
+
+	public static List<String> getAuthlist() {
+
+		return authlist;
+	}
+}

+ 1 - 1
src/main/java/org/barcodeapi/server/core/Blacklist.java

@@ -12,7 +12,7 @@ public class Blacklist {
 
 		try {
 
-			blacklist = Files.readAllLines(Paths.get("resources/blacklist.conf"));
+			blacklist = Files.readAllLines(Paths.get("blacklist.conf"));
 		} catch (Exception e) {
 
 			throw new RuntimeException("Failed to initialize blacklist.");

+ 11 - 0
src/main/java/org/barcodeapi/server/core/CachedObject.java

@@ -4,11 +4,14 @@ import java.util.concurrent.TimeUnit;
 
 public abstract class CachedObject {
 
+	private final long timeCreated;
 	private long timeTimeout;
 	private long timeTouched;
 
 	public CachedObject() {
 
+		this.timeCreated = System.currentTimeMillis();
+
 		this.touch();
 		this.setTimeout(60, TimeUnit.MINUTES);
 	}
@@ -17,6 +20,14 @@ public abstract class CachedObject {
 		return this.timeTimeout;
 	}
 
+	public long getTimeCreated() {
+		return this.timeCreated;
+	}
+
+	public long getTimeLastSeen() {
+		return this.timeTouched;
+	}
+
 	public void setTimeout(long timeoutTime, TimeUnit timeoutUnit) {
 		this.timeTimeout = TimeUnit.MILLISECONDS.convert(timeoutTime, timeoutUnit);
 	}

+ 14 - 3
src/main/java/org/barcodeapi/server/core/Log.java

@@ -29,7 +29,6 @@ public class Log {
 		rollLogs();
 	}
 
-	// TODO call this at midnight
 	public static void rollLogs() {
 
 		for (LOG log : LOG.values()) {
@@ -39,9 +38,11 @@ public class Log {
 
 			try {
 
+				// close open file descriptor
 				if (logFiles.containsKey(log)) {
 					logFiles.get(log).close();
 				}
+
 				logFiles.put(log, new PrintWriter(new FileWriter(f, true), true));
 				Log.out(LOG.SERVER, "Setup log file: " + f.getPath());
 			} catch (Exception e) {
@@ -57,13 +58,23 @@ public class Log {
 		// format log line
 		String output = getTime() + " : " + type.toString() + " : " + message;
 
-		// write to log file and out
+		// write to log file
 		logFiles.get(type).println(output);
-		System.out.println(output);
 	}
 
 	public static String getTime() {
 
 		return _DFORMAT.format(Calendar.getInstance().getTime());
 	}
+
+	public static long timeTillRotate() {
+
+		Calendar midnight = Calendar.getInstance();
+		midnight.set(Calendar.HOUR_OF_DAY, 0);
+		midnight.set(Calendar.MINUTE, 0);
+		midnight.set(Calendar.SECOND, 0);
+		midnight.set(Calendar.MILLISECOND, 1);
+		midnight.set(Calendar.DAY_OF_YEAR, midnight.get(Calendar.DAY_OF_YEAR) + 1);
+		return midnight.getTimeInMillis() - System.currentTimeMillis() - 1;
+	}
 }

+ 7 - 0
src/main/java/org/barcodeapi/server/core/ObjectCache.java

@@ -80,6 +80,13 @@ public class ObjectCache {
 		return cache.remove(key);
 	}
 
+	public void clearCache() {
+
+		double num = cache.size();
+		stats.incrementCounter("cache." + name + ".clear", num);
+		cache.clear();
+	}
+
 	public static synchronized ObjectCache getCache(String name) {
 
 		if (!caches.containsKey(name)) {

+ 11 - 9
src/main/java/org/barcodeapi/server/core/RestHandler.java

@@ -15,7 +15,9 @@ import org.barcodeapi.server.statistics.StatsCollector;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.handler.AbstractHandler;
 
-public class RestHandler extends AbstractHandler {
+public abstract class RestHandler extends AbstractHandler {
+
+	private final String _NAME;
 
 	private final String serverName;
 
@@ -23,6 +25,10 @@ public class RestHandler extends AbstractHandler {
 
 	public RestHandler() {
 
+		// extract class name
+		String className = getClass().getName();
+		_NAME = className.substring(className.lastIndexOf('.') + 1);
+
 		try {
 			serverName = InetAddress.getLocalHost().getHostName();
 		} catch (Exception e) {
@@ -48,10 +54,6 @@ public class RestHandler extends AbstractHandler {
 		baseRequest.setHandled(true);
 		response.setStatus(HttpServletResponse.SC_OK);
 
-		// extract class name
-		String className = getClass().getName();
-		className = className.substring(className.lastIndexOf('.') + 1);
-
 		// get source of the request
 		String source;
 		String ref = request.getHeader("Referer");
@@ -72,18 +74,18 @@ public class RestHandler extends AbstractHandler {
 		}
 
 		// log the request
-		Log.out(LOG.REQUEST,
-				className + " : " + target + " : " + baseRequest.getRemoteAddr() + " : " + source + " : " + from);
+		Log.out(LOG.REQUEST, "" + //
+				_NAME + " : " + target + " : " + baseRequest.getRemoteAddr() + " : " + source + " : " + from);
 
 		// hit the counters
 		getStats().incrementCounter("request.count.total");
-		getStats().incrementCounter("request.count." + className);
+		getStats().incrementCounter("request.count." + _NAME);
 		getStats().incrementCounter("request.method." + request.getMethod());
 
 		// add CORS headers
 		addCORS(baseRequest, response);
 
-		// done if options request
+		// TODO make this end the call
 		if (request.getMethod().equals("OPTIONS")) {
 			return;
 		}

+ 12 - 9
src/main/java/org/barcodeapi/server/session/CachedSession.java

@@ -11,14 +11,12 @@ import org.barcodeapi.server.core.CachedObject;
 public class CachedSession extends CachedObject {
 
 	private final String key;
-	private final long timeCreated;
 	private final ConcurrentHashMap<String, Integer> sessionRequests;
 
 	public CachedSession() {
 		this.setTimeout(6, TimeUnit.HOURS);
 
 		this.key = UUID.randomUUID().toString();
-		this.timeCreated = System.currentTimeMillis();
 		this.sessionRequests = new ConcurrentHashMap<String, Integer>();
 	}
 
@@ -41,17 +39,22 @@ public class CachedSession extends CachedObject {
 
 	public String getDetails() {
 
-		String details = "" + //
-				"Key: " + getKey() + "\n" + //
-				"Created: " + timeCreated + "\n" + //
-				"Requests: " + sessionRequests.size() + "\n";
-
+		String requests = "";
+		int requestCount = 0;
 		for (String key : sessionRequests.keySet()) {
 
-			details += String.format("%s :: %s\n", sessionRequests.get(key), key);
+			int count = sessionRequests.get(key);
+			requestCount += count;
+
+			requests += String.format("%4d :: %s\n", count, key);
 		}
 
-		return details;
+		return "\n" + //
+				" Key: " + getKey() + "\n" + //
+				" Created: " + getTimeCreated() + "\n" + //
+				" Last Seen: " + getTimeLastSeen() + "\n" + //
+				" Request Count: " + requestCount + "\n" + //
+				"\n  --\n\n" + requests;
 	}
 
 	public Cookie getCookie() {

+ 16 - 0
src/main/java/org/barcodeapi/server/tasks/LogRotateTask.java

@@ -0,0 +1,16 @@
+package org.barcodeapi.server.tasks;
+
+import org.barcodeapi.server.core.BackgroundTask;
+import org.barcodeapi.server.core.Log;
+
+public class LogRotateTask extends BackgroundTask {
+
+	public LogRotateTask() {
+		super();
+	}
+
+	@Override
+	public void onRun() {
+		Log.rollLogs();
+	}
+}