diff --git a/examples/fel-example/06-agent/src/main/java/modelengine/example/ai/chat/agent/tool/WeatherService.java b/examples/fel-example/06-agent/src/main/java/modelengine/example/ai/chat/agent/tool/WeatherService.java index 003ae8e6..5f39156c 100644 --- a/examples/fel-example/06-agent/src/main/java/modelengine/example/ai/chat/agent/tool/WeatherService.java +++ b/examples/fel-example/06-agent/src/main/java/modelengine/example/ai/chat/agent/tool/WeatherService.java @@ -6,14 +6,19 @@ package modelengine.example.ai.chat.agent.tool; +import modelengine.fel.tool.annotation.Group; +import modelengine.fel.tool.annotation.ToolMethod; import modelengine.fitframework.annotation.Genericable; +import modelengine.fitframework.annotation.Property; /** * 表示天气服务的接口定义。 * + * @author 杭潇 * @author 易文渊 * @since 2024-09-02 */ +@Group(name = "weather_service") public interface WeatherService { /** * 获取指定地点的当前温度。 @@ -22,8 +27,10 @@ public interface WeatherService { * @param unit 表示温度单位的 {@link String}。 * @return 表示当前温度的 {@link String}。 */ + @ToolMethod(name = "current_temperature", description = "获取指定地点的当前温度") @Genericable("modelengine.example.weather.temperature") - String getCurrentTemperature(String location, String unit); + String getCurrentTemperature(@Property(description = "城市名称", required = true) String location, + @Property(description = "使用的温度单位,可选:Celsius,Fahrenheit", defaultValue = "Celsius") String unit); /** * 获取指定地点的降雨概率。 @@ -31,6 +38,7 @@ public interface WeatherService { * @param location 表示地点名称的 {@link String}。 * @return 表示降雨概率的 {@link String}。 */ + @ToolMethod(name = "rain_probability", description = "获取指定地点的降雨概率") @Genericable("modelengine.example.weather.rain") - String getRainProbability(String location); + String getRainProbability(@Property(description = "城市名称", required = true) String location); } \ No newline at end of file diff --git a/examples/fel-example/06-agent/src/main/java/modelengine/example/ai/chat/agent/tool/WeatherServiceImpl.java b/examples/fel-example/06-agent/src/main/java/modelengine/example/ai/chat/agent/tool/WeatherServiceImpl.java index bd470b09..4a58f65b 100644 --- a/examples/fel-example/06-agent/src/main/java/modelengine/example/ai/chat/agent/tool/WeatherServiceImpl.java +++ b/examples/fel-example/06-agent/src/main/java/modelengine/example/ai/chat/agent/tool/WeatherServiceImpl.java @@ -7,6 +7,7 @@ package modelengine.example.ai.chat.agent.tool; import modelengine.fel.tool.annotation.Attribute; +import modelengine.fel.tool.annotation.Group; import modelengine.fel.tool.annotation.ToolMethod; import modelengine.fitframework.annotation.Component; import modelengine.fitframework.annotation.Fitable; @@ -15,10 +16,12 @@ /** * 表示 {@link WeatherService} 的默认实现。 * + * @author 杭潇 * @author 易文渊 * @since 2024-09-02 */ @Component +@Group(name = "default_weather_service") public class WeatherServiceImpl implements WeatherService { @Override @Fitable("default") @@ -28,15 +31,16 @@ public class WeatherServiceImpl implements WeatherService { @Attribute(key = "attribute", value = "nothing"), @Attribute(key = "attribute", value = "nothing two") }) - public String getCurrentTemperature(@Property(description = "城市名称", required = true) String location, - @Property(description = "使用的温度单位,可选:Celsius,Fahrenheit", defaultValue = "Celsius") String unit) { + @Property(description = "当前温度的结果") + public String getCurrentTemperature(String location, String unit) { return "26"; } @Override @Fitable("default") @ToolMethod(namespace = "example", name = "get_rain_probability", description = "获取指定城市下雨的概率") - public String getRainProbability(@Property(description = "城市名称", required = true) String location) { + @Property(description = "下雨的概率") + public String getRainProbability(String location) { return "0.06"; } } \ No newline at end of file diff --git a/examples/fel-example/06-agent/src/main/resources/application.yml b/examples/fel-example/06-agent/src/main/resources/application.yml index 80da7f56..3186bc28 100644 --- a/examples/fel-example/06-agent/src/main/resources/application.yml +++ b/examples/fel-example/06-agent/src/main/resources/application.yml @@ -1,6 +1,12 @@ fel: openai: - api-base: '${api-base}' - api-key: '${your-api-key}' + api-base: 'https://api.siliconflow.cn/v1' + api-key: 'sk-izfmuercmorlnwqtzdkpgskmdjlnjdtheaaypyrfyetkcsaf' example: - model: '${model-name}' \ No newline at end of file + model: 'Qwen/Qwen2.5-7B-Instruct' + + +okhttp: + config-client: + cache: + max-size: 20 \ No newline at end of file diff --git a/framework/fel/java/components/pom.xml b/framework/fel/java/components/pom.xml new file mode 100644 index 00000000..cb29221a --- /dev/null +++ b/framework/fel/java/components/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + + org.fitframework.fel + fel-parent + 1.0.0-SNAPSHOT + + + fel-component-parent + pom + + + tool-info + + \ No newline at end of file diff --git a/framework/fel/java/components/tool-info/pom.xml b/framework/fel/java/components/tool-info/pom.xml new file mode 100644 index 00000000..d1446485 --- /dev/null +++ b/framework/fel/java/components/tool-info/pom.xml @@ -0,0 +1,65 @@ + + + 4.0.0 + + + org.fitframework.fel + fel-component-parent + 1.0.0-SNAPSHOT + + + tool-info + + + 2.16.2 + + + + + org.fitframework + fit-util + + + com.fasterxml.jackson.core + jackson-annotations + 2.16.2 + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + + + + + + + org.fitframework + fit-dependency-maven-plugin + ${fit.version} + + + dependency + compile + + dependency + + + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven.jar.version} + + + + FIT Lab + + + + + + + \ No newline at end of file diff --git a/framework/fel/java/components/tool-info/src/main/java/modelengine/fel/tool/info/schema/PluginSchema.java b/framework/fel/java/components/tool-info/src/main/java/modelengine/fel/tool/info/schema/PluginSchema.java new file mode 100644 index 00000000..f11bdc8b --- /dev/null +++ b/framework/fel/java/components/tool-info/src/main/java/modelengine/fel/tool/info/schema/PluginSchema.java @@ -0,0 +1,105 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.tool.info.schema; + +/** + * 表示插件的字段集合。 + * + * @author 李金绪 + * @since 2024-10-29 + */ +public interface PluginSchema { + /** + * 表示插件的校验和字段。 + */ + String CHECKSUM = "checksum"; + + /** + * 表示插件的名称字段。 + */ + String PLUGIN_NAME = "name"; + + /** + * 表示插件的描述字段。 + */ + String DESCRIPTION = "description"; + + /** + * 表示插件的类型字段。 + */ + String TYPE = "type"; + + /** + * 表示插件类型为 JAVA。 + */ + String JAVA = "java"; + + /** + * 表示插件类型为 PYTHON。 + */ + String PYTHON = "python"; + + /** + * 表示 JAVA 插件的坐标信息。 + */ + String GROUP_ID = "groupId"; + + /** + * 表示 JAVA 插件的坐标信息。 + */ + String ARTIFACT_ID = "artifactId"; + + /** + * 表示 PYTHON 插件的名称。 + */ + String PYTHON_NAME = "name"; + + /** + * 表示插件的全名字段。 + */ + String PLUGIN_FULL_NAME = "pluginFullName"; + + /** + * 表示插件的 JSON 文件名。 + */ + String PLUGIN_JSON = "plugin.json"; + + /** + * 表示插件. + */ + String PLUGINS = "plugins"; + + /** + * 表示插件的临时目录。 + */ + String TEMP_DIR = "tempDir"; + + /** + * 表示插件的 JAR 文件后缀名。 + */ + String JAR = ".jar"; + + /** + * 表示 HTTP 类型的插件。 + */ + String HTTP = "HTTP"; + + /** + * 表示插件的语言类型字段。 + */ + String LANGUAGE = "language"; + + /** + * 表示插件的唯一性字段。 + */ + String UNIQUENESS = "uniqueness"; + + /** + * 表示分隔符。 + */ + char DOT = '.'; +} diff --git a/framework/fel/java/components/tool-info/src/main/java/modelengine/fel/tool/info/schema/ToolsSchema.java b/framework/fel/java/components/tool-info/src/main/java/modelengine/fel/tool/info/schema/ToolsSchema.java new file mode 100644 index 00000000..cda1f3ca --- /dev/null +++ b/framework/fel/java/components/tool-info/src/main/java/modelengine/fel/tool/info/schema/ToolsSchema.java @@ -0,0 +1,130 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.tool.info.schema; + +/** + * 表示工具的字段集合。 + * + * @author 李金绪 + * @since 2024-10-29 + */ +public interface ToolsSchema { + /** + * 工具的 JSON 文件名。 + */ + String TOOLS_JSON = "tools.json"; + + /** + * 工具的 JSON 文件中的 tools 字段名。 + */ + String TOOLS = "tools"; + + /** + * 工具的 JSON 文件中的 definitions 字段名。 + */ + String DEFINITIONS = "definitions"; + + /** + * 工具的 JSON 文件中的 toolGroups 字段名。 + */ + String TOOL_GROUPS = "toolGroups"; + + /** + * 工具的 JSON 文件中的 definitionGroups 字段名。 + */ + String DEFINITION_GROUPS = "definitionGroups"; + + /** + * 工具的 JSON 文件中的 definitionName 字段名。 + */ + String DEFINITION_NAME = "definitionName"; + + /** + * 工具的 JSON 文件中的 toolName 字段名。 + */ + String TOOL_NAME = "toolName"; + + /** + * 工具的 JSON 文件中的 toolGroupName 字段名。 + */ + String TOOL_GROUP_NAME = "toolGroupName"; + + /** + * 工具的 JSON 文件中的 definitionGroupName 字段名。 + */ + String DEFINITION_GROUP_NAME_IN_TOOL = "definitionGroupName"; + + /** + * 工具的 JSON 文件中的 definitionGroupName 字段名。 + */ + String DEFINITION_GROUP_NAME = "definitionGroups.name"; + + /** + * 工具的 JSON 文件中的 items 字段名。 + */ + String ITEMS = "items"; + + /** + * 工具的 JSON 文件中的 object 字段名。 + */ + String OBJECT = "object"; + + /** + * 工具的 JSON 文件中的 array 字段名。 + */ + String ARRAY = "array"; + + /** + * 工具的 JSON 文件中的 tags 字段名。 + */ + String TAGS = "tags"; + + /** + * 工具的 JSON 文件中的 tag 字段的最大长度。 + */ + int MAX_TAG_LENGTH = 64; + + /** + * 工具的 JSON 文件中的 fit 字段的最大长度。 + */ + int MAX_FIT_TAG_LENGTH = 128; + + /** + * 工具的 JSON 文件中的 fit 或 tag 字段的最小长度。 + */ + int MIN_FIT_LENGTH = 1; + + /** + * 工具的 JSON 文件中的 fit 字段名。 + */ + String FIT = "FIT"; + + /** + * 工具的 JSON 文件中的 fitableId 字段名。 + */ + String FITABLE_ID = "fitableId"; + + /** + * 工具的 JSON 文件中的 genericableId 字段名。 + */ + String GENERICABLE_ID = "genericableId"; + + /** + * 工具的 JSON 文件中的 selectTools 字段名。 + */ + String SELECT_TOOLS = "selectTools"; + + /** + * 工具的 JSON 文件中的 builtIn 字段名。 + */ + String BUILT_IN = "BUILTIN"; + + /** + * 工具的 JSON 文件中的列表形式的展示。 + */ + String LIST_NOTATION = "[]"; +} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/pom.xml b/framework/fel/java/maven-plugins/tool-maven-plugin/pom.xml index 14827c79..10f1007b 100644 --- a/framework/fel/java/maven-plugins/tool-maven-plugin/pom.xml +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/pom.xml @@ -12,6 +12,11 @@ tool-maven-plugin maven-plugin + + 3.8.2 + 4.11.0 + + @@ -29,7 +34,14 @@ tool-service - + + + org.fitframework.fel + tool-info + 1.0.0-SNAPSHOT + + + net.bytebuddy byte-buddy @@ -46,6 +58,11 @@ org.junit.jupiter junit-jupiter + + org.mockito + mockito-inline + ${mockito.version} + org.assertj assertj-core diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/ByteBuddyDefinitionsParser.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/ByteBuddyDefinitionsParser.java new file mode 100644 index 00000000..7f395e65 --- /dev/null +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/ByteBuddyDefinitionsParser.java @@ -0,0 +1,66 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.maven.complie.parser; + +import modelengine.fel.tool.annotation.Group; +import modelengine.fel.tool.info.entity.DefinitionEntity; +import modelengine.fel.tool.info.entity.DefinitionGroupEntity; +import modelengine.fel.tool.info.entity.SchemaEntity; + +import net.bytebuddy.description.annotation.AnnotationDescription; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; + +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; + +/** + * 提供对定义信息的解析。 + * + * @author 杭潇 + * @author 曹嘉美 + * @since 2024-10-30 + */ +public class ByteBuddyDefinitionsParser { + /** + * 解析定义组。 + * + * @param typeDescription 表示类型的描述的 {@link TypeDescription}。 + * @return 表示定义组实体的 {@link DefinitionGroupEntity}。 + */ + public static DefinitionGroupEntity parseDefinitionGroup(TypeDescription typeDescription) { + DefinitionGroupEntity definitionGroupEntity = new DefinitionGroupEntity(); + AnnotationDescription.Loadable groupAnnotation = + typeDescription.getDeclaredAnnotations().ofType(Group.class); + if (groupAnnotation == null) { + return definitionGroupEntity; + } + Group group = groupAnnotation.load(); + definitionGroupEntity.setName(group.name()); + definitionGroupEntity.setSummary(group.summary()); + definitionGroupEntity.setDescription(group.description()); + definitionGroupEntity.setExtensions(ParserUtils.parseAttributes(group.extensions())); + List definitionEntities = new LinkedList<>(); + for (MethodDescription.InDefinedShape methodDescription : typeDescription.getDeclaredMethods()) { + Optional definitionEntity = parseDefinition(methodDescription); + definitionEntity.ifPresent(definitionEntities::add); + } + definitionGroupEntity.setDefinitions(definitionEntities); + return definitionGroupEntity; + } + + private static Optional parseDefinition(MethodDescription.InDefinedShape methodDescription) { + Optional schemaEntity = ByteBuddySchemaParser.parseMethodSchema(methodDescription); + if (!schemaEntity.isPresent()) { + return Optional.empty(); + } + DefinitionEntity definitionEntity = new DefinitionEntity(); + definitionEntity.setSchema(schemaEntity.get()); + return Optional.of(definitionEntity); + } +} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/ByteBuddyGroupParser.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/ByteBuddyGroupParser.java new file mode 100644 index 00000000..092ec607 --- /dev/null +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/ByteBuddyGroupParser.java @@ -0,0 +1,118 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.maven.complie.parser; + +import modelengine.fel.tool.info.entity.DefinitionGroupEntity; +import modelengine.fel.tool.info.entity.ToolGroupEntity; +import modelengine.fel.tool.info.entity.ToolJsonEntity; +import modelengine.fitframework.jvm.classfile.ClassFile; +import modelengine.fitframework.util.FileUtils; +import modelengine.fitframework.util.StringUtils; + +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.pool.TypePool; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 提供对工具组信息的解析。 + * + * @author 杭潇 + * @author 曹嘉美 + * @since 2024-10-26 + */ +public class ByteBuddyGroupParser implements GroupParser { + private static final String VERSION = "1.0.0"; + private static final String DOT = "."; + + private final TypePool typePool; + private final String rootPath; + + public ByteBuddyGroupParser(TypePool typePool, String rootPath) { + this.typePool = typePool; + this.rootPath = Paths.get(rootPath).normalize().toString(); + } + + @Override + public ToolJsonEntity parseJson(String outputDirectory) { + ToolJsonEntity jsonEntity = new ToolJsonEntity(); + jsonEntity.setVersion(VERSION); + List files = this.scanFiles(outputDirectory); + List toolGroups = new LinkedList<>(); + List definitionGroups = new LinkedList<>(); + for (File classFile : files) { + TypeDescription typeDescription = this.getTypeDescription(classFile); + if (!typeDescription.isInterface()) { + List toolGroupEntity = ByteBuddyToolsParser.parseToolGroup(typeDescription); + toolGroups.addAll(toolGroupEntity); + for (TypeDescription.Generic interfaceTypeGeneric : typeDescription.getInterfaces()) { + TypeDescription interfaceType = interfaceTypeGeneric.asErasure(); + parseDefinitionGroup(interfaceType, definitionGroups); + } + } + } + jsonEntity.setDefinitionGroups(definitionGroups); + jsonEntity.setToolGroups(toolGroups); + return jsonEntity; + } + + private static void parseDefinitionGroup(TypeDescription typeDescription, + List definitionGroups) { + DefinitionGroupEntity definitionGroupEntity = ByteBuddyDefinitionsParser.parseDefinitionGroup(typeDescription); + if (definitionGroupEntity.getName() != null && !hasDefinitionGroup(definitionGroups, definitionGroupEntity)) { + definitionGroups.add(definitionGroupEntity); + } + } + + private static boolean hasDefinitionGroup(List definitionGroups, + DefinitionGroupEntity definitionGroupEntity) { + for (DefinitionGroupEntity definitionGroup : definitionGroups) { + if (Objects.equals(definitionGroupEntity.getName(), definitionGroup.getName())) { + return true; + } + } + return false; + } + + private List scanFiles(String outputDirectory) { + try (Stream paths = Files.walk(Paths.get(outputDirectory))) { + return paths.filter(Files::isRegularFile) + .map(Path::toFile) + .filter(FileUtils::isClass) + .collect(Collectors.toList()); + } catch (IOException e) { + throw new IllegalStateException(StringUtils.format("Failed to get class canonical path. [directory={0}]", + outputDirectory)); + } + } + + private TypeDescription getTypeDescription(File classFile) { + String normalizedPath; + try { + normalizedPath = classFile.getCanonicalPath(); + } catch (IOException e) { + throw new IllegalStateException(StringUtils.format("Failed to get class canonical path. [classFile={0}]", + classFile)); + } + if (!normalizedPath.startsWith(rootPath)) { + throw new IllegalStateException(StringUtils.format("The class is not in root directory. [directory={0}]", + rootPath)); + } + String classFullName = normalizedPath.substring(rootPath.length() + 1, + normalizedPath.length() - ClassFile.FILE_EXTENSION.length()).replace(File.separator, DOT); + return this.typePool.describe(classFullName).resolve(); + } +} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/ByteBuddySchemaParser.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/ByteBuddySchemaParser.java new file mode 100644 index 00000000..ef872e49 --- /dev/null +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/ByteBuddySchemaParser.java @@ -0,0 +1,156 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.maven.complie.parser; + +import com.fasterxml.jackson.databind.JsonNode; + +import modelengine.fel.tool.annotation.ToolMethod; +import modelengine.fel.tool.info.entity.ParameterEntity; +import modelengine.fel.tool.info.entity.PropertyEntity; +import modelengine.fel.tool.info.entity.ReturnPropertyEntity; +import modelengine.fel.tool.info.entity.SchemaEntity; +import modelengine.fitframework.annotation.Property; + +import net.bytebuddy.description.annotation.AnnotationDescription; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.method.ParameterDescription; + +import static modelengine.fitframework.inspection.Validation.notNull; + +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +/** + * 提供对摘要信息的解析。 + * + * @author 杭潇 + * @author 曹嘉美 + * @since 2024-10-28 + */ +public class ByteBuddySchemaParser { + private static final String SCHEMA_TYPE = "object"; + + /** + * 解析方法信息。 + * + * @param methodDescription 表示解析方法描述的 {@link MethodDescription}。 + * @return 表示描述信息实体的 {@link SchemaEntity}。 + */ + public static Optional parseMethodSchema(MethodDescription methodDescription) { + AnnotationDescription.Loadable toolAnnotation = + methodDescription.getDeclaredAnnotations().ofType(ToolMethod.class); + if (toolAnnotation == null) { + return Optional.empty(); + } + ToolMethod toolMethod = toolAnnotation.load(); + SchemaEntity schemaEntity = new SchemaEntity(); + schemaEntity.setName(toolMethod.name()); + schemaEntity.setDescription(toolMethod.description()); + schemaEntity.setParameters(parseParameter(methodDescription)); + schemaEntity.setOrder(new LinkedList<>(schemaEntity.getParameters().getProperties().keySet())); + schemaEntity.setRet(getStringObjectMap(parseReturnProperty(methodDescription))); + List extraParams = Arrays.asList(toolMethod.extraParams()); + if (!extraParams.isEmpty()) { + Map parameterExtensions = new LinkedHashMap<>(); + parameterExtensions.put("config", Arrays.asList(toolMethod.extraParams())); + schemaEntity.setParameterExtensions(parameterExtensions); + } + return Optional.of(schemaEntity); + } + + private static Map getStringObjectMap(ReturnPropertyEntity returnPropertyEntity) { + Map returnProperty = new LinkedHashMap<>(); + returnProperty.put("name", returnPropertyEntity.getName()); + returnProperty.put("description", returnPropertyEntity.getDescription()); + returnProperty.put("type", returnPropertyEntity.getType()); + returnProperty.put("items", returnPropertyEntity.getItems()); + returnProperty.put("properties", returnPropertyEntity.getProperties()); + if (returnPropertyEntity.getConvertor() != null) { + returnProperty.put("convertor", returnPropertyEntity.getConvertor()); + } + if (returnPropertyEntity.getExamples() != null) { + returnProperty.put("examples", returnPropertyEntity.getExamples()); + } + return returnProperty; + } + + private static ParameterEntity parseParameter(MethodDescription methodDescription) { + ParameterEntity parameterEntity = new ParameterEntity(); + parameterEntity.setType(SCHEMA_TYPE); + Map properties = new LinkedHashMap<>(); + List required = new LinkedList<>(); + for (ParameterDescription parameterDescription : methodDescription.getParameters()) { + String methodName = parameterDescription.getName(); + PropertyEntity property = parseProperty(parameterDescription); + properties.put(methodName, property); + if (property.isRequired()) { + required.add(methodName); + } + } + parameterEntity.setProperties(properties); + parameterEntity.setRequired(required); + return parameterEntity; + } + + private static PropertyEntity parseProperty(ParameterDescription parameterDescription) { + JsonNode jsonNode = notNull(JacksonTypeParser.getParameterSchema(parameterDescription.getType()), + "The parameter type cannot be null."); + PropertyEntity entity = new PropertyEntity(); + setPropertyType(entity, jsonNode); + entity.setName(parameterDescription.getName()); + AnnotationDescription.Loadable paramAnnotation = + parameterDescription.getDeclaredAnnotations().ofType(Property.class); + if (paramAnnotation != null) { + Property property = paramAnnotation.load(); + entity.setDescription(property.description()); + entity.setRequired(property.required()); + entity.setDefaultValue(property.defaultValue()); + entity.setExamples(property.example()); + } + return entity; + } + + private static ReturnPropertyEntity parseReturnProperty(MethodDescription methodDescription) { + ReturnPropertyEntity returnPropertyEntity = new ReturnPropertyEntity(); + AnnotationDescription.Loadable returnAnnotation = + methodDescription.getDeclaredAnnotations().ofType(Property.class); + if (returnAnnotation != null) { + Property property = returnAnnotation.load(); + returnPropertyEntity.setName(property.name()); + returnPropertyEntity.setDescription(property.description()); + returnPropertyEntity.setExamples(property.example()); + } + notNull(methodDescription.getReturnType(), "The return type cannot be null."); + JsonNode jsonNode = JacksonTypeParser.getParameterSchema(methodDescription.getReturnType()); + setPropertyType(returnPropertyEntity, jsonNode); + AnnotationDescription.Loadable toolMethodAnnotation = + methodDescription.getDeclaredAnnotations().ofType(ToolMethod.class); + if (toolMethodAnnotation != null) { + returnPropertyEntity.setConvertor(toolMethodAnnotation.load().returnConverter()); + } + return returnPropertyEntity; + } + + private static void setPropertyType(PropertyEntity returnPropertyEntity, JsonNode jsonNode) { + returnPropertyEntity.setType(jsonNode.get("type").asText()); + returnPropertyEntity.setItems(null); + returnPropertyEntity.setProperties(null); + if (Objects.equals(returnPropertyEntity.getType(), "array")) { + returnPropertyEntity.setItems(jsonNode.get("items")); + } + if (Objects.equals(returnPropertyEntity.getType(), "object")) { + if (jsonNode.get("properties") != null) { + returnPropertyEntity.setProperties(jsonNode.get("properties")); + } + } + } +} \ No newline at end of file diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/ByteBuddyToolsParser.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/ByteBuddyToolsParser.java new file mode 100644 index 00000000..a0efa509 --- /dev/null +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/ByteBuddyToolsParser.java @@ -0,0 +1,135 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.maven.complie.parser; + +import static modelengine.fel.tool.info.schema.ToolsSchema.FIT; +import static modelengine.fel.tool.info.schema.ToolsSchema.FITABLE_ID; +import static modelengine.fel.tool.info.schema.ToolsSchema.GENERICABLE_ID; +import static modelengine.fitframework.inspection.Validation.notNull; +import static modelengine.fitframework.util.ObjectUtils.cast; + +import modelengine.fel.tool.annotation.Group; +import modelengine.fel.tool.annotation.ToolMethod; +import modelengine.fel.tool.info.entity.ToolEntity; +import modelengine.fel.tool.info.entity.ToolGroupEntity; +import modelengine.fitframework.annotation.Fitable; +import modelengine.fitframework.annotation.Genericable; + +import net.bytebuddy.description.annotation.AnnotationDescription; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * 提供对工具信息的解析。 + * + * @author 杭潇 + * @author 曹嘉美 + * @since 2024-10-30 + */ +public class ByteBuddyToolsParser { + /** + * 解析工具组信息。 + * + * @param typeDescription 表示类型的描述的 {@link TypeDescription}。 + * @return 返回工具组信息的 {@link List}{@code <}{@link ToolGroupEntity}{@code >}。 + */ + public static List parseToolGroup(TypeDescription typeDescription) { + List toolGroupEntities = new LinkedList<>(); + AnnotationDescription.Loadable toolGroupAnnotation = + typeDescription.getDeclaredAnnotations().ofType(Group.class); + if (toolGroupAnnotation == null) { + return toolGroupEntities; + } + for (TypeDescription.Generic interfaceTypeGeneric : typeDescription.getInterfaces()) { + TypeDescription interfaceType = interfaceTypeGeneric.asErasure(); + AnnotationDescription.Loadable defGroupAnnotation = + interfaceType.getDeclaredAnnotations().ofType(Group.class); + if (defGroupAnnotation == null) { + continue; + } + toolGroupEntities.add(buildToolGroupEntity(typeDescription, + defGroupAnnotation, + toolGroupAnnotation, + interfaceType)); + } + return toolGroupEntities; + } + + private static ToolGroupEntity buildToolGroupEntity(TypeDescription typeDescription, + AnnotationDescription.Loadable defGroupAnnotation, + AnnotationDescription.Loadable toolGroupAnnotation, TypeDescription interfaceType) { + ToolGroupEntity toolGroupEntity = new ToolGroupEntity(); + toolGroupEntity.setDefinitionGroupName(defGroupAnnotation.load().name()); + toolGroupEntity.setName(toolGroupAnnotation.load().name()); + toolGroupEntity.setSummary(toolGroupAnnotation.load().summary()); + toolGroupEntity.setDescription(toolGroupAnnotation.load().description()); + toolGroupEntity.setExtensions(ParserUtils.parseAttributes(toolGroupAnnotation.load().extensions())); + List toolEntities = getToolEntities(typeDescription, interfaceType); + toolGroupEntity.setTools(toolEntities); + return toolGroupEntity; + } + + private static List getToolEntities(TypeDescription typeDescription, TypeDescription interfaceType) { + List toolEntities = new LinkedList<>(); + for (MethodDescription defMethodDescription : interfaceType.getDeclaredMethods()) { + for (MethodDescription toolMethodDescription : typeDescription.getDeclaredMethods()) { + if (isSameMethod(defMethodDescription, toolMethodDescription)) { + parseTool(defMethodDescription, toolMethodDescription).ifPresent(toolEntities::add); + } + } + } + return toolEntities; + } + + private static boolean isSameMethod(MethodDescription defMethodDescription, + MethodDescription toolMethodDescription) { + return defMethodDescription.getName().equals(toolMethodDescription.getName()) + && defMethodDescription.getDescriptor().equals(toolMethodDescription.getDescriptor()); + } + + private static Optional parseTool(MethodDescription defMethodDescription, + MethodDescription toolMethodDescription) { + ToolEntity toolEntity = new ToolEntity(); + AnnotationDescription.Loadable defMethodAnnotation = + defMethodDescription.getDeclaredAnnotations().ofType(ToolMethod.class); + if (defMethodAnnotation == null) { + return Optional.empty(); + } + toolEntity.setDefinitionName(defMethodAnnotation.load().name()); + toolEntity.setNamespace(defMethodAnnotation.load().namespace()); + ByteBuddySchemaParser.parseMethodSchema(toolMethodDescription).ifPresent(toolEntity::setSchema); + toolEntity.setRunnables(parserRunnables(defMethodDescription, toolMethodDescription)); + AnnotationDescription.Loadable toolMethodAnnotation = + toolMethodDescription.getDeclaredAnnotations().ofType(ToolMethod.class); + if (toolMethodAnnotation == null) { + return Optional.empty(); + } + toolEntity.setExtensions(ParserUtils.parseAttributes(toolMethodAnnotation.load().extensions())); + return Optional.of(toolEntity); + } + + private static Map parserRunnables(MethodDescription defMethodDescription, + MethodDescription toolMethodDescription) { + AnnotationDescription.Loadable genericableAnnotation = + defMethodDescription.getDeclaredAnnotations().ofType(Genericable.class); + notNull(genericableAnnotation, "The definition method must contain genericable."); + AnnotationDescription.Loadable fitableAnnotation = + toolMethodDescription.getDeclaredAnnotations().ofType(Fitable.class); + notNull(fitableAnnotation, "The tool method must contain fitable."); + Map fit = new LinkedHashMap<>(); + fit.put(GENERICABLE_ID, genericableAnnotation.load().value()); + fit.put(FITABLE_ID, fitableAnnotation.load().value()); + return cast(Collections.singletonMap(FIT, fit)); + } +} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/GroupParser.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/GroupParser.java new file mode 100644 index 00000000..803fdfd0 --- /dev/null +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/GroupParser.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.maven.complie.parser; + +import modelengine.fel.tool.info.entity.ToolJsonEntity; + +import java.io.IOException; + +/** + * 工具解析接口。 + * + * @author 曹嘉美 + * @since 2024-10-26 + */ +public interface GroupParser { + /** + * 基于目标目录将工具注解的方法解析成 {@link ToolJsonEntity}。 + * + * @param outputDirectory 表示目标目录的 {@link String}。 + * @return 表示解析完之后的 {@link ToolJsonEntity}。 + * @throws IOException 当解析过程中发生输入输出异常时。 + */ + ToolJsonEntity parseJson(String outputDirectory) throws IOException; +} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/parser/JacksonTypeParser.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/JacksonTypeParser.java similarity index 96% rename from framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/parser/JacksonTypeParser.java rename to framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/JacksonTypeParser.java index 3464d0bd..7c61b90d 100644 --- a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/parser/JacksonTypeParser.java +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/JacksonTypeParser.java @@ -1,10 +1,10 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -package modelenginei.jade.maven.complie.parser; +package modelengine.fel.maven.complie.parser; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -156,13 +156,15 @@ private static JsonNode getObjectSchema(TypeDescription typeDescription) { ObjectNode schemaNode = OBJECT_MAPPER.createObjectNode(); schemaNode.put("type", "object"); ObjectNode propertiesNode = OBJECT_MAPPER.createObjectNode(); - schemaNode.set("properties", propertiesNode); for (FieldDescription field : typeDescription.getDeclaredFields()) { String fieldName = field.getName(); JsonNode fieldSchema = getParameterSchema(field.getType()); propertiesNode.set(fieldName, fieldSchema); } + if (!propertiesNode.isEmpty()) { + schemaNode.set("properties", propertiesNode); + } PARSED_TYPES.remove(typeName); return schemaNode; } diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/ParserUtils.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/ParserUtils.java new file mode 100644 index 00000000..bf757a4e --- /dev/null +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/parser/ParserUtils.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.maven.complie.parser; + +import static modelengine.fitframework.util.ObjectUtils.cast; + +import modelengine.fel.tool.annotation.Attribute; + +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * 表示通用的解析工具类。 + * + * @author 李金绪 + * @since 2024-12-12 + */ +public class ParserUtils { + /** + * 解析属性。 + * + * @param params 表示属性的 {@link Attribute}。 + * @return 表示解析结果的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 + */ + public static Map parseAttributes(Attribute[] params) { + if (params == null) { + return new LinkedHashMap<>(); + } + List attributeList = new LinkedList<>(Arrays.asList(params)); + Map> attributes = new LinkedHashMap<>(); + attributeList.forEach(attribute -> attributes.computeIfAbsent(attribute.key(), k -> new LinkedList<>()) + .add(attribute.value())); + return cast(attributes); + } +} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/plugin/BuildToolPluginMojo.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/plugin/BuildGroupPluginMojo.java similarity index 77% rename from framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/plugin/BuildToolPluginMojo.java rename to framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/plugin/BuildGroupPluginMojo.java index b9ff9df8..1741fef5 100644 --- a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/plugin/BuildToolPluginMojo.java +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/plugin/BuildGroupPluginMojo.java @@ -1,10 +1,10 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -package modelenginei.jade.maven.complie.plugin; +package modelengine.fel.maven.complie.plugin; import modelengine.fitframework.plugin.maven.support.AbstractMojo; @@ -17,14 +17,14 @@ import java.util.Objects; /** - * 表示编译工具插件的任务。 + * 对 Jar 包进行编译处理。 * - * @author 杭潇 - * @since 2024-06-13 + * @author 曹嘉美 + * @since 2024-10-26 */ @Mojo(name = "build-tool", defaultPhase = LifecyclePhase.COMPILE, requiresDependencyResolution = ResolutionScope.RUNTIME) -public class BuildToolPluginMojo extends AbstractMojo { +public class BuildGroupPluginMojo extends AbstractMojo { @Parameter(defaultValue = "${project.packaging}", readonly = true, required = true) private String packaging; @@ -33,7 +33,7 @@ public void execute() throws MojoExecutionException { if (!Objects.equals(this.packaging, "jar")) { return; } - ToolPluginCompiler compiler = new ToolPluginCompiler(this.project(), this.getLog()); + GroupPluginCompiler compiler = new GroupPluginCompiler(this.project(), this.getLog()); compiler.compile(); } } diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/plugin/GroupPluginCompiler.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/plugin/GroupPluginCompiler.java new file mode 100644 index 00000000..404a0ac5 --- /dev/null +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/plugin/GroupPluginCompiler.java @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.maven.complie.plugin; + +import modelengine.fel.tool.info.entity.ToolJsonEntity; +import modelengine.fitframework.plugin.maven.support.AbstractCompiler; +import modelengine.fel.maven.complie.parser.ByteBuddyGroupParser; +import modelengine.fel.maven.complie.parser.GroupParser; + +import net.bytebuddy.pool.TypePool; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.project.MavenProject; + +import java.io.IOException; +import java.net.URLClassLoader; + +/** + * 向目标文件夹下输出编译产物。 + * + * @author 曹嘉美 + * @since 2024-10-26 + */ +public class GroupPluginCompiler extends AbstractCompiler { + GroupPluginCompiler(MavenProject project, Log log) { + super(project, log, null); + } + + @Override + protected void output(String outputDirectory, String fitRootDirectory) throws MojoExecutionException { + UrlClassLoaderInitializer urlClassLoaderInitializer = new UrlClassLoaderInitializer(); + try (URLClassLoader classLoader = urlClassLoaderInitializer.initUrlClassLoader(outputDirectory, + FIT_ROOT_DIRECTORY)) { + GroupParser groupParser = new ByteBuddyGroupParser(TypePool.Default.of(classLoader), outputDirectory); + ToolJsonEntity toolJsonEntity = groupParser.parseJson(outputDirectory); + urlClassLoaderInitializer.outputToolManifest(outputDirectory, toolJsonEntity); + } catch (IOException e) { + throw new MojoExecutionException("Failed to parse class files.", e); + } + } +} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/plugin/UrlClassLoaderInitializer.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/plugin/UrlClassLoaderInitializer.java new file mode 100644 index 00000000..d576780b --- /dev/null +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/plugin/UrlClassLoaderInitializer.java @@ -0,0 +1,79 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.maven.complie.plugin; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; + +import modelengine.fel.tool.ToolSchema; +import modelengine.fel.tool.info.entity.ToolJsonEntity; +import modelengine.fitframework.log.Logger; +import modelengine.fitframework.protocol.jar.Jar; +import modelengine.fitframework.util.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 提供初始化类加载器和输出配置文件的能力。 + * + * @author 杭潇 + * @author 曹嘉美 + * @since 2024-11-01 + */ +public class UrlClassLoaderInitializer { + private static final Logger log = Logger.get(UrlClassLoaderInitializer.class); + + /** + * 初始化 URLClassLoader。 + * + * @param outputDirectory 表示输出目录的 {@link String}。 + * @param fitRootDirectory 表示 FIT 根目录的 {@link String}。 + * @return 返回初始化后的 {@link URLClassLoader}。 + * @throws IOException 当读取文件或者创建 URLClassLoader 发生输入输出异常时。 + */ + public URLClassLoader initUrlClassLoader(String outputDirectory, String fitRootDirectory) throws IOException { + List urls = new LinkedList<>(); + try (Stream paths = Files.walk(Paths.get(outputDirectory, fitRootDirectory))) { + List files = paths.filter(Files::isRegularFile).map(Path::toFile).collect(Collectors.toList()); + for (File file : files) { + if (FileUtils.isJar(file)) { + urls.add(Jar.from(file).location().toUrl()); + } + } + urls.add(Paths.get(outputDirectory).toUri().toURL()); + } + return new URLClassLoader(urls.toArray(new URL[0]), this.getClass().getClassLoader()); + } + + /** + * 输出工具配置文件。 + * + * @param outputDirectory 表示输出目录的 {@link String}。 + * @param toolJsonEntity 表示工具配置的 {@link ToolJsonEntity}。 + * @throws IOException 当读取文件或者创建 URLClassLoader 发生输入输出异常时。 + */ + public void outputToolManifest(String outputDirectory, ToolJsonEntity toolJsonEntity) throws IOException { + if (toolJsonEntity == null) { + return; + } + File jsonFile = Paths.get(outputDirectory, ToolSchema.TOOL_MANIFEST).toFile(); + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + objectMapper.writerWithDefaultPrettyPrinter().writeValue(jsonFile, toolJsonEntity); + log.info("Write tool json successfully. [file={}]", jsonFile.getName()); + } +} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/util/JsonUtils.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/util/JsonUtils.java similarity index 93% rename from framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/util/JsonUtils.java rename to framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/util/JsonUtils.java index 273ae1c1..959ede8a 100644 --- a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/util/JsonUtils.java +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelengine/fel/maven/complie/util/JsonUtils.java @@ -1,10 +1,10 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -package modelenginei.jade.maven.complie.util; +package modelengine.fel.maven.complie.util; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/entity/ParameterEntity.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/entity/ParameterEntity.java deleted file mode 100644 index d0379912..00000000 --- a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/entity/ParameterEntity.java +++ /dev/null @@ -1,111 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelenginei.jade.maven.complie.entity; - -/** - * 表示参数的定义。 - * - * @author 杭潇 - * @since 2024-06-06 - */ -public class ParameterEntity { - private String defaultValue; - private String description; - private boolean isRequired; - private String name; - private String type; - - /** - * 表示获取参数的描述信息。 - * - * @return 参数的描述信息的 {@link String}。 - */ - public String getDescription() { - return this.description; - } - - /** - * 表示设置参数的描述信息。 - * - * @param description 表示待设置的参数的描述信息的 {@link String}。 - */ - public void setDescription(String description) { - this.description = description; - } - - /** - * 表示获取参数的默认值。 - * - * @return 参数默认值的 {@link String}。 - */ - public String getDefaultValue() { - return this.defaultValue; - } - - /** - * 表示设置参数的默认值。 - * - * @param defaultValue 参数默认值的 {@link String}。 - */ - public void setDefaultValue(String defaultValue) { - this.defaultValue = defaultValue; - } - - /** - * 表示参数是否必须的,如果不设置则是非必须值。 - * - * @return 该参数是否是必须的 {@link Boolean}。 - */ - public boolean isRequired() { - return this.isRequired; - } - - /** - * 表示设置参数是否是必须的值。 - * - * @param isRequired 参数是否是必须的 {@link Boolean}。 - */ - public void setRequired(boolean isRequired) { - this.isRequired = isRequired; - } - - /** - * 表示获取参数的名字。 - * - * @return 参数的名字的 {@link String}。 - */ - public String getName() { - return this.name; - } - - /** - * 表示设置参数名。 - * - * @param name 表示待设置的参数名的 {@link String}。 - */ - public void setName(String name) { - this.name = name; - } - - /** - * 表示获取参数的类型。 - * - * @return 参数的类型的 {@link String}。 - */ - public String getType() { - return this.type; - } - - /** - * 表示设置参数类型。 - * - * @param type 表示待设置的参数类型的 {@link String}。 - */ - public void setType(String type) { - this.type = type; - } -} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/entity/ToolEntity.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/entity/ToolEntity.java deleted file mode 100644 index 99538882..00000000 --- a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/entity/ToolEntity.java +++ /dev/null @@ -1,214 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelenginei.jade.maven.complie.entity; - -import modelengine.fel.tool.ToolSchema; -import modelengine.fel.tool.annotation.ToolMethod; -import modelengine.fitframework.util.MapBuilder; -import modelenginei.jade.maven.complie.util.JsonUtils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * 表示 {@link ToolMethod} 注解下的方法实体。 - * - * @author 杭潇 - * @author 易文渊 - * @since 2024-06-13 - */ -public class ToolEntity { - private String genericableId; - private String fitableId; - private String namespace; - private String name; - private String description; - private List parameterEntities = new ArrayList<>(); - private List extraParameters; - private String returnDescription; - private String returnType; - private String returnConvertor; - private Map> extensions; - - /** - * 设置 Genericable Id 值。 - * - * @param genericableId 待设置的 Genericable Id 值。 - */ - public void setGenericableId(String genericableId) { - this.genericableId = genericableId; - } - - /** - * 设置 Fitable Id 值。 - * - * @param fitableId 待设置的 Fitable Id 值。 - */ - public void setFitableId(String fitableId) { - this.fitableId = fitableId; - } - - /** - * 设置方法名。 - * - * @param name 表示给定的方法名的 {@link String}。 - */ - public void setName(String name) { - this.name = name; - } - - /** - * 设置命名空间。 - * - * @param namespace 表示给定命名空间的 {@link String}。 - */ - public void setNamespace(String namespace) { - this.namespace = namespace; - } - - /** - * 设置方法描述。 - * - * @param description 表示给定的方法描述的 {@link String}。 - */ - public void setDescription(String description) { - this.description = description; - } - - /** - * 设置方法的参数信息列表。 - * - * @param parameterEntities 表示给定的参数信息列表的 {@link List}{@code <}{@link ParameterEntity}{@code >}。 - */ - public void setParameterEntities(List parameterEntities) { - this.parameterEntities = parameterEntities; - } - - /** - * 设置返回值的描述。 - * - * @param returnDescription 表示给定的返回值的描述的 {@link String}。 - */ - public void setReturnDescription(String returnDescription) { - this.returnDescription = returnDescription; - } - - /** - * 设置的返回值类型。 - * - * @param returnType 表示给定的返回值类型的 {@link String}。 - */ - public void setReturnType(String returnType) { - this.returnType = returnType; - } - - /** - * 设置方法额外参数的集合。 - * - * @param extraParameters 表示方法额外参数集合的 {@link Set}{@code <}{@link String}{@code >}。 - */ - public void setExtraParameters(List extraParameters) { - this.extraParameters = extraParameters; - } - - /** - * 设置输出转换器的名称。 - * - * @param returnConvertor 表示输出转换器的名称的 {@link String}。 - */ - public void setReturnConvertor(String returnConvertor) { - this.returnConvertor = returnConvertor; - } - - /** - * 设置扩展属性。 - * - * @param extensions 表示扩展属性的 - * {@link Map}{@code <}{@link String}{@code ,}{@link List}{@code <}{@link String}{@code >>}。 - */ - public void setExtensions(Map> extensions) { - this.extensions = extensions; - } - - /** - * 获取工具信息的标准化格式。 - * - * @return 表示工具标准化信息的 {@link Map}{@link String}{@code , }{@link Object}{@code >}。 - */ - public Map normalize() { - MapBuilder mapBuilder = new MapBuilder<>(); - return mapBuilder.put(ToolSchema.NAME_SPACE, this.namespace) - .put(ToolSchema.SCHEMA, normalizeSchema()) - .put(ToolSchema.RUNNABLE, normalizeRunnable()) - .put(ToolSchema.EXTENSIONS, this.extensions) - .build(); - } - - private Map normalizeSchema() { - List orderParameters = - this.parameterEntities.stream().map(ParameterEntity::getName).collect(Collectors.toList()); - Map schema = new LinkedHashMap<>(); - schema.put(ToolSchema.NAME, this.name); - schema.put(ToolSchema.DESCRIPTION, this.description); - if (this.extraParameters.isEmpty()) { - schema.put(ToolSchema.PARAMETERS, this.normalizeParameters(orderParameters)); - } else { - List fullParameters = new ArrayList<>(orderParameters); - fullParameters.removeAll(this.extraParameters); - schema.put(ToolSchema.PARAMETERS, this.normalizeParameters(fullParameters)); - schema.put(ToolSchema.EXTRA_PARAMETERS, this.normalizeParameters(this.extraParameters)); - } - schema.put(ToolSchema.PARAMETERS_ORDER, orderParameters); - Map returnDetails = new HashMap<>(JsonUtils.convertToMap(this.returnType)); - returnDetails.put(ToolSchema.RETURN_CONVERTER, this.returnConvertor); - if (this.returnDescription != null) { - returnDetails.put(ToolSchema.DESCRIPTION, this.returnDescription); - } - schema.put(ToolSchema.RETURN_SCHEMA, returnDetails); - return schema; - } - - private Map normalizeParameters(List includes) { - Map map = new LinkedHashMap<>(); - map.put(ToolSchema.PROPERTIES_TYPE, "object"); - Map variableInfo = new LinkedHashMap<>(); - Set requiredKey = new LinkedHashSet<>(); - for (ParameterEntity parameterEntity : this.parameterEntities) { - if (!includes.contains(parameterEntity.getName())) { - continue; - } - Map paramDetails = new LinkedHashMap<>(JsonUtils.convertToMap(parameterEntity.getType())); - if (parameterEntity.getDescription() != null) { - paramDetails.put(ToolSchema.DESCRIPTION, parameterEntity.getDescription()); - } - if (!parameterEntity.getDefaultValue().isEmpty()) { - paramDetails.put(ToolSchema.PARAMETER_DEFAULT_VALUE, parameterEntity.getDefaultValue()); - } - if (parameterEntity.isRequired()) { - requiredKey.add(parameterEntity.getName()); - } - variableInfo.put(parameterEntity.getName(), paramDetails); - } - map.put(ToolSchema.PARAMETERS_PROPERTIES, variableInfo); - map.put(ToolSchema.PARAMETERS_REQUIRED, requiredKey); - return map; - } - - private Map normalizeRunnable() { - Map fitInfo = MapBuilder.get() - .put("genericableId", this.genericableId) - .put("fitableId", this.fitableId) - .build(); - return MapBuilder.get().put("FIT", fitInfo).build(); - } -} \ No newline at end of file diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/parser/ByteBuddyToolParser.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/parser/ByteBuddyToolParser.java deleted file mode 100644 index 51ec814e..00000000 --- a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/parser/ByteBuddyToolParser.java +++ /dev/null @@ -1,175 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelenginei.jade.maven.complie.parser; - -import modelengine.fel.tool.annotation.Attribute; -import modelengine.fel.tool.annotation.ToolMethod; -import modelengine.fitframework.annotation.Fitable; -import modelengine.fitframework.annotation.Genericable; -import modelengine.fitframework.annotation.Property; -import modelengine.fitframework.inspection.Validation; -import modelengine.fitframework.jvm.classfile.ClassFile; -import modelenginei.jade.maven.complie.entity.ParameterEntity; -import modelenginei.jade.maven.complie.entity.ToolEntity; - -import net.bytebuddy.description.annotation.AnnotationDescription; -import net.bytebuddy.description.method.MethodDescription; -import net.bytebuddy.description.method.ParameterDescription; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.pool.TypePool; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -/** - * 基于 {@link net.bytebuddy.ByteBuddy} 对于 {@link ToolMethod} 注解的工具解析器。 - * - * @author 杭潇 - * @author 易文渊 - * @since 2024-06-12 - */ -public class ByteBuddyToolParser implements ToolParser { - private static final String DOT = "."; - - private final TypePool typePool; - private final String rootPath; - - public ByteBuddyToolParser(ClassLoader classLoader, String rootPath) { - this.typePool = TypePool.Default.of(classLoader); - this.rootPath = Paths.get(rootPath).normalize().toString(); - } - - @Override - public List parseTool(File classFile) { - String normalizedPath; - try { - normalizedPath = classFile.getCanonicalPath(); - } catch (IOException e) { - throw new IllegalStateException("Failed get class canonical path."); - } - if (!normalizedPath.startsWith(rootPath)) { - throw new IllegalStateException("The class not in root directory."); - } - String classFullName = normalizedPath.substring(rootPath.length() + 1, - normalizedPath.length() - ClassFile.FILE_EXTENSION.length()).replace(File.separator, DOT); - return this.parseMethodAnnotations(this.typePool.describe(classFullName).resolve()); - } - - private List parseMethodAnnotations(TypeDescription typeDescription) { - List tools = new ArrayList<>(); - for (MethodDescription.InDefinedShape methodDescription : typeDescription.getDeclaredMethods()) { - AnnotationDescription.Loadable toolAnnotation = - methodDescription.getDeclaredAnnotations().ofType(ToolMethod.class); - if (toolAnnotation == null) { - continue; - } - ToolMethod toolMethod = toolAnnotation.load(); - ToolEntity tool = new ToolEntity(); - tool.setNamespace(toolMethod.namespace()); - tool.setName(toolMethod.name()); - tool.setDescription(toolMethod.description()); - tool.setReturnType( - Validation.notNull(JacksonTypeParser.getParameterSchema(methodDescription.getReturnType()), - "The return type cannot be null.").toString()); - tool.setExtraParameters(Arrays.asList(toolMethod.extraParams())); - tool.setReturnConvertor(toolMethod.returnConverter()); - tool.setExtensions(parseAttributes(toolMethod)); - - AnnotationDescription.Loadable propertyAnnotation = - methodDescription.getDeclaredAnnotations().ofType(Property.class); - if (propertyAnnotation != null) { - tool.setReturnDescription(propertyAnnotation.load().description()); - } - tool.setParameterEntities(this.parseParameterAnnotations(methodDescription)); - this.parseRunnable(typeDescription, tool, methodDescription); - tools.add(tool); - } - return tools; - } - - private void parseRunnable(TypeDescription typeDescription, ToolEntity tool, - MethodDescription.InDefinedShape methodDescription) { - AnnotationDescription.Loadable fitableAnnotation = - methodDescription.getDeclaredAnnotations().ofType(Fitable.class); - if (fitableAnnotation == null) { - throw new IllegalArgumentException("The tool method must contained fitable."); - } - String fitableId = fitableAnnotation.load().value(); - tool.setFitableId(fitableId); - for (TypeDescription.Generic interfaceType : typeDescription.getInterfaces()) { - TypeDescription interfaceDescription = interfaceType.asErasure(); - Optional genericable = this.parseGenericable(methodDescription, interfaceDescription); - if (genericable.isPresent()) { - tool.setGenericableId(genericable.get()); - return; - } - } - throw new IllegalArgumentException("The tool method must contained genericable."); - } - - private List parseParameterAnnotations(MethodDescription.InDefinedShape methodDescription) { - List parameterEntities = new ArrayList<>(); - for (ParameterDescription.InDefinedShape parameterDescription : methodDescription.getParameters()) { - ParameterEntity entity = new ParameterEntity(); - entity.setType(Objects.requireNonNull(JacksonTypeParser.getParameterSchema(parameterDescription.getType())) - .toString()); - entity.setName(parameterDescription.getName()); - - AnnotationDescription.Loadable paramAnnotation = - parameterDescription.getDeclaredAnnotations().ofType(Property.class); - if (paramAnnotation != null) { - Property property = paramAnnotation.load(); - entity.setDescription(property.description()); - entity.setRequired(property.required()); - entity.setDefaultValue(property.defaultValue()); - } - - parameterEntities.add(entity); - } - return parameterEntities; - } - - private Optional parseGenericable(MethodDescription.InDefinedShape methodDescription, - TypeDescription interfaceDescription) { - for (MethodDescription.InDefinedShape interfaceMethod : interfaceDescription.getDeclaredMethods()) { - if (methodDescription.getName().equals(interfaceMethod.getName()) && methodDescription.getDescriptor() - .equals(interfaceMethod.getDescriptor())) { - AnnotationDescription.Loadable genericableAnnotation = - interfaceMethod.getDeclaredAnnotations().ofType(Genericable.class); - if (genericableAnnotation != null) { - return Optional.of(genericableAnnotation.load().value()); - } - } - } - return Optional.empty(); - } - - private Map> parseAttributes(ToolMethod toolMethod) { - Map> attributes = new HashMap<>(); - for (Attribute attribute : toolMethod.extensions()) { - String key = attribute.key(); - String value = attribute.value(); - - if (attributes.containsKey(key)) { - attributes.get(key).add(value); - } else { - List values = new ArrayList<>(); - values.add(value); - attributes.put(key, values); - } - } - return attributes; - } -} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/parser/ToolParser.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/parser/ToolParser.java deleted file mode 100644 index 6d73ec3e..00000000 --- a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/parser/ToolParser.java +++ /dev/null @@ -1,29 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelenginei.jade.maven.complie.parser; - -import modelenginei.jade.maven.complie.entity.ToolEntity; - -import java.io.File; -import java.nio.file.Path; -import java.util.List; - -/** - * 工具解析接口。 - * - * @author 杭潇 - * @since 2024-06-28 - */ -public interface ToolParser { - /** - * 基于 class 文件路径将工具注解的方法解析成 {@link ToolEntity}。 - * - * @param classFile 表示给定的 class 文件路径的 {@link Path}。 - * @return 表示解析完之后的 {@link List}{@code <}{@link ToolEntity}{@code >}。 - */ - List parseTool(File classFile); -} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/plugin/ToolPluginCompiler.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/plugin/ToolPluginCompiler.java deleted file mode 100644 index 107f2d6b..00000000 --- a/framework/fel/java/maven-plugins/tool-maven-plugin/src/main/java/modelenginei/jade/maven/complie/plugin/ToolPluginCompiler.java +++ /dev/null @@ -1,98 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelenginei.jade.maven.complie.plugin; - -import modelengine.fel.tool.ToolSchema; -import modelengine.fitframework.log.Logger; -import modelengine.fitframework.plugin.maven.support.AbstractCompiler; -import modelengine.fitframework.protocol.jar.Jar; -import modelengine.fitframework.util.FileUtils; -import modelenginei.jade.maven.complie.entity.ToolEntity; -import modelenginei.jade.maven.complie.parser.ByteBuddyToolParser; -import modelenginei.jade.maven.complie.parser.ToolParser; -import modelenginei.jade.maven.complie.util.JsonUtils; - -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.logging.Log; -import org.apache.maven.project.MavenProject; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * 为工具插件提供编译程序。 - * - * @author 杭潇 - * @author 易文渊 - * @since 2024-06-13 - */ -public class ToolPluginCompiler extends AbstractCompiler { - private static final Logger log = Logger.get(ToolPluginCompiler.class); - private static final String TOOLS = "tools"; - - ToolPluginCompiler(MavenProject project, Log log) { - super(project, log, null); - } - - @Override - protected void output(String outputDirectory, String fitRootDirectory) throws MojoExecutionException { - try (URLClassLoader classLoader = initURLClassLoader(outputDirectory)) { - List toolEntities = scanClassFiles(classLoader, outputDirectory); - this.outputToolManifest(outputDirectory, toolEntities); - } catch (IOException e) { - throw new MojoExecutionException("Failed to parse class files.", e); - } - } - - private URLClassLoader initURLClassLoader(String outputDirectory) throws IOException { - List urls = new ArrayList<>(); - try (Stream paths = Files.walk(Paths.get(outputDirectory, FIT_ROOT_DIRECTORY))) { - List files = paths.filter(Files::isRegularFile).map(Path::toFile).collect(Collectors.toList()); - for (File file : files) { - if (!FileUtils.isJar(file)) { - continue; - } - urls.add(Jar.from(file).location().toUrl()); - } - urls.add(Paths.get(outputDirectory).toUri().toURL()); - } - return new URLClassLoader(urls.toArray(new URL[0]), this.getClass().getClassLoader()); - } - - private List scanClassFiles(ClassLoader classLoader, String outputDirectory) throws IOException { - ToolParser toolParser = new ByteBuddyToolParser(classLoader, outputDirectory); - try (Stream paths = Files.walk(Paths.get(outputDirectory))) { - return paths.filter(Files::isRegularFile) - .map(Path::toFile) - .filter(FileUtils::isClass) - .flatMap(path -> toolParser.parseTool(path).stream()) - .collect(Collectors.toList()); - } - } - - private void outputToolManifest(String outputDirectory, List toolEntities) throws IOException { - if (toolEntities.isEmpty()) { - return; - } - File jsonFile = Paths.get(outputDirectory, ToolSchema.TOOL_MANIFEST).toFile(); - Map toolMap = new HashMap<>(); - toolMap.put(TOOLS, toolEntities.stream().map(ToolEntity::normalize).collect(Collectors.toList())); - JsonUtils.OBJECT_MAPPER.writeValue(jsonFile, toolMap); - log.info("Write tool json successfully. [file={}]", jsonFile.getName()); - } -} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/ByteBuddyGroupParserTest.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/ByteBuddyGroupParserTest.java new file mode 100644 index 00000000..8ddbb537 --- /dev/null +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/ByteBuddyGroupParserTest.java @@ -0,0 +1,53 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.jade.maven.compile.parser; + +import static org.assertj.core.api.Assertions.assertThat; + +import modelengine.fel.tool.info.entity.ToolJsonEntity; +import modelengine.fel.maven.complie.parser.ByteBuddyGroupParser; +import modelengine.fel.maven.complie.parser.GroupParser; +import modelengine.fel.maven.complie.plugin.UrlClassLoaderInitializer; + +import net.bytebuddy.pool.TypePool; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +/** + * 添加组解析的测试。 + * + * @author 杭潇 + * @author 曹嘉美 + * @since 2024-10-30 + */ +@DisplayName("测试 ByteBuddyGroupParserTest 类") +public class ByteBuddyGroupParserTest { + @Test + @DisplayName("解析class文件,生成出正确的json文件") + void givenClassesThenParseJsonSuccess() throws IOException { + String outputDirectory = Paths.get("").toAbsolutePath().resolve("target/test-classes").toString(); + String fitRootDirectory = ""; + UrlClassLoaderInitializer urlClassLoaderInitializer = new UrlClassLoaderInitializer(); + URLClassLoader urlClassLoader = urlClassLoaderInitializer.initUrlClassLoader(outputDirectory, fitRootDirectory); + GroupParser groupParser = new ByteBuddyGroupParser(TypePool.Default.of(urlClassLoader), outputDirectory); + ToolJsonEntity toolJsonEntity = groupParser.parseJson(outputDirectory); + urlClassLoaderInitializer.outputToolManifest(outputDirectory, toolJsonEntity); + Path correctJsonPath = + Paths.get("src/test/resources/weather-tools.json"); + Path testJsonPath = Paths.get("target/test-classes/tools.json"); + List correctJson = Files.readAllLines(correctJsonPath); + List testJson = Files.readAllLines(testJsonPath); + assertThat(correctJson).containsExactlyInAnyOrderElementsOf(testJson); + } +} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelenginei/jade/maven/complie/parser/JacksonTypeParserTest.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/JacksonTypeParserTest.java similarity index 85% rename from framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelenginei/jade/maven/complie/parser/JacksonTypeParserTest.java rename to framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/JacksonTypeParserTest.java index d5b17a15..7a238d9a 100644 --- a/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelenginei/jade/maven/complie/parser/JacksonTypeParserTest.java +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/JacksonTypeParserTest.java @@ -1,17 +1,18 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -package modelenginei.jade.maven.complie.parser; +package modelengine.jade.maven.compile.parser; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import com.fasterxml.jackson.databind.JsonNode; -import net.bytebuddy.description.type.TypeDescription; +import modelengine.fel.maven.complie.parser.JacksonTypeParser; + import net.bytebuddy.description.type.TypeDescription.Generic; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -49,7 +50,7 @@ void givenDateTypeSchemaThenParseSuccess() { @Test @DisplayName("解析数组类型数据,解析正确") void givenCollectionTypeSchemaThenParseSuccess() { - TypeDescription.Generic collectionType = Generic.Builder.parameterizedType(List.class, String.class).build(); + Generic collectionType = Generic.Builder.parameterizedType(List.class, String.class).build(); JsonNode schema = JacksonTypeParser.getParameterSchema(collectionType); assertTrue(schema.has("type")); assertEquals("array", schema.get("type").asText()); @@ -60,8 +61,7 @@ void givenCollectionTypeSchemaThenParseSuccess() { @Test @DisplayName("解析 Map 类型的数据,解析正确") void givenMapTypeSchemaThenParseSuccess() { - TypeDescription.Generic mapType = - Generic.Builder.parameterizedType(Map.class, String.class, Integer.class).build(); + Generic mapType = Generic.Builder.parameterizedType(Map.class, String.class, Integer.class).build(); JsonNode schema = JacksonTypeParser.getParameterSchema(mapType); assertTrue(schema.has("type")); assertEquals("object", schema.get("type").asText()); @@ -70,7 +70,7 @@ void givenMapTypeSchemaThenParseSuccess() { @Test @DisplayName("解析自定义数据,解析正确") void givenObjectTypeSchemaThenParseSuccess() { - TypeDescription.Generic objectType = Generic.OfNonGenericType.ForLoadedType.of(TestObject.class); + Generic objectType = Generic.OfNonGenericType.ForLoadedType.of(TestObject.class); JsonNode schema = JacksonTypeParser.getParameterSchema(objectType); assertTrue(schema.has("type")); assertEquals("object", schema.get("type").asText()); diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/weather/Rain.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/weather/Rain.java new file mode 100644 index 00000000..e4552806 --- /dev/null +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/weather/Rain.java @@ -0,0 +1,48 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.jade.maven.compile.parser.weather; + +import modelengine.fel.tool.annotation.Group; +import modelengine.fel.tool.annotation.ToolMethod; +import modelengine.fitframework.annotation.Genericable; +import modelengine.fitframework.annotation.Property; + + +import java.util.Date; + +/** + * 添加测试用的工具的定义。 + * + * @author 杭潇 + * @author 曹嘉美 + * @since 2024-10-26 + */ +@Group(name = "defGroup_weather_Rain", summary = "雨天", description = "下雨的定义组") +public interface Rain { + /** + * 获取今天下雨信息的结果。 + * + * @param location 获取下雨的地址信息的 {@link String}。 + * @param date 获取下雨日期的 {@link Date}。 + * @return 表示今日下雨信息的结果的 {@link String}。 + */ + @ToolMethod(name = "rain_today", description = "该方法获取今天的下雨信息") + @Genericable("genericable_weather_rain_today") + String today(@Property(description = "查询地点", required = true) String location, + @Property(description = "查询日期", required = true) Date date); + + /** + * 获取明天下雨信息的结果。 + * + * @param location 获取下雨的地址信息的 {@link String}。 + * @param date 获取下雨日期的 {@link Date}。 + * @return 表示明天下雨信息的结果的 {@link String}。 + */ + @ToolMethod(name = "rain_tomorrow", description = "该方法获取明天的下雨信息") + @Genericable("genericable_weather_rain_tomorrow") + String tomorrow(String location, Date date); +} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/weather/Wind.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/weather/Wind.java new file mode 100644 index 00000000..e556e0bc --- /dev/null +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/weather/Wind.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.jade.maven.compile.parser.weather; + +import modelengine.fel.tool.annotation.Group; +import modelengine.fel.tool.annotation.ToolMethod; +import modelengine.fitframework.annotation.Genericable; + +/** + * 添加测试用的工具的定义。 + * + * @author 杭潇 + * @author 曹嘉美 + * @since 2024-10-24 + */ +@Group(name = "defGroup_weather_Wind") +public interface Wind { + /** + * 获取今日的风量数据。 + * + * @param location 表示获取风量数据地址的 {@link String}。 + * @return 表示今日风量数据的 {@link String}。 + */ + @ToolMethod(name = "wind_today", description = "获取今日的风量数据") + @Genericable("weather_rain_today") + String today(String location); + + /** + * 获取明日的风量数据。 + * + * @param location 表示获取风量数据地址的 {@link String}。 + * @return 表示明日风量数据的 {@link String}。 + */ + @ToolMethod(name = "wind_tomorrow", description = "获取明日的风量数据") + @Genericable("weather_rain_tomorrow") + String tomorrow(String location); +} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/weather/impl/MobileRainImpl.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/weather/impl/MobileRainImpl.java new file mode 100644 index 00000000..56b544d5 --- /dev/null +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/weather/impl/MobileRainImpl.java @@ -0,0 +1,50 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.jade.maven.compile.parser.weather.impl; + +import modelengine.fel.tool.annotation.Attribute; +import modelengine.fel.tool.annotation.Group; +import modelengine.fel.tool.annotation.ToolMethod; +import modelengine.fitframework.annotation.Fitable; +import modelengine.fitframework.annotation.Property; +import modelengine.jade.maven.compile.parser.weather.Rain; + +import java.util.Date; + +/** + * 添加测试用的工具的实现。 + * + * @author 杭潇 + * @author 曹嘉美 + * @since 2024-10-26 + */ +@Group(name = "implGroup_weather_Rain_Mobile", extensions = { + @Attribute(key = "owner", value = "测试"), @Attribute(key = "language", value = "english") +}) +public class MobileRainImpl implements Rain { + private static final String FITABLE_ID = "weather_rain_mobile"; + + @Fitable(FITABLE_ID) + @ToolMethod(name = "mobile_rain_today", description = "使用A提供的今日下雨信息", extensions = { + @Attribute(key = "tags", value = "FIT"), @Attribute(key = "tags", value = "TEST") + }) + @Property(description = "获取今日下雨信息的结果") + @Override + public String today(String location, Date date) { + return null; + } + + @Fitable(FITABLE_ID) + @ToolMethod(name = "mobile_rain_tomorrow", description = "使用A提供的明日下雨信息", extensions = { + @Attribute(key = "tags", value = "FIT"), @Attribute(key = "tags", value = "TEST") + }) + @Property(description = "获取明日下雨信息的结果") + @Override + public String tomorrow(String location, Date date) { + return null; + } +} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/weather/impl/UnicomRainImpl.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/weather/impl/UnicomRainImpl.java new file mode 100644 index 00000000..a9acf1ec --- /dev/null +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelengine/jade/maven/compile/parser/weather/impl/UnicomRainImpl.java @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.jade.maven.compile.parser.weather.impl; + +import modelengine.fel.tool.annotation.Attribute; +import modelengine.fel.tool.annotation.Group; +import modelengine.fel.tool.annotation.ToolMethod; +import modelengine.fitframework.annotation.Fitable; +import modelengine.jade.maven.compile.parser.weather.Rain; + +import java.util.Date; + +/** + * 添加测试用的工具的实现。 + * + * @author 杭潇 + * @author 曹嘉美 + * @since 2024-10-26 + */ +@Group(name = "implGroup_weather_Rain_Unicom") +public class UnicomRainImpl implements Rain { + private static final String FITABLE_ID = "weather_rain_unicom"; + + @Fitable(FITABLE_ID) + @ToolMethod(name = "unicom_rain_today", description = "使用B提供的今日下雨信息", extensions = { + @Attribute(key = "tags", value = "FIT"), @Attribute(key = "tags", value = "TEST") + }) + @Override + public String today(String location, Date date) { + return null; + } + + @Fitable(FITABLE_ID) + @ToolMethod(name = "unicom_rain_tomorrow", description = "使用B提供的明日下雨信息", extensions = { + @Attribute(key = "tags", value = "FIT"), @Attribute(key = "tags", value = "TEST") + }) + @Override + public String tomorrow(String location, Date date) { + return null; + } +} diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelenginei/jade/maven/complie/entity/ToolEntityTest.java b/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelenginei/jade/maven/complie/entity/ToolEntityTest.java deleted file mode 100644 index 9637766b..00000000 --- a/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/java/modelenginei/jade/maven/complie/entity/ToolEntityTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelenginei.jade.maven.complie.entity; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import modelengine.fitframework.util.MapBuilder; -import modelengine.fitframework.util.ObjectUtils; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * 表示 {@link ToolEntity} 的单元测试。 - * - * @author 杭潇 - * @since 2024-08-05 - */ -@DisplayName("测试 ToolEntity 类") -class ToolEntityTest { - @Test - @DisplayName("测试 ToolEntity 标准化后数据正确") - void shouldOkWhenToolEntityNormalize() { - ToolEntity toolEntity = new ToolEntity(); - toolEntity.setNamespace("test"); - toolEntity.setName("testMethod"); - toolEntity.setDescription("This is a test method."); - toolEntity.setReturnDescription("Return description"); - toolEntity.setReturnType("{\"type\":\"string\"}"); - toolEntity.setFitableId("fitableId123"); - toolEntity.setGenericableId("genericableId123"); - toolEntity.setReturnConvertor(""); - toolEntity.setExtraParameters(Collections.emptyList()); - List list1 = new ArrayList<>(); - List list2 = new ArrayList<>(); - list1.add("v1"); - list2.add("v2"); - toolEntity.setExtensions(MapBuilder.>get().put("k1", list1).put("k2", list2).build()); - - Map result = toolEntity.normalize(); - Map schema = ObjectUtils.cast(result.get("schema")); - assertEquals("testMethod", schema.get("name")); - assertEquals("This is a test method.", schema.get("description")); - - Map runnables = ObjectUtils.cast(result.get("runnables")); - Map fit = ObjectUtils.cast(runnables.get("FIT")); - assertEquals("fitableId123", fit.get("fitableId")); - assertEquals("genericableId123", fit.get("genericableId")); - - Map returns = ObjectUtils.cast(schema.get("return")); - assertEquals("Return description", returns.get("description")); - assertEquals("", returns.get("converter")); - assertEquals("string", returns.get("type")); - - Map extensions = ObjectUtils.cast(result.get("extensions")); - assertEquals(list1, extensions.get("k1")); - assertEquals(list2, extensions.get("k2")); - } -} \ No newline at end of file diff --git a/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/resources/weather-tools.json b/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/resources/weather-tools.json new file mode 100644 index 00000000..13de6df1 --- /dev/null +++ b/framework/fel/java/maven-plugins/tool-maven-plugin/src/test/resources/weather-tools.json @@ -0,0 +1,240 @@ +{ + "version" : "1.0.0", + "definitionGroups" : [ { + "name" : "defGroup_weather_Rain", + "summary" : "雨天", + "description" : "下雨的定义组", + "extensions" : { }, + "definitions" : [ { + "schema" : { + "name" : "rain_today", + "description" : "该方法获取今天的下雨信息", + "parameters" : { + "type" : "object", + "properties" : { + "location" : { + "defaultValue" : "", + "description" : "查询地点", + "name" : "location", + "type" : "string", + "examples" : "", + "required" : true + }, + "date" : { + "defaultValue" : "", + "description" : "查询日期", + "name" : "date", + "type" : "string", + "examples" : "", + "required" : true + } + }, + "required" : [ "location", "date" ] + }, + "order" : [ "location", "date" ], + "return" : { + "type" : "string", + "convertor" : "" + } + } + }, { + "schema" : { + "name" : "rain_tomorrow", + "description" : "该方法获取明天的下雨信息", + "parameters" : { + "type" : "object", + "properties" : { + "location" : { + "name" : "location", + "type" : "string", + "required" : false + }, + "date" : { + "name" : "date", + "type" : "string", + "required" : false + } + }, + "required" : [ ] + }, + "order" : [ "location", "date" ], + "return" : { + "type" : "string", + "convertor" : "" + } + } + } ] + } ], + "toolGroups" : [ { + "name" : "implGroup_weather_Rain_Mobile", + "summary" : "", + "description" : "", + "extensions" : { + "owner" : [ "测试" ], + "language" : [ "english" ] + }, + "definitionGroupName" : "defGroup_weather_Rain", + "tools" : [ { + "namespace" : "Common", + "schema" : { + "name" : "mobile_rain_today", + "description" : "使用A提供的今日下雨信息", + "parameters" : { + "type" : "object", + "properties" : { + "location" : { + "name" : "location", + "type" : "string", + "required" : false + }, + "date" : { + "name" : "date", + "type" : "string", + "required" : false + } + }, + "required" : [ ] + }, + "order" : [ "location", "date" ], + "return" : { + "name" : "", + "description" : "获取今日下雨信息的结果", + "type" : "string", + "convertor" : "", + "examples" : "" + } + }, + "runnables" : { + "FIT" : { + "genericableId" : "genericable_weather_rain_today", + "fitableId" : "weather_rain_mobile" + } + }, + "extensions" : { + "tags" : [ "FIT", "TEST" ] + }, + "definitionName" : "rain_today" + }, { + "namespace" : "Common", + "schema" : { + "name" : "mobile_rain_tomorrow", + "description" : "使用A提供的明日下雨信息", + "parameters" : { + "type" : "object", + "properties" : { + "location" : { + "name" : "location", + "type" : "string", + "required" : false + }, + "date" : { + "name" : "date", + "type" : "string", + "required" : false + } + }, + "required" : [ ] + }, + "order" : [ "location", "date" ], + "return" : { + "name" : "", + "description" : "获取明日下雨信息的结果", + "type" : "string", + "convertor" : "", + "examples" : "" + } + }, + "runnables" : { + "FIT" : { + "genericableId" : "genericable_weather_rain_tomorrow", + "fitableId" : "weather_rain_mobile" + } + }, + "extensions" : { + "tags" : [ "FIT", "TEST" ] + }, + "definitionName" : "rain_tomorrow" + } ] + }, { + "name" : "implGroup_weather_Rain_Unicom", + "summary" : "", + "description" : "", + "extensions" : { }, + "definitionGroupName" : "defGroup_weather_Rain", + "tools" : [ { + "namespace" : "Common", + "schema" : { + "name" : "unicom_rain_today", + "description" : "使用B提供的今日下雨信息", + "parameters" : { + "type" : "object", + "properties" : { + "location" : { + "name" : "location", + "type" : "string", + "required" : false + }, + "date" : { + "name" : "date", + "type" : "string", + "required" : false + } + }, + "required" : [ ] + }, + "order" : [ "location", "date" ], + "return" : { + "type" : "string", + "convertor" : "" + } + }, + "runnables" : { + "FIT" : { + "genericableId" : "genericable_weather_rain_today", + "fitableId" : "weather_rain_unicom" + } + }, + "extensions" : { + "tags" : [ "FIT", "TEST" ] + }, + "definitionName" : "rain_today" + }, { + "namespace" : "Common", + "schema" : { + "name" : "unicom_rain_tomorrow", + "description" : "使用B提供的明日下雨信息", + "parameters" : { + "type" : "object", + "properties" : { + "location" : { + "name" : "location", + "type" : "string", + "required" : false + }, + "date" : { + "name" : "date", + "type" : "string", + "required" : false + } + }, + "required" : [ ] + }, + "order" : [ "location", "date" ], + "return" : { + "type" : "string", + "convertor" : "" + } + }, + "runnables" : { + "FIT" : { + "genericableId" : "genericable_weather_rain_tomorrow", + "fitableId" : "weather_rain_unicom" + } + }, + "extensions" : { + "tags" : [ "FIT", "TEST" ] + }, + "definitionName" : "rain_tomorrow" + } ] + } ] +} \ No newline at end of file diff --git a/framework/fel/java/plugins/tool-discoverer/src/main/java/modelengine/fel/tool/support/DefaultToolDiscoverer.java b/framework/fel/java/plugins/tool-discoverer/src/main/java/modelengine/fel/tool/support/DefaultToolDiscoverer.java index ec52d4cc..e2758cf7 100644 --- a/framework/fel/java/plugins/tool-discoverer/src/main/java/modelengine/fel/tool/support/DefaultToolDiscoverer.java +++ b/framework/fel/java/plugins/tool-discoverer/src/main/java/modelengine/fel/tool/support/DefaultToolDiscoverer.java @@ -9,7 +9,8 @@ import static modelengine.fitframework.inspection.Validation.isTrue; import static modelengine.fitframework.inspection.Validation.notNull; -import modelengine.fel.tool.ToolEntity; +import modelengine.fel.tool.DefaultToolEntity; +import modelengine.fel.tool.info.entity.ToolEntity; import modelengine.fel.tool.ToolSchema; import modelengine.fel.tool.service.ToolRepository; import modelengine.fitframework.annotation.Component; @@ -62,14 +63,14 @@ public DefaultToolDiscoverer(ToolRepository toolRepository, ObjectSerializer ser @Override public void onPluginStarted(Plugin plugin) { - this.scanTools(plugin).forEach(this.toolRepository::addTool); + this.scanTools(plugin).forEach(toolEntity -> this.toolRepository.addTool(new DefaultToolEntity(toolEntity))); } @Override public void onPluginStopping(Plugin plugin) { List toolEntities = this.scanTools(plugin); isTrue(toolEntities.size() < this.maxToolNum, "The tool num in plugin must less than {}", this.maxToolNum); - toolEntities.forEach(tool -> this.toolRepository.deleteTool(tool.namespace(), tool.name())); + toolEntities.forEach(tool -> this.toolRepository.deleteTool(tool.getNamespace(), tool.getSchema().getName())); } private List scanTools(Plugin plugin) { diff --git a/framework/fel/java/plugins/tool-executor/src/main/java/modelengine/fel/tool/support/DefaultToolExecutor.java b/framework/fel/java/plugins/tool-executor/src/main/java/modelengine/fel/tool/support/DefaultToolExecutor.java index c51dde62..544664b9 100644 --- a/framework/fel/java/plugins/tool-executor/src/main/java/modelengine/fel/tool/support/DefaultToolExecutor.java +++ b/framework/fel/java/plugins/tool-executor/src/main/java/modelengine/fel/tool/support/DefaultToolExecutor.java @@ -7,9 +7,11 @@ package modelengine.fel.tool.support; import static modelengine.fitframework.inspection.Validation.notNull; +import static modelengine.fitframework.util.ObjectUtils.cast; +import modelengine.fel.tool.DefaultToolEntity; import modelengine.fel.tool.Tool; -import modelengine.fel.tool.ToolEntity; +import modelengine.fel.tool.info.entity.ToolEntity; import modelengine.fel.tool.ToolFactory; import modelengine.fel.tool.ToolFactoryRepository; import modelengine.fel.tool.service.ToolExecuteService; @@ -80,7 +82,7 @@ public String execute(String uniqueName, Map jsonObject) { } private Tool getTool(String group, String toolName) { - ToolEntity tool = notNull(toolRepository.getTool(group, toolName), + DefaultToolEntity tool = notNull(toolRepository.getTool(group, toolName), () -> new IllegalStateException(StringUtils.format("The tool cannot be found. [group={0}, tool={1}]", group, toolName))); diff --git a/framework/fel/java/plugins/tool-executor/src/test/java/modelengine/fel/tool/support/DefaultToolExecutorTest.java b/framework/fel/java/plugins/tool-executor/src/test/java/modelengine/fel/tool/support/DefaultToolExecutorTest.java index a2ab2edc..1208ae26 100644 --- a/framework/fel/java/plugins/tool-executor/src/test/java/modelengine/fel/tool/support/DefaultToolExecutorTest.java +++ b/framework/fel/java/plugins/tool-executor/src/test/java/modelengine/fel/tool/support/DefaultToolExecutorTest.java @@ -15,8 +15,9 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import modelengine.fel.tool.DefaultToolEntity; import modelengine.fel.tool.Tool; -import modelengine.fel.tool.ToolEntity; +import modelengine.fel.tool.info.entity.ToolEntity; import modelengine.fel.tool.ToolFactory; import modelengine.fel.tool.ToolFactoryRepository; import modelengine.fel.tool.ToolSchema; @@ -68,7 +69,7 @@ void tearDown() { @Test @DisplayName("调用工具成功返回结果") void shouldOkWhenExecuteTool() throws IOException { - ToolEntity toolEntity = getTestEntity(); + DefaultToolEntity toolEntity = getTestEntity(); when(this.toolRepository.getTool(any(), eq(toolEntity.name()))).thenReturn(toolEntity); when(this.toolFactoryRepository.match(any())).thenReturn(Optional.of(this.toolFactory)); Tool tool = mock(Tool.class, RETURNS_DEEP_STUBS); @@ -94,7 +95,7 @@ void shouldFailWhenToolNotFound() { @Test @DisplayName("工具工厂不存在,调用失败") void shouldFailWhenToolFactoryNotFound() throws IOException { - ToolEntity toolEntity = getTestEntity(); + DefaultToolEntity toolEntity = getTestEntity(); when(this.toolRepository.getTool(any(), any())).thenReturn(toolEntity); when(this.toolFactoryRepository.match(any())).thenReturn(Optional.empty()); @@ -105,12 +106,12 @@ void shouldFailWhenToolFactoryNotFound() throws IOException { "test")).isInstanceOf(IllegalStateException.class); } - private ToolEntity getTestEntity() throws IOException { + private DefaultToolEntity getTestEntity() throws IOException { List toolEntities = this.serializer.>>deserialize(IoUtils.content(this.getClass().getClassLoader(), ToolSchema.TOOL_MANIFEST), TypeUtils.parameterized(Map.class, new Type[] { String.class, TypeUtils.parameterized(List.class, new Type[] {ToolEntity.class}) })).get("tools"); - return toolEntities.get(0); + return new DefaultToolEntity(toolEntities.get(0)); } } \ No newline at end of file diff --git a/framework/fel/java/plugins/tool-repository-simple/src/main/java/modelengine/fel/tool/support/SimpleToolRepository.java b/framework/fel/java/plugins/tool-repository-simple/src/main/java/modelengine/fel/tool/support/SimpleToolRepository.java index d1e108e7..4f409976 100644 --- a/framework/fel/java/plugins/tool-repository-simple/src/main/java/modelengine/fel/tool/support/SimpleToolRepository.java +++ b/framework/fel/java/plugins/tool-repository-simple/src/main/java/modelengine/fel/tool/support/SimpleToolRepository.java @@ -9,7 +9,8 @@ import static modelengine.fitframework.inspection.Validation.notBlank; import modelengine.fel.core.tool.ToolInfo; -import modelengine.fel.tool.ToolEntity; +import modelengine.fel.tool.DefaultToolEntity; +import modelengine.fel.tool.info.entity.ToolEntity; import modelengine.fel.tool.service.ToolRepository; import modelengine.fitframework.annotation.Component; import modelengine.fitframework.log.Logger; @@ -30,10 +31,10 @@ public class SimpleToolRepository implements ToolRepository { private static final Logger log = Logger.get(SimpleToolRepository.class); - private final Map toolCache = new ConcurrentHashMap<>(); + private final Map toolCache = new ConcurrentHashMap<>(); @Override - public void addTool(ToolEntity tool) { + public void addTool(DefaultToolEntity tool) { if (tool == null) { return; } @@ -53,7 +54,7 @@ public void deleteTool(String namespace, String toolName) { } @Override - public ToolEntity getTool(String namespace, String toolName) { + public DefaultToolEntity getTool(String namespace, String toolName) { notBlank(namespace, "The namespace cannot be blank."); notBlank(toolName, "The toll name cannot be blank."); String uniqueName = ToolInfo.identify(namespace, toolName); @@ -61,7 +62,7 @@ public ToolEntity getTool(String namespace, String toolName) { } @Override - public List listTool(String namespace) { + public List listTool(String namespace) { notBlank(namespace, "The namespace cannot be blank."); return toolCache.entrySet() .stream() diff --git a/framework/fel/java/pom.xml b/framework/fel/java/pom.xml index fa77a829..53dc75cf 100644 --- a/framework/fel/java/pom.xml +++ b/framework/fel/java/pom.xml @@ -36,6 +36,7 @@ + components fel-community fel-core fel-flow diff --git a/framework/fel/java/services/tool-service/pom.xml b/framework/fel/java/services/tool-service/pom.xml index e28c33ee..2d2d5e6b 100644 --- a/framework/fel/java/services/tool-service/pom.xml +++ b/framework/fel/java/services/tool-service/pom.xml @@ -32,6 +32,12 @@ fel-core + + com.fasterxml.jackson.core + jackson-annotations + 2.16.2 + + org.fitframework diff --git a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/ToolEntity.java b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/DefaultToolEntity.java similarity index 57% rename from framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/ToolEntity.java rename to framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/DefaultToolEntity.java index 03b2e287..da577990 100644 --- a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/ToolEntity.java +++ b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/DefaultToolEntity.java @@ -9,6 +9,7 @@ import static modelengine.fitframework.inspection.Validation.notNull; import static modelengine.fitframework.util.ObjectUtils.cast; +import modelengine.fel.tool.info.entity.ToolEntity; import modelengine.fitframework.inspection.Nonnull; import modelengine.fitframework.util.StringUtils; @@ -20,61 +21,51 @@ * @author 易文渊 * @since 2024-08-14 */ -public class ToolEntity implements Tool.Info { - private String namespace; - private Map schema; - private Map runnables; - private Map extensions; +public class DefaultToolEntity implements Tool.Info { + private ToolEntity toolEntity; /** * 默认构造函数。 */ - public ToolEntity() {} + public DefaultToolEntity() {} /** * 创建 {@link ToolEntity} 的实例。 * - * @param namespace 表示工具命名空间的 {@link String}。 - * @param schema 表示工具格式规范描述的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 - * @param runnables 表示工具运行规范的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 - * @param extensions 表示工具额外参数规范的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 + * @param toolEntity 表示工具实体类的 {@link ToolEntity}。 */ - public ToolEntity(String namespace, Map schema, Map runnables, - Map extensions) { - this.namespace = notNull(namespace, "The namespace cannot be null."); - this.schema = notNull(schema, "The schema cannot be null."); - this.runnables = notNull(runnables, "The runnables cannot be null."); - this.extensions = notNull(extensions, "The extensions cannot be null."); + public DefaultToolEntity(ToolEntity toolEntity) { + this.toolEntity = toolEntity; } @Nonnull @Override public String namespace() { - return this.namespace; + return this.toolEntity.getNamespace(); } @Nonnull @Override public String name() { - return cast(this.schema.get(ToolSchema.NAME)); + return this.toolEntity.getSchema().getName(); } @Nonnull @Override public String description() { - return cast(this.schema.get(ToolSchema.DESCRIPTION)); + return this.toolEntity.getSchema().getDescription(); } @Nonnull @Override public Map parameters() { - return cast(this.schema.get(ToolSchema.PARAMETERS)); + return this.toolEntity.parameters(); } @Nonnull @Override public Map extensions() { - return this.extensions; + return this.toolEntity.getExtensions(); } @Override @@ -99,12 +90,12 @@ public String definitionGroupName() { @Override public Map schema() { - return this.schema; + return this.toolEntity.schema(); } @Override public Map runnables() { - return this.runnables; + return this.toolEntity.getRunnables(); } @Override diff --git a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/DefinitionEntity.java b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/DefinitionEntity.java new file mode 100644 index 00000000..cb839708 --- /dev/null +++ b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/DefinitionEntity.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.tool.info.entity; + +/** + * 表示定义的实体类,用于存储定义信息。 + * + * @author 曹嘉美 + * @author 李金绪 + * @since 2024-10-26 + */ +public class DefinitionEntity { + private SchemaEntity schema; + + /** + * 获取 schema 对象。 + * + * @return 表示 schema 对象的 {@link SchemaEntity}。 + */ + public SchemaEntity getSchema() { + return this.schema; + } + + /** + * 设置 schema 对象。 + * + * @param schema 表示 schema 对象的 {@link SchemaEntity}。 + */ + public void setSchema(SchemaEntity schema) { + this.schema = schema; + } +} diff --git a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/DefinitionGroupEntity.java b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/DefinitionGroupEntity.java new file mode 100644 index 00000000..1146c5f4 --- /dev/null +++ b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/DefinitionGroupEntity.java @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.tool.info.entity; + +import java.util.List; + +/** + * 表示定义组的实体类。 + * + * @author 曹嘉美 + * @author 李金绪 + * @since 2024-10-26 + */ +public class DefinitionGroupEntity extends GroupEntity { + private List definitions; + + /** + * 获取定义组中的所有定义。 + * + * @return 表示定义组的 {@link List}{@code <}{@link DefinitionEntity}{@code >}。 + */ + public List getDefinitions() { + return this.definitions; + } + + /** + * 设置定义组中的所有定义。 + * + * @param definitions 表示定义组的 {@link List}{@code <}{@link DefinitionEntity}{@code >}。 + */ + public void setDefinitions(List definitions) { + this.definitions = definitions; + } +} diff --git a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/GroupEntity.java b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/GroupEntity.java new file mode 100644 index 00000000..48853b6e --- /dev/null +++ b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/GroupEntity.java @@ -0,0 +1,94 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.tool.info.entity; + +import java.util.Map; + +/** + * 表示组的基本实体类。 + * + * @author 李金绪 + * @since 2024-12-12 + */ +public class GroupEntity { + private String name; + private String summary; + private String description; + private Map extensions; + + /** + * 获取组名。 + * + * @return 表示组名的 {@link String}。 + */ + public String getName() { + return this.name; + } + + /** + * 设置组名。 + * + * @param name 表示组名的 {@link String}。 + */ + public void setName(String name) { + this.name = name; + } + + /** + * 获取摘要。 + * + * @return 表示摘要的 {@link String}。 + */ + public String getSummary() { + return this.summary; + } + + /** + * 设置摘要 + * + * @param summary 表示要设置的摘要的 {@link String}。 + */ + public void setSummary(String summary) { + this.summary = summary; + } + + /** + * 获取描述。 + * + * @return 表示描述的 {@link String}。 + */ + public String getDescription() { + return this.description; + } + + /** + * 设置描述。 + * + * @param description 表示要设置的描述的 {@link String}。 + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * 获取扩展属性。 + * + * @return 表示扩展属性的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 + */ + public Map getExtensions() { + return this.extensions; + } + + /** + * 设置扩展属性。 + * + * @param extensions 扩展属性的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 + */ + public void setExtensions(Map extensions) { + this.extensions = extensions; + } +} diff --git a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/HttpJsonEntity.java b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/HttpJsonEntity.java new file mode 100644 index 00000000..bbe62ae7 --- /dev/null +++ b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/HttpJsonEntity.java @@ -0,0 +1,130 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.tool.info.entity; + +/** + * 表示 http 插件的 json 实体。 + * + * @author 李金绪 + * @since 2024-11-05 + */ +public class HttpJsonEntity extends ToolJsonEntity { + /** + * 表示工具的名称。 + */ + private String name; + + /** + * 表示工具的来源。 + */ + private String source; + + /** + * 表示工具的图标。 + */ + private String icon; + + /** + * 表示工具的创建者。 + */ + private String creator; + + /** + * 表示工具的修改者。 + */ + private String modifier; + + /** + * 获取工具的来源。 + * + * @return 表示工具的来源的 {@link String}。 + */ + public String getSource() { + return this.source; + } + + /** + * 设置工具的来源。 + * + * @param source 表示工具的来源的 {@link String}。 + */ + public void setSource(String source) { + this.source = source; + } + + /** + * 获取工具的图标。 + * + * @return 表示工具的图标的 {@link String}。 + */ + public String getIcon() { + return this.icon; + } + + /** + * 设置工具的图标。 + * + * @param icon 表示工具的图标的 {@link String}。 + */ + public void setIcon(String icon) { + this.icon = icon; + } + + /** + * 获取工具的创建者。 + * + * @return 表示工具的创建者的 {@link String}。 + */ + public String getCreator() { + return this.creator; + } + + /** + * 设置工具的创建者。 + * + * @param creator 表示工具的创建者的 {@link String}。 + */ + public void setCreator(String creator) { + this.creator = creator; + } + + /** + * 获取工具的修改者。 + * + * @return 表示工具的修改者的 {@link String}。 + */ + public String getModifier() { + return this.modifier; + } + + /** + * 设置工具的修改者。 + * + * @param modifier 表示工具的修改者的 {@link String}。 + */ + public void setModifier(String modifier) { + this.modifier = modifier; + } + + /** + * 获取工具的名称。 + * + * @return 表示工具的名称的 {@link String}。 + */ + public String getName() { + return this.name; + } + + /** + * 设置工具的名称。 + * + * @param name 表示工具的名称的 {@link String}。 + */ + public void setName(String name) { + this.name = name; + } +} diff --git a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/ParameterEntity.java b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/ParameterEntity.java new file mode 100644 index 00000000..19207184 --- /dev/null +++ b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/ParameterEntity.java @@ -0,0 +1,77 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.tool.info.entity; + +import java.util.List; +import java.util.Map; + +/** + * 表示参数的实体类。 + * + * @author 曹嘉美 + * @author 李金绪 + * @since 2024-10-26 + */ +public class ParameterEntity { + private String type; + private Map properties; + private List required; + + /** + * 获取参数类型。 + * + * @return 表示参数类型的 {@link String}。 + */ + public String getType() { + return this.type; + } + + /** + * 设置参数类型。 + * + * @param type 表示参数类型的 {@link String}。 + */ + public void setType(String type) { + this.type = type; + } + + /** + * 获取参数的属性。 + * + * @return 表示参数属性的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 + */ + public Map getProperties() { + return this.properties; + } + + /** + * 设置参数的属性。 + * + * @param properties 表示参数属性的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 + */ + public void setProperties(Map properties) { + this.properties = properties; + } + + /** + * 获取参数的必填项。 + * + * @return 表示参数必填项的 {@link List}{@code <}{@link String}{@code >}。 + */ + public List getRequired() { + return this.required; + } + + /** + * 设置参数的必填项。 + * + * @param required 表示参数必填项的 {@link List}{@code <}{@link String}{@code >}。 + */ + public void setRequired(List required) { + this.required = required; + } +} diff --git a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/PluginJsonEntity.java b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/PluginJsonEntity.java new file mode 100644 index 00000000..f99efda5 --- /dev/null +++ b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/PluginJsonEntity.java @@ -0,0 +1,113 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.tool.info.entity; + +import java.util.Map; + +/** + * 用于 plugin.json 的序列化与反序列化的实体类。 + * + * @author 李金绪 + * @since 2024-10-28 + */ +public class PluginJsonEntity { + private String checksum; + private String name; + private String description; + private String type; + private Map uniqueness; + + /** + * 获取插件的校验和。 + * + * @return 表示校验和的 {@link String}。 + */ + public String getChecksum() { + return this.checksum; + } + + /** + * 设置插件的校验和。 + * + * @param checksum 表示校验和的 {@link String}。 + */ + public void setChecksum(String checksum) { + this.checksum = checksum; + } + + /** + * 获取插件的名称。 + * + * @return 表示插件名称的 {@link String}。 + */ + public String getName() { + return this.name; + } + + /** + * 设置插件的名称。 + * + * @param name 表示插件名称的 {@link String}。 + */ + public void setName(String name) { + this.name = name; + } + + /** + * 获取插件的描述信息。 + * + * @return 表示插件描述信息的 {@link String}。 + */ + public String getDescription() { + return this.description; + } + + /** + * 设置插件的描述信息。 + * + * @param description 表示插件描述信息的 {@link String}。 + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * 获取插件的唯一性信息。 + * + * @return 表示插件唯一性信息的 {@link Map}{@code <}{@link String}{@code , }{@link String}{@code >}。 + */ + public Map getUniqueness() { + return this.uniqueness; + } + + /** + * 设置插件的唯一性信息。 + * + * @param uniqueness 表示插件唯一性信息的 {@link Map}{@code <}{@link String}{@code , }{@link String}{@code >}。 + */ + public void setUniqueness(Map uniqueness) { + this.uniqueness = uniqueness; + } + + /** + * 获取插件的类型。 + * + * @return 表示插件类型的 {@link String}。 + */ + public String getType() { + return this.type; + } + + /** + * 设置插件的类型。 + * + * @param type 表示插件类型的 {@link String}。 + */ + public void setType(String type) { + this.type = type; + } +} diff --git a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/PropertyEntity.java b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/PropertyEntity.java new file mode 100644 index 00000000..8ed4261d --- /dev/null +++ b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/PropertyEntity.java @@ -0,0 +1,169 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.tool.info.entity; + +/** + * 表示参数属性的实体类。 + * + * @author 曹嘉美 + * @author 李金绪 + * @since 2024-10-26 + */ +public class PropertyEntity { + private String defaultValue; + private String description; + private boolean isRequired; + private String name; + private String type; + private Object items; + private Object properties; + private String examples; + + /** + * 获取参数的默认值。 + * + * @return 表示参数的默认值的 {@link String}。 + */ + public String getDefaultValue() { + return this.defaultValue; + } + + /** + * 设置参数的默认值。 + * + * @param defaultValue 表示参数的默认值的 {@link String}。 + */ + public void setDefaultValue(String defaultValue) { + this.defaultValue = defaultValue; + } + + /** + * 获取参数的描述信息。 + * + * @return 表示参数的描述信息的 {@link String}。 + */ + public String getDescription() { + return this.description; + } + + /** + * 设置参数的描述信息。 + * + * @param description 表示参数的描述信息的 {@link String}。 + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * 获取参数是否是必需的标志。 + * + * @return 如果参数是必需的,则返回 {@code true},否则返回 {@code false}。 + */ + public boolean isRequired() { + return this.isRequired; + } + + /** + * 设置参数是否是必需的标志。 + * + * @param required 表示参数是否是必需的 {@link boolean}。 + */ + public void setRequired(boolean required) { + this.isRequired = required; + } + + /** + * 获取参数的名称。 + * + * @return 表示参数的名称的 {@link String}。 + */ + public String getName() { + return this.name; + } + + /** + * 设置参数的名称。 + * + * @param name 表示参数的名称的 {@link String}。 + */ + public void setName(String name) { + this.name = name; + } + + /** + * 获取参数的类型。 + * + * @return 表示参数的类型的 {@link String}。 + */ + public String getType() { + return this.type; + } + + /** + * 设置参数的类型。 + * + * @param type 表示参数的类型的 {@link String}。 + */ + public void setType(String type) { + this.type = type; + } + + /** + * 获取参数的子类型。 + * + * @return 表示参数的子类型的 {@link Object}。 + */ + public Object getItems() { + return items; + } + + /** + * 设置参数的子类型。 + * + * @param items 表示参数的子类型的 {@link Object}。 + */ + public void setItems(Object items) { + this.items = items; + } + + /** + * 获取参数的属性。 + * + * @return 表示参数的属性的 {@link Object}。 + */ + public Object getProperties() { + return properties; + } + + /** + * 设置参数的属性。 + * + * @param properties 表示参数的属性的 {@link Object}。 + */ + public void setProperties(Object properties) { + this.properties = properties; + } + + /** + * 获取参数的示例值。 + * + * @return 表示参数的示例值的 {@link String}。 + */ + public String getExamples() { + return this.examples; + } + + /** + * 设置参数的示例值。 + * + * @param examples 表示参数的示例值的 {@link String}。 + */ + public void setExamples(String examples) { + this.examples = examples; + } +} diff --git a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/ReturnPropertyEntity.java b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/ReturnPropertyEntity.java new file mode 100644 index 00000000..eac6c2e4 --- /dev/null +++ b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/ReturnPropertyEntity.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.tool.info.entity; + +/** + * 表示方法返回的参数的属性类。 + * + * @author 曹嘉美 + * @author 李金绪 + * @since 2024-10-26 + */ +public class ReturnPropertyEntity extends PropertyEntity { + private String convertor; + + /** + * 获取转换器的名称。 + * + * @return 表示转换器的名称的 {@link String}。 + */ + public String getConvertor() { + return this.convertor; + } + + /** + * 设置转换器的名称。 + * + * @param convertor 表示转换器的名称的 {@link String}。 + */ + public void setConvertor(String convertor) { + this.convertor = convertor; + } +} diff --git a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/SchemaEntity.java b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/SchemaEntity.java new file mode 100644 index 00000000..985042dd --- /dev/null +++ b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/SchemaEntity.java @@ -0,0 +1,140 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.tool.info.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import modelengine.fitframework.annotation.Property; + +import java.util.List; +import java.util.Map; + +/** + * 表示定义组和实现组的结构类。 + * + * @author 曹嘉美 + * @author 李金绪 + * @since 2024-10-26 + */ +public class SchemaEntity { + private String name; + private String description; + private ParameterEntity parameters; + private List order; + @JsonProperty("return") + @Property(name = "return") + private Map ret; + private Map parameterExtensions; + + /** + * 获取结构的名称。 + * + * @return 表示结构的名称的 {@link String}。 + */ + public String getName() { + return this.name; + } + + /** + * 设置结构的名称。 + * + * @param name 表示结构的名称的 {@link String}。 + */ + public void setName(String name) { + this.name = name; + } + + /** + * 获取结构的描述。 + * + * @return 表示结构的描述的 {@link String}。 + */ + public String getDescription() { + return this.description; + } + + /** + * 设置结构的描述。 + * + * @param description 表示结构的描述的 {@link String}。 + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * 获取结构的参数。 + * + * @return 表示结构的参数的 {@link ParameterEntity}。 + */ + public ParameterEntity getParameters() { + return this.parameters; + } + + /** + * 设置结构的参数。 + * + * @param parameters 表示结构的参数的 {@link ParameterEntity}。 + */ + public void setParameters(ParameterEntity parameters) { + this.parameters = parameters; + } + + /** + * 获取参数的执行顺序。 + * + * @return 表示参数的执行顺序的 {@link List}{@code <}{@link String}{@code >}。 + */ + public List getOrder() { + return this.order; + } + + /** + * 设置参数的执行顺序。 + * + * @param order 表示参数的执行顺序的 {@link List}{@code <}{@link String}{@code >}。 + */ + public void setOrder(List order) { + this.order = order; + } + + /** + * 获取方法的返回值。 + * + * @return 表示方法的返回值的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 + */ + public Map getRet() { + return this.ret; + } + + /** + * 设置方法的返回值。 + * + * @param ret 表示方法的返回值的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 + */ + public void setRet(Map ret) { + this.ret = ret; + } + + /** + * 获取扩展参数的信息。 + * + * @return 表示扩展参数的信息的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 + */ + public Map getParameterExtensions() { + return this.parameterExtensions; + } + + /** + * 设置扩展参数的信息。 + * + * @param parameterExtensions 表示扩展参数的信息的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 + */ + public void setParameterExtensions(Map parameterExtensions) { + this.parameterExtensions = parameterExtensions; + } +} diff --git a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/ToolEntity.java b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/ToolEntity.java new file mode 100644 index 00000000..0fca45d2 --- /dev/null +++ b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/ToolEntity.java @@ -0,0 +1,162 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.tool.info.entity; + +import static modelengine.fitframework.util.ObjectUtils.cast; + +import modelengine.fel.tool.Tool; +import modelengine.fel.tool.ToolSchema; +import modelengine.fitframework.inspection.Nonnull; +import modelengine.fitframework.util.StringUtils; + +import java.util.List; +import java.util.Map; +import java.util.HashMap; + +/** + * 表示工具的实体类。 + * + * @author 曹嘉美 + * @author 李金绪 + * @since 2024-10-26 + */ +public class ToolEntity { + private String namespace; + private SchemaEntity schema; + private Map runnables; + private Map extensions; + private List tags; + private String definitionName; + + /** + * 获取 schema 对象。 + * + * @return 表示 schema 对象的 {@link SchemaEntity}。 + */ + public SchemaEntity getSchema() { + return this.schema; + } + + /** + * 设置 schema 对象。 + * + * @param schema 表示 schema 对象的 {@link SchemaEntity}。 + */ + public void setSchema(SchemaEntity schema) { + this.schema = schema; + } + + /** + * 获取 runnables 对象。 + * + * @return 表示 runnables 对象的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 + */ + public Map getRunnables() { + return this.runnables; + } + + /** + * 设置 runnables 对象。 + * + * @param runnables 表示 runnables 对象的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 + */ + + public void setRunnables(Map runnables) { + this.runnables = runnables; + } + + /** + * 获取扩展信息。 + * + * @return 表示扩展信息的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 + */ + public Map getExtensions() { + return this.extensions; + } + + /** + * 设置扩展信息。 + * + * @param extensions 表示扩展信息的 {@link Map}{@code <}{@link String}{@code , }{@link Object}{@code >}。 + */ + public void setExtensions(Map extensions) { + this.extensions = extensions; + } + + /** + * 获取标签列表。 + * + * @return 表示标签列表的 {@link List}{@code <}{@link String}{@code >}。 + */ + public List getTags() { + return this.tags; + } + + /** + * 设置标签列表。 + * + * @param tags 表示标签列表的 {@link List}{@code <}{@link String}{@code >}。 + */ + public void setTags(List tags) { + this.tags = tags; + } + + /** + * 获取工具的名称。 + * + * @return 表示工具名称的 {@link String}。 + */ + public String getDefinitionName() { + return this.definitionName; + } + + /** + * 设置工具的名称。 + * + * @param definitionName 表示工具名称的 {@link String}。 + */ + public void setDefinitionName(String definitionName) { + this.definitionName = definitionName; + } + + /** + * 获取工具的命名空间。 + * + * @return 表示工具命名空间的 {@link String}。 + */ + public String getNamespace() { + return this.namespace; + } + + /** + * + * @param namespace + */ + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public Map parameters() { + Map paramsMap = new HashMap<>(); + ParameterEntity paramEntity = this.schema.getParameters(); + paramsMap.put("type", paramEntity.getType()); + paramsMap.put("properties", paramEntity.getProperties()); + paramsMap.put("required", paramEntity.getRequired()); + return paramsMap; + } + + public Map schema() { + Map schemaMap = new HashMap<>(); + schemaMap.put("name", this.schema.getName()); + schemaMap.put("description", this.schema.getDescription()); + schemaMap.put("parameters", this.parameters()); + schemaMap.put("order", this.schema.getOrder()); + schemaMap.put("return", this.schema.getRet()); + schemaMap.put("parameterExtensions", this.schema.getParameterExtensions()); + return schemaMap; + } +} diff --git a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/ToolGroupEntity.java b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/ToolGroupEntity.java new file mode 100644 index 00000000..4fcadfb9 --- /dev/null +++ b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/ToolGroupEntity.java @@ -0,0 +1,57 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.tool.info.entity; + +import java.util.List; + +/** + * 表示实现组的实体类。 + * + * @author 曹嘉美 + * @author 李金绪 + * @since 2024-10-26 + */ +public class ToolGroupEntity extends GroupEntity { + private String definitionGroupName; + private List tools; + + /** + * 获取定义组名称。 + * + * @return 表示定义组名称的 {@link String}。 + */ + public String getDefinitionGroupName() { + return this.definitionGroupName; + } + + /** + * 设置定义组名称。 + * + * @param definitionGroupName 表示定义组名称的 {@link String}。 + */ + public void setDefinitionGroupName(String definitionGroupName) { + this.definitionGroupName = definitionGroupName; + } + + /** + * 获取工具列表。 + * + * @return 表示工具列表的 {@link List}{@code <}{@link ToolEntity}{@code >}。 + */ + public List getTools() { + return this.tools; + } + + /** + * 设置工具列表。 + * + * @param tools 表示工具列表的 {@link List}{@code <}{@link ToolEntity}{@code >}。 + */ + public void setTools(List tools) { + this.tools = tools; + } +} diff --git a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/ToolJsonEntity.java b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/ToolJsonEntity.java new file mode 100644 index 00000000..57e18a5d --- /dev/null +++ b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/info/entity/ToolJsonEntity.java @@ -0,0 +1,76 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fel.tool.info.entity; + +import java.util.List; + +/** + * 用于 tools.json 的序列化与反序列化的实体类。 + * + * @author 曹嘉美 + * @since 2024-10-26 + */ +public class ToolJsonEntity { + private String version; + private List definitionGroups; + private List toolGroups; + + /** + * 获取工具版本信息。 + * + * @return 表示工具版本信息的 {@link String}。 + */ + public String getVersion() { + return this.version; + } + + /** + * 设置工具版本信息。 + * + * @param version 表示工具版本信息的 {@link String}。 + */ + public void setVersion(String version) { + this.version = version; + } + + /** + * 获取定义组列表。 + * + * @return 表示定义组列表的 {@link List}{@code <}{@link DefinitionGroupEntity}{@code >}。 + */ + public List getDefinitionGroups() { + return this.definitionGroups; + } + + /** + * 设置定义组列表。 + * + * @param definitionGroups 表示定义组列表的 {@link List}{@code <}{@link DefinitionGroupEntity}{@code >}。 + */ + public void setDefinitionGroups(List definitionGroups) { + this.definitionGroups = definitionGroups; + } + + /** + * 获取工具组列表。 + * + * @return 表示工具组列表的 {@link List}{@code <}{@link ToolGroupEntity}{@code >}。 + */ + public List getToolGroups() { + return this.toolGroups; + } + + /** + * 设置工具组列表。 + * + * @param toolGroups 表示工具组列表的 {@link List}{@code <}{@link ToolGroupEntity}{@code >}。 + */ + public void setToolGroups(List toolGroups) { + this.toolGroups = toolGroups; + } +} + diff --git a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/service/ToolRepository.java b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/service/ToolRepository.java index c3c1a15c..9a14973d 100644 --- a/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/service/ToolRepository.java +++ b/framework/fel/java/services/tool-service/src/main/java/modelengine/fel/tool/service/ToolRepository.java @@ -6,7 +6,7 @@ package modelengine.fel.tool.service; -import modelengine.fel.tool.ToolEntity; +import modelengine.fel.tool.DefaultToolEntity; import modelengine.fitframework.annotation.Genericable; import java.util.List; @@ -21,10 +21,10 @@ public interface ToolRepository { /** * 添加工具。 * - * @param tool 表示待增加的工具信息的 {@link ToolEntity}。 + * @param tool 表示待增加的工具信息的 {@link DefaultToolEntity}。 */ @Genericable(id = "modelengine.fel.tool.add") - void addTool(ToolEntity tool); + void addTool(DefaultToolEntity tool); /** * 删除工具。 @@ -40,17 +40,17 @@ public interface ToolRepository { * * @param namespace 表示工具命名空间的 {@link String}。 * @param toolName 表示工具名称的 {@link String}。 - * @return 表示工具的 {@link ToolEntity}。 + * @return 表示工具的 {@link DefaultToolEntity}。 */ @Genericable(id = "modelengine.fel.tool.get") - ToolEntity getTool(String namespace, String toolName); + DefaultToolEntity getTool(String namespace, String toolName); /** * 获取命名空间下的所有工具。 * * @param namespace 表示工具命名空间的 {@link String}。 - * @return 表示工具的 {@link List}{@code <}{@link ToolEntity}{@code >}。 + * @return 表示工具的 {@link List}{@code <}{@link DefaultToolEntity}{@code >}。 */ @Genericable(id = "modelengine.fel.tool.list") - List listTool(String namespace); + List listTool(String namespace); } diff --git a/framework/fel/java/services/tool-service/src/test/java/modelengine/fel/tool/support/FitToolTest.java b/framework/fel/java/services/tool-service/src/test/java/modelengine/fel/tool/support/FitToolTest.java index 56174669..fdb59a4c 100644 --- a/framework/fel/java/services/tool-service/src/test/java/modelengine/fel/tool/support/FitToolTest.java +++ b/framework/fel/java/services/tool-service/src/test/java/modelengine/fel/tool/support/FitToolTest.java @@ -6,6 +6,7 @@ package modelengine.fel.tool.support; +import static modelengine.fitframework.util.ObjectUtils.cast; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; @@ -14,8 +15,9 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import modelengine.fel.tool.DefaultToolEntity; import modelengine.fel.tool.Tool; -import modelengine.fel.tool.ToolEntity; +import modelengine.fel.tool.info.entity.ToolEntity; import modelengine.fel.tool.ToolFactory; import modelengine.fel.tool.ToolSchema; import modelengine.fit.serialization.json.jackson.JacksonObjectSerializer; @@ -62,7 +64,8 @@ void setUp() throws IOException { })).get("tools"); ToolEntity testEntity = toolEntities.get(0); ToolFactory toolFactory = new FitToolFactory(client, serializer); - this.tool = toolFactory.create(testEntity, Tool.Metadata.fromSchema("Common", testEntity.schema())); + DefaultToolEntity defaultToolEntity = new DefaultToolEntity(testEntity); + this.tool = toolFactory.create(defaultToolEntity, Tool.Metadata.fromSchema("Common", testEntity.schema())); } @Test