statusCallback) throws ClientException {
// Initialize the send message dialog
editMessageDialog = new EditMessageDialog();
this.mirthClient = mirthClient;
- login.setStatus("Loading extensions...");
+ statusCallback.accept("Loading extensions...");
try {
loadExtensionMetaData();
} catch (ClientException e) {
@@ -589,10 +583,10 @@ public void setupFrame(Client mirthClient) throws ClientException {
}
setInitialVisibleTasks();
- login.setStatus("Loading preferences...");
+ statusCallback.accept("Loading preferences...");
userPreferences = Preferences.userNodeForPackage(Mirth.class);
userPreferences.put("defaultServer", PlatformUI.SERVER_URL);
- login.setStatus("Loading GUI components...");
+ statusCallback.accept("Loading GUI components...");
splitPane.setDividerSize(0);
splitPane.setBorder(BorderFactory.createEmptyBorder());
@@ -661,15 +655,15 @@ public void setupFrame(Client mirthClient) throws ClientException {
}
setCurrentTaskPaneContainer(taskPaneContainer);
- login.setStatus("Loading dashboard...");
+ statusCallback.accept("Loading dashboard...");
doShowDashboard();
- login.setStatus("Loading channel editor...");
+ statusCallback.accept("Loading channel editor...");
channelEditPanel = new ChannelSetup();
- login.setStatus("Loading alert editor...");
+ statusCallback.accept("Loading alert editor...");
if (alertEditPanel == null) {
alertEditPanel = new DefaultAlertEditPanel();
}
- login.setStatus("Loading message browser...");
+ statusCallback.accept("Loading message browser...");
messageBrowser = new MessageBrowser();
// Refresh code templates after extensions have been loaded
@@ -1524,7 +1518,7 @@ public void alertThrowable(Component parentComponent, Throwable t, String custom
}
mirthClient.close();
this.dispose();
- LoginPanel.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", "");
+ Mirth.showLogin();
return;
} else if (t.getCause() != null && t.getCause() instanceof HttpHostConnectException && (StringUtils.contains(t.getCause().getMessage(), "Connection refused") || StringUtils.contains(t.getCause().getMessage(), "Host is down"))) {
connectionError = true;
@@ -1542,7 +1536,7 @@ public void alertThrowable(Component parentComponent, Throwable t, String custom
}
mirthClient.close();
this.dispose();
- LoginPanel.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", "");
+ Mirth.showLogin();
return;
}
}
@@ -2292,7 +2286,7 @@ public boolean logout(boolean quit, boolean confirmFirst) {
this.dispose();
if (!quit) {
- LoginPanel.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", "");
+ Mirth.showLogin();
}
return true;
diff --git a/client/src/com/mirth/connect/client/ui/LoginPanel.java b/client/src/com/mirth/connect/client/ui/LoginPanel.java
index 0414b7accd..de439c8412 100644
--- a/client/src/com/mirth/connect/client/ui/LoginPanel.java
+++ b/client/src/com/mirth/connect/client/ui/LoginPanel.java
@@ -1,685 +1,149 @@
// SPDX-License-Identifier: MPL-2.0
-// SPDX-FileCopyrightText: Mirth Corporation
-// SPDX-FileCopyrightText: 2025 Mitch Gaffigan and Tony Germano
+// SPDX-FileCopyrightText: 2025 Mitch Gaffigan
+// SPDX-FileCopyrightText: 2026 Tony Germano
package com.mirth.connect.client.ui;
-import static com.mirth.connect.client.core.BrandingConstants.CHECK_FOR_NOTIFICATIONS;
-
-import java.awt.Color;
-import java.awt.Cursor;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.prefs.Preferences;
-
-import javax.swing.ImageIcon;
-import javax.swing.SwingWorker;
-
-import org.apache.commons.lang3.BooleanUtils;
-import org.apache.commons.lang3.StringUtils;
-
import com.mirth.connect.client.core.Client;
import com.mirth.connect.client.core.ClientException;
-import com.mirth.connect.client.core.ConnectServiceUtil;
-import com.mirth.connect.client.core.UnauthorizedException;
-import com.mirth.connect.client.core.api.servlets.UserServletInterface;
-import com.mirth.connect.client.ui.util.DisplayUtil;
-import com.mirth.connect.model.ExtendedLoginStatus;
import com.mirth.connect.model.LoginStatus;
-import com.mirth.connect.model.PublicServerSettings;
-import com.mirth.connect.model.User;
-import com.mirth.connect.model.converters.ObjectXMLSerializer;
-import com.mirth.connect.plugins.MultiFactorAuthenticationClientPlugin;
-import com.mirth.connect.util.MirthSSLUtil;
-
-public class LoginPanel extends javax.swing.JFrame {
-
- private Client client;
- private static final String ERROR_MESSAGE = "There was an error connecting to the server at the specified address. Please verify that the server is up and running.";
- private static LoginPanel instance = null;
-
- private LoginPanel() {
- initComponents();
- DisplayUtil.setResizable(this, false);
- jLabel2.setForeground(UIConstants.HEADER_TITLE_TEXT_COLOR);
- jLabel5.setForeground(UIConstants.HEADER_TITLE_TEXT_COLOR);
- setDefaultCloseOperation(EXIT_ON_CLOSE);
- setIconImage(BrandingConstants.FAVICON.getImage());
- ImageIcon imageIcon = BrandingConstants.LOGO; // load the image to a imageIcon
- mirthCorpImage.setIcon(imageIcon);
- mirthCorpImage.setText("");
- mirthCorpImage.setToolTipText(BrandingConstants.COMPANY_TOOLTIP);
- mirthCorpImage.setCursor(new Cursor(Cursor.HAND_CURSOR));
-
- mirthCorpImage.addMouseListener(new java.awt.event.MouseAdapter() {
-
- public void mouseClicked(java.awt.event.MouseEvent evt) {
- BareBonesBrowserLaunch.openURL(BrandingConstants.COMPANY_URL);
- }
- });
-
- mirthCorpImage1.setIcon(imageIcon);
- mirthCorpImage1.setText("");
- mirthCorpImage1.setToolTipText(BrandingConstants.COMPANY_TOOLTIP);
- mirthCorpImage1.setCursor(new Cursor(Cursor.HAND_CURSOR));
-
- mirthCorpImage1.addMouseListener(new java.awt.event.MouseAdapter() {
-
- public void mouseClicked(java.awt.event.MouseEvent evt) {
- BareBonesBrowserLaunch.openURL(BrandingConstants.COMPANY_URL);
- }
- });
-
- placeholderButton.setVisible(false);
-
- errorTextArea.setBackground(Color.WHITE);
- errorTextArea.setDisabledTextColor(Color.RED);
- }
-
- public static LoginPanel getInstance() {
- synchronized (LoginPanel.class) {
- if (instance == null) {
- instance = new LoginPanel();
- }
- return instance;
- }
- }
-
- public void initialize(String mirthServer, String version, String user, String pass) {
- synchronized (this) {
- // Do not initialize another login window if one is already visible
- if (isVisible()) {
- return;
- }
-
- PlatformUI.CLIENT_VERSION = version;
-
- setTitle(String.format("%s %s - Login", BrandingConstants.PRODUCT_NAME, version));
- setIconImage(BrandingConstants.FAVICON.getImage());
-
- serverName.setText(mirthServer);
-
- // Make sure the login window is centered and not minimized
- setLocationRelativeTo(null);
- setState(Frame.NORMAL);
-
- errorPane.setVisible(false);
- loggingIn.setVisible(false);
- loginMain.setVisible(true);
- loginProgress.setIndeterminate(false);
-
- setStatus("Logging in...");
- username.setText(user);
- password.setText(pass);
+/**
+ * Abstraction for the login panel so that alternative UI toolkit implementations
+ * (e.g. JavaFX) can replace the default Swing-based panel.
+ *
+ * Discovery
+ * Implementations are discovered at runtime via {@link java.util.ServiceLoader}.
+ * To provide a custom login panel, add a
+ * {@code META-INF/services/com.mirth.connect.client.ui.LoginPanel} file whose
+ * single line is the fully-qualified name of the implementing class.
+ * The custom class must have a public no-arg constructor (required by
+ * {@link java.util.ServiceLoader}).
+ * If multiple custom implementations are found, the first one discovered
+ * is used (ordering depends on the classloader).
+ * If no custom implementation is found on the classpath,
+ * {@link DefaultLoginPanel} (the built-in Swing implementation) is used as
+ * a hardcoded fallback. {@code DefaultLoginPanel} itself is not
+ * registered as an SPI provider and uses a package-private constructor
+ * (it is instantiated directly by {@link LoginPanelFactory}).
+ *
+ * Lifecycle
+ *
+ * - The panel is instantiated once by {@link LoginPanelFactory}.
+ * - {@link #initialize} is called each time a login screen is needed
+ * (initial startup and after logout / connection errors).
+ * If {@code user} and {@code pass} are both non-empty the implementation
+ * should attempt an automatic login.
+ * - During the boot sequence after a successful login,
+ * {@link #setStatus} is called repeatedly to report loading progress.
+ * - Once the main application frame is ready, {@link #setVisible(boolean) setVisible(false)}
+ * is called to hide the panel.
+ *
+ *
+ * Multi-Factor Authentication
+ * Existing {@link com.mirth.connect.plugins.MultiFactorAuthenticationClientPlugin}
+ * implementations expect a {@link java.awt.Window} to be passed as their parent
+ * for dialog display. A Swing-based login panel (such as {@link DefaultLoginPanel})
+ * can pass itself directly. Non-Swing implementations are free to define their
+ * own MFA workflow instead of using the plugin API.
+ *
+ * Threading
+ * All methods on this interface ({@link #initialize}, {@link #setStatus},
+ * {@link #setVisible}, {@link #isVisible}, and {@link #showLoginNotification})
+ * may be called from any thread. Implementations must handle any necessary
+ * thread marshalling internally (e.g. posting to the UI thread).
+ *
+ * The thread from which the {@link LoginSuccessHandler} is invoked is
+ * determined by the implementation. {@link DefaultLoginPanel} calls the
+ * handler from a background thread.
+ * The handler (and anything it calls) must not assume it is on a UI thread.
+ *
+ * @see LoginPanelFactory
+ * @see DefaultLoginPanel
+ */
+public interface LoginPanel {
- username.grabFocus();
-
- setVisible(true);
- }
-
- if (user.length() > 0 && pass.length() > 0) {
- loginButtonActionPerformed(null);
- }
+ /**
+ * Callback invoked by the login panel after the server confirms a
+ * successful authentication.
+ *
+ * @see #initialize
+ */
+ @FunctionalInterface
+ interface LoginSuccessHandler {
+ /**
+ * Handle a successful login.
+ *
+ * @param client the authenticated {@link Client} connection
+ * @param loginStatus the status returned by the server
+ * @param userName the username that was used to log in
+ * @return {@code true} if the application booted successfully;
+ * {@code false} if the login flow should restart
+ * (e.g. the user cancelled a first-login dialog)
+ * @throws ClientException if a server communication error occurs
+ */
+ boolean handle(Client client, LoginStatus loginStatus, String userName) throws ClientException;
}
- // @formatter:off
/**
- * This method is called from within the constructor to initialize the form.
- * WARNING: Do NOT modify this code. The content of this method is always
- * regenerated by the Form Editor.
+ * Initialize (or re-initialize) the login UI and make it visible.
+ *
+ * If both {@code user} and {@code pass} are non-empty, the implementation
+ * should start the login attempt automatically without waiting for the
+ * user to click a button.
+ *
+ * If the panel is already visible, the call should be ignored to
+ * prevent duplicate windows.
+ *
+ * @param mirthServer the server URL to display / connect to
+ * @param version the client version string, used in the window title
+ * @param user pre-filled username (may be empty)
+ * @param pass pre-filled password (may be empty)
+ * @param onSuccess callback to invoke after a successful authentication
*/
- // //GEN-BEGIN:initComponents
- private void initComponents() {
-
- loginMain = new javax.swing.JPanel();
- closeButton = new javax.swing.JButton();
- loginButton = new javax.swing.JButton();
- jSeparator1 = new javax.swing.JSeparator();
- serverName = new javax.swing.JTextField();
- jLabel1 = new javax.swing.JLabel();
- jLabel3 = new javax.swing.JLabel();
- mirthHeadingPanel2 = new com.mirth.connect.client.ui.MirthHeadingPanel();
- jLabel2 = new javax.swing.JLabel();
- username = new javax.swing.JTextField();
- jLabel6 = new javax.swing.JLabel();
- password = new javax.swing.JPasswordField();
- mirthCorpImage = new javax.swing.JLabel();
- errorPane = new javax.swing.JScrollPane();
- errorTextArea = new javax.swing.JTextArea();
- loggingIn = new javax.swing.JPanel();
- mirthHeadingPanel1 = new com.mirth.connect.client.ui.MirthHeadingPanel();
- jLabel5 = new javax.swing.JLabel();
- loginProgress = new javax.swing.JProgressBar();
- status = new javax.swing.JLabel();
- jSeparator2 = new javax.swing.JSeparator();
- mirthCorpImage1 = new javax.swing.JLabel();
- placeholderButton = new javax.swing.JButton();
-
- setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
- setTitle(String.format("%s - Login", BrandingConstants.PRODUCT_NAME));
- setIconImage(BrandingConstants.FAVICON.getImage());
-
- loginMain.setBackground(new java.awt.Color(255, 255, 255));
- loginMain.setName(""); // NOI18N
-
- closeButton.setText("Exit");
- closeButton.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- closeButtonActionPerformed(evt);
- }
- });
-
- loginButton.setText("Login");
- loginButton.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- loginButtonActionPerformed(evt);
- }
- });
-
- serverName.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- serverNameActionPerformed(evt);
- }
- });
-
- jLabel1.setText("Server:");
-
- jLabel3.setText("Username:");
-
- jLabel2.setFont(new java.awt.Font("Tahoma", 1, 18)); // NOI18N
- jLabel2.setForeground(new java.awt.Color(255, 255, 255));
- jLabel2.setText(String.format("%s Login", BrandingConstants.PRODUCT_NAME));
-
- javax.swing.GroupLayout mirthHeadingPanel2Layout = new javax.swing.GroupLayout(mirthHeadingPanel2);
- mirthHeadingPanel2.setLayout(mirthHeadingPanel2Layout);
- mirthHeadingPanel2Layout.setHorizontalGroup(
- mirthHeadingPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(mirthHeadingPanel2Layout.createSequentialGroup()
- .addContainerGap()
- .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, 358, Short.MAX_VALUE)
- .addContainerGap())
- );
- mirthHeadingPanel2Layout.setVerticalGroup(
- mirthHeadingPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(mirthHeadingPanel2Layout.createSequentialGroup()
- .addContainerGap()
- .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, 27, Short.MAX_VALUE)
- .addContainerGap())
- );
-
- username.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- usernameActionPerformed(evt);
- }
- });
-
- jLabel6.setText("Password:");
-
- password.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- passwordActionPerformed(evt);
- }
- });
-
- mirthCorpImage.setText(" ");
-
- errorPane.setBorder(null);
- errorPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
- errorPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
-
- errorTextArea.setColumns(20);
- errorTextArea.setEditable(false);
- errorTextArea.setFont(new java.awt.Font("Tahoma", 0, 11));
- errorTextArea.setLineWrap(true);
- errorTextArea.setText("There was an error connecting to the server at the specified address. Please verify that the server is up and running.");
- errorTextArea.setWrapStyleWord(true);
- errorTextArea.setEnabled(false);
- errorPane.setViewportView(errorTextArea);
-
- javax.swing.GroupLayout loginMainLayout = new javax.swing.GroupLayout(loginMain);
- loginMain.setLayout(loginMainLayout);
- loginMainLayout.setHorizontalGroup(
- loginMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(loginMainLayout.createSequentialGroup()
- .addContainerGap()
- .addComponent(jSeparator1, javax.swing.GroupLayout.DEFAULT_SIZE, 358, Short.MAX_VALUE)
- .addContainerGap())
- .addComponent(mirthHeadingPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, 378, Short.MAX_VALUE)
- .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, loginMainLayout.createSequentialGroup()
- .addContainerGap()
- .addComponent(mirthCorpImage)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 235, Short.MAX_VALUE)
- .addComponent(loginButton)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(closeButton)
- .addContainerGap())
- .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, loginMainLayout.createSequentialGroup()
- .addGap(51, 51, 51)
- .addGroup(loginMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(jLabel6, javax.swing.GroupLayout.Alignment.TRAILING)
- .addComponent(jLabel3, javax.swing.GroupLayout.Alignment.TRAILING)
- .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.TRAILING))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(loginMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
- .addComponent(serverName, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 220, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(password, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 220, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(username, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 220, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addGap(51, 51, 51))
- .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, loginMainLayout.createSequentialGroup()
- .addContainerGap(57, Short.MAX_VALUE)
- .addComponent(errorPane, javax.swing.GroupLayout.PREFERRED_SIZE, 264, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addGap(57, 57, 57))
- );
-
- loginMainLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {closeButton, loginButton});
-
- loginMainLayout.setVerticalGroup(
- loginMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, loginMainLayout.createSequentialGroup()
- .addComponent(mirthHeadingPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addGap(22, 22, 22)
- .addGroup(loginMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(jLabel1)
- .addComponent(serverName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(loginMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(jLabel3)
- .addComponent(username, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(loginMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(password, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(jLabel6))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(errorPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 15, Short.MAX_VALUE)
- .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(loginMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(closeButton)
- .addComponent(loginButton)
- .addComponent(mirthCorpImage))
- .addContainerGap())
- );
+ void initialize(String mirthServer, String version, String user, String pass, LoginSuccessHandler onSuccess);
- loggingIn.setBackground(new java.awt.Color(255, 255, 255));
-
- jLabel5.setFont(new java.awt.Font("Tahoma", 1, 18)); // NOI18N
- jLabel5.setForeground(new java.awt.Color(255, 255, 255));
- jLabel5.setText(String.format("%s Login", BrandingConstants.PRODUCT_NAME));
-
- javax.swing.GroupLayout mirthHeadingPanel1Layout = new javax.swing.GroupLayout(mirthHeadingPanel1);
- mirthHeadingPanel1.setLayout(mirthHeadingPanel1Layout);
- mirthHeadingPanel1Layout.setHorizontalGroup(
- mirthHeadingPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(mirthHeadingPanel1Layout.createSequentialGroup()
- .addContainerGap()
- .addComponent(jLabel5, javax.swing.GroupLayout.PREFERRED_SIZE, 326, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addContainerGap(42, Short.MAX_VALUE))
- );
- mirthHeadingPanel1Layout.setVerticalGroup(
- mirthHeadingPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(mirthHeadingPanel1Layout.createSequentialGroup()
- .addContainerGap()
- .addComponent(jLabel5, javax.swing.GroupLayout.DEFAULT_SIZE, 27, Short.MAX_VALUE)
- .addContainerGap())
- );
-
- loginProgress.setDoubleBuffered(true);
-
- status.setText("Please wait: Logging in...");
-
- mirthCorpImage1.setText(" ");
-
- placeholderButton.setText("Placeholder");
-
- javax.swing.GroupLayout loggingInLayout = new javax.swing.GroupLayout(loggingIn);
- loggingIn.setLayout(loggingInLayout);
- loggingInLayout.setHorizontalGroup(
- loggingInLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(mirthHeadingPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 378, Short.MAX_VALUE)
- .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, loggingInLayout.createSequentialGroup()
- .addContainerGap()
- .addComponent(loginProgress, javax.swing.GroupLayout.DEFAULT_SIZE, 358, Short.MAX_VALUE)
- .addContainerGap())
- .addGroup(loggingInLayout.createSequentialGroup()
- .addContainerGap()
- .addComponent(status)
- .addContainerGap(247, Short.MAX_VALUE))
- .addGroup(loggingInLayout.createSequentialGroup()
- .addContainerGap()
- .addComponent(mirthCorpImage1)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 268, Short.MAX_VALUE)
- .addComponent(placeholderButton)
- .addContainerGap())
- .addGroup(loggingInLayout.createSequentialGroup()
- .addContainerGap()
- .addComponent(jSeparator2, javax.swing.GroupLayout.DEFAULT_SIZE, 358, Short.MAX_VALUE)
- .addContainerGap())
- );
- loggingInLayout.setVerticalGroup(
- loggingInLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(loggingInLayout.createSequentialGroup()
- .addComponent(mirthHeadingPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addGap(45, 45, 45)
- .addComponent(status)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(loginProgress, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 82, Short.MAX_VALUE)
- .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(loggingInLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(mirthCorpImage1)
- .addComponent(placeholderButton))
- .addContainerGap())
- );
-
- javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
- getContentPane().setLayout(layout);
- layout.setHorizontalGroup(
- layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(loginMain, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(loggingIn, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- );
- layout.setVerticalGroup(
- layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(loginMain, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(loggingIn, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- );
-
- pack();
- }// //GEN-END:initComponents
- // @formatter:on
-
- private void usernameActionPerformed(java.awt.event.ActionEvent evt)// GEN-FIRST:event_usernameActionPerformed
- {// GEN-HEADEREND:event_usernameActionPerformed
- loginButtonActionPerformed(null);
- }// GEN-LAST:event_usernameActionPerformed
-
- private void serverNameActionPerformed(java.awt.event.ActionEvent evt)// GEN-FIRST:event_serverNameActionPerformed
- {// GEN-HEADEREND:event_serverNameActionPerformed
- loginButtonActionPerformed(null);
- }// GEN-LAST:event_serverNameActionPerformed
-
- private void passwordActionPerformed(java.awt.event.ActionEvent evt)// GEN-FIRST:event_passwordActionPerformed
- {// GEN-HEADEREND:event_passwordActionPerformed
- loginButtonActionPerformed(null);
- }// GEN-LAST:event_passwordActionPerformed
-
- private void loginButtonActionPerformed(java.awt.event.ActionEvent evt)// GEN-FIRST:event_loginButtonActionPerformed
- {// GEN-HEADEREND:event_loginButtonActionPerformed
- errorPane.setVisible(false);
-
- SwingWorker worker = new SwingWorker() {
-
- public Void doInBackground() {
- boolean errorOccurred = false;
-
- try {
- String server = serverName.getText();
- client = new Client(server, PlatformUI.HTTPS_PROTOCOLS, PlatformUI.HTTPS_CIPHER_SUITES);
- PlatformUI.SERVER_URL = server;
-
- // Attempt to login
- LoginStatus loginStatus = null;
- try {
- Map> customHeaders = new HashMap>();
- customHeaders.put(UserServletInterface.LOGIN_SERVER_URL_HEADER, Collections.singletonList(PlatformUI.SERVER_URL));
- loginStatus = client.getServlet(UserServletInterface.class, null, customHeaders).login(username.getText(), String.valueOf(password.getPassword()));
- } catch (ClientException ex) {
- ex.printStackTrace();
-
- if (ex instanceof UnauthorizedException) {
- UnauthorizedException e2 = (UnauthorizedException) ex;
- if (e2.getResponse() != null && e2.getResponse() instanceof LoginStatus) {
- loginStatus = (LoginStatus) e2.getResponse();
- }
- }
-
- // Leave loginStatus null, the error message will be set to the default
- }
-
- // If SUCCESS or SUCCESS_GRACE_PERIOD
- if (loginStatus != null && loginStatus.isSuccess()) {
- if (!handleSuccess(loginStatus)) {
- LoginPanel.getInstance().setVisible(false);
- LoginPanel.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", "");
- }
- } else {
- // Assume failure unless overridden by a plugin
- errorOccurred = true;
-
- if (loginStatus instanceof ExtendedLoginStatus) {
- ExtendedLoginStatus extendedLoginStatus = (ExtendedLoginStatus) loginStatus;
-
- if (StringUtils.isNotBlank(extendedLoginStatus.getClientPluginClass())) {
- String updatedUsername = StringUtils.defaultString(loginStatus.getUpdatedUsername(), username.getText());
- MultiFactorAuthenticationClientPlugin plugin = (MultiFactorAuthenticationClientPlugin) Class.forName(extendedLoginStatus.getClientPluginClass()).newInstance();
-
- loginStatus = plugin.authenticate(LoginPanel.this, client, updatedUsername, loginStatus);
-
- if (loginStatus != null && loginStatus.isSuccess()) {
- errorOccurred = false;
- if (!handleSuccess(loginStatus)) {
- LoginPanel.getInstance().setVisible(false);
- LoginPanel.getInstance().initialize(PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, "", "");
- }
- }
- }
- }
- }
-
- if (errorOccurred) {
- if (loginStatus != null) {
- errorTextArea.setText(loginStatus.getMessage());
- } else {
- errorTextArea.setText(ERROR_MESSAGE);
- }
- }
- } catch (Throwable t) {
- errorOccurred = true;
- errorTextArea.setText(ERROR_MESSAGE);
- t.printStackTrace();
- }
-
- if (errorOccurred) {
- errorPane.setVisible(true);
- loggingIn.setVisible(false);
- loginMain.setVisible(true);
- loginProgress.setIndeterminate(false);
- password.grabFocus();
- }
-
- return null;
- }
-
- private boolean handleSuccess(LoginStatus loginStatus) throws ClientException {
- try {
- PublicServerSettings publicServerSettings = client.getPublicServerSettings();
-
- if (publicServerSettings.getLoginNotificationEnabled() == true) {
- CustomBannerPanelDialog customBannerPanelDialog = new CustomBannerPanelDialog(LoginPanel.getInstance(), "Login Notification", publicServerSettings.getLoginNotificationMessage());
- boolean isAccepted = customBannerPanelDialog.isAccepted();
-
- if (isAccepted == true) {
- client.setUserNotificationAcknowledged(client.getCurrentUser().getId());
- }
- else {
- return false;
- }
- }
-
- String environmentName = publicServerSettings.getEnvironmentName();
- if (!StringUtils.isBlank(environmentName)) {
- PlatformUI.ENVIRONMENT_NAME = environmentName;
- }
-
- String serverName = publicServerSettings.getServerName();
- if (!StringUtils.isBlank(serverName)) {
- PlatformUI.SERVER_NAME = serverName;
- } else {
- PlatformUI.SERVER_NAME = null;
- }
-
- Color defaultBackgroundColor = publicServerSettings.getDefaultAdministratorBackgroundColor();
- if (defaultBackgroundColor != null) {
- PlatformUI.DEFAULT_BACKGROUND_COLOR = defaultBackgroundColor;
- }
- } catch (ClientException e) {
- PlatformUI.SERVER_NAME = null;
- }
-
- try {
- String database = (String) client.getAbout().get("database");
- if (!StringUtils.isBlank(database)) {
- PlatformUI.SERVER_DATABASE = database;
- } else {
- PlatformUI.SERVER_DATABASE = null;
- }
- } catch (ClientException e) {
- PlatformUI.SERVER_DATABASE = null;
- }
-
- try {
- Map map = client.getProtocolsAndCipherSuites();
- PlatformUI.SERVER_HTTPS_SUPPORTED_PROTOCOLS = map.get(MirthSSLUtil.KEY_SUPPORTED_PROTOCOLS);
- PlatformUI.SERVER_HTTPS_ENABLED_CLIENT_PROTOCOLS = map.get(MirthSSLUtil.KEY_ENABLED_CLIENT_PROTOCOLS);
- PlatformUI.SERVER_HTTPS_ENABLED_SERVER_PROTOCOLS = map.get(MirthSSLUtil.KEY_ENABLED_SERVER_PROTOCOLS);
- PlatformUI.SERVER_HTTPS_SUPPORTED_CIPHER_SUITES = map.get(MirthSSLUtil.KEY_SUPPORTED_CIPHER_SUITES);
- PlatformUI.SERVER_HTTPS_ENABLED_CIPHER_SUITES = map.get(MirthSSLUtil.KEY_ENABLED_CIPHER_SUITES);
- } catch (ClientException e) {
- }
-
- PlatformUI.USER_NAME = StringUtils.defaultString(loginStatus.getUpdatedUsername(), username.getText());
- setStatus("Authenticated...");
- new Mirth(client);
- LoginPanel.getInstance().setVisible(false);
-
- User currentUser = PlatformUI.MIRTH_FRAME.getCurrentUser(PlatformUI.MIRTH_FRAME);
- Properties userPreferences = new Properties();
- Set preferenceNames = new HashSet();
- preferenceNames.add("firstlogin");
- preferenceNames.add("checkForNotifications");
- preferenceNames.add("showNotificationPopup");
- preferenceNames.add("archivedNotifications");
- try {
- userPreferences = client.getUserPreferences(currentUser.getId(), preferenceNames);
-
- // Display registration dialog if it's the user's first time logging in
- String firstlogin = userPreferences.getProperty("firstlogin");
- if (firstlogin == null || BooleanUtils.toBoolean(firstlogin)) {
- if (Integer.valueOf(currentUser.getId()) == 1) {
- // if current user is user 1:
- // 1. check system preferences for user information
- // 2. if system preferences exist, populate screen using currentUser
- Preferences preferences = Preferences.userNodeForPackage(Mirth.class);
- String systemUserInfo = preferences.get("userLoginInfo", null);
- if (systemUserInfo != null) {
- String info[] = systemUserInfo.split(",", 0);
- currentUser.setUsername(info[0]);
- currentUser.setFirstName(info[1]);
- currentUser.setLastName(info[2]);
- currentUser.setEmail(info[3]);
- currentUser.setCountry(info[4]);
- currentUser.setStateTerritory(info[5]);
- currentUser.setPhoneNumber(info[6]);
- currentUser.setOrganization(info[7]);
- currentUser.setRole(info[8]);
- currentUser.setIndustry(info[9]);
- currentUser.setDescription(info[10]);
- }
- }
- FirstLoginDialog firstLoginDialog = new FirstLoginDialog(currentUser);
- // if leaving the first login dialog without saving
- if (!firstLoginDialog.getResult()) {
- return false;
- }
- } else if (loginStatus.getStatus() == LoginStatus.Status.SUCCESS_GRACE_PERIOD) {
- new ChangePasswordDialog(currentUser, loginStatus.getMessage());
- }
-
- // Check for new notifications from update server if enabled
- String checkForNotifications = userPreferences.getProperty("checkForNotifications");
- if (CHECK_FOR_NOTIFICATIONS
- && (checkForNotifications == null || BooleanUtils.toBoolean(checkForNotifications))) {
- Set archivedNotifications = new HashSet();
- String archivedNotificationString = userPreferences.getProperty("archivedNotifications");
- if (archivedNotificationString != null) {
- archivedNotifications = ObjectXMLSerializer.getInstance().deserialize(archivedNotificationString, Set.class);
- }
- // Update the Other Tasks pane with the unarchived notification count
- int unarchivedNotifications = ConnectServiceUtil.getNotificationCount(PlatformUI.SERVER_ID, PlatformUI.SERVER_VERSION, LoadedExtensions.getInstance().getExtensionVersions(), archivedNotifications, PlatformUI.HTTPS_PROTOCOLS, PlatformUI.HTTPS_CIPHER_SUITES);
- PlatformUI.MIRTH_FRAME.updateNotificationTaskName(unarchivedNotifications);
-
- // Display notification dialog if enabled and if there are new notifications
- String showNotificationPopup = userPreferences.getProperty("showNotificationPopup");
- if (showNotificationPopup == null || BooleanUtils.toBoolean(showNotificationPopup)) {
- if (unarchivedNotifications > 0) {
- new NotificationDialog();
- }
- }
- }
- } catch (ClientException e) {
- PlatformUI.MIRTH_FRAME.alertThrowable(PlatformUI.MIRTH_FRAME, e);
- }
-
- PlatformUI.MIRTH_FRAME.sendUsageStatistics();
-
- return true;
- }
-
- public void done() {}
- };
- worker.execute();
-
- loggingIn.setVisible(true);
- loginMain.setVisible(false);
- loginProgress.setIndeterminate(true);
- }// GEN-LAST:event_loginButtonActionPerformed
+ /**
+ * Update the status text shown on the login UI.
+ *
+ * Called repeatedly during the post-login boot sequence to report
+ * loading progress (e.g. "Loading extensions…").
+ * Implementations must be safe to call from any thread.
+ *
+ * @param status the progress message to display
+ */
+ void setStatus(String status);
/**
- * If the button is "Next" instead of "Finish" then it moves on to the next options. Otherwise,
- * it creates the new channel.
+ * Show or hide the login panel.
+ *
+ * After the main application frame is ready, {@code setVisible(false)}
+ * is called to dismiss the login UI. Implementations must be safe to
+ * call from any thread.
+ *
+ * @param visible {@code true} to show, {@code false} to hide
*/
- private void closeButtonActionPerformed(java.awt.event.ActionEvent evt)// GEN-FIRST:event_closeButtonActionPerformed
- {// GEN-HEADEREND:event_closeButtonActionPerformed
- this.dispose();
- System.exit(0);
- }// GEN-LAST:event_closeButtonActionPerformed
+ void setVisible(boolean visible);
- public void setStatus(String status) {
- this.status.setText("Please wait: " + status);
- }
+ /**
+ * Returns whether the login panel is currently visible.
+ *
+ * @return {@code true} if the panel is showing
+ */
+ boolean isVisible();
- // Variables declaration - do not modify//GEN-BEGIN:variables
- private javax.swing.JButton closeButton;
- private javax.swing.JScrollPane errorPane;
- private javax.swing.JTextArea errorTextArea;
- private javax.swing.JLabel jLabel1;
- private javax.swing.JLabel jLabel2;
- private javax.swing.JLabel jLabel3;
- private javax.swing.JLabel jLabel5;
- private javax.swing.JLabel jLabel6;
- private javax.swing.JSeparator jSeparator1;
- private javax.swing.JSeparator jSeparator2;
- private javax.swing.JPanel loggingIn;
- private javax.swing.JButton loginButton;
- private javax.swing.JPanel loginMain;
- private javax.swing.JProgressBar loginProgress;
- private javax.swing.JLabel mirthCorpImage;
- private javax.swing.JLabel mirthCorpImage1;
- private com.mirth.connect.client.ui.MirthHeadingPanel mirthHeadingPanel1;
- private com.mirth.connect.client.ui.MirthHeadingPanel mirthHeadingPanel2;
- private javax.swing.JPasswordField password;
- private javax.swing.JButton placeholderButton;
- private javax.swing.JTextField serverName;
- private javax.swing.JLabel status;
- private javax.swing.JTextField username;
- // End of variables declaration//GEN-END:variables
+ /**
+ * Display a modal login-notification banner and wait for the user to
+ * accept or cancel.
+ *
+ * This is called after a successful authentication when the server has
+ * login notifications enabled. If the user does not accept, the
+ * login flow is aborted and restarted.
+ *
+ * @param title the dialog title
+ * @param message the notification body text
+ * @return {@code true} if the user accepted the notification,
+ * {@code false} if they cancelled
+ */
+ boolean showLoginNotification(String title, String message);
}
diff --git a/client/src/com/mirth/connect/client/ui/LoginPanelFactory.java b/client/src/com/mirth/connect/client/ui/LoginPanelFactory.java
new file mode 100644
index 0000000000..83bb5c3f56
--- /dev/null
+++ b/client/src/com/mirth/connect/client/ui/LoginPanelFactory.java
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: MPL-2.0
+// SPDX-FileCopyrightText: 2025-2026 Open Integration Engine Contributors
+
+package com.mirth.connect.client.ui;
+
+import java.util.ServiceLoader;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+/**
+ * Factory for obtaining the application's {@link LoginPanel} implementation.
+ * Uses {@link ServiceLoader} to discover custom implementations, falling back
+ * to {@link DefaultLoginPanel} if none are found.
+ */
+public class LoginPanelFactory {
+
+ private static final Logger logger = LogManager.getLogger(LoginPanelFactory.class);
+ private static LoginPanel loginPanel = null;
+
+ /**
+ * Returns the singleton {@link LoginPanel} instance, discovering it via
+ * {@link ServiceLoader} on first call. If multiple custom implementations
+ * are found, the first one discovered is used (ordering is classloader-dependent).
+ * Falls back to {@link DefaultLoginPanel} if no custom implementation is
+ * registered. {@code DefaultLoginPanel} itself should not be registered
+ * as an SPI provider — it is the hardcoded fallback.
+ */
+ public static synchronized LoginPanel getLoginPanel() {
+ if (loginPanel == null) {
+ loginPanel = ServiceLoader.load(LoginPanel.class)
+ .findFirst()
+ .orElseGet(DefaultLoginPanel::new);
+ logger.info("Using LoginPanel: {}", loginPanel.getClass().getName());
+ }
+ return loginPanel;
+ }
+}
diff --git a/client/src/com/mirth/connect/client/ui/Mirth.java b/client/src/com/mirth/connect/client/ui/Mirth.java
index eacb683313..b5dc9410ca 100644
--- a/client/src/com/mirth/connect/client/ui/Mirth.java
+++ b/client/src/com/mirth/connect/client/ui/Mirth.java
@@ -3,12 +3,18 @@
package com.mirth.connect.client.ui;
+import static com.mirth.connect.client.core.BrandingConstants.CHECK_FOR_NOTIFICATIONS;
+
import java.awt.Color;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.prefs.Preferences;
+import java.util.Map;
+import java.util.Set;
+import java.util.Properties;
+import java.util.HashSet;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
@@ -22,6 +28,7 @@
import javax.swing.text.JTextComponent;
import javax.swing.text.JTextComponent.KeyBinding;
+import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.apache.logging.log4j.Level;
@@ -36,6 +43,12 @@
import com.jgoodies.looks.plastic.PlasticXPLookAndFeel;
import com.mirth.connect.client.core.Client;
import com.mirth.connect.client.core.ClientException;
+import com.mirth.connect.client.core.ConnectServiceUtil;
+import com.mirth.connect.model.LoginStatus;
+import com.mirth.connect.model.PublicServerSettings;
+import com.mirth.connect.model.User;
+import com.mirth.connect.model.converters.ObjectXMLSerializer;
+import com.mirth.connect.util.MirthSSLUtil;
/**
* The main mirth class. Sets up the login and then authenticates the login information and sets up
@@ -56,8 +69,9 @@ public Mirth(Client mirthClient) throws ClientException {
UIManager.put("Tree.closedIcon", UIConstants.CLOSED_ICON);
userPreferences = Preferences.userNodeForPackage(Mirth.class);
- LoginPanel.getInstance().setStatus("Loading components...");
- PlatformUI.MIRTH_FRAME.setupFrame(mirthClient);
+ LoginPanel loginPanel = LoginPanelFactory.getLoginPanel();
+ loginPanel.setStatus("Loading components...");
+ PlatformUI.MIRTH_FRAME.setupFrame(mirthClient, loginPanel::setStatus);
boolean maximized;
int width;
@@ -116,7 +130,7 @@ public static void aboutMac() {
* @return quit
*/
public static boolean quitMac() {
- return (LoginPanel.getInstance().isVisible() || (PlatformUI.MIRTH_FRAME != null && PlatformUI.MIRTH_FRAME.logout(true)));
+ return (LoginPanelFactory.getLoginPanel().isVisible() || (PlatformUI.MIRTH_FRAME != null && PlatformUI.MIRTH_FRAME.logout(true)));
}
/**
@@ -278,8 +292,153 @@ private static void start(final String server, final String version, final Strin
public void run() {
initUIManager();
PlatformUI.BACKGROUND_IMAGE = new ImageIcon(com.mirth.connect.client.ui.Frame.class.getResource("images/header_nologo.png"));
- LoginPanel.getInstance().initialize(server, version, username, password);
+ showLogin(username, password);
}
});
}
+
+ static void showLogin() {
+ showLogin("", "");
+ }
+
+ static void showLogin(String user, String pass) {
+ LoginPanelFactory.getLoginPanel().initialize(
+ PlatformUI.SERVER_URL, PlatformUI.CLIENT_VERSION, user, pass,
+ Mirth::handleLoginSuccess);
+ }
+
+ private static boolean handleLoginSuccess(Client client, LoginStatus loginStatus, String userName) throws ClientException {
+ LoginPanel loginPanel = LoginPanelFactory.getLoginPanel();
+ try {
+ PublicServerSettings publicServerSettings = client.getPublicServerSettings();
+
+ if (publicServerSettings.getLoginNotificationEnabled() == true) {
+ boolean isAccepted = loginPanel.showLoginNotification("Login Notification", publicServerSettings.getLoginNotificationMessage());
+
+ if (isAccepted == true) {
+ client.setUserNotificationAcknowledged(client.getCurrentUser().getId());
+ }
+ else {
+ return false;
+ }
+ }
+
+ String environmentName = publicServerSettings.getEnvironmentName();
+ if (!StringUtils.isBlank(environmentName)) {
+ PlatformUI.ENVIRONMENT_NAME = environmentName;
+ }
+
+ String serverName = publicServerSettings.getServerName();
+ if (!StringUtils.isBlank(serverName)) {
+ PlatformUI.SERVER_NAME = serverName;
+ } else {
+ PlatformUI.SERVER_NAME = null;
+ }
+
+ Color defaultBackgroundColor = publicServerSettings.getDefaultAdministratorBackgroundColor();
+ if (defaultBackgroundColor != null) {
+ PlatformUI.DEFAULT_BACKGROUND_COLOR = defaultBackgroundColor;
+ }
+ } catch (ClientException e) {
+ PlatformUI.SERVER_NAME = null;
+ }
+
+ try {
+ String database = (String) client.getAbout().get("database");
+ if (!StringUtils.isBlank(database)) {
+ PlatformUI.SERVER_DATABASE = database;
+ } else {
+ PlatformUI.SERVER_DATABASE = null;
+ }
+ } catch (ClientException e) {
+ PlatformUI.SERVER_DATABASE = null;
+ }
+
+ try {
+ Map map = client.getProtocolsAndCipherSuites();
+ PlatformUI.SERVER_HTTPS_SUPPORTED_PROTOCOLS = map.get(MirthSSLUtil.KEY_SUPPORTED_PROTOCOLS);
+ PlatformUI.SERVER_HTTPS_ENABLED_CLIENT_PROTOCOLS = map.get(MirthSSLUtil.KEY_ENABLED_CLIENT_PROTOCOLS);
+ PlatformUI.SERVER_HTTPS_ENABLED_SERVER_PROTOCOLS = map.get(MirthSSLUtil.KEY_ENABLED_SERVER_PROTOCOLS);
+ PlatformUI.SERVER_HTTPS_SUPPORTED_CIPHER_SUITES = map.get(MirthSSLUtil.KEY_SUPPORTED_CIPHER_SUITES);
+ PlatformUI.SERVER_HTTPS_ENABLED_CIPHER_SUITES = map.get(MirthSSLUtil.KEY_ENABLED_CIPHER_SUITES);
+ } catch (ClientException e) {
+ }
+
+ PlatformUI.USER_NAME = StringUtils.defaultString(loginStatus.getUpdatedUsername(), userName);
+ loginPanel.setStatus("Authenticated...");
+ new Mirth(client);
+ loginPanel.setVisible(false);
+
+ User currentUser = PlatformUI.MIRTH_FRAME.getCurrentUser(PlatformUI.MIRTH_FRAME);
+ Properties userPreferences = new Properties();
+ Set preferenceNames = new HashSet();
+ preferenceNames.add("firstlogin");
+ preferenceNames.add("checkForNotifications");
+ preferenceNames.add("showNotificationPopup");
+ preferenceNames.add("archivedNotifications");
+ try {
+ userPreferences = client.getUserPreferences(currentUser.getId(), preferenceNames);
+
+ // Display registration dialog if it's the user's first time logging in
+ String firstlogin = userPreferences.getProperty("firstlogin");
+ if (firstlogin == null || BooleanUtils.toBoolean(firstlogin)) {
+ if (Integer.valueOf(currentUser.getId()) == 1) {
+ // if current user is user 1:
+ // 1. check system preferences for user information
+ // 2. if system preferences exist, populate screen using currentUser
+ Preferences preferences = Preferences.userNodeForPackage(Mirth.class);
+ String systemUserInfo = preferences.get("userLoginInfo", null);
+ if (systemUserInfo != null) {
+ String info[] = systemUserInfo.split(",", 0);
+ currentUser.setUsername(info[0]);
+ currentUser.setFirstName(info[1]);
+ currentUser.setLastName(info[2]);
+ currentUser.setEmail(info[3]);
+ currentUser.setCountry(info[4]);
+ currentUser.setStateTerritory(info[5]);
+ currentUser.setPhoneNumber(info[6]);
+ currentUser.setOrganization(info[7]);
+ currentUser.setRole(info[8]);
+ currentUser.setIndustry(info[9]);
+ currentUser.setDescription(info[10]);
+ }
+ }
+ FirstLoginDialog firstLoginDialog = new FirstLoginDialog(currentUser);
+ // if leaving the first login dialog without saving
+ if (!firstLoginDialog.getResult()) {
+ return false;
+ }
+ } else if (loginStatus.getStatus() == LoginStatus.Status.SUCCESS_GRACE_PERIOD) {
+ new ChangePasswordDialog(currentUser, loginStatus.getMessage());
+ }
+
+ // Check for new notifications from update server if enabled
+ String checkForNotifications = userPreferences.getProperty("checkForNotifications");
+ if (CHECK_FOR_NOTIFICATIONS
+ && (checkForNotifications == null || BooleanUtils.toBoolean(checkForNotifications))) {
+ Set archivedNotifications = new HashSet();
+ String archivedNotificationString = userPreferences.getProperty("archivedNotifications");
+ if (archivedNotificationString != null) {
+ archivedNotifications = ObjectXMLSerializer.getInstance().deserialize(archivedNotificationString, Set.class);
+ }
+ // Update the Other Tasks pane with the unarchived notification count
+ int unarchivedNotifications = ConnectServiceUtil.getNotificationCount(PlatformUI.SERVER_ID, PlatformUI.SERVER_VERSION, LoadedExtensions.getInstance().getExtensionVersions(), archivedNotifications, PlatformUI.HTTPS_PROTOCOLS, PlatformUI.HTTPS_CIPHER_SUITES);
+ PlatformUI.MIRTH_FRAME.updateNotificationTaskName(unarchivedNotifications);
+
+ // Display notification dialog if enabled and if there are new notifications
+ String showNotificationPopup = userPreferences.getProperty("showNotificationPopup");
+ if (showNotificationPopup == null || BooleanUtils.toBoolean(showNotificationPopup)) {
+ if (unarchivedNotifications > 0) {
+ new NotificationDialog();
+ }
+ }
+ }
+ } catch (ClientException e) {
+ PlatformUI.MIRTH_FRAME.alertThrowable(PlatformUI.MIRTH_FRAME, e);
+ }
+
+ PlatformUI.MIRTH_FRAME.sendUsageStatistics();
+
+ return true;
+ }
}