2013-02-06 194 views
0

我開發了一個登錄窗口,因爲我的程序連接到SSH服務器。登錄窗口凍結

我在啓動程序時打開此窗口。但我需要稍後重新打開另一臺服務器。第二次我打開它,登錄窗口凍結...

有關信息

下面是登錄窗口代碼:

package com.maxbester.test; 

import java.awt.BorderLayout; 
import java.awt.FlowLayout; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.Insets; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.KeyEvent; 
import java.awt.event.KeyListener; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JOptionPane; 
import javax.swing.JPanel; 
import javax.swing.JPasswordField; 
import javax.swing.JTextField; 

import org.apache.log4j.Logger; 

import com.maxbester.test.Server; 

@SuppressWarnings("serial") 
public class LoginWindow extends JFrame { 

    private static final Logger LOG = Logger.getLogger(LoginWindow.class); 

    private Server _server; 
    private Object _parent; 

    private JPanel _panel; 
    private JLabel _loginLabel; 
    private JTextField _loginInput; 
    private JLabel _passwordLabel; 
    private JPasswordField _passwordInput; 

    private JPanel _buttonPanel; 
    private JButton _okButton; 
    private JButton _cancelButton; 

    public LoginWindow(Object parent, Server server) { 
     _server = server; 
     _parent = parent; 
     initComponents(); 
    } 

    private void initComponents() { 
     setTitle("Connection window"); 
     setLayout(new BorderLayout()); 

     _loginLabel = new JLabel("Login: "); 
     _loginInput = new JTextField(System.getProperty("user.name"), 15); 

     _passwordLabel = new JLabel("Password: "); 

     _panel = new JPanel(new GridBagLayout()); 
     GridBagConstraints c = new GridBagConstraints(); 
     c.gridx = 0; 
     c.gridy = 0; 
     // external padding 
     c.insets = new Insets(5,5,5,5); 
     _panel.add(_loginLabel,c); 
     c.gridx = 1; 
     _panel.add(_loginInput,c); 
     c.gridy = 1; 
     _panel.add(_passwordLabel,c); 
     c.gridx = 0; 
     _panel.add(getPasswordLabel(),c); 

     add(_panel, BorderLayout.CENTER); 

     _okButton = new JButton("Ok"); 
     _okButton.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       okActionPerformed(); 
      } 
     }); 
     _cancelButton = new JButton("Cancel"); 
     _cancelButton.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       System.exit(0); 
      } 
     }); 
     _buttonPanel = new JPanel(new FlowLayout()); 
     _buttonPanel.add(_okButton); 
     _buttonPanel.add(_cancelButton); 
     add(_buttonPanel, BorderLayout.SOUTH); 

     pack(); 
    } 

    /** 
    * @return the _passwordInput 
    */ 
    private JPasswordField getPasswordInput() { 
     if (LOG.isTraceEnabled()) { 
      LOG.trace("getPasswordInput()"); 
     } 
     if (_passwordInput == null) { 
      _passwordInput = new JPasswordField(15) { 
       // Give the focus to this field 
       public void addNotify() { 
        super.addNotify(); 
        requestFocusInWindow();    
       }  
      }; 
      _passwordInput.addKeyListener(new KeyListener() { 
       @Override public void keyTyped(KeyEvent arg0) {} 
       @Override 
       public void keyReleased(KeyEvent keyEvent) { 
        if (keyEvent.getKeyChar() == KeyEvent.VK_ENTER) { 
         if (LOG.isTraceEnabled()) { 
          LOG.trace("Click enter in password field"); 
         } 
         okActionPerformed(); 
        } 
       } 
       @Override public void keyPressed(KeyEvent arg0) {} 
      }); 
     } 
     return _passwordInput; 
    } 


    protected void okActionPerformed() { 
     if (LOG.isTraceEnabled()) { 
      LOG.trace("okActionPerformed()"); 
     } 
     if (_server != null) { 
      String login = _loginInput.getText(); 
      if (login != null && !login.isEmpty()) { 
       _server.setLogin(login); 
       char[] password = _passwordInput.getPassword(); 
       if (password != null && password.length > 0) { 
        _server.setPassword(new String(password)); 
        setVisible(false); 
        synchronized (_parent) { 
         if (LOG.isTraceEnabled()) { 
          LOG.trace("syncronized with "+_parent); 
         } 
         _parent.notifyAll(); 
        } 
       } else { 
        JOptionPane.showMessageDialog(LoginWindow.this,"Please enter a password", "Password required", JOptionPane.WARNING_MESSAGE);  
       } 
      } else { 
       JOptionPane.showMessageDialog(LoginWindow.this,"Please enter your login", "Login required", JOptionPane.WARNING_MESSAGE); 
      } 
     } else { 
      LOG.error("Server is null"); 
      JOptionPane.showMessageDialog(LoginWindow.this,"Server is null.", "An error has occured", JOptionPane.ERROR_MESSAGE); 
      System.exit(-1); 
     } 
    } 
} 

我存儲父類通知它,當用戶輸入他的登錄名和密碼。

服務器類是非常簡單的:

package com.maxbester.test; 

public class Server { 

    private String _url; 
    private String _login = "root"; 
    private String _password = ""; 

    public Server(String url) { 
     _url = url; 
    } 
    public Server(String url, String login, String password) { 
     _url = url; 
     if (login != null) { 
      _login = login; 
     } 
     if (password != null) { 
      _password = password; 
     } 
    } 
    public String getUrl() { 
     return _url; 
    } 
    public String getLogin() { 
     return _login; 
    } 
    public String getPassword() { 
     return _password; 
    } 
    public void setUrl(String url) { 
     if (url != null) { 
      _url = url; 
     } 
    } 
    public void setLogin(String login) { 
     _login = login; 
    } 
    public void setPassword(String password) { 
     _password = password; 
    } 
    public boolean hasLogin() { 
     return _login != null; 
    } 
    public boolean hasPassword() { 
     return _password != null; 
    } 
    public String toString() { 
     return _url; 
    } 
    /** 
    * Test if the server has a login and a password. 
    * @return Return true if the server has a login and a password, false otherwise. 
    */ 
    public boolean hasConnectionId() { 
     return _login != null && !_login.isEmpty() && _password != null && !_password.isEmpty(); 
    } 
} 

該窗口由控制器推出:

package com.maxbester.test; 

public class Controller { 

    public Controller() { 
     Server server = new Server("myserver"); 
     login(server); 
    } 

    /** 
    * <p>This method opens a login window and waits until a signal is receive from 
    * that window. When the signal is received, closes the window.</p> 
    * <p>The login window has to update the login and password of 'Server'.</p> 
    * @param server 
    */ 
    private synchronized void askLoginPassword(final Server server) { 
     server.setLogin(null); 
     server.setPassword(null); 
     while (server.hasConnectionId() == false) { 
      LoginWindow loginWindow = new LoginWindow(Controller.this, server); 
      try { 
       loginWindow.setVisible(true); 
       wait(); 
      } catch (InterruptedException e) { 
       LOG.error("Thread exception", e); 
       JOptionPane.showMessageDialog(loginWindow, "Thread exception", "Error", JOptionPane.ERROR_MESSAGE); 
      } finally { 
       loginWindow.dispose(); 
       loginWindow = null; 
      } 
     } 
    } 

    /** 
    * <p>First of all, this method tests if the server is reachable.</p> 
    * <p>If it is, the method opens a LoginWindow in order to ask the user ids.</p> 
    * <p>When we have the information, the function checks if the 
    * login and password are correct. If they are not, the function repeats the operation.</p> 
    * @param server 
    */ 
    private void login(Server server) { 
     boolean badLogin = true; 
     do { 
      askLoginPassword(server); 
      try { 
       // test if password is OK, if it is not, throw exception 

       badLogin = false; 
      } catch (Exception e) { 
       badLogin = true; 
       LOG.error(e.getMessage(), e); 
       JOptionPane.showMessageDialog(null, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); 
      } 
     } while(badLogin); 
    } 
} 
+0

從哪裏調用'askLoginPassword'方法? – asermax

+0

從Controller構造函數中。我將把它添加到問題中。抱歉。 – Maxbester

+0

不用擔心。事情是,在哪個線程發生?如果從GUI事件偵聽器創建'Controller'(並隨後調用'askLoginPassword'方法),則可能會阻塞事件線程。 – asermax

回答

0

這是一個有點不清楚precisley發生了什麼(尤其是WRT線程) - 但我認爲,你應該去看看SwingWorker文檔,看看如何處理長時間運行的任務,

很難看出哪個是長時間運行方法(我認爲這被註釋掉了) - 但這是可能需要與GUI線程分開保存的peice。

此外,您預計登錄窗口何時會消失? - 在收到服務器響應之前或之後。

(編輯回覆評論)

+0

_長時間運行的方法[..],但這是可能需要被調用()稍後的peice_否,那將會(並且確實)阻止EDT。長時間運行的東西必須在後臺線程上運行。 InvokeLater將結果傳遞迴EDT。 – kleopatra

+0

我快速瀏覽了SwingWorker,但我認爲這不是我需要的。我的控制器類做了很多事情,不是面向HMI的。我想分離GUI和業務(MVC模式)。對於其他HMI,我實現了Observer模式。我想我也可以爲LoginWindow做。但是對於這樣一個小窗口聽起來相當沉重......你覺得怎麼樣? – Maxbester