diff --git a/api/src/main/java/zone/themcgamer/api/API.java b/api/src/main/java/zone/themcgamer/api/API.java index 1e3be45..2060d3a 100644 --- a/api/src/main/java/zone/themcgamer/api/API.java +++ b/api/src/main/java/zone/themcgamer/api/API.java @@ -11,8 +11,8 @@ import zone.themcgamer.api.model.ModelSerializer; import zone.themcgamer.api.model.impl.*; import zone.themcgamer.api.repository.AccountRepository; import zone.themcgamer.api.route.AccountRoute; +import zone.themcgamer.api.route.PlayerStatusRoute; import zone.themcgamer.api.route.ServersRoute; -import zone.themcgamer.api.route.StatusRoute; import zone.themcgamer.data.APIAccessLevel; import zone.themcgamer.data.jedis.JedisController; import zone.themcgamer.data.jedis.data.APIKey; @@ -57,12 +57,12 @@ public class API { addModel(NodeModel.class); addModel(ServerGroupModel.class); addModel(AccountModel.class); - addModel(StatusModel.class); + addModel(PlayerStatusModel.class); // Adding the routes addRoute(new ServersRoute()); addRoute(new AccountRoute(accountRepository)); - addRoute(new StatusRoute()); + addRoute(new PlayerStatusRoute()); // 404 Handling Spark.notFound((request, response) -> { @@ -110,6 +110,8 @@ public class API { System.out.println("Handling incoming request from \"" + request.ip() + "\" using path \"" + request.pathInfo() + "\""); APIKey key = new APIKey(UUID.randomUUID().toString(), APIAccessLevel.STANDARD); + // If authentication is enabled, handle the api key checking and display a Unauthorized error + // if there is a problem checking the key or the key is invalid if (requiresAuthentication) { String apiKey = request.headers("key"); if (apiKey == null) @@ -133,7 +135,9 @@ public class API { if (method.getParameterTypes().length != 3) throw new APIException("Invalid route defined"); Object object = method.invoke(entry.getKey(), request, response, key); - jsonObject.addProperty("success", "true"); + jsonObject.addProperty("success", "true"); // Marking the request as successful in the JsonObject + + // Format the Object returned from the route accordingly if (object instanceof IModel) { if (models.contains(object.getClass())) jsonObject.add("value", gson.toJsonTree(((IModel) object).toMap(), HashMap.class)); @@ -144,13 +148,17 @@ public class API { jsonObject.add("value", gson.toJsonTree(object, HashMap.class)); else jsonObject.addProperty("value", object.toString()); } catch (Throwable ex) { + // If there is an error thrown from a route, we wanna fetch the error from the invoke method + // and get the cause of the exception if (ex instanceof InvocationTargetException) ex = ex.getCause(); String message = ex.getLocalizedMessage(); + // If the exception has no message associated with it, display the type of exception instead if (message == null || (message.trim().isEmpty())) message = ex.getClass().getSimpleName(); jsonObject.addProperty("success", "false"); jsonObject.addProperty("error", message); + // If the caught exception is not an API exception, print the stacktrace if (!(ex instanceof APIException)) { System.err.println("The route \"" + entry.getKey().getClass().getSimpleName() + "\" raised an exception:"); ex.printStackTrace(); @@ -162,10 +170,20 @@ public class API { } } + /** + * Adding a {@link IModel} + * + * @param modelClass the class of the model to add + */ private static void addModel(Class modelClass) { models.add(modelClass); } + /** + * Adding a route + * + * @param object the instance of the route to add + */ private static void addRoute(Object object) { List methods = routes.getOrDefault(object, new ArrayList<>()); for (Method method : object.getClass().getMethods()) { diff --git a/api/src/main/java/zone/themcgamer/api/APIException.java b/api/src/main/java/zone/themcgamer/api/APIException.java index 04d3ba5..1b2164c 100644 --- a/api/src/main/java/zone/themcgamer/api/APIException.java +++ b/api/src/main/java/zone/themcgamer/api/APIException.java @@ -1,16 +1,14 @@ package zone.themcgamer.api; +import lombok.NoArgsConstructor; + /** + * This {@link RuntimeException} gets thrown when there is a problem handling a {@link RestPath} + * * @author Braydon */ +@NoArgsConstructor public class APIException extends RuntimeException { - /** - * Constructs a new runtime exception with {@code null} as its - * detail message. The cause is not initialized, and may subsequently be - * initialized by a call to {@link #initCause}. - */ - public APIException() {} - /** * Constructs a new runtime exception with the specified detail message. * The cause is not initialized, and may subsequently be initialized by a diff --git a/api/src/main/java/zone/themcgamer/api/APIVersion.java b/api/src/main/java/zone/themcgamer/api/APIVersion.java index 6ccc0ed..08fc4fa 100644 --- a/api/src/main/java/zone/themcgamer/api/APIVersion.java +++ b/api/src/main/java/zone/themcgamer/api/APIVersion.java @@ -4,6 +4,8 @@ import lombok.AllArgsConstructor; import lombok.Getter; /** + * The API version is used in {@link RestPath}. It represents the version the path is using + * * @author Braydon */ @AllArgsConstructor @Getter diff --git a/api/src/main/java/zone/themcgamer/api/RestPath.java b/api/src/main/java/zone/themcgamer/api/RestPath.java index ab8b135..250d8ec 100644 --- a/api/src/main/java/zone/themcgamer/api/RestPath.java +++ b/api/src/main/java/zone/themcgamer/api/RestPath.java @@ -8,6 +8,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** + * This annotation represents information for a specific Rest path + * * @author Braydon */ @Retention(RetentionPolicy.RUNTIME) diff --git a/api/src/main/java/zone/themcgamer/api/model/IModel.java b/api/src/main/java/zone/themcgamer/api/model/IModel.java index 0dbd7b5..b3553e2 100644 --- a/api/src/main/java/zone/themcgamer/api/model/IModel.java +++ b/api/src/main/java/zone/themcgamer/api/model/IModel.java @@ -3,6 +3,8 @@ package zone.themcgamer.api.model; import java.util.HashMap; /** + * This interface represents a custom Object that will displayed as json when handling requests + * * @author Braydon */ public interface IModel { diff --git a/api/src/main/java/zone/themcgamer/api/model/ModelSerializer.java b/api/src/main/java/zone/themcgamer/api/model/ModelSerializer.java index 3f33b54..77ff7c4 100644 --- a/api/src/main/java/zone/themcgamer/api/model/ModelSerializer.java +++ b/api/src/main/java/zone/themcgamer/api/model/ModelSerializer.java @@ -9,6 +9,8 @@ import java.lang.reflect.Type; import java.util.Map; /** + * This class handles serializing of {@link IModel}'s + * * @author Braydon */ public class ModelSerializer implements JsonSerializer { diff --git a/api/src/main/java/zone/themcgamer/api/model/impl/StatusModel.java b/api/src/main/java/zone/themcgamer/api/model/impl/PlayerStatusModel.java similarity index 93% rename from api/src/main/java/zone/themcgamer/api/model/impl/StatusModel.java rename to api/src/main/java/zone/themcgamer/api/model/impl/PlayerStatusModel.java index cb731ad..c0cc3a5 100644 --- a/api/src/main/java/zone/themcgamer/api/model/impl/StatusModel.java +++ b/api/src/main/java/zone/themcgamer/api/model/impl/PlayerStatusModel.java @@ -13,7 +13,7 @@ import java.util.UUID; * @author Braydon */ @AllArgsConstructor @Setter @Getter @ToString -public class StatusModel implements IModel { +public class PlayerStatusModel implements IModel { private final UUID uuid; private final String playerName; private String server; diff --git a/api/src/main/java/zone/themcgamer/api/repository/AccountRepository.java b/api/src/main/java/zone/themcgamer/api/repository/AccountRepository.java index 81c58a8..9401a3f 100644 --- a/api/src/main/java/zone/themcgamer/api/repository/AccountRepository.java +++ b/api/src/main/java/zone/themcgamer/api/repository/AccountRepository.java @@ -14,6 +14,8 @@ import java.util.Objects; import java.util.UUID; /** + * This repository handles fetching of {@link AccountModel}'s from MySQL + * * @author Braydon */ public class AccountRepository extends MySQLRepository { @@ -23,6 +25,12 @@ public class AccountRepository extends MySQLRepository { super(dataSource); } + /** + * Fetch the {@link AccountModel} with the provided {@link UUID} + * + * @param uuid the uuid of the account + * @return the account, null if it doesn't exist + */ public AccountModel getAccount(UUID uuid) { AccountModel[] model = new AccountModel[] { null }; executeQuery(SELECT_ACCOUNT, new Column[] { @@ -40,6 +48,7 @@ public class AccountRepository extends MySQLRepository { /** * Construct a {@link AccountModel} from the given parameters + * * @param uuid the uuid * @param resultSet the result set * @return the account diff --git a/api/src/main/java/zone/themcgamer/api/route/AccountRoute.java b/api/src/main/java/zone/themcgamer/api/route/AccountRoute.java index b9d4492..5f63467 100644 --- a/api/src/main/java/zone/themcgamer/api/route/AccountRoute.java +++ b/api/src/main/java/zone/themcgamer/api/route/AccountRoute.java @@ -18,6 +18,8 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; /** + * This route handles everything associated with {@link AccountModel} + * * @author Braydon */ @AllArgsConstructor @@ -29,6 +31,9 @@ public class AccountRoute { private final AccountRepository accountRepository; + /** + * This path handles displaying the {@link AccountModel} with the given {@link UUID} + */ @RestPath(path = "/account/:uuid", version = APIVersion.V1) public AccountModel get(Request request, Response response, APIKey apiKey) throws APIException { UUID uuid = MiscUtils.getUuid(request.params(":uuid")); diff --git a/api/src/main/java/zone/themcgamer/api/route/StatusRoute.java b/api/src/main/java/zone/themcgamer/api/route/PlayerStatusRoute.java similarity index 77% rename from api/src/main/java/zone/themcgamer/api/route/StatusRoute.java rename to api/src/main/java/zone/themcgamer/api/route/PlayerStatusRoute.java index 5244779..3c34a2e 100644 --- a/api/src/main/java/zone/themcgamer/api/route/StatusRoute.java +++ b/api/src/main/java/zone/themcgamer/api/route/PlayerStatusRoute.java @@ -5,7 +5,7 @@ import spark.Response; import zone.themcgamer.api.APIException; import zone.themcgamer.api.APIVersion; import zone.themcgamer.api.RestPath; -import zone.themcgamer.api.model.impl.StatusModel; +import zone.themcgamer.api.model.impl.PlayerStatusModel; import zone.themcgamer.data.APIAccessLevel; import zone.themcgamer.data.jedis.cache.CacheRepository; import zone.themcgamer.data.jedis.cache.ICacheItem; @@ -19,15 +19,20 @@ import java.util.List; import java.util.Map; /** + * This route handles everything associated with {@link PlayerStatusModel} + * * @author Braydon */ -public class StatusRoute { +public class PlayerStatusRoute { private final CacheRepository repository; - public StatusRoute() { + public PlayerStatusRoute() { repository = RedisRepository.getRepository(CacheRepository.class).orElse(null); } + /** + * This path handles displaying of all of the {@link PlayerStatusModel}'s + */ @RestPath(path = "/status", version = APIVersion.V1) public Map getStatuses(Request request, Response response, APIKey apiKey) throws APIException { List> statuses = repository.filter(cacheItem -> cacheItem.getType() == ItemCacheType.PLAYER_STATUS); @@ -44,8 +49,11 @@ public class StatusRoute { }}; } + /** + * This path handles displaying the {@link PlayerStatusModel} with the given name + */ @RestPath(path = "/status/:name", version = APIVersion.V1) - public StatusModel getStatus(Request request, Response response, APIKey apiKey) throws APIException { + public PlayerStatusModel getStatus(Request request, Response response, APIKey apiKey) throws APIException { String name = request.params(":name"); if (name == null || (name.trim().isEmpty() || name.length() > 16)) throw new APIException("Invalid username"); @@ -54,7 +62,7 @@ public class StatusRoute { .stream().findFirst().orElse(null); if (statusCache == null) throw new APIException("Player not found"); - StatusModel model = new StatusModel(statusCache.getUuid(), statusCache.getPlayerName(), statusCache.getServer(), statusCache.getTimeJoined()); + PlayerStatusModel model = new PlayerStatusModel(statusCache.getUuid(), statusCache.getPlayerName(), statusCache.getServer(), statusCache.getTimeJoined()); if (apiKey.getAccessLevel() == APIAccessLevel.STANDARD) model.setServer("Unauthorized"); return model; diff --git a/api/src/main/java/zone/themcgamer/api/route/ServersRoute.java b/api/src/main/java/zone/themcgamer/api/route/ServersRoute.java index 88cdc31..2fb80e1 100644 --- a/api/src/main/java/zone/themcgamer/api/route/ServersRoute.java +++ b/api/src/main/java/zone/themcgamer/api/route/ServersRoute.java @@ -20,6 +20,8 @@ import java.util.List; import java.util.Optional; /** + * This route handles everything associated with {@link ServerGroupModel} and {@link MinecraftServerModel} + * * @author Braydon */ public class ServersRoute { @@ -31,10 +33,9 @@ public class ServersRoute { minecraftServerRepository = RedisRepository.getRepository(MinecraftServerRepository.class).orElse(null); } - /* - Server Groups + /** + * This path handles displaying of all of the {@link ServerGroupModel}'s */ - @RestPath(path = "/serverGroups", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV) public List getGroups(Request request, Response response, APIKey apiKey) throws APIException { List models = new ArrayList<>(); @@ -43,6 +44,9 @@ public class ServersRoute { return models; } + /** + * This path handles displaying the {@link ServerGroupModel} with the given name + */ @RestPath(path = "/serverGroup/:name", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV) public ServerGroupModel getServerGroup(Request request, Response response, APIKey apiKey) throws APIException { String name = request.params(":name"); @@ -54,10 +58,9 @@ public class ServersRoute { return ServerGroupModel.fromServerGroup(optionalServerGroup.get()); } - /* - Minecraft Servers + /** + * This path handles displaying of all of the {@link MinecraftServerModel}'s */ - @RestPath(path = "/minecraftServers", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV) public List getMinecraftServers(Request request, Response response, APIKey apiKey) throws APIException { List models = new ArrayList<>(); @@ -66,6 +69,9 @@ public class ServersRoute { return models; } + /** + * This path handles displaying the {@link MinecraftServerModel} with the given id + */ @RestPath(path = "/minecraftServer/:id", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV) public MinecraftServerModel getMinecraftServer(Request request, Response response, APIKey apiKey) throws APIException { String id = request.params(":id");