diff --git a/framework/spring-boot-starter-plugin/pom.xml b/framework/spring-boot-starter-plugin/pom.xml index 19fd756..525fd17 100644 --- a/framework/spring-boot-starter-plugin/pom.xml +++ b/framework/spring-boot-starter-plugin/pom.xml @@ -21,7 +21,7 @@ cd.casic.boot - spring-boot-starter-biz-data-permission + spring-boot-starter-web @@ -29,6 +29,11 @@ spring-boot-starter-websocket + + cd.casic.boot + spring-boot-starter-mybatis + + cd.casic.boot spring-boot-starter-mongo diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/BasePlugin.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/BasePlugin.java deleted file mode 100644 index b56e9b6..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/BasePlugin.java +++ /dev/null @@ -1,29 +0,0 @@ -package cd.casic.plugin; - -import org.pf4j.Plugin; -import org.pf4j.PluginWrapper; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin - * @Project:ops - * @name:BasePlugin - * @Date:2024/03/18 9:25 - * @Filename:BasePlugin - * @description:插件基类 - */ -public abstract class BasePlugin extends Plugin { - - public BasePlugin(PluginWrapper wrapper) { - super(wrapper); - } - - /** - * 根据插件主类获取插件包 - * - * @return String - */ - public String scanPackage() { - return this.getClass().getPackage().getName(); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/BufferedPluginBundleResource.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/BufferedPluginBundleResource.java deleted file mode 100644 index f504f22..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/BufferedPluginBundleResource.java +++ /dev/null @@ -1,151 +0,0 @@ -package cd.casic.plugin; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.buffer.DataBuffer; -import org.springframework.core.io.buffer.DataBufferUtils; -import org.springframework.lang.Nullable; -import org.springframework.stereotype.Component; -import org.springframework.util.Assert; -import org.springframework.util.FileSystemUtils; -import org.springframework.web.server.ServerWebInputException; - -import java.io.BufferedOutputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - - -@Slf4j -@Component -public class BufferedPluginBundleResource implements DisposableBean { - - private final AtomicReference jsBundle = new AtomicReference<>(); - private final AtomicReference cssBundle = new AtomicReference<>(); - - private final ReadWriteLock jsLock = new ReentrantReadWriteLock(); - private final ReadWriteLock cssLock = new ReentrantReadWriteLock(); - - private Path tempDir; - - public FileSystemResource getJsBundle(String version, List dataBuffers) { - String fileName = tempFileName(version, ".js"); - jsLock.readLock().lock(); - try { - FileSystemResource jsBundleResource = jsBundle.get(); - if (getResourceIfNotChange(fileName, jsBundleResource) != null) { - return jsBundleResource; - } - } finally { - jsLock.readLock().unlock(); - } - - jsLock.writeLock().lock(); - try { - FileSystemResource oldJsBundle = jsBundle.get(); - FileSystemResource newJsBundle = writeBundle(fileName, dataBuffers); - jsBundle.compareAndSet(oldJsBundle, newJsBundle); - return newJsBundle; - } catch (IOException e) { - throw new RuntimeException(e); - } finally { - jsLock.writeLock().unlock(); - } - } - - public FileSystemResource getCssBundle(String version, List dataBuffers) { - String fileName = tempFileName(version, ".css"); - try { - cssLock.readLock().lock(); - FileSystemResource cssBundleResource = cssBundle.get(); - if (getResourceIfNotChange(fileName, cssBundleResource) != null) { - return cssBundleResource; - } - } finally { - cssLock.readLock().unlock(); - } - cssLock.writeLock().lock(); - try { - FileSystemResource oldCssBundle = cssBundle.get(); - FileSystemResource newCssBundle = writeBundle(fileName, dataBuffers); - cssBundle.compareAndSet(oldCssBundle, newCssBundle); - return newCssBundle; - } catch (IOException e) { - throw new RuntimeException(e); - } finally { - cssLock.writeLock().unlock(); - } - } - - @Nullable - private Resource getResourceIfNotChange(String fileName, Resource resource) { - if (resource != null && resource.exists() && fileName.equals(resource.getFilename())) { - return resource; - } - return null; - } - - private FileSystemResource writeBundle(String fileName, List dataBuffers) throws IOException { - Path filePath = createTempFileToStore(fileName); - // 打开文件输出流 - try (FileOutputStream fileOutputStream = new FileOutputStream(filePath.toFile()); - BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream)) { - - // 遍历 DataBuffer 列表并写入文件 - for (DataBuffer dataBuffer : dataBuffers) { - // 将 DataBuffer 转换为字节数组 - byte[] bytes = new byte[dataBuffer.readableByteCount()]; - dataBuffer.read(bytes); - // 写入文件 - bufferedOutputStream.write(bytes); - // 释放 DataBuffer - DataBufferUtils.release(dataBuffer); - } - } - return new FileSystemResource(filePath); - } - - - private Path createTempFileToStore(String fileName) { - try { - if (tempDir == null || !Files.exists(tempDir)) { - this.tempDir = Files.createTempDirectory("ops-plugin-bundle"); - } - Path path = tempDir.resolve(fileName); - log.info("Create temp file: {}", path); - Files.deleteIfExists(path); - return Files.createFile(path); - } catch (IOException e) { - throw new ServerWebInputException("Failed to create temp file.", null, e); - } - } - - /** - * 生成临时文件名 - * - * @param v - * @param suffix - * @return - */ - private String tempFileName(String v, String suffix) { - Assert.notNull(v, "Version must not be null"); - Assert.notNull(suffix, "Suffix must not be null"); - return v + suffix; - } - - @Override - public void destroy() throws Exception { - if (tempDir != null && Files.exists(tempDir)) { - FileSystemUtils.deleteRecursively(tempDir); - } - this.jsBundle.set(null); - this.cssBundle.set(null); - } -} \ No newline at end of file diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/FrontResourceProcessor.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/FrontResourceProcessor.java deleted file mode 100644 index 8019eed..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/FrontResourceProcessor.java +++ /dev/null @@ -1,106 +0,0 @@ -package cd.casic.plugin; - -import cd.casic.plugin.utils.FrontResourceUtils; -import cn.hutool.core.io.IoUtil; -import cn.hutool.crypto.digest.DigestUtil; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.pf4j.PluginWrapper; -import org.pf4j.RuntimeMode; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.Resource; -import org.springframework.core.io.buffer.DataBuffer; -import org.springframework.core.io.buffer.DefaultDataBufferFactory; -import org.springframework.stereotype.Component; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.stream.Collectors; - -/** - * 前端资源处理器,将各个插件的css和js资源合并 - */ -@Slf4j -@Component -@RequiredArgsConstructor -public class FrontResourceProcessor { - - @Autowired - private PluginManager pluginManager; - - public List uglifyJsBundle() { - List dataBuffers = new ArrayList<>(); - List startedPlugins = pluginManager.getStartedPlugins(); - String plugins = String.format("this.enabledPluginNames = [%s];", - startedPlugins.stream() - .map(PluginWrapper::getPluginId) - .collect(Collectors.joining("','", "'", "'"))); - - for (PluginWrapper pluginWrapper : startedPlugins) { - String pluginName = pluginWrapper.getPluginId(); - Resource jsBundleResource = FrontResourceUtils.getJsBundleResource(pluginManager, pluginName, - FrontResourceUtils.JS_BUNDLE); - - if (jsBundleResource != null) { - try (InputStream inputStream = jsBundleResource.getInputStream()) { - byte[] bytes = IoUtil.readBytes(inputStream); - DataBuffer dataBuffer = DefaultDataBufferFactory.sharedInstance.wrap(bytes); - dataBuffers.add(dataBuffer); - // Add a new line after each plugin bundle to avoid syntax error - byte[] newLineBytes = "\n".getBytes(StandardCharsets.UTF_8); - dataBuffers.add(DefaultDataBufferFactory.sharedInstance.wrap(newLineBytes)); - } catch (IOException e) { - log.error("Failed to read plugin bundle resource", e); - } - } - } - - // Add the plugins JavaScript object at the end - byte[] pluginsBytes = plugins.getBytes(StandardCharsets.UTF_8); - DataBuffer pluginsDataBuffer = DefaultDataBufferFactory.sharedInstance.wrap(pluginsBytes); - dataBuffers.add(pluginsDataBuffer); - - - return dataBuffers; - } - - public List uglifyCssBundle() { - List cssDataBuffers = new ArrayList<>(); - for (PluginWrapper pluginWrapper : pluginManager.getStartedPlugins()) { - String pluginName = pluginWrapper.getPluginId(); - Resource resource = FrontResourceUtils.getJsBundleResource(pluginManager, pluginName, FrontResourceUtils.CSS_BUNDLE); - - if (resource != null) { - try (InputStream inputStream = resource.getInputStream()) { - byte[] cssBytes = IoUtil.readBytes(inputStream); // Assuming you have Apache Commons IO for this - - DataBuffer dataBuffer = new DefaultDataBufferFactory().wrap(cssBytes); - cssDataBuffers.add(dataBuffer); - } catch (IOException e) { - log.error("Failed to read plugin css bundle resource for plugin: {}", pluginName, e); - } - } - } - - return cssDataBuffers; - } - - public String generateJsBundleVersion() { - if (RuntimeMode.DEVELOPMENT.equals(pluginManager.getRuntimeMode())) { - return String.valueOf(System.currentTimeMillis()); - } - var compactVersion = pluginManager.getStartedPlugins() - .stream() - .sorted(Comparator.comparing(PluginWrapper::getPluginId)) - .map(pluginWrapper -> pluginWrapper.getPluginId() + ":" - + pluginWrapper.getDescriptor().getVersion() - ) - .collect(Collectors.joining()); - - return DigestUtil.sha256Hex(compactVersion); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/IPluginSystemProperties.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/IPluginSystemProperties.java deleted file mode 100644 index 0d24004..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/IPluginSystemProperties.java +++ /dev/null @@ -1,61 +0,0 @@ - -package cd.casic.plugin; - -import org.pf4j.RuntimeMode; - -import java.util.Set; - -/** - * 插件系统属性接口,定义了插件系统的一些核心配置和操作 - */ -public interface IPluginSystemProperties { - - /** - * 检查插件系统是否启用 - * - * @return 如果插件系统启用则返回true,否则返回false - */ - Boolean enable(); - - /** - * 获取REST API路径前缀 - * - * @return REST API路径前缀字符串 - */ - String restPathPrefix(); - - /** - * 检查插件ID是否作为REST路径前缀启用 - * - * @return 如果启用插件ID作为REST路径前缀则返回true,否则返回false - */ - Boolean enablePluginIdAsRestPrefix(); - - /** - * 获取运行时模式 - * - * @return 当前运行时模式 - */ - RuntimeMode runtimeMode(); - - /** - * 获取插件根目录路径 - * - * @return 插件根目录路径字符串 - */ - String pluginsRoot(); - - /** - * 获取已启用插件的ID集合 - * - * @return 包含已启用插件ID的集合 - */ - Set enabledPlugins(); - - /** - * 获取已禁用插件的ID集合 - * - * @return 包含已禁用插件ID的集合 - */ - Set disabledPlugins(); -} \ No newline at end of file diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginApplicationContextManager.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginApplicationContextManager.java deleted file mode 100644 index 626882e..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginApplicationContextManager.java +++ /dev/null @@ -1,32 +0,0 @@ -package cd.casic.plugin; - -import org.springframework.context.annotation.AnnotationConfigApplicationContext; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin - * @Project:ops - * @name:PluginApplicationContextHolder - * @Date:2024/03/18 10:04 - * @Filename:PluginApplicationContextHolder - * @description:插件的上下文管理器 - */ -public class PluginApplicationContextManager { - - private final static Map pluginApplicationMap = new ConcurrentHashMap<>(); - - public static void addPluginApplicationContext(String pluginId, AnnotationConfigApplicationContext applicationContext) { - pluginApplicationMap.put(pluginId, applicationContext); - } - - public static void removePluginApplicationContext(String pluginId) { - pluginApplicationMap.remove(pluginId); - } - - public static AnnotationConfigApplicationContext getApplicationContext(String pluginId) { - return pluginApplicationMap.get(pluginId); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginBean.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginBean.java deleted file mode 100644 index 1ba14d8..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginBean.java +++ /dev/null @@ -1,47 +0,0 @@ -package cd.casic.plugin; - -import lombok.Data; - -import java.io.Serializable; -import java.util.Date; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin - * @Project:ops - * @name:PluginBean - * @Date:2024/03/18 14:48 - * @Filename:PluginBean - * @description:Ops 插件的bean - */ -@Data -public class PluginBean implements Serializable { - private static final long serialVersionUID = 7817277417501722377L; -// @ApiModelProperty(value="插件ID",name="id") - private Long id; - -// @ApiModelProperty(value="插件名",name="name") - private String name; - -// @ApiModelProperty(value="插件路径",name="path") - private String path; - -// @ApiModelProperty(value="插件描述",name="desc") - private String desc; - -// @ApiModelProperty(value="插件版本",name="version") - private String version; - -// @ApiModelProperty(value="插件作者",name="author") - private String author; - -// @ApiModelProperty(value="创建时间",name="createTime") - private Date createTime; - -// @ApiModelProperty(value="更新时间",name="updateTime") - private Date updateTime; - -// @ApiModelProperty(value="插件状态",name="status") - private Integer status = 0; - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginCache.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginCache.java deleted file mode 100644 index 7e93832..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginCache.java +++ /dev/null @@ -1,38 +0,0 @@ -package cd.casic.plugin; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin - * @Project:ops - * @name:PluginCache - * @Date:2024/03/18 9:34 - * @Filename:PluginCache - * @description:已安装插件的存储 - */ -public class PluginCache { - private static final Map pluginMaps = Collections.synchronizedMap(new HashMap<>()); - - public static void put(String pluginId, PluginInfo plugin) { - pluginMaps.putIfAbsent(pluginId, plugin); - } - - public static PluginInfo getPlugin(String pluginId) { - return pluginMaps.get(pluginId); - } - - public static void remove(String pluginId) { - pluginMaps.remove(pluginId); - } - - public static Map getAllPlugin() { - return pluginMaps; - } - - public static Boolean isExist(String pluginId) { - return pluginMaps.containsKey(pluginId); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginClassLoaderCache.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginClassLoaderCache.java deleted file mode 100644 index 7f087d0..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginClassLoaderCache.java +++ /dev/null @@ -1,24 +0,0 @@ -package cd.casic.plugin; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public class PluginClassLoaderCache { - private static final Map loaderMap = Collections.synchronizedMap(new HashMap<>()); - public static void put(String pluginId, ClassLoader loader) { - loaderMap.putIfAbsent(pluginId, loader); - } - - public static ClassLoader getPlugin(String pluginId) { - return loaderMap.get(pluginId); - } - - public static void remove(String pluginId) { - loaderMap.remove(pluginId); - } - - public static Map getAllPlugin() { - return loaderMap; - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginConfigWrapper.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginConfigWrapper.java deleted file mode 100644 index b68d75b..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginConfigWrapper.java +++ /dev/null @@ -1,44 +0,0 @@ -package cd.casic.plugin; - -import lombok.Data; - -import java.util.Objects; - -@Data -public class PluginConfigWrapper { - - /** - * 插件中的配置文件名称 - */ - private final String fileName; - - /** - * 配置文件实现类的Class定义 - */ - private final Class configClass; - - - - public PluginConfigWrapper(String fileName, Class configClass) { - this.fileName = fileName; - this.configClass = configClass; - } - - @Override - public boolean equals(Object o) { - if (this == o){ - return true; - } - if (!(o instanceof PluginConfigWrapper)){ - return false; - } - PluginConfigWrapper that = (PluginConfigWrapper) o; - return getFileName().equals(that.getFileName()) && - getConfigClass().equals(that.getConfigClass()); - } - - @Override - public int hashCode() { - return Objects.hash(getFileName(), getConfigClass()); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginDescriptorCache.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginDescriptorCache.java deleted file mode 100644 index 4c6309c..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginDescriptorCache.java +++ /dev/null @@ -1,25 +0,0 @@ -package cd.casic.plugin; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public class PluginDescriptorCache { - private static final Map pluginMaps = Collections.synchronizedMap(new HashMap<>()); - public static void put(String pluginId, PluginDescriptorStorage pluginDescriptorStorage) { - pluginMaps.putIfAbsent(pluginId, pluginDescriptorStorage); - } - - public static PluginDescriptorStorage getPlugin(String pluginId) { - return pluginMaps.get(pluginId); - } - - public static void remove(String pluginId) { - pluginMaps.remove(pluginId); - } - - public static Map getAllPlugin() { - return pluginMaps; - } -} - diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginDescriptorStorage.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginDescriptorStorage.java deleted file mode 100644 index b2faac4..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginDescriptorStorage.java +++ /dev/null @@ -1,70 +0,0 @@ -package cd.casic.plugin; - -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; -import lombok.*; -import lombok.experimental.Accessors; -import org.pf4j.Plugin; -import org.pf4j.PluginDependency; - -import java.util.List; - -/** - * PF4J要用到的DefaultDescriptorStorage里一堆protected方法,所以另外弄了个类 - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -@Builder -@TableName("sys_plugins") -@Accessors(chain = true) -public class PluginDescriptorStorage { - @TableId - private String pluginId; - private String pluginDescription; - private String pluginClass = Plugin.class.getName(); - private String version; - private String requires = "*"; // SemVer format - private String provider; - @TableField(typeHandler = JacksonTypeHandler.class) - private List dependencies; - private String license; - private String mapperXmlDir; - private String staticDir; - - private Integer enable; - - private String path; - - @TableField(exist = false) - private String configFileName; - - @TableField(exist = false) - private List configFileActive; - - private String pluginDirPath; - - @Getter - public enum EnableStatus { - /** - * 启用 - */ - ENABLE(1, "启用"), - /** - * 禁用 - */ - DISABLE(0, "禁用"); - private final Integer code; - private final String value; - - EnableStatus(Integer code, String value) { - this.value = value; - this.code = code; - } - - } - -} - diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginInfo.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginInfo.java deleted file mode 100644 index f86c51a..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginInfo.java +++ /dev/null @@ -1,155 +0,0 @@ -package cd.casic.plugin; - -import cd.casic.plugin.utils.PluginsUtils; -import cn.hutool.setting.dialect.Props; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.pf4j.PluginWrapper; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.web.servlet.HandlerInterceptor; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin - * @Project:ops - * @name:PluginDetail - * @Date:2024/03/18 9:34 - * @Filename:PluginDetail - * @description:插件信息类 - */ -@Slf4j -@Data -public class PluginInfo { - - // jar或zip的list集合 - private List> classList; - private ApplicationContext mainApplicationContext; - private Boolean applicationContextIsRefresh = false; - private AnnotationConfigApplicationContext pluginApplicationContext; - private PluginWrapper pluginWrapper; - private List> adminGroupsClassList = new ArrayList<>(); - private List websocketPaths = new ArrayList<>(); - private String pluginId; - private String mapperXmlDir; - private final BasePlugin basePlugin; - private List handlerInterceptorList = new ArrayList<>(); - private Set staticClassPathLocations = new HashSet<>(); - private Set staticFileLocations = new HashSet<>(); - private List> controllers = new ArrayList<>(); - private Set pluginConfigObjects = new HashSet<>(); - private Map webSocketPathMap = new ConcurrentHashMap<>(); - // private ConcurrentHashMap, Object> beanCache = new ConcurrentHashMap<>(); - - // TODO 这个map用于替代前面的ClassList - private Map>> classGroups = new ConcurrentHashMap<>(); - - public PluginInfo(PluginWrapper pluginWrapper, ApplicationContext applicationContext) { - this.classList = new ArrayList<>(); - this.pluginWrapper = pluginWrapper; - this.pluginId = pluginWrapper.getPluginId(); - this.pluginApplicationContext = getContext(); - this.mainApplicationContext = applicationContext; - this.basePlugin = (BasePlugin) pluginWrapper.getPlugin(); - this.pluginApplicationContext.setParent(mainApplicationContext); - Props setting = PluginsUtils.getSetting(pluginWrapper.getPluginId()); - if (!setting.isEmpty()) { - this.mapperXmlDir = setting.getStr("mybatis.mapper.location", null); - String locations = setting.getStr("static.locations", null); - if (StringUtils.isNotBlank(locations)) { - loadResources(locations); - } - } - } - - - public AnnotationConfigApplicationContext getContext() { - AnnotationConfigApplicationContext pluginApplicationContext = - PluginApplicationContextManager.getApplicationContext(pluginWrapper.getPluginId()); - if (pluginApplicationContext == null) - pluginApplicationContext = new AnnotationConfigApplicationContext(); - pluginApplicationContext.setClassLoader(pluginWrapper.getPluginClassLoader()); - PluginApplicationContextManager.addPluginApplicationContext(pluginWrapper.getPluginId(), pluginApplicationContext); - return PluginApplicationContextManager.getApplicationContext(pluginWrapper.getPluginId()); - } - - private void loadResources(String locations) { - String[] staticLocations = locations.split(","); - for (String staticLocation : staticLocations) { - if (staticLocation.contains("classpath:")) { - staticLocation = staticLocation.replace("classpath:", ""); - if (StringUtils.isNotBlank(staticLocation) && staticLocation.startsWith("/")) { - staticLocation = staticLocation.substring(1); - } - this.staticClassPathLocations.add(staticLocation); - } else { - this.staticFileLocations.add(staticLocation); - } - } - } - - public String getMapperXmlDir() { - if (StringUtils.isNotBlank(mapperXmlDir) && mapperXmlDir.startsWith("classpath:")) { - mapperXmlDir = mapperXmlDir.replace("classpath:", ""); - } - if (StringUtils.isNotBlank(mapperXmlDir) && mapperXmlDir.startsWith("/")) { - mapperXmlDir = mapperXmlDir.substring(1); - } - return mapperXmlDir; - } - - /** - * 清理ApplicationContext - */ - public void clearApplicationContext() { - Optional.of(this.getPluginId()) - .ifPresent(var -> PluginApplicationContextManager.removePluginApplicationContext(var.trim())); - Optional.of(this.getPluginApplicationContext()) - .ifPresent(var -> { - var.getDefaultListableBeanFactory().destroySingletons(); - var.close(); - }); - this.applicationContextIsRefresh = false; - this.pluginApplicationContext = null; - } - - /** - * @param c class - * @return java.util.List> - * @description 获取插件内实现指定类的bean - * @author dolphin - */ - public T getPluginBean(Class c) { - try { - return pluginApplicationContext.getBean(c); - } catch (Exception e) { - log.error("要删除的bean:{}不存在" , c.getName()); - return null; - } - } - - public void addController(Class controller) { - this.controllers.add(controller); - } - - public void addPluginConfigObject(Object config) { - this.pluginConfigObjects.add(config); - } - - public void addGroupClass(String groupName, Class clazz) { - classGroups.computeIfAbsent(groupName, k -> new ArrayList<>()).add(clazz); - } - - public List> getGroupClass(String groupName) { - List> result = new ArrayList<>(); - List> classes = classGroups.get(groupName); - if (classes != null) { - result.addAll(classes); - } - return result; - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginLifecycle.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginLifecycle.java deleted file mode 100644 index 26b7230..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginLifecycle.java +++ /dev/null @@ -1,27 +0,0 @@ -package cd.casic.plugin; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin - * @Project:ops - * @name:PluginLifecycle - * @Date:2024/06/15 17:31 - * @Filename:PluginLifecycle - * @description:插件生命周期的操作 - */ -public interface PluginLifecycle { - - /** - * 插件启动前的操作,比如需要单独对插件进行某些特定操作, - * - */ - public void beforeWork(); - - - /** - * 料理后世方的操作 - */ - public void AfterWork(); - - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginManager.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginManager.java deleted file mode 100644 index a4a9213..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginManager.java +++ /dev/null @@ -1,392 +0,0 @@ -package cd.casic.plugin; - -import cd.casic.plugin.event.PluginLoadedEvent; -import cd.casic.plugin.event.PluginUnloadedEvent; -import cd.casic.plugin.pf4j.OpsJarPluginRepository; -import cd.casic.plugin.pf4j.OpsPluginStatusProvider; -import cd.casic.plugin.pf4j.OpsPropertiesPluginDescriptorFinder; -import cd.casic.plugin.pf4j.OpsYamlPluginDescriptorFinder; -import cd.casic.plugin.register.StartPluginManagerHandler; -import cd.casic.plugin.utils.PluginsUtils; -import cd.casic.plugin.utils.SM4EncryptUtil; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.lang3.StringUtils; -import org.pf4j.*; -import org.pf4j.util.FileUtils; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.stereotype.Component; - -import java.io.File; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin - * @Project:ops - * @name:PluginManager - * @Date:2024/03/18 15:03 - * @Filename:PluginManager - * @description:插件核心管理类 - */ -@Slf4j -@Component -public class PluginManager extends DefaultPluginManager implements PluginManagerService, ApplicationContextAware, PluginLifecycle { - - @Getter - ApplicationContext applicationContext; - - @Getter - private final PluginProperties pluginProperties; - - @Autowired - private StartPluginManagerHandler startPluginManagerHandler; - - @Autowired - private BufferedPluginBundleResource bufferedPluginBundleResource; - - @Autowired - private FrontResourceProcessor frontResourceProcessor; - - public PluginManager(@Autowired PluginProperties pluginProperties) { - this.pluginsRoots.add(Paths.get(pluginProperties.getPluginsRoot())); - this.pluginProperties = pluginProperties; - this.setRuntimeMode(pluginProperties.getRuntimeMode()); - super.initialize(); - } - - @Override - protected void initialize() { - // 这里不需要任何操作,只是覆盖父类的initialize方法 - // 如果不重写的话,在调用构造函数的时候会调用父类的无参构造函数,导致父类initialize方法被调用。 - // 父类initialize方法中会调用createPluginStatusProvider方法,该方法需要使用到OpsPluginSystemProperties,而此时还未被注入 - } - - - @Override - public PluginInfo install(Path path) throws Exception { - - // TODO 在install的时候生成插件目录结构 - /* - 工作目录 - │ - ├─plugins - │ ├─example-mybatis-plugin@0.1 插件目录,id@version,存放jar、database、resource - │ │ ├─ops-module-plugin-example-mybatis-plugin.jar 插件jar包,jar包命名不影响 - │ │ ├─database 存放sqlite数据库文件 - │ │ └─resource 存放静态资源 - │ └─example-redis-plugin@1.1.4 - │ ├─ops-module-plugin-example-redis-plugin.jar - │ ├─database - │ └─resource - */ - - String pluginId = null; - try { - this.beforeWork(); - pluginId = this.loadPlugin(path); - super.startPlugin(pluginId); - log.info("install plugin [{}] success", pluginId); - return PluginCache.getPlugin(pluginId); - } catch (Exception e) { - log.error("安装插件出现异常:{}", e.getMessage()); - if (StringUtils.isNotBlank(pluginId)) { - PluginCache.remove(pluginId); - } - throw new Exception(e.getMessage()); - } - } - - @Override - public void installAfter(String pluginId) { - try { - super.stopPlugin(pluginId); - } catch (Exception e) { - e.printStackTrace(); - log.error("install plugin after error:{}", e.getMessage()); - } - } - - @Override - public void unInstall(String pluginId, boolean isUpdate) throws Exception { - // TODO unInstall的时候除掉插件资源 - log.info("准备卸载插件:" + pluginId); - PluginInfo plugin = PluginCache.getPlugin(pluginId); - plugin.clearApplicationContext(); - PluginCache.remove(pluginId); - //删除插件 - PluginsUtils.forceDelete(plugin.getPluginWrapper().getPluginPath().toFile()); - } - - @Override - public void initPlugins(List plugins) throws Exception { - // 初始化插件处理器 - startPluginManagerHandler.initialize(); - for (PluginBean plugin : plugins) { - File file = new File(pluginsRoots.get(0) + File.separator + plugin.getPath()); - if (!file.exists()) { - continue; - } - String pluginId = this.loadPlugin(file.toPath().toAbsolutePath()); - PluginInfo pluginInfo = PluginCache.getPlugin(pluginId); - if (plugin.getStatus() == 1) { - this.startPlugin(pluginInfo.getPluginId()); - } - } - } - - @Override - public List getInstallPlugins() { - return getPlugins(); - } - - /** - * 加载插件 - * - * @param pluginPath 插件路径 - * @return String - */ - @Override - public String loadPlugin(Path pluginPath) { - Optional.ofNullable(pluginPath) - .filter(path -> Files.exists(path)) - .orElseThrow(() -> new IllegalArgumentException(String.format("plugin %s 不存在", pluginPath))); - - log.debug("Loading plugin from '{}'", pluginPath); - - PluginWrapper pluginWrapper = loadPluginFromPath(pluginPath); - PluginInfo pluginInfo = new PluginInfo(pluginWrapper, applicationContext); - try { - resolvePlugins(); - sendPluginEvenet(new PluginLoadedEvent(this, pluginInfo)); - } catch (Exception e) { - log.error("加载插件出现异常:{}", e.getMessage()); - sendPluginEvenet(new PluginUnloadedEvent(this, pluginInfo)); - } - return pluginWrapper.getDescriptor().getPluginId(); - } - - @Override - public PluginWrapper loadPluginFromPath(Path pluginPath) { - try { - pluginPath = FileUtils.expandIfZip(pluginPath); - } catch (Exception var3) { - log.info(MessageFormat.format("路径:{0}的插件包解压缩失败,失败原因{1} ", pluginPath, var3)); - return null; - } - return super.loadPluginFromPath(pluginPath); - } - - @Override - public void loadPlugins() { - log.debug("Lookup plugins in '{}'", pluginsRoots); - // check for plugins roots - if (pluginsRoots.isEmpty()) { - log.warn("No plugins roots configured"); - return; - } - pluginsRoots.forEach(path -> { - if (Files.notExists(path) || !Files.isDirectory(path)) { - log.warn("No '{}' root", path); - } - }); - - // get all plugin paths from repository - List pluginPaths = pluginRepository.getPluginPaths(); - - // check for no plugins - if (pluginPaths.isEmpty()) { - log.info("No plugins"); - return; - } - - log.debug("Found {} possible plugins: {}", pluginPaths.size(), pluginPaths); - - // load plugins from plugin paths - for (Path pluginPath : pluginPaths) { - try { - PluginWrapper pluginWrapper = this.loadPluginFromPath(pluginPath); - if (ObjectUtils.isNotEmpty(pluginWrapper)) { - String license = pluginWrapper.getDescriptor().getLicense(); - if (SM4EncryptUtil.checkLicense(pluginWrapper.getDescriptor().getLicense(), pluginWrapper.getPluginId())) { - PluginInfo plugin = new PluginInfo(pluginWrapper, applicationContext); - // startPluginManagerHandler.registry(plugin); - sendPluginEvenet(new PluginLoadedEvent(this, plugin)); - } - } - } catch (Exception e) { - log.error(e.getMessage(), e); - } - } - - // resolve plugins - try { - resolvePlugins(); - } catch (PluginRuntimeException e) { - log.error(e.getMessage(), e); - } - } - - @Override - public boolean unloadPlugin(String pluginId) { - if (pluginId == null) { - throw new IllegalArgumentException(String.format("plugin %s 不存在", pluginId)); - } - log.info("unloading plugin {}", pluginId); - try { - super.unloadPlugin(pluginId, true); - } catch (Exception e) { - log.info("卸载插件出现异常,{}", e.getMessage()); - return false; - } finally { - sendPluginEvenet(new PluginUnloadedEvent(this, PluginCache.getPlugin(pluginId))); - System.gc(); - } - return true; - } - - - @Override - public void unloadPlugins() { - for (PluginWrapper pluginWrapper : new ArrayList<>(resolvedPlugins)) { - this.unloadPlugin(pluginWrapper.getPluginId()); - } - } - - @Override - public PluginState startPlugin(String pluginId) { - PluginState pluginState = null; - try { - PluginInfo plugin = PluginCache.getPlugin(pluginId); - if (plugin.getPluginWrapper().getPluginState().equals(PluginState.DISABLED)) return PluginState.STOPPED; - - if (ObjectUtils.isEmpty((plugin.getPluginApplicationContext()))) { - plugin.setPluginApplicationContext(plugin.getContext()); - plugin.getPluginApplicationContext().setParent(applicationContext); - } - - startPluginManagerHandler.registry(plugin); - pluginState = super.startPlugin(pluginId); - - // todo 这里有uglify存在循环遍历的问题,后面改 - bufferedPluginBundleResource.getJsBundle(String.valueOf(System.currentTimeMillis()), frontResourceProcessor.uglifyJsBundle()); - bufferedPluginBundleResource.getCssBundle(String.valueOf(System.currentTimeMillis()), frontResourceProcessor.uglifyCssBundle()); -// bufferedPluginBundleResource.getHtmlBundle(String.valueOf(System.currentTimeMillis()), frontResourceProcessor.uglifyHtmlBundle()); - } catch (Exception e) { - e.printStackTrace(); - log.error("plugin start error : {}", e.getMessage()); - } - return pluginState; - } - - protected PluginState stopPlugin(String pluginId, boolean stopDependents) { - checkPluginId(pluginId); - - PluginWrapper pluginWrapper = getPlugin(pluginId); - PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor(); - PluginState pluginState = pluginWrapper.getPluginState(); - if (PluginState.STOPPED == pluginState) { - log.debug("Already stopped plugin '{}'", getPluginLabel(pluginDescriptor)); - return PluginState.STOPPED; - } - - // test for disabled plugin - if (PluginState.DISABLED == pluginState) { - // do nothing - return pluginState; - } - - if (stopDependents) { - List dependents = dependencyResolver.getDependents(pluginId); - while (!dependents.isEmpty()) { - String dependent = dependents.remove(0); - stopPlugin(dependent, false); - dependents.addAll(0, dependencyResolver.getDependents(dependent)); - } - } - - log.info("Stop plugin '{}'", getPluginLabel(pluginDescriptor)); - pluginWrapper.getPlugin().stop(); - pluginWrapper.setPluginState(PluginState.STOPPED); - startedPlugins.remove(pluginWrapper); - - try { - // todo 没得到plugin - PluginInfo plugin = PluginCache.getPlugin(pluginId); - // todo 停止事件 - startPluginManagerHandler.unRegistry(plugin); - plugin.clearApplicationContext(); - } catch (Exception e) { - log.error("plugin stop error : {}", e.getMessage()); - } - - firePluginStateEvent(new PluginStateEvent(this, pluginWrapper, pluginState)); - this.AfterWork(); - return pluginWrapper.getPluginState(); - } - - public void setRuntimeMode(RuntimeMode runtimeMode) { - this.runtimeMode = runtimeMode; - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - - @Override - protected PluginDescriptorFinder createPluginDescriptorFinder() { - return new CompoundPluginDescriptorFinder() - .add(new OpsPropertiesPluginDescriptorFinder()) - .add(new OpsYamlPluginDescriptorFinder()); - } - - @Override - protected PluginRepository createPluginRepository() { -// return new CompoundPluginRepository() -// .add(new DevelopmentPluginRepository(getPluginsRoots()), this::isDevelopment) -// .add(new OpsJarPluginRepository(getPluginsRoots()), this::isNotDevelopment); - // .add(new DefaultPluginRepository(getPluginsRoots()), this::isNotDevelopment); - return new OpsJarPluginRepository(getPluginsRoots()); - } - - @Override - protected PluginLoader createPluginLoader() { - return new CompoundPluginLoader() - .add(new JarPluginLoader(this)) - .add(new DefaultPluginLoader(this)); - } - - @Override - public boolean isDevelopment() { - return this.getRuntimeMode().equals(RuntimeMode.DEVELOPMENT); - } - - @Override - protected PluginStatusProvider createPluginStatusProvider() { - if (OpsPluginStatusProvider.isPropertySet(pluginProperties)) { - return new OpsPluginStatusProvider(pluginProperties); - } - return super.createPluginStatusProvider(); - } - - @Override - public void beforeWork() { - - } - - @Override - public void AfterWork() { - - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginManagerService.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginManagerService.java deleted file mode 100644 index a4811c1..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginManagerService.java +++ /dev/null @@ -1,69 +0,0 @@ -package cd.casic.plugin; - -import cd.casic.framework.commons.util.spring.SpringUtils; -import org.pf4j.PluginState; -import org.pf4j.PluginWrapper; -import org.springframework.context.ApplicationEvent; - -import java.nio.file.Path; -import java.util.List; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin - * @Project:ops - * @name:PluginManagerService - * @Date:2024/03/18 14:46 - * @Filename:PluginManagerService - * @description:插件基础安装类 - */ -public interface PluginManagerService { - /** - * @param path 插件路径 - * @description 安装插件 - */ - PluginInfo install(Path path) throws Exception; - - /** - * 安装插件后置操作 - * - * @param pluginId pluginId - */ - void installAfter(String pluginId); - - /** - * @description 卸载插件 - */ - void unInstall(String pluginId, boolean isUpdate) throws Exception; - - /** - * 启动插件 - * - * @param pluginId - * @return - */ - PluginState startPlugin(String pluginId); - - /** - * 停止插件 - * - * @param pluginId pluginId - * @return PluginState - */ - PluginState stopPlugin(String pluginId); - - /** - * @description 插件初始化 - */ - void initPlugins(List plugins) throws Exception; - - /** - * @description 获取所有插件 - */ - List getInstallPlugins(); - - - default void sendPluginEvenet(ApplicationEvent applicationEvent) { - SpringUtils.publishEvent(applicationEvent); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginProperties.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginProperties.java deleted file mode 100644 index 7a629ae..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginProperties.java +++ /dev/null @@ -1,53 +0,0 @@ -package cd.casic.plugin; - -import cn.hutool.core.io.FileUtil; -import lombok.Data; -import org.pf4j.RuntimeMode; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.boot.context.properties.ConfigurationProperties; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.HashSet; -import java.util.Set; - -@Data -@ConfigurationProperties(prefix = "cd.casic.ops.plugin") -public class PluginProperties implements InitializingBean { - /** - * 是否启用插件系统 - */ - private Boolean enable; - /** - * 插件根目录 - */ - private String pluginsRoot; - /** - * 运行模式,可以是 development 或者 deployment - */ - private RuntimeMode runtimeMode; - /** - * 插件接口RESTful API的路径前缀 - */ - private String restPathPrefix; - /** - * 是否在RESTful API前缀中包含插件ID,默认为true - */ - private boolean enablePluginIdAsRestPrefix = true; - /** - * 已启用的插件集合 - */ - private Set enabledPlugins = new HashSet<>(); - /** - * 已禁用的插件集合 - */ - private Set disabledPlugins = new HashSet<>(); - - @Override - public void afterPropertiesSet() { - Path pluginsRootPath = Paths.get(this.pluginsRoot); - if (!pluginsRootPath.toFile().exists()) { - FileUtil.mkdir(pluginsRootPath.toFile()); - } - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginYamlConfigurationParser.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginYamlConfigurationParser.java deleted file mode 100644 index 34df992..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginYamlConfigurationParser.java +++ /dev/null @@ -1,72 +0,0 @@ -package cd.casic.plugin; - -import cd.casic.plugin.utils.YamlUtils; -import cn.hutool.core.util.StrUtil; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.TreeTraversingParser; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import com.fasterxml.jackson.dataformat.yaml.YAMLParser; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; - -import java.io.InputStream; -import java.nio.file.Path; - -public class PluginYamlConfigurationParser { - private final ObjectMapper objectMapper; - private final YAMLFactory yamlFactory; - - public PluginYamlConfigurationParser(){ - this.objectMapper = new ObjectMapper(); - this.yamlFactory = new YAMLFactory(); - } - - public Object parse(PluginInfo pluginInfo, PluginConfigWrapper pluginConfigWrapper) throws Exception { - Class configClass = pluginConfigWrapper.getConfigClass(); - if(configClass == null){ - throw new IllegalArgumentException("pluginConfigDefinition : " + pluginConfigWrapper + " " + - "configClass can not be null"); - } - String yamlFileName = pluginConfigWrapper.getFileName(); - if(StrUtil.isEmpty(yamlFileName)){ - throw new IllegalArgumentException("pluginConfigDefinition : " + pluginConfigWrapper + " " + - "fileName can not be empty"); - } - - Path yamlPath = YamlUtils.getYamlPath(pluginInfo.getPluginWrapper().getPluginPath(), yamlFileName); - Resource resource = new FileSystemResource(yamlPath); - Object o = convert(resource, configClass); - if(o == null){ - return configClass.getConstructor().newInstance(); - } - return o; - } - - - private Object convert(Resource resource, Class configClass) throws Exception { - InputStream inputStream = null; - YAMLParser yamlParser = null; - TreeTraversingParser treeTraversingParser = null; - try { - inputStream = resource.getInputStream(); - yamlParser = yamlFactory.createParser(inputStream); - final JsonNode node = objectMapper.readTree(yamlParser); - if(node == null){ - return configClass.getConstructor().newInstance(); - } - treeTraversingParser = new TreeTraversingParser(node); - return objectMapper.readValue(treeTraversingParser, configClass); - } finally { - if(treeTraversingParser != null){ - treeTraversingParser.close(); - } - if(yamlParser != null){ - yamlParser.close(); - } - if(inputStream != null){ - inputStream.close(); - } - } - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginYamlProcessor.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginYamlProcessor.java deleted file mode 100644 index ca3d542..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/PluginYamlProcessor.java +++ /dev/null @@ -1,43 +0,0 @@ -package cd.casic.plugin; - -import cd.casic.plugin.utils.PluginDescriptorUtils; -import org.springframework.beans.factory.config.YamlProcessor; -import org.springframework.core.io.Resource; - -import java.util.ArrayList; -import java.util.List; - -import static cd.casic.plugin.utils.PluginDescriptorUtils.*; - - -public class PluginYamlProcessor extends YamlProcessor { - /** - * 检查这些必须有的属性是否存在 - */ - private static final DocumentMatcher DEFAULT_DOCUMENT_MATCHER = properties -> { - if (properties.containsKey(PLUGIN_ID) - && properties.containsKey(PLUGIN_VERSION) - && properties.containsKey(PLUGIN_CLASS)){ - return MatchStatus.FOUND; - } - return MatchStatus.NOT_FOUND; - }; - - public PluginYamlProcessor(Resource... resources) { - setResources(resources); - setDocumentMatchers(DEFAULT_DOCUMENT_MATCHER); - } - - /** - * 读取yaml文件 - * @return PluginDescriptorStorage 插件的相关配置信息以及后续用于插件信息持久化存储的持久化对象 - */ - public PluginDescriptorStorage loadYaml() { - List pluginDescriptor = new ArrayList<>(); - this.process(((properties, map) -> { - pluginDescriptor.add(PluginDescriptorUtils.propertiesToStorage(properties)); - })); - - return pluginDescriptor.get(0); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/annotation/AdminGroup.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/annotation/AdminGroup.java deleted file mode 100644 index 1a54110..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/annotation/AdminGroup.java +++ /dev/null @@ -1,38 +0,0 @@ -package cd.casic.plugin.annotation; - - -import cd.casic.plugin.constants.OpsConstants; - -import java.lang.annotation.*; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.annotation - * @Project:ops - * @name:AdminGroup - * @Date:2024/03/18 17:06 - * @Filename:AdminGroup - * @description:自定义菜单Group注解 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.ANNOTATION_TYPE}) -@Documented -public @interface AdminGroup { - /** 菜单名称 */ - String name(); - - /** 菜单组id */ - String groupId(); - - /** 菜单图标 */ - String icon() default "fa-circle-o"; - - /** 菜单url */ - String url() default ""; - - /** 菜单角色 */ - String[] role() default {OpsConstants.ROLE_ADMIN}; - - /** 菜单序号 */ - int seq() default 99; -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/annotation/AdminGroups.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/annotation/AdminGroups.java deleted file mode 100644 index 191c5f4..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/annotation/AdminGroups.java +++ /dev/null @@ -1,20 +0,0 @@ -package cd.casic.plugin.annotation; - -import java.lang.annotation.*; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.annotation - * @Project:ops - * @name:AdminGroups - * @Date:2024/03/18 17:05 - * @Filename:AdminGroups - * @description:自定义菜单groups注解 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.TYPE}) -@Documented -public @interface AdminGroups { - /** 菜单组 */ - AdminGroup[] groups(); -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/annotation/InterceptPath.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/annotation/InterceptPath.java deleted file mode 100644 index 88b8171..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/annotation/InterceptPath.java +++ /dev/null @@ -1,22 +0,0 @@ -package cd.casic.plugin.annotation; - -import java.lang.annotation.*; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.annotation - * @Project:ops - * @name:InterceptPath - * @Date:2024/03/18 16:09 - * @Filename:InterceptPath - * @description:插件拦截器 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Documented -public @interface InterceptPath { - /** - * 拦截的路径 - */ - String[] value(); -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/annotation/PluginConfiguration.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/annotation/PluginConfiguration.java deleted file mode 100644 index e6a94ec..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/annotation/PluginConfiguration.java +++ /dev/null @@ -1,17 +0,0 @@ -package cd.casic.plugin.annotation; - -import java.lang.annotation.*; - -/** - * 用于标记插件内部的独立配置类 - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface PluginConfiguration { - String fileName() default ""; // 插件配置文件的文件名 - - String deploySuffix() default ""; // 插件配置文件在deployment模式下的后缀 - - String devSuffix() default ""; // 插件配置文件在development模式下的后缀 -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/config/OpsPluginConfig.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/config/OpsPluginConfig.java deleted file mode 100644 index 28ceb18..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/config/OpsPluginConfig.java +++ /dev/null @@ -1,29 +0,0 @@ -package cd.casic.plugin.config; - -import cd.casic.plugin.PluginManager; -import cd.casic.plugin.PluginProperties; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * 配置类:用于定义和管理插件系统的Bean - */ -@Configuration -@EnableConfigurationProperties({PluginProperties.class}) -public class OpsPluginConfig { - /** - * 定义并创建一个PluginManager Bean - *

- * 此Bean负责管理和操作插件系统,仅在没有已定义的PluginManager Bean时创建 - * - * @param pluginProperties 插件系统的属性配置,用于初始化PluginManager - * @return 初始化并配置好的PluginManager实例 - */ - @Bean - @ConditionalOnMissingBean - public PluginManager pluginManager(PluginProperties pluginProperties) { - return new PluginManager(pluginProperties); - } -} \ No newline at end of file diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/constants/OpsConstants.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/constants/OpsConstants.java deleted file mode 100644 index a896d40..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/constants/OpsConstants.java +++ /dev/null @@ -1,53 +0,0 @@ -package cd.casic.plugin.constants; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.constants - * @Project:ops - * @name:OpsConstants - * @Date:2024/03/18 9:30 - * @Filename:OpsConstants - * @description:Todo - */ -public class OpsConstants { - /** - * 插件目录 - */ - public static final String PLUGIN_PATH = "/plugins"; - /** - * 插件路径 - */ - public static final String PLUGINS_DIR = "resources/plugins"; - /** - * 插件静态资源目录 - */ - public static final String PLUGINS_RESOURCES_DIR = "resources/pluginResources"; - //public static final String PLUGINS_RESOURCES_DIR = "ops-module-plugins/ops-module-plugins-example-web/src/main/resources/static"; - - /** - * 角色:管理员 - */ - public static final String ROLE_ADMIN = "admin"; - /** - * 角色:用户 - */ - public static final String ROLE_USER = "user"; - /** - * 角色:编辑 - */ - public static final String ROLE_EDITOR = "editor"; - - - /** - * todo 区分插件类型,目前只支持两种,一种为zip ,一种为jar包形式,主要使用zip形式,别面jar包被人轻易破解 - */ - public static class Suffix { - - private Suffix() { - throw new IllegalStateException(); - } - - public static final String JAR = "jar"; - public static final String ZIP = "zip"; - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/constants/PluginBuildTypeEnum.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/constants/PluginBuildTypeEnum.java deleted file mode 100644 index 62d34d8..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/constants/PluginBuildTypeEnum.java +++ /dev/null @@ -1,27 +0,0 @@ -package cd.casic.plugin.constants; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.constants - * @Project:ops - * @name:PluginBuildTypeEnum - * @Date:2024/03/21 19:53 - * @Filename:PluginBuildTypeEnum - * @description:插件构建方式区分 - */ -public enum PluginBuildTypeEnum { - - /** - * 构建 - */ - BUILD, - /** - * 注册 - */ - REGISTER, - /** - * 卸载 - */ - UNREGISTER - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/OpsMainAppReadyEvent.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/OpsMainAppReadyEvent.java deleted file mode 100644 index 9d7a715..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/OpsMainAppReadyEvent.java +++ /dev/null @@ -1,20 +0,0 @@ -package cd.casic.plugin.event; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationEvent; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.event - * @Project:ops - * @name:OpsMainAppReadyEvent - * @Date:2024/03/22 10:29 - * @Filename:OpsMainAppReadyEvent - * @description:主程序启动完毕,此事件发布到插件应用程序,此时,插件还未启动 - */ -public class OpsMainAppReadyEvent extends ApplicationEvent { - - public OpsMainAppReadyEvent(ApplicationContext mainApplicationContext) { - super(mainApplicationContext); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/OpsMainAppStartedEvent.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/OpsMainAppStartedEvent.java deleted file mode 100644 index 2f798c6..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/OpsMainAppStartedEvent.java +++ /dev/null @@ -1,20 +0,0 @@ -package cd.casic.plugin.event; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationEvent; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.event - * @Project:ops - * @name:OpsMainAppStartedEvent - * @Date:2024/03/22 10:31 - * @Filename:OpsMainAppStartedEvent - * @description:主程序启动完毕,此事件发布到插件应用程序,此时,原神启动 - */ -public class OpsMainAppStartedEvent extends ApplicationEvent { - - public OpsMainAppStartedEvent(ApplicationContext mainApplicationContext) { - super(mainApplicationContext); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginDirCheckEvent.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginDirCheckEvent.java deleted file mode 100644 index 7a1972b..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginDirCheckEvent.java +++ /dev/null @@ -1,13 +0,0 @@ -package cd.casic.plugin.event; - -import lombok.Getter; -import org.springframework.context.ApplicationEvent; - -@Getter -public class PluginDirCheckEvent extends ApplicationEvent { - - public PluginDirCheckEvent(Object source) { - super(source); - } - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginLoadedEvent.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginLoadedEvent.java deleted file mode 100644 index 96e6a9f..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginLoadedEvent.java +++ /dev/null @@ -1,30 +0,0 @@ -package cd.casic.plugin.event; - -import cd.casic.plugin.PluginCache; -import cd.casic.plugin.PluginClassLoaderCache; -import cd.casic.plugin.PluginInfo; -import cd.casic.plugin.PluginManager; -import lombok.Getter; -import org.springframework.context.ApplicationEvent; - -@Getter -public class PluginLoadedEvent extends ApplicationEvent { - - private final PluginManager pluginManager; - - private final PluginInfo pluginInfo; - - public PluginLoadedEvent(Object source, PluginInfo pluginInfo) { - super(source); - this.pluginManager = (PluginManager) source; - this.pluginInfo = pluginInfo; - - if (!PluginCache.isExist(pluginInfo.getPluginId())) { - PluginCache.put(pluginInfo.getPluginId(), pluginInfo); - } - if (PluginClassLoaderCache.getPlugin(pluginInfo.getPluginId()) == null) { - PluginClassLoaderCache.put(pluginInfo.getPluginId(), pluginInfo.getPluginWrapper().getPluginClassLoader()); - } - } - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginRestartedEvent.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginRestartedEvent.java deleted file mode 100644 index 8933a3f..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginRestartedEvent.java +++ /dev/null @@ -1,19 +0,0 @@ -package cd.casic.plugin.event; - -import org.springframework.context.ApplicationEvent; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.event - * @Project:ops - * @name:PluginRestartedEvent - * @Date:2024/03/22 10:51 - * @Filename:PluginRestartedEvent - * @description:插件重启,在插件管理器中重启插件,和同目录上面的OpsMian****的事件不同 - */ -public class PluginRestartedEvent extends ApplicationEvent { - - public PluginRestartedEvent(Object source) { - super(source); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginStartedEvent.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginStartedEvent.java deleted file mode 100644 index b8ad5ca..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginStartedEvent.java +++ /dev/null @@ -1,20 +0,0 @@ -package cd.casic.plugin.event; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationEvent; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.event - * @Project:ops - * @name:PluginStartedEvent - * @Date:2024/03/22 10:57 - * @Filename:PluginStartedEvent - * @description:发布到插件管理器 - */ -public class PluginStartedEvent extends ApplicationEvent { - - public PluginStartedEvent(ApplicationContext pluginApplicationContext) { - super(pluginApplicationContext); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginStateChangedEvent.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginStateChangedEvent.java deleted file mode 100644 index 9f6527c..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginStateChangedEvent.java +++ /dev/null @@ -1,19 +0,0 @@ -package cd.casic.plugin.event; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationEvent; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.event - * @Project:ops - * @name:PluginStateChangedEvent - * @Date:2024/03/22 11:02 - * @Filename:PluginStateChangedEvent - * @description:插件状态,这个是考虑到插件的更新 - */ -public class PluginStateChangedEvent extends ApplicationEvent { - public PluginStateChangedEvent(ApplicationContext mainApplicationContext) { - super(mainApplicationContext); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginStoppedEvent.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginStoppedEvent.java deleted file mode 100644 index 5c76b01..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginStoppedEvent.java +++ /dev/null @@ -1,19 +0,0 @@ -package cd.casic.plugin.event; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationEvent; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.event - * @Project:ops - * @name:PluginStoppedEvent - * @Date:2024/03/22 11:05 - * @Filename:PluginStoppedEvent - * @description:插件停止,停止后应该删除一切内容 - */ -public class PluginStoppedEvent extends ApplicationEvent { - public PluginStoppedEvent(ApplicationContext pluginApplicationContext) { - super(pluginApplicationContext); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginUnloadedEvent.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginUnloadedEvent.java deleted file mode 100644 index ab30894..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/event/PluginUnloadedEvent.java +++ /dev/null @@ -1,26 +0,0 @@ -package cd.casic.plugin.event; - -import cd.casic.plugin.*; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.ApplicationEvent; - -@Getter -@Slf4j -public class PluginUnloadedEvent extends ApplicationEvent { - - private final PluginManager pluginManager; - - private final PluginInfo pluginInfo; - - public PluginUnloadedEvent(Object source, PluginInfo pluginInfo) { - super(source); - this.pluginManager = (PluginManager) source; - this.pluginInfo = pluginInfo; - - String startErrorPluginId = this.pluginInfo.getPluginId(); - PluginCache.remove(startErrorPluginId); - PluginClassLoaderCache.remove(startErrorPluginId); - PluginApplicationContextManager.removePluginApplicationContext(startErrorPluginId); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/execption/PluginException.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/execption/PluginException.java deleted file mode 100644 index c665cdf..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/execption/PluginException.java +++ /dev/null @@ -1,29 +0,0 @@ -package cd.casic.plugin.execption; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.execption - * @Project:ops - * @name:PluginException - * @Date:2024/03/21 19:54 - * @Filename:PluginException - * @description:毫无疑问,看这个名字就知道是插件异常类 - */ -public class PluginException extends RuntimeException { - - public PluginException() { - super(); - } - - public PluginException(String s) { - super(s); - } - - public PluginException(String message, Throwable cause) { - super(message, cause); - } - - public PluginException(Throwable cause) { - super(cause); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/pf4j/OpsJarPluginRepository.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/pf4j/OpsJarPluginRepository.java deleted file mode 100644 index a9cc4dd..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/pf4j/OpsJarPluginRepository.java +++ /dev/null @@ -1,55 +0,0 @@ -package cd.casic.plugin.pf4j; - -import lombok.extern.slf4j.Slf4j; -import org.pf4j.JarPluginRepository; - -import java.io.File; -import java.io.IOException; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -@Slf4j -public class OpsJarPluginRepository extends JarPluginRepository { - - public OpsJarPluginRepository(Path... pluginsRoots) { - this(Arrays.asList(pluginsRoots)); - } - - public OpsJarPluginRepository(List pluginsRoots) { - super(pluginsRoots); - } - - @Override - public List getPluginPaths() { - List pluginPaths = new ArrayList<>(); - for (Path pluginRoot : pluginsRoots){ - File rootDir = pluginRoot.toFile(); - - scanForJars(rootDir.toPath(), pluginPaths); - - } - return pluginPaths; - } - - private void scanForJars(Path directory, List pluginPaths) { - try (DirectoryStream stream = Files.newDirectoryStream(directory)) { - for (Path entry : stream) { - if (Files.isDirectory(entry)) { - // 如果是目录,递归进入下一层 - scanForJars(entry, pluginPaths); - } else if (entry.getFileName().toString().endsWith(".jar")) { - // 如果是.jar文件,添加到结果列表 - pluginPaths.add(entry); - } - } - } catch (IOException e) { - System.err.println("Error scanning directory " + directory + ": " + e.getMessage()); - } - } - - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/pf4j/OpsPluginDescriptor.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/pf4j/OpsPluginDescriptor.java deleted file mode 100644 index 6fbef82..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/pf4j/OpsPluginDescriptor.java +++ /dev/null @@ -1,20 +0,0 @@ -package cd.casic.plugin.pf4j; - -import lombok.Getter; -import org.pf4j.DefaultPluginDescriptor; - -import java.util.List; - -@Getter -public class OpsPluginDescriptor extends DefaultPluginDescriptor { - private final String configFileName; - private final List configFileActive; - - public OpsPluginDescriptor(String pluginId, String pluginDescription, String pluginClass, - String version, String requires, String provider, String license, - String configFileName, List configFileActive){ - super(pluginId, pluginDescription, pluginClass, version, requires, provider, license); - this.configFileActive = configFileActive; - this.configFileName = configFileName; - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/pf4j/OpsPluginStatusProvider.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/pf4j/OpsPluginStatusProvider.java deleted file mode 100644 index e83b393..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/pf4j/OpsPluginStatusProvider.java +++ /dev/null @@ -1,50 +0,0 @@ -package cd.casic.plugin.pf4j; - -import cd.casic.plugin.PluginProperties; -import cn.hutool.core.collection.CollectionUtil; -import org.pf4j.PluginStatusProvider; - -import java.util.HashSet; -import java.util.Set; - -public class OpsPluginStatusProvider implements PluginStatusProvider { - - private final Set enabledPlugins = new HashSet<>(); - private final Set disabledPlugins = new HashSet<>(); - - public OpsPluginStatusProvider(PluginProperties pluginProperties) { - this.enabledPlugins.addAll(pluginProperties.getEnabledPlugins()); - this.disabledPlugins.addAll(pluginProperties.getDisabledPlugins()); - } - - public static boolean isPropertySet(PluginProperties pluginProperties) { - return CollectionUtil.isNotEmpty(pluginProperties.getEnabledPlugins()) - || CollectionUtil.isNotEmpty(pluginProperties.getDisabledPlugins()); - } - - @Override - public boolean isPluginDisabled(String pluginId) { - if (disabledPlugins.contains(pluginId)) { - return true; - } - return !enabledPlugins.isEmpty() && !enabledPlugins.contains(pluginId); - } - - @Override - public void disablePlugin(String pluginId) { - if (isPluginDisabled(pluginId)) { - return; - } - disabledPlugins.add(pluginId); - enabledPlugins.remove(pluginId); - } - - @Override - public void enablePlugin(String pluginId) { - if (!isPluginDisabled(pluginId)) { - return; - } - enabledPlugins.add(pluginId); - disabledPlugins.remove(pluginId); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/pf4j/OpsPropertiesPluginDescriptorFinder.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/pf4j/OpsPropertiesPluginDescriptorFinder.java deleted file mode 100644 index fe89008..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/pf4j/OpsPropertiesPluginDescriptorFinder.java +++ /dev/null @@ -1,60 +0,0 @@ -package cd.casic.plugin.pf4j; - -import cd.casic.plugin.PluginDescriptorCache; -import cd.casic.plugin.PluginDescriptorStorage; -import cd.casic.plugin.utils.PluginDescriptorUtils; -import org.pf4j.DevelopmentPluginClasspath; -import org.pf4j.PluginDescriptor; -import org.pf4j.PluginRuntimeException; -import org.pf4j.PropertiesPluginDescriptorFinder; -import org.pf4j.util.FileUtils; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Properties; - -public class OpsPropertiesPluginDescriptorFinder extends PropertiesPluginDescriptorFinder { - static final DevelopmentPluginClasspath PLUGIN_CLASSPATH = new DevelopmentPluginClasspath(); - - public OpsPropertiesPluginDescriptorFinder(){ - super(); - } - - public OpsPropertiesPluginDescriptorFinder(String propertiesFileName){ - super(propertiesFileName); - } - - @Override - protected Path getPropertiesPath(Path pluginPath, String propertiesFileName) { - if (Files.isDirectory(pluginPath)) { - for (String location : PLUGIN_CLASSPATH.getClassesDirectories()) { - Path path = pluginPath.resolve(location).resolve(propertiesFileName); - Resource propertyResource = new FileSystemResource(path); - if (propertyResource.exists()) { - return path; - } - } - throw new PluginRuntimeException( - "Unable to find plugin descriptor file: " + DEFAULT_PROPERTIES_FILE_NAME); - } - - // it's a zip or jar file - try { - return FileUtils.getPath(pluginPath, propertiesFileName); - } catch (IOException e) { - throw new PluginRuntimeException(e); - } - } - - @Override - public PluginDescriptor find(Path pluginPath) { - Properties properties = readProperties(pluginPath); - PluginDescriptorStorage storage = PluginDescriptorUtils.propertiesToStorage(properties); - PluginDescriptorCache.put(storage.getPluginId(), storage); - return PluginDescriptorUtils.storageToDescriptor(storage); - } - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/pf4j/OpsYamlPluginDescriptorFinder.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/pf4j/OpsYamlPluginDescriptorFinder.java deleted file mode 100644 index 96b5bc8..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/pf4j/OpsYamlPluginDescriptorFinder.java +++ /dev/null @@ -1,64 +0,0 @@ -package cd.casic.plugin.pf4j; - -import cd.casic.plugin.PluginDescriptorCache; -import cd.casic.plugin.PluginDescriptorStorage; -import cd.casic.plugin.PluginYamlProcessor; -import cd.casic.plugin.utils.PluginDescriptorUtils; -import cd.casic.plugin.utils.YamlUtils; -import lombok.extern.slf4j.Slf4j; -import org.pf4j.PluginDescriptor; -import org.pf4j.PluginDescriptorFinder; -import org.pf4j.PluginRuntimeException; -import org.pf4j.util.FileUtils; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; - -import java.nio.file.Files; -import java.nio.file.Path; - -@Slf4j -public class OpsYamlPluginDescriptorFinder implements PluginDescriptorFinder { - public static final String DEFAULT_YAML_FILE_NAME = "plugin.yaml"; - - private final String yamlFileName; - - public OpsYamlPluginDescriptorFinder() { - this(DEFAULT_YAML_FILE_NAME); - } - - public OpsYamlPluginDescriptorFinder(String yamlFileName) { - this.yamlFileName = yamlFileName; - } - - @Override - public boolean isApplicable(Path pluginPath) { - return Files.exists(pluginPath) - && (Files.isDirectory(pluginPath) - || FileUtils.isJarFile(pluginPath)); - } - - @Override - public PluginDescriptor find(Path pluginPath) { - Path yamlPath = null; - try { - yamlPath = YamlUtils.getYamlPath(pluginPath, yamlFileName); - if (yamlPath == null) { - throw new PluginRuntimeException("Cannot find the plugin manifest path"); - } - log.debug("Lookup plugin descriptor in '{}'", yamlPath); - if (Files.notExists(yamlPath)) { - throw new PluginRuntimeException("Cannot find '{}' path", yamlPath); - } - - Resource yamlResource = new FileSystemResource(yamlPath); - PluginYamlProcessor pluginYamlProcessor = new PluginYamlProcessor(yamlResource); - PluginDescriptorStorage pluginDescriptor = pluginYamlProcessor.loadYaml(); - PluginDescriptorCache.put(pluginDescriptor.getPluginId(), pluginDescriptor); - OpsPluginDescriptor defaultPluginDescriptor = PluginDescriptorUtils.storageToDescriptor(pluginDescriptor); - pluginDescriptor.getDependencies().forEach(defaultPluginDescriptor::addDependency); - return defaultPluginDescriptor; - } finally { - FileUtils.closePath(yamlPath); - } - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/AnnotationHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/AnnotationHandler.java deleted file mode 100644 index f0e53d5..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/AnnotationHandler.java +++ /dev/null @@ -1,145 +0,0 @@ -package cd.casic.plugin.register; - -import cd.casic.plugin.BasePlugin; -import cd.casic.plugin.PluginClassLoaderCache; -import cd.casic.plugin.PluginInfo; -import cd.casic.plugin.annotation.AdminGroups; -import cd.casic.plugin.annotation.InterceptPath; -import cd.casic.plugin.register.group.AnnotationUtils; -import cd.casic.plugin.register.group.ClassGroupHandler; -import lombok.extern.slf4j.Slf4j; -import org.apache.ibatis.annotations.Mapper; -import org.pf4j.PluginWrapper; -import org.pf4j.util.FileUtils; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.stereotype.Component; -import org.springframework.stereotype.Controller; -import org.springframework.stereotype.Repository; -import org.springframework.stereotype.Service; -import org.springframework.web.bind.annotation.RestController; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.stream.Collectors; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.register - * @Project:ops - * @name:AnnotationHandler - * @Date:2024/03/18 15:59 - * @Filename:AnnotationHandler - * @deprecated 不再使用,改用{@link ClassGroupHandler} 实现扫包后分组存储。 - */ -@Slf4j -@Deprecated -public class AnnotationHandler implements BasePluginHandler { - private final static Class[] REGISTER_ANNO = { - Bean.class, - Mapper.class, - Service.class, - Component.class, - Repository.class, - Controller.class, - Configuration.class, - RestController.class, - InterceptPath.class, - }; - - @Override - public void initialize() throws Exception { - - } - - @Override - public void registry(PluginInfo plugin) throws Exception { - List> classList = new ArrayList<>(); - List> adminGroupsClassList = new ArrayList<>(); - Set classPackageName = scanClassPackageName(plugin.getBasePlugin().scanPackage(), plugin.getBasePlugin().getWrapper()); - for (String packageName : classPackageName) { - ClassLoader loader = PluginClassLoaderCache.getPlugin(plugin.getPluginId()); - log.info("Load class {} using classloader {} for plugin {}", packageName, PluginClassLoaderCache.getPlugin(plugin.getPluginId()), plugin.getPluginId()); - Class clazz = loader.loadClass(packageName); -// Class clazz = plugin.getPluginWrapper().getPluginClassLoader().loadClass(packageName); -// log.info("Load class {} using classloader {} for plugin {}", packageName, plugin.getPluginWrapper().getPluginClassLoader(), plugin.getPluginId()); - if (!BasePlugin.class.isAssignableFrom(clazz)) { - classList.add(clazz); - } - AdminGroups annotation = clazz.getAnnotation(AdminGroups.class); - if (annotation != null) { - adminGroupsClassList.add(clazz); - } - } - plugin.setClassList(classList); - plugin.setAdminGroupsClassList(adminGroupsClassList); - List> pluginClassList = plugin.getClassList().stream().filter(item -> !item.isInterface()).collect(Collectors.toList()); - if (!pluginClassList.isEmpty()) { - List> registryClassList = new ArrayList<>(); - for (Class aClass : pluginClassList) { - // 原本这里使用Collections.disjoint()实现,是有问题的,结果总是true。 - // 因为aClass.getAnnotations()获得的是Proxy数组,而REGIS_ANNO是Class数组 - if(AnnotationUtils.hasAnnotations(aClass, false, Bean.class, - Mapper.class, - Service.class, - Component.class, - Repository.class, - Controller.class, - Configuration.class, - RestController.class, - InterceptPath.class)){ - registryClassList.add(aClass); - } - } - if (!registryClassList.isEmpty()) { - plugin.getPluginApplicationContext().register(registryClassList.toArray(new Class[0])); - // plugin.getBeanCache().putAll(BeanUtils.getTempBeans(registryClassList)); - } - } - } - - @Override - public void unRegistry(PluginInfo plugin) throws Exception { - // 不做操作,直接通过关闭PluginApplicationContext完成注销 - } - - /** - * 扫描jar包中的类。 - * - * @param basePackage 包名 - * @param pluginWrapper jar的PluginWrapper - * @return 类全路径 - * @throws IOException 扫描异常 - */ - public static Set scanClassPackageName(String basePackage, PluginWrapper pluginWrapper) throws IOException { - Path pluginPath = pluginWrapper.getPluginPath(); - Set classPackageNames = new HashSet<>(); - File jarFile = null; - if(Files.isDirectory(pluginPath)){ - List jars = FileUtils.getJars(pluginPath); - jarFile = jars.get(0); - }else if(pluginPath.toFile().getName().toLowerCase().endsWith(".jar")){ - jarFile = pluginPath.toFile(); - }else { - throw new RuntimeException("不正确的pluginPath"); - } - try (JarFile jar = new JarFile(jarFile)) { - Enumeration jarEntries = jar.entries(); - while (jarEntries.hasMoreElements()) { - JarEntry entry = jarEntries.nextElement(); - String jarEntryName = entry.getName(); - if (jarEntryName.contains(".class") && jarEntryName.replaceAll("/", ".").startsWith(basePackage)) { - String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replace("/", "."); - classPackageNames.add(className); - } - } - } - return classPackageNames; - } - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/ApplicationContextPluginHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/ApplicationContextPluginHandler.java deleted file mode 100644 index 36b783e..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/ApplicationContextPluginHandler.java +++ /dev/null @@ -1,54 +0,0 @@ -package cd.casic.plugin.register; - -import cd.casic.plugin.PluginInfo; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; - -import java.util.Arrays; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.register - * @Project:ops - * @name:ApplicationContextPluginHandler - * @Date:2024/03/19 14:48 - * @Filename:ApplicationContextPluginHandler - * @description:Todo - */ -public class ApplicationContextPluginHandler implements BasePluginHandler { - @Override - public void initialize() throws Exception { - - } - - @Override - public void registry(PluginInfo plugin) throws Exception { - if (plugin.getApplicationContextIsRefresh()) { - return; - } - plugin.getPluginApplicationContext().setClassLoader(plugin.getPluginWrapper().getPluginClassLoader()); - plugin.getPluginApplicationContext().getDefaultListableBeanFactory() - .registerSingleton(plugin.getPluginWrapper().getPluginId().trim(), - plugin.getPluginWrapper().getPlugin()); - plugin.getPluginApplicationContext().refresh(); - plugin.setApplicationContextIsRefresh(true); - } - - @Override - public void unRegistry(PluginInfo plugin) throws Exception { - // 获取插件ApplicationContext的DefaultListableBeanFactory实例 - DefaultListableBeanFactory beanFactory = plugin.getPluginApplicationContext().getDefaultListableBeanFactory(); - - // 根据插件ID获取Bean的名称 -// String beanName = plugin.getPluginWrapper().getPluginId().trim(); -// -// // 删除已注册的Bean -// if (beanFactory.containsBeanDefinition(beanName)) { -// beanFactory.removeBeanDefinition(beanName); -// } - - String[] beanNames = beanFactory.getBeanNamesForType(plugin.getPluginWrapper().getPlugin().getClass()); - Arrays.stream(beanNames) - .filter(beanName -> beanName.equals(plugin.getPluginWrapper().getPluginId().trim())) - .forEach(beanFactory::destroySingleton); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/BasePluginHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/BasePluginHandler.java deleted file mode 100644 index be8e9eb..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/BasePluginHandler.java +++ /dev/null @@ -1,40 +0,0 @@ -package cd.casic.plugin.register; - - -import cd.casic.plugin.PluginInfo; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.register - * @Project:ops - * @name:BasePluginHandler - * @Date:2024/03/18 15:48 - * @Filename:BasePluginHandler - * @description:基础插件注册类 - */ -public interface BasePluginHandler { - - /** - * 插件组件初始化 - * - * @throws Exception - */ - void initialize() throws Exception; - - /** - * 插件组件注册 - * - * @param plugin - * @throws Exception - */ - void registry(PluginInfo plugin) throws Exception; - - /** - * 插件组件卸载注册 - * - * @param plugin - * @throws Exception - */ - void unRegistry(PluginInfo plugin) throws Exception; - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/ControllerHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/ControllerHandler.java deleted file mode 100644 index a928343..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/ControllerHandler.java +++ /dev/null @@ -1,169 +0,0 @@ -package cd.casic.plugin.register; - -import cd.casic.plugin.PluginInfo; -import cd.casic.plugin.PluginProperties; -import cd.casic.plugin.register.group.filter.impl.ControllerFilter; -import cn.hutool.core.util.StrUtil; -import cn.hutool.extra.spring.SpringUtil; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.ApplicationContext; -import org.springframework.util.ReflectionUtils; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.mvc.method.RequestMappingInfo; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.*; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.register - * @Project:ops - * @name:ControllerHandler - * @Date:2024/03/19 14:22 - * @Filename:ControllerHandler - * @description:Todo - */ -@Slf4j -public class ControllerHandler implements BasePluginHandler { - - RequestMappingHandlerMapping requestMappingHandlerMapping; - - Method getMappingForMethod; - - @Override - public void initialize() throws Exception { - - // 这里反射获取 getMappingForMethod - requestMappingHandlerMapping = SpringUtil.getBean(RequestMappingHandlerMapping.class); - getMappingForMethod = ReflectionUtils.findMethod(RequestMappingHandlerMapping.class, "getMappingForMethod", Method.class, Class.class); - getMappingForMethod.setAccessible(true); - } - - @Override - public void registry(PluginInfo plugin) throws Exception { - ApplicationContext applicationContext = plugin.getMainApplicationContext(); - PluginProperties pluginProperties = applicationContext.getBean(PluginProperties.class); - for (Class aClass : plugin.getGroupClass(ControllerFilter.GROUP_NAME)) { - setPathPrefix(plugin.getPluginId(), aClass, pluginProperties); - plugin.addController(aClass); - Object bean = plugin.getPluginApplicationContext().getBean(aClass); - Method[] methods = aClass.getMethods(); - for (Method method : methods) { - if (method.getAnnotation(RequestMapping.class) != null - || method.getAnnotation(GetMapping.class) != null - || method.getAnnotation(PostMapping.class) != null - || method.getAnnotation(DeleteMapping.class) != null - || method.getAnnotation(PutMapping.class) != null - || method.getAnnotation(PatchMapping.class) != null) { - RequestMappingInfo requestMappingInfo = (RequestMappingInfo) getMappingForMethod.invoke(requestMappingHandlerMapping, method, aClass); - requestMappingHandlerMapping.registerMapping(requestMappingInfo, bean, method); - } - } - } - } - - @Override - public void unRegistry(PluginInfo plugin) throws Exception { - for (RequestMappingInfo requestMappingInfo : getRequestMappingInfo(plugin)) { - requestMappingHandlerMapping.unregisterMapping(requestMappingInfo); - } - } - - List getRequestMappingInfo(PluginInfo plugin) throws Exception { - List requestMappingInfoList = new ArrayList<>(); - for (Class aClass : plugin.getGroupClass(ControllerFilter.GROUP_NAME)) { - Method[] methods = aClass.getMethods(); - for (Method method : methods) { - RequestMappingInfo requestMappingInfo = (RequestMappingInfo) getMappingForMethod.invoke(requestMappingHandlerMapping, method, aClass); - requestMappingInfoList.add(requestMappingInfo); - } - } - return requestMappingInfoList; - } - - - /** - * 设置请求路径前缀 - * - * @param aClass controller 类 - */ - private void setPathPrefix(String pluginId, Class aClass, PluginProperties pluginProperties) { - RequestMapping requestMapping = aClass.getAnnotation(RequestMapping.class); - if (requestMapping == null) { - return; - } - String pathPrefix = pluginProperties.getRestPathPrefix(); - if (pluginProperties.isEnablePluginIdAsRestPrefix()) { - if (StrUtil.isNotEmpty(pathPrefix)) { - pathPrefix = joiningPath(pathPrefix, pluginId); - } else { - pathPrefix = pluginId; - } - } else { - if (StrUtil.isEmpty(pathPrefix)) { - // 不启用插件id作为路径前缀, 并且路径前缀为空, 则直接返回。 - return; - } - } - handleRequestMapping(requestMapping, pathPrefix); - } - - @SuppressWarnings("unchecked") - private void handleRequestMapping(RequestMapping requestMapping, String pathPrefix) { - InvocationHandler invocationHandler = Proxy.getInvocationHandler(requestMapping); - Set definePaths = new HashSet<>(); - definePaths.addAll(Arrays.asList(requestMapping.path())); - definePaths.addAll(Arrays.asList(requestMapping.value())); - try { - Field field = invocationHandler.getClass().getDeclaredField("memberValues"); - field.setAccessible(true); - Map memberValues = (Map) field.get(invocationHandler); - String[] newPath = new String[definePaths.size()]; - int i = 0; - for (String definePath : definePaths) { - // 解决插件启用、禁用后, 路径前缀重复的问题。 - if (definePath.contains(pathPrefix)) { - newPath[i++] = definePath; - } else { - newPath[i++] = joiningPath(pathPrefix, definePath); - } - } - if (newPath.length == 0) { - newPath = new String[]{pathPrefix}; - } - memberValues.put("path", newPath); - memberValues.put("value", new String[]{}); - } catch (Exception e) { - log.error("Define Plugin RestController pathPrefix error : {}", e.getMessage(), e); - } - } - - /** - * 拼接路径 - * - * @param path1 路径1 - * @param path2 路径2 - * @return 拼接的路径 - */ - private String joiningPath(String path1, String path2) { - if (path1 != null && path2 != null) { - if (path1.endsWith("/") && path2.startsWith("/")) { - return path1 + path2.substring(1); - } else if (!path1.endsWith("/") && !path2.startsWith("/")) { - return path1 + "/" + path2; - } else { - return path1 + path2; - } - } else if (path1 != null) { - return path1; - } else if (path2 != null) { - return path2; - } else { - return ""; - } - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/MybatisHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/MybatisHandler.java deleted file mode 100644 index 8dc6f41..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/MybatisHandler.java +++ /dev/null @@ -1,163 +0,0 @@ -package cd.casic.plugin.register; - -import cd.casic.plugin.PluginInfo; -import cd.casic.plugin.register.mybatis.mybatisplus.MybatisPlusHandler; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.builder.xml.XMLMapperBuilder; -import org.apache.ibatis.executor.ErrorContext; -import org.apache.ibatis.io.Resources; -import org.apache.ibatis.session.Configuration; -import org.apache.ibatis.session.SqlSessionFactory; -import org.apache.ibatis.session.defaults.DefaultSqlSession; -import org.mybatis.spring.mapper.MapperFactoryBean; -import org.pf4j.util.FileUtils; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.GenericBeanDefinition; -import org.springframework.util.ClassUtils; - -import java.io.File; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.net.JarURLConnection; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.regex.Pattern; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.register - * @Project:ops - * @name:MybatisHandler - * @Date:2024/03/19 14:51 - * @Filename:MybatisHandler - * @deprecated 不再使用,采用{@link MybatisPlusHandler} 统一实现 - */ -@Deprecated -public class MybatisHandler implements BasePluginHandler { - - @Override - public void initialize() throws Exception { - - } - - @Override - public void registry(PluginInfo plugin) throws Exception { - List> mapperClassList = getMapperList(plugin); - if (mapperClassList.isEmpty()) return; - - //注册mapper - for (Class mapperClass : mapperClassList) { - GenericBeanDefinition definition = new GenericBeanDefinition(); - definition.getConstructorArgumentValues().addGenericArgumentValue(mapperClass); - definition.setBeanClass(MapperFactoryBean.class); - definition.getPropertyValues().add("addToConfig", true); - definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); - plugin.getPluginApplicationContext().registerBeanDefinition(mapperClass.getName(), definition); - } - //注册mapper.xml - SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) plugin.getMainApplicationContext().getBean("sqlSessionFactory"); - Configuration configuration = sqlSessionFactory.getConfiguration(); - try { - Resources.setDefaultClassLoader(plugin.getPluginWrapper().getPluginClassLoader()); - Path pluginPath = plugin.getPluginWrapper().getPluginPath(); - String xmlLocationPattern = plugin.getMapperXmlDir(); - xmlLocationPattern = xmlLocationPattern.replaceAll("\\*\\*", "<>").replaceAll("\\*", "<>") - .replaceAll("\\.", "\\.").replaceAll("<>", ".*"); - File jarFile = null; - if(Files.isDirectory(pluginPath)){ - List jars = FileUtils.getJars(pluginPath); - jarFile = jars.get(0); - }else if(pluginPath.toFile().getName().toLowerCase().endsWith(".jar")){ - jarFile = pluginPath.toFile(); - }else { - throw new RuntimeException("不正确的pluginPath"); - } - Enumeration jarEntries = new JarFile(jarFile).entries(); - while (jarEntries.hasMoreElements()) { - JarEntry entry = jarEntries.nextElement(); - String jarEntryName = entry.getName(); - if (Pattern.matches(xmlLocationPattern, jarEntryName) && jarEntryName.endsWith(".xml")) { - URL url = new URL("jar:file:" + jarFile.getAbsolutePath() + "!/" + jarEntryName); - JarURLConnection jarConnection = (JarURLConnection) url.openConnection(); - InputStream in = jarConnection.getInputStream(); - try { - XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(in, - configuration, url.getPath(), configuration.getSqlFragments()); - xmlMapperBuilder.parse(); - in.close(); - } catch (Exception e) { - throw new Exception("Failed to parse mapping resource: '" + url.getPath() + "'", e); - } finally { - if (in != null) { - in.close(); - } - ErrorContext.instance().reset(); - JarFile currJarFile = jarConnection.getJarFile(); - currJarFile.close(); - } - } - } - } finally { - Resources.setDefaultClassLoader(ClassUtils.getDefaultClassLoader()); - } - } - - @Override - public void unRegistry(PluginInfo plugin) throws Exception { - List> mapperClassList = getMapperList(plugin); - if (mapperClassList.isEmpty()) return; - - for (Class mapperClass : mapperClassList) { - String[] beanNames = plugin.getPluginApplicationContext().getBeanNamesForType(mapperClass); - Arrays.stream(beanNames).forEach(beanName -> plugin.getPluginApplicationContext().removeBeanDefinition(beanName)); - } - SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) plugin.getMainApplicationContext().getBean("sqlSessionFactory"); - Configuration configuration = sqlSessionFactory.getConfiguration(); - clearValues(configuration, "mappedStatements"); - clearValues(configuration, "caches"); - clearValues(configuration, "resultMaps"); - clearValues(configuration, "parameterMaps"); - clearValues(configuration, "keyGenerators"); - clearValues(configuration, "sqlFragments"); - // Field loadedResourcesField = configuration.getClass().getDeclaredField("loadedResources"); - // loadedResourcesField.setAccessible(true); - // ((Set) loadedResourcesField.get(configuration)).clear(); - } - - /** - * @description 获取所有Mapper接口 - * @author dolphin - * @date 2021/11/13 8:31 - */ - private List> getMapperList(PluginInfo plugin){ - List> mapperClassList = new ArrayList<>(); - - for (Class aClass : plugin.getClassList()) { - Mapper annotation = aClass.getAnnotation(Mapper.class); - if (annotation != null) { - mapperClassList.add(aClass); - } - } - return mapperClassList; - } - - private void clearValues(Configuration configuration, String fieldName) throws Exception { - - Field field = configuration.getClass().getDeclaredField(fieldName); - field.setAccessible(true); - Map map = (Map) field.get(configuration); - DefaultSqlSession.StrictMap newMap = new DefaultSqlSession.StrictMap(); - for (Object key : map.keySet()) { - try { - newMap.put((String) key, map.get(key)); - } catch (IllegalArgumentException ex) { - newMap.put((String) key, ex.getMessage()); - } - } - field.set(configuration, newMap); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/ResourcesHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/ResourcesHandler.java deleted file mode 100644 index ce3533a..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/ResourcesHandler.java +++ /dev/null @@ -1,90 +0,0 @@ -package cd.casic.plugin.register; - -import cd.casic.plugin.PluginInfo; -import cd.casic.plugin.constants.OpsConstants; -import cn.hutool.core.io.FileUtil; -import org.pf4j.util.FileUtils; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.net.JarURLConnection; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Enumeration; -import java.util.List; -import java.util.Set; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.register - * @Project:ops - * @name:ResourcesHandler - * @Date:2024/03/19 14:54 - * @Filename:ResourcesHandler - * @description:Todo - */ -public class ResourcesHandler implements BasePluginHandler { - - @Override - public void initialize() throws Exception { - - } - - @Override - public void registry(PluginInfo plugin) throws Exception { - Path pluginPath = plugin.getPluginWrapper().getPluginPath(); - Set staticClassPathLocations = plugin.getStaticClassPathLocations(); - File jarFile = null; - if(Files.isDirectory(pluginPath)){ - List jars = FileUtils.getJars(pluginPath); - jarFile = jars.get(0); - }else if(pluginPath.toFile().getName().toLowerCase().endsWith(".jar")){ - jarFile = pluginPath.toFile(); - }else { - throw new RuntimeException("不正确的pluginPath"); - } - Enumeration jarEntries = new JarFile(jarFile).entries(); - File file = new File(OpsConstants.PLUGINS_RESOURCES_DIR + File.separator + plugin.getPluginId()); - if (!file.exists()) { - FileUtil.mkdir(file); - } - FileUtil.clean(file); - while (jarEntries.hasMoreElements()) { - JarEntry entry = jarEntries.nextElement(); - String jarEntryName = entry.getName(); - for (String staticClassPathLocation : staticClassPathLocations) { //staticClassPathLocation里读取到所有静态资源的位置 然后将以插件为单位 打包到web的static目录下 即可访问 - if (!staticClassPathLocation.equals(jarEntryName) && jarEntryName.startsWith(staticClassPathLocation) - && !jarEntryName.endsWith(".class") && !entry.isDirectory()) { - URL url = new URL("jar:file:" + jarFile.getAbsolutePath() + "!/" + jarEntryName); - JarURLConnection jarConnection = (JarURLConnection) url.openConnection(); - InputStream in = jarConnection.getInputStream(); - File file1 = new File(file.getAbsolutePath() + File.separator + jarEntryName); - FileUtil.touch(file1.getAbsolutePath()); - int index; - byte[] bytes = new byte[1024]; - FileOutputStream downloadFile = new FileOutputStream(file.getAbsolutePath() + File.separator + jarEntryName); - while ((index = in.read(bytes)) != -1) { - downloadFile.write(bytes, 0, index); - downloadFile.flush(); - } - downloadFile.close(); - in.close(); - JarFile currJarFile = jarConnection.getJarFile(); - currJarFile.close(); - } - } - } - } - - @Override - public void unRegistry(PluginInfo plugin) throws Exception { - File file = new File(OpsConstants.PLUGINS_RESOURCES_DIR + File.separator + plugin.getPluginId()); - if (file.exists()) { - FileUtil.del(file.getAbsolutePath()); - } - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/SpringBeanRegisterHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/SpringBeanRegisterHandler.java deleted file mode 100644 index b4f86ce..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/SpringBeanRegisterHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -package cd.casic.plugin.register; - -import cd.casic.plugin.PluginInfo; -import cd.casic.plugin.register.group.filter.impl.BasicBeanFilter; -import cd.casic.plugin.register.group.filter.impl.ControllerFilter; -import cd.casic.plugin.register.group.filter.impl.MapperFilter; -import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition; -import org.springframework.beans.factory.support.BeanNameGenerator; -import org.springframework.context.annotation.AnnotationBeanNameGenerator; - -import java.util.ArrayList; -import java.util.List; - -public class SpringBeanRegisterHandler implements BasePluginHandler { - @Override - public void initialize() throws Exception { - - } - - @Override - public void registry(PluginInfo plugin) throws Exception { - List> basicBeanClassList = new ArrayList<>(); - basicBeanClassList.addAll(plugin.getGroupClass(BasicBeanFilter.GROUP_NAME)); - basicBeanClassList.addAll(plugin.getGroupClass(MapperFilter.GROUP_NAME)); - basicBeanClassList.addAll(plugin.getGroupClass(ControllerFilter.GROUP_NAME)); -// if(!basicBeanClassList.isEmpty()){ -// plugin.getPluginApplicationContext().register(basicBeanClassList.toArray(new Class[0])); -// } - basicBeanClassList.forEach(clazz -> { - AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(clazz); - beanDefinition.setBeanClass(clazz); - BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator(); - String beanName = beanNameGenerator.generateBeanName(beanDefinition, plugin.getPluginApplicationContext()); - plugin.getPluginApplicationContext().registerBeanDefinition(beanName, beanDefinition); - }); - } - - @Override - public void unRegistry(PluginInfo plugin) throws Exception { - - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/SpringDocHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/SpringDocHandler.java deleted file mode 100644 index 0476777..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/SpringDocHandler.java +++ /dev/null @@ -1,69 +0,0 @@ -package cd.casic.plugin.register; - -import cd.casic.plugin.PluginInfo; -import cn.hutool.core.util.ReflectUtil; -import cn.hutool.extra.spring.SpringUtil; -import lombok.extern.slf4j.Slf4j; -import org.springdoc.api.AbstractOpenApiResource; -import org.springdoc.core.service.OpenAPIService; -import org.springframework.context.ApplicationContext; - -import java.lang.reflect.Field; -import java.util.Locale; -import java.util.Set; - -/** - * 插件系统集成SpringDoc。swagger能够根据插件启停自动更新接口文档 - */ -@Slf4j -public class SpringDocHandler implements BasePluginHandler { - private Set> restControllers; - private OpenAPIService openAPIService; - - @SuppressWarnings("unchecked") - @Override - public void initialize() { - ApplicationContext applicationContext = SpringUtil.getApplicationContext(); - AbstractOpenApiResource openApiResource = applicationContext.getBean(AbstractOpenApiResource.class); - try { - // 获取OpenApiResource的ADDITIONAL_REST_CONTROLLERS字段 - Field additionalRestControllers = ReflectUtil.getField(openApiResource.getClass(), "ADDITIONAL_REST_CONTROLLERS"); - additionalRestControllers.setAccessible(true); - restControllers = (Set>) additionalRestControllers.get(openApiResource); - } catch (IllegalAccessException e) { - restControllers = null; - } - openAPIService = applicationContext.getBean(OpenAPIService.class); - } - - @Override - public void registry(PluginInfo plugin) throws Exception { - if(restControllers != null){ - // 将插件中的Controller类添加到OpenApiResource的ADDITIONAL_REST_CONTROLLERS字段 - restControllers.addAll(plugin.getControllers()); - refresh(); - } - } - - @Override - public void unRegistry(PluginInfo plugin) throws Exception { - if(restControllers != null && !restControllers.isEmpty()){ - for (Class clazz : plugin.getControllers()) { - // 从OpenApiResource的ADDITIONAL_REST_CONTROLLERS字段中移除插件中的Controller类 - restControllers.remove(clazz); - } - refresh(); - plugin.getControllers().clear(); - } - } - - private void refresh(){ - if(openAPIService != null){ - // 手动刷新OpenApiResource - openAPIService.setCachedOpenAPI(null, Locale.getDefault()); - // openAPIService.resetCalculatedOpenAPI(); - } - } - - -} \ No newline at end of file diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/StartPluginManagerHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/StartPluginManagerHandler.java deleted file mode 100644 index a9fdfab..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/StartPluginManagerHandler.java +++ /dev/null @@ -1,74 +0,0 @@ -package cd.casic.plugin.register; - -import cd.casic.plugin.PluginInfo; -import cd.casic.plugin.register.config.ConfigurationFileHandler; -import cd.casic.plugin.register.config.SpringAutoConfigurationFileHandler; -import cd.casic.plugin.register.database.DatabaseHandler; -import cd.casic.plugin.register.group.ClassGroupHandler; -import cd.casic.plugin.register.mongoplus.MongoHandler; -import cd.casic.plugin.register.mybatis.mybatisplus.MybatisPlusHandler; -import cd.casic.plugin.register.websocket.WebSocketHandler; -import jakarta.annotation.PostConstruct; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.handler - * @Project:ops - * @name:LoadPluginHandle - * @Date:2024/03/18 15:46 - * @Filename:LoadPluginHandle - * @description:Todo - */ -@Component -@Slf4j -public class StartPluginManagerHandler implements BasePluginHandler { - List pluginRegisterList = Collections.synchronizedList(new ArrayList<>()); - - @PostConstruct - @Override - public void initialize() throws Exception { - pluginRegisterList.clear(); - pluginRegisterList.add(new ClassGroupHandler()); - // pluginRegisterList.add(new AnnotationHandler()); - pluginRegisterList.add(new ConfigurationFileHandler()); - pluginRegisterList.add(new SpringAutoConfigurationFileHandler()); - pluginRegisterList.add(new SpringBeanRegisterHandler()); - pluginRegisterList.add(new MybatisPlusHandler()); - // pluginRegisterList.add(new MybatisHandler()); - pluginRegisterList.add(new ResourcesHandler()); - pluginRegisterList.add(new ApplicationContextPluginHandler()); - pluginRegisterList.add(new DatabaseHandler()); - pluginRegisterList.add(new ControllerHandler()); - pluginRegisterList.add(new WebSocketHandler()); - pluginRegisterList.add(new SpringDocHandler()); - pluginRegisterList.add(new MongoHandler()); - for (BasePluginHandler pluginHandle : pluginRegisterList) { - pluginHandle.initialize(); - } - } - - @Override - public void registry(PluginInfo plugin) throws Exception { - for (BasePluginHandler pluginHandler : pluginRegisterList) { - pluginHandler.registry(plugin); - } - } - - @Override - public void unRegistry(PluginInfo plugin) throws Exception { - for (BasePluginHandler pluginHandler : pluginRegisterList) { - pluginHandler.unRegistry(plugin); - } -// for (int i = pluginRegisterList.size() - 1; i >= 0; i--){ -// pluginRegisterList.get(i).unRegistry(plugin); -// } - plugin.getClassList().clear(); - plugin.setClassList(null); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/config/ConfigFileUtils.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/config/ConfigFileUtils.java deleted file mode 100644 index d136ba8..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/config/ConfigFileUtils.java +++ /dev/null @@ -1,35 +0,0 @@ -package cd.casic.plugin.register.config; - -import org.pf4j.util.StringUtils; - -public class ConfigFileUtils { - /** - * 拼接插件独立配置文件的文件名和环境后缀 - * @param fileName 插件独立配置文件文件名 - * @param suffix 配置文件环境后缀,PluginConfiguration中定义 - * @return 拼接后的文件名 - */ - public static String joinConfigFileName(String fileName, String suffix){ - if(StringUtils.isNullOrEmpty(fileName)){ - return null; - } - String fileNamePrefix; - String fileNamePrefixSuffix; - - if(fileName.lastIndexOf(".") == -1) { - fileNamePrefix = fileName; - fileNamePrefixSuffix = ""; - } else { - int index = fileName.lastIndexOf("."); - fileNamePrefix = fileName.substring(0, index); - fileNamePrefixSuffix = fileName.substring(index); - } - if(suffix == null){ - suffix = ""; - } - if(StringUtils.isNotNullOrEmpty(suffix) && !suffix.startsWith("-")){ - suffix = "-" + suffix; - } - return fileNamePrefix + suffix + fileNamePrefixSuffix; - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/config/ConfigurationFileHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/config/ConfigurationFileHandler.java deleted file mode 100644 index 59554e0..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/config/ConfigurationFileHandler.java +++ /dev/null @@ -1,126 +0,0 @@ -package cd.casic.plugin.register.config; - -import cd.casic.plugin.PluginConfigWrapper; -import cd.casic.plugin.PluginInfo; -import cd.casic.plugin.PluginProperties; -import cd.casic.plugin.PluginYamlConfigurationParser; -import cd.casic.plugin.annotation.PluginConfiguration; -import cd.casic.plugin.register.BasePluginHandler; -import org.pf4j.RuntimeMode; -import org.pf4j.util.StringUtils; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; - -import java.util.ArrayList; -import java.util.List; - -/** - * 配置文件处理器,用于处理插件独立的配置文件 - */ -public class ConfigurationFileHandler implements BasePluginHandler { - private final PluginYamlConfigurationParser configurationParser; - - public ConfigurationFileHandler(){ - this.configurationParser = new PluginYamlConfigurationParser(); - } - - @Override - public void initialize() throws Exception { - - } - - @Override - public void registry(PluginInfo plugin) throws Exception { - PluginProperties pluginProperties = plugin.getMainApplicationContext().getBean(PluginProperties.class); - RuntimeMode runtimeMode = pluginProperties.getRuntimeMode(); - for(Class aClass : plugin.getClassList()){ - PluginConfiguration configDefinition = aClass.getAnnotation(PluginConfiguration.class); - if(configDefinition == null){ - continue; - } - String fileName = getConfigFileName(configDefinition, runtimeMode); - Object parseObject; - if(!StringUtils.isNullOrEmpty(fileName)){ - PluginConfigWrapper pluginConfigWrapper = - new PluginConfigWrapper(fileName, aClass); - parseObject = configurationParser.parse(plugin, pluginConfigWrapper); - } else { - try { - parseObject = aClass.getDeclaredConstructor().newInstance(); - } catch (NoSuchMethodException | InstantiationException | IllegalAccessException e) { - throw new RuntimeException("Failed to instantiate class " + aClass.getName(), e); - } - } - - String name = aClass.getSimpleName(); - DefaultListableBeanFactory listableBeanFactory = plugin.getPluginApplicationContext().getDefaultListableBeanFactory(); - if(!listableBeanFactory.containsSingleton(name)) { - listableBeanFactory.registerSingleton(name, parseObject); - } - plugin.addPluginConfigObject(parseObject); - } - } - - @Override - public void unRegistry(PluginInfo plugin) throws Exception { - /*上面的写法没有考虑到资源泄露,这里把clear,关闭资源*/ - List objectsToClear = new ArrayList<>(plugin.getPluginConfigObjects()); - plugin.getPluginConfigObjects().clear(); - for (Object obj : objectsToClear) { - if (obj instanceof AutoCloseable) { - ((AutoCloseable) obj).close(); - } - } - } - - /** - * 获取插件独立配置文件的文件名 - * @param pluginConfiguration 插件配置类上的自定义注解 - * @param runtimeMode 插件系统运行模式 - * @return 插件独立配置文件的文件名 - */ - private String getConfigFileName(PluginConfiguration pluginConfiguration, RuntimeMode runtimeMode){ - String fileName = pluginConfiguration.fileName(); - if(StringUtils.isNullOrEmpty(fileName)){ - return null; - } - String suffix = ""; - if(runtimeMode == RuntimeMode.DEPLOYMENT){ - // deployment模式 - suffix = pluginConfiguration.deploySuffix(); - } else if(runtimeMode == RuntimeMode.DEVELOPMENT){ - // development模式 - suffix = pluginConfiguration.devSuffix(); - } - return joinConfigFileName(fileName, suffix); - } - - /** - * 拼接插件独立配置文件的文件名和环境后缀 - * @param fileName 插件独立配置文件文件名 - * @param suffix 配置文件环境后缀,PluginConfiguration中定义 - * @return 拼接后的文件名 - */ - private String joinConfigFileName(String fileName, String suffix){ - if(StringUtils.isNullOrEmpty(fileName)){ - return null; - } - String fileNamePrefix; - String fileNamePrefixSuffix; - - if(fileName.lastIndexOf(".") == -1) { - fileNamePrefix = fileName; - fileNamePrefixSuffix = ""; - } else { - int index = fileName.lastIndexOf("."); - fileNamePrefix = fileName.substring(0, index); - fileNamePrefixSuffix = fileName.substring(index); - } - if(suffix == null){ - suffix = ""; - } - if(StringUtils.isNotNullOrEmpty(suffix) && !suffix.startsWith("-")){ - suffix = "-" + suffix; - } - return fileNamePrefix + suffix + fileNamePrefixSuffix; - } -} \ No newline at end of file diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/config/SpringAutoConfigurationFileHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/config/SpringAutoConfigurationFileHandler.java deleted file mode 100644 index cc604c7..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/config/SpringAutoConfigurationFileHandler.java +++ /dev/null @@ -1,286 +0,0 @@ -package cd.casic.plugin.register.config; - -import cd.casic.plugin.PluginInfo; -import cd.casic.plugin.pf4j.OpsPluginDescriptor; -import cd.casic.plugin.register.BasePluginHandler; -import cd.casic.plugin.utils.YamlUtils; -import cn.hutool.core.util.StrUtil; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.pf4j.PluginDescriptor; -import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor; -import org.springframework.boot.context.properties.bind.Binder; -import org.springframework.boot.env.PropertiesPropertySourceLoader; -import org.springframework.boot.env.PropertySourceLoader; -import org.springframework.boot.env.YamlPropertySourceLoader; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.Environment; -import org.springframework.core.env.PropertySource; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; -import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.*; -import java.util.stream.Collectors; - -@Slf4j -public class SpringAutoConfigurationFileHandler implements BasePluginHandler { - List propertySourceLoaders = new ArrayList<>(); - - /** - * 活动文件的属性名称,就是dev,prod等 - */ - private static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active"; - - /** - * 配置文件的属性名称 - */ - private static final String INCLUDE_PROFILES_PROPERTY = "spring.profiles.include"; - - - @Override - public void initialize() throws Exception { - propertySourceLoaders.add(new YamlPropertySourceLoader()); - propertySourceLoaders.add(new PropertiesPropertySourceLoader()); - } - - @Override - public void registry(PluginInfo plugin) throws Exception { - PluginDescriptor pluginDescriptor = plugin.getPluginWrapper().getDescriptor(); - ConfigurableEnvironment environment = plugin.getPluginApplicationContext().getEnvironment(); - - if(!(pluginDescriptor instanceof OpsPluginDescriptor)){ - return; - } - - List resourcesFromDescriptor = getConfigResourceFromDescriptor(plugin); - - List> propProfiles = getPropProfiles(resourcesFromDescriptor); - if(ObjectUtils.isEmpty(propProfiles)){ - return; - } - for (PropertySource propertySource : propProfiles) { - environment.getPropertySources().addLast(propertySource); - } - - // 发现原始文件中配置的 profiles - List profiles = getProfiles(environment); - if(!ObjectUtils.isEmpty(profiles)){ - loadProfilesConfig(plugin.getPluginWrapper().getPluginPath(), (OpsPluginDescriptor) pluginDescriptor, environment, profiles); - } - - ConfigurationPropertiesBindingPostProcessor.register(plugin.getPluginApplicationContext()); - } - - @Override - public void unRegistry(PluginInfo plugin) throws Exception { - // 无需处理,后续关闭pluginApplicationContext即可 - } - - private List getConfigResourceFromDescriptor(PluginInfo plugin){ - log.info("插件 {} 尝试从插件描述中读取配置文件名", plugin.getPluginId()); - PluginDescriptor descriptor = plugin.getPluginWrapper().getDescriptor(); - if(!(descriptor instanceof OpsPluginDescriptor)){ - return Collections.emptyList(); - } - - OpsPluginDescriptor opsPluginDescriptor = (OpsPluginDescriptor) descriptor; - String configFileName = opsPluginDescriptor.getConfigFileName(); - if(StrUtil.isEmpty(configFileName)){ - log.info("插件 {} 的插件描述中未设置配置文件名", plugin.getPluginId()); - return Collections.emptyList(); - } - - List configFileActiveNames = getConfigFileActiveNames(configFileName, opsPluginDescriptor.getConfigFileActive()); - log.info("插件{} 的配置文件为 {} {}", plugin.getPluginId(), configFileName, configFileActiveNames); - Path pluginPath = plugin.getPluginWrapper().getPluginPath(); - - List configFileResources = configFileActiveNames.stream() - .map(configFileActiveName -> YamlUtils.getYamlPath(pluginPath, configFileActiveName)) - .filter(Objects::nonNull) - .map(FileSystemResource::new) - .collect(Collectors.toList()); - - configFileResources.add(new FileSystemResource(YamlUtils.getYamlPath(pluginPath, configFileName))); - - return configFileResources; - } - - private List getConfigResourceFromAnnotation(){ - return Collections.emptyList(); - } - - private List getConfigFileActiveNames(String configFileName, List configFileActives){ - return configFileActives.stream() - .map(configFileActive -> ConfigFileUtils.joinConfigFileName(configFileName, configFileActive)) - .collect(Collectors.toList()); - } - - /** - * 从 Resource 中解析出 PropertySource - * @param resources resources - * @return List - * @throws IOException 加载文件 IOException 异常 - */ - private List> getPropProfiles(List resources) throws IOException { - List> propProfiles = new ArrayList<>(); - if(resources == null || resources.isEmpty()){ - return propProfiles; - } - for (Resource resource : resources) { - if(resource == null || !resource.exists()){ - continue; - } - String filename = resource.getFilename(); - if(ObjectUtils.isEmpty(filename)){ - log.error("File name is empty!"); - return null; - } - for (PropertySourceLoader propertySourceLoader : propertySourceLoaders) { - if(!canLoadFileExtension(propertySourceLoader, filename)){ - continue; - } - log.info("正在从 {} 读取插件配置", filename); - List> propertySources = propertySourceLoader.load(filename, resource); - if(ObjectUtils.isEmpty(propertySources)){ - continue; - } - propProfiles.addAll(propertySources); - } - } - return propProfiles; - } - - /** - * 根据文件后缀判断是否可解析 - * @param loader PropertySourceLoader - * @param name 文件名称 - * @return boolean - */ - private boolean canLoadFileExtension(PropertySourceLoader loader, String name) { - return Arrays.stream(loader.getFileExtensions()) - .anyMatch((fileExtension) -> StringUtils.endsWithIgnoreCase(name, - fileExtension)); - } - - /** - * 加载 spring.profiles.active/spring.profiles.include 定义的配置 - * @param environment ConfigurableEnvironment - * @param profiles 主配置文件中定义的值 - * @throws Exception Exception - */ - private void loadProfilesConfig(Path pluginPath, OpsPluginDescriptor opsPluginDescriptor, - ConfigurableEnvironment environment, List profiles) throws Exception { - // 解析当前文件名称 - for (Profile profile : profiles) { - String name = profile.getName(); - String fileName = ConfigFileUtils.joinConfigFileName(opsPluginDescriptor.getConfigFileName(), name); - - - Path configFilePath = YamlUtils.getYamlPath(pluginPath, fileName); - FileSystemResource configFileResource = new FileSystemResource(configFilePath); - if(ObjectUtils.isEmpty(configFileResource)){ - continue; - } - List> propProfiles = getPropProfiles(Collections.singletonList(configFileResource)); - if(ObjectUtils.isEmpty(propProfiles)){ - return; - } - for (PropertySource propertySource : propProfiles) { - environment.getPropertySources().addLast(propertySource); - } - } - // 重新设置 ActiveProfiles - String[] names = profiles.stream() - .filter((profile) -> profile != null && !profile.isDefaultProfile()) - .map(Profile::getName) - .toArray(String[]::new); - environment.setActiveProfiles(names); - } - - private List getProfiles(Environment environment) { - List profiles = new ArrayList<>(); - Set activatedViaProperty = getProfilesActivatedViaProperty(environment); - profiles.addAll(getOtherActiveProfiles(environment, activatedViaProperty)); - profiles.addAll(activatedViaProperty); - profiles.removeIf( - (profile) -> (profile != null && profile.isDefaultProfile())); - return profiles; - } - - private Set getProfilesActivatedViaProperty(Environment environment) { - if (!environment.containsProperty(ACTIVE_PROFILES_PROPERTY) - && !environment.containsProperty(INCLUDE_PROFILES_PROPERTY)) { - return Collections.emptySet(); - } - Binder binder = Binder.get(environment); - Set activeProfiles = new LinkedHashSet<>(); - activeProfiles.addAll(getProfiles(binder, INCLUDE_PROFILES_PROPERTY)); - activeProfiles.addAll(getProfiles(binder, ACTIVE_PROFILES_PROPERTY)); - return activeProfiles; - } - - private List getOtherActiveProfiles(Environment environment, Set activatedViaProperty) { - return Arrays.stream(environment.getActiveProfiles()).map(Profile::new) - .filter((profile) -> !activatedViaProperty.contains(profile)) - .collect(Collectors.toList()); - } - - private Set getProfiles(Binder binder, String name) { - return binder.bind(name, String[].class).map(this::asProfileSet) - .orElse(Collections.emptySet()); - } - - private Set asProfileSet(String[] profileNames) { - List profiles = new ArrayList<>(); - for (String profileName : profileNames) { - profiles.add(new Profile(profileName)); - } - return new LinkedHashSet<>(profiles); - } - - @Getter - private static class Profile { - - private final String name; - - private final boolean defaultProfile; - - Profile(String name) { - this(name, false); - } - - Profile(String name, boolean defaultProfile) { - Assert.notNull(name, "Name must not be null"); - this.name = name; - this.defaultProfile = defaultProfile; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (obj == null || obj.getClass() != getClass()) { - return false; - } - return ((Profile) obj).name.equals(this.name); - } - - @Override - public int hashCode() { - return this.name.hashCode(); - } - - @Override - public String toString() { - return this.name; - } - - } - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/database/DataBaseProperty.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/database/DataBaseProperty.java deleted file mode 100644 index 0a44ea3..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/database/DataBaseProperty.java +++ /dev/null @@ -1,12 +0,0 @@ -package cd.casic.plugin.register.database; - - -import cd.casic.plugin.utils.dBUtils.DBEnums; - -public interface DataBaseProperty { - DBEnums type(); - String driver(); - String url(); - String username(); - String password(); -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/database/DatabaseHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/database/DatabaseHandler.java deleted file mode 100644 index 496f0c7..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/database/DatabaseHandler.java +++ /dev/null @@ -1,84 +0,0 @@ -package cd.casic.plugin.register.database; - -import cd.casic.plugin.PluginInfo; -import cd.casic.plugin.pf4j.OpsPluginDescriptor; -import cd.casic.plugin.register.BasePluginHandler; -import cd.casic.plugin.register.group.filter.impl.DataBaseEntityFilter; -import cd.casic.plugin.utils.dBUtils.SQLGenerator; -import cn.hutool.core.util.StrUtil; -import lombok.extern.slf4j.Slf4j; -import org.pf4j.PluginDescriptor; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; - -import java.util.List; - -@Slf4j -public class DatabaseHandler implements BasePluginHandler { - @Override - public void initialize() throws Exception { - - } - @Override - public void registry(PluginInfo plugin) throws Exception { - DataBaseProperty dataBaseProperty; - SQLGenerator sqlGenerator; - PluginDescriptor descriptor = plugin.getPluginWrapper().getDescriptor(); - if(!(descriptor instanceof OpsPluginDescriptor)){ - return; - } - OpsPluginDescriptor opsPluginDescriptor = (OpsPluginDescriptor) descriptor; - if(StrUtil.isNotEmpty(opsPluginDescriptor.getConfigFileName())){ - // 使用插件独立数据源 - AnnotationConfigApplicationContext pluginApplicationContext = plugin.getPluginApplicationContext(); - try{ - dataBaseProperty = pluginApplicationContext.getBean(DataBaseProperty.class); - }catch (Exception e){ - dataBaseProperty = null; - log.info("插件未配置独立数据源"); - } - } else { - dataBaseProperty = null; - } - try { - sqlGenerator = plugin.getMainApplicationContext().getBean(SQLGenerator.class); - }catch (Exception e){ - log.error("无法获取SqlGenerator类型的Bean对象"); - return; - } - List> entities = plugin.getGroupClass(DataBaseEntityFilter.GROUP_NAME); - for(Class entity : entities){ - sqlGenerator.sqlDeleteGenerator(entity, dataBaseProperty, plugin.getPluginId()); - sqlGenerator.sqlGenerator(entity, dataBaseProperty, plugin.getPluginId()); - } - } - - @Override - public void unRegistry(PluginInfo plugin) throws Exception { - DataBaseProperty dataBaseProperty; - SQLGenerator sqlGenerator; - PluginDescriptor descriptor = plugin.getPluginWrapper().getDescriptor(); - if(!(descriptor instanceof OpsPluginDescriptor)){ - return; - } - OpsPluginDescriptor opsPluginDescriptor = (OpsPluginDescriptor) descriptor; - if(StrUtil.isNotEmpty(opsPluginDescriptor.getConfigFileName())){ - // 使用插件独立数据源 - AnnotationConfigApplicationContext pluginApplicationContext = plugin.getPluginApplicationContext(); - try{ - dataBaseProperty = pluginApplicationContext.getBean(DataBaseProperty.class); - }catch (Exception e){ - log.info("插件未配置独立数据源"); - return; - } - } else { - return; - } - try { - sqlGenerator = plugin.getMainApplicationContext().getBean(SQLGenerator.class); - }catch (Exception e){ - log.error("无法获取SqlGenerator类型的Bean对象"); - return; - } - sqlGenerator.destroyDataSource(dataBaseProperty, plugin.getPluginId()); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/AnnotationUtils.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/AnnotationUtils.java deleted file mode 100644 index 73b58de..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/AnnotationUtils.java +++ /dev/null @@ -1,20 +0,0 @@ -package cd.casic.plugin.register.group; - -import java.lang.annotation.Annotation; - -public class AnnotationUtils { - - @SafeVarargs - public static boolean hasAnnotations(Class clazz, boolean allRequired, Class... annotations){ - if(clazz == null) return false; - if(annotations == null) return false; - for(Class annotation : annotations){ - if(clazz.isAnnotationPresent(annotation)){ - if(!allRequired) return true; - }else{ - if(allRequired) return false; - } - } - return allRequired; - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/ClassGroupHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/ClassGroupHandler.java deleted file mode 100644 index 602e38a..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/ClassGroupHandler.java +++ /dev/null @@ -1,111 +0,0 @@ -package cd.casic.plugin.register.group; - -import cd.casic.plugin.BasePlugin; -import cd.casic.plugin.PluginClassLoaderCache; -import cd.casic.plugin.PluginInfo; -import cd.casic.plugin.register.BasePluginHandler; -import cd.casic.plugin.register.group.filter.PluginClassFilter; -import cd.casic.plugin.register.group.filter.impl.*; -import lombok.extern.slf4j.Slf4j; -import org.pf4j.PluginWrapper; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.stream.Collectors; - -/** - * 加载插件中所有的类,并且分组存放到pluginInfo的map中,便于后面的handler进行处理 - */ -@Slf4j -public class ClassGroupHandler implements BasePluginHandler { - private final List classFilters = new ArrayList<>(); - - @Override - public void initialize() throws Exception { - classFilters.add(new BasicBeanFilter()); - classFilters.add(new ControllerFilter()); - classFilters.add(new DataBaseEntityFilter()); - classFilters.add(new MapperFilter()); - classFilters.add(new PluginConfigurationFilter()); - classFilters.add(new WebSocketFilter()); - } - - /** - * 将类分组存到PluginInfo的map中,方便后面其他Handler进行处理 - * @param plugin PluginInfo - */ - @Override - public void registry(PluginInfo plugin) throws Exception { - List> classList = new ArrayList<>(); - Set classPackageName = scanClassPackageName(plugin.getBasePlugin().scanPackage(), plugin.getBasePlugin().getWrapper()); - for (String packageName : classPackageName) { - ClassLoader loader = PluginClassLoaderCache.getPlugin(plugin.getPluginId()); - log.warn("Load class {} using classloader {} for plugin {}", packageName, PluginClassLoaderCache.getPlugin(plugin.getPluginId()), plugin.getPluginId()); - Class clazz = loader.loadClass(packageName); - if (!BasePlugin.class.isAssignableFrom(clazz)) { - classList.add(clazz); - } - } - plugin.setClassList(classList); - /*这里分组其实只是为了分组而分组,目前没有特别明确的用途*/ - List> pluginClassList = plugin.getClassList().stream().filter(item -> !item.isInterface()).collect(Collectors.toList()); - if (!pluginClassList.isEmpty()) { - for (Class clazz : pluginClassList) { - boolean grouped = false; - for(PluginClassFilter filter : classFilters){ - if(filter.filter(clazz)){ - log.info("将类 {} 添加到 {} 分组", clazz, filter.groupName()); - plugin.addGroupClass(filter.groupName(), clazz); - grouped = true; - } - } - if(!grouped){ - log.info("类 {} 不属于任何已知分组", clazz); - plugin.addGroupClass("unknown", clazz); - } - } - } - } - - /** - * 卸载插件时,将插件的类列表清空 - * @param plugin PluginInfo - */ - @Override - public void unRegistry(PluginInfo plugin) throws Exception { - plugin.getClassList().clear(); - } - - /** - * 扫描插件所在包,获取插件中所有的类名 - * @param basePackage 插件所在包名 - * @param pluginWrapper 插件对象包装类 - * @return 所有的类名集合 - */ - private Set scanClassPackageName(String basePackage, PluginWrapper pluginWrapper) throws IOException { - Path pluginPath = pluginWrapper.getPluginPath(); - if(pluginPath == null || !Files.exists(pluginPath)){ - throw new RuntimeException("错误的插件路径"); - } - File pluginFile = pluginPath.toFile(); - Set classPackageNames = new HashSet<>(); - - try (JarFile jar = new JarFile(pluginFile)) { - Enumeration jarEntries = jar.entries(); - while (jarEntries.hasMoreElements()) { - JarEntry entry = jarEntries.nextElement(); - String jarEntryName = entry.getName(); - if (jarEntryName.contains(".class") && jarEntryName.replaceAll("/", ".").startsWith(basePackage)) { - String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replace("/", "."); - classPackageNames.add(className); - } - } - } - return classPackageNames; - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/PluginClassFilter.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/PluginClassFilter.java deleted file mode 100644 index 9579281..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/PluginClassFilter.java +++ /dev/null @@ -1,9 +0,0 @@ -package cd.casic.plugin.register.group.filter; - -public interface PluginClassFilter{ - String groupName(); - - void initialize(); - - boolean filter(Class clazz); -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/BasicBeanFilter.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/BasicBeanFilter.java deleted file mode 100644 index 38b7239..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/BasicBeanFilter.java +++ /dev/null @@ -1,30 +0,0 @@ -package cd.casic.plugin.register.group.filter.impl; - -import cd.casic.plugin.register.group.AnnotationUtils; -import cd.casic.plugin.register.group.filter.PluginClassFilter; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; - -public class BasicBeanFilter implements PluginClassFilter { - public static final String GROUP_NAME = "basic_bean"; - - @Override - public String groupName() { - return GROUP_NAME; - } - - @Override - public void initialize() { - - } - - @Override - public boolean filter(Class clazz) { - return AnnotationUtils.hasAnnotations(clazz, false, Bean.class, - Service.class, - Component.class, - Configuration.class); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/ControllerFilter.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/ControllerFilter.java deleted file mode 100644 index 6b3cd19..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/ControllerFilter.java +++ /dev/null @@ -1,28 +0,0 @@ -package cd.casic.plugin.register.group.filter.impl; - -import cd.casic.plugin.register.group.AnnotationUtils; -import cd.casic.plugin.register.group.filter.PluginClassFilter; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RestController; - -/** - * Controller 过滤器,筛选带有Controller或者RestController注解的类 - */ -public class ControllerFilter implements PluginClassFilter { - public static final String GROUP_NAME = "spring_controller"; - - @Override - public String groupName() { - return GROUP_NAME; - } - - @Override - public void initialize() { - - } - - @Override - public boolean filter(Class clazz) { - return AnnotationUtils.hasAnnotations(clazz, false, Controller.class, RestController.class); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/DataBaseEntityFilter.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/DataBaseEntityFilter.java deleted file mode 100644 index ad1ee0b..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/DataBaseEntityFilter.java +++ /dev/null @@ -1,24 +0,0 @@ -package cd.casic.plugin.register.group.filter.impl; - - -import cd.casic.plugin.register.group.AnnotationUtils; -import cd.casic.plugin.register.group.filter.PluginClassFilter; -import cd.casic.plugin.utils.dBUtils.annotation.Entity; - -public class DataBaseEntityFilter implements PluginClassFilter { - public static final String GROUP_NAME = "database_entity"; - @Override - public String groupName() { - return GROUP_NAME; - } - - @Override - public void initialize() { - - } - - @Override - public boolean filter(Class clazz) { - return AnnotationUtils.hasAnnotations(clazz, false, Entity.class); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/MapperFilter.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/MapperFilter.java deleted file mode 100644 index e3c3969..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/MapperFilter.java +++ /dev/null @@ -1,24 +0,0 @@ -package cd.casic.plugin.register.group.filter.impl; - -import cd.casic.plugin.register.group.filter.PluginClassFilter; -import org.apache.ibatis.annotations.Mapper; -import org.springframework.stereotype.Repository; - -public class MapperFilter implements PluginClassFilter { - public static final String GROUP_NAME = "mapper"; - - @Override - public String groupName() { - return GROUP_NAME; - } - - @Override - public void initialize() { - - } - - @Override - public boolean filter(Class clazz) { - return clazz.isAnnotationPresent(Mapper.class) || clazz.isAnnotationPresent(Repository.class); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/PluginConfigurationFilter.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/PluginConfigurationFilter.java deleted file mode 100644 index a9dc6db..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/PluginConfigurationFilter.java +++ /dev/null @@ -1,29 +0,0 @@ -package cd.casic.plugin.register.group.filter.impl; - - -import cd.casic.plugin.BasePlugin; -import cd.casic.plugin.annotation.PluginConfiguration; -import cd.casic.plugin.register.group.filter.PluginClassFilter; - -public class PluginConfigurationFilter implements PluginClassFilter { - public static final String GROUP_NAME = "plugin_config"; - - @Override - public String groupName() { - return GROUP_NAME; - } - - @Override - public void initialize() { - - } - - @Override - public boolean filter(Class clazz) { - if(BasePlugin.class.isAssignableFrom(clazz)){ - return false; - } - - return clazz.isAnnotationPresent(PluginConfiguration.class); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/WebSocketFilter.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/WebSocketFilter.java deleted file mode 100644 index 2d7c892..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/group/filter/impl/WebSocketFilter.java +++ /dev/null @@ -1,25 +0,0 @@ -package cd.casic.plugin.register.group.filter.impl; - - -import cd.casic.plugin.register.group.filter.PluginClassFilter; -import jakarta.websocket.server.ServerEndpoint; - -public class WebSocketFilter implements PluginClassFilter { - - public static final String GROUP_NAME = "websocket"; - - @Override - public String groupName() { - return GROUP_NAME; - } - - @Override - public void initialize() { - - } - - @Override - public boolean filter(Class clazz) { - return clazz.isAnnotationPresent(ServerEndpoint.class); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mongoplus/MongoHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mongoplus/MongoHandler.java deleted file mode 100644 index 861f23c..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mongoplus/MongoHandler.java +++ /dev/null @@ -1,112 +0,0 @@ -package cd.casic.plugin.register.mongoplus; - -import cd.casic.plugin.PluginInfo; -import cd.casic.plugin.register.BasePluginHandler; -import com.anwen.mongo.annotation.collection.CollectionName; -import com.anwen.mongo.conn.CollectionManager; -import com.anwen.mongo.conn.ConnectMongoDB; -import com.anwen.mongo.convert.CollectionNameConvert; -import com.anwen.mongo.manager.MongoPlusClient; -import com.anwen.mongo.mapper.BaseMapper; -import com.anwen.mongo.service.IService; -import com.anwen.mongo.service.impl.ServiceImpl; -import com.mongodb.MongoException; -import com.mongodb.client.MongoCollection; -import com.mongodb.client.MongoDatabase; -import lombok.extern.slf4j.Slf4j; -import org.bson.Document; -import org.springframework.beans.BeansException; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -@Slf4j -public class MongoHandler implements BasePluginHandler { - private AnnotationConfigApplicationContext applicationContext; - - @Override - public void initialize() throws Exception { - log.info("Start to hand the Mongo Class for plugin"); - } - - @Override - public void registry(PluginInfo plugin) throws Exception { - try { - applicationContext = plugin.getPluginApplicationContext(); - - // 注册AutoConfigurationPackages, 用于插件可自动配置 -// AutoConfigurationPackages.register(applicationContext.getDefaultListableBeanFactory(), -// plugin.getBasePlugin().scanPackage()); -// -// Set.of(MongoPlusConfiguration.class, MongoPlusAutoConfiguration.class, OverrideMongoConfiguration.class, -// MongoSpringProperty.class, MongoDBFieldProperty.class, MongoTransactionManagerAutoConfiguration.class, -// MongoPropertyConfiguration.class, ) -// ClassLoader pluginClassLoader = pluginRegistryInfo.getPluginClassLoader(); -// for (String autoConfigClassPackage : installAutoConfigClassString) { -// Class aClass = Class.forName(autoConfigClassPackage, false, pluginClassLoader); -// autoConfigurationClassSet.add(aClass); -// } -// for (Class autoConfigurationClass : autoConfigurationClassSet) { -// pluginApplicationContext.registerBean(autoConfigurationClass); -// } - - applicationContext.getBeansOfType(IService.class) - .values() - .stream() - .filter(s -> s instanceof ServiceImpl) - .forEach(s -> { - Class clazz = s.getGenericityClass(); - ServiceImpl serviceImpl = (ServiceImpl) s; - serviceImpl.setClazz(clazz); - String database = initFactory(clazz); - // 这里需要将MongoPlusClient给工厂 - serviceImpl.setDatabase(database); - serviceImpl.setBaseMapper(applicationContext.getBean("baseMapper", BaseMapper.class)); - }); - }catch(BeansException e){ - log.info(e.getMessage()); - } - } - - private String initFactory(Class clazz) { - String collectionName = clazz.getSimpleName().toLowerCase(); - final String[] dataBaseName = {""}; - if (clazz.isAnnotationPresent(CollectionName.class)) { - CollectionName annotation = clazz.getAnnotation(CollectionName.class); - collectionName = annotation.value(); - dataBaseName[0] = annotation.database(); - } - try { - String finalCollectionName = collectionName; - final String[] finalDataBaseName = {dataBaseName[0]}; - List mongoDatabaseList = new ArrayList<>(); - MongoPlusClient mongoPlusClient = applicationContext.getBean("mongoPlusClient", MongoPlusClient.class); - String database = mongoPlusClient.getBaseProperty().getDatabase(); - Arrays.stream(database.split(",")).collect(Collectors.toList()).forEach(db -> { - CollectionNameConvert collectionNameConvert = applicationContext.getBean("collectionNameConvert", CollectionNameConvert.class); - CollectionManager collectionManager = new CollectionManager(mongoPlusClient.getMongoClient(), collectionNameConvert, db); - ConnectMongoDB connectMongodb = new ConnectMongoDB(mongoPlusClient.getMongoClient(), db, finalCollectionName); - MongoDatabase mongoDatabase = mongoPlusClient.getMongoClient().getDatabase(db); - mongoDatabaseList.add(mongoDatabase); - if (Objects.equals(db, finalDataBaseName[0])) { - MongoCollection collection = connectMongodb.open(mongoDatabase); - collectionManager.setCollectionMap(finalCollectionName, collection); - } - mongoPlusClient.getCollectionManager().put(db, collectionManager); - }); - mongoPlusClient.setMongoDatabase(mongoDatabaseList); - } catch (MongoException e) { - log.error("Failed to connect to MongoDB: {}", e.getMessage(), e); - } - return dataBaseName[0]; - } - - @Override - public void unRegistry(PluginInfo plugin) throws Exception { - // 不做操作,直接通过关闭PluginApplicationContext完成注销 - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/MapperHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/MapperHandler.java deleted file mode 100644 index db9160e..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/MapperHandler.java +++ /dev/null @@ -1,101 +0,0 @@ -package cd.casic.plugin.register.mybatis; - -import cd.casic.plugin.PluginInfo; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.session.SqlSessionFactory; -import org.mybatis.spring.SqlSessionTemplate; -import org.mybatis.spring.mapper.MapperFactoryBean; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition; -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; -import org.springframework.beans.factory.support.GenericBeanDefinition; -import org.springframework.context.annotation.*; - -import java.util.ArrayList; -import java.util.List; - -public class MapperHandler { - - private static final Logger LOGGER = LoggerFactory.getLogger(MapperHandler.class); - - private static final String MAPPER_INTERFACE_NAMES = "MybatisMapperInterfaceNames"; - - private final ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver(); - - - public MapperHandler() { - } - - /** - * 处理插件中的Mapper - * @param pluginInfo 插件信息 - * @param processMapper Mapper的具体处理者 - */ - public void processMapper(PluginInfo pluginInfo, - ProcessMapper processMapper){ - AnnotationConfigApplicationContext applicationContext = pluginInfo.getPluginApplicationContext(); - // TODO 这里可以把类进行分组,就不用每次都扫mapper - List> mapperClassList = new ArrayList<>(); - - for (Class aClass : pluginInfo.getClassList()) { - Mapper annotation = aClass.getAnnotation(Mapper.class); - if (annotation != null) { - mapperClassList.add(aClass); - } - } - - String pluginId = pluginInfo.getPluginId(); - for (Class mapperClass : mapperClassList) { - if (mapperClass == null) { - continue; - } -// BeanNameGenerator beanNameGenerator = new PluginAnnotationBeanNameGenerator(pluginId); - AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(mapperClass); - ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(abd); - abd.setScope(scopeMetadata.getScopeName()); -// String beanName = beanNameGenerator.generateBeanName(abd, applicationContext); - String beanName = abd.getBeanClassName(); - BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); - AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); - BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, applicationContext); - try { - processMapper.process(definitionHolder, mapperClass); - } catch (Exception e) { - LOGGER.error("process mapper '{}' error. {}", mapperClass.getName(), e.getMessage(), e); - } - } - } - - - /** - * 公共注册生成代理Mapper接口 - * @param holder ignore - * @param mapperClass ignore - * @param sqlSessionFactory ignore - * @param sqlSessionTemplate ignore - */ - public void commonProcessMapper(BeanDefinitionHolder holder, - Class mapperClass, - SqlSessionFactory sqlSessionFactory, - SqlSessionTemplate sqlSessionTemplate) { - GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition(); - definition.getConstructorArgumentValues().addGenericArgumentValue(mapperClass); - definition.setBeanClass(MapperFactoryBean.class); - definition.getPropertyValues().add("addToConfig", true); - definition.getPropertyValues().add("sqlSessionFactory", sqlSessionFactory); - definition.getPropertyValues().add("sqlSessionTemplate", sqlSessionTemplate); - definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); - } - - - - @FunctionalInterface - public interface ProcessMapper{ - void process(BeanDefinitionHolder holder, Class mapperClass) throws Exception; - } - - -} \ No newline at end of file diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/MybatisCommonConfig.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/MybatisCommonConfig.java deleted file mode 100644 index bf670a9..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/MybatisCommonConfig.java +++ /dev/null @@ -1,38 +0,0 @@ -package cd.casic.plugin.register.mybatis; - -import java.util.Set; - -/** - * Mybatis基础配置 - */ -public interface MybatisCommonConfig { - - /** - * 数据库表对应的实体类的包名集合。可配置多个 - * @return Set - */ - Set entityPackage(); - - /** - * mybatis xml mapper 匹配规则
- * ? 匹配一个字符
- * * 匹配零个或多个字符
- * ** 匹配路径中的零或多个目录
- * 例如:
- * 文件路径配置为

file:D://xml/*PluginMapper.xml


- * resources路径配置为

classpath:xml/mapper/*PluginMapper.xml


- * 包路径配置为

package:com.plugin.xml.mapper.*PluginMapper.xml


- * @return Set - */ - Set xmlLocationsMatch(); - - /** - * 插件是否自主启用配置. 默认进行禁用, 使用主程序的配置 - * @return 返回true, 表示进行插件自主进行Mybatis相关配置 - */ - default boolean enableOneselfConfig(){ - return false; - } - - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/PluginFollowCoreConfig.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/PluginFollowCoreConfig.java deleted file mode 100644 index 1ebe43e..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/PluginFollowCoreConfig.java +++ /dev/null @@ -1,123 +0,0 @@ -package cd.casic.plugin.register.mybatis; - -import com.baomidou.mybatisplus.core.MybatisConfiguration; -import org.apache.ibatis.mapping.DatabaseIdProvider; -import org.apache.ibatis.plugin.Interceptor; -import org.apache.ibatis.scripting.LanguageDriver; -import org.apache.ibatis.scripting.LanguageDriverRegistry; -import org.apache.ibatis.session.SqlSessionFactory; -import org.springframework.context.ApplicationContext; -import org.springframework.util.ReflectionUtils; - -import javax.sql.DataSource; -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 插件跟随主程序时, 获取主程序的Mybatis定义的一些配置 - */ -public class PluginFollowCoreConfig { - - private final ApplicationContext mainApplicationContext; - - public PluginFollowCoreConfig(ApplicationContext mainApplicationContext) { - this.mainApplicationContext = mainApplicationContext; - } - - - public DataSource getDataSource(){ - return mainApplicationContext.getBean(DataSource.class); - } - - public MybatisConfiguration getMybatisPlusConfiguration(){ - MybatisConfiguration configuration = new MybatisConfiguration(); - try { - Map customizerMap = - mainApplicationContext.getBeansOfType(com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer.class); - if(!customizerMap.isEmpty()){ - for (com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer customizer : customizerMap.values()) { - customizer.customize(configuration); - } - } - } catch (Exception e){ - // ignore - } - return configuration; - } - - public Interceptor[] getInterceptor(){ - Map, Interceptor> interceptorMap = new HashMap<>(); - try { - SqlSessionFactory sqlSessionFactory = mainApplicationContext.getBean(SqlSessionFactory.class); - // 先从 SqlSessionFactory 工厂中获取拦截器 - List interceptors = sqlSessionFactory.getConfiguration().getInterceptors(); - if(interceptors != null){ - for (Interceptor interceptor : interceptors) { - if(interceptor == null){ - continue; - } - interceptorMap.put(interceptor.getClass(), interceptor); - } - } - } catch (Exception e){ - // ignore - } - // 再从定义Bean中获取拦截器 - Map beanInterceptorMap = mainApplicationContext.getBeansOfType(Interceptor.class); - if(!beanInterceptorMap.isEmpty()){ - beanInterceptorMap.forEach((k, v)->{ - // 如果Class一致, 则会覆盖 - interceptorMap.put(v.getClass(), v); - }); - } - if(interceptorMap.isEmpty()) { - return null; - } else { - return interceptorMap.values().toArray(new Interceptor[0]); - } - } - - public DatabaseIdProvider getDatabaseIdProvider(){ - String[] beanNamesForType = mainApplicationContext.getBeanNamesForType(DatabaseIdProvider.class, false, false); - if(beanNamesForType.length > 0){ - return mainApplicationContext.getBean(DatabaseIdProvider.class); - } - return null; - } - - @SuppressWarnings("unchecked") - public LanguageDriver[] getLanguageDriver(){ - Map, LanguageDriver> languageDriverMap = new HashMap<>(); - try { - SqlSessionFactory sqlSessionFactory = mainApplicationContext.getBean(SqlSessionFactory.class); - LanguageDriverRegistry languageRegistry = sqlSessionFactory.getConfiguration() - .getLanguageRegistry(); - // 先从 SqlSessionFactory 工厂中获取LanguageDriver - Field proxyTypesField = ReflectionUtils.findField(languageRegistry.getClass(), "LANGUAGE_DRIVER_MAP"); - Map, LanguageDriver> driverMap = null; - if(proxyTypesField != null){ - proxyTypesField.setAccessible(true); - driverMap = (Map, LanguageDriver>) proxyTypesField.get(languageRegistry); - } - if(driverMap != null){ - languageDriverMap.putAll(driverMap); - } - } catch (Exception e){ - // ignore - } - Map beansLanguageDriver = mainApplicationContext.getBeansOfType(LanguageDriver.class); - if(!beansLanguageDriver.isEmpty()){ - beansLanguageDriver.forEach((k, v)->{ - // 如果Class一致, 则会覆盖 - languageDriverMap.put(v.getClass(), v); - }); - } - if(languageDriverMap.isEmpty()){ - return null; - } - return languageDriverMap.values().toArray(new LanguageDriver[0]); - } - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/PluginResourceFinder.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/PluginResourceFinder.java deleted file mode 100644 index 70a6ad2..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/PluginResourceFinder.java +++ /dev/null @@ -1,121 +0,0 @@ -package cd.casic.plugin.register.mybatis; - -import cd.casic.plugin.PluginInfo; -import cd.casic.plugin.utils.ResourceUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.core.type.ClassMetadata; -import org.springframework.core.type.classreading.MetadataReaderFactory; -import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; -import org.springframework.util.ClassUtils; - -import java.io.IOException; -import java.util.*; - -/** - * 插件资源发现者 - * @author starBlues - * @version 2.4.0 - */ -public class PluginResourceFinder { - - private static final Logger LOGGER = LoggerFactory.getLogger(PluginResourceFinder.class); - - private final ClassLoader classLoader; - private final ResourcePatternResolver resourcePatternResolver; - private final MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); - - - public PluginResourceFinder(PluginInfo pluginInfo) { - this.classLoader = pluginInfo.getPluginWrapper().getPluginClassLoader(); - this.resourcePatternResolver = new PathMatchingResourcePatternResolver(classLoader); - } - - /** - * 获取插件中xml资源 - * @param xmlLocationsMatchSet xml资源匹配集合 - * @return xml Resource 数组 - * @throws IOException 获取xml资源异常 - */ - public Resource[] getXmlResource(Set xmlLocationsMatchSet) throws IOException { - if(xmlLocationsMatchSet == null || xmlLocationsMatchSet.isEmpty()){ - return null; - } - List resources = new ArrayList<>(); - for (String xmlLocationsMatch : xmlLocationsMatchSet) { - if(xmlLocationsMatchSet.isEmpty()){ - continue; - } - List loadResources = getXmlResources(xmlLocationsMatch); - if(loadResources != null && !loadResources.isEmpty()){ - resources.addAll(loadResources); - } - } - - if(resources.isEmpty()){ - return null; - } - - return resources.toArray(new Resource[0]); - } - - - - /** - * 获取插件的实体类及其别名 - * @param packagePatterns 实体类包名 - * @return class 数组 - * @throws IOException 获取医院异常 - */ - public Class[] getAliasesClasses(Set packagePatterns) throws IOException { - if(packagePatterns == null || packagePatterns.isEmpty()){ - return null; - } - Set> aliasesClasses = new HashSet<>(); - for (String packagePattern : packagePatterns) { - Resource[] resources = resourcePatternResolver.getResources( - ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX - + ClassUtils.convertClassNameToResourcePath(packagePattern) + "/**/*.class"); - for (Resource resource : resources) { - try { - ClassMetadata classMetadata = metadataReaderFactory.getMetadataReader(resource).getClassMetadata(); - Class clazz = classLoader.loadClass(classMetadata.getClassName()); - aliasesClasses.add(clazz); - } catch (Throwable e) { - LOGGER.warn("Cannot load the '{}'. Cause by {}", resource, e.toString()); - } - } - } - return aliasesClasses.toArray(new Class[0]); - } - - /** - * 获取Xml资源 - * @param mybatisMapperXmlLocationMatch mybatis xml 批量规则 - * @return 匹配到的xml资源 - * @throws IOException IO 异常 - */ - private List getXmlResources(String mybatisMapperXmlLocationMatch) throws IOException { - String matchLocation = ResourceUtils.getMatchLocation(mybatisMapperXmlLocationMatch); - if(matchLocation == null){ - LOGGER.error("mybatisMapperXmlLocation {} illegal", mybatisMapperXmlLocationMatch); - return null; - } - try { - Resource[] resources = resourcePatternResolver.getResources(matchLocation); - if(resources.length > 0){ - return Arrays.asList(resources); - } else { - return null; - } - } catch (IOException e) { - LOGGER.error("mybatis xml resource '{}' match error : {}", mybatisMapperXmlLocationMatch, - e.getMessage(), e); - throw e; - } - } - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/mybatisplus/MybatisPlusConfig.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/mybatisplus/MybatisPlusConfig.java deleted file mode 100644 index dcf74c9..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/mybatisplus/MybatisPlusConfig.java +++ /dev/null @@ -1,27 +0,0 @@ -package cd.casic.plugin.register.mybatis.mybatisplus; - -import cd.casic.plugin.register.mybatis.MybatisCommonConfig; -import com.baomidou.mybatisplus.core.MybatisConfiguration; -import com.baomidou.mybatisplus.core.config.GlobalConfig; -import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; - -public interface MybatisPlusConfig extends MybatisCommonConfig { - - /** - * 插件自主配置Mybatis-Plus的MybatisSqlSessionFactoryBean - * MybatisSqlSessionFactoryBean 具体配置说明参考 Mybatis-plus 官网 - * @param sqlSessionFactoryBean MybatisSqlSessionFactoryBean - */ - default void oneselfConfig(MybatisSqlSessionFactoryBean sqlSessionFactoryBean){ - } - - /** - * 重写设置配置 - * 只有 enableOneselfConfig 返回 false, 实现该方法才生效 - * @param configuration 当前 MybatisConfiguration - * @param globalConfig 当前全局配置GlobalConfig - */ - default void reSetMainConfig(MybatisConfiguration configuration, GlobalConfig globalConfig){ - - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/mybatisplus/MybatisPlusHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/mybatisplus/MybatisPlusHandler.java deleted file mode 100644 index e6d2866..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/mybatis/mybatisplus/MybatisPlusHandler.java +++ /dev/null @@ -1,133 +0,0 @@ -package cd.casic.plugin.register.mybatis.mybatisplus; - -import cd.casic.plugin.PluginInfo; -import cd.casic.plugin.register.BasePluginHandler; -import cd.casic.plugin.register.mybatis.MapperHandler; -import cd.casic.plugin.register.mybatis.PluginFollowCoreConfig; -import cd.casic.plugin.register.mybatis.PluginResourceFinder; -import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties; -import com.baomidou.mybatisplus.core.MybatisConfiguration; -import com.baomidou.mybatisplus.core.config.GlobalConfig; -import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; -import org.apache.ibatis.io.Resources; -import org.apache.ibatis.mapping.DatabaseIdProvider; -import org.apache.ibatis.plugin.Interceptor; -import org.apache.ibatis.scripting.LanguageDriver; -import org.apache.ibatis.session.SqlSessionFactory; -import org.mybatis.spring.SqlSessionTemplate; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.context.ApplicationContext; -import org.springframework.core.io.Resource; -import org.springframework.util.ClassUtils; - -import java.io.IOException; -import java.util.Set; - -public class MybatisPlusHandler implements BasePluginHandler { - @Override - public void initialize() throws Exception { - - } - - @Override - public void registry(PluginInfo plugin) throws IOException { - MybatisPlusConfig config = getObjectByInterfaceClass(plugin.getPluginConfigObjects(), MybatisPlusConfig.class); - if(config == null) return; - final MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean(); - - if(config.enableOneselfConfig()){ - config.oneselfConfig(factory); - } else { - PluginFollowCoreConfig followCoreConfig = new PluginFollowCoreConfig( - plugin.getMainApplicationContext() - ); - MybatisConfiguration mybatisPlusConfiguration = followCoreConfig.getMybatisPlusConfiguration(); - factory.setDataSource(followCoreConfig.getDataSource()); - factory.setConfiguration(mybatisPlusConfiguration); - Interceptor[] interceptor = followCoreConfig.getInterceptor(); - if(interceptor != null && interceptor.length > 0){ - factory.setPlugins(interceptor); - } - DatabaseIdProvider databaseIdProvider = followCoreConfig.getDatabaseIdProvider(); - if(databaseIdProvider != null){ - factory.setDatabaseIdProvider(databaseIdProvider); - } - LanguageDriver[] languageDriver = followCoreConfig.getLanguageDriver(); - if(languageDriver != null){ - factory.setScriptingLanguageDrivers(languageDriver); - } - // 配置mybatis-plus私有的配置 - GlobalConfig globalConfig = mybatisPlusFollowCoreConfig(factory, plugin.getMainApplicationContext()); - config.reSetMainConfig(mybatisPlusConfiguration, globalConfig); - } - - PluginResourceFinder pluginResourceFinder = new PluginResourceFinder(plugin); - - Class[] aliasesClasses = pluginResourceFinder.getAliasesClasses(config.entityPackage()); - if(aliasesClasses != null && aliasesClasses.length > 0){ - factory.setTypeAliases(aliasesClasses); - } - - Resource[] xmlResource = pluginResourceFinder.getXmlResource(config.xmlLocationsMatch()); - if(xmlResource != null && xmlResource.length > 0){ - factory.setMapperLocations(xmlResource); - } - ClassLoader defaultClassLoader = Resources.getDefaultClassLoader(); - try { - Resources.setDefaultClassLoader(plugin.getPluginWrapper().getPluginClassLoader()); - SqlSessionFactory sqlSessionFactory = factory.getObject(); - if(sqlSessionFactory == null){ - throw new Exception("Get mybatis-plus sqlSessionFactory is null"); - } - SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory); - MapperHandler mapperHandler = new MapperHandler(); - mapperHandler.processMapper(plugin, (holder, mapperClass) -> - mapperHandler.commonProcessMapper(holder, mapperClass, sqlSessionFactory, sqlSessionTemplate)); - DefaultListableBeanFactory beanFactory = plugin.getPluginApplicationContext().getDefaultListableBeanFactory(); - beanFactory.registerSingleton("sqlSessionFactory", sqlSessionFactory); - beanFactory.registerSingleton("sqlSession", sqlSessionTemplate); - } catch (Exception e) { - throw new RuntimeException(e); - } finally { - Resources.setDefaultClassLoader(defaultClassLoader); - } - } - - @Override - public void unRegistry(PluginInfo plugin) throws Exception { - // 不做操作,直接通过关闭PluginApplicationContext完成注销。 - } - - - private GlobalConfig mybatisPlusFollowCoreConfig(MybatisSqlSessionFactoryBean factory, - ApplicationContext mainApplicationContext){ - MybatisPlusProperties plusProperties = mainApplicationContext.getBean(MybatisPlusProperties.class); - - GlobalConfig currentGlobalConfig = new GlobalConfig(); - currentGlobalConfig.setBanner(false); - GlobalConfig globalConfig = plusProperties.getGlobalConfig(); - if(globalConfig != null){ - currentGlobalConfig.setDbConfig(globalConfig.getDbConfig()); - currentGlobalConfig.setIdentifierGenerator(globalConfig.getIdentifierGenerator()); - currentGlobalConfig.setMetaObjectHandler(globalConfig.getMetaObjectHandler()); - currentGlobalConfig.setSqlInjector(globalConfig.getSqlInjector()); - } - factory.setGlobalConfig(currentGlobalConfig); - return currentGlobalConfig; - } - - // TODO 临时放这里,先跑通mybatis-plus集成测试 - public static T getObjectByInterfaceClass(Set sourceObject, Class interfaceClass){ - if(sourceObject == null || sourceObject.isEmpty()){ - return null; - } - for (Object configSingletonObject : sourceObject) { - Set> allInterfacesForClassAsSet = ClassUtils - .getAllInterfacesAsSet(configSingletonObject); - if(allInterfacesForClassAsSet.contains(interfaceClass)){ - return (T) configSingletonObject; - } - } - return null; - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/websocket/BaseServerEndpoint.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/websocket/BaseServerEndpoint.java deleted file mode 100644 index a16c36e..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/websocket/BaseServerEndpoint.java +++ /dev/null @@ -1,7 +0,0 @@ -package cd.casic.plugin.register.websocket; - -import org.springframework.beans.factory.DisposableBean; - -public interface BaseServerEndpoint extends DisposableBean { - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/websocket/WebSocketHandler.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/websocket/WebSocketHandler.java deleted file mode 100644 index 85e521d..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/register/websocket/WebSocketHandler.java +++ /dev/null @@ -1,235 +0,0 @@ -package cd.casic.plugin.register.websocket; - -import cd.casic.plugin.PluginInfo; -import cd.casic.plugin.register.BasePluginHandler; -import cd.casic.plugin.register.group.filter.impl.WebSocketFilter; -import cn.hutool.core.util.StrUtil; -import cn.hutool.extra.spring.SpringUtil; -import jakarta.servlet.ServletContext; -import jakarta.websocket.DeploymentException; -import jakarta.websocket.EndpointConfig; -import jakarta.websocket.Session; -import jakarta.websocket.server.ServerContainer; -import jakarta.websocket.server.ServerEndpoint; -import jakarta.websocket.server.ServerEndpointConfig; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.pf4j.util.StringUtils; -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.socket.server.standard.ServerEndpointExporter; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentSkipListMap; - -@Slf4j -@SuppressWarnings("unchecked") -public class WebSocketHandler implements BasePluginHandler { - private ApplicationContext mainApplicationContext; - - @Override - public void initialize() throws Exception { - this.mainApplicationContext = SpringUtil.getApplicationContext(); - } - - @Override - public void registry(PluginInfo plugin) throws Exception { - ServerContainer serverContainer = getServerContainer(); - if (serverContainer == null) return; - - List> webSocketClassList = plugin.getGroupClass(WebSocketFilter.GROUP_NAME); - if(webSocketClassList.isEmpty()) return; - String pluginId = plugin.getPluginId(); - webSocketClassList.forEach(websocketClass -> { - ServerEndpoint serverEndpoint = websocketClass.getDeclaredAnnotation(ServerEndpoint.class); - if (serverEndpoint == null) { - log.warn("WebSocket class {} doesn't has annotation {}", websocketClass.getName(), ServerEndpoint.class.getName()); - return; - } - String sourcePath = serverEndpoint.value(); - if (StringUtils.isNullOrEmpty(sourcePath)) { - return; - } - String processPath = sourcePath; - if(!processPath.startsWith("/")){ - processPath = "/".concat(processPath); - } - UriTemplate uriTemplate; - try { - uriTemplate = new UriTemplate(processPath); - } catch (DeploymentException e) { - log.error("Websocket path validate failed.", e); - return; - } - String newWebsocketPath = "/".concat(pluginId).concat(processPath); - String newWebsocketTemplatePath = "/".concat(pluginId).concat(uriTemplate.getPath()); - Map annotationsUpdater; - try { - InvocationHandler invocationHandler = Proxy.getInvocationHandler(serverEndpoint); - Field field = invocationHandler.getClass().getDeclaredField("memberValues"); - field.setAccessible(true); - annotationsUpdater = (Map) field.get(invocationHandler); - } catch (Exception e) { - log.error("Process and update websocket path '{}' annotation exception.", sourcePath, e); - return; - } - try { - annotationsUpdater.put("value", newWebsocketPath); - serverContainer.addEndpoint(websocketClass); - plugin.getWebSocketPathMap().put(newWebsocketPath, newWebsocketTemplatePath); - log.info("Succeed to create websocket service for path {}", newWebsocketPath); - } catch (Exception e) { - log.error("Create websocket service for websocket class " + websocketClass.getName() + " failed.", e); - } finally { - annotationsUpdater.put("value", sourcePath); - } - }); - - } - - @Override - public void unRegistry(PluginInfo plugin){ - ServerContainer serverContainer = getServerContainer(); - if (serverContainer == null) { - log.warn("Not found ServerContainer, So websocket can't used!"); - return; - } - - Class containerClass = serverContainer.getClass(); - try { - Field configExactMatchMapField = containerClass.getDeclaredField("configExactMatchMap"); - configExactMatchMapField.setAccessible(true); - Map configExactMatchMap = (Map) configExactMatchMapField.get(serverContainer); - - Field configTemplateMatchMapField = containerClass.getDeclaredField("configTemplateMatchMap"); - configTemplateMatchMapField.setAccessible(true); - Map> configTemplateMatchMap = - (Map>) configTemplateMatchMapField.get(serverContainer); - - Map webSocketPathMap = plugin.getWebSocketPathMap(); - webSocketPathMap.forEach((webSocketPath, newWebsocketTemplatePath)->{ - configExactMatchMap.remove(webSocketPath); - log.debug("Removed websocket config for path {}", webSocketPath); - configTemplateMatchMap.forEach((key, value) -> value.remove(newWebsocketTemplatePath)); - log.debug("Removed websocket session for path {}", webSocketPath); - log.info("Remove websocket for path {} success.", webSocketPath); - }); - }catch (Exception e){ - throw new RuntimeException(e); - } - - - } - - /** - * 得到 Tomcat ServerContainer - * @return ServerContainer - */ - private ServerContainer getServerContainer() { - try { - mainApplicationContext.getBean(ServerEndpointExporter.class); - } catch (BeansException e) { - log.debug("The required bean of {} not found, if you want to use plugin websocket, please create it.", ServerEndpointExporter.class.getName()); - return null; - } - if (!(mainApplicationContext instanceof WebApplicationContext)) { - return null; - } - WebApplicationContext webApplicationContext = (WebApplicationContext) mainApplicationContext; - ServletContext servletContext = webApplicationContext.getServletContext(); - if (servletContext == null) { - log.warn("Servlet context is null."); - return null; - } - Object obj = servletContext.getAttribute("javax.websocket.server.ServerContainer"); - if (!(obj instanceof ServerContainer)) { - return null; - } - return (ServerContainer) obj; - } - - /** - * 关闭session - * @param session session - * @param websocketPath websocketPath 路径 - * @return 如果需要关闭并且关闭成功, 则返回true。 否则返回false - * @throws Exception 关闭异常 - */ - @Deprecated - private boolean closeSession(Session session, String websocketPath) throws Exception{ - EndpointConfig endpointConfig = (EndpointConfig) session.getClass().getDeclaredField("endpointConfig").get(session); - ServerEndpointConfig perEndpointConfig = (ServerEndpointConfig) endpointConfig.getClass().getDeclaredField("perEndpointConfig").get(endpointConfig); - String path = perEndpointConfig.getPath(); - if (path.equals(websocketPath)) { - session.close(); - log.info("Closed websocket session {} for path {}", session.getId(), websocketPath); - return true; - } - return false; - } - - /** - * websocket路径解析类,主要用于处理参数 - */ - @Getter - private static class UriTemplate { - - private final Map paramMap = new ConcurrentHashMap<>(); - private final String path; - - private UriTemplate(String path) throws DeploymentException { - if (StrUtil.isEmpty(path) || !path.startsWith("/") || path.contains("/../") || path.contains("/./") || path.contains("//")) { - throw new DeploymentException(String.format("The path [%s] is not valid.", path)); - } - StringBuilder normalized = new StringBuilder(path.length()); - Set paramNames = new HashSet<>(); - - // Include empty segments. - String[] segments = path.split("/", -1); - int paramCount = 0; - - for (int i = 0; i < segments.length; i++) { - String segment = segments[i]; - if (segment.isEmpty()) { - if (i == 0 || (i == segments.length - 1 && paramCount == 0)) { - // Ignore the first empty segment as the path must always - // start with '/' - // Ending with a '/' is also OK for instances used for - // matches but not for parameterised templates. - continue; - } else { - // As per EG discussion, all other empty segments are - // invalid - throw new DeploymentException(String.format("The path [%s] contains one or more empty segments which is not permitted", path)); - } - } - normalized.append('/'); - if (segment.startsWith("{") && segment.endsWith("}")) { - segment = segment.substring(1, segment.length() - 1); - normalized.append('{'); - normalized.append(paramCount++); - normalized.append('}'); - if (!paramNames.add(segment)) { - throw new DeploymentException(String.format("The parameter [%s] appears more than once in the path which is not permitted", segment)); - } - paramMap.put(segment, paramCount - 1); - } else { - if (segment.contains("{") || segment.contains("}")) { - throw new DeploymentException(String.format("The segment [%s] is not valid in the provided path [%s]", segment, path)); - } - normalized.append(segment); - } - } - this.path = normalized.toString(); - } - - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/BeanUtils.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/BeanUtils.java deleted file mode 100644 index 3020c6c..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/BeanUtils.java +++ /dev/null @@ -1,226 +0,0 @@ -package cd.casic.plugin.utils; - -import lombok.NoArgsConstructor; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.lang.NonNull; - -import java.io.*; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; - -@NoArgsConstructor -public class BeanUtils { - - public static T getFieldValue(@NonNull Object target, @NonNull String path) { - String[] fieldPath = path.split("\\."); - Object obj = target; - int i = 0; - while (i < fieldPath.length) { - if (obj == null) break; - if ("*".equals(fieldPath[i])) { - // merge map - if (obj instanceof Map) { - obj = ((Map) obj).values(); - } else if (obj instanceof Collection) { - obj = obj; - } else { - // non-support object fields - return null; - } - } else { - if (obj instanceof Collection) { - List values = new ArrayList<>(); - for (Object item : (Collection) obj) { - Object value = getFieldValue(item, item.getClass(), fieldPath[i]); - values.add(value); - } - obj = values; - } else { - obj = getFieldValue(obj, obj.getClass(), fieldPath[i]); - } - } - i++; - } - return (T) obj; - } - - public static Class getFieldClass(@NonNull Object target, @NonNull String fieldName) { - try { - return target.getClass().getDeclaredField(fieldName).getType(); - } catch (Exception e) { - return null; - } - } - - - private static Object getFieldValue(@NonNull Object target, @NonNull Class clazz, @NonNull String fieldName) { - if (Map.class.isAssignableFrom(clazz)) { - return ((Map) target).get(fieldName); - } - - try { - Field field = target instanceof Class - ? ((Class) target).getDeclaredField(fieldName) - : clazz.getDeclaredField(fieldName); - field.setAccessible(true); - return field.get(target); - } catch (NoSuchFieldException nsfe) { - if (clazz.getSuperclass() != null) { - return target instanceof Class - ? getFieldValue(((Class) target).getSuperclass(), clazz, fieldName) - : getFieldValue(target, clazz.getSuperclass(), fieldName); - } else { - return null; - } - } catch (Exception e) { - return null; - } - } - - public static void setFieldValue(@NonNull Object target, @NonNull String fieldName, Object value) { - setFieldValue(target, target.getClass(), fieldName, value); - } - - private static void setFieldValue(@NonNull Object target, @NonNull Class clazz, @NonNull String fieldName, Object value) { - try { - Field field = target instanceof Class - ? ((Class) target).getDeclaredField(fieldName) - : clazz.getDeclaredField(fieldName); - field.setAccessible(true); - field.set(target, value); - } catch (NoSuchFieldException nsfe) { - if (clazz.getSuperclass() != null) { - setFieldValue(target, clazz.getSuperclass(), fieldName, value); - } else { - throw new RuntimeException("Set field " + fieldName + " failed.", nsfe); - } - } catch (Exception e) { - throw new RuntimeException("Set field " + fieldName + " failed.", e); - } - } - - public static T deepClone(@NonNull T o) { - try { - ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(byteOut); - out.writeObject(o); - out.flush(); - ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(byteOut.toByteArray())); - return (T) o.getClass().cast(in.readObject()); - } catch (Exception e) { - throw new RuntimeException("Failed to copy Object " + o.getClass().getName(), e); - } - } - - public static Method getDeclaredMethod(@NonNull Class clazz, @NonNull String methodName, Class... parameterTypes) { - Method method = null; - Class clz = clazz; - while (clz != Object.class) { - try { - method = parameterTypes.length > 0 - ? clz.getDeclaredMethod(methodName, parameterTypes) - : clz.getDeclaredMethod(methodName); - break; - } catch (NoSuchMethodException e) { - clz = clz.getSuperclass(); - } - } - if (method != null) method.setAccessible(true); - return method; - } - - public static Method getMethod(@NonNull Class clazz, @NonNull String methodName, Class... parameterTypes) { - Method method; - try { - method = parameterTypes.length > 0 - ? clazz.getMethod(methodName, parameterTypes) - : clazz.getMethod(methodName); - } catch (NoSuchMethodException e) { - return null; - } - if (method != null) method.setAccessible(true); - return method; - } - - public static R callMethod(O object, @NonNull String methodName, Object... parameters) { - Class clazz = (Class) object.getClass(); - return callMethod(clazz, object, methodName, parameters); - } - - /** - * This method doesn't always function as expected. Be 100% sure - * and tested when you use it. - *

- * As known, this method is not worked for following case: - * * parameter type is primitive number, e.g. int.class - * * parameter type is general type, e.g. Object.class - */ - public static R callMethod(Class clazz, Object object, @NonNull String methodName, Object... parameters) { - if (object == null) return null; - - Method method; - // try get method from `getMethod` - if (parameters.length == 0) { - method = getMethod(clazz, methodName); - } else { - method = getMethod(clazz, methodName, - Arrays.stream(parameters).map(Object::getClass).toArray(Class[]::new)); - } - - // try get method from `getDeclaredMethod` - if (method == null) { - if (parameters.length == 0) { - method = getDeclaredMethod(clazz, methodName); - } else { - method = getDeclaredMethod(clazz, methodName, - Arrays.stream(parameters).map(Object::getClass).toArray(Class[]::new)); - } - } - - if (method == null) return null; - - try { - return (R) method.invoke(object, parameters); - } catch (IllegalAccessException | InvocationTargetException ignore) { - } - return null; - } - - public static String getBeanName(BeanFactory beanFactory, Object bean) { - String beanName = null; - Map beans = BeanUtils.getFieldValue(beanFactory, "disposableBeans"); - if (beans != null) { - beanName = beans.entrySet().stream() - .filter(entry -> entry.getValue() == bean).findAny() - .map(Map.Entry::getKey).orElse(null); - } - if (beanName == null) { - beans = BeanUtils.getFieldValue(beanFactory, "singletonObjects"); - if (beans != null) { - beanName = beans.entrySet().stream() - .filter(entry -> entry.getValue() == bean).findAny() - .map(Map.Entry::getKey).orElse(null); - } - } - return beanName; - } - - public static Map, ?> getTempBeans(List> classList){ - // 创建临时上下文 - AnnotationConfigApplicationContext tempContext = new AnnotationConfigApplicationContext(); - // 注册需要即时使用的类 - classList.forEach(tempContext::register); - // 刷新临时上下文 - tempContext.refresh(); - // 获取bean - Map, ?> tempBean = classList.stream().collect(Collectors.toMap(Function.identity(), tempContext::getBean)); - // 关闭临时上下文 - tempContext.close(); - return tempBean; - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/CommonUtils.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/CommonUtils.java deleted file mode 100644 index 00b1df9..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/CommonUtils.java +++ /dev/null @@ -1,152 +0,0 @@ -package cd.casic.plugin.utils; - -import cd.casic.plugin.PluginProperties; -import cn.hutool.core.util.StrUtil; -import org.pf4j.util.StringUtils; - -import java.io.File; -import java.util.Comparator; -import java.util.List; -import java.util.function.Function; - -/** - * 通用工具 - */ -public class CommonUtils { - - private CommonUtils() { - } - - /** - * list按照int排序. 数字越大, 越排在前面 - * - * @param list list集合 - * @param orderImpl 排序实现 - * @param T - * @return List - */ - public static List order(List list, Function orderImpl) { - if (list == null) { - return null; - } - list.sort(Comparator.comparing(orderImpl, Comparator.nullsLast(Comparator.reverseOrder()))); - return list; - } - - - /** - * 得到插件接口前缀 - * - * @param configuration 配置 - * @param pluginId 插件id - * @return 接口前缀 - */ - public static String getPluginRestPrefix(PluginProperties pluginProperties, String pluginId) { - String pathPrefix = pluginProperties.getRestPathPrefix(); - if (pluginProperties.isEnablePluginIdAsRestPrefix()) { - if (StrUtil.isNotEmpty(pathPrefix)) { - pathPrefix = restJoiningPath(pathPrefix, pluginId); - } else { - pathPrefix = pluginId; - } - return pathPrefix; - } else { - if (StrUtil.isEmpty(pathPrefix)) { - // 不启用插件id作为路径前缀, 并且路径前缀为空, 则直接返回。 - return null; - } - } - return pathPrefix; - } - - - /** - * rest接口拼接路径 - * - * @param path1 路径1 - * @param path2 路径2 - * @return 拼接的路径 - */ - public static String restJoiningPath(String path1, String path2) { - if (path1 != null && path2 != null) { - if (path1.endsWith("/") && path2.startsWith("/")) { - return path1 + path2.substring(1); - } else if (!path1.endsWith("/") && !path2.startsWith("/")) { - return path1 + "/" + path2; - } else { - return path1 + path2; - } - } else if (path1 != null) { - return path1; - } else if (path2 != null) { - return path2; - } else { - return ""; - } - } - - - /** - * 拼接url路径 - * - * @param paths 拼接的路径 - * @return 拼接的路径 - */ - public static String joiningPath(String... paths) { - if (paths == null || paths.length == 0) { - return ""; - } - StringBuilder stringBuilder = new StringBuilder(); - int length = paths.length; - for (int i = 0; i < length; i++) { - String path = paths[i]; - if (StringUtils.isNullOrEmpty(path)) { - continue; - } - if ((i < length - 1) && path.endsWith("/")) { - path = path.substring(path.lastIndexOf("/")); - } - if (path.startsWith("/")) { - stringBuilder.append(path); - } else { - stringBuilder.append("/").append(path); - } - } - - return stringBuilder.toString(); - } - - /** - * 拼接file路径 - * - * @param paths 拼接的路径 - * @return 拼接的路径 - */ - public static String joiningFilePath(String... paths) { - if (paths == null || paths.length == 0) { - return ""; - } - StringBuilder stringBuilder = new StringBuilder(); - int length = paths.length; - for (int i = 0; i < length; i++) { - String path = paths[i]; - if (StringUtils.isNullOrEmpty(path)) { - continue; - } - if (i > 0) { - if (path.startsWith(File.separator) || path.startsWith("/") || - path.startsWith("\\") || path.startsWith("//")) { - stringBuilder.append(path); - } else { - stringBuilder.append(File.separator).append(path); - } - } else { - stringBuilder.append(path); - } - } - - return stringBuilder.toString(); - } - - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/FrontResourceUtils.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/FrontResourceUtils.java deleted file mode 100644 index 3d898fd..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/FrontResourceUtils.java +++ /dev/null @@ -1,47 +0,0 @@ -package cd.casic.plugin.utils; - -import lombok.extern.slf4j.Slf4j; -import org.pf4j.PluginManager; -import org.pf4j.PluginWrapper; -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.core.io.Resource; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -@Slf4j -public abstract class FrontResourceUtils { - private static final String FRONT_BUNDLE_LOCATION = "/static/ui"; - public static final String JS_BUNDLE = "/assets/main.js"; - public static final String CSS_BUNDLE = "/assets/style.css"; - - @Nullable - public static Resource getJsBundleResource(PluginManager pluginManager, String pluginName, - String bundleName) { - Assert.hasText(pluginName, "The pluginName must not be blank"); - Assert.hasText(bundleName, "Bundle name must not be blank"); - DefaultResourceLoader resourceLoader = getResourceLoader(pluginManager, pluginName); - if (resourceLoader == null) { - return null; - } - String path = FRONT_BUNDLE_LOCATION + bundleName; - String simplifyPath = StringUtils.cleanPath(path); - Resource resource = resourceLoader.getResource(simplifyPath); - log.info("Get {} for plugin {} in the {} using {}", bundleName, pluginName, simplifyPath, resourceLoader); - return resource.exists() ? resource : null; - } - - @Nullable - public static DefaultResourceLoader getResourceLoader(PluginManager pluginManager, - String pluginName) { - Assert.notNull(pluginManager, "Plugin manager must not be null"); - PluginWrapper plugin = pluginManager.getPlugin(pluginName); - if (plugin == null) { - return null; - } - return new DefaultResourceLoader(plugin.getPluginClassLoader()); - } - - -} - diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/PluginDescriptorUtils.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/PluginDescriptorUtils.java deleted file mode 100644 index 8830f92..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/PluginDescriptorUtils.java +++ /dev/null @@ -1,118 +0,0 @@ -package cd.casic.plugin.utils; - -import cd.casic.plugin.PluginDescriptorStorage; -import cd.casic.plugin.pf4j.OpsPluginDescriptor; -import cn.hutool.core.util.StrUtil; -import org.pf4j.PluginDependency; - -import java.util.*; -import java.util.stream.Collectors; - -public class PluginDescriptorUtils { - public static final String PLUGIN_ID = "plugin.id"; - public static final String PLUGIN_DESCRIPTION = "plugin.description"; - public static final String PLUGIN_CLASS = "plugin.class"; - public static final String PLUGIN_VERSION = "plugin.version"; - public static final String PLUGIN_PROVIDER = "plugin.provider"; - public static final String PLUGIN_DEPENDENCIES = "plugin.dependencies"; - public static final String PLUGIN_REQUIRES = "plugin.requires"; - public static final String PLUGIN_LICENSE = "plugin.license"; - public static final String MYBATIS_MAPPER_LOCATION = "mybatis.mapper.location"; - public static final String STATIC_LOCATIONS = "static.locations"; - public static final String CONFIG_FILE_NAME = "plugin.config.file"; - public static final String CONFIG_FILE_ACTIVE = "plugin.config.active"; - - public static PluginDescriptorStorage propertiesToStorage(Properties properties){ - PluginDescriptorStorage pluginDescriptor = new PluginDescriptorStorage(); - - String id = properties.getProperty(PLUGIN_ID); - pluginDescriptor.setPluginId(id); - - String description = properties.getProperty(PLUGIN_DESCRIPTION); - if (StrUtil.isEmptyIfStr(description)) { - pluginDescriptor.setPluginDescription(""); - } else { - pluginDescriptor.setPluginDescription(description); - } - - String clazz = properties.getProperty(PLUGIN_CLASS); - if (!StrUtil.isEmptyIfStr(clazz)) { - pluginDescriptor.setPluginClass(clazz); - } - - String version = properties.getProperty(PLUGIN_VERSION); - if (!StrUtil.isEmptyIfStr(version)) { - pluginDescriptor.setVersion(version); - } - - String provider = properties.getProperty(PLUGIN_PROVIDER); - pluginDescriptor.setProvider(provider); - - String requires = properties.getProperty(PLUGIN_REQUIRES); - if (StrUtil.isEmptyIfStr(requires)) { - pluginDescriptor.setRequires("0.0.0"); - }else{ - pluginDescriptor.setRequires(requires); - } - - String mapperXmlDir = properties.getProperty(MYBATIS_MAPPER_LOCATION); - pluginDescriptor.setMapperXmlDir(mapperXmlDir); - - String staticDir = properties.getProperty(STATIC_LOCATIONS); - pluginDescriptor.setStaticDir(staticDir); - - String license = properties.getProperty(PLUGIN_LICENSE); - pluginDescriptor.setLicense(license); - - String dependencies = properties.getProperty(PLUGIN_DEPENDENCIES); - if(!StrUtil.isEmptyIfStr(dependencies)){ - List dependencyList = Arrays.stream(dependencies.trim().split(",")) - .map(dependency->new PluginDependency(dependency.trim())) - .collect(Collectors.toList()); - pluginDescriptor.setDependencies(dependencyList); - }else { - pluginDescriptor.setDependencies(Collections.emptyList()); - } - - String configFileName = properties.getProperty(CONFIG_FILE_NAME); - if(!StrUtil.isEmptyIfStr(configFileName)){ - pluginDescriptor.setConfigFileName(configFileName); - } - - List configFileActives = new ArrayList<>(); - for (String key : properties.stringPropertyNames()) { - if (key.startsWith(CONFIG_FILE_ACTIVE)) { - configFileActives.add(properties.getProperty(key)); - } - } - if(!configFileActives.isEmpty()){ - pluginDescriptor.setConfigFileActive(configFileActives); - }else{ - pluginDescriptor.setConfigFileActive(Collections.emptyList()); - } - - return pluginDescriptor; - } - -// public static DefaultPluginDescriptor storageToDescriptor(PluginDescriptorStorage pluginDescriptor){ -// return new DefaultPluginDescriptor(pluginDescriptor.getPluginId(), -// pluginDescriptor.getPluginDescription(), -// pluginDescriptor.getPluginClass(), -// pluginDescriptor.getVersion(), -// pluginDescriptor.getRequires(), -// pluginDescriptor.getProvider(), -// pluginDescriptor.getLicense()); -// } - - public static OpsPluginDescriptor storageToDescriptor(PluginDescriptorStorage pluginDescriptor){ - return new OpsPluginDescriptor(pluginDescriptor.getPluginId(), - pluginDescriptor.getPluginDescription(), - pluginDescriptor.getPluginClass(), - pluginDescriptor.getVersion(), - pluginDescriptor.getRequires(), - pluginDescriptor.getProvider(), - pluginDescriptor.getLicense(), - pluginDescriptor.getConfigFileName(), - pluginDescriptor.getConfigFileActive()); - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/PluginsUtils.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/PluginsUtils.java deleted file mode 100644 index 288bda7..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/PluginsUtils.java +++ /dev/null @@ -1,121 +0,0 @@ -package cd.casic.plugin.utils; - -import cd.casic.plugin.PluginCache; -import cd.casic.plugin.PluginDescriptorCache; -import cd.casic.plugin.PluginDescriptorStorage; -import cd.casic.plugin.PluginInfo; -import cn.hutool.core.util.StrUtil; -import cn.hutool.setting.dialect.Props; -import org.pf4j.PluginState; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -/** - * @Author:mianbin - * @Package:cd.casic.plugin.utils - * @Project:ops - * @name:PluginsUtils - * @Date:2024/03/18 10:19 - * @Filename:PluginsUtils - * @description:插件工具类 - */ -public class PluginsUtils { - /** - * param jarFile jarFile - * @description 加载插件配置文件 - * @author dolphin - */ - public static Props getSetting(String pluginId){ - // TODO 这个地方如果按照原来的写法,既要区分file是jar还是目录,又要区分是properties还是yaml,而且还要重复读取 - // TODO 目前暂时是弄了个PluginDescriptorCache,在两个DescriptorFinder中读取配置时就写Cache - // TODO 上面的做法有待完善 -// Enumeration entries = new JarFile(jarFile).entries(); -// while (entries.hasMoreElements()) { -// JarEntry jarEntry = entries.nextElement(); -// String entryName = jarEntry.getName(); -// if (entryName.equals("plugin.properties")) { -// URL url = new URL("jar:file:" + jarFile.getPath() + "!/" + entryName); -// JarURLConnection jarConnection = (JarURLConnection) url.openConnection(); -// InputStream in = jarConnection.getInputStream(); -// String read = IoUtil.read(in, CharsetUtil.UTF_8); -// in.close(); -// JarFile currJarFile = jarConnection.getJarFile(); -// currJarFile.close(); -// File file = new File("resources/temp"); -// File tempFile = new File(file.getAbsolutePath() + "/plugin.properties"); -// FileWriter writer = new FileWriter(tempFile); -// writer.write(read); -// return new Props(tempFile, CharsetUtil.CHARSET_UTF_8); -// }else if(entryName.equals("plugin.yaml")){ -// Path path = FileUtils.getPath(Paths.get(jarFile.getPath()), "plugin.yaml"); -// FileSystemResource resource = new FileSystemResource(path); -// PluginDescriptorStorage pluginDescriptorStorage = new PluginYamlProcessor(resource).loadYaml(); -// Props props = new Props(); -// props.put("mybatis.mapper.location", pluginDescriptorStorage.getMapperXmlDir()); -// props.put("static.locations", pluginDescriptorStorage.getStaticDir()); -// return props; -// -// } -// } - PluginDescriptorStorage descriptor = PluginDescriptorCache.getPlugin(pluginId); - if(descriptor == null){ -// throw new Exception("加载插件:读取配置文件失败"); - }else{ - Props props = new Props(); - if(!StrUtil.isEmptyIfStr(descriptor.getMapperXmlDir())){ - props.put("mybatis.mapper.location", descriptor.getMapperXmlDir()); - } - if(!StrUtil.isEmptyIfStr(descriptor.getStaticDir())){ - props.put("static.locations", descriptor.getStaticDir()); - } - - return props; - } - return null; - } - - /** - * @description 强制删除 - * @author dolphin - */ - public static void forceDelete(File file) { - if (!file.exists()) { - return; - } - boolean result = file.delete(); - if (result) { - return; - } - int tryCount = 0; - while (!result && tryCount++ < 5) { - System.gc(); - try { - Thread.sleep(150); - } catch (InterruptedException e) { - e.printStackTrace(); - } - result = file.delete(); - } - } - - public static List getAllPluginProxyClass(Class clazz) { - List result = new ArrayList<>(); - Map allPlugin = PluginCache.getAllPlugin(); - for (String key : allPlugin.keySet()) { - PluginInfo pluginInfo = allPlugin.get(key); - if (!pluginInfo.getPluginWrapper().getPluginState().equals(PluginState.STARTED)) { - continue; - } - T pluginBean = pluginInfo.getPluginApplicationContext().getBean(clazz); - if (pluginBean != null) { - result.add(pluginBean); - } - Optional.of(pluginBean).ifPresent(result::add); - } - return result; - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/ResourceUtils.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/ResourceUtils.java deleted file mode 100644 index 378ce41..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/ResourceUtils.java +++ /dev/null @@ -1,92 +0,0 @@ -package cd.casic.plugin.utils; - -import cd.casic.plugin.PluginInfo; -import org.pf4j.PluginWrapper; -import org.pf4j.RuntimeMode; -import org.pf4j.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * 对资源解析的工具类 - */ -public class ResourceUtils { - - private static final Logger LOGGER = LoggerFactory.getLogger(ResourceUtils.class); - - public final static String TYPE_FILE = "file"; - public final static String TYPE_CLASSPATH = "classpath"; - public final static String TYPE_PACKAGE = "package"; - - public static final String ROOT_PLUGIN_SIGN = "~"; - - public final static String TYPE_SPLIT = ":"; - - /** - * 获取匹配路绝 - * @param locationMatch 原始匹配路径。规则为: file:xxx, classpath:xxx , package:xxx - * @return 整合出完整的匹配路绝 - */ - public static String getMatchLocation(String locationMatch){ - if(StringUtils.isNullOrEmpty(locationMatch)){ - return null; - } - String classPathType = TYPE_CLASSPATH + TYPE_SPLIT; - if(isClasspath(locationMatch)){ - return locationMatch.replaceFirst(classPathType, ""); - } - String fileType = TYPE_FILE + TYPE_SPLIT; - if(isFile(locationMatch)){ - return locationMatch.replaceFirst(fileType, ""); - } - String packageType = TYPE_PACKAGE + TYPE_SPLIT; - if(isPackage(locationMatch)){ - String location = locationMatch.replaceFirst(packageType, ""); - return location.replace(".", "/"); - } - LOGGER.error("locationMatch {} illegal", locationMatch); - return null; - } - - public static boolean isClasspath(String locationMatch){ - return locationMatch.startsWith(TYPE_CLASSPATH + TYPE_SPLIT); - } - - public static boolean isFile(String locationMatch){ - return locationMatch.startsWith(TYPE_FILE + TYPE_SPLIT); - } - - public static boolean isPackage(String locationMatch){ - return locationMatch.startsWith(TYPE_PACKAGE + TYPE_SPLIT); - } - - /** - * 根据 ~ 标记获取, 得到绝对路径 - * @param pluginRegistryInfo pluginRegistryInfo - * @param rootDir 根目录 - * @return java.lang.String - **/ - public static String getAbsolutePath(PluginInfo pluginRegistryInfo, String rootDir){ - if(StringUtils.isNullOrEmpty(rootDir)){ - return rootDir; - } - String home = null; - if(rootDir.startsWith(ResourceUtils.ROOT_PLUGIN_SIGN)){ - String pluginRootDir; - PluginWrapper pluginWrapper = pluginRegistryInfo.getPluginWrapper(); - RuntimeMode runtimeMode = pluginWrapper.getRuntimeMode(); - if(runtimeMode == RuntimeMode.DEVELOPMENT){ - pluginRootDir = pluginWrapper.getPluginPath().toString(); - } else { - pluginRootDir = System.getProperty("user.dir"); - } - // 如果root路径中开始存在ROOT_PLUGIN_SIGN,则说明进行插件根路替换 - home = rootDir.replaceFirst("\\" + ResourceUtils.ROOT_PLUGIN_SIGN, ""); - home = CommonUtils.joiningFilePath(pluginRootDir, home); - } else { - home = rootDir; - } - return home; - } - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/SM4EncryptUtil.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/SM4EncryptUtil.java deleted file mode 100644 index 6081ea1..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/SM4EncryptUtil.java +++ /dev/null @@ -1,47 +0,0 @@ -package cd.casic.plugin.utils; - -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.crypto.SmUtil; -import cn.hutool.crypto.symmetric.SM4; -import lombok.extern.slf4j.Slf4j; - -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; - -@Slf4j -public class SM4EncryptUtil { - private static DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); -// @Value("${encryption-key}") - private static String key = "abcdabcdabcdabcd"; - - public static String encrypt(String str) { - SM4 sm4 = SmUtil.sm4(key.getBytes()); - String s = sm4.encryptHex(str.getBytes()); - return s; - } - public static String decrypt(String str) { - SM4 sm4 = SmUtil.sm4(key.getBytes()); - String s = sm4.decryptStr(str); - return s; - } - - public static void main(String[] args) { - - String encrypt = encrypt(LocalDateTime.now().plusMonths(1).format(dateTimeFormatter)); - System.out.println(encrypt); - System.out.println(decrypt(encrypt)); - } - public static boolean checkLicense(String license, String pluginId) { - // 逻辑是 不存在证书直接放行 存在证书需要判断证书是否过期 - if (ObjectUtil.isNotEmpty(license)) { - String decrypt = SM4EncryptUtil.decrypt(license); - LocalDateTime overDueTime = LocalDateTime.parse(decrypt, dateTimeFormatter); - LocalDateTime now = LocalDateTime.now(); - if (now.isAfter(overDueTime)) { - log.warn("plugin:[{}] license expired!", pluginId); - return false; - } - } - return true; - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/YamlUtils.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/YamlUtils.java deleted file mode 100644 index 624c2c8..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/YamlUtils.java +++ /dev/null @@ -1,35 +0,0 @@ -package cd.casic.plugin.utils; - -import org.pf4j.DevelopmentPluginClasspath; -import org.pf4j.PluginRuntimeException; -import org.pf4j.util.FileUtils; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; - -public class YamlUtils { - static final DevelopmentPluginClasspath PLUGIN_CLASSPATH = new DevelopmentPluginClasspath(); - - public static Path getYamlPath(Path pluginPath, String yamlFileName) { - if (Files.isDirectory(pluginPath)) { - for (String location : PLUGIN_CLASSPATH.getClassesDirectories()) { - Path path = pluginPath.resolve(location).resolve(yamlFileName); - Resource propertyResource = new FileSystemResource(path); - if (propertyResource.exists()) { - return path; - } - } - throw new PluginRuntimeException( - "Unable to find plugin yaml file: " + yamlFileName); - } else { - try { - return FileUtils.getPath(pluginPath, yamlFileName); - } catch (IOException e) { - throw new PluginRuntimeException(e); - } - } - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/dBUtils/AnnotationScanner.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/dBUtils/AnnotationScanner.java deleted file mode 100644 index 7e00308..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/dBUtils/AnnotationScanner.java +++ /dev/null @@ -1,77 +0,0 @@ -package cd.casic.plugin.utils.dBUtils; - -import java.io.File; -import java.io.IOException; -import java.lang.annotation.Annotation; -import java.net.JarURLConnection; -import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -public class AnnotationScanner { - - public static List> scanPackageForAnnotatedClasses(String packageName, Class annotationClass,ClassLoader classLoader) throws IOException, ClassNotFoundException { - List> annotatedClasses = new ArrayList<>(); - - // 获取包所在的URL - Enumeration urls = classLoader.getResources(packageName.replace('.', '/')); -// - while (urls.hasMoreElements()) { - URL url = urls.nextElement(); - String protocol = url.getProtocol(); - - if ("file".equals(protocol)) { - // 处理文件系统中的包 - File packageDir = new File(url.getFile()); - scanDirectoryForAnnotatedClasses(packageDir, packageName, annotationClass, annotatedClasses); - } else if ("jar".equals(protocol)) { - // 处理JAR文件中的包 - JarFile jarFile = ((JarURLConnection) url.openConnection()).getJarFile(); - scanJarFileForAnnotatedClasses(jarFile, packageName, annotationClass, annotatedClasses, classLoader); - } - } - - return annotatedClasses; - } - - private static void scanDirectoryForAnnotatedClasses(File directory, String packageName, Class annotationClass, List> annotatedClasses) throws ClassNotFoundException { - File[] files = directory.listFiles(); - if (files != null) { - for (File file : files) { - if (file.isDirectory()) { - scanDirectoryForAnnotatedClasses(file, packageName + "." + file.getName(), annotationClass, annotatedClasses); - } else if (file.isFile() && file.getName().endsWith(".class")) { - String className = packageName + '.' + file.getName().substring(0, file.getName().length() - 6); - Class clazz = Class.forName(className); - if (clazz.isAnnotationPresent(annotationClass)) { - annotatedClasses.add(clazz); - } - } - } - } - } - - private static void scanJarFileForAnnotatedClasses(JarFile jarFile, String packageName, Class annotationClass, List> annotatedClasses,ClassLoader classLoader) { - Enumeration entries = jarFile.entries(); - while (entries.hasMoreElements()) { - JarEntry entry = entries.nextElement(); - String entryName = entry.getName(); - if (entryName.endsWith(".class") && entryName.startsWith(packageName.replace('.', '/')) && !entryName.contains("$")) { // 忽略内部类 - String className = entryName.substring(0, entryName.length() - 6).replace('/', '.'); - try { -// Class clazz = Class.forName(className); - Class clazz = classLoader.loadClass(className); - if (clazz.isAnnotationPresent(annotationClass)) { - annotatedClasses.add(clazz); - } - } catch (Exception e) { - // ignore - System.err.println("Class not found: " + className);; - } - } - } - } -} \ No newline at end of file diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/dBUtils/DBEnums.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/dBUtils/DBEnums.java deleted file mode 100644 index 202d67d..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/dBUtils/DBEnums.java +++ /dev/null @@ -1,26 +0,0 @@ -package cd.casic.plugin.utils.dBUtils; - -import lombok.Getter; - -@Getter -public enum DBEnums { - MYSQL("mysql"), - SQLITE("sqlite"); - - final String DBType; - - DBEnums(String DBType) { - this.DBType = DBType; - } - - public static DBEnums getEnumByString(String type){ - switch (type){ - case "mysql": - return MYSQL; - case "sqlite": - return SQLITE; - default: - return null; - } - } -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/dBUtils/SQLGenerator.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/dBUtils/SQLGenerator.java deleted file mode 100644 index 7f57505..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/dBUtils/SQLGenerator.java +++ /dev/null @@ -1,222 +0,0 @@ -package cd.casic.plugin.utils.dBUtils; - -import cd.casic.plugin.register.database.DataBaseProperty; -import cd.casic.plugin.utils.dBUtils.annotation.Entity; -import cd.casic.plugin.utils.dBUtils.annotation.SQL; -import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; -import com.mysql.cj.jdbc.MysqlDataSource; -import jakarta.annotation.Resource; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.ObjectUtils; -import org.springframework.boot.jdbc.DataSourceBuilder; -import org.springframework.stereotype.Component; -import org.sqlite.SQLiteDataSource; - -import javax.sql.DataSource; -import java.io.IOException; -import java.lang.reflect.Field; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.sql.Connection; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Objects; - -@Data -@Slf4j -@Component -public class SQLGenerator { - @Resource - private DynamicRoutingDataSource dynamicRoutingDataSource; - - private String mapToSqlType(Class fieldType) { - // 简化的类型映射,针对MySQL数据库 - if (fieldType == int.class || fieldType == Integer.class) { - return "INTEGER"; - } else if (fieldType == long.class || fieldType == Long.class) { - return "BIGINT"; - } else if (fieldType == float.class || fieldType == Float.class) { - return "FLOAT"; - } else if (fieldType == double.class || fieldType == Double.class) { - return "DOUBLE"; - } else if (fieldType == boolean.class || fieldType == Boolean.class) { - return "BOOLEAN"; // 或者 "TINYINT(1)" - } else if (fieldType == String.class) { - return "VARCHAR(255)"; - } else if (fieldType == java.util.Date.class || fieldType == java.sql.Date.class) { - return "DATETIME"; // 或者 "TIMESTAMP" - } else if (fieldType == java.sql.Timestamp.class) { - return "TIMESTAMP"; - } else if (fieldType == byte[].class) { - return "BLOB"; - } else if (fieldType.isEnum()) { - return "ENUM"; // 需要进一步处理,如列出所有枚举值 - } else if (fieldType.isArray() || Collection.class.isAssignableFrom(fieldType)) { - throw new IllegalArgumentException("Arrays and Collections are not directly supported. Consider using a join table or serialization."); - } else { - throw new IllegalArgumentException("Unsupported field type: " + fieldType.getName()); - } - } - - public void sqlDeleteGenerator(Class c, DataBaseProperty dataBaseProperty, String pluginId) { - StringBuilder sql = new StringBuilder("\n"); - String tableName = "plugin_" + (c.toString().substring(c.toString().lastIndexOf(".") + 1)).toLowerCase(); - - sql.append("drop table if exists ").append(tableName); - String dbPath = "ops-module-plugins/plugins/" + pluginId + "/datasource/database.db"; - - this.executeSql(sql.toString(), dataBaseProperty, pluginId); - log.info(sql.toString()); - } - - public void sqlGenerator(Class c, DataBaseProperty dataBaseProperty, String pluginId) { - - String dbPath = "ops-module-plugins/plugins/" + pluginId + "/datasource/database.db"; - -// log.info(pluginRoot); - Entity entityAnnotation = c.getAnnotation(Entity.class); - if (ObjectUtils.isEmpty(entityAnnotation)) { - return; - } - - StringBuilder sql = new StringBuilder("\n"); - String tableName = "plugin_" + (c.toString().substring(c.toString().lastIndexOf(".") + 1)).toLowerCase(); - - sql.append("create table ").append(tableName).append("(").append("\n"); - int count = c.getDeclaredFields().length; - int index = 0; - boolean pkFlag = false; - for (Field field : c.getDeclaredFields()) { - SQL annotation = field.getAnnotation(SQL.class); - index += 1; - sql.append(field.getName()).append(" ").append(mapToSqlType(field.getType())).append(" "); - if (ObjectUtils.isNotEmpty(annotation) && ObjectUtils.isNotEmpty(annotation.defaultValue())) { - sql.append(" default " + "'").append(annotation.defaultValue()).append("'"); - } - if (ObjectUtils.isNotEmpty(annotation) && annotation.notNull()) { - sql.append(" not null "); - } - if (ObjectUtils.isNotEmpty(annotation) && annotation.pK()) { - // TODO 这是如果dataBaseProperty是null(即使用主程序的数据源时),数据库类型先写死。 - DBEnums type = dataBaseProperty == null ? DBEnums.MYSQL : dataBaseProperty.type(); - if (pkFlag) { - log.error("Duplicate Primary Key"); - throw new RuntimeException("Duplicate Primary Key"); - } - this.genPrimaryKey(sql, type, tableName); - pkFlag = true; - if (annotation.autoIncrement()) { - this.genAutoIncrement(sql, type); - } - } - if (index != count) { - sql.append("," + "\n"); - } else { - sql.append("\n"); - } - } - sql.append(")"); - log.info(sql.toString()); - this.executeSql(sql.toString(), dataBaseProperty, pluginId); - } - - public void destroyDataSource(DataBaseProperty dataBaseProperty, String pluginId){ - if(dataBaseProperty == null) return; - String dataSourceId = pluginId + "-" + dataBaseProperty.type().getDBType(); - if(dynamicRoutingDataSource.getDataSources().containsKey(dataSourceId)){ - dynamicRoutingDataSource.removeDataSource(dataSourceId); - } - } - - private void executeSql(String sql, DataBaseProperty dataBaseProperty, String pluginId){ - try{ - Connection connection; - if(Objects.isNull(dataBaseProperty)){ - connection = dynamicRoutingDataSource.getConnection(); - }else{ - String dataSourceId = pluginId + "-" + dataBaseProperty.type().getDBType(); - if(!dynamicRoutingDataSource.getDataSources().containsKey(dataSourceId)){ - DataSource dataSource; - if(dataBaseProperty.type().equals(DBEnums.SQLITE)){ - dataSource = DataSourceBuilder.create().type(SQLiteDataSource.class) - .driverClassName(dataBaseProperty.driver()) - .url(dataBaseProperty.url()).build(); - }else { - dataSource = DataSourceBuilder.create() - .type(MysqlDataSource.class) - .driverClassName(dataBaseProperty.driver()) - .username(dataBaseProperty.username()).password(dataBaseProperty.password()) - .url(dataBaseProperty.url()).build(); - } - dynamicRoutingDataSource.addDataSource(dataSourceId, dataSource); - } - connection = dynamicRoutingDataSource.getDataSource(dataSourceId).getConnection(); - } - connection.createStatement().execute(sql); - }catch(Exception e){ - log.error(e.getMessage()); - } - } - - private void genPrimaryKey(StringBuilder sql, DBEnums dbEnums, String tableName) { - switch (dbEnums) { - case MYSQL: - sql.append("primary key "); - break; - case SQLITE: - sql.append("constraint ").append(tableName).append("_pk primary key "); - break; - default: - log.error("Unsupported Database"); - throw new RuntimeException("Unsupported Database"); - } - } - - private void genAutoIncrement(StringBuilder sql, DBEnums dbEnums) { - switch (dbEnums) { - case MYSQL: - sql.append(" AUTO_INCREMENT"); - break; - case SQLITE: - sql.append(" AUTOINCREMENT"); - break; - default: - log.error("Unsupported Database"); - throw new RuntimeException("Unsupported Database"); - } - } - - private String getSQLiteDBLocation(String pluginRoot, ClassLoader classLoader, String pluginId) { - List pluginFolders = new ArrayList<>(); - try { - Path rootPath = Paths.get(pluginRoot); - if (!Files.isDirectory(rootPath)) { - System.out.println("提供的路径不是一个有效的目录:" + pluginRoot); - } - this.findPluginFoldersRecursively(rootPath, pluginFolders); - } catch (IOException e) { - throw new RuntimeException(e); - } - return "s"; - } - - private void findPluginFoldersRecursively(Path folder,List pluginFolders) throws IOException - { - try (DirectoryStream stream = Files.newDirectoryStream(folder)) { - for (Path entry : stream) { - if (Files.isDirectory(entry)) { - String folderName = entry.getFileName().toString(); - if (folderName.contains("datasource")) { - pluginFolders.add(entry.toString()); - } - findPluginFoldersRecursively(entry, pluginFolders); // 递归查找子目录 - } - } - } - } -} - diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/dBUtils/annotation/Entity.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/dBUtils/annotation/Entity.java deleted file mode 100644 index d2e0e95..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/dBUtils/annotation/Entity.java +++ /dev/null @@ -1,10 +0,0 @@ -package cd.casic.plugin.utils.dBUtils.annotation; - -import java.lang.annotation.*; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface Entity { - -} diff --git a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/dBUtils/annotation/SQL.java b/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/dBUtils/annotation/SQL.java deleted file mode 100644 index bd4c0c5..0000000 --- a/framework/spring-boot-starter-plugin/src/main/java/cd/casic/plugin/utils/dBUtils/annotation/SQL.java +++ /dev/null @@ -1,14 +0,0 @@ -package cd.casic.plugin.utils.dBUtils.annotation; - -import java.lang.annotation.*; - -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface SQL { - boolean pK() default false; - boolean notNull() default false; - String defaultValue() default ""; - boolean autoIncrement() default false; -} -