PandaLib/pandalib-ws/src/main/java/fr/pandacube/lib/ws/PayloadRegistry.java

104 lines
3.8 KiB
Java
Raw Normal View History

2023-03-14 16:22:50 +01:00
package fr.pandacube.lib.ws;
import com.google.gson.JsonParseException;
import fr.pandacube.lib.core.json.Json;
import fr.pandacube.lib.util.BiMap;
import fr.pandacube.lib.ws.payloads.ErrorPayload;
import fr.pandacube.lib.ws.payloads.LoginPayload;
import fr.pandacube.lib.ws.payloads.LoginSucceedPayload;
import fr.pandacube.lib.ws.payloads.MessagePayload;
import fr.pandacube.lib.ws.payloads.Payload;
import java.util.regex.Pattern;
/**
* Handles the registration of all the {@link Payload} types, the serialization and deserialization of the payload data.
*/
public class PayloadRegistry {
private static final String PAYLOAD_TYPE_SEPARATOR = ":";
private static final BiMap<String, Class<? extends Payload>> payloadClasses = new BiMap<>();
private static boolean isTypeValid(String type) {
return !type.contains(PAYLOAD_TYPE_SEPARATOR);
}
private static String validateType(String type) {
if (isTypeValid(type))
return type;
throw new IllegalArgumentException("Invalid characters in type identifier '" + type + "'");
}
/**
* Register a new {@link Payload} type.
* @param type the id of the payload type.
* @param clazz the payload class to register.
*/
public static void registerPayloadType(String type, Class<? extends Payload> clazz) {
payloadClasses.put(validateType(type), clazz);
}
/**
* Deserialize the provided String into a valid Payload.
* @param message the serialized data.
* @return the {@link Payload}.
* @throws IllegalArgumentException if the serialized data does not have the proper format.
*/
public static Payload fromString(String message) {
String[] split = message.split(Pattern.quote(PAYLOAD_TYPE_SEPARATOR), 2);
if (split.length != 2) {
throw new IllegalArgumentException("Malformed message: does not respect format <type>" + PAYLOAD_TYPE_SEPARATOR + "<jsonObject>.");
2023-03-14 16:22:50 +01:00
}
Class<? extends Payload> detectedClass = payloadClasses.get(split[0]);
if (detectedClass == null) {
throw new IllegalArgumentException("Unrecognized data type " + split[0] + ".");
2023-03-14 16:22:50 +01:00
}
try {
return Json.gson.fromJson(split[1], detectedClass);
} catch (JsonParseException e) {
throw new IllegalArgumentException(e.toString());
}
}
/**
* Serialize the provided {@link Payload}.
* @param p the {@link Payload} to serialize. Must be of a registered type.
* @return the serialized data.
* @throws JsonParseException if the json is invalid.
2023-03-14 16:22:50 +01:00
*/
public static String toString(Payload p) throws JsonParseException {
2023-03-14 16:22:50 +01:00
String type = payloadClasses.getKey(p.getClass());
if (type == null)
throw new IllegalArgumentException(p.getClass() + " is not a registered payload type.");
return arbitraryToString(type, p, false);
}
/**
* Serialize the provided arbitrary data, that consist of a type and an object that will be converted
* to a Json string.
* @param type the type
* @param obj the object to Jsonify
* @param serializeNulls if null properties must be included in the json object.
2023-03-14 16:22:50 +01:00
* @return the String to send through the websocket
* @throws JsonParseException if the json is invalid.
2023-03-14 16:22:50 +01:00
*/
public static String arbitraryToString(String type, Object obj, boolean serializeNulls) throws JsonParseException {
2023-03-14 16:22:50 +01:00
return validateType(type) + PAYLOAD_TYPE_SEPARATOR + (serializeNulls ? Json.gsonSerializeNulls : Json.gson).toJson(obj);
}
static {
registerPayloadType("error", ErrorPayload.class);
registerPayloadType("message", MessagePayload.class);
registerPayloadType("login", LoginPayload.class);
registerPayloadType("login-succeed", LoginSucceedPayload.class);
}
}