/* The contents of this file are subject to the license and copyright terms * detailed in the license directory at the root of the source tree (also * available online at http://fedora-commons.org/license/). */ package fedora.client; import java.awt.BorderLayout; import java.awt.Container; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Properties; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.apache.log4j.Logger; import fedora.common.Constants; import fedora.server.access.FedoraAPIA; import fedora.server.management.FedoraAPIM; /** * Launch a dialog for logging into a Fedora repository. * * @author Chris Wilper */ public class LoginDialog extends JDialog { /** Logger for this class. */ private static final Logger LOG = Logger.getLogger(LoginDialog.class.getName()); private static final long serialVersionUID = 1L; private final JComboBox m_serverComboBox; private final JComboBox m_protocolComboBox; private final JComboBox m_usernameComboBox; private final JPasswordField m_passwordField; private final JComboBox m_contextComboBox; private String m_lastUsername = "fedoraAdmin"; private String m_lastServer = "localhost:8080"; private String m_lastProtocol = "http"; private String m_lastContext = Constants.FEDORA_DEFAULT_APP_CONTEXT; private final HashMap<String, String> m_usernames; private final HashMap<String, String> m_servers; private final HashMap<String, String> m_protocols; private final HashMap<String, String> m_contexts; public LoginDialog() { super(JOptionPane.getFrameForComponent(Administrator.getDesktop()), "Login", true); m_servers = new HashMap<String, String>(); m_contexts = new HashMap<String, String>(); m_protocols = new HashMap<String, String>(); m_protocols.put("http", ""); m_protocols.put("https", ""); m_usernames = new HashMap<String, String>(); JLabel serverLabel = new JLabel("Fedora Server"); JLabel protocolLabel = new JLabel("Protocol"); JLabel usernameLabel = new JLabel("Username"); JLabel passwordLabel = new JLabel("Password"); JLabel contextLabel = new JLabel("Context"); m_serverComboBox = new JComboBox(); m_serverComboBox.setEditable(true); m_protocolComboBox = new JComboBox(); m_protocolComboBox.setEditable(true); m_contextComboBox = new JComboBox(); m_contextComboBox.setEditable(true); m_usernameComboBox = new JComboBox(); m_usernameComboBox.setEditable(true); m_passwordField = new JPasswordField(); setComboBoxValues(); LoginAction loginAction = new LoginAction(this); JButton loginButton = new JButton(loginAction); loginAction.setButton(loginButton); loginButton.setEnabled(false); m_passwordField .getDocument() .addDocumentListener(new PasswordChangeListener(loginButton, m_passwordField)); m_passwordField.setAction(loginAction); JPanel inputPane = new JPanel(); inputPane.setBorder(BorderFactory .createCompoundBorder(BorderFactory .createCompoundBorder(BorderFactory .createEmptyBorder(6, 6, 6, 6), BorderFactory .createEtchedBorder()), BorderFactory .createEmptyBorder(6, 6, 6, 6))); GridBagLayout gridBag = new GridBagLayout(); inputPane.setLayout(gridBag); addLabelValueRows(new JLabel[] {serverLabel, protocolLabel, contextLabel, usernameLabel, passwordLabel}, new JComponent[] { m_serverComboBox, m_protocolComboBox, m_contextComboBox, m_usernameComboBox, m_passwordField}, gridBag, inputPane); JButton cancelButton = new JButton(new AbstractAction() { private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent evt) { dispose(); } }); if (Administrator.APIA == null) { cancelButton.setText("Exit"); // if haven't logged in yet } else { cancelButton.setText("Cancel"); } JPanel buttonPane = new JPanel(); buttonPane.add(loginButton); buttonPane.add(cancelButton); Container contentPane = getContentPane(); contentPane.setLayout(new BorderLayout()); contentPane.add(inputPane, BorderLayout.CENTER); contentPane.add(buttonPane, BorderLayout.SOUTH); addWindowListener(new WindowAdapter() { @Override public void windowOpened(WindowEvent evt) { m_passwordField.requestFocus(); } }); pack(); setLocation(Administrator.INSTANCE.getCenteredPos(getWidth(), getHeight())); setVisible(true); } // re-writes fedora-admin.properties with latest values for servers // and usernames public void saveProperties() { try { Properties props = new Properties(); props.setProperty("lastServer", m_lastServer); props.setProperty("lastProtocol", m_lastProtocol); props.setProperty("lastUsername", m_lastUsername); props.setProperty("lastContext", m_lastContext); Iterator<String> iter; int i; iter = m_servers.keySet().iterator(); i = 0; while (iter.hasNext()) { String name = iter.next(); props.setProperty("server" + i, name); i++; } iter = m_protocols.keySet().iterator(); i = 0; while (iter.hasNext()) { String name = iter.next(); props.setProperty("protocol" + i, name); i++; } iter = m_usernames.keySet().iterator(); i = 0; while (iter.hasNext()) { String name = iter.next(); props.setProperty("username" + i, name); i++; } iter = m_contexts.keySet().iterator(); i = 0; while (iter.hasNext()) { String name = iter.next(); props.setProperty("context" + i, name); i++; } props .store(new FileOutputStream(new File(Administrator.BASE_DIR, "fedora-admin.properties")), "Fedora Administrator saved settings"); } catch (Exception e) { System.err.println("Warning: Error writing properties: " + e.getClass().getName() + ": " + e.getMessage()); } } private void setComboBoxValues() { // get values from prop file, or use localhost:8080/fedoraAdmin if none try { Properties props = new Properties(); props .load(new FileInputStream(new File(Administrator.BASE_DIR, "fedora-admin.properties"))); Enumeration<?> names = props.propertyNames(); while (names.hasMoreElements()) { String prop = (String) names.nextElement(); if (prop.equals("lastServer")) { m_lastServer = props.getProperty(prop); } else if (prop.equals("lastProtocol")) { m_lastProtocol = props.getProperty(prop); } else if (prop.startsWith("lastContext")) { m_lastContext = props.getProperty(prop); } else if (prop.equals("lastUsername")) { m_lastUsername = props.getProperty(prop); } else if (prop.startsWith("server")) { m_servers.put(props.getProperty(prop), ""); } else if (prop.startsWith("protocol")) { m_protocols.put(props.getProperty(prop), ""); } else if (prop.startsWith("context")) { m_contexts.put(props.getProperty(prop), ""); } else if (prop.startsWith("username")) { m_usernames.put(props.getProperty(prop), ""); } } } catch (Exception e) { // if props file doesn't exist, this must be the first // time they've run the java client for this install, // so point them to the new one. JOptionPane.showMessageDialog(Administrator.getDesktop(), "Check out the new, web-based Fedora Administrator.\n" + "\n http://localhost:8080/fedora/admin\n\n" + "NOTE: The web-based Fedora Admin GUI will completely\n" + "replace this one in future releases of Fedora.", "Try the *New* Fedora Admin GUI!", JOptionPane.INFORMATION_MESSAGE); } // finally, populate them m_serverComboBox.addItem(m_lastServer); Iterator<String> sIter = m_servers.keySet().iterator(); while (sIter.hasNext()) { String a = sIter.next(); if (!a.equals(m_lastServer)) { m_serverComboBox.addItem(a); } } m_servers.put(m_lastServer, ""); m_protocolComboBox.addItem(m_lastProtocol); Iterator<String> protocolIter = m_protocols.keySet().iterator(); while (protocolIter.hasNext()) { String a = protocolIter.next(); if (!a.equals(m_lastProtocol)) { m_protocolComboBox.addItem(a); } } m_protocols.put(m_lastProtocol, ""); m_contextComboBox.addItem(m_lastContext); Iterator<String> contextIter = m_contexts.keySet().iterator(); while (contextIter.hasNext()) { String a = contextIter.next(); if (!a.equals(m_lastContext)) { m_contextComboBox.addItem(a); } } m_contexts.put(m_lastContext, ""); m_usernameComboBox.addItem(m_lastUsername); Iterator<String> uIter = m_usernames.keySet().iterator(); while (uIter.hasNext()) { String a = uIter.next(); if (!a.equals(m_lastUsername)) { m_usernameComboBox.addItem(a); } } m_usernames.put(m_lastUsername, ""); // make all entry widgets same size Dimension newSize = new Dimension(m_serverComboBox.getPreferredSize().width + 20, m_serverComboBox.getPreferredSize().height); m_serverComboBox.setPreferredSize(newSize); m_protocolComboBox.setPreferredSize(newSize); m_usernameComboBox.setPreferredSize(newSize); m_passwordField.setPreferredSize(newSize); } public void addLabelValueRows(JLabel[] labels, JComponent[] values, GridBagLayout gridBag, Container container) { GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(0, 6, 6, 6); for (int i = 0; i < labels.length; i++) { c.anchor = GridBagConstraints.EAST; c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last c.fill = GridBagConstraints.NONE; //reset to default c.weightx = 0.0; //reset to default gridBag.setConstraints(labels[i], c); container.add(labels[i]); c.gridwidth = GridBagConstraints.REMAINDER; //end row if (!(values[i] instanceof JComboBox)) { c.fill = GridBagConstraints.HORIZONTAL; } else { c.anchor = GridBagConstraints.WEST; } c.weightx = 1.0; gridBag.setConstraints(values[i], c); container.add(values[i]); } } // sets Administrator.APIA/M if success, throws Exception if fails. public void tryLogin(String protocol, String host, int port, String context, String user, String pass) throws Exception { try { LOG.info("Logging in..."); // get a FedoraClient String baseURL = protocol + "://" + host + ":" + port + "/" + context; FedoraClient fc = new FedoraClient(baseURL, user, pass); // attempt to connect via REST String serverVersion = fc.getServerVersion(); // ensure client is compatible with server, warn if not List<String> compatibleVersions = FedoraClient.getCompatibleServerVersions(); if (!compatibleVersions.contains(serverVersion)) { StringBuffer endText = new StringBuffer(); if (compatibleVersions.size() == 1) { // version A endText.append("version " + compatibleVersions.get(0)); } else { // versions A and B // versions A, B, and C endText.append("versions "); for (int i = 0; i < compatibleVersions.size(); i++) { if (i > 0) { if (i == compatibleVersions.size() - 1) { if (i > 1) { endText.append(","); } endText.append(" and "); } else { endText.append(", "); } } endText.append(compatibleVersions.get(i)); } } System.err.println("WARNING: Server version is " + serverVersion + ". This client is " + "only designed to work with " + endText.toString()); } // set SOAP stubs for Administrator Administrator.APIA = fc.getAPIA(); Administrator.APIM = fc.getAPIM(); } catch (Exception e) { if (e.getMessage().indexOf("Unauthorized") != -1 || e.getMessage().indexOf("Unrecognized") != -1) { throw new IOException("Bad username or password."); } else { if (e.getMessage() != null) { throw new IOException(e.getClass().getName() + ": " + e.getMessage()); } else { throw new IOException(e.getClass().getName()); } } } } public class PasswordChangeListener implements DocumentListener { private final JButton m_loginButton; private final JPasswordField m_passField; public PasswordChangeListener(JButton loginButton, JPasswordField pf) { m_loginButton = loginButton; m_passField = pf; } public void changedUpdate(DocumentEvent e) { dataChanged(); } public void insertUpdate(DocumentEvent e) { dataChanged(); } public void removeUpdate(DocumentEvent e) { dataChanged(); } public void dataChanged() { if (m_passField.getPassword().length == 0) { m_loginButton.setEnabled(false); } else { m_loginButton.setEnabled(true); } } } public class LoginAction extends AbstractAction { private static final long serialVersionUID = 1L; LoginDialog m_loginDialog; JButton m_button; public LoginAction(LoginDialog loginDialog) { super("Login"); m_loginDialog = loginDialog; } public void setButton(JButton button) { m_button = button; } public void actionPerformed(ActionEvent evt) { if (m_button.isEnabled()) { FedoraAPIA oldAPIA = Administrator.APIA; FedoraAPIM oldAPIM = Administrator.APIM; try { // pull out values and do a quick syntax check String hostPort = (String) m_serverComboBox.getSelectedItem(); int colonPos = hostPort.indexOf(":"); if (colonPos == -1) { throw new IOException("Server must be specified as host:port"); } String[] s = hostPort.split(":"); String host = s[0]; if (host.length() == 0) { throw new IOException("No server name provided."); } int port = 0; try { port = Integer.parseInt(s[1]); } catch (NumberFormatException nfe) { throw new IOException("Server port must be an integer."); } String protocol = (String) m_protocolComboBox.getSelectedItem(); if (protocol.equals("")) { throw new IOException("No protocol provided."); } String context = (String) m_contextComboBox.getSelectedItem(); if (context.equals("")){ throw new IOException("No context provided"); } String username = (String) m_usernameComboBox.getSelectedItem(); if (username.equals("")) { throw new IOException("No username provided."); } String pass = new String(m_passwordField.getPassword()); tryLogin(protocol, host, port, context, username, pass); // all looks ok...just save stuff and exit now m_lastServer = host + ":" + port; m_lastProtocol = protocol; m_lastUsername = username; m_loginDialog.saveProperties(); Administrator.INSTANCE.setLoginInfo(protocol, host, port, context, username, pass); m_loginDialog.dispose(); } catch (Exception e) { String msg = e.getMessage(); Administrator.showErrorDialog(m_loginDialog, "Login Error", msg, e); Administrator.APIA = oldAPIA; Administrator.APIM = oldAPIM; } } } } }