第一次提交

This commit is contained in:
wyw
2024-08-08 00:31:26 +08:00
commit c202e2b63d
1819 changed files with 221890 additions and 0 deletions

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>fastbee-protocol</artifactId>
<groupId>com.fastbee</groupId>
<version>3.8.5</version>
</parent>
<description>网关协议管理模块</description>
<artifactId>fastbee-protocol-base</artifactId>
<dependencies>
<dependency>
<groupId>com.fastbee</groupId>
<artifactId>fastbee-iot-service</artifactId>
</dependency>
<dependency>
<groupId>com.fastbee</groupId>
<artifactId>base-server</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,33 @@
package com.fastbee.protocol;
import com.fastbee.protocol.base.model.WModel;
import com.fastbee.protocol.util.SingleVersionUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
/**
* @author bill
*/
public class PrepareLoadStore<T> {
private final Map<T, WModel> models = new TreeMap<>();
public PrepareLoadStore<T> addSchema(T key, WModel schema) {
models.put(key, schema);
return this;
}
public PrepareLoadStore<T> addSchema(T key, Class typeClass) {
WModel<Object> model = SingleVersionUtils.getActiveModel(typeClass);
models.put(key, model);
return this;
}
public Map<T, WModel> build() {
Map<T, WModel> a = new HashMap<>(models.size());
a.putAll(models);
return a;
}
}

View File

@ -0,0 +1,147 @@
package com.fastbee.protocol;
import com.fastbee.protocol.base.annotation.Column;
import com.fastbee.protocol.base.annotation.Columns;
import com.fastbee.protocol.base.annotation.MergeSubClass;
import com.fastbee.protocol.base.model.ActiveModel;
import com.fastbee.protocol.base.model.ModelRegistry;
import com.fastbee.protocol.base.model.WModel;
import com.fastbee.protocol.base.struc.BaseStructure;
import com.fastbee.protocol.util.ArrayMap;
import com.fastbee.protocol.util.ClassUtils;
import java.lang.reflect.Field;
import java.util.*;
/**
* 消息架构加载
* @author bill
*/
public class ProtocolLoadUtils {
private static final Map<String, ArrayMap<ActiveModel>> CACHE = new WeakHashMap<>();
public static ArrayMap<ActiveModel> getActiveMap(Class typeClass) {
return getActiveMap(CACHE, typeClass);
}
public static ActiveModel getActiveMap(Class typeClass, int version) {
ArrayMap<ActiveModel> schemaMap = getActiveMap(CACHE, typeClass);
if (schemaMap == null) return null;
return schemaMap.getOrDefault(version);
}
public static ArrayMap<ActiveModel> getActiveMap(Map<String, ArrayMap<ActiveModel>> root, final Class typeClass) {
ArrayMap<ActiveModel> schemaMap = root.get(typeClass.getName());
//不支持循环引用
if (schemaMap != null) return schemaMap;
List<Field> fs = findFields(typeClass);
if (fs.isEmpty()) return null;
root.put(typeClass.getName(), schemaMap = new ArrayMap<>());
Map<Integer, Set<BaseStructure>> multiVersionFields = findMultiVersionFields(root, fs);
Set<BaseStructure> defFields = multiVersionFields.get(Integer.MAX_VALUE);
for (Map.Entry<Integer, Set<BaseStructure>> entry : multiVersionFields.entrySet()) {
Integer version = entry.getKey();
Set<BaseStructure> fieldList = entry.getValue();
if (defFields != null && !version.equals(Integer.MAX_VALUE)) {
for (BaseStructure defField : defFields) {
if (!fieldList.contains(defField))
fieldList.add(defField);
}
}
BaseStructure[] fields = fieldList.toArray(new BaseStructure[fieldList.size()]);
Arrays.sort(fields);
ActiveModel schema = new ActiveModel(typeClass, version, fields);
schemaMap.put(version, schema);
}
root.put(typeClass.getName(), schemaMap.fillDefaultValue());
return schemaMap;
}
private static List<Field> findFields(Class typeClass) {
LinkedList<Field> fs = new LinkedList<>();
boolean addFirst = false;
Class<?> temp = typeClass;
while (temp != null) {
if (addFirst)
fs.addAll(0, Arrays.asList(temp.getDeclaredFields()));
else
fs.addAll(Arrays.asList(temp.getDeclaredFields()));
MergeSubClass marge = temp.getAnnotation(MergeSubClass.class);
if (marge == null)
break;
addFirst = marge.addBefore();
temp = typeClass.getSuperclass();
}
List<Field> result = new ArrayList<>(fs.size());
for (Field f : fs) {
if (f.isAnnotationPresent(Columns.class) || f.isAnnotationPresent(Column.class)) {
f.setAccessible(true);
result.add(f);
}
}
return result;
}
private static Map<Integer, Set<BaseStructure>> findMultiVersionFields(Map<String, ArrayMap<ActiveModel>> root, List<Field> fs) {
final int size = fs.size();
Map<Integer, Set<BaseStructure>> multiVersionFields = new TreeMap<Integer, Set<BaseStructure>>() {
@Override
public Set<BaseStructure> get(Object key) {
Set result = super.get(key);
if (result == null) super.put((Integer) key, result = new HashSet(size));
return result;
}
};
for (int i = 0; i < size; i++) {
Field f = fs.get(i);
Column column = f.getDeclaredAnnotation(Column.class);
if (column != null) {
fillField(root, multiVersionFields, column, f, i);
} else {
Column[] clos = f.getDeclaredAnnotation(Columns.class).value();
for (int j = 0; j < clos.length; j++)
fillField(root, multiVersionFields, clos[j], f, i);
}
}
return multiVersionFields;
}
private static void fillField(Map<String, ArrayMap<ActiveModel>> root, Map<Integer, Set<BaseStructure>> multiVersionFields, Column column, Field field, int position) {
BaseStructure BaseStructure = ModelRegistry.get(column, field);
int[] versions = getVersions(column, ALL);
if (BaseStructure != null) {
for (int ver : versions) {
multiVersionFields.get(ver).add(BaseStructure.init(column, field, position));
}
} else {
ArrayMap<ActiveModel> modelMap = getActiveMap(root, ClassUtils.getGenericType(field));
if (versions == ALL)
versions = modelMap.keys();
for (int ver : versions) {
WModel model = modelMap.getOrDefault(ver);
BaseStructure = ModelRegistry.get(column, field, model);
multiVersionFields.get(ver).add(BaseStructure.init(column, field, position));
}
}
}
private static final int[] ALL = {Integer.MAX_VALUE};
private static int[] getVersions(Column column, int[] def) {
int[] result = column.version();
if (result.length == 0)
result = def;
return result;
}
}

View File

@ -0,0 +1,82 @@
package com.fastbee.protocol;
import com.fastbee.protocol.base.annotation.Protocol;
import com.fastbee.protocol.base.model.ActiveModel;
import com.fastbee.protocol.util.ArrayMap;
import com.fastbee.protocol.util.ClassUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 消息架构管理类
*
* @author bill
*/
public class WModelManager {
private final Map<Integer, ArrayMap<ActiveModel>> typeIdMapping;
private final Map<String, ArrayMap<ActiveModel>> typeClassMapping;
public WModelManager() {
this(128);
}
public WModelManager(int initialCapacity) {
this.typeIdMapping = new HashMap<>(initialCapacity);
this.typeClassMapping = new HashMap<>(initialCapacity);
}
public WModelManager(String... basePackages) {
this(256, basePackages);
}
public WModelManager(int initialCapacity, String... basePackages) {
this(initialCapacity);
for (String basePackage : basePackages) {
List<Class> types = ClassUtils.getClassList(basePackage);
for (Class<?> type : types) {
Protocol protocol = type.getAnnotation(Protocol.class);
if (protocol != null) {
int[] values = protocol.value();
for (Integer typeId : values) {
loadRuntimeSchema(typeId, type);
}
}
}
}
}
public void loadRuntimeSchema(Integer typeId, Class typeClass) {
ArrayMap<ActiveModel> schemaMap = ProtocolLoadUtils.getActiveMap(typeClassMapping, typeClass);
if (schemaMap != null) {
typeIdMapping.put(typeId, schemaMap);
}
}
public <T> ActiveModel<T> getActiveMap(Class<T> typeClass, int version) {
ArrayMap<ActiveModel> schemaMap = ProtocolLoadUtils.getActiveMap(typeClassMapping, typeClass);
if (schemaMap == null) {
return null;
}
return schemaMap.getOrDefault(version);
}
public ArrayMap<ActiveModel> getActiveMap(Class typeClass) {
return ProtocolLoadUtils.getActiveMap(typeClassMapping, typeClass);
}
public ActiveModel getActiveMap(Integer typeId, int version) {
ArrayMap<ActiveModel> schemaMap = typeIdMapping.get(typeId);
if (schemaMap == null) {
return null;
}
return schemaMap.getOrDefault(version);
}
public ArrayMap<ActiveModel> getActiveMap(Integer typeId) {
return typeIdMapping.get(typeId);
}
}

View File

@ -0,0 +1,42 @@
package com.fastbee.protocol.base.annotation;
import com.fastbee.protocol.base.model.WModel;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 报文解析字段注解
* @author bill
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
/** 长度 默认使用类型长度 -1读取剩余报文长度*/
int length() default -1;
/** 排序默认按照model字段顺序编解码*/
int index() default 0;
/** 该字段的前置长度 1- BYTE 2-WORD 3.double 4.DWORD */
int lengthUnit() default -1;
/** 该字段的前置数量单位 1- BYTE 2-WORD 3.double 4.DWORD*/
int totalUnit() default -1;
/** 字符集 HEX ,UTF8 ,GBK, BCD...*/
String charset() default "HEX";
/**描述*/
String desc() default "";
/** 版本号 ,默认不区分*/
int[] version() default {};
/** 自定义报文转换器*/
Class<? extends WModel> converter() default WModel.class;
}

View File

@ -0,0 +1,16 @@
package com.fastbee.protocol.base.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author bill
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Columns {
Column[] value();
}

View File

@ -0,0 +1,18 @@
package com.fastbee.protocol.base.annotation;
import java.lang.annotation.*;
/**
* 将父类字段合并到子类
* @author bill
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MergeSubClass {
/**
* 合并父类属性到当前类属性前
*/
boolean addBefore() default false;
}

View File

@ -0,0 +1,18 @@
package com.fastbee.protocol.base.annotation;
import java.lang.annotation.*;
/**
* 协议类型标注
* @author bill
*/
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Protocol {
int[] value() default {};
String desc() default "";
}

View File

@ -0,0 +1,22 @@
package com.fastbee.protocol.base.message;
/**
* 通用消息体
* @author bill
*/
public interface MessageBody {
/**
* 消息体
* @return
*/
byte[] getPayload();
/**
* 消息体长度
* @return
*/
default int getLength(){
return getPayload().length;
}
}

View File

@ -0,0 +1,46 @@
package com.fastbee.protocol.base.message;
/**
* @author bill
*/
public interface MessageHead {
/**
* 设备编号 modbus对应从机编号
* @return
*/
String getSerialNumber();
/**
* 设置设备编号
* @param serialNumber
*/
MessageHead setSerialNumber(String serialNumber);
/**
* 获取消息ID
* @return
*/
String getMessageId();
/**
* 设置消息id
* @param messageId 消息ID
* @return
*/
MessageHead setMessageId(String messageId);
/**
* 消息头data
* @return
*/
byte[] getMessage();
/**
* 消息头长度
* @return
*/
default int getLength() {
return getMessage().length;
}
}

View File

@ -0,0 +1,157 @@
package com.fastbee.protocol.base.model;
import com.fastbee.protocol.base.struc.BaseStructure;
import com.fastbee.protocol.util.ExplainUtils;
import io.netty.buffer.ByteBuf;
import java.lang.reflect.Constructor;
/**
* 运行时根据Class生成的消息结构model序列化对象
* @author bill
*/
public class ActiveModel<T> implements WModel<T>{
protected int version;
protected int length;
protected Class<T> typeClass;
protected BaseStructure[] structures;
protected Constructor<T> constructor;
public ActiveModel(Class<T> typeClass, int version, BaseStructure[] structures) {
this.typeClass = typeClass;
this.version = version;
this.structures = structures;
int length = 0;
for (BaseStructure structure : structures)
length += structure.length();
this.length = length;
try {
this.constructor = typeClass.getDeclaredConstructor((Class[]) null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public T newInstance() {
try {
return constructor.newInstance((Object[]) null);
} catch (Exception e) {
throw new RuntimeException("newInstance failed " + typeClass.getName(), e);
}
}
public T mergeFrom(ByteBuf input, T result) {
int i = 0;
try {
for (; i < structures.length; i++) {
structures[i].readAndSet(input, result);
}
return result;
} catch (Exception e) {
throw new RuntimeException("Read failed " + i + " " + typeClass.getName() + " " + structures[i].filedName(), e);
}
}
public T mergeFrom(ByteBuf input, T result, ExplainUtils explain) {
int i = 0;
try {
if (explain == null)
for (; i < structures.length; i++)
structures[i].readAndSet(input, result);
else
for (; i < structures.length; i++)
structures[i].readAndSet(input, result, explain);
return result;
} catch (Exception e) {
throw new RuntimeException("Read failed " + i + " " + typeClass.getName() + " " + structures[i].filedName(), e);
}
}
@Override
public T readFrom(ByteBuf input) {
int i = 0;
try {
T result = constructor.newInstance((Object[]) null);
for (; i < structures.length; i++) {
structures[i].readAndSet(input, result);
}
return result;
} catch (Exception e) {
throw new RuntimeException("Read failed " + i + " " + typeClass.getName() + " " + structures[i].filedName(), e);
}
}
@Override
public T readFrom(ByteBuf input, ExplainUtils explain) {
int i = 0;
try {
T result = constructor.newInstance((Object[]) null);
if (explain == null) {
for (; i < structures.length; i++) {
structures[i].readAndSet(input, result);
}
} else {
for (; i < structures.length; i++) {
structures[i].readAndSet(input, result, explain);
}
}
return result;
} catch (Exception e) {
throw new RuntimeException("Read failed " + i + " " + typeClass.getName() + " " + structures[i].filedName(), e);
}
}
@Override
public void writeTo(ByteBuf output, T message) {
int i = 0;
try {
for (; i < structures.length; i++) {
structures[i].getAndWrite(output, message);
}
} catch (Exception e) {
throw new RuntimeException("Write failed " + i + " " + typeClass.getName() + " " + structures[i].filedName(), e);
}
}
@Override
public void writeTo(ByteBuf output, T message, ExplainUtils explain) {
int i = 0;
try {
if (explain == null) {
for (; i < structures.length; i++) {
structures[i].getAndWrite(output, message);
}
} else {
for (; i < structures.length; i++) {
structures[i].getAndWrite(output, message, explain);
}
}
} catch (Exception e) {
throw new RuntimeException("Write failed " + i + " " + typeClass.getName() + " " + structures[i].filedName(), e);
}
}
public Class<T> typeClass() {
return typeClass;
}
public int version() {
return version;
}
@Override
public int length() {
return length;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder(48);
sb.append("{typeClass=").append(typeClass.getSimpleName());
sb.append(", version=").append(version);
sb.append(", length=").append(length);
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,168 @@
package com.fastbee.protocol.base.model;
import com.fastbee.protocol.base.struc.BaseStructure;
import io.netty.buffer.ByteBuf;
/**
* @author gsb
* @date 2022/11/9 17:33
*/
public class ArrayModel {
public static final WModel<char[]> CHARS = new CharArray();
public static final WModel<byte[]> BYTES = new ByteArray();
public static final WModel<short[]> SHORTS = new ShortArray();
public static final WModel<int[]> INTS = new IntArray();
public static final WModel<float[]> FLOATS = new FloatArray();
public static final WModel<long[]> LONGS = new LongArray();
public static final WModel<double[]> DOUBLES = new DoubleArray();
protected static class ByteArray extends BaseStructure<byte[]> {
@Override
public byte[] readFrom(ByteBuf input) {
byte[] array = new byte[input.readableBytes()];
input.readBytes(array);
return array;
}
@Override
public void writeTo(ByteBuf output, byte[] array) {
if (array == null) {
return;
}
output.writeBytes(array);
}
}
protected static class CharArray extends BaseStructure<char[]> {
@Override
public char[] readFrom(ByteBuf input) {
int total = input.readableBytes() >> 1;
char[] array = new char[total];
for (int i = 0; i < total; i++) {
array[i] = input.readChar();
}
return array;
}
@Override
public void writeTo(ByteBuf output, char[] array) {
if (array == null) {
return;
}
for (int i = 0; i < array.length; i++) {
output.writeChar(array[i]);
}
}
}
protected static class ShortArray extends BaseStructure<short[]> {
@Override
public short[] readFrom(ByteBuf input) {
int total = input.readableBytes() >> 1;
short[] array = new short[total];
for (int i = 0; i < total; i++) {
array[i] = input.readShort();
}
return array;
}
@Override
public void writeTo(ByteBuf output, short[] array) {
if (array == null) {
return;
}
for (int i = 0; i < array.length; i++) {
output.writeShort(array[i]);
}
}
}
protected static class IntArray extends BaseStructure<int[]> {
@Override
public int[] readFrom(ByteBuf input) {
int total = input.readableBytes() >> 2;
int[] array = new int[total];
for (int i = 0; i < total; i++) {
array[i] = input.readInt();
}
return array;
}
@Override
public void writeTo(ByteBuf output, int[] array) {
if (array == null) {
return;
}
for (int i = 0; i < array.length; i++) {
output.writeInt(array[i]);
}
}
}
protected static class LongArray extends BaseStructure<long[]> {
@Override
public long[] readFrom(ByteBuf input) {
int total = input.readableBytes() >> 3;
long[] array = new long[total];
for (int i = 0; i < total; i++) {
array[i] = input.readLong();
}
return array;
}
@Override
public void writeTo(ByteBuf output, long[] array) {
if (array == null) {
return;
}
for (int i = 0; i < array.length; i++) {
output.writeLong(array[i]);
}
}
}
protected static class FloatArray extends BaseStructure<float[]> {
@Override
public float[] readFrom(ByteBuf input) {
int total = input.readableBytes() >> 2;
float[] array = new float[total];
for (int i = 0; i < total; i++) {
array[i] = input.readFloat();
}
return array;
}
@Override
public void writeTo(ByteBuf output, float[] array) {
if (array == null) {
return;
}
for (int i = 0; i < array.length; i++) {
output.writeFloat(array[i]);
}
}
}
protected static class DoubleArray extends BaseStructure<double[]> {
@Override
public double[] readFrom(ByteBuf input) {
int total = input.readableBytes() >> 3;
double[] array = new double[total];
for (int i = 0; i < total; i++) {
array[i] = input.readDouble();
}
return array;
}
@Override
public void writeTo(ByteBuf output, double[] array) {
if (array == null) {
return;
}
for (int i = 0; i < array.length; i++) {
output.writeDouble(array[i]);
}
}
}
}

View File

@ -0,0 +1,39 @@
package com.fastbee.protocol.base.model;
import com.fastbee.protocol.base.struc.BaseStructure;
import io.netty.buffer.ByteBuf;
import java.nio.ByteBuffer;
/**
* @author gsb
* @date 2022/11/9 17:37
*/
public class BufferModel {
public static class ByteBufSchema extends BaseStructure<ByteBuf> {
@Override
public ByteBuf readFrom(ByteBuf input) {
return input.readSlice(input.readableBytes());
}
@Override
public void writeTo(ByteBuf output, ByteBuf value) {
output.writeBytes(value);
}
}
public static class ByteBufferSchema extends BaseStructure<ByteBuffer> {
@Override
public ByteBuffer readFrom(ByteBuf input) {
ByteBuffer message = input.nioBuffer();
input.skipBytes(input.readableBytes());
return message;
}
@Override
public void writeTo(ByteBuf output, ByteBuffer value) {
output.writeBytes(value);
}
}
}

View File

@ -0,0 +1,84 @@
package com.fastbee.protocol.base.model;
import com.fastbee.protocol.base.struc.BaseStructure;
import com.fastbee.protocol.util.DateTool;
import io.netty.buffer.ByteBuf;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
/**
* @author gsb
* @date 2022/11/9 17:35
*/
public class DateTimeModel {
public static final WModel<LocalTime> BYTE_TIME = new Time(DateTool.BYTE);
public static final WModel<LocalDate> BYTE_DATE = new Date(DateTool.BYTE);
public static final WModel<LocalDateTime> BYTE_DATETIME = new DateTime(DateTool.BYTE);
public static final WModel<LocalTime> BCD_TIME = new Time(DateTool.BCD);
public static final WModel<LocalDate> BCD_DATE = new Date(DateTool.BCD);
public static final WModel<LocalDateTime> BCD_DATETIME = new DateTime(DateTool.BCD);
protected static class DateTime extends BaseStructure<LocalDateTime> {
protected final DateTool tool;
protected DateTime(DateTool tool) {
this.tool = tool;
}
@Override
public LocalDateTime readFrom(ByteBuf input) {
byte[] bytes = new byte[6];
input.readBytes(bytes);
return tool.toDateTime(bytes);
}
@Override
public void writeTo(ByteBuf output, LocalDateTime value) {
output.writeBytes(tool.from(value));
}
}
protected static class Date extends BaseStructure<LocalDate> {
protected final DateTool tool;
protected Date(DateTool tool) {
this.tool = tool;
}
@Override
public LocalDate readFrom(ByteBuf input) {
byte[] bytes = new byte[3];
input.readBytes(bytes);
return tool.toDate(bytes);
}
@Override
public void writeTo(ByteBuf output, LocalDate value) {
output.writeBytes(tool.from(value));
}
}
protected static class Time extends BaseStructure<LocalTime> {
protected final DateTool tool;
protected Time(DateTool tool) {
this.tool = tool;
}
@Override
public LocalTime readFrom(ByteBuf input) {
byte[] bytes = new byte[3];
input.readBytes(bytes);
return tool.toTime(bytes);
}
@Override
public void writeTo(ByteBuf output, LocalTime value) {
output.writeBytes(tool.from(value));
}
}
}

View File

@ -0,0 +1,91 @@
package com.fastbee.protocol.base.model;
import com.fastbee.protocol.PrepareLoadStore;
import com.fastbee.protocol.base.struc.BaseStructure;
import com.fastbee.protocol.util.IntTool;
import com.fastbee.protocol.util.KeyValuePair;
import io.netty.buffer.ByteBuf;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
/**
* @author bill
*/
@Slf4j
public abstract class MapModel<K,V> extends BaseStructure<Map.Entry<K, V>> {
public final WModel<K> kwModel;
public final int lengthUnit;
public final IntTool intTool;
public final Map<K, WModel> valueSchema;
public MapModel(WModel<K> keySchema, int lengthUnit) {
this.kwModel = keySchema;
this.lengthUnit = lengthUnit;
this.intTool = IntTool.getInstance(lengthUnit);
PrepareLoadStore<K> loadStrategy = new PrepareLoadStore<>();
addSchemas(loadStrategy);
this.valueSchema = loadStrategy.build();
}
protected abstract void addSchemas(PrepareLoadStore<K> schemaRegistry);
@Override
public KeyValuePair<K, V> readFrom(ByteBuf in) {
K key = kwModel.readFrom(in);
KeyValuePair<K, V> result = new KeyValuePair<>(key);
int length = intTool.read(in);
if (length > 0) {
int writerIndex = in.writerIndex();
in.writerIndex(in.readerIndex() + length);
WModel<V> model = valueSchema.get(key);
if (model != null) {
V value = model.readFrom(in, length);
result.setValue(value);
} else {
byte[] bytes = new byte[length];
in.readBytes(bytes);
result.setValue((V) bytes);
}
in.writerIndex(writerIndex);
} else if (length < 0) {
WModel<V> model = valueSchema.get(key);
if (model != null) {
V value = model.readFrom(in);
result.setValue(value);
} else {
byte[] bytes = new byte[in.readableBytes()];
in.readBytes(bytes);
result.setValue((V) bytes);
}
}
return result;
}
@Override
public void writeTo(ByteBuf out, Map.Entry<K, V> entry) {
if (entry == null)
return;
K key = entry.getKey();
kwModel.writeTo(out, key);
WModel model = valueSchema.get(key);
if (model != null) {
int begin = out.writerIndex();
intTool.write(out, 0);
Object value = entry.getValue();
if (value != null) {
model.writeTo(out, value);
int length = out.writerIndex() - begin - lengthUnit;
intTool.set(out, begin, length);
}
} else {
log.warn("未注册的信息:ID[{}], Value[{}]", key, entry.getValue());
}
}
}

View File

@ -0,0 +1,218 @@
package com.fastbee.protocol.base.model;
import com.google.protobuf.MapField;
import com.fastbee.protocol.base.annotation.Column;
import com.fastbee.protocol.base.struc.*;
import com.fastbee.protocol.util.DateTool;
import io.netty.buffer.ByteBuf;
import java.nio.ByteBuffer;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.Temporal;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* 消息编码类注册
*
* @author gsb
* @date 2022/11/9 16:55
*/
public class ModelRegistry {
private static final Map<String, Function<DateTool, BaseStructure>> TIME_MODEL = new HashMap<>(6);
private static final Map<String, Supplier<BaseStructure>> NO_ARGS = new HashMap<>(128);
private static final Map<String, Integer> NUMBER = new HashMap<>(12);
static {
NUMBER.put(boolean.class.getName(), 1);
NUMBER.put(char.class.getName(), 2);
NUMBER.put(byte.class.getName(), 1);
NUMBER.put(short.class.getName(), 2);
NUMBER.put(int.class.getName(), 4);
NUMBER.put(long.class.getName(), 8);
NUMBER.put(float.class.getName(), 4);
NUMBER.put(double.class.getName(), 8);
NUMBER.put(Boolean.class.getName(), 1);
NUMBER.put(Character.class.getName(), 2);
NUMBER.put(Byte.class.getName(), 1);
NUMBER.put(Short.class.getName(), 2);
NUMBER.put(Integer.class.getName(), 4);
NUMBER.put(Long.class.getName(), 8);
NUMBER.put(Float.class.getName(), 4);
NUMBER.put(Double.class.getName(), 8);
register(short.class, NumberPModel.WORD2ShortLE::new, 2, "LE");
register(int.class, NumberPModel.WORD2IntLE::new, 2, "LE");
register(int.class, NumberPModel.DWORD2IntLE::new, 4, "LE");
register(long.class, NumberPModel.DWORD2LongLE::new, 4, "LE");
register(long.class, NumberPModel.QWORD2LongLE::new, 8, "LE");
register(short.class, NumberPModel.WORD2ShortLE::new, "LE");
register(int.class, NumberPModel.DWORD2IntLE::new, "LE");
register(long.class, NumberPModel.QWORD2LongLE::new, "LE");
register(float.class, NumberPModel.DWORD2FloatLE::new, "LE");
register(double.class, NumberPModel.QWORD2DoubleLE::new, "LE");
register(byte.class, NumberPModel.BYTE2Byte::new, 1);
register(short.class, NumberPModel.BYTE2Short::new, 1);
register(int.class, NumberPModel.BYTE2Int::new, 1);
register(short.class, NumberPModel.WORD2Short::new, 2);
register(int.class, NumberPModel.WORD2Int::new, 2);
register(int.class, NumberPModel.DWORD2Int::new, 4);
register(long.class, NumberPModel.DWORD2Long::new, 4);
register(long.class, NumberPModel.QWORD2Long::new, 8);
register(boolean.class, NumberPModel.BOOL::new);
register(char.class, NumberPModel.CHAR::new);
register(byte.class, NumberPModel.BYTE2Byte::new);
register(short.class, NumberPModel.WORD2Short::new);
register(int.class, NumberPModel.DWORD2Int::new);
register(long.class, NumberPModel.QWORD2Long::new);
register(float.class, NumberPModel.DWORD2Float::new);
register(double.class, NumberPModel.QWORD2Double::new);
register(Short.class, NumberModel.WORD2ShortLE::new, 2, "LE");
register(Integer.class, NumberModel.WORD2IntLE::new, 2, "LE");
register(Integer.class, NumberModel.DWORD2IntLE::new, 4, "LE");
register(Long.class, NumberModel.DWORD2LongLE::new, 4, "LE");
register(Long.class, NumberModel.QWORD2LongLE::new, 8, "LE");
register(Short.class, NumberModel.WORD2ShortLE::new, "LE");
register(Integer.class, NumberModel.DWORD2IntLE::new, "LE");
register(Long.class, NumberModel.QWORD2LongLE::new, "LE");
register(Float.class, NumberModel.DWORD2FloatLE::new, "LE");
register(Double.class, NumberModel.QWORD2DoubleLE::new, "LE");
register(Byte.class, NumberModel.BYTE2Byte::new, 1);
register(Short.class, NumberModel.BYTE2Short::new, 1);
register(Integer.class, NumberModel.BYTE2Int::new, 1);
register(Short.class, NumberModel.WORD2Short::new, 2);
register(Integer.class, NumberModel.WORD2Int::new, 2);
register(Integer.class, NumberModel.DWORD2Int::new, 4);
register(Long.class, NumberModel.DWORD2Long::new, 4);
register(Long.class, NumberModel.QWORD2Long::new, 8);
register(Boolean.class, NumberModel.BOOL::new);
register(Character.class, /**/NumberModel.CHAR::new);
register(Byte.class, NumberModel.BYTE2Byte::new);
register(Short.class, NumberModel.WORD2Short::new);
register(Integer.class, NumberModel.DWORD2Int::new);
register(Long.class, NumberModel.QWORD2Long::new);
register(Float.class, NumberModel.DWORD2Float::new);
register(Double.class, NumberModel.QWORD2Double::new);
register(byte[].class, ArrayModel.ByteArray::new);
register(char[].class, ArrayModel.CharArray::new);
register(short[].class, ArrayModel.ShortArray::new);
register(int[].class, ArrayModel.IntArray::new);
register(long[].class, ArrayModel.LongArray::new);
register(float[].class, ArrayModel.FloatArray::new);
register(double[].class, ArrayModel.DoubleArray::new);
register(ByteBuffer.class, BufferModel.ByteBufferSchema::new);
register(ByteBuf.class, BufferModel.ByteBufSchema::new);
TIME_MODEL.put(LocalTime.class.getName(), DateTimeModel.Time::new);
TIME_MODEL.put(LocalDate.class.getName(), DateTimeModel.Date::new);
TIME_MODEL.put(LocalDateTime.class.getName(), DateTimeModel.DateTime::new);
}
public static void register(Class typeClass, Supplier<BaseStructure> supplier, int length, String charset) {
NO_ARGS.put(typeClass.getName() + "/" + length + "/" + charset, supplier);
}
public static void register(Class typeClass, Supplier<BaseStructure> supplier, int length) {
NO_ARGS.put(typeClass.getName() + "/" + length, supplier);
}
public static void register(Class typeClass, Supplier<BaseStructure> supplier, String charset) {
NO_ARGS.put(typeClass.getName() + "/" + charset, supplier);
}
public static void register(Class typeClass, Supplier model) {
NO_ARGS.put(typeClass.getName(), model);
}
public static WModel getCustom(Class<? extends WModel> clazz) {
try {
return clazz.getDeclaredConstructor((Class[]) null).newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static BaseStructure get(Column column, java.lang.reflect.Field f) {
Class typeClass = f.getType();
String name = typeClass.getName();
String charset = column.charset().toUpperCase();
int length = column.length();
if (NUMBER.containsKey(name)) {
if (length > 0)
name += "/" + length;
if (charset.equals("LE"))
name += "/LE";
return NO_ARGS.get(name).get();
}
if (String.class.isAssignableFrom(typeClass)) {
return StringModel.getInstance(charset, length, column.lengthUnit());
}
if (Temporal.class.isAssignableFrom(typeClass)) {
return TIME_MODEL.get(name).apply(charset.equals("BCD") ? DateTool.BCD : DateTool.BYTE);
}
if (WModel.class != column.converter()) {
return get(column, f, getCustom(column.converter()));
}
Supplier<BaseStructure> supplier = NO_ARGS.get(name);
if (supplier != null)
return get(column, f, supplier.get());
return null;
}
public static BaseStructure get(Column column, java.lang.reflect.Field f, WModel model) {
Class typeClass = f.getType();
if (column.totalUnit() > 0) {
if (Collection.class.isAssignableFrom(typeClass)) {
return new TotalCollectionStructure(model, column.totalUnit());
}
if (Map.class.isAssignableFrom(typeClass)) {
return new TotalMapStructure((MapModel) model, column.totalUnit(), typeClass);
}
if (typeClass.isArray()) {
typeClass = typeClass.getComponentType();
if (typeClass.isPrimitive())
return new TotalArrayPrimitiveStructure(model, column.totalUnit(), typeClass);
return new TotalArrayObjectStructure(model, column.totalUnit(), typeClass);
}
}
if (column.lengthUnit() > 0) {
if (Collection.class.isAssignableFrom(typeClass))
return new LengthUnitCollectionStructure(model, column.lengthUnit());
return new LengthStructure(model, column.lengthUnit());
}
if (column.length() > 0) {
return new LengthStructure(model, column.length());
}
if (Collection.class.isAssignableFrom(typeClass)) {
return new CollectionStructure(model);
} else if (Map.class.isAssignableFrom(typeClass)) {
return new MapStructure((MapModel) model, typeClass);
}
return (BaseStructure) model;
}
public static int getLength(Class typeClass) {
Integer len = NUMBER.get(typeClass.getName());
if (len == null)
return -1;
return len;
}
}

View File

@ -0,0 +1,367 @@
package com.fastbee.protocol.base.model;
import com.fastbee.protocol.base.struc.BaseStructure;
import io.netty.buffer.ByteBuf;
/**
* @author gsb
* @date 2022/11/9 16:43
*/
public class NumberModel {
public static final WModel<Boolean> BOOL = new BOOL();
public static final WModel<Character> CHAR = new CHAR();
public static final WModel<Byte> BYTE_BYTE = new BYTE2Byte();
public static final WModel<Short> BYTE_SHORT = new BYTE2Short();
public static final WModel<Integer> BYTE_INT = new BYTE2Int();
public static final WModel<Short> WORD_SHORT = new WORD2Short();
public static final WModel<Integer> WORD_INT = new WORD2Int();
public static final WModel<Integer> DWORD_INT = new DWORD2Int();
public static final WModel<Long> DWORD_LONG = new DWORD2Long();
public static final WModel<Float> DWORD_FLOAT = new DWORD2Float();
public static final WModel<Long> QWORD_LONG = new QWORD2Long();
public static final WModel<Double> QWORD_DOUBLE = new QWORD2Double();
public static final WModel<Short> WORD_SHORT_LE = new WORD2ShortLE();
public static final WModel<Integer> WORD_INT_LE = new WORD2IntLE();
public static final WModel<Integer> DWORD_INT_LE = new DWORD2IntLE();
public static final WModel<Long> DWORD_LONG_LE = new DWORD2LongLE();
public static final WModel<Float> DWORD_FLOAT_LE = new DWORD2FloatLE();
public static final WModel<Long> QWORD_LONG_LE = new QWORD2LongLE();
public static final WModel<Double> QWORD_DOUBLE_LE = new QWORD2DoubleLE();
protected static class BOOL extends BaseStructure<Boolean> {
@Override
public Boolean readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readBoolean();
}
@Override
public void writeTo(ByteBuf output, Boolean value) {
if (value != null) {
output.writeBoolean(value);
}
}
}
protected static class CHAR extends BaseStructure<Character> {
@Override
public Character readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readChar();
}
@Override
public void writeTo(ByteBuf output, Character value) {
if (value != null) {
output.writeChar(value);
}
}
}
protected static class BYTE2Byte extends BaseStructure<Byte> {
@Override
public Byte readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readByte();
}
@Override
public void writeTo(ByteBuf output, Byte value) {
if (value != null) {
output.writeByte(value);
}
}
}
protected static class BYTE2Short extends BaseStructure<Short> {
@Override
public Short readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readUnsignedByte();
}
@Override
public void writeTo(ByteBuf output, Short value) {
if (value != null) {
output.writeByte(value);
}
}
}
protected static class BYTE2Int extends BaseStructure<Integer> {
@Override
public Integer readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return (int) input.readUnsignedByte();
}
@Override
public void writeTo(ByteBuf output, Integer value) {
if (value != null) {
output.writeByte(value);
}
}
}
protected static class WORD2Short extends BaseStructure<Short> {
@Override
public Short readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readShort();
}
@Override
public void writeTo(ByteBuf output, Short value) {
if (value != null) {
output.writeShort(value);
}
}
}
protected static class WORD2Int extends BaseStructure<Integer> {
@Override
public void readAndSet(ByteBuf input, Object obj) throws Exception {
super.readAndSet(input, obj);
}
@Override
public void getAndWrite(ByteBuf output, Object obj) throws Exception {
super.getAndWrite(output, obj);
}
@Override
public Integer readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readUnsignedShort();
}
@Override
public void writeTo(ByteBuf output, Integer value) {
if (value != null) {
output.writeShort(value);
}
}
}
protected static class DWORD2Int extends BaseStructure<Integer> {
@Override
public Integer readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readInt();
}
@Override
public void writeTo(ByteBuf output, Integer value) {
if (value != null) {
output.writeInt(value);
}
}
}
protected static class DWORD2Long extends BaseStructure<Long> {
@Override
public Long readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readUnsignedInt();
}
@Override
public void writeTo(ByteBuf output, Long value) {
if (value != null) {
output.writeInt(value.intValue());
}
}
}
protected static class DWORD2Float extends BaseStructure<Float> {
@Override
public Float readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readFloat();
}
@Override
public void writeTo(ByteBuf output, Float value) {
if (value != null) {
output.writeFloat(value);
}
}
}
protected static class QWORD2Long extends BaseStructure<Long> {
@Override
public Long readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readLong();
}
@Override
public void writeTo(ByteBuf output, Long value) {
if (value != null) {
output.writeLong(value);
}
}
}
protected static class QWORD2Double extends BaseStructure<Double> {
@Override
public Double readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readDouble();
}
@Override
public void writeTo(ByteBuf output, Double value) {
if (value != null) {
output.writeDouble(value);
}
}
}
protected static class WORD2ShortLE extends BaseStructure<Short> {
@Override
public Short readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readShortLE();
}
@Override
public void writeTo(ByteBuf output, Short value) {
if (value != null) {
output.writeShortLE(value);
}
}
}
protected static class WORD2IntLE extends BaseStructure<Integer> {
@Override
public Integer readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readUnsignedShortLE();
}
@Override
public void writeTo(ByteBuf output, Integer value) {
if (value != null) {
output.writeShortLE(value);
}
}
}
protected static class DWORD2IntLE extends BaseStructure<Integer> {
@Override
public Integer readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readIntLE();
}
@Override
public void writeTo(ByteBuf output, Integer value) {
if (value != null) {
output.writeIntLE(value);
}
}
}
protected static class DWORD2LongLE extends BaseStructure<Long> {
@Override
public Long readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readUnsignedIntLE();
}
@Override
public void writeTo(ByteBuf output, Long value) {
if (value != null) {
output.writeIntLE(value.intValue());
}
}
}
protected static class DWORD2FloatLE extends BaseStructure<Float> {
@Override
public Float readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readFloatLE();
}
@Override
public void writeTo(ByteBuf output, Float value) {
if (value != null) {
output.writeFloatLE(value);
}
}
}
protected static class QWORD2LongLE extends BaseStructure<Long> {
@Override
public Long readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readLongLE();
}
@Override
public void writeTo(ByteBuf output, Long value) {
if (value != null) {
output.writeLongLE(value);
}
}
}
protected static class QWORD2DoubleLE extends BaseStructure<Double> {
@Override
public Double readFrom(ByteBuf input) {
if (!input.isReadable()) {
return null;
}
return input.readDoubleLE();
}
@Override
public void writeTo(ByteBuf output, Double value) {
if (value != null) {
output.writeDoubleLE(value);
}
}
}
}

View File

@ -0,0 +1,454 @@
package com.fastbee.protocol.base.model;
import com.fastbee.protocol.base.struc.BaseStructure;
import io.netty.buffer.ByteBuf;
/**
* @author gsb
* @date 2022/11/9 16:56
*/
public class NumberPModel {
public static final WModel<Boolean> BOOL = new BOOL();
public static final WModel<Character> CHAR = new CHAR();
public static final WModel<Byte> BYTE_BYTE = new BYTE2Byte();
public static final WModel<Short> BYTE_SHORT = new BYTE2Short();
public static final WModel<Integer> BYTE_INT = new BYTE2Int();
public static final WModel<Short> WORD_SHORT = new WORD2Short();
public static final WModel<Integer> WORD_INT = new WORD2Int();
public static final WModel<Integer> DWORD_INT = new DWORD2Int();
public static final WModel<Long> DWORD_LONG = new DWORD2Long();
public static final WModel<Float> DWORD_FLOAT = new DWORD2Float();
public static final WModel<Long> QWORD_LONG = new QWORD2Long();
public static final WModel<Double> QWORD_DOUBLE = new QWORD2Double();
public static final WModel<Short> WORD_SHORT_LE = new WORD2ShortLE();
public static final WModel<Integer> WORD_INT_LE = new WORD2IntLE();
public static final WModel<Integer> DWORD_INT_LE = new DWORD2IntLE();
public static final WModel<Long> DWORD_LONG_LE = new DWORD2LongLE();
public static final WModel<Float> DWORD_FLOAT_LE = new DWORD2FloatLE();
public static final WModel<Long> QWORD_LONG_LE = new QWORD2LongLE();
public static final WModel<Double> QWORD_DOUBLE_LE = new QWORD2DoubleLE();
protected static class BOOL extends BaseStructure<Boolean> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setBoolean(obj, in.readBoolean());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeBoolean(field.getBoolean(obj));
}
@Override
public Boolean readFrom(ByteBuf in) {
return in.readBoolean();
}
@Override
public void writeTo(ByteBuf out, Boolean value) {
out.writeBoolean(value);
}
}
protected static class CHAR extends BaseStructure<Character> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setChar(obj, in.readChar());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeChar(field.getChar(obj));
}
@Override
public Character readFrom(ByteBuf in) {
return in.readChar();
}
@Override
public void writeTo(ByteBuf out, Character value) {
out.writeChar(value);
}
}
protected static class BYTE2Byte extends BaseStructure<Byte> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setByte(obj, in.readByte());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeByte(field.getByte(obj));
}
@Override
public Byte readFrom(ByteBuf in) {
return in.readByte();
}
@Override
public void writeTo(ByteBuf out, Byte value) {
out.writeByte(value);
}
}
protected static class BYTE2Short extends BaseStructure<Short> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setShort(obj, in.readUnsignedByte());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeByte(field.getShort(obj));
}
@Override
public Short readFrom(ByteBuf in) {
return in.readUnsignedByte();
}
@Override
public void writeTo(ByteBuf out, Short value) {
out.writeByte(value);
}
}
protected static class BYTE2Int extends BaseStructure<Integer> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setInt(obj, in.readUnsignedByte());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeByte(field.getInt(obj));
}
@Override
public Integer readFrom(ByteBuf in) {
return (int) in.readUnsignedByte();
}
@Override
public void writeTo(ByteBuf out, Integer value) {
out.writeByte(value);
}
}
protected static class WORD2Short extends BaseStructure<Short> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setShort(obj, in.readShort());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeShort(field.getShort(obj));
}
@Override
public Short readFrom(ByteBuf in) {
return in.readShort();
}
@Override
public void writeTo(ByteBuf out, Short value) {
out.writeShort(value);
}
}
protected static class WORD2Int extends BaseStructure<Integer> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setInt(obj, in.readUnsignedShort());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeShort(field.getInt(obj));
}
@Override
public Integer readFrom(ByteBuf in) {
return in.readUnsignedShort();
}
@Override
public void writeTo(ByteBuf out, Integer value) {
out.writeShort(value);
}
}
protected static class DWORD2Int extends BaseStructure<Integer> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setInt(obj, in.readInt());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeInt(field.getInt(obj));
}
@Override
public Integer readFrom(ByteBuf in) {
return in.readInt();
}
@Override
public void writeTo(ByteBuf out, Integer value) {
out.writeInt(value);
}
}
protected static class DWORD2Long extends BaseStructure<Long> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setLong(obj, in.readUnsignedInt());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeInt((int) field.getLong(obj));
}
@Override
public Long readFrom(ByteBuf in) {
return in.readUnsignedInt();
}
@Override
public void writeTo(ByteBuf out, Long value) {
out.writeInt(value.intValue());
}
}
protected static class DWORD2Float extends BaseStructure<Float> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setFloat(obj, in.readFloat());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeFloat(field.getFloat(obj));
}
@Override
public Float readFrom(ByteBuf in) {
return in.readFloat();
}
@Override
public void writeTo(ByteBuf out, Float value) {
out.writeFloat(value);
}
}
protected static class QWORD2Long extends BaseStructure<Long> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setLong(obj, in.readLong());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeLong(field.getLong(obj));
}
@Override
public Long readFrom(ByteBuf in) {
return in.readLong();
}
@Override
public void writeTo(ByteBuf out, Long value) {
out.writeLong(value);
}
}
protected static class QWORD2Double extends BaseStructure<Double> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setDouble(obj, in.readDouble());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeDouble(field.getDouble(obj));
}
@Override
public Double readFrom(ByteBuf in) {
return in.readDouble();
}
@Override
public void writeTo(ByteBuf out, Double value) {
out.writeDouble(value);
}
}
protected static class WORD2ShortLE extends BaseStructure<Short> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setShort(obj, in.readShortLE());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeShortLE(field.getShort(obj));
}
@Override
public Short readFrom(ByteBuf in) {
return in.readShortLE();
}
@Override
public void writeTo(ByteBuf out, Short value) {
out.writeShortLE(value);
}
}
protected static class WORD2IntLE extends BaseStructure<Integer> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setInt(obj, in.readUnsignedShortLE());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeShortLE(field.getInt(obj));
}
@Override
public Integer readFrom(ByteBuf in) {
return in.readUnsignedShortLE();
}
@Override
public void writeTo(ByteBuf out, Integer value) {
out.writeShortLE(value);
}
}
protected static class DWORD2IntLE extends BaseStructure<Integer> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setInt(obj, in.readIntLE());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeIntLE(field.getInt(obj));
}
@Override
public Integer readFrom(ByteBuf in) {
return in.readIntLE();
}
@Override
public void writeTo(ByteBuf out, Integer value) {
out.writeIntLE(value);
}
}
protected static class DWORD2LongLE extends BaseStructure<Long> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setLong(obj, in.readUnsignedIntLE());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeIntLE((int) field.getLong(obj));
}
@Override
public Long readFrom(ByteBuf in) {
return in.readUnsignedIntLE();
}
@Override
public void writeTo(ByteBuf out, Long value) {
out.writeIntLE(value.intValue());
}
}
protected static class DWORD2FloatLE extends BaseStructure<Float> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setFloat(obj, in.readFloatLE());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeFloatLE(field.getFloat(obj));
}
@Override
public Float readFrom(ByteBuf in) {
return in.readFloatLE();
}
@Override
public void writeTo(ByteBuf out, Float value) {
out.writeFloatLE(value);
}
}
protected static class QWORD2LongLE extends BaseStructure<Long> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setLong(obj, in.readLongLE());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeLongLE(field.getLong(obj));
}
@Override
public Long readFrom(ByteBuf in) {
return in.readLongLE();
}
@Override
public void writeTo(ByteBuf out, Long value) {
out.writeLongLE(value);
}
}
protected static class QWORD2DoubleLE extends BaseStructure<Double> {
@Override
public void readAndSet(ByteBuf in, Object obj) throws Exception {
field.setDouble(obj, in.readDoubleLE());
}
@Override
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
out.writeDoubleLE(field.getDouble(obj));
}
@Override
public Double readFrom(ByteBuf in) {
return in.readDoubleLE();
}
@Override
public void writeTo(ByteBuf out, Double value) {
out.writeDoubleLE(value);
}
}
}

View File

@ -0,0 +1,170 @@
package com.fastbee.protocol.base.model;
import com.fastbee.protocol.base.struc.BaseStructure;
import com.fastbee.protocol.base.struc.LengthStructure;
import com.fastbee.protocol.util.CharsBuilder;
import io.netty.buffer.ByteBuf;
import io.netty.util.internal.StringUtil;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* @author gsb
* @date 2022/11/9 17:39
*/
public class StringModel {
public static final WModel<String> HEX = new HEX(-1);
public static final WModel<String> BCD = new BCD(-1);
public static final WModel<String> GBK = new STR(Charset.forName("GBK"), -1);
public static final WModel<String> UTF8 = new STR(StandardCharsets.UTF_8, -1);
public static final WModel<String> ASCII = new STR(StandardCharsets.US_ASCII, -1);
public static BaseStructure<String> getInstance(String charset, int length, int lengthUnit) {
final String cs = charset.toUpperCase();
BaseStructure<String> model;
if ("BCD".equals(cs)) {
model = new BCD(length);
} else if ("HEX".equals(cs)) {
model = new HEX(length);
} else {
model = new STR(Charset.forName(charset), length);
}
if (lengthUnit > 0) {
model = new LengthStructure<>(model, lengthUnit);
}
return model;
}
public static class STR extends BaseStructure<String> {
private static final ByteBuffer EMPTY = ByteBuffer.allocate(0);
private final Charset charset;
private final int length;
private final boolean fixed;
private STR(Charset charset, int length) {
this.charset = charset;
this.length = length;
this.fixed = length > -1;
}
@Override
public String readFrom(ByteBuf input) {
int len = input.readableBytes();
if (fixed && len > length)
len = length;
byte[] bytes = new byte[len];
input.readBytes(bytes);
int st = 0;
while ((st < len) && (bytes[st] == 0)) {
st++;
}
while ((st < len) && (bytes[len - 1] == 0)) {
len--;
}
return new String(bytes, st, len - st, charset);
}
@Override
public void writeTo(ByteBuf output, String value) {
if (fixed) {
ByteBuffer buffer;
if (value == null) {
buffer = EMPTY;
} else {
buffer = charset.encode(value);
}
int srcPos = length - buffer.limit();
if (srcPos > 0) {
output.writeBytes(buffer);
output.writeBytes(new byte[srcPos]);
} else if (srcPos < 0) {
buffer.position(-srcPos);
output.writeBytes(buffer);
} else {
output.writeBytes(buffer);
}
} else {
if (value != null) {
output.writeBytes(charset.encode(value));
}
}
}
}
public static class HEX extends BaseStructure<String> {
protected final int length;
protected final int charSize;
protected final boolean fixed;
public HEX(int length) {
this.length = length;
this.charSize = length << 1;
this.fixed = length > -1;
}
@Override
public String readFrom(ByteBuf input) {
return readCharsBuilder(input).toString();
}
protected CharsBuilder readCharsBuilder(ByteBuf input) {
int len = fixed ? length : input.readableBytes();
byte[] bytes = new byte[len];
input.readBytes(bytes);
CharsBuilder cb = new CharsBuilder(charSize);
StringUtil.toHexStringPadded(cb, bytes);
return cb;
}
@Override
public void writeTo(ByteBuf output, String value) {
if (value == null) {
if (fixed) {
output.writeBytes(new byte[length]);
}
return;
}
int charSize = this.charSize;
int strLength = value.length();
if (!fixed) {
charSize = strLength + (strLength & 1);
}
char[] chars = new char[charSize];
int i = charSize - strLength;
if (i >= 0) {
value.getChars(0, charSize - i, chars, i);
while (i > 0) {
chars[--i] = '0';
}
} else {
value.getChars(-i, charSize - i, chars, 0);
}
byte[] src = StringUtil.decodeHexDump(new CharsBuilder(chars));
output.writeBytes(src);
}
}
public static class BCD extends HEX {
public BCD(int length) {
super(length);
}
@Override
public String readFrom(ByteBuf input) {
return readCharsBuilder(input).leftStrip('0');
}
}
}

View File

@ -0,0 +1,74 @@
package com.fastbee.protocol.base.model;
import com.fastbee.protocol.util.ExplainUtils;
import io.netty.buffer.ByteBuf;
/**
* 消息结构
*
* @author gsb
* @date 2022/11/9 11:55
*/
public interface WModel<T> {
/**
* 读缓存
*/
T readFrom(ByteBuf in);
void writeTo(ByteBuf out, T value);
default T readFrom(ByteBuf in, int length) {
/*输入的报文长度*/
int readLength = in.readerIndex() + length;
/*读索引位*/
int writerIndex = in.writerIndex();
in.writerIndex(readLength);
T value = readFrom(in);
in.setIndex(readLength, writerIndex);
return value;
}
default void writeTo(ByteBuf out, int length, T value) {
int writeLength = out.writerIndex() + length;
writeTo(out, value);
out.writerIndex(writeLength);
}
default T readFrom(ByteBuf in, ExplainUtils explain) {
int start = in.readerIndex();
T value = readFrom(in);
explain.readField(start,desc(), value,in);
return value;
}
default void writeTo(ByteBuf out, T value, ExplainUtils explain) {
int begin = out.writerIndex();
writeTo(out, value);
explain.writeField(begin, desc(), value, out);
}
default T readFrom(ByteBuf in, int length, ExplainUtils explain) {
int readerLength = in.readerIndex() + length;
int writerIndex = in.writerIndex();
in.writerIndex(readerLength);
T value = readFrom(in, explain);
in.setIndex(readerLength, writerIndex);
return value;
}
default void writeTo(ByteBuf out, int length, T value, ExplainUtils explain) {
int writerLength = out.writerIndex() + length;
writeTo(out, value, explain);
out.writerIndex(writerLength);
}
/** 内存分配 */
default int length() {
return 32;
}
default String desc() {
return "";
}
}

View File

@ -0,0 +1,31 @@
package com.fastbee.protocol.base.protocol;
import com.fastbee.common.core.mq.DeviceReport;
import com.fastbee.common.core.mq.MQSendMessageBo;
import com.fastbee.common.core.mq.message.DeviceData;
import com.fastbee.common.core.mq.message.FunctionCallBackBo;
/**
* 基础协议
* @author gsb
* @date 2022/10/10 15:48
*/
public interface IProtocol {
DeviceReport decode(DeviceData data, String clientId);
FunctionCallBackBo encode(MQSendMessageBo message);
/**
* 默认方法,处理设备回复的报文编码
*/
public default byte[] encodeCallBack(Object message) {
return new byte[0];
}
public default byte[] encodeOTA(Object message) {
return new byte[0];
}
}

View File

@ -0,0 +1,102 @@
package com.fastbee.protocol.base.struc;
import com.fastbee.protocol.base.annotation.Column;
import com.fastbee.protocol.base.model.ModelRegistry;
import com.fastbee.protocol.base.model.WModel;
import com.fastbee.protocol.util.ExplainUtils;
import io.netty.buffer.ByteBuf;
import java.lang.reflect.Field;
/**
* 基础消息结构
*
* @author gsb
* @date 2022/11/9 16:45
*/
public abstract class BaseStructure<T> implements WModel<T>, Comparable<BaseStructure> {
protected Field field;
protected Column column;
protected int index;
protected int length;
protected String description;
public void readAndSet(ByteBuf in, Object obj) throws Exception {
T value = readFrom(in);
field.set(obj, value);
}
public void getAndWrite(ByteBuf out, Object obj) throws Exception {
T value = (T) field.get(obj);
writeTo(out, value);
}
public void readAndSet(ByteBuf in, Object obj, ExplainUtils explain) throws Exception {
T value = readFrom(in, explain);
field.set(obj, value);
}
public void getAndWrite(ByteBuf out, Object obj, ExplainUtils explain) throws Exception {
T value = (T) field.get(obj);
writeTo(out, value, explain);
}
public BaseStructure<T> init(Column column, Field field, int position) {
if (this.field == null && this.column == null) {
this.field = field;
this.column = column;
length = column.length() > 0 ? column.length() : ModelRegistry.getLength(field.getType());
length = length > 0 ? length : 16;
description = column.desc();
if (description.isEmpty()) {
description = field.getName();
}
index = column.index();
if (index == 0) {
index = position;
}
}
return this;
}
public String filedName(){
return field.getName();
}
public String description(){
return description;
}
@Override
public int compareTo(BaseStructure that) {
return Integer.compare(this.index, that.index);
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof BaseStructure)) {
return false;
}
BaseStructure that = (BaseStructure) other;
return field.equals(that.field);
}
@Override
public int hashCode() {
return field.hashCode();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder(12);
sb.append(description).append(' ').append(field);
return sb.toString();
}
}

View File

@ -0,0 +1,58 @@
package com.fastbee.protocol.base.struc;
import com.fastbee.protocol.base.model.WModel;
import com.fastbee.protocol.util.ExplainUtils;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import java.util.ArrayList;
import java.util.Collection;
/**
* 集合域,位于消息末尾
* @author bill
*/
@AllArgsConstructor
public class CollectionStructure<T> extends BaseStructure<Collection<T>> {
private final WModel<T> schema;
@Override
public Collection<T> readFrom(ByteBuf input) {
Collection list = new ArrayList<>();
while (input.isReadable()) {
T t = schema.readFrom(input);
list.add(t);
}
return list;
}
@Override
public void writeTo(ByteBuf output, Collection<T> list) {
if (list != null) {
for (T t : list) {
schema.writeTo(output, t);
}
}
}
@Override
public Collection<T> readFrom(ByteBuf input, ExplainUtils explain) {
Collection list = new ArrayList<>();
while (input.isReadable()) {
T t = schema.readFrom(input, explain);
list.add(t);
}
return list;
}
@Override
public void writeTo(ByteBuf output, Collection<T> list, ExplainUtils explain) {
if (list != null) {
for (T t : list) {
schema.writeTo(output, t, explain);
}
}
}
}

View File

@ -0,0 +1,43 @@
package com.fastbee.protocol.base.struc;
import com.fastbee.protocol.base.model.WModel;
import com.fastbee.protocol.util.ExplainUtils;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
/**
* 指定长度报文结构
* @author bill
*/
@AllArgsConstructor
public class LengthStructure<T> extends BaseStructure<T> {
private final WModel<T> schema;
private final int length;
@Override
public T readFrom(ByteBuf input) {
if (input.isReadable(length))
return schema.readFrom(input, length);
return null;
}
@Override
public void writeTo(ByteBuf output, T value) {
if (value != null)
schema.writeTo(output, length, value);
}
@Override
public T readFrom(ByteBuf input, ExplainUtils explain) {
if (input.isReadable(length))
return schema.readFrom(input, length, explain);
return null;
}
@Override
public void writeTo(ByteBuf output, T value, ExplainUtils explain) {
if (value != null)
schema.writeTo(output, length, value, explain);
}
}

View File

@ -0,0 +1,83 @@
package com.fastbee.protocol.base.struc;
import com.fastbee.protocol.base.model.WModel;
import com.fastbee.protocol.util.ExplainUtils;
import com.fastbee.protocol.util.IntTool;
import com.fastbee.protocol.util.Msg;
import io.netty.buffer.ByteBuf;
import java.util.ArrayList;
import java.util.Collection;
/**
* 每个元素长度单位的集合域,位于消息末尾
* @author bill
*/
public class LengthUnitCollectionStructure<T> extends BaseStructure<Collection<T>> {
private final WModel<T> model;
private final int lengthUnit;
private final IntTool intTool;
public LengthUnitCollectionStructure(WModel<T> model, int lengthUnit) {
this.model = model;
this.lengthUnit = lengthUnit;
this.intTool = IntTool.getInstance(lengthUnit);
}
@Override
public Collection<T> readFrom(ByteBuf input) {
Collection list = new ArrayList<>();
while (input.isReadable()) {
int length = intTool.read(input);
T t = model.readFrom(input, length);
list.add(t);
}
return list;
}
@Override
public void writeTo(ByteBuf output, Collection<T> list) {
if (list != null) {
for (T t : list) {
if (t != null) {
int begin = output.writerIndex();
intTool.write(output, 0);
model.writeTo(output, t);
int length = output.writerIndex() - begin - lengthUnit;
intTool.set(output, begin, length);
}
}
}
}
@Override
public Collection<T> readFrom(ByteBuf input, ExplainUtils explain) {
Collection list = new ArrayList<>();
while (input.isReadable()) {
int length = intTool.read(input);
explain.lengthField(input.readerIndex() - lengthUnit, description + "长度", length, lengthUnit);
T t = model.readFrom(input, length, explain);
list.add(t);
}
return list;
}
@Override
public void writeTo(ByteBuf output, Collection<T> list, ExplainUtils explain) {
if (list != null) {
for (T t : list) {
if (t != null) {
int begin = output.writerIndex();
Msg msg = explain.lengthField(begin, description + "长度", 0, lengthUnit);
intTool.write(output, 0);
model.writeTo(output, t, explain);
int length = output.writerIndex() - begin - lengthUnit;
intTool.set(output, begin, length);
msg.setLength(length, lengthUnit);
}
}
}
}
}

View File

@ -0,0 +1,64 @@
package com.fastbee.protocol.base.struc;
import com.fastbee.protocol.base.model.WModel;
import com.fastbee.protocol.util.ExplainUtils;
import com.fastbee.protocol.util.IntTool;
import com.fastbee.protocol.util.Msg;
import io.netty.buffer.ByteBuf;
/**
* 指定长度单位域
* @author bill
*/
public class LengthUnitStructure<T> extends BaseStructure<T> {
private final WModel<T> schema;
private final int lengthUnit;
private final IntTool intTool;
public LengthUnitStructure(WModel<T> model, int lengthUnit) {
this.schema = model;
this.lengthUnit = lengthUnit;
this.intTool = IntTool.getInstance(lengthUnit);
}
@Override
public T readFrom(ByteBuf in) {
int length = intTool.read(in);
return schema.readFrom(in, length);
}
@Override
public void writeTo(ByteBuf out, T value) {
int begin = out.writerIndex();
intTool.write(out, 0);
if (value != null) {
schema.writeTo(out, value);
int length = out.writerIndex() - begin - lengthUnit;
intTool.set(out, begin, length);
}
}
@Override
public T readFrom(ByteBuf in, ExplainUtils explain) {
int length = intTool.read(in);
explain.lengthField(in.readerIndex() - lengthUnit, description + "长度", length, lengthUnit);
T value = schema.readFrom(in, length, explain);
explain.setLastDesc(description);
return value;
}
@Override
public void writeTo(ByteBuf out, T value, ExplainUtils explain) {
int begin = out.writerIndex();
Msg msg = explain.lengthField(begin, description + "长度", 0, lengthUnit);
intTool.write(out, 0);
if (value != null) {
schema.writeTo(out, value, explain);
explain.setLastDesc(description);
int length = out.writerIndex() - begin - lengthUnit;
intTool.set(out, begin, length);
msg.setLength(length, lengthUnit);
}
}
}

View File

@ -0,0 +1,188 @@
package com.fastbee.protocol.base.struc;
import com.fastbee.protocol.base.model.MapModel;
import com.fastbee.protocol.base.model.WModel;
import com.fastbee.protocol.util.ExplainUtils;
import com.fastbee.protocol.util.IntTool;
import com.fastbee.protocol.util.Msg;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
/**
* map类型位于报文末尾
* @author bill
*/
@Slf4j
public class MapStructure<K,V> extends BaseStructure<Map<K,V>> {
private final WModel<K> kwModel;
private final Map<K, WModel<V>> valuesModel;
private final int lengthUnit;
private final IntTool valueIntTool;
private final boolean treeMap;
public MapStructure(MapModel mapModel, Class typeClass) {
this.kwModel = mapModel.kwModel;
this.valuesModel = mapModel.valueSchema;
this.lengthUnit = mapModel.lengthUnit;
this.valueIntTool = mapModel.intTool;
this.treeMap = !HashMap.class.isAssignableFrom(typeClass);
}
@Override
public Map<K, V> readFrom(ByteBuf in) {
if (!in.isReadable())
return null;
Map map;
if (treeMap) {
map = new TreeMap();
}
else{ map = new HashMap(8);}
K key = null;
int length = 0;
try {
do {
key = kwModel.readFrom(in);
length = valueIntTool.read(in);
if (length <= 0)
continue;
int writerIndex = in.writerIndex();
int readerIndex = in.readerIndex() + length;
if (writerIndex > readerIndex) {
in.writerIndex(readerIndex);
Object value = readValue(key, in);
map.put(key, value);
in.setIndex(readerIndex, writerIndex);
} else {
Object value = readValue(key, in);
map.put(key, value);
break;
}
} while (in.isReadable());
} catch (Exception e) {
log.warn("解析出错:ID[{}], LENGTH[{}], {}", key, length, e.getMessage());
}
return map;
}
public Object readValue(Object key, ByteBuf in) {
WModel model = valuesModel.get(key);
if (model != null) {
return model.readFrom(in);
}
byte[] bytes = new byte[in.readableBytes()];
in.readBytes(bytes);
return bytes;
}
@Override
public void writeTo(ByteBuf output, Map<K, V> map) {
if (map == null)
return;
for (Map.Entry<K, V> entry : map.entrySet()) {
K key = entry.getKey();
kwModel.writeTo(output, key);
V value = entry.getValue();
WModel<V> schema = valuesModel.get(key);
if (schema != null) {
int begin = output.writerIndex();
valueIntTool.write(output, 0);
schema.writeTo(output, value);
int length = output.writerIndex() - begin - lengthUnit;
valueIntTool.set(output, begin, length);
} else {
log.warn("未注册的信息:ID[{}], VALUE[{}]", key, value);
}
}
}
@Override
public Map<K, V> readFrom(ByteBuf in, ExplainUtils explain) {
if (!in.isReadable())
return null;
Map map;
if (treeMap) map = new TreeMap();
else map = new HashMap(8);
K key = null;
int length = 0;
try {
do {
key = kwModel.readFrom(in, explain);
explain.setLastDesc(description + "ID");
length = valueIntTool.read(in);
explain.lengthField(in.readerIndex() - lengthUnit, description + "长度", length, lengthUnit);
if (length <= 0)
continue;
int writerIndex = in.writerIndex();
int readerIndex = in.readerIndex() + length;
if (writerIndex > readerIndex) {
in.writerIndex(readerIndex);
Object value = readValue(key, in, explain);
map.put(key, value);
in.setIndex(readerIndex, writerIndex);
} else {
Object value = readValue(key, in, explain);
map.put(key, value);
break;
}
} while (in.isReadable());
} catch (Exception e) {
log.warn("解析出错:ID[{}], LENGTH[{}], {}", key, length, e.getMessage());
}
return map;
}
public Object readValue(Object key, ByteBuf in, ExplainUtils explain) {
WModel model = valuesModel.get(key);
if (model != null) {
Object value = model.readFrom(in, explain);
return value;
}
int begin = in.readerIndex();
byte[] bytes = new byte[in.readableBytes()];
in.readBytes(bytes);
explain.readField(begin, description, ByteBufUtil.hexDump(bytes), in);
return bytes;
}
@Override
public void writeTo(ByteBuf output, Map<K, V> map, ExplainUtils explain) {
if (map == null)
return;
for (Map.Entry<K, V> entry : map.entrySet()) {
K key = entry.getKey();
kwModel.writeTo(output, key, explain);
explain.setLastDesc(description + "ID");
V value = entry.getValue();
WModel<V> model = valuesModel.get(key);
if (model != null) {
int begin = output.writerIndex();
Msg msg = explain.lengthField(begin, description + "长度", 0, lengthUnit);
valueIntTool.write(output, 0);
model.writeTo(output, value, explain);
int length = output.writerIndex() - begin - lengthUnit;
valueIntTool.set(output, begin, length);
msg.setLength(length, lengthUnit);
} else {
log.warn("未注册的信息:ID[{}], VALUE[{}]", key, value);
}
}
}
}

View File

@ -0,0 +1,84 @@
package com.fastbee.protocol.base.struc;
import com.fastbee.protocol.base.model.WModel;
import com.fastbee.protocol.util.ExplainUtils;
import com.fastbee.protocol.util.IntTool;
import io.netty.buffer.ByteBuf;
import java.lang.reflect.Array;
/**
* 指定前置数量的数组域
* @author bill
*/
public class TotalArrayObjectStructure<T> extends BaseStructure<T[]> {
private final WModel<T> model;
private final int totalUnit;
private final IntTool intTool;
private final Class<T> arrayClass;
public TotalArrayObjectStructure(WModel<T> model, int totalUnit, Class<T> arrayClass) {
this.model = model;
this.totalUnit = totalUnit;
this.intTool = IntTool.getInstance(totalUnit);
this.arrayClass = arrayClass;
}
@Override
public T[] readFrom(ByteBuf in) {
int total = intTool.read(in);
if (total <= 0)
return null;
T[] value = (T[]) Array.newInstance(arrayClass, total);
for (int i = 0; i < total; i++) {
T t = model.readFrom(in);
value[i] = t;
}
return value;
}
@Override
public void writeTo(ByteBuf out, T[] value) {
if (value == null) {
intTool.write(out, 0);
} else {
int length = value.length;
intTool.write(out, length);
for (int i = 0; i < length; i++) {
T t = value[i];
model.writeTo(out, t);
}
}
}
@Override
public T[] readFrom(ByteBuf in, ExplainUtils explain) {
int total = intTool.read(in);
explain.lengthField(in.readerIndex() - totalUnit, description + "数量", total, totalUnit);
if (total <= 0)
return null;
T[] value = (T[]) Array.newInstance(arrayClass, total);
for (int i = 0; i < total; i++) {
T t = model.readFrom(in, explain);
value[i] = t;
}
return value;
}
@Override
public void writeTo(ByteBuf out, T[] value, ExplainUtils explain) {
if (value == null) {
explain.lengthField(out.writerIndex(), description + "数量", 0, totalUnit);
intTool.write(out, 0);
} else {
int total = value.length;
explain.lengthField(out.writerIndex(), description + "数量", total, totalUnit);
intTool.write(out, total);
for (int i = 0; i < total; i++) {
T t = value[i];
model.writeTo(out, t, explain);
}
}
}
}

View File

@ -0,0 +1,73 @@
package com.fastbee.protocol.base.struc;
import com.fastbee.protocol.base.model.ModelRegistry;
import com.fastbee.protocol.base.model.WModel;
import com.fastbee.protocol.util.ExplainUtils;
import com.fastbee.protocol.util.IntTool;
import io.netty.buffer.ByteBuf;
import java.lang.reflect.Array;
/**
* 指定前置数量的数组域
*
* @author bill
*/
public class TotalArrayPrimitiveStructure extends BaseStructure {
private final WModel model;
private final int totalUnit;
private final int valueUnit;
private final IntTool intTool;
public TotalArrayPrimitiveStructure(WModel model, int totalUnit, Class arrayClass) {
this.model = model;
this.totalUnit = totalUnit;
this.valueUnit = ModelRegistry.getLength(arrayClass);
this.intTool = IntTool.getInstance(totalUnit);
}
@Override
public Object readFrom(ByteBuf in) {
int total = intTool.read(in);
if (total <= 0) {
return null;
}
int length = valueUnit * (total/2);
return model.readFrom(in, length);
}
@Override
public void writeTo(ByteBuf out, Object value) {
if (value == null) {
intTool.write(out, 0);
} else {
int total = Array.getLength(value);
intTool.write(out, total);
model.writeTo(out, value);
}
}
@Override
public Object readFrom(ByteBuf in, ExplainUtils explain) {
int total = intTool.read(in);
explain.lengthField(in.readerIndex() - totalUnit, description + "数量", total, totalUnit);
if (total <= 0)
return null;
int length = valueUnit * total;
return model.readFrom(in, length, explain);
}
@Override
public void writeTo(ByteBuf out, Object value, ExplainUtils explain) {
if (value == null) {
explain.lengthField(out.writerIndex(), description + "数量", 0, totalUnit);
intTool.write(out, 0);
} else {
int total = Array.getLength(value);
explain.lengthField(out.writerIndex(), description + "数量", total, totalUnit);
intTool.write(out, total);
model.writeTo(out, value, explain);
}
}
}

View File

@ -0,0 +1,82 @@
package com.fastbee.protocol.base.struc;
import com.fastbee.protocol.base.model.WModel;
import com.fastbee.protocol.util.ExplainUtils;
import com.fastbee.protocol.util.IntTool;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import java.util.ArrayList;
import java.util.Collection;
/**
* 前置数量的集合报文结构
* @author bill
*/
public class TotalCollectionStructure<T> extends BaseStructure<Collection<T>> {
private final WModel<T> model;
private final int totalUnit;
private final IntTool intTool;
public TotalCollectionStructure(WModel<T> model, int totalUnit){
this.model =model;
this.totalUnit =totalUnit;
this.intTool = IntTool.getInstance(totalUnit);
}
@Override
public Collection<T> readFrom(ByteBuf input) {
int total = intTool.read(input);
if (total <= 0)
return null;
ArrayList<T> list = new ArrayList<>(total);
for (int i = 0; i < total; i++) {
T t = model.readFrom(input);
list.add(t);
}
return list;
}
@Override
public void writeTo(ByteBuf output, Collection<T> list) {
if (list != null) {
intTool.write(output, list.size());
for (T t : list) {
model.writeTo(output, t);
}
} else {
intTool.write(output, 0);
}
}
@Override
public Collection<T> readFrom(ByteBuf input, ExplainUtils explain) {
int total = intTool.read(input);
explain.lengthField(input.readerIndex() - totalUnit, description + "数量", total, totalUnit);
if (total <= 0)
return null;
ArrayList<T> list = new ArrayList<>(total);
for (int i = 0; i < total; i++) {
T t = model.readFrom(input, explain);
list.add(t);
}
return list;
}
@Override
public void writeTo(ByteBuf output, Collection<T> list, ExplainUtils explain) {
if (list != null) {
int total = list.size();
explain.lengthField(output.writerIndex(), description + "数量", total, totalUnit);
intTool.write(output, total);
for (T t : list) {
model.writeTo(output, t, explain);
}
} else {
explain.lengthField(output.writerIndex(), description + "数量", 0, totalUnit);
intTool.write(output, 0);
}
}
}

View File

@ -0,0 +1,198 @@
package com.fastbee.protocol.base.struc;
import com.fastbee.protocol.base.model.MapModel;
import com.fastbee.protocol.base.model.WModel;
import com.fastbee.protocol.util.ExplainUtils;
import com.fastbee.protocol.util.IntTool;
import com.fastbee.protocol.util.Msg;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
/**
* @author bill
*/
@Slf4j
public class TotalMapStructure<K,V> extends BaseStructure<Map<K,V>> {
private final WModel<K> kwModel;
private final Map<K, WModel<V>> valueModel;
private final int lengthUnit;
private final IntTool valueIntTool;
private final int totalUnit;
private final IntTool totalIntTool;
private final boolean treeMap;
public TotalMapStructure(MapModel model, int totalUnit, Class typeClass) {
this.kwModel = model.kwModel;
this.valueModel = model.valueSchema;
this.lengthUnit = model.lengthUnit;
this.valueIntTool = model.intTool;
this.totalUnit = totalUnit;
this.totalIntTool = IntTool.getInstance(totalUnit);
this.treeMap = !HashMap.class.isAssignableFrom(typeClass);
}
@Override
public Map<K, V> readFrom(ByteBuf in) {
if (!in.isReadable())
return null;
int total = totalIntTool.read(in);
if (total <= 0)
return null;
Map map;
if (treeMap) map = new TreeMap();
else map = new HashMap((int) (total / 0.75) + 1);
K key = null;
int length = 0;
try {
for (int i = 0; i < total; i++) {
key = kwModel.readFrom(in);
length = valueIntTool.read(in);
if (length <= 0)
continue;
int writerIndex = in.writerIndex();
int readerIndex = in.readerIndex() + length;
if (writerIndex > readerIndex) {
in.writerIndex(readerIndex);
Object value = readValue(key, in);
map.put(key, value);
in.setIndex(readerIndex, writerIndex);
} else {
Object value = readValue(key, in);
map.put(key, value);
break;
}
}
} catch (Exception e) {
log.warn("解析出错:ID[{}], LENGTH[{}], {}", key, length, e.getMessage());
}
return map;
}
public Object readValue(Object key, ByteBuf in) {
WModel model = valueModel.get(key);
if (model != null) {
return model.readFrom(in);
}
byte[] bytes = new byte[in.readableBytes()];
in.readBytes(bytes);
return bytes;
}
@Override
public void writeTo(ByteBuf output, Map<K, V> map) {
if (map == null)
return;
totalIntTool.write(output, map.size());
for (Map.Entry<K, V> entry : map.entrySet()) {
K key = entry.getKey();
kwModel.writeTo(output, key);
V value = entry.getValue();
WModel<V> model = valueModel.get(key);
if (model != null) {
int begin = output.writerIndex();
valueIntTool.write(output, 0);
model.writeTo(output, value);
int length = output.writerIndex() - begin - lengthUnit;
valueIntTool.set(output, begin, length);
} else {
log.warn("未注册的信息:ID[{}], VALUE[{}]", key, value);
}
}
}
@Override
public Map<K, V> readFrom(ByteBuf in, ExplainUtils explain) {
if (!in.isReadable())
return null;
int total = totalIntTool.read(in);
explain.lengthField(in.readerIndex() - totalUnit, description + "数量", total, totalUnit);
if (total <= 0)
return null;
Map map;
if (treeMap) map = new TreeMap();
else map = new HashMap((int) (total / 0.75) + 1);
K key = null;
int length = 0;
try {
for (int i = 0; i < total; i++) {
key = kwModel.readFrom(in, explain);
explain.setLastDesc(description + "ID");
length = valueIntTool.read(in);
explain.lengthField(in.readerIndex() - lengthUnit, description + "长度", length, lengthUnit);
if (length <= 0)
continue;
int writerIndex = in.writerIndex();
int readerIndex = in.readerIndex() + length;
if (writerIndex > readerIndex) {
in.writerIndex(readerIndex);
Object value = readValue(key, in, explain);
map.put(key, value);
in.setIndex(readerIndex, writerIndex);
} else {
Object value = readValue(key, in, explain);
map.put(key, value);
break;
}
}
} catch (Exception e) {
log.warn("解析出错:ID[{}], LENGTH[{}], {}", key, length, e.getMessage());
}
return map;
}
public Object readValue(Object key, ByteBuf in, ExplainUtils explain) {
WModel model = valueModel.get(key);
if (model != null) {
Object value = model.readFrom(in, explain);
return value;
}
int begin = in.readerIndex();
byte[] bytes = new byte[in.readableBytes()];
in.readBytes(bytes);
explain.readField(begin, description, ByteBufUtil.hexDump(bytes), in);
return bytes;
}
@Override
public void writeTo(ByteBuf output, Map<K, V> map, ExplainUtils explain) {
if (map == null)
return;
totalIntTool.write(output, map.size());
for (Map.Entry<K, V> entry : map.entrySet()) {
K key = entry.getKey();
kwModel.writeTo(output, key, explain);
explain.setLastDesc(description + "ID");
V value = entry.getValue();
WModel<V> model = valueModel.get(key);
if (model != null) {
int begin = output.writerIndex();
Msg msg = explain.lengthField(begin, description + "长度", 0, lengthUnit);
valueIntTool.write(output, 0);
model.writeTo(output, value, explain);
int length = output.writerIndex() - begin - lengthUnit;
valueIntTool.set(output, begin, length);
msg.setLength(length, lengthUnit);
} else {
log.warn("未注册的信息:ID[{}], VALUE[{}]", key, value);
}
}
}
}

View File

@ -0,0 +1,22 @@
package com.fastbee.protocol.domain;
import com.fastbee.protocol.base.protocol.IProtocol;
import lombok.Data;
/**
* 设备协议model
* @author gsb
* @date 2022/10/25 13:38
*/
@Data
public class DeviceProtocol {
/**协议实例*/
private IProtocol protocol;
/**产品id*/
private Long productId;
/**设备编号*/
private String serialNumber;
}

View File

@ -0,0 +1,19 @@
package com.fastbee.protocol.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 位定义 0-关闭 1-k开启 ,如果不同状态清重写
* @author bill
*/
@Getter
@AllArgsConstructor
public enum ModbusBitStatus {
OPEN((byte) 0x01),
CLOSED((byte) 0x00)
;
private byte bit;
}

View File

@ -0,0 +1,20 @@
package com.fastbee.protocol.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 线圈状态
* @author bill
*/
@Getter
@AllArgsConstructor
public enum ModbusCoilStatus {
//线圈开启
ON(new byte[] {(byte) 0xFF, 0x00}),
//线圈关闭
OFF(new byte[] {0x00, 0x00})
;
private byte[] data;
}

View File

@ -0,0 +1,44 @@
package com.fastbee.protocol.enums;
import com.fastbee.common.exception.ServiceException;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum ModbusErrCode {
E01((byte) 0x01, "非法功能"),
E02((byte) 0x02, "非法数据地址"),
E03((byte) 0x03, "非法数据值"),
E04((byte) 0x04, "从站设备故障"),
E05((byte) 0x05, "确认"),
E06((byte) 0x06, "从属设备忙"),
E07((byte) 0x07, "从属设备忙"),
E08((byte) 0x08, "存储奇偶性差错"),
E0A((byte) 0x0A, "不可用网关路径"),
E0B((byte) 0x0B, "网关目标设备响应失败")
;
private byte code;
private String desc;
public static ModbusErrCode valueOf(int code) {
switch (code) {
case 0x01: return E01;
case 0x02: return E02;
case 0x03: return E03;
case 0x04: return E04;
case 0x05: return E05;
case 0x06: return E06;
case 0x07: return E07;
case 0x08: return E08;
case 0x0A: return E0A;
case 0x0B: return E0B;
default: throw new ServiceException("未知错误码["+code+"]");
}
}
}

View File

@ -0,0 +1,34 @@
package com.fastbee.protocol.service;
import com.fastbee.common.core.mq.message.ProtocolDto;
import com.fastbee.protocol.base.protocol.IProtocol;
import com.fastbee.protocol.domain.DeviceProtocol;
import java.util.List;
/**
* @author gsb
* @date 2022/10/10 17:07
*/
public interface IProtocolManagerService {
/**
*获取所有的协议,包含脚本解析协议和系统内部定义协议
*/
public List<ProtocolDto> getAllProtocols();
/**
* 根据协议编码获取系统内部协议
* @param protocolCode 协议编码
* @return 协议
*/
IProtocol getProtocolByProtocolCode(String protocolCode);
/**
* 根据设备编号获取系统内部协议实例
* @param serialNumber 产品编号
* @return 协议实例
*/
DeviceProtocol getProtocolBySerialNumber(String serialNumber);
}

View File

@ -0,0 +1,129 @@
package com.fastbee.protocol.service.impl;
import com.alibaba.fastjson2.JSONObject;
import com.fastbee.common.annotation.SysProtocol;
import com.fastbee.common.core.device.DeviceAndProtocol;
import com.fastbee.common.core.mq.message.ProtocolDto;
import com.fastbee.common.utils.DateUtils;
import com.fastbee.common.utils.StringUtils;
import com.fastbee.common.utils.spring.SpringUtils;
import com.fastbee.iot.domain.Protocol;
import com.fastbee.iot.service.IDeviceService;
import com.fastbee.iot.service.IProtocolService;
import com.fastbee.protocol.base.protocol.IProtocol;
import com.fastbee.protocol.domain.DeviceProtocol;
import com.fastbee.protocol.service.IProtocolManagerService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 设备内部协议管理类
* @author bill
*/
@Slf4j
@Service
public class ProtocolManagerServiceImpl<M> implements IProtocolManagerService {
@Autowired
private IDeviceService deviceService;
@Autowired
private IProtocolService protocolService;
private final Map<String, IProtocol> protocolMap = new HashMap<>();
/**
*获取所有的协议,包含脚本解析协议和系统内部定义协议
*/
@Override
public List<ProtocolDto> getAllProtocols(){
List<ProtocolDto> result = new ArrayList<>();
//获取@SysProtocol注解的bean
Map<String, Object> annotations = SpringUtils.getBeanWithAnnotation(SysProtocol.class);
//获取外部配置协议
Protocol protocol = new Protocol();
protocol.setProtocolStatus(1);
protocol.setDelFlag(0);
List<Protocol> protocolList = protocolService.selectByCondition(protocol);
annotations.forEach((key,value)->{
SysProtocol annotation = value.getClass().getAnnotation(SysProtocol.class);
ProtocolDto protocolDto = new ProtocolDto();
protocolDto.setCode(annotation.protocolCode());
protocolDto.setName(annotation.name());
protocolDto.setDescription(annotation.description());
/*系统内部协议*/
protocolDto.setProtocolType(0);
result.add(protocolDto);
boolean match = protocolList.stream().anyMatch(po -> po.getProtocolCode().equals(annotation.protocolCode()));
if (!match){
Protocol newPo = new Protocol();
newPo.setProtocolCode(annotation.protocolCode());
newPo.setProtocolName(annotation.name());
newPo.setJarSign(annotation.description());
newPo.setProtocolStatus(1);
newPo.setDelFlag(0);
newPo.setCreateTime(DateUtils.getNowDate());
protocolService.insertProtocol(newPo);
}
});
/**外部协议*/
for (Protocol item : protocolList) {
ProtocolDto protocolDto = new ProtocolDto();
protocolDto.setCode(item.getProtocolCode());
protocolDto.setName(item.getProtocolName());
protocolDto.setProtocolUrl(item.getProtocolFileUrl());
protocolDto.setProtocolType(item.getProtocolType());
result.add(protocolDto);
}
return result;
}
/**
* 根据协议编码获取系统内部协议
* @param protocolCode 协议编码
* @return 协议
*/
@Override
public IProtocol getProtocolByProtocolCode(String protocolCode) {
if (!CollectionUtils.isEmpty(this.protocolMap)){
return protocolMap.get(protocolCode);
}
Map<String, IProtocol> annotations = SpringUtils.getBeanWithAnnotation(SysProtocol.class);
IProtocol protocol = null;
for (IProtocol item : annotations.values()) {
SysProtocol annotation = item.getClass().getAnnotation(SysProtocol.class);
protocolMap.put(annotation.protocolCode(), item);
if (annotation.protocolCode().equals(protocolCode)){
protocol = item;
}
}
return protocol;
}
/**
* 根据设备编号获取协议实例
* @param serialNumber 产品编号
* @return 协议实例
*/
@Override
public DeviceProtocol getProtocolBySerialNumber(String serialNumber){
DeviceAndProtocol deviceAndProtocol = deviceService.selectProtocolBySerialNumber(serialNumber);
String protocolCode = deviceAndProtocol.getProtocolCode();
if (StringUtils.isEmpty(protocolCode)){
log.error("=>设备的协议编号为空{}",serialNumber);
return null;
}
DeviceProtocol deviceProtocol = new DeviceProtocol();
deviceProtocol.setSerialNumber(deviceAndProtocol.getSerialNumber());
deviceProtocol.setProductId(deviceProtocol.getProductId());
IProtocol baseProtocol = getProtocolByProtocolCode(protocolCode);
deviceProtocol.setProtocol(baseProtocol);
return deviceProtocol;
}
}

View File

@ -0,0 +1,114 @@
package com.fastbee.protocol.util;
import java.util.ArrayList;
import java.util.List;
/**
* 使用数组实现key为int的Map数组的长度等于key的最大值减去最小值
* 因此key的区间跨度太大会造成内存空间上的浪费仅适用于小范围且连续的key
* 可指定value为null的缺省返回值该返回值位于数组的末位,key为int的最大值
* @author bill
*/
public class ArrayMap<T> {
public static final int DEFAULT_KEY = Integer.MAX_VALUE;
private T[] array = (T[]) new Object[2];
private boolean init = true;
private int min;
private int max;
public T get(int key) {
if (key < min || key > max)
return null;
return array[key - min];
}
public T getOrDefault(int key) {
if (key < min || key > max)
return array[array.length - 1];
return array[key - min];
}
public void defaultValue(T value) {
array[array.length - 1] = value;
}
public void put(int key, T value) {
if (key == DEFAULT_KEY) {
defaultValue(value);
return;
}
if (this.init) {
this.init = false;
this.min = key;
this.max = key;
}
int offset = Math.max(0, min - key);
if (key < min) min = key;
if (key > max) max = key;
ensureCapacityInternal(offset);
array[key - min] = value;
}
private void ensureCapacityInternal(int offset) {
final int minCapacity = max - min + 2;
if (minCapacity > 256)
throw new IllegalArgumentException("min:" + min + ", max:" + max + "key的区间过大");
final int length = array.length - 1;
if (minCapacity >= length) {
T[] temp = (T[]) new Object[minCapacity];
System.arraycopy(array, 0, temp, offset, length);
temp[temp.length - 1] = array[length];
array = temp;
} else {
if (offset > 0) {
System.arraycopy(array, 0, array, offset, length);
}
}
}
public List<T> values() {
List<T> values = new ArrayList<>(array.length);
for (T t : array)
if (t != null)
values.add(t);
return values;
}
public int[] keys() {
int length = size();
int[] keys = new int[length];
int count = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] != null) keys[count++] = i + min;
}
if (array[array.length - 1] != null)
keys[keys.length - 1] = DEFAULT_KEY;
return keys;
}
public int size() {
int count = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] != null) count++;
}
return count;
}
public ArrayMap<T> fillDefaultValue() {
if (array.length == 2) {
if (array[0] == null)
array[0] = array[1];
} else {
for (int i = 0; i < array.length - 2; i++) {
if (array[i] == null)
array[i] = array[array.length - 1];
}
}
return this;
}
}

View File

@ -0,0 +1,243 @@
package com.fastbee.protocol.util;
import org.apache.commons.lang3.ArrayUtils;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.io.UnsupportedEncodingException;
/**
* Bytes和 Hex转换工具类
*/
public class ByteToHexUtil {
/**
* 单个Hex字符串转byte
*
* @param hexStr
* @return
*/
public static byte hexToByte(String hexStr) {
return (byte) Integer.parseInt(hexStr, 16);
}
/**
* hex字符串转为 byte数组
*
* @param inHex 转换的 hex字符串
* @return 转换后的 byte数组
*/
public static byte[] hexToByteArray(String inHex) {
int hexlen = inHex.length();
byte[] result;
if (hexlen % 2 == 1) {
// 奇数
hexlen++;
result = new byte[(hexlen / 2)];
inHex = "0" + inHex;
} else {
// 偶数
result = new byte[(hexlen / 2)];
}
int j = 0;
for (int i = 0; i < hexlen; i += 2) {
result[j] = hexToByte(inHex.substring(i, i + 2));
j++;
}
return result;
}
/**
* 单个字节转换十六进制
*
* @param b byte字节
* @return 转换后的单个hex字符
*/
public static String byteToHex(byte b) {
String hex = Integer.toHexString(b & 0xFF);
if (hex.length() < 2) {
hex = "0" + hex;
}
return hex;
}
/**
* byte数组转换炒年糕十六进制字符串
*
* @param bArray byte数组
* @return hex字符串
*/
public static String bytesToHexString(byte[] bArray) {
StringBuffer sb = new StringBuffer(bArray.length);
for (int i = 0; i < bArray.length; i++) {
String hexStr = Integer.toHexString(0xFF & bArray[i]);
if (hexStr.length() < 2)
sb.append(0);
sb.append(hexStr.toUpperCase());
}
return sb.toString();
}
/**
* 将hex转为正负数 2个字节
*
* @param hexStr hex字符串
* @return 结果
*/
public static int parseHex2(String hexStr) {
if (hexStr.length() != 4) {
throw new NumberFormatException("Wrong length: " + hexStr.length() + ", must be 4.");
}
int ret = Integer.parseInt(hexStr, 16);
ret = ((ret & 0x8000) > 0) ? (ret - 0x10000) : (ret);
return ret;
}
public static Integer cutMessageHexTo(byte[] source, int startIndex, int endIndex){
byte[] subarray = ArrayUtils.subarray(source, startIndex, endIndex);
String s = bytesToHexString(subarray);
return Integer.parseInt(s,16);
}
public static String bSubstring(String s,int start, int length) throws Exception
{
byte[] bytes = s.getBytes("Unicode");
int n = 0; // 表示当前的字节数
int i = start; // 要截取的字节数从第3个字节开始
for (; i < bytes.length && n < length; i++)
{
// 奇数位置如3、5、7等为UCS2编码中两个字节的第二个字节
if (i % 2 == 1)
{
n++; // 在UCS2第二个字节时n加1
}
else
{
// 当UCS2编码的第一个字节不等于0时该UCS2字符为汉字一个汉字算两个字节
if (bytes[i] != 0)
{
n++;
}
}
}
// 如果i为奇数时处理成偶数
if (i % 2 == 1)
{
// 该UCS2字符是汉字时去掉这个截一半的汉字
if (bytes[i - 1] != 0)
i = i - 1;
// 该UCS2字符是字母或数字则保留该字符
else
i = i + 1;
}
return new String(bytes, 0, i, "Unicode");
}
/**
*
* @param orignal 要截取的字符串
* @param start 开始下标
* @param count 截取长度
* @return
*/
public static String substringByte(String orignal, int start, int count) {
// 如果目标字符串为空,则直接返回,不进入截取逻辑;
if (orignal == null || "".equals(orignal)){
return orignal;
}
// 截取Byte长度必须>0
if (count <= 0) {
return orignal;
}
// 截取的起始字节数必须比
if (start < 0) {
start = 0;
}
// 目标char Pull buff缓存区间
StringBuffer buff = new StringBuffer();
try {
// 截取字节起始字节位置大于目标String的Byte的length则返回空值
if (start >= getStringByteLenths(orignal)) {
return null;
}
int len = 0;
char c;
// 遍历String的每一个Char字符计算当前总长度
// 如果到当前Char的的字节长度大于要截取的字符总长度则跳出循环返回截取的字符串。
for (int i = 0; i < orignal.toCharArray().length; i++) {
c = orignal.charAt(i);
// 当起始位置为0时候
if (start == 0) {
len += String.valueOf(c).getBytes("GBK").length;
if (len <= count) {
buff.append(c);
}else {
break;
}
} else {
// 截取字符串从非0位置开始
len += String.valueOf(c).getBytes("GBK").length;
if (len > start && len <= start + count) {
buff.append(c);
}
if (len > start + count) {
break;
}
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// 返回最终截取的字符结果;
// 创建String对象传入目标char Buff对象
return new String(buff);
}
public static int getStringByteLenths(String args) throws UnsupportedEncodingException {
return args != null && args != "" ? args.getBytes("Unicode").length : 0;
}
public static void main(String[] args) {
//String str = "000000000111";
//byte[] result = hexToByteArray(str);
//System.out.println("hex字符串转byte数组 ---" + Arrays.toString(result));
//
//System.out.println("hex字符串---"+bytesToHexString(result));
//int parseInt = Integer.parseInt(str, 16);
//System.out.println(parseInt);
//
//int va = -40;
//byte[] bytes = IntegerToByteUtil.intToBytes2(va);
//System.out.println("hex字符串转byte数组 ---" + Arrays.toString(bytes));
//
//int num = 1713;
//String hexString = Integer.toHexString(num);
//System.out.println(hexString);
ScriptEngine js = new ScriptEngineManager().getEngineByName("JavaScript");
String str = "8*%s";
try {
System.out.println(js.eval(str.replace("%s","0.42")));
}catch (Exception e){
}
}
}

View File

@ -0,0 +1,53 @@
package com.fastbee.protocol.util;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
/**
* @author bill
*/
public class Cache<K,V> {
private volatile Map<K, V> cache;
public Cache() {
this(32);
}
public Cache(Map<K, V> cache) {
this.cache = cache;
}
public Cache(int initialCapacity) {
this.cache = new HashMap<>((int) (initialCapacity / 0.75) + 1);
}
public V get(K key) {
return cache.get(key);
}
public V get(K key, Supplier<V> function) {
V value = cache.get(key);
if (value == null) {
synchronized (cache) {
value = cache.get(key);
if (value == null) {
cache.put(key, value = function.get());
}
}
}
return value;
}
public V put(K key, V value) {
synchronized (cache) {
cache.put(key, value);
}
return value;
}
@Override
public String toString() {
return cache.toString();
}
}

View File

@ -0,0 +1,87 @@
package com.fastbee.protocol.util;
import java.io.IOException;
import java.util.Arrays;
/**
* @author gsb
* @date 2022/11/9 17:47
*/
public class CharsBuilder implements CharSequence, Appendable{
private char[] value;
private int pos;
public CharsBuilder(int length) {
this.value = new char[length];
}
public CharsBuilder(char[] chars) {
this.value = chars;
}
@Override
public Appendable append(CharSequence s) {
return append(s, 0, s.length());
}
@Override
public Appendable append(CharSequence s, int start, int end) {
int len = end - start;
for (int i = start, j = pos; i < end; i++, j++)
value[j] = s.charAt(i);
pos += len;
return this;
}
@Override
public Appendable append(char c) {
value[pos++] = c;
return this;
}
@Override
public char charAt(int index) {
return value[index];
}
@Override
public CharSequence subSequence(int start, int end) {
if (start == end) {
return new CharsBuilder(Math.min(16, value.length));
}
return new CharsBuilder(Arrays.copyOfRange(value, start, end));
}
@Override
public int length() {
return value.length;
}
@Override
public String toString() {
return new String(value);
}
public String leftStrip(char c) {
int i = leftOf(value, c);
return new String(value, i, value.length - i);
}
public String rightStrip(char c) {
int i = rightOf(value, c);
return new String(value, 0, i);
}
public static int leftOf(char[] chars, char pad) {
int i = 0, len = chars.length;
while (i < len && chars[i] == pad) i++;
return i;
}
public static int rightOf(char[] chars, char pad) {
int i = 0, len = chars.length;
while ((i < len) && (chars[len - 1] <= pad)) len--;
return len;
}
}

View File

@ -0,0 +1,118 @@
package com.fastbee.protocol.util;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* @author bill
*/
public class ClassUtils {
public static List<Class> getClassList(String packageName, Class<? extends Annotation> annotationClass) {
List<Class> classList = getClassList(packageName);
classList.removeIf(next -> !next.isAnnotationPresent(annotationClass));
return classList;
}
public static List<Class> getClassList(String packageName) {
List<Class> classList = new LinkedList<>();
String path = packageName.replace(".", "/");
try {
Enumeration<URL> urls = ClassUtils.getClassLoader().getResources(path);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
if (url != null) {
String protocol = url.getProtocol();
if (protocol.equals("file")) {
addClass(classList, url.toURI().getPath(), packageName);
} else if (protocol.equals("jar")) {
JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
JarFile jarFile = jarURLConnection.getJarFile();
Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
String entryName = jarEntry.getName();
if (entryName.startsWith(path) && entryName.endsWith(".class")) {
String className = entryName.substring(0, entryName.lastIndexOf(".")).replaceAll("/", ".");
addClass(classList, className);
}
}
}
}
}
} catch (Exception e) {
throw new RuntimeException("Initial class error!");
}
return classList;
}
private static void addClass(List<Class> classList, String packagePath, String packageName) {
try {
File[] files = new File(packagePath).listFiles(file -> (file.isDirectory() || file.getName().endsWith(".class")));
if (files != null)
for (File file : files) {
String fileName = file.getName();
if (file.isFile()) {
String className = fileName.substring(0, fileName.lastIndexOf("."));
if (packageName != null) {
className = packageName + "." + className;
}
addClass(classList, className);
} else {
String subPackagePath = fileName;
if (packageName != null) {
subPackagePath = packagePath + "/" + subPackagePath;
}
String subPackageName = fileName;
if (packageName != null) {
subPackageName = packageName + "." + subPackageName;
}
addClass(classList, subPackagePath, subPackageName);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static void addClass(List<Class> classList, String className) {
classList.add(loadClass(className, false));
}
public static Class loadClass(String className, boolean isInitialized) {
try {
return Class.forName(className, isInitialized, getClassLoader());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
public static ClassLoader getClassLoader() {
return Thread.currentThread().getContextClassLoader();
}
public static Class getGenericType(Field f) {
Class typeClass = f.getType();
if (Collection.class.isAssignableFrom(typeClass)) {
return (Class) ((ParameterizedType) f.getGenericType()).getActualTypeArguments()[0];
} else if (Map.class.isAssignableFrom(typeClass)) {
return (Class) ((ParameterizedType) f.getGenericType()).getActualTypeArguments()[1];
} else if (typeClass.isArray()) {
return typeClass.getComponentType();
}
return typeClass;
}
}

View File

@ -0,0 +1,126 @@
package com.fastbee.protocol.util;
import io.netty.buffer.ByteBuf;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
/**
* 时间编码工具
* @author gsb
* @date 2022/11/9 17:26
*/
public class DateTool {
public static final DateTool BYTE = new DateTool();
public static final DateTool BCD = new BCD();
public static final int YEAR = LocalDate.now().getYear();
public static final int YEAR_RANGE = YEAR - 30;
public static final int HUNDRED_YEAR = YEAR_RANGE / 100 * 100;
public static int getYear(int year) {
year += HUNDRED_YEAR;
if (year < YEAR_RANGE) {
year += 100;
}
return year;
}
/** 时间转byte[] (yyMMddHHmmss) */
public final byte[] from(LocalDateTime dateTime) {
byte[] bytes = new byte[6];
bytes[0] = toByte(dateTime.getYear() % 100);
bytes[1] = toByte(dateTime.getMonthValue());
bytes[2] = toByte(dateTime.getDayOfMonth());
bytes[3] = toByte(dateTime.getHour());
bytes[4] = toByte(dateTime.getMinute());
bytes[5] = toByte(dateTime.getSecond());
return bytes;
}
/** byte[]转时间 (yyMMddHHmmss) */
public final LocalDateTime toDateTime(byte[] bytes) {
try {
return LocalDateTime.of(
getYear(toInt(bytes[0])),
toInt(bytes[1]),
toInt(bytes[2]),
toInt(bytes[3]),
toInt(bytes[4]),
toInt(bytes[5]));
} catch (Exception e) {
return null;
}
}
/** 日期转byte[] (yyMMdd) */
public final byte[] from(LocalDate date) {
return new byte[]{
toByte((date.getYear() % 100)),
toByte(date.getMonthValue()),
toByte(date.getDayOfMonth())
};
}
/** byte[]转日期 (yyMMdd) */
public final LocalDate toDate(byte[] bytes) {
return LocalDate.of(
getYear(toInt(bytes[0])),
toInt(bytes[1]),
toInt(bytes[2])
);
}
/** 时间转byte[] (HHmmss) */
public final byte[] from(LocalTime time) {
return new byte[]{
toByte(time.getHour()),
toByte(time.getMinute()),
toByte(time.getSecond())
};
}
/** byte[]转时间 (HHmmss) */
public final LocalTime toTime(byte[] bytes) {
return LocalTime.of(
toInt(bytes[0]),
toInt(bytes[1]),
toInt(bytes[2])
);
}
/** 写入2位时间(HHmm) */
public final void writeTime2(ByteBuf output, LocalTime time) {
output.writeByte(toByte(time.getHour())).writeByte(toByte(time.getMinute()));
}
/** 读取2位时间(HHmm) */
public final LocalTime readTime2(ByteBuf input) {
return LocalTime.of(toInt(input.readByte()), toInt(input.readByte()));
}
private DateTool() {
}
public byte toByte(int i) {
return (byte) i;
}
public int toInt(byte b) {
return b & 0xff;
}
private static class BCD extends DateTool {
@Override
public byte toByte(int i) {
return (byte) ((i / 10 << 4) | (i % 10 & 0xf));
}
@Override
public int toInt(byte b) {
return (b >> 4 & 0xf) * 10 + (b & 0xf);
}
}
}

View File

@ -0,0 +1,52 @@
package com.fastbee.protocol.util;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import java.util.LinkedList;
/**
* 编解码分析
*
* @author gsb
* @date 2022/11/9 16:35
*/
public class ExplainUtils extends LinkedList<Msg> {
public void readField(int index, String desc, Object value, ByteBuf input) {
if (value != null) {
this.add(Msg.field(index, desc, value, ByteBufUtil.hexDump(input, index, input.readerIndex() - index)));
}
}
public void writeField(int index, String desc, Object value, ByteBuf output) {
if (value != null) {
this.add(Msg.field(index, desc, value, ByteBufUtil.hexDump(output, index, output.writerIndex() - index)));
}
}
public Msg lengthField(int index, String desc, int length, int lengthUnit) {
Msg info = Msg.lengthField(index, desc, length, lengthUnit);
this.add(info);
return info;
}
public void setLastDesc(String desc) {
this.get(this.size() - 1).desc = desc;
}
public void println() {
for (Msg info : this) {
System.out.println(info);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(this.size() << 5);
for (Msg info : this) {
sb.append(info).append('\n');
}
return sb.toString();
}
}

View File

@ -0,0 +1,140 @@
package com.fastbee.protocol.util;
import io.netty.buffer.ByteBuf;
/**
* @author bill
*/
public interface IntTool {
static IntTool getInstance(int length) {
switch (length) {
case -1:
case 0:
return ALL;
case 1:
return BYTE;
case 2:
return WORD;
case 3:
return MEDIUM;
case 4:
return DWORD;
default:
throw new IllegalArgumentException("unsupported length: " + length + " (expected: 1, 2, 3, 4)");
}
}
int get(ByteBuf in, int i);
void set(ByteBuf out, int i, int n);
int read(ByteBuf in);
void write(ByteBuf out, int n);
/** -1读取剩余所有字节 */
IntTool ALL = new IntTool() {
@Override
public int get(ByteBuf in, int i) {
return -1;
}
@Override
public void set(ByteBuf out, int i, int n) {
}
@Override
public int read(ByteBuf in) {
return -1;
}
@Override
public void write(ByteBuf out, int n) {
}
};
IntTool BYTE = new IntTool() {
@Override
public int get(ByteBuf in, int i) {
return in.getUnsignedByte(i);
}
@Override
public void set(ByteBuf out, int i, int n) {
out.setByte(i, n);
}
@Override
public int read(ByteBuf in) {
return in.readUnsignedByte();
}
@Override
public void write(ByteBuf out, int n) {
out.writeByte(n);
}
};
IntTool WORD = new IntTool() {
@Override
public int get(ByteBuf in, int i) {
return in.getUnsignedShort(i);
}
@Override
public void set(ByteBuf out, int i, int n) {
out.setShort(i, n);
}
@Override
public int read(ByteBuf in) {
return in.readUnsignedShort();
}
@Override
public void write(ByteBuf out, int n) {
out.writeShort(n);
}
};
IntTool MEDIUM = new IntTool() {
@Override
public int get(ByteBuf in, int i) {
return in.getUnsignedMedium(i);
}
@Override
public void set(ByteBuf out, int i, int n) {
out.setMedium(i, n);
}
@Override
public int read(ByteBuf in) {
return in.readUnsignedMedium();
}
@Override
public void write(ByteBuf out, int n) {
out.writeMedium(n);
}
};
IntTool DWORD = new IntTool() {
@Override
public int get(ByteBuf in, int i) {
return in.getInt(i);
}
@Override
public void set(ByteBuf out, int i, int n) {
out.setInt(i, n);
}
@Override
public int read(ByteBuf in) {
return in.readInt();
}
@Override
public void write(ByteBuf out, int n) {
out.writeInt(n);
}
};
}

View File

@ -0,0 +1,232 @@
package com.fastbee.protocol.util;
import java.util.Arrays;
import java.util.Map;
/**
* Integer转 byte
*/
public class IntegerToByteUtil {
/**
* 将int转换为byte数组并指定长度
*
* @param data int数据
* @param byteLen 指定长度
* @return byte[]
*/
public static byte[] intToByteArr(int data, int byteLen) {
byte[] bytes = new byte[byteLen];
for (int i = 0; i < bytes.length; i++) {
bytes[byteLen - i - 1] = (byte) (data % 256);
data = data / 256;
}
return bytes;
}
/**
* byte转int
*
* @param b
* @return
*/
public static int byteToInt(byte b) {
return b & 0xff;
}
/**
* byte[]转int
*
* @param bytes 需要转换成int的数组
* @return int值
*/
public static int byteArrayToInt(byte[] src) {
int value;
int offset = 0;
value = (int) ((src[offset] & 0xFF)
| ((src[offset+1] & 0xFF)<<8)
| ((src[offset+2] & 0xFF)<<16)
| ((src[offset+3] & 0xFF)<<24));
return value;
}
/**
* 将int数值转换为占四个字节的byte数组本方法适用于(低位在前,高位在后)的顺序。 和bytesToInt配套使用
*
* @param value 要转换的int值
* @return byte数组
*/
public static byte[] intToBytes(int value) {
byte[] src = new byte[4];
src[3] = (byte) ((value >> 24) & 0xFF);
src[2] = (byte) ((value >> 16) & 0xFF);
src[1] = (byte) ((value >> 8) & 0xFF);
src[0] = (byte) (value & 0xFF);
return src;
}
/**
* 将int数值转换为占2个字节的byte数组本方法适用于(高位在前,低位在后)的顺序。 和bytesToInt2配套使用
*/
public static byte[] intToBytes2(int value) {
byte[] src = new byte[2];
src[0] = (byte) ((value >> 8) & 0xFF);
src[1] = (byte) (value & 0xFF);
return src;
}
/**
* byte数组中取int数值本方法适用于(低位在前,高位在后)的顺序和和intToBytes配套使用
*
* @param src byte数组
* @param offset 从数组的第offset位开始
* @return int数值
*/
public static int bytesToInt(byte[] src, int offset) {
int value;
value = (int) ((src[offset] & 0xFF)
| ((src[offset + 1] & 0xFF) << 8)
| ((src[offset + 2] & 0xFF) << 16)
| ((src[offset + 3] & 0xFF) << 24));
return value;
}
/**
* byte数组中取int数值本方法适用于(低位在后,高位在前)的顺序。和intToBytes2配套使用
*/
public static int bytesToInt2(byte[] src, int offset) {
int value;
value = (int) (((src[offset] & 0xFF) << 24)
| ((src[offset + 1] & 0xFF) << 16)
| ((src[offset + 2] & 0xFF) << 8)
| (src[offset + 3] & 0xFF));
return value;
}
/**
* 将不满4位的byte数组转为四位
*
* @param src 不满四位数组
* @return 满4位数组
*/
public static byte[] bytesToBytes4(byte[] src) {
if (src.length < 4) {
byte[] result = new byte[4];
for (int i = 0; i < 4; i++) {
if (i >= 4 - src.length) {
result[i] = src[Math.abs(4 - i - src.length)];
} else {
result[i] = 0; //补全0
}
}
return result;
} else {
return src;
}
}
/**
* 将16进制转换为二进制
*/
public static String hexString2binaryString(int num, int radix) {
StringBuffer sb = new StringBuffer();
switch (radix) {
case 2:
String s = Integer.toBinaryString(num);
for (int i = 0; i < 16 - s.length(); i++) {
sb.append("0");
}
return sb.append(s).toString();
case 8:
return Integer.toOctalString(num);
case 16:
return Integer.toHexString(num);
default:
return null;
}
}
public static int binaryToInt(String binary) {
return Integer.parseInt(binary, 2);
}
/**
* 将某个数的n位变为1或0
*
* @param value 1/0
* @param data 待修改的数据
* @param position 更改位置
* @return 结果
*/
public static int bitOperation(int data, int value, int position) {
if (value == 0) {
return data & ~(1 << position);
} else if (value == 1) {
return data | (1 << position);
}
return data;
}
/**
* 批量修改bit位
*
* @param data 源数据
* @param map 数据map
* @return 结果
*/
public static int bitOperationBatch(int data, Map<Integer, Integer> map) {
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (entry.getValue() == 0) {
data = data & ~(1 << entry.getKey());
} else if (entry.getValue() == 1) {
data = data | (1 << entry.getKey());
}
}
return data;
}
private static String encodeHexString(byte[] data) {
char[] hexArray = "0123456789abcdef".toCharArray();
char[] out = new char[data.length * 2];
for (int i = 0; i < data.length; i++) {
int v = data[i] & 0xFF;//取byte的后八位
out[i * 2] = hexArray[v >>> 4];
out[i * 2 + 1] = hexArray[v & 0x0F];
}
return new String(out);
}
public static String intToHexString6(int number){
StringBuilder sb = new StringBuilder();
String hexString = Integer.toHexString(number);
for (int i = 0; i < 12 - hexString.length(); i++) {
sb.append("0");
}
return sb.append(hexString).toString();
}
public static void main(String[] args) {
byte[] bytes = intToByteArr(-40, 2);
System.out.println("将整数转换为byte数组并指定长度---" + Arrays.toString(bytes));
System.out.println(IntegerToByteUtil.encodeHexString(bytes));
String hexString6 = intToHexString6(17);
byte[] bytes1 = ByteToHexUtil.hexToByteArray(hexString6);
int ret = bitOperation(0, 98, 6);
byte[] bytes2 = IntegerToByteUtil.intToByteArr(ret, 2);
byte[] b1 = {(byte) 0x01,(byte) 0x02};
System.out.println(ByteToHexUtil.bytesToHexString(b1));
System.out.println(ByteToHexUtil.bytesToHexString(bytes2));
}
}

View File

@ -0,0 +1,49 @@
package com.fastbee.protocol.util;
import java.util.Map;
/**
* 键值对
* @author bill
*/
public class KeyValuePair<K, V> implements Map.Entry<K, V> {
private K key;
private V value;
public KeyValuePair() {
}
public KeyValuePair(K key) {
this.key = key;
}
@Override
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V value) {
this.value = value;
return value;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder(32);
sb.append("KeyValuePair{key=").append(key);
sb.append(", value=").append(value);
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,41 @@
package com.fastbee.protocol.util;
import com.fastbee.common.utils.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author gsb
* @date 2022/11/9 16:28
*/
@Getter
@AllArgsConstructor
public class Msg {
protected int index;
protected String desc;
protected Object value;
protected String raw;
public static Msg field(int index, String desc, Object value, String raw) {
return new Msg(index, desc, value, raw);
}
public static Msg lengthField(int index, String desc, int value, int lengthUnit) {
return new Msg(index, desc, value, StringUtils.leftPad(Integer.toHexString(value), 1 << lengthUnit, '0'));
}
public void setLength(int length, int lengthUnit) {
this.value = length;
this.raw = StringUtils.leftPad(Integer.toHexString(length), 1 << lengthUnit, '0');
}
@Override
public String toString() {
if (desc == null) {
return index + "\t[" + raw + "] [" + StringUtils.toString(value) + "]";
}
return index + "\t[" + raw + "] [" + StringUtils.toString(value) + "] " + desc;
}
}

View File

@ -0,0 +1,75 @@
package com.fastbee.protocol.util;
import com.fastbee.protocol.base.annotation.Column;
import com.fastbee.protocol.base.model.ActiveModel;
import com.fastbee.protocol.base.model.ModelRegistry;
import com.fastbee.protocol.base.struc.BaseStructure;
import java.lang.reflect.Field;
import java.util.*;
/**
* 单版本加载
* @author bill
*/
public abstract class SingleVersionUtils {
private static final Map<String, ActiveModel> CACHE = new WeakHashMap<>();
public static <T> ActiveModel<T> getActiveModel(Class<T> typeClass) {
return getActiveModel(CACHE, typeClass);
}
public static <T> ActiveModel<T> getActiveModel(Map<String, ActiveModel> root, Class<T> typeClass) {
ActiveModel<T> schema = root.get(typeClass.getName());
//不支持循环引用
if (schema != null) return schema;
List<Field> fs = findFields(typeClass);
if (fs.isEmpty()) return null;
List<BaseStructure> fieldList = findFields(root, fs);
BaseStructure[] fields = fieldList.toArray(new BaseStructure[fieldList.size()]);
Arrays.sort(fields);
schema = new ActiveModel(typeClass, 0, fields);
root.put(typeClass.getName(), schema);
return schema;
}
private static List<Field> findFields(Class typeClass) {
Field[] fields = typeClass.getDeclaredFields();
List<Field> result = new ArrayList<>(fields.length);
for (Field f : fields) {
if (f.isAnnotationPresent(Column.class)) {
result.add(f);
}
}
return result;
}
private static List<BaseStructure> findFields(Map<String, ActiveModel> root, List<Field> fs) {
int size = fs.size();
List<BaseStructure> fields = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
Field f = fs.get(i);
Column column = f.getDeclaredAnnotation(Column.class);
if (column != null) {
f.setAccessible(true);
fillField(root, fields, column, f, i);
}
}
return fields;
}
private static void fillField(Map<String, ActiveModel> root, List<BaseStructure> fields, Column column, Field f, int position) {
BaseStructure BaseStructure = ModelRegistry.get(column, f);
if (BaseStructure != null) {
fields.add(BaseStructure.init(column, f, position));
} else {
ActiveModel schema = getActiveModel(root, ClassUtils.getGenericType(f));
BaseStructure = ModelRegistry.get(column, f, schema);
fields.add(BaseStructure.init(column, f, position));
}
}
}

View File

@ -0,0 +1,144 @@
package com.fastbee.protocol.util;
import java.beans.Transient;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.WeakHashMap;
import java.util.function.BiConsumer;
/**
* @author bill
*/
public class ToStringBuilder {
private static Cache<String, Builder[]> CACHE = new Cache<>(new WeakHashMap<>());
public static String toString(Object object) {
return toString(null, object, true, (String[]) null);
}
public static String toString(Object object, boolean superclass, String... ignores) {
return toString(null, object, superclass, ignores);
}
public static String toString(StringBuilder sb, Object object, boolean superclass, String... ignores) {
Class<?> typeClass = object.getClass();
Builder[] builders = getBuilders(typeClass, ignores);
if (sb == null)
sb = new StringBuilder(builders.length * 10);
String name = typeClass.getName();
sb.append(name, name.lastIndexOf('.') + 1, name.length());
sb.append('{');
try {
if (superclass) {
for (Builder builder : builders)
builder.append(sb, object);
} else {
for (Builder builder : builders)
if (!builder.superclass)
builder.append(sb, object);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
sb.setCharAt(sb.length() - 1, '}');
return sb.toString();
}
private static Builder[] getBuilders(Class<?> typeClass, String... ignores) {
return CACHE.get(typeClass.getName(), () -> {
Method[] methods = typeClass.getMethods();
ArrayList<Builder> result = new ArrayList<>(methods.length);
for (Method method : methods) {
String mName = method.getName();
String name = getName(mName);
if ((mName.startsWith("get") || mName.startsWith("is")) &&
!"class".equals(name) &&
!contains(ignores, name) &&
method.getParameterCount() == 0 && !method.isAnnotationPresent(Transient.class))
result.add(new Builder(name, method, !typeClass.equals(method.getDeclaringClass())));
}
Builder[] temp = new Builder[result.size()];
result.toArray(temp);
Arrays.sort(temp);
return temp;
});
}
private static boolean contains(Object[] array, Object obj) {
if (array == null || array.length == 0 || obj == null)
return false;
for (Object t : array) {
if (obj.equals(t))
return true;
}
return false;
}
private static String getName(String methodName) {
char[] name = methodName.toCharArray();
if (name[0] == 'g') {
name[3] += 32;
return new String(name, 3, name.length - 3);
} else {
name[2] += 32;
return new String(name, 2, name.length - 2);
}
}
private static class Builder implements Comparable<Builder> {
private static final BiConsumer<StringBuilder, Object> APPEND_OBJ = StringBuilder::append;
private static final BiConsumer<StringBuilder, Object> APPEND_ARRAY = (sb, array) -> {
sb.append('[');
int length = Array.getLength(array);
boolean tooLong = length > 140;
length = tooLong ? 140 : length;
for (int i = 0; i < length; i++)
sb.append(Array.get(array, i)).append(',');
if (tooLong)
sb.append("......");
sb.setCharAt(sb.length() - 1, ']');
};
public final String name;
public final boolean superclass;
private final Method method;
private final BiConsumer<StringBuilder, Object> append;
public void append(StringBuilder sb, Object obj) throws Exception {
Object value = method.invoke(obj);
if (value != null) {
sb.append(name).append('=');
append.accept(sb, value);
sb.append(',');
}
}
public Builder(String name, Method method, boolean superclass) {
this.name = name;
this.method = method;
this.superclass = superclass;
if (method.getReturnType().isArray()) {
append = APPEND_ARRAY;
} else {
append = APPEND_OBJ;
}
}
@Override
public int compareTo(Builder that) {
Class<?> thatType = that.method.getReturnType();
if (Iterable.class.isAssignableFrom(thatType) || thatType.isArray())
return -1;
Class<?> thisType = this.method.getReturnType();
if (Iterable.class.isAssignableFrom(thisType) || thisType.isArray())
return 1;
return 0;
}
}
}