diff --git a/designer-base/src/main/java/com/fr/design/PluginClassRefreshManager.java b/designer-base/src/main/java/com/fr/design/PluginClassRefreshManager.java new file mode 100644 index 000000000..711dd2975 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/PluginClassRefreshManager.java @@ -0,0 +1,78 @@ +package com.fr.design; + +import com.fr.design.constants.DesignerLaunchStatus; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.fun.HyperlinkProvider; +import com.fr.design.fun.TableDataDefineProvider; +import com.fr.plugin.observer.PluginEvent; +import com.fr.plugin.observer.PluginEventListener; +import com.fr.plugin.observer.PluginEventType; +import com.fr.plugin.observer.PluginListenerRegistration; +import java.util.HashSet; +import java.util.Set; + +/** + * + * @author hades + * @version 10.0 + * Created by hades on 2020/12/17 + */ +public class PluginClassRefreshManager { + + + private static final PluginClassRefreshManager INSTANCE = new PluginClassRefreshManager(); + + private final Set context = new HashSet<>(); + + private final PluginEventListener pluginAfterRunEventListener = new PluginEventListener() { + @Override + public void on(PluginEvent event) { + // 兼容之前版本特性 + for (String tag : context) { + if (event.getContext().contain(tag)) { + HistoryTemplateListCache.getInstance().reloadAllEditingTemplate(); + return; + } + } + // 重新载入模板xml内容 到 Workbook/Form对象中 + HistoryTemplateListCache.getInstance().reloadAllEditingTemplateByPlugin(event.getContext()); + } + }; + + + public static PluginClassRefreshManager getInstance() { + return INSTANCE; + } + + public void load() { + context.add(TableDataDefineProvider.XML_TAG); + context.add(HyperlinkProvider.XML_TAG); + } + + private PluginClassRefreshManager() { + PluginListenerRegistration.getInstance().listen(PluginEventType.BeforeAllActive, new PluginEventListener() { + @Override + public void on(PluginEvent event) { + removePluginListener(); + } + }); + PluginListenerRegistration.getInstance().listen(PluginEventType.AfterAllActive, new PluginEventListener() { + @Override + public void on(PluginEvent event) { + addPluginListener(); + if (DesignerLaunchStatus.getStatus() != DesignerLaunchStatus.WORKSPACE_INIT_COMPLETE) { + HistoryTemplateListCache.getInstance().reloadAllEditingTemplate(); + } + } + }); + } + + public void removePluginListener() { + PluginListenerRegistration.getInstance().stopListen(this.pluginAfterRunEventListener); + } + + public void addPluginListener() { + PluginListenerRegistration.getInstance().listen(PluginEventType.AfterRun, this.pluginAfterRunEventListener); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java index a2cc5b7d2..ca587c3da 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java @@ -18,8 +18,6 @@ import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.BasicPane; import com.fr.design.dialog.DialogActionAdapter; import com.fr.design.dialog.FineJOptionPane; -import com.fr.design.file.HistoryTemplateListCache; -import com.fr.design.fun.TableDataDefineProvider; import com.fr.design.fun.TableDataPaneProcessor; import com.fr.design.gui.ibutton.UIHeadGroup; import com.fr.design.gui.icontainer.UIScrollPane; @@ -28,7 +26,6 @@ import com.fr.design.gui.itoolbar.UIToolbar; import com.fr.design.icon.IconPathConstants; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; -import com.fr.design.mainframe.JTemplate; import com.fr.design.menu.MenuDef; import com.fr.design.menu.SeparatorDef; import com.fr.design.menu.ToolBarDef; @@ -97,7 +94,6 @@ public class TableDataTreePane extends BasicTableDataTreePane { addMenuDef.setIconPath(IconPathConstants.ADD_POPMENU_ICON_PATH); createAddMenuDef(); - // 创建插件监听 createPluginListener(); @@ -160,34 +156,6 @@ public class TableDataTreePane extends BasicTableDataTreePane { return context.contain(PluginModule.ExtraDesign); } }); - - //监听数据集插件 - GeneralContext.listenPluginRunningChanged(new PluginEventListener() { - @Override - public void on(PluginEvent event) { - //REPORT-25577 - //如果数据集插件禁用或启用。需要清空当前模板中的缓存 - reloadCurrTemplate(); - } - - private void reloadCurrTemplate() { - JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - if (accept(jt)) { - jt.refreshResource(); - } - } - - private boolean accept(JTemplate jt) { - - return jt != null && jt.getEditingFILE() != null && jt.getEditingFILE().exists(); - } - }, new PluginFilter() { - @Override - public boolean accept(PluginContext pluginContext) { - - return pluginContext.contain(TableDataDefineProvider.XML_TAG); - } - }); } diff --git a/designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java b/designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java index 7b13c94a0..06bfd3cf7 100644 --- a/designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java +++ b/designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java @@ -17,7 +17,10 @@ import com.fr.file.FILE; import com.fr.file.FileNodeFILE; import com.fr.file.StashedFILE; import com.fr.general.ComparatorUtils; +import com.fr.invoke.ClassHelper; import com.fr.log.FineLoggerFactory; +import com.fr.plugin.context.PluginContext; +import com.fr.plugin.manage.PluginManager; import com.fr.stable.CoreConstants; import com.fr.stable.StringUtils; import com.fr.third.org.apache.commons.io.FilenameUtils; @@ -29,6 +32,7 @@ import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.Set; /** * 历史模板缓存 @@ -370,7 +374,6 @@ public class HistoryTemplateListCache implements CallbackEvent { */ public void load() { FineLoggerFactory.getLogger().info("Env Change Template Loading..."); - JTemplate currentTemplate = null; if (stashFILEMap != null && stashFILEMap.size() != 0) { int size = historyList.size(); for (int i = 0; i < size; i++) { @@ -381,32 +384,14 @@ public class HistoryTemplateListCache implements CallbackEvent { if (stashedFile == null) { continue; } - JTemplate template = JTemplateFactory.createJTemplate(stashedFile); - if (template != null) { - historyList.set(i, template); - // 替换当前正在编辑的模板,使用添加并激活的方式,以便使用统一的入口来处理监听事件 - if (isCurrentEditingFile(template.getPath())) { - currentTemplate = template; - } - } else { - // 当模板为空时 说明是一个新建的未保存模板 但是内存中保存了该模板 可以从中获取 - JTemplate jt = historyList.get(i); - // 另外如果该模板是正在编辑的模板,需要要激活 - if (jt != null && isCurrentEditingFile(jt.getPath())) { - currentTemplate = jt; - } - } + FineLoggerFactory.getLogger().info("{} is being reloaded", stashedFile.getName()); + JTemplate template = historyList.get(i); + template.refreshResource(stashedFile); } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } } - // 最后加载当前正在编辑的模板 以保证数据集刷新正常 - if (currentTemplate != null) { - loadCurrentTemplate(currentTemplate); - } stashFILEMap.clear(); - MutilTempalteTabPane.getInstance().refreshOpenedTemplate(historyList); - MutilTempalteTabPane.getInstance().repaint(); } FineLoggerFactory.getLogger().info("Env Change Template Loaded."); } @@ -420,12 +405,9 @@ public class HistoryTemplateListCache implements CallbackEvent { /** * 重新载入当前模板,刷新数据/对象 */ + @Deprecated public void reloadCurrentTemplate() { - JTemplate jt = getCurrentEditingTemplate(); - boolean access = jt != null && jt.getEditingFILE() != null && jt.getEditingFILE().exists(); - if (access) { - jt.refreshResource(); - } + reloadAllEditingTemplate(); } /** @@ -440,4 +422,72 @@ public class HistoryTemplateListCache implements CallbackEvent { }); } + /** + * 插件安装后/启用 重新加载模板资源 + */ + private void _reloadAllEditingTemplate(PluginContext context) { + FineLoggerFactory.getLogger().info("Plugin env change reload all template started"); + long start = System.currentTimeMillis(); + int size = historyList.size(); + for (int i = 0; i < size; i++) { + JTemplate template = historyList.get(i); + FILE file = template.getEditingFILE(); + boolean needReload = context == null || needReloadTemplate(context, template); + if (needReload) { + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + BaseBook target = template.getTarget(); + if (target != null) { + FineLoggerFactory.getLogger().info("{} is being reloaded", file.getName()); + target.export(outputStream); + FILE stashedFile = new StashedFILE(file, outputStream.toByteArray()); + template.refreshResource(stashedFile); + } + // 如果 target == null 那么这个模板是被模板内存优化功能处理过的,不用处理 + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + } + FineLoggerFactory.getLogger().info("Plugin env change reload all template ended"); + FineLoggerFactory.getLogger().info("Reload all template spend: {} ms", (System.currentTimeMillis() - start)); + } + + /** + * 根据具体插件来刷新模板 + * @param context + */ + public void reloadAllEditingTemplateByPlugin(PluginContext context) { + _reloadAllEditingTemplate(context); + } + + /** + * 直接刷新所以模板 + */ + public void reloadAllEditingTemplate() { + _reloadAllEditingTemplate(null); + } + + private boolean needReloadTemplate(PluginContext context, JTemplate template) { + BaseBook baseBook = template.getTarget(); + if (baseBook != null) { + String name = template.getEditingFILE().getName(); + String pluginId = context.getID(); + long start = System.currentTimeMillis(); + Set set = ClassHelper.getClassLoaders(baseBook); + FineLoggerFactory.getLogger().info("{} find plugin classloader spend: {} ms", name, (System.currentTimeMillis() - start)); + if (set != null) { + for (ClassLoader classLoader : set) { + if (ComparatorUtils.equals(pluginId, PluginManager.detectLeakingPlugin(classLoader))) { + return true; + } + } + } else { + // set为null说明 检测classloader 这里返回true直接刷新 兜底行为 + return true; + } + } + return false; + } + } diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/HyperlinkGroupPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/HyperlinkGroupPane.java index 8405ce09e..0a8e4769a 100644 --- a/designer-base/src/main/java/com/fr/design/gui/frpane/HyperlinkGroupPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/HyperlinkGroupPane.java @@ -46,7 +46,6 @@ public abstract class HyperlinkGroupPane extends UIListControlPane { @Override public void on(PluginEvent event) { refreshNameableCreator(createNameableCreators()); - HistoryTemplateListCache.getInstance().reloadCurrentTemplate(); } }, new PluginFilter() { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java index 5cfd7a13d..f540cdbc6 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java @@ -47,6 +47,7 @@ import com.fr.design.menu.MenuDef; import com.fr.design.menu.NameSeparator; import com.fr.design.menu.ShortCut; import com.fr.design.preview.PagePreview; +import com.fr.design.ui.util.UIUtil; import com.fr.design.write.submit.DBManipulationInWidgetEventPane; import com.fr.design.write.submit.DBManipulationPane; import com.fr.event.EventDispatcher; @@ -332,10 +333,15 @@ public abstract class JTemplate> * CenterPane 负责监听改动。 * 所以需要同步处理 */ + @Deprecated public void refreshResource() { + refreshResource(this.editingFILE); + } + + public void refreshResource(FILE file) { try { - this.template = JTemplateFactory.asIOFile(this.editingFILE); + this.template = JTemplateFactory.asIOFile(file); setTarget(this.template); // 先移除旧的。 diff --git a/designer-base/src/test/java/com/fr/base/ClassHelperTest.java b/designer-base/src/test/java/com/fr/base/ClassHelperTest.java new file mode 100644 index 000000000..c77bb7b67 --- /dev/null +++ b/designer-base/src/test/java/com/fr/base/ClassHelperTest.java @@ -0,0 +1,29 @@ +package com.fr.base; + +import com.fr.form.main.Form; +import com.fr.invoke.ClassHelper; +import com.fr.main.impl.WorkBook; +import java.util.Set; +import junit.framework.TestCase; +import org.junit.Assert; + + +/** + * @author hades + * @version 10.0 + * Created by hades on 2020/12/28 + */ +public class ClassHelperTest extends TestCase { + + + public void testGetClassLoaders() { + WorkBook workBook = new WorkBook(); + Set set = ClassHelper.getClassLoaders(workBook); + Assert.assertFalse(set.isEmpty()); + Form form = new Form(); + Set set1 = ClassHelper.getClassLoaders(form); + Assert.assertFalse(set1.isEmpty()); + + } + +} \ No newline at end of file diff --git a/designer-realize/src/main/java/com/fr/start/module/DesignerInitActivator.java b/designer-realize/src/main/java/com/fr/start/module/DesignerInitActivator.java index 1eeb5a6a3..ebea410bb 100644 --- a/designer-realize/src/main/java/com/fr/start/module/DesignerInitActivator.java +++ b/designer-realize/src/main/java/com/fr/start/module/DesignerInitActivator.java @@ -1,5 +1,6 @@ package com.fr.start.module; +import com.fr.design.PluginClassRefreshManager; import com.fr.module.Activator; import com.fr.start.DesignerInitial; @@ -15,6 +16,7 @@ public class DesignerInitActivator extends Activator { @Override public void start() { + PluginClassRefreshManager.getInstance().load(); DesignerInitial.init(findSingleton(StartupArgs.class).get()); } diff --git a/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceActivator.java b/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceActivator.java index f5231eafe..1842ea762 100644 --- a/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceActivator.java +++ b/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceActivator.java @@ -1,6 +1,7 @@ package com.fr.start.module; import com.fr.concurrent.NamedThreadFactory; +import com.fr.design.PluginRefreshManager; import com.fr.design.file.HistoryTemplateListCache; import com.fr.event.Event; import com.fr.event.Listener; @@ -50,7 +51,7 @@ public class DesignerWorkspaceActivator extends Activator { @Override public void on(Event event, Workspace workspace) { - + PluginRefreshManager.getInstance().removePluginListener(); HistoryTemplateListCache.getInstance().stash(); } }); @@ -62,6 +63,7 @@ public class DesignerWorkspaceActivator extends Activator { public void on(Event event, Workspace workspace) { HistoryTemplateListCache.getInstance().load(); + PluginRefreshManager.getInstance().addPluginListener(); } }); }