Browse Source

Merge pull request #1428 in BA/design from ~VITO/design:release/9.0 to release/9.0

* commit 'fba3595d78074ec212b7f56d25e2d86ab8b05194':
  无jira任务 SonarQube
  无jira任务 SonarQube
  refact: 增加ThreadFactoryBuilder
  REPORT-5518 [9.0三轮回归]jdk1.7的设计器起不来
master
neil 7 years ago
parent
commit
1c9aa222c4
  1. 51
      designer/src/com/fr/design/mainframe/bbs/UserInfoLabel.java
  2. 42
      designer/src/com/fr/start/Designer.java
  3. 15
      designer_base/src/com/fr/design/extra/LoginWebBridge.java
  4. 21
      designer_base/src/com/fr/design/extra/PluginWebBridge.java
  5. 6
      designer_base/src/com/fr/design/extra/ShopManagerPane.java
  6. 60
      designer_base/src/com/fr/design/extra/WebViewDlgHelper.java
  7. 178
      designer_base/src/com/fr/design/utils/concurrent/ThreadFactoryBuilder.java

51
designer/src/com/fr/design/mainframe/bbs/UserInfoLabel.java

@ -7,28 +7,43 @@ import com.fr.base.ConfigManager;
import com.fr.base.FRContext;
import com.fr.design.DesignerEnvManager;
import com.fr.design.bbs.BBSLoginUtils;
import com.fr.design.extra.*;
import com.fr.design.extra.LoginContextListener;
import com.fr.design.extra.LoginWebBridge;
import com.fr.design.extra.PluginWebBridge;
import com.fr.design.extra.UserLoginContext;
import com.fr.design.extra.WebViewDlgHelper;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.imenu.UIMenuItem;
import com.fr.design.gui.imenu.UIPopupMenu;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.utils.concurrent.ThreadFactoryBuilder;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.general.ComparatorUtils;
import com.fr.general.DateUtils;
import com.fr.general.Inter;
import com.fr.general.SiteCenter;
import com.fr.general.http.HttpClient;
import com.fr.stable.*;
import javax.swing.*;
import java.awt.*;
import com.fr.stable.EncodeConstants;
import com.fr.stable.OperatingSystem;
import com.fr.stable.StringUtils;
import javax.swing.SwingConstants;
import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.Frame;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author neil
@ -72,6 +87,10 @@ public class UserInfoLabel extends UILabel {
}
public UserInfoLabel(UserInfoPane userInfoPane) {
init(userInfoPane);
}
private void init(UserInfoPane userInfoPane) {
this.userInfoPane = userInfoPane;
String userName = ConfigManager.getProviderInstance().getBbsUsername();
@ -104,8 +123,13 @@ public class UserInfoLabel extends UILabel {
* showBBSDialog 弹出BBS资讯框
*/
public static void showBBSDialog() {
Thread showBBSThread = new Thread(new Runnable() {
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("bbs-dlg-thread-%s").build();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1), namedThreadFactory);
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
// vito:最新mac10.12和javafx弹出框初始化时会有大几率卡死在native方法,这里先屏蔽一下。
@ -127,18 +151,21 @@ public class UserInfoLabel extends UILabel {
return;
}
String res = hc.getResponseText();
if (res.indexOf(BBSConstants.UPDATE_KEY) == -1) {
if (!res.contains(BBSConstants.UPDATE_KEY)) {
return;
}
try {
BBSDialog bbsLabel = new BBSDialog(DesignerContext.getDesignerFrame());
bbsLabel.showWindow(SiteCenter.getInstance().acquireUrlByKind("bbs.popup"));
Class<?> clazz = Class.forName("com.fr.design.mainframe.bbs.BBSDialog");
Constructor constructor = clazz.getConstructor(Frame.class);
Object instance = constructor.newInstance(DesignerContext.getDesignerFrame());
Method showWindow = clazz.getMethod("showWindow", String.class);
showWindow.invoke(instance, SiteCenter.getInstance().acquireUrlByKind("bbs.popup"));
DesignerEnvManager.getEnvManager().setLastShowBBSNewsTime(DateUtils.DATEFORMAT2.format(new Date()));
} catch (Throwable e) {
} catch (Throwable ignored) {
// ignored
}
}
});
showBBSThread.start();
}
private void sleep(long millis) {

42
designer/src/com/fr/start/Designer.java

@ -20,7 +20,12 @@ import com.fr.design.gui.ibutton.UIPreviewButton;
import com.fr.design.gui.imenu.UIMenuItem;
import com.fr.design.gui.imenu.UIPopupMenu;
import com.fr.design.gui.itoolbar.UILargeToolbar;
import com.fr.design.mainframe.*;
import com.fr.design.mainframe.ActiveKeyGenerator;
import com.fr.design.mainframe.BaseJForm;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.InformationCollector;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.JWorkBook;
import com.fr.design.mainframe.alphafine.component.AlphaFinePane;
import com.fr.design.mainframe.bbs.UserInfoLabel;
import com.fr.design.mainframe.bbs.UserInfoPane;
@ -31,22 +36,30 @@ import com.fr.design.menu.SeparatorDef;
import com.fr.design.menu.ShortCut;
import com.fr.design.module.DesignModuleFactory;
import com.fr.design.module.DesignerModule;
import com.fr.design.utils.concurrent.ThreadFactoryBuilder;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.general.ComparatorUtils;
import com.fr.general.Inter;
import com.fr.stable.ProductConstants;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
import com.fr.stable.web.ServletContext;
import com.fr.stable.xml.XMLTools;
import javax.swing.*;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.border.MatteBorder;
import java.awt.*;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Designer extends BaseDesigner {
private static final int TOOLBARPANEVGAP = -4;
@ -147,6 +160,7 @@ public class Designer extends BaseDesigner {
private JPanel generateEmptyGap(final int width) {
JPanel panel = new JPanel() {
@Override
public Dimension getPreferredSize() {
Dimension dim = super.getPreferredSize();
dim.width = width;
@ -163,6 +177,7 @@ public class Designer extends BaseDesigner {
*
* @return 按钮
*/
@Override
public UIButton[] createUp() {
return new UIButton[]{createSaveButton(), createUndoButton(), createRedoButton()};
}
@ -218,10 +233,12 @@ public class Designer extends BaseDesigner {
private void createRunButton(UILargeToolbar largeToolbar) {
run = new UIPreviewButton(new UIButton(UIConstants.PAGE_BIG_ICON) {
@Override
public Dimension getPreferredSize() {
return new Dimension(34, 34);
}
}, new UIButton(UIConstants.PREVIEW_DOWN) {
@Override
public Dimension getPreferredSize() {
return new Dimension(34, 10);
}
@ -296,6 +313,7 @@ public class Designer extends BaseDesigner {
* @param plus 对象
* @return 更新后的toolbar
*/
@Override
public JComponent resetToolBar(JComponent toolbarComponent, ToolBarMenuDockPlus plus) {
//如果是处于权限编辑状态
if (BaseUtils.isAuthorityEditing()) {
@ -339,6 +357,7 @@ public class Designer extends BaseDesigner {
*
* @return 面板组件
*/
@Override
public Component createBBSLoginPane() {
if (userInfoPane == null) {
userInfoPane = new UserInfoPane();
@ -351,11 +370,13 @@ public class Designer extends BaseDesigner {
*
* @return 面板组件
*/
@Override
public Component createAlphaFinePane() {
return AlphaFinePane.getAlphaFinePane();
}
@Override
protected SplashPane createSplashPane() {
return new ReportSplashPane();
}
@ -363,6 +384,7 @@ public class Designer extends BaseDesigner {
/**
* 收集用户信息吗
*/
@Override
protected void collectUserInformation() {
//定制的就不弹出来了
if (!ComparatorUtils.equals(ProductConstants.APP_NAME, ProductConstants.DEFAULT_APP_NAME)) {
@ -395,14 +417,19 @@ public class Designer extends BaseDesigner {
int status = envManager.getActiveKeyStatus();
//没有联网验证过
if (status != 0) {
Thread authThread = new Thread(new Runnable() {
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("net-verify-thread-%s").build();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1),
namedThreadFactory);
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
ActiveKeyGenerator.onLineVerify(key);
}
});
authThread.start();
}
}
@ -443,6 +470,7 @@ public class Designer extends BaseDesigner {
/**
* 设计器退出时, 做的一些操作.
*/
@Override
public void shutDown() {
InformationCollector collector = InformationCollector.getInstance();
collector.collectStopTime();

15
designer_base/src/com/fr/design/extra/LoginWebBridge.java

@ -8,6 +8,7 @@ import com.fr.design.extra.exe.PluginLoginExecutor;
import com.fr.design.extra.ucenter.Client;
import com.fr.design.extra.ucenter.XMLHelper;
import com.fr.design.gui.ilable.UILabel;
import com.fr.general.ComparatorUtils;
import com.fr.general.SiteCenter;
import com.fr.general.http.HttpClient;
import com.fr.json.JSONObject;
@ -63,7 +64,7 @@ public class LoginWebBridge {
private UILabel uiLabel;
private WebEngine webEngine;
public LoginWebBridge() {
private LoginWebBridge() {
}
public static LoginWebBridge getHelper() {
@ -92,7 +93,7 @@ public class LoginWebBridge {
return messageCount;
}
public void setQqDialog(UIDialog qqDialog) {
public void setQQDialog(UIDialog qqDialog) {
closeQQWindow();
this.qqDialog = qqDialog;
}
@ -282,9 +283,9 @@ public class LoginWebBridge {
try {
JSONObject jo = new JSONObject(userInfo);
String status = jo.get("status").toString();
if (status.equals(LOGIN_SUCCESS)) {
if (ComparatorUtils.equals(status, LOGIN_SUCCESS)) {
String username = jo.get("username").toString();
int uid = Integer.parseInt(jo.get("uid") == null ? "" : jo.get("uid").toString());
int uid = Integer.parseInt(jo.get("uid") == null ? StringUtils.EMPTY : jo.get("uid").toString());
closeQQWindow();
loginSuccess(username);
@ -293,18 +294,18 @@ public class LoginWebBridge {
list.add(username);
list.add(StringUtils.EMPTY);
BBSLoginUtils.bbsLogin(list);
} else if (status.equals(LOGIN_FAILED)) {
} else if (ComparatorUtils.equals(status, LOGIN_FAILED)) {
//账号没有QQ授权
closeQQWindow();
try {
Desktop.getDesktop().browse(new URI(SiteCenter.getInstance().acquireUrlByKind("QQ_binding")));
} catch (Exception exp) {
} catch (Exception ignored) {
// ignored
}
}
} catch (Exception e) {
FRContext.getLogger().error(e.getMessage());
}
}
public void openUrlAtLocalWebBrowser(WebEngine eng, String url) {

21
designer_base/src/com/fr/design/extra/PluginWebBridge.java

@ -7,12 +7,13 @@ import com.fr.design.bbs.BBSLoginUtils;
import com.fr.design.dialog.UIDialog;
import com.fr.design.extra.exe.GetPluginCategoriesExecutor;
import com.fr.design.extra.exe.GetPluginFromStoreExecutor;
import com.fr.design.extra.exe.GetPluginPrefixExecutor;
import com.fr.design.extra.exe.PluginLoginExecutor;
import com.fr.design.extra.exe.ReadUpdateOnlineExecutor;
import com.fr.design.extra.exe.SearchOnlineExecutor;
import com.fr.design.extra.exe.callback.JSCallback;
import com.fr.design.extra.exe.GetPluginPrefixExecutor;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.utils.concurrent.ThreadFactoryBuilder;
import com.fr.general.FRLogger;
import com.fr.general.Inter;
import com.fr.general.SiteCenter;
@ -28,6 +29,7 @@ import javafx.scene.web.WebEngine;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import netscape.javascript.JSObject;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
@ -41,25 +43,34 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 开放给Web组件的接口,用于安装,卸载,更新以及更改插件可用状态
*/
public class PluginWebBridge {
private static final String THREAD_NAME_TEMPLATE = "pluginbridge-thread-%s";
private static final String ACTION = "action";
private static final String KEYWORD = "keyword";
private static final int COREPOOLSIZE = 3;
private static final int MAXPOOLSIZE = 5;
private static PluginWebBridge helper;
private UIDialog uiDialog;
private ACTIONS action;
private String ACTION = "action";
private String KEYWORD = "keyword";
private Map<String, Object> config;
private WebEngine webEngine;
private UILabel uiLabel;
private ExecutorService threadPoolExecutor = Executors.newSingleThreadExecutor();
private ExecutorService threadPoolExecutor = new ThreadPoolExecutor(COREPOOLSIZE, MAXPOOLSIZE,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(COREPOOLSIZE),
new ThreadFactoryBuilder().setNameFormat(THREAD_NAME_TEMPLATE).build());
/**
* 动作枚举

6
designer_base/src/com/fr/design/extra/ShopManagerPane.java

@ -2,9 +2,9 @@ package com.fr.design.extra;
import com.fr.design.dialog.BasicPane;
import com.fr.general.Inter;
import javafx.embed.swing.JFXPanel;
import java.awt.*;
import java.awt.BorderLayout;
import java.awt.Component;
/**
* @author richie
@ -19,7 +19,7 @@ import java.awt.*;
*/
public class ShopManagerPane extends BasicPane {
public ShopManagerPane(JFXPanel webPane) {
public ShopManagerPane(Component webPane) {
setLayout(new BorderLayout());
add(webPane, BorderLayout.CENTER);
}

60
designer_base/src/com/fr/design/extra/WebViewDlgHelper.java

@ -17,23 +17,28 @@ import com.fr.plugin.PluginVerifyException;
import com.fr.stable.EnvChangedListener;
import com.fr.stable.StableUtils;
import javax.swing.*;
import java.awt.*;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
import java.awt.BorderLayout;
import java.awt.Component;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.net.HttpURLConnection;
import java.util.concurrent.ExecutionException;
/**
* Created by vito on 2016/9/28.
* 在合适的 jre 环境下创建带有 WebView 的窗口
*
* @author vito
* @date 2016/9/28
*/
public class WebViewDlgHelper {
private static final String LATEST = "latest";
private static final String SHOP_SCRIPTS = "shop_scripts";
private static final int VERSION_8 = 8;
// 调试时,使用installHome = ClassLoader.getSystemResource("").getPath()代替下面
private static String installHome = FRContext.getCurrentEnv().getWebReportPath();
private static final int BYTES_NUM = 1024;
@ -146,24 +151,46 @@ public class WebViewDlgHelper {
}
public static void createQQLoginDialog() {
QQLoginWebPane webPane = new QQLoginWebPane(new File(installHome).getAbsolutePath());
UIDialog qqlog = new QQLoginDialog(DesignerContext.getDesignerFrame(), webPane);
LoginWebBridge.getHelper().setQqDialog(qqlog);
qqlog.setVisible(true);
try {
Class<?> clazz = Class.forName("com.fr.design.extra.QQLoginWebPane");
Constructor constructor = clazz.getConstructor(String.class);
Component webPane = (Component) constructor.newInstance(new File(installHome).getAbsolutePath());
UIDialog qqLoginDialog = new QQLoginDialog(DesignerContext.getDesignerFrame(), webPane);
LoginWebBridge.getHelper().setQQDialog(qqLoginDialog);
qqLoginDialog.setVisible(true);
} catch (Throwable ignored) {
// ignored
}
}
private static void showPluginDlg(String mainJsPath) {
BasicPane managerPane = new ShopManagerPane(new PluginWebPane(mainJsPath));
UIDialog dlg = new ShopDialog(DesignerContext.getDesignerFrame(), managerPane);
PluginWebBridge.getHelper().setDialogHandle(dlg);
dlg.setVisible(true);
try {
Class<?> clazz = Class.forName("com.fr.design.extra.PluginWebPane");
Constructor constructor = clazz.getConstructor(String.class);
Component webPane = (Component) constructor.newInstance(mainJsPath);
BasicPane managerPane = new ShopManagerPane(webPane);
UIDialog dlg = new ShopDialog(DesignerContext.getDesignerFrame(), managerPane);
PluginWebBridge.getHelper().setDialogHandle(dlg);
dlg.setVisible(true);
} catch (Throwable ignored) {
// ignored
}
}
private static void showLoginDlg() {
LoginWebPane webPane = new LoginWebPane(installHome);
UIDialog qqdlg = new LoginDialog(DesignerContext.getDesignerFrame(), webPane);
LoginWebBridge.getHelper().setDialogHandle(qqdlg);
qqdlg.setVisible(true);
try {
Class<?> clazz = Class.forName("com.fr.design.extra.LoginWebPane");
Constructor constructor = clazz.getConstructor(String.class);
Component webPane = (Component) constructor.newInstance(installHome);
UIDialog qqdlg = new LoginDialog(DesignerContext.getDesignerFrame(), webPane);
LoginWebBridge.getHelper().setDialogHandle(qqdlg);
qqdlg.setVisible(true);
} catch (Throwable ignored) {
// ignored
}
}
private static Component initTraditionalStore() {
@ -183,6 +210,7 @@ public class WebViewDlgHelper {
PluginUtils.downloadShopScripts(scriptsId, new Process<Double>() {
@Override
public void process(Double integer) {
// 这个注释毫无意义,就是为了通过SonarQube
}
});
} catch (PluginVerifyException e) {

178
designer_base/src/com/fr/design/utils/concurrent/ThreadFactoryBuilder.java

@ -0,0 +1,178 @@
/*
* Copyright (C) 2010 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.fr.design.utils.concurrent;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Locale;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
/**
* A ThreadFactory builder, providing any combination of these features:
* <ul>
* <li>whether threads should be marked as {@linkplain Thread#setDaemon daemon} threads
* <li>a {@linkplain ThreadFactoryBuilder#setNameFormat naming format}
* <li>a {@linkplain Thread#setPriority thread priority}
* <li>an {@linkplain Thread#setUncaughtExceptionHandler uncaught exception handler}
* <li>a {@linkplain ThreadFactory#newThread backing thread factory}
* </ul>
* <p>If no backing thread factory is provided, a default backing thread factory is used as if by
* calling {@code setThreadFactory(}{@link Executors#defaultThreadFactory()}{@code )}.
*
* @author Kurt Alfred Kluever
* @since 4.0
*/
public final class ThreadFactoryBuilder {
private String nameFormat = null;
private Boolean daemon = null;
private Integer priority = null;
private UncaughtExceptionHandler uncaughtExceptionHandler = null;
private ThreadFactory backingThreadFactory = null;
/**
* Creates a new {@link ThreadFactory} builder.
*/
public ThreadFactoryBuilder() {
// 这个注释毫无意义,就是为了通过SonarQube
}
/**
* Sets the naming format to use when naming threads ({@link Thread#setName}) which are created
* with this ThreadFactory.
*
* @param nameFormat a {@link String#format(String, Object...)}-compatible format String, to which
* a unique integer (0, 1, etc.) will be supplied as the single parameter. This integer will
* be unique to the built instance of the ThreadFactory and will be assigned sequentially. For
* example, {@code "rpc-pool-%d"} will generate thread names like {@code "rpc-pool-0"},
* {@code "rpc-pool-1"}, {@code "rpc-pool-2"}, etc.
* @return this for the builder pattern
*/
public ThreadFactoryBuilder setNameFormat(String nameFormat) {
String unused = format(nameFormat, 0); // fail fast if the format is bad or null
this.nameFormat = nameFormat;
return this;
}
/**
* Sets daemon or not for new threads created with this ThreadFactory.
*
* @param daemon whether or not new Threads created with this ThreadFactory will be daemon threads
* @return this for the builder pattern
*/
public ThreadFactoryBuilder setDaemon(boolean daemon) {
this.daemon = daemon;
return this;
}
/**
* Sets the priority for new threads created with this ThreadFactory.
*
* @param priority the priority for new Threads created with this ThreadFactory
* @return this for the builder pattern
*/
public ThreadFactoryBuilder setPriority(int priority) {
// Thread#setPriority() already checks for validity. These error messages
// are nicer though and will fail-fast.
if (priority < Thread.MIN_PRIORITY) {
throw new IllegalArgumentException(format("Thread priority (%s) must be >= %s", priority, Thread.MIN_PRIORITY));
}
if (priority > Thread.MAX_PRIORITY) {
throw new IllegalArgumentException(format("Thread priority (%s) must be <= %s", priority, Thread.MAX_PRIORITY));
}
this.priority = priority;
return this;
}
/**
* Sets the {@link UncaughtExceptionHandler} for new threads created with this ThreadFactory.
*
* @param uncaughtExceptionHandler the uncaught exception handler for new Threads created with
* this ThreadFactory
* @return this for the builder pattern
*/
public ThreadFactoryBuilder setUncaughtExceptionHandler(
UncaughtExceptionHandler uncaughtExceptionHandler) {
if (uncaughtExceptionHandler == null) {
throw new NullPointerException();
}
this.uncaughtExceptionHandler = uncaughtExceptionHandler;
return this;
}
/**
* Sets the backing {@link ThreadFactory} for new threads created with this ThreadFactory. Threads
* will be created by invoking #newThread(Runnable) on this backing {@link ThreadFactory}.
*
* @param backingThreadFactory the backing {@link ThreadFactory} which will be delegated to during
* thread creation.
* @return this for the builder pattern
*/
public ThreadFactoryBuilder setThreadFactory(ThreadFactory backingThreadFactory) {
if (backingThreadFactory == null) {
throw new NullPointerException();
}
this.backingThreadFactory = backingThreadFactory;
return this;
}
/**
* Returns a new thread factory using the options supplied during the building process. After
* building, it is still possible to change the options used to build the ThreadFactory and/or
* build again. State is not shared amongst built instances.
*
* @return the fully constructed {@link ThreadFactory}
*/
public ThreadFactory build() {
return doBuild(this);
}
// Split out so that the anonymous ThreadFactory can't contain a reference back to the builder.
// At least, I assume that's why. TODO(cpovirk): Check, and maybe add a test for this.
private static ThreadFactory doBuild(ThreadFactoryBuilder builder) {
final String nameFormat = builder.nameFormat;
final Boolean daemon = builder.daemon;
final Integer priority = builder.priority;
final UncaughtExceptionHandler uncaughtExceptionHandler = builder.uncaughtExceptionHandler;
final ThreadFactory backingThreadFactory =
(builder.backingThreadFactory != null)
? builder.backingThreadFactory
: Executors.defaultThreadFactory();
final AtomicLong count = (nameFormat != null) ? new AtomicLong(0) : null;
return new ThreadFactory() {
@Override
public Thread newThread(Runnable runnable) {
Thread thread = backingThreadFactory.newThread(runnable);
if (nameFormat != null) {
thread.setName(format(nameFormat, count.getAndIncrement()));
}
if (daemon != null) {
thread.setDaemon(daemon);
}
if (priority != null) {
thread.setPriority(priority);
}
if (uncaughtExceptionHandler != null) {
thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
}
return thread;
}
};
}
private static String format(String format, Object... args) {
return String.format(Locale.ROOT, format, args);
}
}
Loading…
Cancel
Save