* commit '4438f218032680c87104e3312869d7af14b9cf1a': (74 commits) REPORT-141155 FR12埋点-远程设计切换埋点appid字段没有记录 REPORT-145453 【fr-fbp】ssh和ssl的数据连接,去获取密钥等文件时,路径深的时候选择后路径有问题 REPORT-144999 fix: 适配新的日志接口 & 删除多余逻辑 fix: REPORT-145393 数据中心,日期弹窗主题色是绿色的 REPORT-145295 fix:修复模板树移动显示空白 REPORT-145301 fix:优化web属性几个面板中涉及到的滚动效果 Revert "REPORT-145379 远程设计调试工具适配gzip" REPORT-145379 远程设计调试工具适配gzip REPORT-145372 修复设计器双击模板tab栏后台NPE的问题 Revert "REPORT-145338 修复远程切换大量exist操作的问题" fix: REPORT-145330 公式显示为英文了 REPORT-145338 修复远程切换大量exist操作的问题 修改文件注释 换个换行符 增加单元格组图标 fix: REPORT-145192 权限申请审批、数据中心-数据目录两个页面存在国际化问题 无jira 代码质量 REPORT-144981 fix:预览按钮禁用状态调整 REPORT-145133 fix:重名校验交互变更 REPORT-145122 feat:树组件选中状态问题修复 ...fbp/master
@ -0,0 +1,68 @@ |
|||||||
|
package com.fr.design.carton; |
||||||
|
|
||||||
|
/** |
||||||
|
* SwingEvent事件包装类 |
||||||
|
* |
||||||
|
* @author Levy.Xie |
||||||
|
* @since 11.0 |
||||||
|
* Created on 2024/11/05 |
||||||
|
*/ |
||||||
|
public class DispatchInfo { |
||||||
|
|
||||||
|
/** |
||||||
|
* 当前线程 |
||||||
|
*/ |
||||||
|
private final Thread eventDispatchThread = Thread.currentThread(); |
||||||
|
/** |
||||||
|
* 上次触发时间 |
||||||
|
*/ |
||||||
|
private long lastDispatchTimeMillis = System.currentTimeMillis(); |
||||||
|
/** |
||||||
|
* 开始时间 |
||||||
|
*/ |
||||||
|
private final long startDispatchTimeMillis = System.currentTimeMillis(); |
||||||
|
/** |
||||||
|
* 事件唯一编号 |
||||||
|
*/ |
||||||
|
private final long eventSeq; |
||||||
|
|
||||||
|
public DispatchInfo() { |
||||||
|
eventSeq = EventDispatchThreadHangMonitor.incrementAndGetSeq(); |
||||||
|
} |
||||||
|
|
||||||
|
public Thread getEventDispatchThread() { |
||||||
|
return eventDispatchThread; |
||||||
|
} |
||||||
|
|
||||||
|
public long getLastDispatchTimeMillis() { |
||||||
|
return lastDispatchTimeMillis; |
||||||
|
} |
||||||
|
|
||||||
|
public long getStartDispatchTimeMillis() { |
||||||
|
return startDispatchTimeMillis; |
||||||
|
} |
||||||
|
|
||||||
|
public void setLastDispatchTimeMillis(long lastDispatchTimeMillis) { |
||||||
|
this.lastDispatchTimeMillis = lastDispatchTimeMillis; |
||||||
|
} |
||||||
|
|
||||||
|
public long getEventSeq() { |
||||||
|
return eventSeq; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* event事件已运行时间 |
||||||
|
*/ |
||||||
|
public long timeSoFar() { |
||||||
|
return (System.currentTimeMillis() - lastDispatchTimeMillis); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* event事件总运行时间 |
||||||
|
*/ |
||||||
|
public long totalTime() { |
||||||
|
return (System.currentTimeMillis() - startDispatchTimeMillis); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
package com.fr.design.carton.latency; |
||||||
|
|
||||||
|
import com.fr.design.carton.DispatchInfo; |
||||||
|
|
||||||
|
/** |
||||||
|
* 设计器UI事件切面处理器 |
||||||
|
* |
||||||
|
* @author Levy.Xie |
||||||
|
* @since 11.0 |
||||||
|
* Created on 2024/11/07 |
||||||
|
*/ |
||||||
|
public abstract class AbstractUIDispatchHandler { |
||||||
|
|
||||||
|
/** |
||||||
|
* 是否需要处理 |
||||||
|
*/ |
||||||
|
protected abstract boolean accept(DispatchInfo info); |
||||||
|
|
||||||
|
/** |
||||||
|
* 实际处理 |
||||||
|
*/ |
||||||
|
protected abstract void doHandle(DispatchInfo info); |
||||||
|
|
||||||
|
/** |
||||||
|
* 处理UI切面 |
||||||
|
*/ |
||||||
|
public void handle(DispatchInfo info) { |
||||||
|
if (accept(info)) { |
||||||
|
doHandle(info); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,104 @@ |
|||||||
|
package com.fr.design.carton.latency; |
||||||
|
|
||||||
|
import com.fr.design.carton.DispatchInfo; |
||||||
|
import com.fr.design.carton.EventDispatchThreadHangMonitor; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.LinkedList; |
||||||
|
import java.util.List; |
||||||
|
import java.util.concurrent.Executors; |
||||||
|
import java.util.concurrent.ScheduledExecutorService; |
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
import static com.fr.design.carton.CartonConstants.CHECK_INTERVAL_MS; |
||||||
|
|
||||||
|
/** |
||||||
|
* 设计器UI事件切面处理器 |
||||||
|
* |
||||||
|
* @author Levy.Xie |
||||||
|
* @since 11.0 |
||||||
|
* Created on 2024/11/05 |
||||||
|
*/ |
||||||
|
public class UIDispatchManager { |
||||||
|
|
||||||
|
private ScheduledExecutorService scheduler; |
||||||
|
private final List<AbstractUIDispatchHandler> handlerList = new ArrayList<>(); |
||||||
|
|
||||||
|
private final static class InstanceHolder { |
||||||
|
static final UIDispatchManager INSTANCE = new UIDispatchManager(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 单例 |
||||||
|
*/ |
||||||
|
public static UIDispatchManager getInstance() { |
||||||
|
return UIDispatchManager.InstanceHolder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 注册处理器 |
||||||
|
* @param handler 处理器 |
||||||
|
*/ |
||||||
|
public void registerHandler(AbstractUIDispatchHandler handler) { |
||||||
|
handlerList.add(handler); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 注销处理器 |
||||||
|
* @param handler 处理器 |
||||||
|
*/ |
||||||
|
public void unregisterHandler(AbstractUIDispatchHandler handler) { |
||||||
|
handlerList.remove(handler); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 开启定时UI事件监听任务 |
||||||
|
*/ |
||||||
|
public void startScheduler() { |
||||||
|
if (scheduler != null && !scheduler.isShutdown()) { |
||||||
|
return; |
||||||
|
} |
||||||
|
scheduler = Executors.newSingleThreadScheduledExecutor(r -> { |
||||||
|
Thread thread = new Thread(r, "DesignerLatencyChecker"); |
||||||
|
thread.setDaemon(true); |
||||||
|
return thread; |
||||||
|
}); |
||||||
|
scheduler.scheduleAtFixedRate(new DispatchChecker(), 0, CHECK_INTERVAL_MS, TimeUnit.MILLISECONDS); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 尝试停止定时UI事件监听任务,但如果存在处理器,则不停止 |
||||||
|
*/ |
||||||
|
public void stopSchedulerIfNecessary() { |
||||||
|
if (!handlerList.isEmpty()) { |
||||||
|
return; |
||||||
|
} |
||||||
|
if (scheduler != null && !scheduler.isShutdown()) { |
||||||
|
scheduler.shutdownNow(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* UI事件切面检查器 |
||||||
|
*/ |
||||||
|
public class DispatchChecker implements Runnable { |
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
LinkedList<DispatchInfo> dispatches = EventDispatchThreadHangMonitor.INSTANCE.getDispatches(); |
||||||
|
synchronized (dispatches) { |
||||||
|
if (EventDispatchThreadHangMonitor.INSTANCE.ready()) { |
||||||
|
handle(dispatches.getLast()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 处理UI事件 |
||||||
|
* @param dispatchInfo ui事件信息 |
||||||
|
*/ |
||||||
|
public void handle(DispatchInfo dispatchInfo) { |
||||||
|
handlerList.forEach(handler -> handler.handle(dispatchInfo)); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,264 +0,0 @@ |
|||||||
package com.fr.design.data.datapane.connect; |
|
||||||
|
|
||||||
import java.awt.BorderLayout; |
|
||||||
import java.awt.Dimension; |
|
||||||
import java.awt.event.ActionEvent; |
|
||||||
import java.awt.event.ActionListener; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.Properties; |
|
||||||
|
|
||||||
import javax.naming.Context; |
|
||||||
import javax.swing.JDialog; |
|
||||||
|
|
||||||
import com.fine.theme.utils.FineUIScale; |
|
||||||
import com.formdev.flatlaf.util.ScaledEmptyBorder; |
|
||||||
import com.fr.design.constants.LayoutConstants; |
|
||||||
import com.fr.design.gui.ilable.UILabel; |
|
||||||
import javax.swing.JPanel; |
|
||||||
import javax.swing.JScrollPane; |
|
||||||
import javax.swing.SwingUtilities; |
|
||||||
|
|
||||||
import com.fr.data.impl.JNDIDatabaseConnection; |
|
||||||
import com.fr.design.gui.icombobox.UIComboBox; |
|
||||||
import com.fr.design.gui.itextfield.UITextField; |
|
||||||
import com.fr.design.gui.ilable.ActionLabel; |
|
||||||
import com.fr.design.gui.ilable.FRExplainLabel; |
|
||||||
import com.fr.design.layout.FRGUIPaneFactory; |
|
||||||
import com.fr.design.dialog.BasicPane; |
|
||||||
import com.fr.general.ComparatorUtils; |
|
||||||
|
|
||||||
import com.fr.stable.StringUtils; |
|
||||||
|
|
||||||
import static com.fine.swing.ui.layout.Layouts.cell; |
|
||||||
import static com.fine.swing.ui.layout.Layouts.column; |
|
||||||
import static com.fine.swing.ui.layout.Layouts.row; |
|
||||||
import static com.fine.theme.utils.FineUIUtils.wrapComponentWithTitle; |
|
||||||
|
|
||||||
public class JNDIDefPane extends JPanel { |
|
||||||
private static Map<String, String> jndiMap = new HashMap<String, String>(); |
|
||||||
|
|
||||||
static { |
|
||||||
jndiMap.put("weblogic.jndi.WLInitialContextFactory", "t3://localhost:7001"); |
|
||||||
jndiMap.put("com.ibm.websphere.naming.WsnInitialContextFactory", "iiop://localhost:2809"); |
|
||||||
jndiMap.put("org.jboss.naming.HttpNamingContextFactory", "http://jboss_server_address:8080/invoker/JNDIFactory"); |
|
||||||
jndiMap.put("org.jnp.interfaces.NamingContextFactory", "localhost:1099"); |
|
||||||
jndiMap.put("com.caucho.burlap.BurlapContextFactory", "http://localhost:8080/hello/burlap"); |
|
||||||
} |
|
||||||
|
|
||||||
private UITextField jndiNameTextField; |
|
||||||
|
|
||||||
private UIComboBox JNDIFactoryComboBox; |
|
||||||
private ContextTextField PROVIDER_URL_TF = new ContextTextField(Context.PROVIDER_URL); |
|
||||||
private ContextTextField SECURITY_PRINCIPAL_TF = new ContextTextField(Context.SECURITY_PRINCIPAL); |
|
||||||
private ContextTextField SECURITY_CREDENTIALS_TF = new ContextTextField(Context.SECURITY_CREDENTIALS); |
|
||||||
|
|
||||||
private ContextTextField OBJECT_FACTORIES_TF = new ContextTextField(Context.OBJECT_FACTORIES); |
|
||||||
private ContextTextField STATE_FACTORIES_TF = new ContextTextField(Context.STATE_FACTORIES); |
|
||||||
private ContextTextField URL_PKG_PREFIXES_TF = new ContextTextField(Context.URL_PKG_PREFIXES); |
|
||||||
private ContextTextField DNS_URL_TF = new ContextTextField(Context.DNS_URL); |
|
||||||
private ContextTextField AUTHORITATIVE_TF = new ContextTextField(Context.AUTHORITATIVE); |
|
||||||
private ContextTextField BATCHSIZE_TF = new ContextTextField(Context.BATCHSIZE); |
|
||||||
private ContextTextField REFERRAL_TF = new ContextTextField(Context.REFERRAL); |
|
||||||
private ContextTextField SECURITY_PROTOCOL_TF = new ContextTextField(Context.SECURITY_PROTOCOL); |
|
||||||
private ContextTextField SECURITY_AUTHENTICATION_TF = new ContextTextField(Context.SECURITY_AUTHENTICATION); |
|
||||||
private ContextTextField LANGUAGE_TF = new ContextTextField(Context.LANGUAGE); |
|
||||||
private ContextTextField APPLET_TF = new ContextTextField(Context.APPLET); |
|
||||||
|
|
||||||
private JDialog otherAttrDialog; |
|
||||||
|
|
||||||
public JNDIDefPane() { |
|
||||||
this.setLayout(new BorderLayout()); |
|
||||||
|
|
||||||
jndiNameTextField = new UITextField(20); |
|
||||||
JNDIFactoryComboBox = new UIComboBox(new String[] { "", "weblogic.jndi.WLInitialContextFactory", "com.ibm.websphere.naming.WsnInitialContextFactory", |
|
||||||
"org.jboss.naming.HttpNamingContextFactory", "org.jnp.interfaces.NamingContextFactory", "com.caucho.burlap.BurlapContextFactory", }); |
|
||||||
JNDIFactoryComboBox.setEditable(true); |
|
||||||
JNDIFactoryComboBox.addActionListener(jndiListener); |
|
||||||
JNDIFactoryComboBox.setPreferredSize(new Dimension(FineUIScale.scale(30), JNDIFactoryComboBox.getPreferredSize().height + FineUIScale.scale(2))); |
|
||||||
|
|
||||||
// 上下文
|
|
||||||
JPanel contextPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
|
||||||
contextPane.add(column(LayoutConstants.VERTICAL_GAP, |
|
||||||
row(LayoutConstants.HORIZONTAL_GAP, cell(new UILabel("INITIAL_CONTEXT_FACTORY")).weight(0.35), cell(JNDIFactoryComboBox).weight(0.65)), |
|
||||||
row(LayoutConstants.HORIZONTAL_GAP,cell(new UILabel("PROVIDER_URL")).weight(0.35), cell(PROVIDER_URL_TF).weight(0.65)), |
|
||||||
row(LayoutConstants.HORIZONTAL_GAP,cell(new UILabel("SECURITY_PRINCIPAL")).weight(0.35), cell(SECURITY_PRINCIPAL_TF).weight(0.65)), |
|
||||||
row(LayoutConstants.HORIZONTAL_GAP,cell(new UILabel("SECURITY_CREDENTIALS")).weight(0.35), cell(SECURITY_CREDENTIALS_TF).weight(0.65)) |
|
||||||
).getComponent()); |
|
||||||
|
|
||||||
//其他属性
|
|
||||||
JPanel otherAttributePanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
|
||||||
ActionLabel actionLabel = new ActionLabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Datasource_Other_Attributes")); |
|
||||||
actionLabel.addActionListener(new ActionListener() { |
|
||||||
public void actionPerformed(ActionEvent evt) { |
|
||||||
//其他属性弹窗
|
|
||||||
JDialog wDialog = createJDialog(); |
|
||||||
wDialog.setVisible(true); |
|
||||||
} |
|
||||||
}); |
|
||||||
otherAttributePanel.add(actionLabel, BorderLayout.EAST); |
|
||||||
//注意描述
|
|
||||||
JPanel jndiDesPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
|
||||||
jndiDesPanel.add(new JScrollPane(new FRExplainLabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Datasource_JNDI_DES"))), BorderLayout.WEST); |
|
||||||
//JNDI面板
|
|
||||||
JPanel centerPanel = column(LayoutConstants.VERTICAL_GAP, |
|
||||||
row(cell(new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Datasource_JNDI_Name"))).weight(0.15), cell(jndiNameTextField).weight(0.85)), |
|
||||||
row(cell(getTopAlignLabelPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Datasource_Context"))).weight(0.15), cell(contextPane).weight(0.85)), |
|
||||||
cell(otherAttributePanel), |
|
||||||
cell(jndiDesPanel) |
|
||||||
).getComponent(); |
|
||||||
this.add(wrapComponentWithTitle(centerPanel,"JNDI")); |
|
||||||
} |
|
||||||
|
|
||||||
private JPanel getTopAlignLabelPane(String labelText) { |
|
||||||
return column(LayoutConstants.VERTICAL_GAP, cell(new UILabel(labelText))) |
|
||||||
.with(it -> it.setBorder(new ScaledEmptyBorder(2,0,0,0))).getComponent(); |
|
||||||
} |
|
||||||
|
|
||||||
public void populate(JNDIDatabaseConnection jndiDatabase) { |
|
||||||
if (jndiDatabase == null) { |
|
||||||
jndiDatabase = new JNDIDatabaseConnection(); |
|
||||||
} |
|
||||||
|
|
||||||
// Properties.
|
|
||||||
Map<String, String> contextHashtable = jndiDatabase.getContextHashtable(); |
|
||||||
Object INITIAL_CONTEXT_FACTORY = contextHashtable.get(Context.INITIAL_CONTEXT_FACTORY); |
|
||||||
|
|
||||||
this.JNDIFactoryComboBox.setSelectedItem(INITIAL_CONTEXT_FACTORY == null ? "" : INITIAL_CONTEXT_FACTORY); |
|
||||||
this.jndiNameTextField.setText(jndiDatabase.getJNDIName() == null ? "" : jndiDatabase.getJNDIName()); |
|
||||||
populateContextAttributes(contextHashtable, this.PROVIDER_URL_TF, Context.PROVIDER_URL); |
|
||||||
populateContextAttributes(contextHashtable, this.SECURITY_PRINCIPAL_TF, Context.SECURITY_PRINCIPAL); |
|
||||||
populateContextAttributes(contextHashtable, this.SECURITY_CREDENTIALS_TF, Context.SECURITY_CREDENTIALS); |
|
||||||
|
|
||||||
populateContextAttributes(contextHashtable, this.OBJECT_FACTORIES_TF, Context.OBJECT_FACTORIES); |
|
||||||
populateContextAttributes(contextHashtable, this.STATE_FACTORIES_TF, Context.STATE_FACTORIES); |
|
||||||
populateContextAttributes(contextHashtable, this.URL_PKG_PREFIXES_TF, Context.URL_PKG_PREFIXES); |
|
||||||
|
|
||||||
populateContextAttributes(contextHashtable, this.DNS_URL_TF, Context.DNS_URL); |
|
||||||
populateContextAttributes(contextHashtable, this.AUTHORITATIVE_TF, Context.AUTHORITATIVE); |
|
||||||
populateContextAttributes(contextHashtable, this.BATCHSIZE_TF, Context.BATCHSIZE); |
|
||||||
populateContextAttributes(contextHashtable, this.REFERRAL_TF, Context.REFERRAL); |
|
||||||
populateContextAttributes(contextHashtable, this.SECURITY_PROTOCOL_TF, Context.SECURITY_PROTOCOL); |
|
||||||
populateContextAttributes(contextHashtable, this.SECURITY_AUTHENTICATION_TF, Context.SECURITY_AUTHENTICATION); |
|
||||||
populateContextAttributes(contextHashtable, this.LANGUAGE_TF, Context.LANGUAGE); |
|
||||||
populateContextAttributes(contextHashtable, this.APPLET_TF, Context.APPLET); |
|
||||||
} |
|
||||||
|
|
||||||
private void populateContextAttributes(Map<String, String> properties, UITextField textField, String contextAttr) { |
|
||||||
String PROVIDER_URL = properties.get(contextAttr); |
|
||||||
if (PROVIDER_URL != null) { |
|
||||||
textField.setText(PROVIDER_URL); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public JNDIDatabaseConnection update() { |
|
||||||
JNDIDatabaseConnection jndiDatabase = new JNDIDatabaseConnection(); |
|
||||||
|
|
||||||
jndiDatabase.setJNDIName(this.jndiNameTextField.getText()); |
|
||||||
|
|
||||||
Map<String, String> contextHashtable = jndiDatabase.getContextHashtable(); |
|
||||||
|
|
||||||
String factoryString = (String)this.JNDIFactoryComboBox.getEditor().getItem(); |
|
||||||
if (factoryString != null && factoryString.trim().length() > 0) { |
|
||||||
contextHashtable.put(Context.INITIAL_CONTEXT_FACTORY, factoryString); |
|
||||||
} |
|
||||||
updateContextAttributes(contextHashtable, this.PROVIDER_URL_TF, Context.PROVIDER_URL); |
|
||||||
updateContextAttributes(contextHashtable, this.SECURITY_PRINCIPAL_TF, Context.SECURITY_PRINCIPAL); |
|
||||||
updateContextAttributes(contextHashtable, this.SECURITY_CREDENTIALS_TF, Context.SECURITY_CREDENTIALS); |
|
||||||
|
|
||||||
updateContextAttributes(contextHashtable, this.OBJECT_FACTORIES_TF, Context.OBJECT_FACTORIES); |
|
||||||
updateContextAttributes(contextHashtable, this.STATE_FACTORIES_TF, Context.STATE_FACTORIES); |
|
||||||
updateContextAttributes(contextHashtable, this.URL_PKG_PREFIXES_TF, Context.URL_PKG_PREFIXES); |
|
||||||
|
|
||||||
updateContextAttributes(contextHashtable, this.DNS_URL_TF, Context.DNS_URL); |
|
||||||
updateContextAttributes(contextHashtable, this.AUTHORITATIVE_TF, Context.AUTHORITATIVE); |
|
||||||
updateContextAttributes(contextHashtable, this.BATCHSIZE_TF, Context.BATCHSIZE); |
|
||||||
updateContextAttributes(contextHashtable, this.REFERRAL_TF, Context.REFERRAL); |
|
||||||
updateContextAttributes(contextHashtable, this.SECURITY_PROTOCOL_TF, Context.SECURITY_PROTOCOL); |
|
||||||
updateContextAttributes(contextHashtable, this.SECURITY_AUTHENTICATION_TF, Context.SECURITY_AUTHENTICATION); |
|
||||||
updateContextAttributes(contextHashtable, this.LANGUAGE_TF, Context.LANGUAGE); |
|
||||||
updateContextAttributes(contextHashtable, this.APPLET_TF, Context.APPLET); |
|
||||||
|
|
||||||
return jndiDatabase; |
|
||||||
} |
|
||||||
|
|
||||||
private void updateContextAttributes(Map<String, String> contextHashtable, UITextField textField, String contextAttr) { |
|
||||||
String tValue = textField.getText(); |
|
||||||
if (tValue != null && tValue.trim().length() > 0) { |
|
||||||
contextHashtable.put(contextAttr, tValue); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ActionListener jndiListener = new ActionListener() { |
|
||||||
public void actionPerformed(ActionEvent e) { |
|
||||||
Object o = JNDIFactoryComboBox.getSelectedItem(); |
|
||||||
if (o == null || ComparatorUtils.equals(o, StringUtils.EMPTY)) { |
|
||||||
PROVIDER_URL_TF.setText(""); |
|
||||||
return; |
|
||||||
} |
|
||||||
PROVIDER_URL_TF.setText(jndiMap.get(o)); |
|
||||||
} |
|
||||||
|
|
||||||
}; |
|
||||||
|
|
||||||
private JDialog createJDialog() { |
|
||||||
if (this.otherAttrDialog == null) { |
|
||||||
this.otherAttrDialog = new OtherAttrPane().showWindow(SwingUtilities.getWindowAncestor(JNDIDefPane.this)); |
|
||||||
} |
|
||||||
|
|
||||||
return this.otherAttrDialog; |
|
||||||
} |
|
||||||
|
|
||||||
class OtherAttrPane extends BasicPane { |
|
||||||
public OtherAttrPane() { |
|
||||||
// JPanel northFlowPane
|
|
||||||
JPanel northFlowPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
|
||||||
northFlowPane.setBorder(new ScaledEmptyBorder(10,10,10,10)); |
|
||||||
// ContextPane
|
|
||||||
northFlowPane.add(column(LayoutConstants.VERTICAL_GAP, |
|
||||||
row(LayoutConstants.HORIZONTAL_GAP, cell(new UILabel("OBJECT_FACTORIES")).weight(0.35), cell(OBJECT_FACTORIES_TF)).weight(0.65), |
|
||||||
row(LayoutConstants.HORIZONTAL_GAP, cell(new UILabel("STATE_FACTORIES")).weight(0.35), cell(STATE_FACTORIES_TF)).weight(0.65), |
|
||||||
row(LayoutConstants.HORIZONTAL_GAP, cell(new UILabel("URL_PKG_PREFIXES")).weight(0.35), cell(URL_PKG_PREFIXES_TF)).weight(0.65), |
|
||||||
row(LayoutConstants.HORIZONTAL_GAP, cell(new UILabel("DNS_URL")).weight(0.35), cell(DNS_URL_TF)).weight(0.65), |
|
||||||
row(LayoutConstants.HORIZONTAL_GAP, cell(new UILabel("AUTHORITATIVE")).weight(0.35), cell(AUTHORITATIVE_TF)).weight(0.65), |
|
||||||
row(LayoutConstants.HORIZONTAL_GAP, cell(new UILabel("BATCHSIZE")).weight(0.35), cell(BATCHSIZE_TF)).weight(0.65), |
|
||||||
row(LayoutConstants.HORIZONTAL_GAP, cell(new UILabel("REFERRAL")).weight(0.35), cell(REFERRAL_TF)).weight(0.65), |
|
||||||
row(LayoutConstants.HORIZONTAL_GAP, cell(new UILabel("SECURITY_PROTOCOL")).weight(0.35), cell(SECURITY_PROTOCOL_TF)).weight(0.65), |
|
||||||
row(LayoutConstants.HORIZONTAL_GAP, cell(new UILabel("SECURITY_AUTHENTICATION")).weight(0.35), cell(SECURITY_AUTHENTICATION_TF)).weight(0.65), |
|
||||||
row(LayoutConstants.HORIZONTAL_GAP, cell(new UILabel("LANGUAGE")).weight(0.35), cell(LANGUAGE_TF)).weight(0.65), |
|
||||||
row(LayoutConstants.HORIZONTAL_GAP, cell(new UILabel("APPLET")).weight(0.35), cell(APPLET_TF)).weight(0.65) |
|
||||||
).getComponent()); |
|
||||||
this.add(northFlowPane, BorderLayout.NORTH); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected String title4PopupWindow() { |
|
||||||
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Datasource_Other_Attributes"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// 主力Context属性
|
|
||||||
class ContextTextField extends UITextField { |
|
||||||
private String contextName; |
|
||||||
|
|
||||||
public ContextTextField(String contextName) { |
|
||||||
this.setContextName(contextName); |
|
||||||
this.setColumns(24); |
|
||||||
} |
|
||||||
|
|
||||||
public String getContextName() { |
|
||||||
return contextName; |
|
||||||
} |
|
||||||
|
|
||||||
public void setContextName(String contextName) { |
|
||||||
this.contextName = contextName; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* 更新Properties. |
|
||||||
*/ |
|
||||||
public void applyProperties(Properties properties) { |
|
||||||
properties.put(contextName, this.getText()); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,30 @@ |
|||||||
|
package com.fr.design.debug.edt; |
||||||
|
|
||||||
|
/** |
||||||
|
* Swing组件严格限制EDT运行 |
||||||
|
* |
||||||
|
* @author vito |
||||||
|
* @since 11.0 |
||||||
|
* Created on 2023/8/9 |
||||||
|
*/ |
||||||
|
public class StrictEDTException extends RuntimeException { |
||||||
|
|
||||||
|
public StrictEDTException() { |
||||||
|
} |
||||||
|
|
||||||
|
public StrictEDTException(String message) { |
||||||
|
super(message); |
||||||
|
} |
||||||
|
|
||||||
|
public StrictEDTException(String message, Throwable cause) { |
||||||
|
super(message, cause); |
||||||
|
} |
||||||
|
|
||||||
|
public StrictEDTException(Throwable cause) { |
||||||
|
super(cause); |
||||||
|
} |
||||||
|
|
||||||
|
public StrictEDTException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { |
||||||
|
super(message, cause, enableSuppression, writableStackTrace); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,130 @@ |
|||||||
|
package com.fr.design.debug.edt; |
||||||
|
|
||||||
|
import com.fr.design.ui.util.EdtInvocationManager; |
||||||
|
import com.fr.log.FineLoggerFactory; |
||||||
|
|
||||||
|
import java.awt.event.ComponentEvent; |
||||||
|
import java.awt.event.ComponentListener; |
||||||
|
import java.awt.event.HierarchyEvent; |
||||||
|
import java.awt.event.HierarchyListener; |
||||||
|
import java.awt.event.KeyEvent; |
||||||
|
import java.awt.event.KeyListener; |
||||||
|
import java.awt.event.MouseEvent; |
||||||
|
import java.awt.event.MouseListener; |
||||||
|
import java.awt.event.MouseMotionListener; |
||||||
|
import java.awt.event.MouseWheelEvent; |
||||||
|
import java.awt.event.MouseWheelListener; |
||||||
|
import java.beans.PropertyChangeEvent; |
||||||
|
import java.beans.PropertyChangeListener; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Swing组件严格限制EDT运行监听器 |
||||||
|
* |
||||||
|
* @author vito |
||||||
|
* @since 11.0 |
||||||
|
* Created on 2023/8/9 |
||||||
|
*/ |
||||||
|
public class StrictEdtListeners implements HierarchyListener, PropertyChangeListener, ComponentListener, MouseListener, |
||||||
|
MouseWheelListener, MouseMotionListener, KeyListener { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void componentResized(ComponentEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void componentMoved(ComponentEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void componentShown(ComponentEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void componentHidden(ComponentEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void hierarchyChanged(HierarchyEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void keyTyped(KeyEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void keyPressed(KeyEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void keyReleased(KeyEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void mouseClicked(MouseEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void mousePressed(MouseEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void mouseReleased(MouseEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void mouseEntered(MouseEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void mouseExited(MouseEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
// redispatchMouseEvent(e);
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void mouseDragged(MouseEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void mouseMoved(MouseEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void mouseWheelMoved(MouseWheelEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void propertyChange(PropertyChangeEvent e) { |
||||||
|
checkEventDispatchThread(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 检查当前是否处于EDT中,并发出告警 |
||||||
|
*/ |
||||||
|
public static void checkEventDispatchThread() { |
||||||
|
if (!EdtInvocationManager.getInstance().isEventDispatchThread()) { |
||||||
|
String s = String.format( |
||||||
|
"[StrictEDT] The current operation can only be in an EDT (Event Dispatch Thread). Current thread is: %s", |
||||||
|
Thread.currentThread().getName() |
||||||
|
); |
||||||
|
StrictEDTException strictEdtException = new StrictEDTException(s); |
||||||
|
FineLoggerFactory.getLogger().warn(s, strictEdtException); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,135 @@ |
|||||||
|
package com.fr.design.debug.edt; |
||||||
|
|
||||||
|
import com.fanruan.gui.InspectorWindow; |
||||||
|
import com.fr.design.mainframe.DesignerContext; |
||||||
|
import com.fr.log.FineLoggerFactory; |
||||||
|
import org.jetbrains.annotations.NotNull; |
||||||
|
|
||||||
|
import java.awt.AWTEvent; |
||||||
|
import java.awt.Component; |
||||||
|
import java.awt.Container; |
||||||
|
import java.awt.Toolkit; |
||||||
|
import java.awt.Window; |
||||||
|
import java.awt.event.AWTEventListener; |
||||||
|
import java.awt.event.ContainerEvent; |
||||||
|
|
||||||
|
/** |
||||||
|
* 严格UI线程运行管理器 |
||||||
|
* |
||||||
|
* @author vito |
||||||
|
* @since 11.0 |
||||||
|
* Created on 2024/12/20 |
||||||
|
*/ |
||||||
|
public class StrictEdtManager { |
||||||
|
|
||||||
|
private static final StrictEdtListeners LISTENERS = new StrictEdtListeners(); |
||||||
|
|
||||||
|
private static void installContainerEDTCheckers(@NotNull final Container component, int level) { |
||||||
|
if (FineLoggerFactory.getLogger().isDebugEnabled()) { |
||||||
|
for (int i = 0; i < level; i++) { |
||||||
|
FineLoggerFactory.getLogger().debug(" "); |
||||||
|
} |
||||||
|
FineLoggerFactory.getLogger().debug(component.toString()); |
||||||
|
} |
||||||
|
|
||||||
|
int count = component.getComponentCount(); |
||||||
|
level += 1; |
||||||
|
for (int i = 0; i < count; i++) { |
||||||
|
Component comp = component.getComponent(i); |
||||||
|
addEDTCheckersListener(comp); |
||||||
|
if (comp instanceof Container) { |
||||||
|
installContainerEDTCheckers((Container) comp, level); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static void addEDTCheckersListener(Component comp) { |
||||||
|
comp.addHierarchyListener(LISTENERS); |
||||||
|
comp.addPropertyChangeListener(LISTENERS); |
||||||
|
comp.addComponentListener(LISTENERS); |
||||||
|
comp.addMouseListener(LISTENERS); |
||||||
|
comp.addMouseMotionListener(LISTENERS); |
||||||
|
comp.addKeyListener(LISTENERS); |
||||||
|
} |
||||||
|
|
||||||
|
private static void installEDTCheckers(Container container, int level) { |
||||||
|
installContainerEDTCheckers(container, level); |
||||||
|
level += 1; |
||||||
|
if (container instanceof Window) { |
||||||
|
Window[] children = ((Window) container).getOwnedWindows(); |
||||||
|
for (Window child : children) { |
||||||
|
if (child instanceof InspectorWindow) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
installEDTCheckers(child, level); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static final AWTEventListener AWT_EVENT_LISTENER = (AWTEvent event) -> { |
||||||
|
if (event instanceof ContainerEvent) { |
||||||
|
Component child = event.getID() == ContainerEvent.COMPONENT_ADDED ? ((ContainerEvent) event).getChild() : null; |
||||||
|
if (child != null) { |
||||||
|
addEDTCheckersListener(child); |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* 监听组件,警告不在EDT中执行的UI操作 |
||||||
|
*/ |
||||||
|
public static void install() { |
||||||
|
// 监听当前的组件
|
||||||
|
installEDTCheckers(DesignerContext.getDesignerFrame(), 0); |
||||||
|
// 监听新增的组件
|
||||||
|
Toolkit.getDefaultToolkit().addAWTEventListener(AWT_EVENT_LISTENER, AWTEvent.CONTAINER_EVENT_MASK); |
||||||
|
FineLoggerFactory.getLogger().info("[StrictEDT] install Strict EDT Checkers"); |
||||||
|
} |
||||||
|
|
||||||
|
private static void uninstallContainerEDTCheckers(@NotNull final Container component, int level) { |
||||||
|
int count = component.getComponentCount(); |
||||||
|
level += 1; |
||||||
|
for (int i = 0; i < count; i++) { |
||||||
|
Component comp = component.getComponent(i); |
||||||
|
removeEDTCheckersListener(comp); |
||||||
|
if (comp instanceof Container) { |
||||||
|
uninstallContainerEDTCheckers((Container) comp, level); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static void removeEDTCheckersListener(Component comp) { |
||||||
|
comp.removeHierarchyListener(LISTENERS); |
||||||
|
comp.removePropertyChangeListener(LISTENERS); |
||||||
|
comp.removeComponentListener(LISTENERS); |
||||||
|
comp.removeMouseListener(LISTENERS); |
||||||
|
comp.removeMouseMotionListener(LISTENERS); |
||||||
|
comp.removeKeyListener(LISTENERS); |
||||||
|
} |
||||||
|
|
||||||
|
private static void removeEDTCheckers(Container container, int level) { |
||||||
|
uninstallContainerEDTCheckers(container, level); |
||||||
|
level += 1; |
||||||
|
if (container instanceof Window) { |
||||||
|
Window[] children = ((Window) container).getOwnedWindows(); |
||||||
|
for (Window child : children) { |
||||||
|
if (child instanceof InspectorWindow) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
removeEDTCheckers(child, level); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 监听组件,警告不在EDT中执行的UI操作 |
||||||
|
*/ |
||||||
|
public static void uninstall() { |
||||||
|
// 取消监听新增的组件
|
||||||
|
Toolkit.getDefaultToolkit().removeAWTEventListener(AWT_EVENT_LISTENER); |
||||||
|
// 解除监听当前的组件
|
||||||
|
removeEDTCheckers(DesignerContext.getDesignerFrame(), 0); |
||||||
|
FineLoggerFactory.getLogger().info("[StrictEDT] uninstall Strict EDT Checkers"); |
||||||
|
} |
||||||
|
} |
@ -1,4 +1,4 @@ |
|||||||
package com.fr.design.remote.ui.debug; |
package com.fr.design.debug.remote; |
||||||
|
|
||||||
import com.fine.theme.icon.LazyIcon; |
import com.fine.theme.icon.LazyIcon; |
||||||
import com.fine.theme.light.ui.FineTableHeaderUI; |
import com.fine.theme.light.ui.FineTableHeaderUI; |
@ -1,4 +1,4 @@ |
|||||||
package com.fr.design.remote.ui.debug; |
package com.fr.design.debug.remote; |
||||||
|
|
||||||
import com.fr.stable.StringUtils; |
import com.fr.stable.StringUtils; |
||||||
|
|
@ -1,4 +1,4 @@ |
|||||||
package com.fr.design.remote.ui.debug; |
package com.fr.design.debug.remote; |
||||||
|
|
||||||
import javax.swing.table.DefaultTableModel; |
import javax.swing.table.DefaultTableModel; |
||||||
import javax.swing.table.TableRowSorter; |
import javax.swing.table.TableRowSorter; |
@ -1,10 +1,10 @@ |
|||||||
package com.fr.design.remote.ui.debug; |
package com.fr.design.debug.remote; |
||||||
|
|
||||||
import com.fine.theme.light.ui.FineTableHeaderUI; |
import com.fine.theme.light.ui.FineTableHeaderUI; |
||||||
|
|
||||||
import java.awt.Color; |
import java.awt.Color; |
||||||
|
|
||||||
import static com.fr.design.remote.ui.debug.RemoteDesignNetWorkHelper.DEFAULT_COLOR; |
import static com.fr.design.debug.remote.RemoteDesignNetWorkHelper.DEFAULT_COLOR; |
||||||
|
|
||||||
/** |
/** |
||||||
* 大小多颜色渲染 |
* 大小多颜色渲染 |
@ -1,10 +1,10 @@ |
|||||||
package com.fr.design.remote.ui.debug; |
package com.fr.design.debug.remote; |
||||||
|
|
||||||
import com.fine.theme.light.ui.FineTableHeaderUI; |
import com.fine.theme.light.ui.FineTableHeaderUI; |
||||||
|
|
||||||
import java.awt.Color; |
import java.awt.Color; |
||||||
|
|
||||||
import static com.fr.design.remote.ui.debug.RemoteDesignNetWorkHelper.DEFAULT_COLOR; |
import static com.fr.design.debug.remote.RemoteDesignNetWorkHelper.DEFAULT_COLOR; |
||||||
|
|
||||||
/** |
/** |
||||||
* 时间多颜色渲染 |
* 时间多颜色渲染 |
@ -0,0 +1,48 @@ |
|||||||
|
package com.fr.design.debug.ui; |
||||||
|
|
||||||
|
/** |
||||||
|
* UI卡顿信息Bean |
||||||
|
* |
||||||
|
* @author Levy.Xie |
||||||
|
* @since 11.0 |
||||||
|
* Created on 2024/11/07 |
||||||
|
*/ |
||||||
|
public class LatencyInfo { |
||||||
|
|
||||||
|
// swing事件编号
|
||||||
|
private long seq; |
||||||
|
// 耗时 ms
|
||||||
|
private long cost; |
||||||
|
// 堆栈信息
|
||||||
|
private StackTraceElement[] detailStack; |
||||||
|
|
||||||
|
public LatencyInfo(long seq, long cost, StackTraceElement[] detailStack) { |
||||||
|
this.seq = seq; |
||||||
|
this.cost = cost; |
||||||
|
this.detailStack = detailStack; |
||||||
|
} |
||||||
|
|
||||||
|
public long getCost() { |
||||||
|
return cost; |
||||||
|
} |
||||||
|
|
||||||
|
public void setCost(long cost) { |
||||||
|
this.cost = cost; |
||||||
|
} |
||||||
|
|
||||||
|
public StackTraceElement[] getDetailStack() { |
||||||
|
return detailStack; |
||||||
|
} |
||||||
|
|
||||||
|
public void setDetailStack(StackTraceElement[] detailStack) { |
||||||
|
this.detailStack = detailStack; |
||||||
|
} |
||||||
|
|
||||||
|
public long getSeq() { |
||||||
|
return seq; |
||||||
|
} |
||||||
|
|
||||||
|
public void setSeq(long seq) { |
||||||
|
this.seq = seq; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
package com.fr.design.debug.ui; |
||||||
|
|
||||||
|
import com.fr.event.Event; |
||||||
|
|
||||||
|
/** |
||||||
|
* UI性能监控事件 |
||||||
|
* |
||||||
|
* @author Levy.Xie |
||||||
|
* @since 11.0 |
||||||
|
* Created on 2024/11/08 |
||||||
|
*/ |
||||||
|
public enum LatencyMonitorEvent implements Event<LatencyInfo> { |
||||||
|
/** |
||||||
|
* 超出卡顿阈值 |
||||||
|
*/ |
||||||
|
OFF_THRESHOLD_EVENT |
||||||
|
} |
@ -0,0 +1,56 @@ |
|||||||
|
package com.fr.design.debug.ui; |
||||||
|
|
||||||
|
import com.fanruan.gui.UiInspector; |
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean; |
||||||
|
|
||||||
|
/** |
||||||
|
* UIInspectorHolder 单例管理 |
||||||
|
* |
||||||
|
* @author Levy.Xie |
||||||
|
* @since 11.0 |
||||||
|
* Created on 2024/11/08 |
||||||
|
*/ |
||||||
|
public class UIInspectorHolder { |
||||||
|
|
||||||
|
private UiInspector uiInspector; |
||||||
|
private final AtomicBoolean installed = new AtomicBoolean(false); |
||||||
|
|
||||||
|
private final static class InstanceHolder { |
||||||
|
static final UIInspectorHolder INSTANCE = new UIInspectorHolder(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 单例 |
||||||
|
*/ |
||||||
|
public static UIInspectorHolder getInstance() { |
||||||
|
return UIInspectorHolder.InstanceHolder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 是否已启用UIInspector |
||||||
|
* @return 是否启用 |
||||||
|
*/ |
||||||
|
public boolean isInstalled() { |
||||||
|
return installed.get(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 启用UIInspector |
||||||
|
*/ |
||||||
|
public void install() { |
||||||
|
if (installed.compareAndSet(false, true)) { |
||||||
|
uiInspector = new UiInspector(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 注销UIInspector |
||||||
|
*/ |
||||||
|
public void uninstall() { |
||||||
|
if (uiInspector != null) { |
||||||
|
uiInspector.dispose(); |
||||||
|
installed.set(false); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
package com.fr.design.debug.ui; |
||||||
|
|
||||||
|
import com.fr.design.carton.DispatchInfo; |
||||||
|
import com.fr.design.carton.latency.AbstractUIDispatchHandler; |
||||||
|
|
||||||
|
/** |
||||||
|
* UI卡顿实时监控Handler |
||||||
|
* |
||||||
|
* @author Levy.Xie |
||||||
|
* @since 11.0 |
||||||
|
* Created on 2024/11/07 |
||||||
|
*/ |
||||||
|
public class UILatencyInfoHandler extends AbstractUIDispatchHandler { |
||||||
|
|
||||||
|
private long threshold = 200; |
||||||
|
|
||||||
|
private final static class InstanceHolder { |
||||||
|
static final UILatencyInfoHandler INSTANCE = new UILatencyInfoHandler(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 单例 |
||||||
|
*/ |
||||||
|
public static UILatencyInfoHandler getInstance() { |
||||||
|
return UILatencyInfoHandler.InstanceHolder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
public long getThreshold() { |
||||||
|
return threshold; |
||||||
|
} |
||||||
|
|
||||||
|
public void setThreshold(long threshold) { |
||||||
|
this.threshold = threshold; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected boolean accept(DispatchInfo info) { |
||||||
|
return info.timeSoFar() > threshold; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void doHandle(DispatchInfo info) { |
||||||
|
LatencyInfo infoBean = new LatencyInfo(info.getEventSeq(), info.timeSoFar(), info.getEventDispatchThread().getStackTrace()); |
||||||
|
UILatencyWorker.getInstance().submit(infoBean); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,124 @@ |
|||||||
|
package com.fr.design.debug.ui; |
||||||
|
|
||||||
|
import com.fr.design.carton.latency.UIDispatchManager; |
||||||
|
import com.fr.event.EventDispatcher; |
||||||
|
import com.fr.third.guava.cache.Cache; |
||||||
|
import com.fr.third.guava.cache.CacheBuilder; |
||||||
|
|
||||||
|
import java.util.Collection; |
||||||
|
import java.util.concurrent.ExecutorService; |
||||||
|
import java.util.concurrent.Executors; |
||||||
|
import java.util.concurrent.atomic.AtomicBoolean; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
/** |
||||||
|
* UI性能监控Worker |
||||||
|
* |
||||||
|
* @author Levy.Xie |
||||||
|
* @since 11.0 |
||||||
|
* Created on 2024/11/07 |
||||||
|
*/ |
||||||
|
public class UILatencyWorker { |
||||||
|
|
||||||
|
private ExecutorService executorService; |
||||||
|
private final AtomicBoolean initialized = new AtomicBoolean(false); |
||||||
|
|
||||||
|
// 默认允许存储300卡顿信息
|
||||||
|
private final Cache<Long, LatencyInfo> infoContainer = CacheBuilder.newBuilder() |
||||||
|
.maximumSize(300).build(); |
||||||
|
|
||||||
|
private final static class InstanceHolder { |
||||||
|
static final UILatencyWorker INSTANCE = new UILatencyWorker(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 单例 |
||||||
|
*/ |
||||||
|
public static UILatencyWorker getInstance() { |
||||||
|
return InstanceHolder.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 开始监控: 启动异步提交线程、启动定时堆栈检测任务 |
||||||
|
*/ |
||||||
|
public void start() { |
||||||
|
if (initialized.compareAndSet(false, true)) { |
||||||
|
executorService = Executors.newSingleThreadExecutor(); |
||||||
|
UIDispatchManager.getInstance().registerHandler(UILatencyInfoHandler.getInstance()); |
||||||
|
UIDispatchManager.getInstance().startScheduler(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 停止监控:关闭异步提交线程及定时堆栈任务 |
||||||
|
*/ |
||||||
|
public void stop() { |
||||||
|
UIDispatchManager.getInstance().unregisterHandler(UILatencyInfoHandler.getInstance()); |
||||||
|
UIDispatchManager.getInstance().stopSchedulerIfNecessary(); |
||||||
|
if (this.executorService != null) { |
||||||
|
this.executorService.shutdown(); |
||||||
|
} |
||||||
|
initialized.set(false); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 是否监控中 |
||||||
|
* |
||||||
|
* @return 是否监控中 |
||||||
|
*/ |
||||||
|
public boolean isMonitoring() { |
||||||
|
return initialized.get(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 设置UI卡顿堆栈阈值 |
||||||
|
* @param threshold 阈值 ms |
||||||
|
*/ |
||||||
|
public void resetThreshold(long threshold) { |
||||||
|
UILatencyInfoHandler.getInstance().setThreshold(threshold); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 提交卡顿堆栈信息 |
||||||
|
* @param latencyInfo 卡顿信息 |
||||||
|
*/ |
||||||
|
public void submit(LatencyInfo latencyInfo) { |
||||||
|
executorService.submit(() -> { |
||||||
|
if (UIMonitorHelper.isIgnoreEvent(latencyInfo.getDetailStack())) { |
||||||
|
return; |
||||||
|
} |
||||||
|
LatencyInfo existInfo = infoContainer.getIfPresent(latencyInfo.getSeq()); |
||||||
|
// 确保记录的是最深的堆栈信息
|
||||||
|
if (existInfo == null || latencyInfo.getDetailStack().length > existInfo.getDetailStack().length) { |
||||||
|
infoContainer.put(latencyInfo.getSeq(), latencyInfo); |
||||||
|
EventDispatcher.fire(LatencyMonitorEvent.OFF_THRESHOLD_EVENT, latencyInfo); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 输出卡顿文本信息 |
||||||
|
* |
||||||
|
* @return 卡顿文本信息 |
||||||
|
*/ |
||||||
|
public String getLatencyData() { |
||||||
|
return getAllLatencyInfo().stream().map(info -> "seq:" + info.getSeq() + "\n" + |
||||||
|
"cost:" + info.getCost() + "ms\n" + |
||||||
|
"stack:" + UIMonitorHelper.convertStack(info.getDetailStack()) + "\n").collect(Collectors.joining("\n")); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取当前记录的所有卡顿信息 |
||||||
|
* @return 全量卡顿信息 |
||||||
|
*/ |
||||||
|
public Collection<LatencyInfo> getAllLatencyInfo() { |
||||||
|
return infoContainer.asMap().values(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 清空全量卡顿信息 |
||||||
|
*/ |
||||||
|
public void clearData() { |
||||||
|
infoContainer.invalidateAll(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
package com.fr.design.debug.ui; |
||||||
|
|
||||||
|
import com.fine.theme.utils.FineUIUtils; |
||||||
|
import com.fr.design.actions.UpdateAction; |
||||||
|
import com.fr.design.mainframe.DesignerContext; |
||||||
|
import com.fr.design.utils.gui.GUICoreUtils; |
||||||
|
|
||||||
|
import javax.swing.JDialog; |
||||||
|
import javax.swing.KeyStroke; |
||||||
|
import java.awt.event.ActionEvent; |
||||||
|
import java.awt.event.KeyEvent; |
||||||
|
|
||||||
|
import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; |
||||||
|
|
||||||
|
/** |
||||||
|
* UI实时监控 |
||||||
|
* |
||||||
|
* @author Levy.Xie |
||||||
|
* @since 11.0 |
||||||
|
* Created on 2024/11/07 |
||||||
|
*/ |
||||||
|
public class UIMonitorAction extends UpdateAction { |
||||||
|
|
||||||
|
public static final String TITLE = "UI Monitor"; |
||||||
|
|
||||||
|
public UIMonitorAction() { |
||||||
|
this.setName(TITLE); |
||||||
|
this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_U, DEFAULT_MODIFIER)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void actionPerformed(ActionEvent e) { |
||||||
|
JDialog jDialog = new JDialog(DesignerContext.getDesignerFrame(), TITLE); |
||||||
|
jDialog.setSize(FineUIUtils.calPaneDimensionByContext(0.5, 0.7)); |
||||||
|
UIMonitorPane monitorPane = new UIMonitorPane(); |
||||||
|
jDialog.add(monitorPane); |
||||||
|
GUICoreUtils.centerWindow(jDialog); |
||||||
|
jDialog.setVisible(true); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
package com.fr.design.debug.ui; |
||||||
|
|
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
/** |
||||||
|
* UI性能监控工具类 |
||||||
|
* |
||||||
|
* @author Levy.Xie |
||||||
|
* @since 11.0 |
||||||
|
* Created on 2024/11/08 |
||||||
|
*/ |
||||||
|
public class UIMonitorHelper { |
||||||
|
|
||||||
|
/** |
||||||
|
* 判断是否特定的堆栈 |
||||||
|
*/ |
||||||
|
public static boolean stackTraceElementIs(StackTraceElement e, String className, String methodName, boolean isNative) { |
||||||
|
return e.getClassName().equals(className) && e.getMethodName().equals(methodName) && e.isNativeMethod() == isNative; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 用于判断是否为需要忽略记录的堆栈信息 |
||||||
|
*/ |
||||||
|
public static boolean isIgnoreEvent(StackTraceElement[] currentStack) { |
||||||
|
|
||||||
|
return currentStack != null && currentStack.length >= 1 && ( |
||||||
|
stackTraceElementIs(currentStack[0], "java.lang.Object", "wait", true) |
||||||
|
|| stackTraceElementIs(currentStack[0], "sun.misc.Unsafe", "park", true) |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 堆栈格式化 |
||||||
|
* @param stackTrace 堆栈信息 |
||||||
|
* |
||||||
|
* @return 格式化后的堆栈信息 |
||||||
|
*/ |
||||||
|
public static String convertStack(StackTraceElement[] stackTrace) { |
||||||
|
return Arrays.stream(stackTrace) |
||||||
|
.map(st -> "\t" + st.toString()).collect(Collectors.joining("\n")); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,285 @@ |
|||||||
|
package com.fr.design.debug.ui; |
||||||
|
|
||||||
|
import com.fine.swing.ui.layout.Row; |
||||||
|
import com.fine.theme.icon.LazyIcon; |
||||||
|
import com.fine.theme.utils.FineClientProperties; |
||||||
|
import com.fine.theme.utils.FineUIUtils; |
||||||
|
import com.formdev.flatlaf.util.ScaledEmptyBorder; |
||||||
|
import com.fr.base.extension.FileExtension; |
||||||
|
import com.fr.design.border.FineBorderFactory; |
||||||
|
import com.fr.design.carton.latency.LatencyLevel; |
||||||
|
import com.fr.design.debug.edt.StrictEdtManager; |
||||||
|
import com.fr.design.dialog.BasicDialog; |
||||||
|
import com.fr.design.dialog.BasicPane; |
||||||
|
import com.fr.design.gui.ibutton.UIButton; |
||||||
|
import com.fr.design.gui.icheckbox.UICheckBox; |
||||||
|
import com.fr.design.gui.icombobox.UIComboBox; |
||||||
|
import com.fr.design.gui.icontainer.UIScrollPane; |
||||||
|
import com.fr.design.gui.icontainer.UITableScrollPane; |
||||||
|
import com.fr.design.gui.ilable.UILabel; |
||||||
|
import com.fr.design.gui.itable.FineUITable; |
||||||
|
import com.fr.design.gui.itextarea.UITextArea; |
||||||
|
import com.fr.design.gui.itoolbar.UIToolbar; |
||||||
|
import com.fr.design.mainframe.DesignerContext; |
||||||
|
import com.fr.event.Event; |
||||||
|
import com.fr.event.EventDispatcher; |
||||||
|
import com.fr.event.Listener; |
||||||
|
import com.fr.file.FILE; |
||||||
|
import com.fr.file.FILEChooserPane; |
||||||
|
import com.fr.file.filter.ChooseFileFilter; |
||||||
|
import com.fr.general.GeneralUtils; |
||||||
|
import com.fr.log.FineLoggerFactory; |
||||||
|
import org.jetbrains.annotations.NotNull; |
||||||
|
|
||||||
|
import javax.swing.JPanel; |
||||||
|
import javax.swing.JTable; |
||||||
|
import javax.swing.JToolBar; |
||||||
|
import javax.swing.SwingUtilities; |
||||||
|
import javax.swing.table.DefaultTableModel; |
||||||
|
import javax.swing.table.TableColumn; |
||||||
|
import javax.swing.table.TableColumnModel; |
||||||
|
import java.awt.BorderLayout; |
||||||
|
import java.awt.Point; |
||||||
|
import java.awt.event.MouseAdapter; |
||||||
|
import java.awt.event.MouseEvent; |
||||||
|
import java.io.BufferedWriter; |
||||||
|
import java.io.FileWriter; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
import static com.fine.swing.ui.layout.Layouts.cell; |
||||||
|
import static com.fine.swing.ui.layout.Layouts.column; |
||||||
|
import static com.fine.swing.ui.layout.Layouts.row; |
||||||
|
|
||||||
|
/** |
||||||
|
* UI监控面板 |
||||||
|
* |
||||||
|
* @author Levy.Xie |
||||||
|
* @since 11.0 |
||||||
|
* Created on 2024/11/07 |
||||||
|
*/ |
||||||
|
public class UIMonitorPane extends JPanel { |
||||||
|
|
||||||
|
private DefaultTableModel model; |
||||||
|
private UICheckBox inspector; |
||||||
|
private UICheckBox strictEDTChecker; |
||||||
|
private UICheckBox monitor; |
||||||
|
|
||||||
|
public UIMonitorPane() { |
||||||
|
setLayout(new BorderLayout()); |
||||||
|
setBorder(new ScaledEmptyBorder(10, 10, 10, 10)); |
||||||
|
initComponent(); |
||||||
|
} |
||||||
|
|
||||||
|
private void initComponent() { |
||||||
|
UITableScrollPane tablePane = initLatencyTable(); |
||||||
|
Row topSettingRow = initTopSettingRow(); |
||||||
|
inspector = new UICheckBox("Open UI Inspector"); |
||||||
|
strictEDTChecker = new UICheckBox("Open Strict EDT Checker"); |
||||||
|
monitor = new UICheckBox("Open Latency Monitor"); |
||||||
|
|
||||||
|
JPanel monitorPane = column(10, |
||||||
|
cell(monitor), cell(topSettingRow), cell(tablePane).weight(1) |
||||||
|
).getComponent(); |
||||||
|
|
||||||
|
add(column(10, |
||||||
|
cell(FineUIUtils.wrapComponentWithTitle(inspector, "UI Inspector")), |
||||||
|
cell(FineUIUtils.wrapComponentWithTitle(strictEDTChecker, "Strict EDT Checker")), |
||||||
|
cell(FineUIUtils.wrapComponentWithTitle(monitorPane, "UI Latency Monitor")) |
||||||
|
).getComponent(), BorderLayout.CENTER); |
||||||
|
|
||||||
|
topSettingRow.setVisible(false); |
||||||
|
tablePane.setVisible(false); |
||||||
|
|
||||||
|
initMonitorStatus(topSettingRow, tablePane); |
||||||
|
} |
||||||
|
|
||||||
|
private void initMonitorStatus(Row topSettingRow, UITableScrollPane tablePane) { |
||||||
|
inspector.setSelected(UIInspectorHolder.getInstance().isInstalled()); |
||||||
|
monitor.setSelected(UILatencyWorker.getInstance().isMonitoring()); |
||||||
|
// 注册事件监听
|
||||||
|
inspector.addActionListener(e -> { |
||||||
|
if (inspector.isSelected()) { |
||||||
|
UIInspectorHolder.getInstance().install(); |
||||||
|
} else { |
||||||
|
UIInspectorHolder.getInstance().uninstall(); |
||||||
|
} |
||||||
|
}); |
||||||
|
strictEDTChecker.addActionListener(e -> { |
||||||
|
if (strictEDTChecker.isSelected()) { |
||||||
|
StrictEdtManager.install(); |
||||||
|
} else { |
||||||
|
StrictEdtManager.uninstall(); |
||||||
|
} |
||||||
|
}); |
||||||
|
monitor.addActionListener(e -> { |
||||||
|
topSettingRow.setVisible(monitor.isSelected()); |
||||||
|
tablePane.setVisible(monitor.isSelected()); |
||||||
|
if (monitor.isSelected()) { |
||||||
|
startMonitor(); |
||||||
|
} else { |
||||||
|
stopMonitor(); |
||||||
|
} |
||||||
|
}); |
||||||
|
// 初始化卡顿堆栈表
|
||||||
|
if (monitor.isSelected()) { |
||||||
|
SwingUtilities.invokeLater(() -> UILatencyWorker.getInstance().getAllLatencyInfo() |
||||||
|
.forEach(info -> model.addRow(parseInfo2Row(info)))); |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private Row initTopSettingRow() { |
||||||
|
UIComboBox comboBox = initThresholdComboBox(); |
||||||
|
UIButton export = new UIButton(new LazyIcon("export")); |
||||||
|
export.setToolTipText("Export latency log"); |
||||||
|
UIButton clear = new UIButton(new LazyIcon("remove")); |
||||||
|
clear.setToolTipText("Clear latency log"); |
||||||
|
|
||||||
|
JToolBar toolbar = new UIToolbar(); |
||||||
|
toolbar.add(comboBox); |
||||||
|
toolbar.add(clear); |
||||||
|
toolbar.add(export); |
||||||
|
|
||||||
|
export.addActionListener(e -> exportData()); |
||||||
|
clear.addActionListener(e -> { |
||||||
|
model.setRowCount(0); |
||||||
|
UILatencyWorker.getInstance().clearData(); |
||||||
|
}); |
||||||
|
|
||||||
|
return row(5, cell(new UILabel("Latency Threshold")), cell(toolbar)).getComponent(); |
||||||
|
} |
||||||
|
|
||||||
|
private static @NotNull UIComboBox initThresholdComboBox() { |
||||||
|
UIComboBox comboBox = new UIComboBox(Arrays.stream(LatencyLevel.values()) |
||||||
|
.filter(it -> it != LatencyLevel.FLASH).map(LatencyLevel::getStart).toArray()); |
||||||
|
comboBox.putClientProperty(FineClientProperties.COMBO_BOX_TYPE, FineClientProperties.ADAPTIVE_COMBO_BOX); |
||||||
|
comboBox.setSelectedItem(UILatencyInfoHandler.getInstance().getThreshold()); |
||||||
|
comboBox.addActionListener(e -> { |
||||||
|
if (comboBox.getSelectedItem() != null) { |
||||||
|
UILatencyWorker.getInstance().resetThreshold((Long) comboBox.getSelectedItem()); |
||||||
|
} |
||||||
|
}); |
||||||
|
// 阈值初始化
|
||||||
|
comboBox.setSelectedItem(comboBox.getSelectedItem()); |
||||||
|
return comboBox; |
||||||
|
} |
||||||
|
|
||||||
|
private UITableScrollPane initLatencyTable() { |
||||||
|
model = new DefaultTableModel(); |
||||||
|
model.addColumn("seq"); |
||||||
|
model.addColumn("cost(ms)"); |
||||||
|
model.addColumn("stack"); |
||||||
|
FineUITable table = new FineUITable(model) { |
||||||
|
public boolean isCellEditable(int row, int column) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
}; |
||||||
|
UITableScrollPane tablePane = new UITableScrollPane(table); |
||||||
|
table.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS); |
||||||
|
table.addMouseListener(new MouseAdapter() { |
||||||
|
@Override |
||||||
|
public void mouseClicked(MouseEvent e) { |
||||||
|
int row = table.rowAtPoint(e.getPoint()); |
||||||
|
if (row >= 0) { |
||||||
|
String stack = (String) table.getValueAt(row, 2); |
||||||
|
StackPane stackPane = new StackPane(stack); |
||||||
|
BasicDialog dialog = stackPane.showLargeWindow(SwingUtilities.getWindowAncestor(e.getComponent()), null); |
||||||
|
dialog.setAlwaysOnTop(true); |
||||||
|
dialog.setVisible(true); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
TableColumnModel columnModel = table.getColumnModel(); |
||||||
|
adjustColumnWidth(columnModel.getColumn(0)); |
||||||
|
adjustColumnWidth(columnModel.getColumn(1)); |
||||||
|
return tablePane; |
||||||
|
} |
||||||
|
|
||||||
|
private void adjustColumnWidth(TableColumn column) { |
||||||
|
column.setPreferredWidth(100); |
||||||
|
column.setMinWidth(100); |
||||||
|
column.setMaxWidth(100); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 开启性能监控 |
||||||
|
*/ |
||||||
|
public void startMonitor() { |
||||||
|
EventDispatcher.listen(LatencyMonitorEvent.OFF_THRESHOLD_EVENT, latencyInfoListener); |
||||||
|
UILatencyWorker.getInstance().start(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 关闭性能监控 |
||||||
|
*/ |
||||||
|
public void stopMonitor() { |
||||||
|
UILatencyWorker.getInstance().stop(); |
||||||
|
EventDispatcher.stopListen(latencyInfoListener); |
||||||
|
model.setRowCount(0); |
||||||
|
} |
||||||
|
|
||||||
|
private void exportData() { |
||||||
|
// 导出为txt文件
|
||||||
|
FILEChooserPane fileChooserPane = FILEChooserPane.getMultiEnvInstance(true, false); |
||||||
|
String fileName = "latency_log_" + GeneralUtils.objectToString(new Date()).replaceAll(":", "_"); |
||||||
|
fileChooserPane.setFileNameTextField(fileName, ".txt"); |
||||||
|
fileChooserPane.addChooseFILEFilter(new ChooseFileFilter(FileExtension.TXT)); |
||||||
|
int saveValue = fileChooserPane.showSaveDialog(DesignerContext.getDesignerFrame()); |
||||||
|
if (saveValue == FILEChooserPane.JOPTIONPANE_OK_OPTION || saveValue == FILEChooserPane.OK_OPTION) { |
||||||
|
FILE target = fileChooserPane.getSelectedFILE(); |
||||||
|
try { |
||||||
|
target.mkfile(); |
||||||
|
try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(target.getPath(), true))) { |
||||||
|
bufferedWriter.write(UILatencyWorker.getInstance().getLatencyData()); |
||||||
|
} |
||||||
|
} catch (Exception exp) { |
||||||
|
FineLoggerFactory.getLogger().error("[Latency] Error export latency log.", exp); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private final Listener<LatencyInfo> latencyInfoListener = new Listener<LatencyInfo>() { |
||||||
|
@Override |
||||||
|
public void on(Event event, LatencyInfo latencyInfo) { |
||||||
|
SwingUtilities.invokeLater(() -> { |
||||||
|
// 存量卡顿堆栈信息更新
|
||||||
|
for (int i = 0; i < model.getRowCount(); i++) { |
||||||
|
if (latencyInfo.getSeq() == (Long) model.getValueAt(i, 0)) { |
||||||
|
model.removeRow(i); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
model.addRow(parseInfo2Row(latencyInfo)); |
||||||
|
}); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
private Object[] parseInfo2Row(LatencyInfo latencyInfo) { |
||||||
|
return new Object[]{ |
||||||
|
latencyInfo.getSeq(), |
||||||
|
latencyInfo.getCost(), |
||||||
|
UIMonitorHelper.convertStack(latencyInfo.getDetailStack())}; |
||||||
|
} |
||||||
|
|
||||||
|
static class StackPane extends BasicPane { |
||||||
|
|
||||||
|
public StackPane(String stack) { |
||||||
|
setLayout(new BorderLayout()); |
||||||
|
UITextArea textArea = new UITextArea(); |
||||||
|
textArea.setBorder(null); |
||||||
|
textArea.setEditable(false); |
||||||
|
textArea.setText(stack); |
||||||
|
UIScrollPane scrollPane = new UIScrollPane(textArea); |
||||||
|
scrollPane.setBorder(FineBorderFactory.createWrappedRoundBorder()); |
||||||
|
add(scrollPane); |
||||||
|
SwingUtilities.invokeLater(() -> scrollPane.getViewport().setViewPosition(new Point(0, 0))); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected String title4PopupWindow() { |
||||||
|
return "Latency Stack"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1 +1,84 @@ |
|||||||
package com.fr.design.editor.editor;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.stable.ColumnRowGroup;
import java.awt.*;
/**
* Author : Shockway
* Date: 14-1-10
* Time: 下午1:46
*/
public class ColumnRowGroupEditor extends Editor<ColumnRowGroup> {
private UITextField crEditor;
public ColumnRowGroupEditor() {
this("");
}
public ColumnRowGroupEditor(String name) {
this(null, name);
}
public ColumnRowGroupEditor(ColumnRowGroup value) {
this(value, "");
}
public ColumnRowGroupEditor(ColumnRowGroup value, String name) {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
crEditor = new UITextField();
this.add(crEditor, BorderLayout.CENTER);
this.setValue(value);
this.setName(name);
}
@Override
public ColumnRowGroup getValue() {
return new ColumnRowGroup(this.crEditor.getText());
}
@Override
public void setValue(ColumnRowGroup value) {
if (value == null) {
this.crEditor.setText("");
} else {
this.crEditor.setText(value.toString());
}
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
this.crEditor.setEnabled(enabled);
}
/**
* 获取焦点
*/
public void requestFocus() {
this.crEditor.requestFocus();
}
public String getIconName() {
return "cell_group";
}
/**
* 是否接收/支持这个对象
* @param object 检测对象
* @return 是否支持
*/
public boolean accept(Object object) {
return object instanceof ColumnRowGroup;
}
} |
package com.fr.design.editor.editor; |
||||||
|
|
||||||
|
import com.fr.design.gui.itextfield.UITextField; |
||||||
|
import com.fr.design.layout.FRGUIPaneFactory; |
||||||
|
import com.fr.stable.ColumnRowGroup; |
||||||
|
|
||||||
|
import java.awt.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* 单元格组编辑 |
||||||
|
* |
||||||
|
* @author Shockway |
||||||
|
* @since 2014-01-10 |
||||||
|
* Created on 2024-01-10 |
||||||
|
*/ |
||||||
|
public class ColumnRowGroupEditor extends Editor<ColumnRowGroup> { |
||||||
|
|
||||||
|
private UITextField crEditor; |
||||||
|
|
||||||
|
public ColumnRowGroupEditor() { |
||||||
|
this(""); |
||||||
|
} |
||||||
|
|
||||||
|
public ColumnRowGroupEditor(String name) { |
||||||
|
this(null, name); |
||||||
|
} |
||||||
|
|
||||||
|
public ColumnRowGroupEditor(ColumnRowGroup value) { |
||||||
|
this(value, ""); |
||||||
|
} |
||||||
|
|
||||||
|
public ColumnRowGroupEditor(ColumnRowGroup value, String name) { |
||||||
|
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
||||||
|
crEditor = new UITextField(); |
||||||
|
this.add(crEditor, BorderLayout.CENTER); |
||||||
|
this.setValue(value); |
||||||
|
this.setName(name); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ColumnRowGroup getValue() { |
||||||
|
return new ColumnRowGroup(this.crEditor.getText()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setValue(ColumnRowGroup value) { |
||||||
|
if (value == null) { |
||||||
|
this.crEditor.setText(""); |
||||||
|
} else { |
||||||
|
this.crEditor.setText(value.toString()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setEnabled(boolean enabled) { |
||||||
|
super.setEnabled(enabled); |
||||||
|
|
||||||
|
this.crEditor.setEnabled(enabled); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取焦点 |
||||||
|
*/ |
||||||
|
public void requestFocus() { |
||||||
|
this.crEditor.requestFocus(); |
||||||
|
} |
||||||
|
|
||||||
|
public String getIconName() { |
||||||
|
return "cell_group"; |
||||||
|
} |
||||||
|
|
||||||
|
public String getIconId() { |
||||||
|
return "cell_group_popup"; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 是否接收/支持这个对象 |
||||||
|
* @param object 检测对象 |
||||||
|
* @return 是否支持 |
||||||
|
*/ |
||||||
|
public boolean accept(Object object) { |
||||||
|
return object instanceof ColumnRowGroup; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,56 @@ |
|||||||
|
package com.fr.design.i18n; |
||||||
|
|
||||||
|
import com.fr.config.ConfigContext; |
||||||
|
import com.fr.config.DefaultConfiguration; |
||||||
|
import com.fr.config.Identifier; |
||||||
|
import com.fr.config.holder.factory.Holders; |
||||||
|
import com.fr.config.holder.impl.MapConf; |
||||||
|
|
||||||
|
import java.util.Collections; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* 设计器语言扩展配置 |
||||||
|
* |
||||||
|
* @author obo |
||||||
|
* @since 11.0 |
||||||
|
* Created on 2024/09/26 |
||||||
|
*/ |
||||||
|
public class DesignExtendLanguageConfig extends DefaultConfiguration { |
||||||
|
|
||||||
|
private static volatile DesignExtendLanguageConfig designExtendLanguageConfig = null; |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取实例 |
||||||
|
*/ |
||||||
|
public static DesignExtendLanguageConfig getInstance() { |
||||||
|
if (designExtendLanguageConfig == null) { |
||||||
|
designExtendLanguageConfig = ConfigContext.getConfigInstance(DesignExtendLanguageConfig.class); |
||||||
|
} |
||||||
|
return designExtendLanguageConfig; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 设计器扩展的语言 |
||||||
|
* key为localeString,例如en_US或en;value为改语言对应的国际化翻译key |
||||||
|
*/ |
||||||
|
@Identifier("extendDesignLocales") |
||||||
|
private MapConf<Map<String, String>> extendDesignLocales = Holders.map(new HashMap<>(), String.class, String.class); |
||||||
|
|
||||||
|
public Map<String, String> getExtendedDesignLocales() { |
||||||
|
return Collections.unmodifiableMap(extendDesignLocales.get()); |
||||||
|
} |
||||||
|
|
||||||
|
public void setExtendedDesignLocales(Map<String, String> map) { |
||||||
|
extendDesignLocales.set(map); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object clone() throws CloneNotSupportedException { |
||||||
|
DesignExtendLanguageConfig cloned = (DesignExtendLanguageConfig) super.clone(); |
||||||
|
cloned.extendDesignLocales = ( MapConf<Map<String, String>>) extendDesignLocales.clone(); |
||||||
|
return cloned; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,158 +0,0 @@ |
|||||||
package com.fr.design.record.analyzer; |
|
||||||
|
|
||||||
import com.fr.base.OptimizeUtil; |
|
||||||
import com.fr.collect.Collect; |
|
||||||
import com.fr.design.record.analyzer.Interceptor.CollectInterceptor; |
|
||||||
import com.fr.concurrent.NamedThreadFactory; |
|
||||||
import com.fr.design.constants.DesignerLaunchStatus; |
|
||||||
import com.fr.design.record.analyzer.advice.CollectAdvice; |
|
||||||
import com.fr.design.record.analyzer.advice.DBMonitorAdvice; |
|
||||||
import com.fr.design.record.analyzer.advice.FaultToleranceAdvice; |
|
||||||
import com.fr.design.record.analyzer.advice.FocusAdvice; |
|
||||||
import com.fr.design.record.analyzer.advice.MonitorAdvice; |
|
||||||
import com.fr.design.record.analyzer.advice.PerformancePointAdvice; |
|
||||||
import com.fr.event.Event; |
|
||||||
import com.fr.event.EventDispatcher; |
|
||||||
import com.fr.event.Listener; |
|
||||||
import com.fr.event.Null; |
|
||||||
import com.fr.intelli.metrics.Compute; |
|
||||||
import com.fr.intelli.record.Focus; |
|
||||||
import com.fr.intelli.record.PerformancePoint; |
|
||||||
import com.fr.jvm.assist.FineAssist; |
|
||||||
import com.fr.module.Activator; |
|
||||||
import com.fr.module.extension.Prepare; |
|
||||||
import com.fr.record.analyzer.AnalyzerConfiguration; |
|
||||||
import com.fr.record.analyzer.AnalyzerKey; |
|
||||||
import com.fr.record.analyzer.Assistant; |
|
||||||
import com.fr.record.analyzer.DBMetrics; |
|
||||||
import com.fr.record.analyzer.FineAnalyzer; |
|
||||||
import com.fr.record.analyzer.advice.AnalyzerAdviceKey; |
|
||||||
import com.fr.record.analyzer.advice.FineAdviceAssistant; |
|
||||||
import com.fr.record.analyzer.configuration.AnalyzerAssemblyFactory; |
|
||||||
import com.fr.record.analyzer.configuration.FineAnalyzerAssemblyFactory; |
|
||||||
import com.fr.stable.collections.CollectionUtils; |
|
||||||
import com.fr.third.net.bytebuddy.description.type.TypeDescription; |
|
||||||
import com.fr.third.net.bytebuddy.dynamic.DynamicType; |
|
||||||
import com.fr.third.net.bytebuddy.implementation.MethodDelegation; |
|
||||||
import com.fr.third.net.bytebuddy.matcher.ElementMatchers; |
|
||||||
import com.fr.third.net.bytebuddy.utility.JavaModule; |
|
||||||
import com.fr.tolerance.FaultTolerance; |
|
||||||
import org.jetbrains.annotations.NotNull; |
|
||||||
|
|
||||||
import java.util.List; |
|
||||||
import java.util.concurrent.ExecutorService; |
|
||||||
|
|
||||||
/** |
|
||||||
* created by Harrison on 2022/03/04 |
|
||||||
**/ |
|
||||||
public class DesignerAnalyzerActivator extends Activator implements Prepare { |
|
||||||
|
|
||||||
@Override |
|
||||||
public void start() { |
|
||||||
|
|
||||||
OptimizeUtil.open(OptimizeUtil.Module.ANALYZER,() -> { |
|
||||||
|
|
||||||
AnalyzerAssemblyFactory basicFactory = createBasicFactory(); |
|
||||||
|
|
||||||
// 兼容逻辑
|
|
||||||
List<AnalyzerConfiguration> backwardsConfigurations = findMutableBackwards(AnalyzerKey.KEY); |
|
||||||
if (!CollectionUtils.isEmpty(backwardsConfigurations)) { |
|
||||||
// 直接初始化,不添加默认值,防止和下面的冲突
|
|
||||||
FineAnalyzer.initDirectly(FineAssist.findInstrumentation(), basicFactory, backwardsConfigurations.toArray(new AnalyzerConfiguration[0])); |
|
||||||
} |
|
||||||
|
|
||||||
// 等页面完全打开后,再进行 retransform, 别影响了启动速度
|
|
||||||
EventDispatcher.listen(DesignerLaunchStatus.STARTUP_COMPLETE, new Listener<Null>() { |
|
||||||
|
|
||||||
@Override |
|
||||||
public void on(Event event, Null param) { |
|
||||||
|
|
||||||
ExecutorService es = newSingleThreadExecutor(new NamedThreadFactory("designer-analyzer", true)); |
|
||||||
try { |
|
||||||
// 加入 retransform 部分的逻辑
|
|
||||||
List<FineAdviceAssistant> adviceConfigurations = findMutable(AnalyzerAdviceKey.KEY); |
|
||||||
|
|
||||||
if (!CollectionUtils.isEmpty(adviceConfigurations)) { |
|
||||||
AnalyzerConfiguration[] configurations = convertConfigurations(adviceConfigurations); |
|
||||||
es.submit(() -> { |
|
||||||
DesignerAnalyzer.init(basicFactory, configurations); |
|
||||||
}); |
|
||||||
} |
|
||||||
} finally { |
|
||||||
es.shutdown(); |
|
||||||
} |
|
||||||
} |
|
||||||
}); |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
@NotNull |
|
||||||
private AnalyzerConfiguration[] convertConfigurations(List<FineAdviceAssistant> list) { |
|
||||||
|
|
||||||
return list.stream() |
|
||||||
.map(AnalyzerConfiguration::create) |
|
||||||
.toArray(AnalyzerConfiguration[]::new); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void stop() { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void prepare() { |
|
||||||
|
|
||||||
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create( |
|
||||||
ElementMatchers.isAnnotatedWith(Focus.class), |
|
||||||
FocusAdvice.class |
|
||||||
)); |
|
||||||
|
|
||||||
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create( |
|
||||||
ElementMatchers.isAnnotatedWith(Compute.class), |
|
||||||
MonitorAdvice.class |
|
||||||
)); |
|
||||||
|
|
||||||
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create( |
|
||||||
ElementMatchers.isAnnotatedWith(DBMetrics.class), |
|
||||||
DBMonitorAdvice.class |
|
||||||
)); |
|
||||||
|
|
||||||
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create( |
|
||||||
ElementMatchers.isAnnotatedWith(PerformancePoint.class), |
|
||||||
PerformancePointAdvice.class |
|
||||||
)); |
|
||||||
|
|
||||||
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create( |
|
||||||
ElementMatchers.isAnnotatedWith(FaultTolerance.class), |
|
||||||
FaultToleranceAdvice.class |
|
||||||
)); |
|
||||||
|
|
||||||
// 保持M1 可用
|
|
||||||
addMutable(AnalyzerKey.KEY, AnalyzerConfiguration.create(new Assistant() { |
|
||||||
|
|
||||||
@Override |
|
||||||
public DynamicType.Builder<?> supply(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) { |
|
||||||
|
|
||||||
return builder |
|
||||||
.method(ElementMatchers.isAnnotatedWith(Collect.class)) |
|
||||||
.intercept(MethodDelegation.to(CollectInterceptor.class)); |
|
||||||
} |
|
||||||
})); |
|
||||||
|
|
||||||
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create( |
|
||||||
ElementMatchers.isAnnotatedWith(Collect.class), |
|
||||||
CollectAdvice.class |
|
||||||
)); |
|
||||||
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private AnalyzerAssemblyFactory createBasicFactory() { |
|
||||||
|
|
||||||
AnalyzerAssemblyFactory factory = findSingleton(AnalyzerAssemblyFactory.class); |
|
||||||
FineAnalyzerAssemblyFactory basicFactory = new FineAnalyzerAssemblyFactory(); |
|
||||||
basicFactory.prepare(factory); |
|
||||||
return basicFactory; |
|
||||||
} |
|
||||||
} |
|
@ -1,27 +0,0 @@ |
|||||||
package com.fr.env; |
|
||||||
|
|
||||||
import com.fr.env.detect.EnvDetectorCenter; |
|
||||||
import com.fr.module.Activator; |
|
||||||
|
|
||||||
/** |
|
||||||
* 设计器环境准备 |
|
||||||
* 更多的是一些钩子,需要在环境启动、切换时进行处理 |
|
||||||
* 使用监听 {@link com.fr.workspace.WorkspaceEvent} 只能满足 |
|
||||||
* before -> stop -> start -> after |
|
||||||
* 现在支持 => |
|
||||||
* before -> stop -> prepare -> start -> after |
|
||||||
* |
|
||||||
* created by Harrison on 2022/05/29 |
|
||||||
**/ |
|
||||||
public class EnvPrepare extends Activator { |
|
||||||
|
|
||||||
@Override |
|
||||||
public void start() { |
|
||||||
EnvDetectorCenter.getInstance().init(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void stop() { |
|
||||||
EnvDetectorCenter.getInstance().destroy(); |
|
||||||
} |
|
||||||
} |
|
@ -1,156 +0,0 @@ |
|||||||
package com.fr.start.server; |
|
||||||
|
|
||||||
import com.fr.cbb.websocket.core.WebSocketEndpoint; |
|
||||||
import com.fr.design.DesignerEnvManager; |
|
||||||
import com.fr.log.FineLoggerFactory; |
|
||||||
import com.fr.module.Activator; |
|
||||||
import com.fr.module.ModuleRole; |
|
||||||
import com.fr.stable.EncodeConstants; |
|
||||||
import com.fanruan.product.ProductConstants; |
|
||||||
import com.fr.stable.StringUtils; |
|
||||||
import com.fr.third.springframework.web.SpringServletContainerInitializer; |
|
||||||
import com.fr.third.springframework.web.context.support.AnnotationConfigWebApplicationContext; |
|
||||||
import com.fr.workspace.WorkContext; |
|
||||||
import org.apache.catalina.Context; |
|
||||||
import org.apache.catalina.LifecycleException; |
|
||||||
import org.apache.catalina.loader.WebappLoader; |
|
||||||
import org.apache.catalina.startup.Tomcat; |
|
||||||
import org.apache.catalina.webresources.StandardRoot; |
|
||||||
import org.apache.tomcat.websocket.server.WsSci; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.util.HashSet; |
|
||||||
import java.util.Set; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by juhaoyu on 2018/6/5. |
|
||||||
*/ |
|
||||||
@Deprecated |
|
||||||
public class FineEmbedServerActivator extends Activator { |
|
||||||
|
|
||||||
private static final String TOMCAT_MAX_HEADER_SIZE = "tomcat-maxHttpHeaderSize"; |
|
||||||
|
|
||||||
private Tomcat tomcat; |
|
||||||
|
|
||||||
@Override |
|
||||||
public synchronized void start() { |
|
||||||
|
|
||||||
try { |
|
||||||
FineEmbedServerMonitor.getInstance().reset(); |
|
||||||
//初始化tomcat
|
|
||||||
initTomcat(); |
|
||||||
tomcat.start(); |
|
||||||
|
|
||||||
} catch (LifecycleException e) { |
|
||||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
||||||
} finally { |
|
||||||
FineEmbedServerMonitor.getInstance().setComplete(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public synchronized void stop() { |
|
||||||
|
|
||||||
try { |
|
||||||
stopSpring(); |
|
||||||
stopServerActivator(); |
|
||||||
stopTomcat(); |
|
||||||
} catch (Exception e) { |
|
||||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void initTomcat() { |
|
||||||
|
|
||||||
tomcat = new Tomcat(); |
|
||||||
|
|
||||||
tomcat.setPort(DesignerEnvManager.getEnvManager().getEmbedServerPort()); |
|
||||||
// 设置解码uri使用的字符编码
|
|
||||||
tomcat.getConnector().setURIEncoding(EncodeConstants.ENCODING_UTF_8); |
|
||||||
// 参考 https://jira.atlassian.com/browse/CONFSERVER-57582
|
|
||||||
// https://tomcat.apache.org/tomcat-8.5-doc/config/http.html
|
|
||||||
// 8.5.x 请求参数带特殊字符被tomcat拒绝 []|{}^\`"<>
|
|
||||||
tomcat.getConnector().setProperty("relaxedQueryChars", "[]|{}^\`"<>"); |
|
||||||
setMaxPostSize(); |
|
||||||
setMaxHttpHeaderSize(); |
|
||||||
String docBase = new File(WorkContext.getCurrent().getPath()).getParent(); |
|
||||||
|
|
||||||
//内置的上下文使用工程目录比如webroot
|
|
||||||
String contextPath = "/" + ProductConstants.getAppFolderName(); |
|
||||||
final Context context = tomcat.addContext(contextPath, docBase); |
|
||||||
context.setResources(new StandardRoot(context)); |
|
||||||
Tomcat.initWebappDefaults(context); |
|
||||||
//覆盖tomcat的WebAppClassLoader
|
|
||||||
context.setLoader(new FRTomcatLoader()); |
|
||||||
|
|
||||||
|
|
||||||
//直接指定initializer,tomcat就不用再扫描一遍了
|
|
||||||
SpringServletContainerInitializer initializer = new SpringServletContainerInitializer(); |
|
||||||
Set<Class<?>> classes = new HashSet<Class<?>>(); |
|
||||||
/// 该Initializer已去除
|
|
||||||
//classes.add(FineWebApplicationInitializer.class);
|
|
||||||
context.addServletContainerInitializer(initializer, classes); |
|
||||||
// 后面本地设计的内置服务器考虑用XST
|
|
||||||
// context.addServletContainerInitializer(new WsSci(), Sets.newHashSet(WebSocketEndpoint.class));
|
|
||||||
} |
|
||||||
|
|
||||||
// tomcat的maxPostSize会影响到post参数获取,默认2M
|
|
||||||
private void setMaxPostSize() { |
|
||||||
|
|
||||||
if (System.getProperty("tomcat-maxPostSize") != null) { |
|
||||||
try { |
|
||||||
tomcat.getConnector().setMaxPostSize(Integer.parseInt(System.getProperty("tomcat-maxPostSize"))); |
|
||||||
} catch (Exception e) { |
|
||||||
FineLoggerFactory.getLogger().error("maxPostSize error: " + e.getMessage(), e); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void setMaxHttpHeaderSize() { |
|
||||||
String value = System.getProperty(TOMCAT_MAX_HEADER_SIZE); |
|
||||||
if (StringUtils.isNotEmpty(value)) { |
|
||||||
try { |
|
||||||
tomcat.getConnector().setProperty("maxHttpHeaderSize", value); |
|
||||||
} catch (Exception e) { |
|
||||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private void stopServerActivator() { |
|
||||||
|
|
||||||
ModuleRole.ServerRoot.stop(); |
|
||||||
} |
|
||||||
|
|
||||||
private void stopSpring() { |
|
||||||
|
|
||||||
AnnotationConfigWebApplicationContext context = ModuleRole.ServerRoot.findSingleton(AnnotationConfigWebApplicationContext.class); |
|
||||||
if (context != null) { |
|
||||||
context.stop(); |
|
||||||
context.destroy(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void stopTomcat() throws LifecycleException { |
|
||||||
|
|
||||||
tomcat.stop(); |
|
||||||
tomcat.destroy(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Created by juhaoyu on 2018/6/5. |
|
||||||
* 自定义的tomcat loader,主要用于防止内置服务器再加载一遍class |
|
||||||
*/ |
|
||||||
private static class FRTomcatLoader extends WebappLoader { |
|
||||||
|
|
||||||
@Override |
|
||||||
public ClassLoader getClassLoader() { |
|
||||||
|
|
||||||
return this.getClass().getClassLoader(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 361 B |
After Width: | Height: | Size: 362 B |
After Width: | Height: | Size: 340 B |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 985 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 42 KiB |