diff --git a/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolNote.java b/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolNote.java index 34847b09..aff1ec02 100644 --- a/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolNote.java +++ b/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolNote.java @@ -82,6 +82,9 @@ public abstract class GenerateProtocolNote { private static String formatNote(CodeLanguage language, String note) { switch (language) { case Cpp: + case Java: + case Kotlin: + case Scala: case Golang: case JavaScript: case EcmaScript: diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java b/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java index d10a962d..2994b253 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java @@ -17,6 +17,7 @@ import com.zfoo.protocol.serializer.csharp.CodeGenerateCsharp; import com.zfoo.protocol.serializer.ecmascript.CodeGenerateEcmaScript; import com.zfoo.protocol.serializer.gdscript.CodeGenerateGdScript; import com.zfoo.protocol.serializer.golang.CodeGenerateGolang; +import com.zfoo.protocol.serializer.java.CodeGenerateJava; import com.zfoo.protocol.serializer.javascript.CodeGenerateJavaScript; import com.zfoo.protocol.serializer.lua.CodeGenerateLua; import com.zfoo.protocol.serializer.python.CodeGeneratePython; @@ -32,23 +33,29 @@ public enum CodeLanguage { */ Enhance(1, null), - Cpp(1 << 1, CodeGenerateCpp.class), + Java(1<<1, CodeGenerateJava.class), - Golang(1 << 2, CodeGenerateGolang.class), + Kotlin(1<<2, null), - JavaScript(1 << 3, CodeGenerateJavaScript.class), + Scala(1<<3, null), - EcmaScript(1 << 4, CodeGenerateEcmaScript.class), + Cpp(1 << 7, CodeGenerateCpp.class), - TypeScript(1 << 5, CodeGenerateTypeScript.class), + Golang(1 << 9, CodeGenerateGolang.class), - Lua(1 << 10, CodeGenerateLua.class), + JavaScript(1 << 10, CodeGenerateJavaScript.class), - CSharp(1 << 11, CodeGenerateCsharp.class), + EcmaScript(1 << 11, CodeGenerateEcmaScript.class), - GdScript(1 << 12, CodeGenerateGdScript.class), + TypeScript(1 << 12, CodeGenerateTypeScript.class), - Python(1 << 13, CodeGeneratePython.class), + Lua(1 << 15, CodeGenerateLua.class), + + CSharp(1 << 18, CodeGenerateCsharp.class), + + GdScript(1 << 20, CodeGenerateGdScript.class), + + Python(1 << 22, CodeGeneratePython.class), Protobuf(1 << 30, null); diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/CodeTemplatePlaceholder.java b/protocol/src/main/java/com/zfoo/protocol/serializer/CodeTemplatePlaceholder.java index 20308f91..5a25f40f 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/CodeTemplatePlaceholder.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/CodeTemplatePlaceholder.java @@ -12,6 +12,7 @@ package com.zfoo.protocol.serializer; +import com.zfoo.protocol.exception.RunException; import com.zfoo.protocol.util.FileUtils; import com.zfoo.protocol.util.StringUtils; @@ -73,6 +74,9 @@ public enum CodeTemplatePlaceholder { // calculate the tab length var startSpace = StringUtils.substringBeforeFirst(line, startPlaceholder.placeholder); var startPlaceholderValue = placeholderMap.get(startPlaceholder); + if (startPlaceholderValue == null) { + throw new RunException("placeholder:[{}] not exist, and add [{}] to your placeholderMap", startPlaceholder, startPlaceholder); + } var startPlaceholderValueLines = Arrays.stream(startPlaceholderValue.split(FileUtils.LS_REGEX)).map(it -> startSpace + it).toList(); // add tab length to start placeholder @@ -83,7 +87,11 @@ public enum CodeTemplatePlaceholder { for (var codeTemplatePlaceholder : CodeTemplatePlaceholder.values()) { if (formatLine.contains(codeTemplatePlaceholder.placeholder)) { - formatLine = formatLine.replace(codeTemplatePlaceholder.placeholder, placeholderMap.get(codeTemplatePlaceholder)); + var placeholder = placeholderMap.get(codeTemplatePlaceholder); + if (placeholder == null) { + throw new RunException("placeholder:[{}] not exist, and add [{}] to your placeholderMap", placeholder, placeholder); + } + formatLine = formatLine.replace(codeTemplatePlaceholder.placeholder, placeholder); } } diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/java/CodeGenerateJava.java b/protocol/src/main/java/com/zfoo/protocol/serializer/java/CodeGenerateJava.java new file mode 100644 index 00000000..fd248280 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/java/CodeGenerateJava.java @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.java; + +import com.zfoo.protocol.anno.Compatible; +import com.zfoo.protocol.generate.GenerateOperation; +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.generate.GenerateProtocolNote; +import com.zfoo.protocol.generate.GenerateProtocolPath; +import com.zfoo.protocol.registration.ProtocolAnalysis; +import com.zfoo.protocol.registration.ProtocolRegistration; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.serializer.CodeLanguage; +import com.zfoo.protocol.serializer.CodeTemplatePlaceholder; +import com.zfoo.protocol.serializer.ICodeGenerate; +import com.zfoo.protocol.serializer.enhance.EnhanceObjectProtocolSerializer; +import com.zfoo.protocol.serializer.reflect.*; +import com.zfoo.protocol.util.ClassUtils; +import com.zfoo.protocol.util.FileUtils; +import com.zfoo.protocol.util.ReflectionUtils; +import com.zfoo.protocol.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.zfoo.protocol.util.FileUtils.LS; +import static com.zfoo.protocol.util.StringUtils.TAB; + + +/** + * @author godotg + */ +public class CodeGenerateJava implements ICodeGenerate { + private static final Logger logger = LoggerFactory.getLogger(CodeGenerateJava.class); + + // custom configuration + public static String protocolOutputRootPath = "zfoojava"; + private static String protocolOutputPath = StringUtils.EMPTY; + public static String protocolPackage = "com.zfoo.java"; + + private static final Map javaSerializerMap = new HashMap<>(); + + public static IJavaSerializer javaSerializer(ISerializer serializer) { + return javaSerializerMap.get(serializer); + } + + @Override + public void init(GenerateOperation generateOperation) { + protocolOutputPath = FileUtils.joinPath(generateOperation.getProtocolPath(), protocolOutputRootPath); + FileUtils.deleteFile(new File(protocolOutputPath)); + + javaSerializerMap.put(BooleanSerializer.INSTANCE, new JavaBooleanSerializer()); + javaSerializerMap.put(ByteSerializer.INSTANCE, new JavaByteSerializer()); + javaSerializerMap.put(ShortSerializer.INSTANCE, new JavaShortSerializer()); + javaSerializerMap.put(IntSerializer.INSTANCE, new JavaIntSerializer()); + javaSerializerMap.put(LongSerializer.INSTANCE, new JavaLongSerializer()); + javaSerializerMap.put(FloatSerializer.INSTANCE, new JavaFloatSerializer()); + javaSerializerMap.put(DoubleSerializer.INSTANCE, new JavaDoubleSerializer()); + javaSerializerMap.put(StringSerializer.INSTANCE, new JavaStringSerializer()); + javaSerializerMap.put(ArraySerializer.INSTANCE, new JavaArraySerializer()); + javaSerializerMap.put(ListSerializer.INSTANCE, new JavaListSerializer()); + javaSerializerMap.put(SetSerializer.INSTANCE, new JavaSetSerializer()); + javaSerializerMap.put(MapSerializer.INSTANCE, new JavaMapSerializer()); + javaSerializerMap.put(ObjectProtocolSerializer.INSTANCE, new JavaObjectProtocolSerializer()); + } + + @Override + public void mergerProtocol(List registrations) throws IOException { + createTemplateFile(); + var protocol_root_path = StringUtils.format("package {};", protocolPackage); + + var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("java/ProtocolManagerTemplate.java"); + var protocol_manager_registrations = new StringBuilder(); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_manager_registrations.append(StringUtils.format("protocols[{}] = Protocols.registration{};", protocol_id, protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("protocolIdMap.put(Protocols.{}.class, (short){});", protocol_name, protocol_id)).append(LS); + } + + var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_root_path, protocol_root_path + , CodeTemplatePlaceholder.protocol_imports, StringUtils.EMPTY + , CodeTemplatePlaceholder.protocol_manager_registrations, protocol_manager_registrations.toString()); + var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); + var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputRootPath, "ProtocolManager.java")); + FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); + logger.info("Generated Java protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); + + var protocol_class = new StringBuilder(); + var protocol_registration = new StringBuilder(); + for (var registration : GenerateProtocolFile.subProtocolFirst(registrations)) { + var protocol_id = registration.protocolId(); + // protocol + protocol_class.append(protocol_class(registration)).append(LS); + // registration + protocol_registration.append(protocol_registration(registration)).append(LS); + } + var protocolTemplate = ClassUtils.getFileFromClassPathToString("java/ProtocolsTemplate.java"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_root_path, protocol_root_path + , CodeTemplatePlaceholder.protocol_imports, StringUtils.EMPTY + , CodeTemplatePlaceholder.protocol_class, protocol_class.toString().replace("public class", "public static class") + , CodeTemplatePlaceholder.protocol_registration, protocol_registration.toString() + )); + var outputPath = StringUtils.format("{}/Protocols.java", protocolOutputPath); + var file = new File(outputPath); + FileUtils.writeStringToFile(file, formatProtocolTemplate, true); + logger.info("Generated Java protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + } + + @Override + public void foldProtocol(List registrations) throws IOException { + createTemplateFile(); + + var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("java/ProtocolManagerTemplate.java"); + var protocol_manager_registrations = new StringBuilder(); + var protocol_imports = new StringBuilder(); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_imports.append(StringUtils.format("import {}.{}.{};", protocolPackage, GenerateProtocolPath.protocolPathPeriod(protocol_id), protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("protocols[{}] = {}.registration{};", protocol_id, protocol_name, protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("protocolIdMap.put({}.class, (short){});", protocol_name, protocol_id)).append(LS); + } + + var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_root_path, StringUtils.format("package {};", protocolPackage) + , CodeTemplatePlaceholder.protocol_imports, protocol_imports.toString() + , CodeTemplatePlaceholder.protocol_manager_registrations, protocol_manager_registrations.toString()); + var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); + var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputRootPath, "ProtocolManager.java")); + FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); + logger.info("Generated Java protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); + + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + var protocolTemplate = ClassUtils.getFileFromClassPathToString("java/ProtocolTemplate.java"); + var protocol_root_path = StringUtils.format("package {}.{};", protocolPackage, GenerateProtocolPath.protocolPathPeriod(protocol_id)); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_root_path, protocol_root_path + , CodeTemplatePlaceholder.protocol_imports, protocol_imports_fold(registration) + , CodeTemplatePlaceholder.protocol_note, GenerateProtocolNote.protocol_note(protocol_id, CodeLanguage.Java) + , CodeTemplatePlaceholder.protocol_name, protocol_name + , CodeTemplatePlaceholder.protocol_field_definition, protocol_field_definition(registration) + , CodeTemplatePlaceholder.protocol_registration, protocol_registration(registration) + )); + var outputPath = StringUtils.format("{}/{}/{}.java", protocolOutputPath, GenerateProtocolPath.protocolPathPeriod(protocol_id), protocol_name); + var file = new File(outputPath); + FileUtils.writeStringToFile(file, formatProtocolTemplate, true); + logger.info("Generated Java protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + } + } + + @Override + public void defaultProtocol(List registrations) throws IOException { + createTemplateFile(); + var protocol_root_path = StringUtils.format("package {};", protocolPackage); + + var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("java/ProtocolManagerTemplate.java"); + var protocol_manager_registrations = new StringBuilder(); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_manager_registrations.append(StringUtils.format("protocols[{}] = {}.registration{};", protocol_id, protocol_name, protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("protocolIdMap.put({}.class, (short){});", protocol_name, protocol_id)).append(LS); + } + + var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_root_path, protocol_root_path + , CodeTemplatePlaceholder.protocol_imports, StringUtils.EMPTY + , CodeTemplatePlaceholder.protocol_manager_registrations, protocol_manager_registrations.toString()); + var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); + var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputRootPath, "ProtocolManager.java")); + FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); + logger.info("Generated Java protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); + + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + var protocolTemplate = ClassUtils.getFileFromClassPathToString("java/ProtocolTemplate.java"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_root_path, protocol_root_path + , CodeTemplatePlaceholder.protocol_imports, StringUtils.EMPTY + , CodeTemplatePlaceholder.protocol_note, GenerateProtocolNote.protocol_note(protocol_id, CodeLanguage.Java) + , CodeTemplatePlaceholder.protocol_name, protocol_name + , CodeTemplatePlaceholder.protocol_field_definition, protocol_field_definition(registration) + , CodeTemplatePlaceholder.protocol_registration, protocol_registration(registration) + )); + var outputPath = StringUtils.format("{}/{}.java", protocolOutputPath, protocol_name); + var file = new File(outputPath); + FileUtils.writeStringToFile(file, formatProtocolTemplate, true); + logger.info("Generated Java protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + } + } + + private void createTemplateFile() { + var rootPackage = StringUtils.format("package {};", protocolPackage); + var list = List.of("java/IProtocolRegistration.java" + , "java/ByteBuffer.java"); + for (var fileName : list) { + // IProtocolRegistration + var template = ClassUtils.getFileFromClassPathToString(fileName); + var formatTemplate = CodeTemplatePlaceholder.formatTemplate(template, Map.of( + CodeTemplatePlaceholder.protocol_root_path, rootPackage + , CodeTemplatePlaceholder.protocol_imports, StringUtils.EMPTY + )); + var createFile = new File(StringUtils.format("{}/{}", protocolOutputPath, StringUtils.substringAfterFirst(fileName, "java/"))); + FileUtils.writeStringToFile(createFile, formatTemplate, false); + } + } + + private String protocol_class(ProtocolRegistration registration) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + var protocolTemplate = ClassUtils.getFileFromClassPathToString("java/ProtocolClassTemplate.java"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_note, GenerateProtocolNote.protocol_note(protocol_id, CodeLanguage.Java) + , CodeTemplatePlaceholder.protocol_name, protocol_name + , CodeTemplatePlaceholder.protocol_id, String.valueOf(protocol_id) + , CodeTemplatePlaceholder.protocol_field_definition, protocol_field_definition(registration) + , CodeTemplatePlaceholder.protocol_registration, protocol_registration(registration) + )); + return formatProtocolTemplate; + } + + private String protocol_registration(ProtocolRegistration registration) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + var protocolTemplate = ClassUtils.getFileFromClassPathToString("java/ProtocolRegistrationTemplate.java"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_name, protocol_name + , CodeTemplatePlaceholder.protocol_id, String.valueOf(protocol_id) + , CodeTemplatePlaceholder.protocol_write_serialization, protocol_write_serialization(registration) + , CodeTemplatePlaceholder.protocol_read_deserialization, protocol_read_deserialization(registration) + )); + return formatProtocolTemplate; + } + + + private String protocol_imports_fold(ProtocolRegistration registration) { + var protocolId = registration.getId(); + var subProtocols = ProtocolAnalysis.getAllSubProtocolIds(protocolId); + var javaBuilder = new StringBuilder(); + for (var subProtocolId : subProtocols) { + var protocolName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(subProtocolId); + var subProtocolPath = StringUtils.format("import {}.{}.{};", protocolPackage, GenerateProtocolPath.protocolPathPeriod(subProtocolId), protocolName); + javaBuilder.append(subProtocolPath).append(LS); + } + javaBuilder.append(StringUtils.format("import {}.IProtocolRegistration;", protocolPackage)).append(LS); + javaBuilder.append(StringUtils.format("import {}.ByteBuffer;", protocolPackage)).append(LS); + return javaBuilder.toString(); + } + + private String protocol_field_definition(ProtocolRegistration registration) { + var protocolId = registration.getId(); + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var javaBuilder = new StringBuilder(); + var sequencedFields = ReflectionUtils.notStaticAndTransientFields(registration.getConstructor().getDeclaringClass()); + for (int i = 0; i < sequencedFields.size(); i++) { + var field = sequencedFields.get(i); + IFieldRegistration fieldRegistration = fieldRegistrations[GenerateProtocolFile.indexOf(fields, field)]; + var fieldName = field.getName(); + var propertyType = toJavaClassName(field.getGenericType().getTypeName()); + var propertyFullName = StringUtils.format("public {} {};", propertyType, fieldName); + // 生成注释 + var fieldNotes = GenerateProtocolNote.fieldNotes(protocolId, fieldName, CodeLanguage.Java); + for (var fieldNote : fieldNotes) { + javaBuilder.append(fieldNote).append(LS); + } + javaBuilder.append(propertyFullName).append(LS); + } + return javaBuilder.toString(); + } + + + private String protocol_write_serialization(ProtocolRegistration registration) { + GenerateProtocolFile.localVariableId = 0; + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var javaBuilder = new StringBuilder(); + if (registration.isCompatible()) { + javaBuilder.append("int beforeWriteIndex = buffer.writeOffset();").append(LS); + javaBuilder.append(StringUtils.format("buffer.writeInt({});", registration.getPredictionLength())).append(LS); + } else { + javaBuilder.append("buffer.writeInt(-1);").append(LS); + } + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + var fieldRegistration = fieldRegistrations[i]; + javaSerializer(fieldRegistration.serializer()).writeObject(javaBuilder, "message." + field.getName(), 0, field, fieldRegistration); + } + if (registration.isCompatible()) { + javaBuilder.append(StringUtils.format("buffer.adjustPadding({}, beforeWriteIndex);", registration.getPredictionLength())).append(LS); + } + return javaBuilder.toString(); + } + + + private String protocol_read_deserialization(ProtocolRegistration registration) { + GenerateProtocolFile.localVariableId = 0; + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var javaBuilder = new StringBuilder(); + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + var fieldRegistration = fieldRegistrations[i]; + + if (field.isAnnotationPresent(Compatible.class)) { + javaBuilder.append("if (buffer.compatibleRead(beforeReadIndex, length)) {").append(LS); + var compatibleReadObject = javaSerializer(fieldRegistration.serializer()).readObject(javaBuilder, 1, field, fieldRegistration); + javaBuilder.append(TAB).append(StringUtils.format("packet.{} = {};", field.getName(), compatibleReadObject)).append(LS); + javaBuilder.append("}").append(LS); + continue; + } + var readObject = javaSerializer(fieldRegistration.serializer()).readObject(javaBuilder, 0, field, fieldRegistration); + javaBuilder.append(StringUtils.format("packet.{} = {};", field.getName(), readObject)).append(LS); + } + return javaBuilder.toString(); + } + + public static String toJavaClassName(String typeName) { + typeName = typeName.replaceAll("java.util.|java.lang.", StringUtils.EMPTY); + typeName = typeName.replaceAll("[a-zA-Z0-9_.]*\\.", StringUtils.EMPTY); + return typeName; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/java/IJavaSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/java/IJavaSerializer.java new file mode 100644 index 00000000..35774a70 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/java/IJavaSerializer.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.java; + +import com.zfoo.protocol.registration.field.IFieldRegistration; + +import java.lang.reflect.Field; + +/** + * @author godotg + */ +public interface IJavaSerializer { + + void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration); + + String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration); + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaArraySerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaArraySerializer.java new file mode 100644 index 00000000..26c18706 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaArraySerializer.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.java; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.registration.field.ArrayField; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.serializer.CodeLanguage; +import com.zfoo.protocol.serializer.CutDownArraySerializer; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class JavaArraySerializer implements IJavaSerializer { + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + if (CutDownArraySerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.Java)) { + return; + } + + ArrayField arrayField = (ArrayField) fieldRegistration; + + builder.append(StringUtils.format("if (({} == null) || ({}.length == 0)) {", objectStr, objectStr)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0);").append(LS); + GenerateProtocolFile.addTab(builder, deep); + + builder.append("} else {").append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.length);", objectStr)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + String length = "length" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("int {} = {}.length;", length, objectStr)).append(LS); + + String i = "i" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for (int {} = 0; {} < {}; {}++) {", i, i, length, i)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 2); + String element = "element" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("{} {} = {}[{}];", CodeGenerateJava.toJavaClassName(arrayField.getType().getSimpleName()), element, objectStr, i)).append(LS); + + CodeGenerateJava.javaSerializer(arrayField.getArrayElementRegistration().serializer()) + .writeObject(builder, element, deep + 2, field, arrayField.getArrayElementRegistration()); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + var cutDown = CutDownArraySerializer.getInstance().readObject(builder, field, fieldRegistration, CodeLanguage.Java); + if (cutDown != null) { + return cutDown; + } + + + var arrayField = (ArrayField) fieldRegistration; + var result = "result" + GenerateProtocolFile.localVariableId++; + + var typeName = CodeGenerateJava.toJavaClassName(arrayField.getType().getSimpleName()); + + var i = "index" + GenerateProtocolFile.localVariableId++; + var size = "size" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("int {} = buffer.readInt();", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("{}[] {} = new {}[{}];", typeName, result, typeName, size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("if ({} > 0) {", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for (int {} = 0; {} < {}; {}++) {", i, i, size, i)).append(LS); + var readObject = CodeGenerateJava.javaSerializer(arrayField.getArrayElementRegistration().serializer()) + .readObject(builder, deep + 2, field, arrayField.getArrayElementRegistration()); + GenerateProtocolFile.addTab(builder, deep + 2); + builder.append(StringUtils.format("{}[{}] = {};", result, i, readObject)); + builder.append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + + + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaBooleanSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaBooleanSerializer.java new file mode 100644 index 00000000..a6d776cf --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaBooleanSerializer.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.java; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class JavaBooleanSerializer implements IJavaSerializer { + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeBool({});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("boolean {} = buffer.readBool();", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaByteSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaByteSerializer.java new file mode 100644 index 00000000..18c19cc0 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaByteSerializer.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.java; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class JavaByteSerializer implements IJavaSerializer { + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeByte({});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("byte {} = buffer.readByte();", result)).append(LS); + return result; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaDoubleSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaDoubleSerializer.java new file mode 100644 index 00000000..6c597968 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaDoubleSerializer.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.java; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class JavaDoubleSerializer implements IJavaSerializer { + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeDouble({});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("double {} = buffer.readDouble();", result)).append(LS); + return result; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaFloatSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaFloatSerializer.java new file mode 100644 index 00000000..27141b8d --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaFloatSerializer.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.java; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class JavaFloatSerializer implements IJavaSerializer { + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeFloat({});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("float {} = buffer.readFloat();", result)).append(LS); + return result; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaIntSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaIntSerializer.java new file mode 100644 index 00000000..e5e6edc7 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaIntSerializer.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.java; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class JavaIntSerializer implements IJavaSerializer { + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeInt({});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("int {} = buffer.readInt();", result)).append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaListSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaListSerializer.java new file mode 100644 index 00000000..fc97b81c --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaListSerializer.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.java; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.registration.field.ListField; +import com.zfoo.protocol.serializer.CodeLanguage; +import com.zfoo.protocol.serializer.CutDownListSerializer; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class JavaListSerializer implements IJavaSerializer { + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + if (CutDownListSerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.Java)) { + return; + } + + ListField listField = (ListField) fieldRegistration; + builder.append(StringUtils.format("if ({} == null) {", objectStr)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0);").append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("else {").append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.size());", objectStr)).append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + String length = "length" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("int {} = {}.size();", length, objectStr)).append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + String element = "element" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("for (var {} : {}) {", element, objectStr)).append(LS); + + CodeGenerateJava.javaSerializer(listField.getListElementRegistration().serializer()) + .writeObject(builder, element, deep + 2, field, listField.getListElementRegistration()); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + var cutDown = CutDownListSerializer.getInstance().readObject(builder, field, fieldRegistration, CodeLanguage.Java); + if (cutDown != null) { + return cutDown; + } + + var listField = (ListField) fieldRegistration; + var result = "result" + GenerateProtocolFile.localVariableId++; + + var typeName = CodeGenerateJava.toJavaClassName(listField.getType().toString()); + + var i = "index" + GenerateProtocolFile.localVariableId++; + var size = "size" + GenerateProtocolFile.localVariableId++; + + builder.append(StringUtils.format("int {} = buffer.readInt();", size)).append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("var {} = new Array{}({});", result, typeName, size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("if ({} > 0) {", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for (int {} = 0; {} < {}; {}++) {", i, i, size, i)).append(LS); + var readObject = CodeGenerateJava.javaSerializer(listField.getListElementRegistration().serializer()) + .readObject(builder, deep + 2, field, listField.getListElementRegistration()); + GenerateProtocolFile.addTab(builder, deep + 2); + builder.append(StringUtils.format("{}.add({});", result, readObject)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + + + return result; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaLongSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaLongSerializer.java new file mode 100644 index 00000000..959bf2c7 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaLongSerializer.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.java; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class JavaLongSerializer implements IJavaSerializer { + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeLong({});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("long {} = buffer.readLong();", result)).append(LS); + return result; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaMapSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaMapSerializer.java new file mode 100644 index 00000000..76f19671 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaMapSerializer.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.java; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.registration.field.MapField; +import com.zfoo.protocol.serializer.CodeLanguage; +import com.zfoo.protocol.serializer.CutDownMapSerializer; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class JavaMapSerializer implements IJavaSerializer { + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + if (CutDownMapSerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.Java)) { + return; + } + + MapField mapField = (MapField) fieldRegistration; + + builder.append(StringUtils.format("if ({} == null) {", objectStr, objectStr)).append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0);").append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append("} else {").append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.size());", objectStr)).append(LS); + + + String i = "i" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for (var {} : {}.entrySet()) {", i, objectStr)).append(LS); + + GenerateProtocolFile.addTab(builder, deep + 2); + String key = "keyElement" + GenerateProtocolFile.localVariableId++; + String value = "valueElement" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("var {} = {}.getKey();", key, i)).append(LS); + + GenerateProtocolFile.addTab(builder, deep + 2); + builder.append(StringUtils.format("var {} = {}.getValue();", value, i)).append(LS); + + CodeGenerateJava.javaSerializer(mapField.getMapKeyRegistration().serializer()) + .writeObject(builder, key, deep + 2, field, mapField.getMapKeyRegistration()); + CodeGenerateJava.javaSerializer(mapField.getMapValueRegistration().serializer()) + .writeObject(builder, value, deep + 2, field, mapField.getMapValueRegistration()); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + } + + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + var cutDown = CutDownMapSerializer.getInstance().readObject(builder, field, fieldRegistration, CodeLanguage.Java); + if (cutDown != null) { + return cutDown; + } + + MapField mapField = (MapField) fieldRegistration; + String result = "result" + GenerateProtocolFile.localVariableId++; + + var typeName = CodeGenerateJava.toJavaClassName(mapField.getType().toString()); + + String size = "size" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("int {} = buffer.readInt();", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("var {} = new Hash{}({});", result, typeName, size)).append(LS); + + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("if ({} > 0) {", size)).append(LS); + + String i = "index" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for (var {} = 0; {} < {}; {}++) {", i, i, size, i)).append(LS); + + String keyObject = CodeGenerateJava.javaSerializer(mapField.getMapKeyRegistration().serializer()) + .readObject(builder, deep + 2, field, mapField.getMapKeyRegistration()); + + + String valueObject = CodeGenerateJava.javaSerializer(mapField.getMapValueRegistration().serializer()) + .readObject(builder, deep + 2, field, mapField.getMapValueRegistration()); + GenerateProtocolFile.addTab(builder, deep + 2); + + builder.append(StringUtils.format("{}.put({}, {});", result, keyObject, valueObject)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + return result; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaObjectProtocolSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaObjectProtocolSerializer.java new file mode 100644 index 00000000..11e1b0db --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaObjectProtocolSerializer.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.java; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.registration.field.ObjectProtocolField; +import com.zfoo.protocol.serializer.enhance.EnhanceObjectProtocolSerializer; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + + +/** + * @author godotg + */ +public class JavaObjectProtocolSerializer implements IJavaSerializer { + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + ObjectProtocolField objectProtocolField = (ObjectProtocolField) fieldRegistration; + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writePacket({}, (short){});", objectStr, objectProtocolField.getProtocolId())) + .append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + ObjectProtocolField objectProtocolField = (ObjectProtocolField) fieldRegistration; + String result = "result" + GenerateProtocolFile.localVariableId++; + + var protocolSimpleName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(objectProtocolField.getProtocolId()); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("{} {} = ({}) buffer.readPacket((short){});", protocolSimpleName, result, protocolSimpleName, objectProtocolField.getProtocolId())) + .append(LS); + return result; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaSetSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaSetSerializer.java new file mode 100644 index 00000000..1c59fbe0 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaSetSerializer.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.java; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.registration.field.SetField; +import com.zfoo.protocol.serializer.CodeLanguage; +import com.zfoo.protocol.serializer.CutDownSetSerializer; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class JavaSetSerializer implements IJavaSerializer { + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + if (CutDownSetSerializer.getInstance().writeObject(builder, objectStr, field, fieldRegistration, CodeLanguage.Java)) { + return; + } + + SetField setField = (SetField) fieldRegistration; + + builder.append(StringUtils.format("if ({} == null) {", objectStr)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("buffer.writeInt(0);").append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append("} else {").append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("buffer.writeInt({}.size());", objectStr)).append(LS); + + String element = "i" + GenerateProtocolFile.localVariableId++; + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for (var {} : {}) {", element, objectStr)).append(LS); + + CodeGenerateJava.javaSerializer(setField.getSetElementRegistration().serializer()) + .writeObject(builder, element, deep + 2, field, setField.getSetElementRegistration()); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + var cutDown = CutDownSetSerializer.getInstance().readObject(builder, field, fieldRegistration, CodeLanguage.Java); + if (cutDown != null) { + return cutDown; + } + + SetField setField = (SetField) fieldRegistration; + var result = "result" + GenerateProtocolFile.localVariableId++; + + var typeName = CodeGenerateJava.toJavaClassName(setField.getType().toString()); + + var i = "index" + GenerateProtocolFile.localVariableId++; + var size = "size" + GenerateProtocolFile.localVariableId++; + builder.append(StringUtils.format("int {} = buffer.readInt();", size)).append(LS); + GenerateProtocolFile.addTab(builder, deep); + // unity里不支持HashSet的初始化大小 +// builder.append("var " + result + " = new " + typeName + "(" + size + ");" + LS); + builder.append(StringUtils.format("var {} = new Hash{}();", result, typeName)).append(LS); + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("if ({} > 0) {", size)).append(LS); + + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append(StringUtils.format("for (int {} = 0; {} < {}; {}++) {", i, i, size, i)).append(LS); + + var readObject = CodeGenerateJava.javaSerializer(setField.getSetElementRegistration().serializer()) + .readObject(builder, deep + 2, field, setField.getSetElementRegistration()); + GenerateProtocolFile.addTab(builder, deep + 2); + builder.append(StringUtils.format("{}.add({});", result, readObject)).append(LS); + GenerateProtocolFile.addTab(builder, deep + 1); + builder.append("}").append(LS); + GenerateProtocolFile.addTab(builder, deep); + builder.append("}").append(LS); + + return result; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaShortSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaShortSerializer.java new file mode 100644 index 00000000..cdaa6d83 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaShortSerializer.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.java; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class JavaShortSerializer implements IJavaSerializer { + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeShort({});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("short {} = buffer.readShort();", result)).append(LS); + return result; + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaStringSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaStringSerializer.java new file mode 100644 index 00000000..acc7c6a7 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/java/JavaStringSerializer.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.protocol.serializer.java; + +import com.zfoo.protocol.generate.GenerateProtocolFile; +import com.zfoo.protocol.registration.field.IFieldRegistration; +import com.zfoo.protocol.util.StringUtils; + +import java.lang.reflect.Field; + +import static com.zfoo.protocol.util.FileUtils.LS; + +/** + * @author godotg + */ +public class JavaStringSerializer implements IJavaSerializer { + + @Override + public void writeObject(StringBuilder builder, String objectStr, int deep, Field field, IFieldRegistration fieldRegistration) { + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("buffer.writeString({});", objectStr)).append(LS); + } + + @Override + public String readObject(StringBuilder builder, int deep, Field field, IFieldRegistration fieldRegistration) { + String result = "result" + GenerateProtocolFile.localVariableId++; + + GenerateProtocolFile.addTab(builder, deep); + builder.append(StringUtils.format("String {} = buffer.readString();", result)).append(LS); + return result; + } + + +} diff --git a/protocol/src/main/resources/java/ByteBuffer.java b/protocol/src/main/resources/java/ByteBuffer.java new file mode 100644 index 00000000..a7c2d80a --- /dev/null +++ b/protocol/src/main/resources/java/ByteBuffer.java @@ -0,0 +1,1266 @@ +${protocol_root_path} + +import java.nio.charset.Charset; +import java.util.*; + +public class ByteBuffer { + private static final int INIT_SIZE = 128; + private static final int MAX_SIZE = 655537; + + private byte[] buffer = new byte[INIT_SIZE]; + private int writeOffset = 0; + private int readOffset = 0; + + + public void adjustPadding(int predictionLength, int beforewriteIndex) { + // 因为写入的是可变长的int,如果预留的位置过多,则清除多余的位置 + var currentwriteIndex = writeOffset; + var predictionCount = writeIntCount(predictionLength); + var length = currentwriteIndex - beforewriteIndex - predictionCount; + var lengthCount = writeIntCount(length); + var padding = lengthCount - predictionCount; + if (padding == 0) { + writeOffset = beforewriteIndex; + writeInt(length); + writeOffset = currentwriteIndex; + } else { + var bytes = new byte[length]; + System.arraycopy(buffer, currentwriteIndex - length, bytes, 0, length); + writeOffset = beforewriteIndex; + writeInt(length); + writeBytes(bytes); + } + } + + public boolean compatibleRead(int beforereadIndex, int length) { + return length != -1 && readOffset < length + beforereadIndex; + } + + // -------------------------------------------------get/set------------------------------------------------- + public int writeOffset() { + return writeOffset; + } + + public void setwriteOffset(int writeIndex) { + if (writeIndex > buffer.length) { + throw new RuntimeException("writeIndex[" + writeIndex + "] out of bounds exception: readerIndex: " + readOffset + + ", writerIndex: " + writeOffset + "(expected: 0 <= readerIndex <= writerIndex <= capacity:" + buffer.length); + } + writeOffset = writeIndex; + } + + public int readOffset() { + return readOffset; + } + + public void setReadOffset(int readIndex) { + if (readIndex > writeOffset) { + throw new RuntimeException("readIndex[" + readIndex + "] out of bounds exception: readerIndex: " + readOffset + + ", writerIndex: " + writeOffset + "(expected: 0 <= readerIndex <= writerIndex <= capacity:" + buffer.length); + } + readOffset = readIndex; + } + + public byte[] toBytes() { + var bytes = new byte[writeOffset]; + System.arraycopy(buffer, 0, bytes, 0, writeOffset); + return bytes; + } + + public boolean isReadable() { + return writeOffset > readOffset; + } + + // -------------------------------------------------write/read------------------------------------------------- + public void writeBool(boolean value) { + ensureCapacity(1); + buffer[writeOffset] = value ? (byte) 1 : (byte) 0; + writeOffset++; + } + + public boolean readBool() { + var byteValue = buffer[readOffset]; + readOffset++; + return byteValue == 1; + } + + public void writeByte(byte value) { + ensureCapacity(1); + buffer[writeOffset++] = value; + } + + public byte readByte() { + return buffer[readOffset++]; + } + + public int getCapacity() { + return buffer.length - writeOffset; + } + + public void ensureCapacity(int capacity) { + while (capacity - getCapacity() > 0) { + var newSize = buffer.length * 2; + if (newSize > MAX_SIZE) { + throw new RuntimeException("Bytebuf max size is [655537], out of memory error"); + } + + var newBytes = new byte[newSize]; + System.arraycopy(buffer, 0, newBytes, 0, buffer.length); + this.buffer = newBytes; + } + } + + public void writeBytes(byte[] bytes) { + writeBytes(bytes, bytes.length); + } + + public void writeBytes(byte[] bytes, int length) { + ensureCapacity(length); + System.arraycopy(bytes, 0, buffer, writeOffset, length); + writeOffset += length; + } + + public byte[] readBytes(int count) { + var bytes = new byte[count]; + System.arraycopy(buffer, readOffset, bytes, 0, count); + readOffset += count; + return bytes; + } + + public void writeShort(short value) { + ensureCapacity(2); + buffer[writeOffset++] = (byte) (value >>> 8); + buffer[writeOffset++] = (byte) value; + } + + public short readShort() { + return (short) (buffer[readOffset++] << 8 | buffer[readOffset++] & 255); + } + + // *******************************************int*************************************************** + public int writeInt(int value) { + return writeVarInt((value << 1) ^ (value >> 31)); + } + + public int writeVarInt(int value) { + int a = value >>> 7; + if (a == 0) { + writeByte((byte) value); + return 1; + } + + ensureCapacity(5); + + buffer[writeOffset++] = (byte) (value | 0x80); + int b = value >>> 14; + if (b == 0) { + buffer[writeOffset++] = (byte) a; + return 2; + } + + buffer[writeOffset++] = (byte) (a | 0x80); + a = value >>> 21; + if (a == 0) { + buffer[writeOffset++] = (byte) (b); + return 3; + } + + buffer[writeOffset++] = (byte) (b | 0x80); + b = value >>> 28; + if (b == 0) { + buffer[writeOffset++] = (byte) (a); + return 4; + } + + buffer[writeOffset++] = (byte) (a | 0x80); + buffer[writeOffset++] = (byte) b; + return 5; + } + + public int readInt() { + int b = readByte(); + int value = b; + if (b < 0) { + b = readByte(); + value = value & 0x0000007F | b << 7; + if (b < 0) { + b = readByte(); + value = value & 0x00003FFF | b << 14; + if (b < 0) { + b = readByte(); + value = value & 0x001FFFFF | b << 21; + if (b < 0) { + value = value & 0x0FFFFFFF | readByte() << 28; + } + } + } + } + return ((value >>> 1) ^ -(value & 1)); + } + + public int writeIntCount(int value) { + value = (value << 1) ^ (value >> 31); + + if (value >>> 7 == 0) { + return 1; + } + + if (value >>> 14 == 0) { + return 2; + } + + if (value >>> 21 == 0) { + return 3; + } + + if (value >>> 28 == 0) { + return 4; + } + + return 5; + } + + // 写入没有压缩的int + public void writeRawInt(int value) { + ensureCapacity(4); + buffer[writeOffset++] = (byte) (value >>> 24); + buffer[writeOffset++] = (byte) (value >>> 16); + buffer[writeOffset++] = (byte) (value >>> 8); + buffer[writeOffset++] = (byte) value; + } + + // 读取没有压缩的int + public int readRawInt() { + return (buffer[readOffset++] & 255) << 24 | (buffer[readOffset++] & 255) << 16 | (buffer[readOffset++] & 255) << 8 | buffer[readOffset++] & 255; + } + + // *******************************************long************************************************** + public void writeLong(long value) { + long mask = (value << 1) ^ (value >> 63); + + if (mask >>> 32 == 0) { + writeVarInt((int) mask); + return; + } + + byte[] bytes = new byte[9]; + bytes[0] = (byte) (mask | 0x80); + bytes[1] = (byte) (mask >>> 7 | 0x80); + bytes[2] = (byte) (mask >>> 14 | 0x80); + bytes[3] = (byte) (mask >>> 21 | 0x80); + + + int a = (int) (mask >>> 28); + int b = (int) (mask >>> 35); + if (b == 0) { + bytes[4] = (byte) a; + writeBytes(bytes, 5); + return; + } + + bytes[4] = (byte) (a | 0x80); + a = (int) (mask >>> 42); + if (a == 0) { + bytes[5] = (byte) b; + writeBytes(bytes, 6); + return; + } + + bytes[5] = (byte) (b | 0x80); + b = (int) (mask >>> 49); + if (b == 0) { + bytes[6] = (byte) a; + writeBytes(bytes, 7); + return; + } + + bytes[6] = (byte) (a | 0x80); + a = (int) (mask >>> 56); + if (a == 0) { + bytes[7] = (byte) b; + writeBytes(bytes, 8); + return; + } + + bytes[7] = (byte) (b | 0x80); + bytes[8] = (byte) a; + writeBytes(bytes, 9); + } + + public long readLong() { + long b = readByte(); + long value = b; + if (b < 0) { + b = readByte(); + value = value & 0x00000000_0000007FL | b << 7; + if (b < 0) { + b = readByte(); + value = value & 0x00000000_00003FFFL | b << 14; + if (b < 0) { + b = readByte(); + value = value & 0x00000000_001FFFFFL | b << 21; + if (b < 0) { + b = readByte(); + value = value & 0x00000000_0FFFFFFFL | b << 28; + if (b < 0) { + b = readByte(); + value = value & 0x00000007_FFFFFFFFL | b << 35; + if (b < 0) { + b = readByte(); + value = value & 0x000003FF_FFFFFFFFL | b << 42; + if (b < 0) { + b = readByte(); + value = value & 0x0001FFFF_FFFFFFFFL | b << 49; + if (b < 0) { + b = readByte(); + value = value & 0x00FFFFFF_FFFFFFFFL | b << 56; + } + } + } + } + } + } + } + } + return ((value >>> 1) ^ -(value & 1)); + } + + public void writeRawLong(long value) { + ensureCapacity(8); + buffer[writeOffset++] = (byte) ((int) (value >>> 56)); + buffer[writeOffset++] = (byte) ((int) (value >>> 48)); + buffer[writeOffset++] = (byte) ((int) (value >>> 40)); + buffer[writeOffset++] = (byte) ((int) (value >>> 32)); + buffer[writeOffset++] = (byte) ((int) (value >>> 24)); + buffer[writeOffset++] = (byte) ((int) (value >>> 16)); + buffer[writeOffset++] = (byte) ((int) (value >>> 8)); + buffer[writeOffset++] = (byte) ((int) value); + } + + public long readRawLong() { + return ((long) buffer[readOffset++] & 255L) << 56 | ((long) buffer[readOffset++] & 255L) << 48 | ((long) buffer[readOffset++] & 255L) << 40 | ((long) buffer[readOffset++] & 255L) << 32 | ((long) buffer[readOffset++] & 255L) << 24 | ((long) buffer[readOffset++] & 255L) << 16 | ((long) buffer[readOffset++] & 255L) << 8 | (long) buffer[readOffset++] & 255L; + } + + // *******************************************float*************************************************** + public void writeFloat(float value) { + writeRawInt(Float.floatToRawIntBits(value)); + } + + public float readFloat() { + return Float.intBitsToFloat(readRawInt()); + } + + // *******************************************double*************************************************** + public void writeDouble(double value) { + writeRawLong(Double.doubleToRawLongBits(value)); + } + + public double readDouble() { + return Double.longBitsToDouble(readRawLong()); + } + + // *******************************************String*************************************************** + public static final String DEFAULT_CHARSET_NAME = "UTF-8"; + public static final Charset DEFAULT_CHARSET = Charset.forName(DEFAULT_CHARSET_NAME); + + public void writeString(String value) { + if (value == null || value.isEmpty()) { + writeInt(0); + return; + } + var bytes = value.getBytes(DEFAULT_CHARSET); + writeInt(bytes.length); + writeBytes(bytes); + } + + public String readString() { + int length = readInt(); + if (length <= 0) { + return ""; + } + byte[] bytes = readBytes(length); + return new String(bytes, DEFAULT_CHARSET); + } + + public void writeBooleanArray(boolean[] array) { + if ((array == null) || (array.length == 0)) { + writeInt(0); + } else { + writeInt(array.length); + int length = array.length; + for (int index = 0; index < length; index++) { + writeBool(array[index]); + } + } + } + + public boolean[] readBooleanArray() { + int size = readInt(); + boolean[] array = new boolean[size]; + if (size > 0) { + for (int index = 0; index < size; index++) { + array[index] = readBool(); + } + } + return array; + } + + public void writeByteArray(byte[] array) { + if ((array == null) || (array.length == 0)) { + writeInt(0); + } else { + writeInt(array.length); + int length = array.length; + for (int index = 0; index < length; index++) { + writeByte(array[index]); + } + } + } + + public byte[] readByteArray() { + int size = readInt(); + byte[] array = new byte[size]; + if (size > 0) { + for (int index = 0; index < size; index++) { + array[index] = readByte(); + } + } + return array; + } + + public void writeShortArray(short[] array) { + if ((array == null) || (array.length == 0)) { + writeInt(0); + } else { + writeInt(array.length); + int length = array.length; + for (int index = 0; index < length; index++) { + writeShort(array[index]); + } + } + } + + public short[] readShortArray() { + int size = readInt(); + short[] array = new short[size]; + if (size > 0) { + for (int index = 0; index < size; index++) { + array[index] = readShort(); + } + } + return array; + } + + public void writeIntArray(int[] array) { + if ((array == null) || (array.length == 0)) { + writeInt(0); + } else { + writeInt(array.length); + int length = array.length; + for (int index = 0; index < length; index++) { + writeInt(array[index]); + } + } + } + + public int[] readIntArray() { + int size = readInt(); + int[] array = new int[size]; + if (size > 0) { + for (int index = 0; index < size; index++) { + array[index] = readInt(); + } + } + return array; + } + + public void writeLongArray(long[] array) { + if ((array == null) || (array.length == 0)) { + writeInt(0); + } else { + writeInt(array.length); + int length = array.length; + for (int index = 0; index < length; index++) { + writeLong(array[index]); + } + } + } + + public long[] readLongArray() { + int size = readInt(); + long[] array = new long[size]; + if (size > 0) { + for (int index = 0; index < size; index++) { + array[index] = readLong(); + } + } + return array; + } + + public void writeFloatArray(float[] array) { + if ((array == null) || (array.length == 0)) { + writeInt(0); + } else { + writeInt(array.length); + int length = array.length; + for (int index = 0; index < length; index++) { + writeFloat(array[index]); + } + } + } + + public float[] readFloatArray() { + int size = readInt(); + float[] array = new float[size]; + if (size > 0) { + for (int index = 0; index < size; index++) { + array[index] = readFloat(); + } + } + return array; + } + + public void writeDoubleArray(double[] array) { + if ((array == null) || (array.length == 0)) { + writeInt(0); + } else { + writeInt(array.length); + int length = array.length; + for (int index = 0; index < length; index++) { + writeDouble(array[index]); + } + } + } + + public double[] readDoubleArray() { + int size = readInt(); + double[] array = new double[size]; + if (size > 0) { + for (int index = 0; index < size; index++) { + array[index] = readDouble(); + } + } + return array; + } + + public void writeStringArray(String[] array) { + if ((array == null) || (array.length == 0)) { + writeInt(0); + } else { + writeInt(array.length); + int length = array.length; + for (int index = 0; index < length; index++) { + writeString(array[index]); + } + } + } + + public String[] readStringArray() { + int size = readInt(); + String[] array = new String[size]; + if (size > 0) { + for (int index = 0; index < size; index++) { + array[index] = readString(); + } + } + return array; + } + + public void writeBooleanList(List list) { + if ((list == null) || list.isEmpty()) { + writeInt(0); + } else { + writeInt(list.size()); + for (var ele : list) { + writeBool(ele); + } + } + } + + public List readBooleanList() { + int size = readInt(); + List list = new ArrayList<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + list.add(readBool()); + } + } + return list; + } + + public void writeByteList(List list) { + if ((list == null) || list.isEmpty()) { + writeInt(0); + } else { + writeInt(list.size()); + for (var ele : list) { + writeByte(ele); + } + } + } + + public List readByteList() { + int size = readInt(); + List list = new ArrayList<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + list.add(readByte()); + } + } + return list; + } + + public void writeShortList(List list) { + if ((list == null) || list.isEmpty()) { + writeInt(0); + } else { + writeInt(list.size()); + for (var ele : list) { + writeShort(ele); + } + } + } + + public List readShortList() { + int size = readInt(); + List list = new ArrayList<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + list.add(readShort()); + } + } + return list; + } + + public void writeIntList(List list) { + if ((list == null) || list.isEmpty()) { + writeInt(0); + } else { + writeInt(list.size()); + for (var ele : list) { + writeInt(ele); + } + } + } + + public List readIntList() { + int size = readInt(); + List list = new ArrayList<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + list.add(readInt()); + } + } + return list; + } + + public void writeLongList(List list) { + if ((list == null) || list.isEmpty()) { + writeInt(0); + } else { + writeInt(list.size()); + for (var ele : list) { + writeLong(ele); + } + } + } + + public List readLongList() { + int size = readInt(); + List list = new ArrayList<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + list.add(readLong()); + } + } + return list; + } + + public void writeFloatList(List list) { + if ((list == null) || list.isEmpty()) { + writeInt(0); + } else { + writeInt(list.size()); + for (var ele : list) { + writeFloat(ele); + } + } + } + + public List readFloatList() { + int size = readInt(); + List list = new ArrayList<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + list.add(readFloat()); + } + } + return list; + } + + public void writeDoubleList(List list) { + if ((list == null) || list.isEmpty()) { + writeInt(0); + } else { + writeInt(list.size()); + for (var ele : list) { + writeDouble(ele); + } + } + } + + public List readDoubleList() { + int size = readInt(); + List list = new ArrayList<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + list.add(readDouble()); + } + } + return list; + } + + public void writeStringList(List list) { + if ((list == null) || list.isEmpty()) { + writeInt(0); + } else { + writeInt(list.size()); + for (var ele : list) { + writeString(ele); + } + } + } + + public List readStringList() { + int size = readInt(); + List list = new ArrayList<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + list.add(readString()); + } + } + return list; + } + + public void writePacketList(List list, short protocolId) { + if ((list == null) || list.isEmpty()) { + writeInt(0); + } else { + IProtocolRegistration protocolRegistration = ProtocolManager.getProtocol(protocolId); + writeInt(list.size()); + for(var ele : list) { + protocolRegistration.write(this, ele); + } + } + } + + public List readPacketList(short protocolId) { + int size = readInt(); + List list = new ArrayList<>(); + if (size > 0) { + IProtocolRegistration protocolRegistration = ProtocolManager.getProtocol(protocolId); + for (int index = 0; index < size; index++) { + list.add(protocolRegistration.read(this)); + } + } + return list; + } + + public void writeBooleanSet(Set set) { + if ((set == null) || set.isEmpty()) { + writeInt(0); + } else { + writeInt(set.size()); + for (var ele : set) { + writeBool(ele); + } + } + } + + public Set readBooleanSet() { + int size = readInt(); + Set set = new HashSet<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + set.add(readBool()); + } + } + return set; + } + + public void writeShortSet(Set set) { + if ((set == null) || set.isEmpty()) { + writeInt(0); + } else { + writeInt(set.size()); + for (var ele : set) { + writeShort(ele); + } + } + } + + public Set readShortSet() { + int size = readInt(); + Set set = new HashSet<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + set.add(readShort()); + } + } + return set; + } + + public void writeIntSet(Set set) { + if ((set == null) || set.isEmpty()) { + writeInt(0); + } else { + writeInt(set.size()); + for (var ele : set) { + writeInt(ele); + } + } + } + + public Set readIntSet() { + int size = readInt(); + Set set = new HashSet<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + set.add(readInt()); + } + } + return set; + } + + public void writeLongSet(Set set) { + if ((set == null) || set.isEmpty()) { + writeInt(0); + } else { + writeInt(set.size()); + for (var ele : set) { + writeLong(ele); + } + } + } + + public Set readLongSet() { + int size = readInt(); + Set set = new HashSet<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + set.add(readLong()); + } + } + return set; + } + + public void writeFloatSet(Set set) { + if ((set == null) || set.isEmpty()) { + writeInt(0); + } else { + writeInt(set.size()); + for (var ele : set) { + writeFloat(ele); + } + } + } + + public Set readFloatSet() { + int size = readInt(); + Set set = new HashSet<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + set.add(readFloat()); + } + } + return set; + } + + public void writeDoubleSet(Set set) { + if ((set == null) || set.isEmpty()) { + writeInt(0); + } else { + writeInt(set.size()); + for (var ele : set) { + writeDouble(ele); + } + } + } + + public Set readDoubleSet() { + int size = readInt(); + Set set = new HashSet<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + set.add(readDouble()); + } + } + return set; + } + + public void writeStringSet(Set set) { + if ((set == null) || set.isEmpty()) { + writeInt(0); + } else { + writeInt(set.size()); + for (var ele : set) { + writeString(ele); + } + } + } + + public Set readStringSet() { + int size = readInt(); + Set set = new HashSet<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + set.add(readString()); + } + } + return set; + } + + public void writePacketSet(Set set, short protocolId) { + if ((set == null) || set.isEmpty()) { + writeInt(0); + } else { + IProtocolRegistration protocolRegistration = ProtocolManager.getProtocol(protocolId); + writeInt(set.size()); + for(var element : set) { + protocolRegistration.write(this, element); + } + } + } + + public Set readPacketSet(short protocolId) { + int size = readInt(); + Set set = new HashSet<>(); + if (size > 0) { + IProtocolRegistration protocolRegistration = ProtocolManager.getProtocol(protocolId); + for (int index = 0; index < size; index++) { + set.add(protocolRegistration.read(this)); + } + } + + return set; + } + + public void writeIntIntMap(Map map) { + if ((map == null) || map.isEmpty()) { + writeInt(0); + } else { + writeInt(map.size()); + for (var entry : map.entrySet()) { + writeInt(entry.getKey()); + writeInt(entry.getValue()); + } + } + } + + public Map readIntIntMap() { + int size = readInt(); + Map map = new HashMap<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + var key = readInt(); + var value = readInt(); + map.put(key, value); + } + } + return map; + } + + public void writeIntLongMap(Map map) { + if ((map == null) || map.isEmpty()) { + writeInt(0); + } else { + writeInt(map.size()); + for (var entry : map.entrySet()) { + writeInt(entry.getKey()); + writeLong(entry.getValue()); + } + } + } + + public Map readIntLongMap() { + int size = readInt(); + Map map = new HashMap<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + var key = readInt(); + var value = readLong(); + map.put(key, value); + } + } + return map; + } + + public void writeIntStringMap(Map map) { + if ((map == null) || map.isEmpty()) { + writeInt(0); + } else { + writeInt(map.size()); + for (var entry : map.entrySet()) { + writeInt(entry.getKey()); + writeString(entry.getValue()); + } + } + } + + public Map readIntStringMap() { + int size = readInt(); + Map map = new HashMap<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + var key = readInt(); + var value = readString(); + map.put(key, value); + } + } + return map; + } + + + public void writeIntPacketMap(Map map, short protocolId) { + if ((map == null) || map.isEmpty()) { + writeInt(0); + } else { + IProtocolRegistration protocolRegistration = ProtocolManager.getProtocol(protocolId); + writeInt(map.size()); + for(var element : map.entrySet()) { + writeInt(element.getKey()); + protocolRegistration.write(this, element.getValue()); + } + } + } + + public Map readIntPacketMap(short protocolId) { + int size = readInt(); + Map map = new HashMap<>(); + if (size > 0) { + IProtocolRegistration protocolRegistration = ProtocolManager.getProtocol(protocolId); + for (int index = 0; index < size; index++) { + var key = readInt(); + var value = protocolRegistration.read(this); + map.put(key, value); + } + } + return map; + } + + public void writeLongIntMap(Map map) { + if ((map == null) || map.isEmpty()) { + writeInt(0); + } else { + writeInt(map.size()); + for (var entry : map.entrySet()) { + writeLong(entry.getKey()); + writeInt(entry.getValue()); + } + } + } + + public Map readLongIntMap() { + int size = readInt(); + Map map = new HashMap<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + var key = readLong(); + var value = readInt(); + map.put(key, value); + } + } + return map; + } + + public void writeLongLongMap(Map map) { + if ((map == null) || map.isEmpty()) { + writeInt(0); + } else { + writeInt(map.size()); + for (var entry : map.entrySet()) { + writeLong(entry.getKey()); + writeLong(entry.getValue()); + } + } + } + + public Map readLongLongMap() { + int size = readInt(); + Map map = new HashMap<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + var key = readLong(); + var value = readLong(); + map.put(key, value); + } + } + return map; + } + + public void writeLongStringMap(Map map) { + if ((map == null) || map.isEmpty()) { + writeInt(0); + } else { + writeInt(map.size()); + for (var entry : map.entrySet()) { + writeLong(entry.getKey()); + writeString(entry.getValue()); + } + } + } + + public Map readLongStringMap() { + int size = readInt(); + Map map = new HashMap<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + var key = readLong(); + var value = readString(); + map.put(key, value); + } + } + return map; + } + + public void writeLongPacketMap(Map map, short protocolId) { + if ((map == null) || map.isEmpty()) { + writeInt(0); + } else { + IProtocolRegistration protocolRegistration = ProtocolManager.getProtocol(protocolId); + writeInt(map.size()); + for(var element : map.entrySet()) { + writeLong(element.getKey()); + protocolRegistration.write(this, element.getValue()); + } + } + } + + public Map readLongPacketMap(short protocolId) { + int size = readInt(); + Map map = new HashMap<>(); + if (size > 0) { + IProtocolRegistration protocolRegistration = ProtocolManager.getProtocol(protocolId); + for (int index = 0; index < size; index++) { + var key = readLong(); + var value = protocolRegistration.read(this); + map.put(key, value); + } + } + return map; + } + + public void writeStringIntMap(Map map) { + if ((map == null) || map.isEmpty()) { + writeInt(0); + } else { + writeInt(map.size()); + for (var entry : map.entrySet()) { + writeString(entry.getKey()); + writeInt(entry.getValue()); + } + } + } + + public Map readStringIntMap() { + int size = readInt(); + Map map = new HashMap<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + var key = readString(); + var value = readInt(); + map.put(key, value); + } + } + return map; + } + + public void writeStringLongMap(Map map) { + if ((map == null) || map.isEmpty()) { + writeInt(0); + } else { + writeInt(map.size()); + for (var entry : map.entrySet()) { + writeString(entry.getKey()); + writeLong(entry.getValue()); + } + } + } + + public Map readStringLongMap() { + int size = readInt(); + Map map = new HashMap<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + var key = readString(); + var value = readLong(); + map.put(key, value); + } + } + return map; + } + + public void writeStringStringMap(Map map) { + if ((map == null) || map.isEmpty()) { + writeInt(0); + } else { + writeInt(map.size()); + for (var entry : map.entrySet()) { + writeString(entry.getKey()); + writeString(entry.getValue()); + } + } + } + + public Map readStringStringMap() { + int size = readInt(); + Map map = new HashMap<>(); + if (size > 0) { + for (int index = 0; index < size; index++) { + var key = readString(); + var value = readString(); + map.put(key, value); + } + } + return map; + } + + + public void writeStringPacketMap(Map map, short protocolId) { + if ((map == null) || map.isEmpty()) { + writeInt(0); + } else { + IProtocolRegistration protocolRegistration = ProtocolManager.getProtocol(protocolId); + writeInt(map.size()); + for (var element : map.entrySet()) { + writeString(element.getKey()); + protocolRegistration.write(this, element.getValue()); + } + } + } + + public Map readStringPacketMap(short protocolId) { + int size = readInt(); + Map map = new HashMap<>(); + if (size > 0) { + IProtocolRegistration protocolRegistration = ProtocolManager.getProtocol(protocolId); + for (int index = 0; index < size; index++) { + var key = readString(); + var value = protocolRegistration.read(this); + map.put(key, value); + } + } + return map; + } + + public void writePacket(Object packet, short protocolId) { + IProtocolRegistration protocolRegistration = ProtocolManager.getProtocol(protocolId); + protocolRegistration.write(this, packet); + } + + public Object readPacket(short protocolId) { + IProtocolRegistration protocolRegistration = ProtocolManager.getProtocol(protocolId); + return protocolRegistration.read(this); + } + +} \ No newline at end of file diff --git a/protocol/src/main/resources/java/IProtocolRegistration.java b/protocol/src/main/resources/java/IProtocolRegistration.java new file mode 100644 index 00000000..23386a04 --- /dev/null +++ b/protocol/src/main/resources/java/IProtocolRegistration.java @@ -0,0 +1,10 @@ +${protocol_root_path} + +public interface IProtocolRegistration { + short protocolId(); + + void write(ByteBuffer buffer, Object packet); + + Object read(ByteBuffer buffer); + +} \ No newline at end of file diff --git a/protocol/src/main/resources/java/ProtocolClassTemplate.java b/protocol/src/main/resources/java/ProtocolClassTemplate.java new file mode 100644 index 00000000..867e2335 --- /dev/null +++ b/protocol/src/main/resources/java/ProtocolClassTemplate.java @@ -0,0 +1,4 @@ +${protocol_note} +public class ${protocol_name} { + ${protocol_field_definition} +} \ No newline at end of file diff --git a/protocol/src/main/resources/java/ProtocolManagerTemplate.java b/protocol/src/main/resources/java/ProtocolManagerTemplate.java new file mode 100644 index 00000000..db742f6e --- /dev/null +++ b/protocol/src/main/resources/java/ProtocolManagerTemplate.java @@ -0,0 +1,44 @@ +${protocol_root_path} +import java.util.HashMap; +import java.util.Map; +${protocol_imports} + +public class ProtocolManager { + + public static final short MAX_PROTOCOL_NUM = Short.MAX_VALUE; + + public static final IProtocolRegistration[] protocols = new IProtocolRegistration[MAX_PROTOCOL_NUM]; + + public static Map, Short> protocolIdMap = new HashMap<>(); + + public static void initProtocol() { + // initProtocol + ${protocol_manager_registrations} + } + + public static short getProtocolId(Class clazz) { + return protocolIdMap.get(clazz); + } + + public static IProtocolRegistration getProtocol(short protocolId) { + var protocol = protocols[protocolId]; + if (protocol == null) { + throw new RuntimeException("[protocolId:" + protocolId + "] not exist"); + } + return protocol; + } + + public static void write(ByteBuffer buffer, Object packet) { + var protocolId = getProtocolId(packet.getClass()); + // write protocol id to buffer + buffer.writeShort(protocolId); + // write packet + getProtocol(protocolId).write(buffer, packet); + } + + public static Object read(ByteBuffer buffer) { + var protocolId = buffer.readShort(); + return getProtocol(protocolId).read(buffer); + } + +} diff --git a/protocol/src/main/resources/java/ProtocolRegistrationTemplate.java b/protocol/src/main/resources/java/ProtocolRegistrationTemplate.java new file mode 100644 index 00000000..000ded95 --- /dev/null +++ b/protocol/src/main/resources/java/ProtocolRegistrationTemplate.java @@ -0,0 +1,31 @@ +public static final IProtocolRegistration registration${protocol_name} = new IProtocolRegistration() { + @Override + public short protocolId() { + return ${protocol_id}; + } + + @Override + public void write(ByteBuffer buffer, Object packet) { + if (packet == null) { + buffer.writeInt(0); + return; + } + ${protocol_name} message = (${protocol_name}) packet; + ${protocol_write_serialization} + } + + @Override + public Object read(ByteBuffer buffer) { + var length = buffer.readInt(); + if (length == 0) { + return null; + } + var beforeReadIndex = buffer.readOffset(); + var packet = new ${protocol_name}(); + ${protocol_read_deserialization} + if (length > 0) { + buffer.setReadOffset(beforeReadIndex + length); + } + return packet; + } +}; \ No newline at end of file diff --git a/protocol/src/main/resources/java/ProtocolTemplate.java b/protocol/src/main/resources/java/ProtocolTemplate.java new file mode 100644 index 00000000..081db0bc --- /dev/null +++ b/protocol/src/main/resources/java/ProtocolTemplate.java @@ -0,0 +1,9 @@ +${protocol_root_path} +${protocol_imports} +import java.util.*; +${protocol_note} +public class ${protocol_name} { + ${protocol_field_definition} + + ${protocol_registration} +} \ No newline at end of file diff --git a/protocol/src/main/resources/java/ProtocolsTemplate.java b/protocol/src/main/resources/java/ProtocolsTemplate.java new file mode 100644 index 00000000..4a803366 --- /dev/null +++ b/protocol/src/main/resources/java/ProtocolsTemplate.java @@ -0,0 +1,10 @@ +${protocol_root_path} +${protocol_imports} +import java.util.*; +public class Protocols { + ${protocol_class} + + // ----------------------------------------------------------------------------------------------------------------- + + ${protocol_registration} +}