From 8dfaa970401c0811db0dc9b9cf302c51ba6b156e Mon Sep 17 00:00:00 2001 From: LamGC Date: Wed, 7 Oct 2020 00:17:29 +0800 Subject: [PATCH] =?UTF-8?q?[Add]=20Framework-API=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=9F=BA=E4=BA=8E=20PF4J=20=E7=9A=84=E6=A1=86=E6=9E=B6API?= =?UTF-8?q?=E5=88=9D=E7=89=88;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Add] Framework, FrameworkDescriptor, FrameworkManager 添加框架相关类; [Add] AuthorJsonSerializer, BotCodeDescriptorJsonSerializer, PlatformJsonSerializer, PluginDependencyJsonSerializer 添加一组辅助解析 FrameworkDescriptor 的 Json 序列化工具类; [Add] Author, BotCodeDescriptor, Platform 添加与框架相关的信息类; [Add] BotCode 添加机器人功能码接口, 以抽象化各框架实现的功能码; [Add] DefaultFrameworkDescriptor 添加 FrameworkDescriptor 的默认实现(应该不会再改的了); [Add] JsonFrameworkDescriptorFinder 添加自定义的 Json 框架元数据查找解析器; [Add] FrameworkFactory 添加用于构造框架对象的工厂类; [Add] org.pf4j:pf4j 添加 PF4J 作为 Framework-API 的插件框架; [Add] com.google.code.gson:gson 添加 Gson 作为框架元数据的解析工具; --- ContentGrabbingJi-framework-api/pom.xml | 12 ++ .../net/lamgc/cgj/bot/framework/Author.java | 78 ++++++++++++ .../framework/DefaultFrameworkDescriptor.java | 100 +++++++++++++++ .../lamgc/cgj/bot/framework/Framework.java | 85 +++++++++++++ .../bot/framework/FrameworkDescriptor.java | 49 ++++++++ .../cgj/bot/framework/FrameworkFactory.java | 79 ++++++++++++ .../cgj/bot/framework/FrameworkManager.java | 52 ++++++++ .../JsonFrameworkDescriptorFinder.java | 115 ++++++++++++++++++ .../net/lamgc/cgj/bot/framework/Platform.java | 59 +++++++++ .../cgj/bot/framework/message/BotCode.java | 90 ++++++++++++++ .../framework/message/BotCodeDescriptor.java | 45 +++++++ .../framework/util/AuthorJsonSerializer.java | 65 ++++++++++ .../util/BotCodeDescriptorJsonSerializer.java | 76 ++++++++++++ .../util/PlatformJsonSerializer.java | 58 +++++++++ .../util/PluginDependencyJsonSerializer.java | 59 +++++++++ 15 files changed, 1022 insertions(+) create mode 100644 ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/Author.java create mode 100644 ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/DefaultFrameworkDescriptor.java create mode 100644 ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/Framework.java create mode 100644 ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/FrameworkDescriptor.java create mode 100644 ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/FrameworkFactory.java create mode 100644 ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/FrameworkManager.java create mode 100644 ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/JsonFrameworkDescriptorFinder.java create mode 100644 ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/Platform.java create mode 100644 ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/BotCode.java create mode 100644 ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/BotCodeDescriptor.java create mode 100644 ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/AuthorJsonSerializer.java create mode 100644 ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/BotCodeDescriptorJsonSerializer.java create mode 100644 ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/PlatformJsonSerializer.java create mode 100644 ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/PluginDependencyJsonSerializer.java diff --git a/ContentGrabbingJi-framework-api/pom.xml b/ContentGrabbingJi-framework-api/pom.xml index 6f9226d..8acbff6 100644 --- a/ContentGrabbingJi-framework-api/pom.xml +++ b/ContentGrabbingJi-framework-api/pom.xml @@ -28,5 +28,17 @@ ContentGrabbingJi-framework-api + + + org.pf4j + pf4j + 3.4.1 + + + com.google.code.gson + gson + 2.8.6 + + \ No newline at end of file diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/Author.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/Author.java new file mode 100644 index 0000000..45c42d6 --- /dev/null +++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/Author.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2020 LamGC + * + * ContentGrabbingJi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ContentGrabbingJi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package net.lamgc.cgj.bot.framework; + +import java.util.Objects; + +/** + * 框架作者信息. + *

我觉得改成维护者会更好一些? + * @author LamGC + */ +public class Author { + + private final String name; + private final String url; + private final String email; + + public Author(String name, String url, String email) { + this.name = Objects.requireNonNull(name); + this.url = url; + this.email = email; + } + + public String getName() { + return name; + } + + public String getUrl() { + return url; + } + + public String getEmail() { + return email; + } + + @Override + public String toString() { + return "Author{" + + "name='" + getName() + '\'' + + ", url='" + getUrl() + '\'' + + ", email='" + getEmail() + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Author author = (Author) o; + return name.equals(author.name) && + Objects.equals(url, author.url) && + Objects.equals(email, author.email); + } + + @Override + public int hashCode() { + return Objects.hash(name, url, email); + } +} diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/DefaultFrameworkDescriptor.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/DefaultFrameworkDescriptor.java new file mode 100644 index 0000000..00c6f7a --- /dev/null +++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/DefaultFrameworkDescriptor.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2020 LamGC + * + * ContentGrabbingJi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ContentGrabbingJi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package net.lamgc.cgj.bot.framework; + +import net.lamgc.cgj.bot.framework.message.BotCodeDescriptor; +import org.pf4j.PluginDependency; + +import java.util.ArrayList; +import java.util.List; + +/** + * 默认框架描述对象. + * @author LamGC + */ +class DefaultFrameworkDescriptor implements FrameworkDescriptor { + + private String id; + private String description; + private String version; + private String requiresVersion; + private String provider; + private String license; + private String frameworkClass; + private final List dependencies = new ArrayList<>(); + + private Platform platform; + private BotCodeDescriptor botCode; + private List authors; + + @Override + public String getPluginId() { + return id; + } + + @Override + public String getPluginDescription() { + return description; + } + + @Override + public String getPluginClass() { + return frameworkClass; + } + + @Override + public String getVersion() { + return version; + } + + @Override + public String getRequires() { + return requiresVersion; + } + + @Override + public String getProvider() { + return provider; + } + + @Override + public String getLicense() { + return license; + } + + @Override + public List getDependencies() { + return dependencies; + } + + @Override + public Platform getPlatform() { + return platform; + } + + @Override + public BotCodeDescriptor getBotCodeDescriptor() { + return botCode; + } + + @Override + public List getAuthors() { + return authors; + } + +} diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/Framework.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/Framework.java new file mode 100644 index 0000000..b3dee4c --- /dev/null +++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/Framework.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2020 LamGC + * + * ContentGrabbingJi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ContentGrabbingJi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package net.lamgc.cgj.bot.framework; + +import org.pf4j.Plugin; +import org.pf4j.PluginDescriptor; +import org.pf4j.PluginState; +import org.pf4j.PluginWrapper; + +import java.io.File; + +/** + * 框架抽象类. + * @author LamGC + */ +public abstract class Framework extends Plugin { + + private final File dataFolder; + + /** + * 由 FrameworkManager 执行的构造方法. + *

不要在构造方法内做任何处理. 如果你需要, 请在 {@link #initial()} 进行初始化. + * + * @param wrapper 包含框架运行期间需要使用对象的包装器. + */ + public Framework(PluginWrapper wrapper, File dataFolder) { + super(wrapper); + this.dataFolder = dataFolder; + try { + initial(); + } catch (Throwable e) { + wrapper.setFailedException(e); + wrapper.setPluginState(PluginState.FAILED); + log.error("An exception occurred while initializing the framework", e); + } + } + + /** + * 执行初始化操作. + */ + protected abstract void initial(); + + /** + * 获取仅属于该框架的数据存储目录. + * + *

调用本方法将会检查目录是否存在, 并在目录不存在时尝试创建. + *

请不要在除数据存储目录外的其他位置存储数据, 这将使用户感到困扰! + * + * @return 返回数据存储目录. + */ + public File getDataFolder() { + if (!dataFolder.exists() && !dataFolder.mkdirs()) { + log.warn("框架 {} 数据目录创建失败.", getDescriptor().getPluginId()); + } + return dataFolder; + } + + /** + * 获取框架描述对象. + * @return 返回框架描述对象. + */ + public FrameworkDescriptor getDescriptor() { + PluginDescriptor descriptor = getWrapper().getDescriptor(); + if (descriptor instanceof FrameworkDescriptor) { + return (FrameworkDescriptor) descriptor; + } + throw new IllegalStateException("无法转换 Descriptor 的类型, 框架管理器可能遭到修改!"); + } + +} diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/FrameworkDescriptor.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/FrameworkDescriptor.java new file mode 100644 index 0000000..51557cf --- /dev/null +++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/FrameworkDescriptor.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2020 LamGC + * + * ContentGrabbingJi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ContentGrabbingJi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package net.lamgc.cgj.bot.framework; + +import net.lamgc.cgj.bot.framework.message.BotCodeDescriptor; +import org.pf4j.PluginDescriptor; + +import java.util.List; + +/** + * 框架描述对象. + * @author LamGC + */ +public interface FrameworkDescriptor extends PluginDescriptor { + + /** + * 获取框架所属平台. + * @return 返回平台对象. + */ + Platform getPlatform(); + + /** + * 获取 BotCode 描述. + * @return 返回 BotCode 描述对象. + */ + BotCodeDescriptor getBotCodeDescriptor(); + + /** + * 获取框架作者信息. + * @return 返回存储了所有作者信息的 List. + */ + List getAuthors(); + +} diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/FrameworkFactory.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/FrameworkFactory.java new file mode 100644 index 0000000..2699819 --- /dev/null +++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/FrameworkFactory.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2020 LamGC + * + * ContentGrabbingJi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ContentGrabbingJi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package net.lamgc.cgj.bot.framework; + +import org.pf4j.Plugin; +import org.pf4j.PluginFactory; +import org.pf4j.PluginWrapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; + +/** + * 经过调整的, 针对 Framework 的实例工厂类. + * @author LamGC + */ +final class FrameworkFactory implements PluginFactory { + + private final static Logger log = LoggerFactory.getLogger(FrameworkFactory.class); + + private final File dataRootFolder; + + public FrameworkFactory(File dataRootFolder) { + this.dataRootFolder = dataRootFolder; + if (!this.dataRootFolder.exists() && !this.dataRootFolder.mkdirs()) { + log.warn("框架数据目录创建异常, 可能会导致后续框架存取数据失败!"); + } + } + + @Override + public Plugin create(PluginWrapper pluginWrapper) { + String pluginClassName = pluginWrapper.getDescriptor().getPluginClass(); + log.debug("Create instance for framework '{}'", pluginClassName); + + Class pluginClass; + try { + pluginClass = pluginWrapper.getPluginClassLoader().loadClass(pluginClassName); + } catch (ClassNotFoundException e) { + log.error(e.getMessage(), e); + return null; + } + + // 如果成功获取类, 就需要对其检查, 以确保类符合框架主类的要求. + int modifiers = pluginClass.getModifiers(); + if (Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers) + || (!Framework.class.isAssignableFrom(pluginClass))) { + log.error("The framework class '{}' is not valid", pluginClassName); + return null; + } + + try { + // (PluginWrapper, DataFolder) + Constructor constructor = pluginClass.getConstructor(PluginWrapper.class, File.class); + return (Plugin) constructor.newInstance(pluginWrapper, + new File(dataRootFolder, pluginWrapper.getPluginId())); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + + return null; + } +} diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/FrameworkManager.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/FrameworkManager.java new file mode 100644 index 0000000..15cf9d0 --- /dev/null +++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/FrameworkManager.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2020 LamGC + * + * ContentGrabbingJi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ContentGrabbingJi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package net.lamgc.cgj.bot.framework; + +import org.pf4j.*; + +import java.io.File; + +/** + * 框架管理器. + * @author LamGC + */ +public class FrameworkManager extends JarPluginManager { + + public FrameworkManager(String systemVersion, File frameworksDirectory) { + super(frameworksDirectory.toPath()); + setSystemVersion(systemVersion); + } + + @Override + protected PluginDescriptorFinder createPluginDescriptorFinder() { + return new JsonFrameworkDescriptorFinder(); + } + + @Override + protected PluginRepository createPluginRepository() { + return new CompoundPluginRepository() + .add(new DevelopmentPluginRepository(getPluginsRoot()), this::isDevelopment) + .add(new JarPluginRepository(getPluginsRoot()), this::isNotDevelopment) + .add(new DefaultPluginRepository(getPluginsRoot()), this::isNotDevelopment); + } + + @Override + protected PluginFactory createPluginFactory() { + return new FrameworkFactory(getPluginsRoot().getParent().resolve("frameworkData").toFile()); + } +} diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/JsonFrameworkDescriptorFinder.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/JsonFrameworkDescriptorFinder.java new file mode 100644 index 0000000..133e7a0 --- /dev/null +++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/JsonFrameworkDescriptorFinder.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2020 LamGC + * + * ContentGrabbingJi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ContentGrabbingJi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package net.lamgc.cgj.bot.framework; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import net.lamgc.cgj.bot.framework.message.BotCodeDescriptor; +import net.lamgc.cgj.bot.framework.util.AuthorJsonSerializer; +import net.lamgc.cgj.bot.framework.util.BotCodeDescriptorJsonSerializer; +import net.lamgc.cgj.bot.framework.util.PlatformJsonSerializer; +import net.lamgc.cgj.bot.framework.util.PluginDependencyJsonSerializer; +import org.pf4j.PluginDependency; +import org.pf4j.PluginDescriptor; +import org.pf4j.PluginDescriptorFinder; +import org.pf4j.PluginRuntimeException; +import org.pf4j.util.FileUtils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Json格式的框架描述文件查找器. + * @author LamGC + */ +class JsonFrameworkDescriptorFinder implements PluginDescriptorFinder { + + private final static String DESCRIPTOR_FILE_NAME = "framework.json"; + private final Gson gson; + + public JsonFrameworkDescriptorFinder() { + this(new Gson()); + } + + public JsonFrameworkDescriptorFinder(Gson gson) { + this.gson = gson.newBuilder() + .serializeNulls() + .registerTypeAdapter(Author.class, new AuthorJsonSerializer()) + .registerTypeAdapter(BotCodeDescriptor.class, new BotCodeDescriptorJsonSerializer()) + .registerTypeAdapter(Platform.class, new PlatformJsonSerializer()) + .registerTypeAdapter(PluginDependency.class, new PluginDependencyJsonSerializer()) + .create(); + } + + @Override + public boolean isApplicable(Path frameworkPath) { + return Files.exists(frameworkPath) && (Files.isDirectory(frameworkPath) || FileUtils.isJarFile(frameworkPath)); + } + + @Override + public PluginDescriptor find(Path frameworkPath) { + JsonObject descriptorObject = loadFrameworkDescriptorObject(frameworkPath); + return createFrameworkDescriptor(descriptorObject); + } + + private Path getFrameworkDescriptorPath(Path frameworkPath) { + if (Files.isDirectory(frameworkPath)) { + return frameworkPath.resolve(Paths.get(DESCRIPTOR_FILE_NAME)); + } else { + try { + return FileUtils.getPath(frameworkPath, DESCRIPTOR_FILE_NAME); + } catch (IOException e) { + throw new PluginRuntimeException(e); + } + } + } + + private JsonObject loadFrameworkDescriptorObject(Path frameworkPath) { + Path descriptorPath = getFrameworkDescriptorPath(frameworkPath); + if (frameworkPath == null) { + throw new PluginRuntimeException("Cannot find the json path"); + } + + JsonObject descriptorObject; + try { + if (Files.notExists(descriptorPath)) { + throw new PluginRuntimeException("Cannot find '{}' path", descriptorPath); + } + try (InputStream input = Files.newInputStream(descriptorPath)) { + descriptorObject = gson.fromJson( + new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)), JsonObject.class); + } catch (IOException e) { + throw new PluginRuntimeException("Exception loading descriptor", e); + } + } finally { + FileUtils.closePath(descriptorPath); + } + return descriptorObject; + } + + private FrameworkDescriptor createFrameworkDescriptor(JsonObject descriptorObject) { + return gson.fromJson(descriptorObject, DefaultFrameworkDescriptor.class); + } + +} diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/Platform.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/Platform.java new file mode 100644 index 0000000..7a03733 --- /dev/null +++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/Platform.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2020 LamGC + * + * ContentGrabbingJi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ContentGrabbingJi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package net.lamgc.cgj.bot.framework; + +/** + * 框架平台DO. + * @author LamGC + */ +public class Platform { + + private final String platformName; + private final String platformIdentify; + + public Platform(String platformName, String platformIdentify) { + this.platformName = platformName; + this.platformIdentify = platformIdentify; + } + + @Override + public String toString() { + return "Platform{" + + "platformName='" + platformName + '\'' + + ", platformIdentify='" + platformIdentify + '\'' + + '}'; + } + + /** + * 获取平台名称. + * @return 返回平台名称. + */ + public String getPlatformName() { + return platformName; + } + + /** + * 获取平台唯一标识. + * 注意, 该标识将应用于平台所属事件的处理相关. + * @return 返回平台标识. + */ + public String getPlatformIdentify() { + return platformIdentify; + } + +} diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/BotCode.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/BotCode.java new file mode 100644 index 0000000..f3db467 --- /dev/null +++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/BotCode.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2020 LamGC + * + * ContentGrabbingJi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ContentGrabbingJi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package net.lamgc.cgj.bot.framework.message; + +import net.lamgc.cgj.bot.framework.Platform; +import net.lamgc.cgj.bot.framework.message.exception.BuildBotCodeException; +import net.lamgc.cgj.bot.framework.message.exception.InvalidBotCodeException; +import net.lamgc.cgj.bot.framework.message.exception.UnsupportedBotCodeException; + +import java.util.Set; + +/** + * 功能码接口. + * @author LamGC + */ +public interface BotCode { + + /** + * 获取 BotCode 实现所属平台. + * @return 返回所属平台. + */ + Platform getPlatform(); + + /** + * 转换为平台或框架可识别并处理的BotCode字符串形式. + * @return 返回转换后的结果. + * @throws UnsupportedBotCodeException 当框架不支持该 BotCode 时抛出. + * @throws BuildBotCodeException 当 BotCode 无法构造出字符串形式时抛出, 包含原因. + */ + String toBotCodeString() throws UnsupportedBotCodeException, BuildBotCodeException; + + /** + * 从 BotCode 字符串转换成 BotCode 对象. + * @param botCodeString 传入的 BotCode 字符串. + * @throws InvalidBotCodeException 当传入的 BotCode 字符串无法转换成该实现对应的 BotCode 对象时可抛出该异常, + * 务必在异常中清晰说明异常原因. + * @throws UnsupportedBotCodeException 当框架不支持该 BotCode 时抛出. + */ + void fromBotCodeString(String botCodeString) throws InvalidBotCodeException, UnsupportedBotCodeException; + + /** + * 取功能函数名. + * @return 返回功能函数名. + */ + String getFunctionName(); + + /** + * 设置功能函数名 + * @param functionName 新的功能函数名. + */ + void setFunctionName(String functionName); + + /** + * 设置功能参数 + * @param key 参数名 + * @param value 参数值, 如果参数值为 {@code null} 则删除该参数. + * @throws NullPointerException 当 key 为 null 时抛出. + */ + void setProperty(String key, String value); + + /** + * 获取功能参数 + * @param key 参数名 + * @return 如果存在, 返回参数名, 否则返回 {@code null}. + * @throws NullPointerException 当 key 为 null 时抛出. + */ + String getProperty(String key); + + /** + * 取功能码参数键集. + * @return 返回存储了所有参数键名的Set. + */ + Set getPropertiesKeys(); + +} diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/BotCodeDescriptor.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/BotCodeDescriptor.java new file mode 100644 index 0000000..b7b3323 --- /dev/null +++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/BotCodeDescriptor.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 LamGC + * + * ContentGrabbingJi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ContentGrabbingJi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package net.lamgc.cgj.bot.framework.message; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.regex.Pattern; + +/** + * BotCode 描述对象. + * @author LamGC + */ +public final class BotCodeDescriptor { + + private final List patterns; + + public BotCodeDescriptor(List patternStrings) { + List patterns = new ArrayList<>(); + for (String patternString : patternStrings) { + patterns.add(Pattern.compile(patternString)); + } + this.patterns = patterns; + } + + public List getPatterns() { + return patterns; + } + +} diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/AuthorJsonSerializer.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/AuthorJsonSerializer.java new file mode 100644 index 0000000..dc3ef7a --- /dev/null +++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/AuthorJsonSerializer.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020 LamGC + * + * ContentGrabbingJi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ContentGrabbingJi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package net.lamgc.cgj.bot.framework.util; + +import com.google.gson.*; +import net.lamgc.cgj.bot.framework.Author; + +import java.lang.reflect.Type; + +/** + * {@link Author} Json 序列化工具. + * @see Author + * @author LamGC + */ +public class AuthorJsonSerializer implements JsonSerializer, JsonDeserializer { + + private final static String FIELD_NAME = "name"; + private final static String FIELD_URL = "url"; + private final static String FIELD_EMAIL = "email"; + + @Override + public Author deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + if (!json.isJsonObject()) { + throw new JsonParseException("Not a JsonObject"); + } + + JsonObject authorObject = json.getAsJsonObject(); + if (!authorObject.has(FIELD_NAME) || !authorObject.get(FIELD_NAME).isJsonPrimitive()) { + throw new JsonParseException("A required field is missing or the type is incorrect: " + FIELD_NAME); + } + + String name = authorObject.get(FIELD_NAME).getAsString(); + String url = authorObject.has(FIELD_URL) && authorObject.get(FIELD_URL).isJsonPrimitive() ? + authorObject.get(FIELD_URL).getAsString() : null; + String email = authorObject.has(FIELD_EMAIL) && authorObject.get(FIELD_EMAIL).isJsonPrimitive() ? + authorObject.get(FIELD_EMAIL).getAsString() : null; + + return new Author(name, url, email); + } + + @Override + public JsonElement serialize(Author src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject result = new JsonObject(); + result.addProperty(FIELD_NAME, src.getName()); + result.addProperty(FIELD_URL, src.getUrl()); + result.addProperty(FIELD_EMAIL, src.getEmail()); + return result; + } +} diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/BotCodeDescriptorJsonSerializer.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/BotCodeDescriptorJsonSerializer.java new file mode 100644 index 0000000..a84b6b1 --- /dev/null +++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/BotCodeDescriptorJsonSerializer.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2020 LamGC + * + * ContentGrabbingJi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ContentGrabbingJi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package net.lamgc.cgj.bot.framework.util; + +import com.google.gson.*; +import net.lamgc.cgj.bot.framework.message.BotCodeDescriptor; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +/** + * BotCode 描述对象序列化工具. + * @see BotCodeDescriptor + * @author LamGC + */ +public class BotCodeDescriptorJsonSerializer + implements JsonSerializer, JsonDeserializer { + + private final static String FIELD_PATTERNS = "patterns"; + + @Override + public BotCodeDescriptor deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + if (!json.isJsonObject()) { + throw new JsonParseException("Not a JsonObject"); + } + + JsonObject descriptorObject = json.getAsJsonObject(); + List patternStrings = new ArrayList<>(); + if (descriptorObject.has(FIELD_PATTERNS) && descriptorObject.get(FIELD_PATTERNS).isJsonArray()) { + for (JsonElement jsonElement : descriptorObject.getAsJsonArray(FIELD_PATTERNS)) { + if (!jsonElement.isJsonPrimitive()) { + continue; + } + + JsonPrimitive primitive = jsonElement.getAsJsonPrimitive(); + if (!primitive.isString()) { + continue; + } + patternStrings.add(primitive.getAsString()); + } + } + + return new BotCodeDescriptor(patternStrings); + } + + @Override + public JsonElement serialize(BotCodeDescriptor src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject result = new JsonObject(); + + JsonArray patterns = new JsonArray(); + for (Pattern pattern : src.getPatterns()) { + patterns.add(pattern.pattern()); + } + result.add(FIELD_PATTERNS, patterns); + + return result; + } +} diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/PlatformJsonSerializer.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/PlatformJsonSerializer.java new file mode 100644 index 0000000..f28ddc8 --- /dev/null +++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/PlatformJsonSerializer.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020 LamGC + * + * ContentGrabbingJi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ContentGrabbingJi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package net.lamgc.cgj.bot.framework.util; + +import com.google.gson.*; +import net.lamgc.cgj.bot.framework.Platform; + +import java.lang.reflect.Type; + +/** + * {@link Platform} 序列化工具. + * @see Platform + * @author LamGC + */ +public final class PlatformJsonSerializer implements JsonSerializer, JsonDeserializer { + + private final static String FIELD_NAME = "name"; + private final static String FIELD_IDENTIFY = "identify"; + + + @Override + public Platform deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + if (!json.isJsonObject()) { + throw new JsonParseException("Not a JsonObject"); + } + + JsonObject descriptorObject = json.getAsJsonObject(); + if (!descriptorObject.has(FIELD_NAME) || !descriptorObject.has(FIELD_IDENTIFY)) { + throw new JsonParseException("A required field is missing"); + } + return new Platform(descriptorObject.get(FIELD_NAME).getAsString(), + descriptorObject.get(FIELD_IDENTIFY).getAsString()); + } + + @Override + public JsonElement serialize(Platform src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject result = new JsonObject(); + result.addProperty(FIELD_NAME, src.getPlatformName()); + result.addProperty(FIELD_IDENTIFY, src.getPlatformIdentify()); + return result; + } +} diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/PluginDependencyJsonSerializer.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/PluginDependencyJsonSerializer.java new file mode 100644 index 0000000..610cdc8 --- /dev/null +++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/util/PluginDependencyJsonSerializer.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2020 LamGC + * + * ContentGrabbingJi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * ContentGrabbingJi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package net.lamgc.cgj.bot.framework.util; + +import com.google.gson.*; +import org.pf4j.PluginDependency; + +import java.lang.reflect.Type; + +/** + * PluginDependency Json 序列化/反序列化 工具. + * @see PluginDependency + * @author LamGC + */ +public class PluginDependencyJsonSerializer implements JsonSerializer, JsonDeserializer { + private final static String PLUGIN_VERSION_SUPPORT_ALL = "*"; + + @Override + public JsonElement serialize(PluginDependency src, Type typeOfSrc, JsonSerializationContext context) { + StringBuilder builder = new StringBuilder(src.getPluginId()); + String pluginVersionSupport = src.getPluginVersionSupport(); + if (src.isOptional()) { + builder.append('?'); + } + if (src.getPluginVersionSupport() != null || !PLUGIN_VERSION_SUPPORT_ALL.equals(pluginVersionSupport)) { + builder.append('@').append(pluginVersionSupport); + } + return new JsonPrimitive(builder.toString()); + } + + @Override + public PluginDependency deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + if (!json.isJsonPrimitive()) { + throw new JsonParseException("Only JsonPrimitive types are supported for conversion"); + } + + JsonPrimitive primitive = json.getAsJsonPrimitive(); + if (!primitive.isString()) { + throw new JsonParseException("Only String is supported"); + } + + return new PluginDependency(primitive.getAsString()); + } +}