com.github.linyuzai.plugin.autoconfigure.management.PluginManagementController Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of concept-plugin-spring-boot-starter Show documentation
Show all versions of concept-plugin-spring-boot-starter Show documentation
Dynamic loading classes with external jar simply and gracefully
The newest version!
package com.github.linyuzai.plugin.autoconfigure.management;
import com.github.linyuzai.plugin.autoconfigure.preperties.PluginConceptProperties;
import com.github.linyuzai.plugin.core.autoload.*;
import com.github.linyuzai.plugin.core.autoload.location.LocalPluginLocation;
import com.github.linyuzai.plugin.core.autoload.location.PluginLocation;
import com.github.linyuzai.plugin.core.concept.Plugin;
import com.github.linyuzai.plugin.core.concept.PluginConcept;
import com.github.linyuzai.plugin.core.event.PluginEventListener;
import com.github.linyuzai.plugin.core.executer.PluginExecutor;
import com.github.linyuzai.plugin.core.metadata.PluginMetadata;
import lombok.Data;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class PluginManagementController {
protected final Log log = LogFactory.getLog("PluginManagement");
protected final Set loadingSet = Collections.newSetFromMap(new ConcurrentHashMap<>());
protected final Set unloadingSet = Collections.newSetFromMap(new ConcurrentHashMap<>());
protected final Set updatingSet = Collections.newSetFromMap(new ConcurrentHashMap<>());
@Autowired
protected PluginConceptProperties properties;
@Autowired
protected PluginConcept concept;
@Autowired
protected PluginLocation location;
@Autowired
protected PluginAutoLoader loader;
@Autowired
protected PluginExecutor executor;
@Autowired
protected PluginManagementAuthorizer authorizer;
@Autowired
protected PluginPropertiesProvider propertiesProvider;
protected final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@GetMapping("/setting")
public Response setting() {
return manage(() -> new Setting(
properties.getManagement().getGithubCorner(),
properties.getManagement().getHeader(),
properties.getManagement().getFooter()), () -> "获取配置");
}
@PostMapping("/auth/unlock")
public Response unlock(@RequestParam("password") String password) {
return manage(() -> authorizer.unlock(password), () -> null);
}
@PostMapping("/group/add")
public Response addGroup(@RequestParam("group") String group) {
return manage(() -> {
loader.addGroup(group);
return null;
}, () -> "插件分组添加");
}
@GetMapping("/group/list")
public Response listGroup() {
return manage(() -> {
String[] groups = location.getGroups();
return Arrays.stream(groups)
.map(this::group)
.collect(Collectors.toList());
}, () -> "插件分组获取");
}
@PostMapping("/plugin/load")
public Response loadPlugin(@RequestParam("group") String group,
@RequestParam("name") String name) {
return manage(() -> {
String path = location.getLoadedPluginPath(group, name);
loadingSet.add(path);
try {
location.load(group, name);
} catch (Throwable e) {
executor.execute(() -> {
try {
concept.load(path);
} catch (Throwable e1) {
log.error("Load plugin error: " + path, e1);
} finally {
loadingSet.remove(path);
}
}, 1000, TimeUnit.MILLISECONDS);
}
return null;
}, () -> "插件加载");
}
@PostMapping("/plugin/unload")
public Response unloadPlugin(@RequestParam("group") String group,
@RequestParam("name") String name) {
return manage(() -> {
String path = location.getLoadedPluginPath(group, name);
unloadingSet.add(path);
try {
location.unload(group, name);
} catch (Throwable e) {
executor.execute(() -> {
try {
concept.unload(path);
} catch (Throwable e1) {
log.error("Unload plugin error: " + path, e1);
} finally {
unloadingSet.remove(path);
}
}, 1000, TimeUnit.MILLISECONDS);
}
return null;
}, () -> "插件卸载");
}
@PostMapping("/plugin/reload")
public Response reloadPlugin(@RequestParam("group") String group,
@RequestParam("name") String name) {
return manage(() -> {
String path = location.getLoadedPluginPath(group, name);
loadingSet.add(path);
try {
concept.unload(path);
} catch (Throwable e) {
loadingSet.remove(path);
throw e;
}
executor.execute(() -> {
try {
concept.load(path);
} catch (Throwable e) {
log.error("Reload plugin error: " + path, e);
} finally {
loadingSet.remove(path);
}
}, 1000, TimeUnit.MILLISECONDS);
return null;
}, () -> "插件重新加载");
}
@GetMapping("/plugin/exist")
public Response existPlugin(@RequestParam("group") String group,
@RequestParam("name") String name) {
return manage(() -> location.exist(group, name), () -> "插件包重名判断");
}
@PostMapping("/plugin/rename")
public Response renamePlugin(@RequestParam("group") String group,
@RequestParam("name") String name,
@RequestParam("rename") String rename) {
return manage(() -> {
location.rename(group, name, rename);
return null;
}, () -> "插件包重命名");
}
@PostMapping("/plugin/delete")
public Response deletePlugin(@RequestParam("group") String group,
@RequestParam("name") String name) {
return manage(() -> {
location.delete(group, name);
return null;
}, () -> "插件删除");
}
@GetMapping("/plugin/properties")
public Response getProperties(@RequestParam("group") String group,
@RequestParam("name") String name) {
return manage(() -> propertiesProvider.getProperties(group, name), () -> "查询配置");
}
@GetMapping("/plugin/list")
public Response listPlugin(@RequestParam("group") String group,
@RequestParam("deleted") Boolean deleted) {
return manage(() -> {
List list = new ArrayList<>();
if (deleted == Boolean.TRUE) {
String[] plugins = location.getDeletedPlugins(group);
for (String plugin : plugins) {
list.add(deletedPlugin(group, plugin));
}
} else {
String[] loaded = location.getLoadedPlugins(group);
for (String load : loaded) {
list.add(loadedPlugin(group, load));
}
String[] unloaded = location.getUnloadedPlugins(group);
for (String unload : unloaded) {
list.add(unloadedPlugin(group, unload));
}
}
list.sort((o1, o2) -> Long.compare(o2.sort, o1.sort));
return list;
}, () -> "插件列表获取");
}
public void autoload(String group, String name, File file) {
if (name == null || name.trim().isEmpty()) {
return;
}
String newPath = location.getLoadedPluginPath(group, file.getName());
loadingSet.add(newPath);
String oldPath = location.getLoadedPluginPath(group, name);
updatingSet.add(oldPath);
PluginEventListener listener = new PluginEventListener() {
@Override
public void onEvent(Object event) {
if (event instanceof PluginAutoEvent) {
String path = ((PluginAutoEvent) event).getPath();
if (Objects.equals(newPath, path)) {
updatingSet.remove(oldPath);
if (event instanceof PluginAutoLoadEvent) {
location.delete(group, name);
concept.getEventPublisher().unregister(this);
}
}
}
}
};
concept.getEventPublisher().register(listener);
try {
location.load(group, file.getName());
} catch (Throwable e) {
log.error("Load plugin error: " + newPath, e);
loadingSet.remove(newPath);
updatingSet.remove(oldPath);
concept.getEventPublisher().unregister(listener);
}
}
public InputStream downloadPlugin(String group, String name, Boolean deleted, HttpHeaders headers) throws IOException {
headers.set(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(name, "UTF-8"));
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
if (deleted == Boolean.TRUE) {
return location.getDeletedPluginInputStream(group, name);
} else {
try {
return location.getLoadedPluginInputStream(group, name);
} catch (Throwable e) {
return location.getUnloadedPluginInputStream(group, name);
}
}
}
public Response manage(Supplier
© 2015 - 2024 Weber Informatics LLC | Privacy Policy