![JAR search and dependency download from the Maven repository](/logo.png)
de.datasecs.hydra.shared.protocol.packets.Packet Maven / Gradle / Ivy
The newest version!
package de.datasecs.hydra.shared.protocol.packets;
import io.netty.buffer.ByteBuf;
import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
import java.util.stream.StreamSupport;
/**
* Created with love by DataSecs on 29.09.2017.
*/
@SuppressWarnings("unchecked")
public abstract class Packet {
private Object objectToSerialize;
public abstract void read(ByteBuf byteBuf);
public abstract void write(ByteBuf byteBuf);
protected void writeInt(ByteBuf byteBuf, int integer) {
byteBuf.writeInt(integer);
}
protected int readInt(ByteBuf byteBuf) {
return byteBuf.readInt();
}
protected void writeString(ByteBuf byteBuf, String string) {
byte[] bytes = string.getBytes(StandardCharsets.UTF_8);
byteBuf.writeInt(bytes.length);
byteBuf.writeBytes(bytes);
}
protected String readString(ByteBuf byteBuf) {
byte[] bytes = new byte[byteBuf.readInt()];
byteBuf.readBytes(bytes);
return new String(bytes, StandardCharsets.UTF_8);
}
// TODO: Add serialization for custom objects that are send using .send(customObject) or whenever this method is called
protected void writeObject(ByteBuf byteBuf, Object object) {
if (object == null) {
throw new IllegalArgumentException("object cannot be null");
}
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) {
objectOutputStream.writeObject(object);
byte[] bytes = byteArrayOutputStream.toByteArray();
byteBuf.writeInt(bytes.length);
byteBuf.writeBytes(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
protected Object readObject(ByteBuf byteBuf) {
Object object = null;
int length = byteBuf.readInt();
if (length > byteBuf.readableBytes()) {
throw new IllegalStateException("length cannot be larger than the readable bytes");
}
byte[] bytes = new byte[length];
byteBuf.readBytes(bytes);
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)) {
object = objectInputStream.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return object;
}
protected void writeCustomObject(ByteBuf byteBuf, T customObject) {
// Send path for rebuild of custom class
writeString(byteBuf, customObject.getClass().getName());
// Serialize objects and send them as String(fieldName) + Object(value)
writeCustomObject(byteBuf, customObject, "");
// Signalizes that transmission is over
writeString(byteBuf, "~");
}
private void writeCustomObject(ByteBuf byteBuf, T customObject, String prefix) {
Field[] declaredFields = customObject.getClass().getDeclaredFields();
for (int i = 0; i < declaredFields.length - 1; i++) {
serializeField(byteBuf, declaredFields[i], prefix, customObject);
}
prefix = prefix.startsWith("#") ? "§" + prefix : prefix;
serializeField(byteBuf, declaredFields[declaredFields.length - 1], prefix, customObject);
}
private void serializeField(ByteBuf byteBuf, Field declaredField, String prefix, T customObject) {
if (!Modifier.isTransient(declaredField.getModifiers())) {
boolean isAccessible = declaredField.isAccessible();
declaredField.setAccessible(true);
try {
objectToSerialize = declaredField.get(customObject);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
// Ignore if object is null
if (objectToSerialize == null) {
return;
}
if (!(objectToSerialize instanceof Serializable)) {
writeString(byteBuf, String.format("$%s#%s;%s", prefix, objectToSerialize.getClass().getCanonicalName(), declaredField.getName()));
writeCustomObject(byteBuf, objectToSerialize, String.format("%s#", prefix));
} else {
writeString(byteBuf, String.format("%s%s", prefix, declaredField.getName()));
writeObject(byteBuf, objectToSerialize);
}
declaredField.setAccessible(isAccessible);
}
}
protected T readCustomObject(ByteBuf byteBuf) {
T customObject = null;
try {
customObject = (T) Class.forName(readString(byteBuf)).getDeclaredConstructor().newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return readCustomObject(byteBuf, customObject);
}
protected T readCustomObject(ByteBuf byteBuf, T object) {
String input;
while (!(input = readString(byteBuf)).startsWith("~")) {
// $ indicates the beginning of an embedded class
if (input.startsWith("$")) {
input = input.replace("#", "");
T subObject = getNewInstance(input.substring(1, input.lastIndexOf(";")));
subObject = readCustomObject(byteBuf, subObject);
setField(object, input.substring(input.lastIndexOf(";") + 1), subObject);
}
// § indicates the last object of an embedded class. Read it and then return object because it's complete
else if (input.startsWith("§")) {
setField(object, input.substring(1).replace("#", ""), readObject(byteBuf));
return object;
} else {
if (input.startsWith("#")) {
input = input.replace("#", "");
}
setField(object, input, readObject(byteBuf));
}
}
return object;
}
private T getNewInstance(String path) {
try {
return (T) Class.forName(path).getDeclaredConstructor().newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void setField(T customObject, String fieldName, Object fieldValue) {
boolean isAccessible;
Field field = null;
try {
field = customObject.getClass().getDeclaredField(fieldName);
isAccessible = field.isAccessible();
field.setAccessible(true);
field.set(customObject, fieldValue);
field.setAccessible(isAccessible);
} catch (Exception e) {
e.printStackTrace();
String stringBuilder = "\nAdditional information:\n" +
"customObject: " + customObject + "\n" +
"Field name: " + fieldName + "\n" +
"Field value: " + fieldValue + "\n" +
"Found field by name: " + field + "\n" +
"Field Accessibility: "
+ (field == null ? "Could not print accessibility, field == null" : field.isAccessible())
+ "\n";
System.err.println(stringBuilder);
}
}
protected void writeArray(ByteBuf byteBuf, Object[] array) {
writeObject(byteBuf, array);
}
protected T[] readArray(ByteBuf byteBuf) {
int length = byteBuf.readInt();
if (length > byteBuf.readableBytes()) {
throw new IllegalStateException("length can't be larger than the readable bytes");
}
byte[] bytes = new byte[length];
byteBuf.readBytes(bytes);
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)) {
return (T[]) objectInputStream.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
protected void writeCustomClassArray(ByteBuf byteBuf, T[] array) {
writeInt(byteBuf, array.length);
writeString(byteBuf, array.getClass().getCanonicalName().replace("[]", ""));
for (T t : array) {
writeCustomObject(byteBuf, t);
}
}
protected T[] readCustomClassArray(ByteBuf byteBuf) {
int length = readInt(byteBuf);
String path = readString(byteBuf);
T[] array = null;
try {
array = (T[]) Array.newInstance(Class.forName(path), length);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Objects.requireNonNull(array, "Array could not be instantiated.");
for (int i = 0; i < length; i++) {
array[i] = readCustomObject(byteBuf);
}
return array;
}
protected void writeCustomClassCollection(ByteBuf byteBuf, Collection collection) {
writeInt(byteBuf, collection.size());
writeString(byteBuf, collection.getClass().getCanonicalName());
collection.forEach(object -> writeCustomObject(byteBuf, object));
}
protected Collection readCustomClassCollection(ByteBuf byteBuf) {
int length = readInt(byteBuf);
Collection collection = null;
try {
collection = (Collection) Class.forName(readString(byteBuf)).getDeclaredConstructor().newInstance();
} catch (Exception e) {
e.printStackTrace();
}
Objects.requireNonNull(collection);
for (int i = 0; i < length; i++) {
collection.add(readCustomObject(byteBuf));
}
return collection;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy