--- a/usr/src/java/vpanels/client/org/opensolaris/os/vp/client/common/ConnectionManager.java Wed Nov 03 17:45:45 2010 -0700
+++ b/usr/src/java/vpanels/client/org/opensolaris/os/vp/client/common/ConnectionManager.java Fri Nov 05 15:51:25 2010 -0400
@@ -20,12 +20,12 @@
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
package org.opensolaris.os.vp.client.common;
+import java.beans.*;
import java.util.*;
import javax.management.*;
import javax.management.remote.JMXConnectionNotification;
@@ -99,6 +99,9 @@
}
};
+ private ConnectionListListeners listeners =
+ new ConnectionListListeners();
+
//
// ConnectionManager methods
//
@@ -125,6 +128,7 @@
connection = new ManagedConnection(info);
connections.add(connection);
+ fireAddEvent(info);
}
Set<ConnectionListener> clients = connection.getClients();
@@ -176,6 +180,21 @@
}
/**
+ * Gets a list of healthy {@code ConnectionInfo} objects managed by
+ * this instance.
+ */
+ public synchronized List<ConnectionInfo> getConnections() {
+ List<ConnectionInfo> list = new LinkedList<ConnectionInfo>();
+
+ for (ManagedConnection connection : connections) {
+ if (connection.isHealthy()) {
+ list.add(connection.getConnectionInfo());
+ }
+ }
+ return list;
+ }
+
+ /**
* Removes a {@link ConnectionListener} from the list of clients to be
* notified when {@code info} fails or is replaced. When the last of these
* clients is {@link #remove removed}, {@code info} will be removed from
@@ -192,16 +211,41 @@
* {@code info} to the above test for removal from management
*/
public synchronized void remove(ConnectionInfo info,
- ConnectionListener client) {
-
+ ConnectionListener client) {
ManagedConnection connection = getManagedConnection(info);
remove(connection, client);
}
+ /**
+ * Adds a {@code ConnectionListListener} to notification.
+ */
+ public synchronized void addConnectionListListener(
+ ConnectionListListener listener) {
+ listeners.add(listener);
+ }
+
+ /**
+ * Removes a {@code ConnectionListListener} from notification.
+ */
+ public synchronized void removeConnectionListListener(
+ ConnectionListListener listener) {
+ listeners.remove(listener);
+ }
+
//
// Private methods
//
+ // Fire the add connection event.
+ private synchronized void fireAddEvent(ConnectionInfo info) {
+ listeners.connectionAdded(new ConnectionEvent(this, info));
+ }
+
+ // Fire the remove connection event.
+ private synchronized void fireRemoveEvent(ConnectionInfo info) {
+ listeners.connectionRemoved(new ConnectionEvent(this, info));
+ }
+
private synchronized void fireConnectionFailed(ConnectionInfo info) {
ManagedConnection connection = getManagedConnection(info);
@@ -293,6 +337,7 @@
if (remove) {
connections.remove(connection);
+ fireRemoveEvent(info);
try {
info.getConnector().removeConnectionNotificationListener(
--- a/usr/src/java/vpanels/client/org/opensolaris/os/vp/client/common/RadLoginManager.java Wed Nov 03 17:45:45 2010 -0700
+++ b/usr/src/java/vpanels/client/org/opensolaris/os/vp/client/common/RadLoginManager.java Fri Nov 05 15:51:25 2010 -0400
@@ -794,7 +794,7 @@
}
// Authentication failed
- if (user.isEditable()) {
+ if (user.isEditable() || user.isEditableOnError()) {
user.setErrored(true);
}
@@ -888,7 +888,7 @@
}
// Authentication failed
- if (role.isEditable()) {
+ if (role.isEditable() || role.isEditableOnError()) {
role.setErrored(true);
}
--- a/usr/src/java/vpanels/client/org/opensolaris/os/vp/client/swing/AppInstance.java Wed Nov 03 17:45:45 2010 -0700
+++ b/usr/src/java/vpanels/client/org/opensolaris/os/vp/client/swing/AppInstance.java Fri Nov 05 15:51:25 2010 -0400
@@ -28,6 +28,7 @@
import java.awt.Window;
import java.awt.event.*;
import java.net.URL;
+import java.beans.*;
import java.security.*;
import java.util.*;
import java.util.logging.*;
@@ -78,7 +79,7 @@
//
private App app;
-
+ private LoginHistory loginHistory;
private BusyIndicator busy;
private ConnectionInfo info;
private HelpBroker helpBroker;
@@ -107,6 +108,10 @@
return SwingNavigator.getLastWindow(getNavigator());
}
});
+
+ // Initialize login history.
+ loginHistory = AppLoginHistory.getInstance(
+ app.getConnectionManager());
}
public AppInstance(App app, Properties hints, ConnectionInfo info) {
@@ -283,6 +288,11 @@
showHelpAction.actionPerformed(event);
}
+ @Override
+ public LoginHistory getLoginHistory() {
+ return loginHistory;
+ }
+
//
// AppInstance methods
//
@@ -295,7 +305,6 @@
if (info != null) {
app.getConnectionManager().remove(info, this);
}
-
app.instanceClosed(this);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/java/vpanels/client/org/opensolaris/os/vp/client/swing/AppLoginHistory.java Fri Nov 05 15:51:25 2010 -0400
@@ -0,0 +1,289 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+package org.opensolaris.os.vp.client.swing;
+
+import java.beans.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.logging.*;
+import javax.swing.event.*;
+import org.opensolaris.os.vp.client.common.ConnectionManager;
+import org.opensolaris.os.vp.panel.common.*;
+import org.opensolaris.os.vp.util.misc.NetUtil;
+import org.opensolaris.os.vp.util.swing.event.ChangeListeners;
+
+public class AppLoginHistory implements LoginHistory {
+ //
+ // Instance data
+ //
+
+ // The only instance of this class.
+ private static AppLoginHistory instance = null;
+
+ // Used to format logins as host:user:role
+ private static final String LOGIN_DELIMITER = ":";
+
+ // File used to persist login history.
+ private File loginFile = new File(App.VP_USER_DIR, "history");
+
+ // The size of persisted login history.
+ private static final int LOGINS_SIZE = 5;
+
+ // Array used to maintain login history.
+ private Stack<LoginInfo> logins = new Stack<LoginInfo>();
+
+ // ConnectionManager used for logins.
+ private ConnectionManager connManager = null;
+
+ // login history listeners.
+ private ChangeListeners listeners = new ChangeListeners();
+
+ // ConnectionManager listener.
+ private ConnectionListListener connListener =
+ new ConnectionListListener() {
+ @Override
+ public void connectionRemoved(ConnectionEvent event) {
+ // Don't clear history when connections are removed.
+ }
+
+ @Override
+ public void connectionAdded(ConnectionEvent event) {
+ LoginInfo info = (LoginInfo) event.getConnectionInfo();
+
+ if (info != null) {
+ // Push to top of stack.
+ if (!updateLogin(info)) {
+ pushLogin(info);
+ writeLogins();
+ fireStateChanged();
+ }
+ }
+ }
+ };
+
+ //
+ // Constructors
+ //
+
+ // There is only one instance of this class.
+ private AppLoginHistory(ConnectionManager connManager) {
+ this.connManager = connManager;
+ if (connManager != null) {
+ connManager.addConnectionListListener(connListener);
+ }
+ readLogins();
+ }
+
+ //
+ // LoginHistory methods
+ //
+
+ @Override
+ public void clearLogins() {
+ logins.clear();
+ loginFile.delete();
+ fireStateChanged();
+ }
+
+ @Override
+ public List<LoginInfo> getLogins() {
+ return new ArrayList<LoginInfo>(logins);
+ }
+
+ //
+ // AppLoginHistory methods
+ //
+
+ /**
+ * Get {@code AppLoginHistory} instance.
+ */
+ public static AppLoginHistory getInstance(ConnectionManager connManager) {
+ if (instance == null) {
+ instance = new AppLoginHistory(connManager);
+ }
+ return instance;
+ }
+
+ /**
+ * Adds a {@code ChangeListener} to be notified upon changes in state.
+ */
+ public void addChangeListener(ChangeListener listener) {
+ listeners.add(listener);
+ }
+
+ /**
+ * Removes a {@code ChangeListener} from notification.
+ */
+ public void removeChangeListener(ChangeListener listener) {
+ listeners.remove(listener);
+ }
+
+ //
+ // Private methods
+ //
+
+ // Fire property change event.
+ private void fireStateChanged() {
+ listeners.stateChanged(new ChangeEvent(this));
+ }
+
+ // Push logins to top of stack.
+ private void pushLogin(LoginInfo info) {
+ logins.push(info);
+ if (logins.size() > LOGINS_SIZE) {
+ logins.remove(0);
+ }
+ }
+
+ // Update existing login. Returns true if a match was found.
+ private boolean updateLogin(LoginInfo info) {
+ boolean match = false;
+ for (int i = 0; i < logins.size(); i++) {
+ LoginInfo oldInfo = logins.elementAt(i);
+
+ // Don't display dup localhost for matching host name.
+ if (oldInfo.matches(info)) {
+ match = true;
+ } else if (NetUtil.isLoopbackAddress(info.getHost())) {
+ // localhost given as host.
+ if (oldInfo.matches(NetUtil.getHostName(), info.getUser(),
+ info.getRole())) {
+ match = true;
+ }
+ } else if (NetUtil.isLoopbackAddress(oldInfo.getHost())) {
+ // localhost found in stack.
+ if (info.matches(NetUtil.getHostName(), oldInfo.getUser(),
+ oldInfo.getRole())) {
+ match = true;
+ }
+ }
+
+ // Replace login info created from history file.
+ if (match) {
+ logins.setElementAt(info, i);
+ break;
+ }
+ }
+ return match;
+ }
+
+ // Read persistent login history.
+ private void readLogins() {
+ // Ensure file exists.
+ if (!loginFile.canRead()) {
+ String message = "Cannot read login history: " +
+ loginFile.getAbsolutePath();
+ Logger.getLogger(getClass().getName()).log(
+ Level.WARNING, message);
+ return;
+ }
+
+ try {
+ BufferedReader reader = new BufferedReader(
+ new FileReader(loginFile));
+
+ int i = 0;
+ String line = null;
+
+ // Read login history
+ while ((line = reader.readLine()) != null
+ && i < LOGINS_SIZE) {
+ StringTokenizer st = new StringTokenizer(line, LOGIN_DELIMITER);
+
+ // Login history formated as host:user:role
+ String host = null;
+ if (st.hasMoreTokens()) {
+ host = st.nextToken();
+ }
+ String user = null;
+ if (st.hasMoreTokens()) {
+ user = st.nextToken();
+ }
+ String role = null;
+ if (st.hasMoreTokens()) {
+ role = st.nextToken();
+ }
+
+ // Populate logins history.
+ if (host != null && host.length() > 0
+ && user != null && user.length() > 0) {
+ ConnectionInfo info = new ConnectionInfo(
+ host, user, role, null);
+ if (!updateLogin(info)) {
+ pushLogin(info);
+ }
+ }
+ }
+ reader.close();
+ } catch (IOException e) {
+ String message = "Cannot obtain login history";
+ Logger.getLogger(getClass().getName()).log(
+ Level.WARNING, message, e);
+ }
+ }
+
+ // Write persistent login history.
+ private void writeLogins() {
+ File loginDir = loginFile.getParentFile();
+
+ // Ensure directory exists.
+ if (!loginDir.exists()) {
+ if (!loginDir.mkdirs()) {
+ String message = "Cannot create login history directory: " +
+ loginDir.getAbsolutePath();
+ Logger.getLogger(getClass().getName()).log(
+ Level.WARNING, message);
+ return;
+ }
+ }
+
+ try {
+ // Write new file.
+ File tmpFile = File.createTempFile(loginFile.getName(), ".tmp",
+ loginDir);
+ BufferedWriter writer = new BufferedWriter(new FileWriter(tmpFile));
+
+ // Format logins as host:user:role
+ for (LoginInfo info : logins) {
+ if (info.getRole() != null && info.getRole().length() > 0) {
+ writer.write(info.getHost() + LOGIN_DELIMITER +
+ info.getUser() + LOGIN_DELIMITER + info.getRole());
+ } else {
+ writer.write(info.getHost() + LOGIN_DELIMITER +
+ info.getUser());
+ }
+ writer.newLine();
+ }
+ tmpFile.renameTo(loginFile);
+ writer.close();
+ } catch (IOException e) {
+ String message = "Cannot persist login history";
+ Logger.getLogger(getClass().getName()).log(
+ Level.WARNING, message, e);
+ }
+ }
+}
--- a/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/common/ClientContext.java Wed Nov 03 17:45:45 2010 -0700
+++ b/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/common/ClientContext.java Fri Nov 05 15:51:25 2010 -0400
@@ -116,4 +116,9 @@
* Displays the {@link #getHelpBroker HelpBroker}'s help.
*/
void showHelp();
+
+ /**
+ * Gets the login history associated with connection manager.
+ */
+ LoginHistory getLoginHistory();
}
--- a/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/common/ConnectionInfo.java Wed Nov 03 17:45:45 2010 -0700
+++ b/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/common/ConnectionInfo.java Fri Nov 05 15:51:25 2010 -0400
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
package org.opensolaris.os.vp.panel.common;
@@ -34,7 +33,7 @@
* The {@code ConnectionInfo} class encapsulate an open {@code JMXConnector} and
* some of its attributes.
*/
-public class ConnectionInfo {
+public class ConnectionInfo implements LoginInfo {
//
// Instance data
//
@@ -83,10 +82,6 @@
return connector;
}
- public String getHost() {
- return host;
- }
-
public synchronized InetAddress[] getInetAddresses() {
if (addrs == null) {
try {
@@ -98,22 +93,6 @@
return addrs;
}
- public String getRole() {
- return role;
- }
-
- public String getUser() {
- return user;
- }
-
- public boolean matches(String host, String user, String role) {
- return matchesUser(user) && matchesRole(role) && matchesHost(host);
- }
-
- public boolean matches(ConnectionInfo info) {
- return matches(info.getHost(), info.getUser(), info.getRole());
- }
-
public boolean matchesHost(String host) {
// Avoid IP resolution if possible
if (ObjectUtil.equals(host, getHost())) {
@@ -144,4 +123,33 @@
public boolean matchesUser(String user) {
return user.equals(getUser());
}
+
+ //
+ // LoginInfo methods
+ //
+
+ @Override
+ public String getHost() {
+ return host;
+ }
+
+ @Override
+ public String getRole() {
+ return role;
+ }
+
+ @Override
+ public String getUser() {
+ return user;
+ }
+
+ @Override
+ public boolean matches(String host, String user, String role) {
+ return matchesUser(user) && matchesRole(role) && matchesHost(host);
+ }
+
+ @Override
+ public boolean matches(LoginInfo info) {
+ return matches(info.getHost(), info.getUser(), info.getRole());
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/common/ConnectionListListener.java Fri Nov 05 15:51:25 2010 -0400
@@ -0,0 +1,46 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+package org.opensolaris.os.vp.panel.common;
+
+/**
+ * The {@code ConnectionListListener} interface defines common
+ * connection list functionality.
+ */
+public interface ConnectionListListener {
+ /**
+ * Notify listener that a connection has been added.
+ *
+ * @param event The {@code ConnectionEvent} object associated with event.
+ */
+ void connectionAdded(ConnectionEvent event);
+
+ /**
+ * Notify listener that a connection has been removed.
+ *
+ * @param event The {@code ConnectionEvent} object associated with event.
+ */
+ void connectionRemoved(ConnectionEvent event);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/common/ConnectionListListeners.java Fri Nov 05 15:51:25 2010 -0400
@@ -0,0 +1,77 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+package org.opensolaris.os.vp.panel.common;
+
+import org.opensolaris.os.vp.util.misc.event.*;
+
+/**
+ * The {@code ConnectionListListeners} class encapsulates event listener
+ * management.
+ */
+public class ConnectionListListeners extends
+ EventListeners<ConnectionListListener>
+ implements ConnectionListListener {
+
+ //
+ // Static data
+ //
+
+ private static final
+ EventDispatcher<ConnectionEvent, ConnectionListListener>
+ addDispatcher =
+ new EventDispatcher<ConnectionEvent, ConnectionListListener>() {
+ @Override
+ public void dispatch(ConnectionListListener listener,
+ ConnectionEvent event) {
+ listener.connectionAdded(event);
+ }
+ };
+
+ private static final
+ EventDispatcher<ConnectionEvent, ConnectionListListener>
+ removeDispatcher =
+ new EventDispatcher<ConnectionEvent, ConnectionListListener>() {
+ @Override
+ public void dispatch(ConnectionListListener listener,
+ ConnectionEvent event) {
+ listener.connectionRemoved(event);
+ }
+ };
+
+ //
+ // ConnectionListListener methods
+ //
+
+ @Override
+ public void connectionAdded(ConnectionEvent e) {
+ dispatch(addDispatcher, e);
+ }
+
+ @Override
+ public void connectionRemoved(ConnectionEvent e) {
+ dispatch(removeDispatcher, e);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/common/LoginHistory.java Fri Nov 05 15:51:25 2010 -0400
@@ -0,0 +1,60 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+package org.opensolaris.os.vp.panel.common;
+
+import java.beans.*;
+import java.util.*;
+import javax.swing.event.*;
+
+/**
+ * The {@code LoginHistory} interface defines common login history
+ * functionality.
+ *
+ * Note: This interface allows {@link ClientContext#getLoginHistory} to be
+ * defined while {@code AppLoginHistory} is located in the
+ * org.opensolaris.os.vp.client.swing package.
+ */
+public interface LoginHistory {
+ /**
+ * Clears login history.
+ */
+ public void clearLogins();
+
+ /**
+ * Gets a list of {@code LoginInfo} objects.
+ */
+ public List<LoginInfo> getLogins();
+
+ /**
+ * Adds a {@code ChangeListener} to be notified upon changes in state.
+ */
+ public void addChangeListener(ChangeListener listener);
+
+ /**
+ * Removes a {@code ChangeListener} from notification.
+ */
+ public void removeChangeListener(ChangeListener listener);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/common/LoginInfo.java Fri Nov 05 15:51:25 2010 -0400
@@ -0,0 +1,57 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+package org.opensolaris.os.vp.panel.common;
+
+/**
+ * The {@code LoginInfo} interface encapsulates common
+ * login attributes.
+ */
+public interface LoginInfo {
+ /**
+ * Gets the host for this login.
+ */
+ public String getHost();
+
+ /**
+ * Gets the role for this login.
+ */
+ public String getRole();
+
+ /**
+ * Gets the user for this login.
+ */
+ public String getUser();
+
+ /**
+ * Test if given properties match this instance.
+ */
+ public boolean matches(String host, String user, String role);
+
+ /**
+ * Test if given {@link LoginInfo} matches this instance.
+ */
+ public boolean matches(LoginInfo info);
+}
--- a/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/common/LoginProperty.java Wed Nov 03 17:45:45 2010 -0700
+++ b/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/common/LoginProperty.java Fri Nov 05 15:51:25 2010 -0400
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
package org.opensolaris.os.vp.panel.common;
@@ -34,6 +33,7 @@
private String name;
private String value;
private boolean editable;
+ private boolean editableOnError;
private boolean errored;
private boolean masked;
@@ -88,6 +88,13 @@
}
/**
+ * Gets whether this {@code LoginProperty} is editable in an errored state.
+ */
+ public boolean isEditableOnError() {
+ return editableOnError;
+ }
+
+ /**
* Gets whether this {@code LoginProperty} is in an errored state.
*/
public boolean isErrored() {
@@ -102,10 +109,27 @@
}
/**
+ * Sets whether this {@code LoginProperty} is editable.
+ */
+ public void setEditable(boolean editable) {
+ this.editable = editable;
+ }
+
+ /**
+ * Sets whether this {@code LoginProperty} is editable in an errored state.
+ */
+ public void setEditableOnError(boolean editableOnError) {
+ this.editableOnError = editableOnError;
+ }
+
+ /**
* Sets whether this {@code LoginProperty} is in an errored state.
*/
public void setErrored(boolean errored) {
this.errored = errored;
+ if (isEditableOnError()) {
+ setEditable(true);
+ }
}
/**
--- a/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/swing/control/PanelFrameControl.java Wed Nov 03 17:45:45 2010 -0700
+++ b/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/swing/control/PanelFrameControl.java Fri Nov 05 15:51:25 2010 -0400
@@ -25,11 +25,13 @@
package org.opensolaris.os.vp.panel.swing.control;
+import java.awt.EventQueue;
import java.awt.event.*;
import java.beans.*;
import java.util.*;
import java.util.logging.*;
-import javax.swing.Icon;
+import javax.swing.*;
+import javax.swing.event.*;
import javax.swing.border.Border;
import org.opensolaris.os.vp.panel.common.*;
import org.opensolaris.os.vp.panel.common.action.ActionAbortedException;
@@ -48,15 +50,16 @@
// Instance data
//
- private String title;
+ // Login popup menu.
+ private JPopupMenu popupMenu;
- private ActionListener loginListener =
- new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- promptForLogin(getClientContext());
- }
- };
+ // Clear popup menu item.
+ private JMenuItem clearMenuItem;
+
+ // Login menu item count.
+ private int loginItemCount = 0;
+
+ private String title;
private ConnectionListener connListener =
new ConnectionListener() {
@@ -90,12 +93,35 @@
}
};
+ // Listener to recreate popup menu on login changes.
+ private ChangeListener loginListener = new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ createLoginItems();
+ }
+ };
+
+ // Listener to display popup menu on mouse navigation.
+ private ActionListener loginActionListener =
+ new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (!popupMenu.isVisible()) {
+ JButton button = getComponent().getAuthPanel().getButton();
+ popupMenu.show(button, 0, button.getHeight());
+ } else {
+ popupMenu.setVisible(false);
+ }
+ }
+ };
+
//
// Constructors
//
public PanelFrameControl(String id, String name, P descriptor) {
super(id, name, descriptor);
+ popupMenu = createPopupMenu();
}
public PanelFrameControl(P descriptor) {
@@ -141,8 +167,11 @@
ManagedObject.PROPERTY_STATUS_TEXT, statusListener);
statusChanged();
- getComponent().getAuthPanel().getButton().addActionListener(
- loginListener);
+ JButton button = getComponent().getAuthPanel().getButton();
+ button.addActionListener(loginActionListener);
+
+ context.getLoginHistory().addChangeListener(loginListener);
+ createLoginItems();
}
@Override
@@ -151,13 +180,14 @@
ClientContext context = getClientContext();
context.removeConnectionListener(connListener);
+ context.getLoginHistory().removeChangeListener(loginListener);
PanelDescriptor descriptor = getPanelDescriptor();
descriptor.removePropertyChangeListener(healthListener);
descriptor.removePropertyChangeListener(statusListener);
- getComponent().getAuthPanel().getButton().removeActionListener(
- loginListener);
+ JButton button = getComponent().getAuthPanel().getButton();
+ button.removeActionListener(loginActionListener);
}
//
@@ -231,6 +261,179 @@
return GUIUtil.getEmptyBorder();
}
+ /**
+ * Gets a {@code PopupMenu} to display when the
+ * login button is clicked.
+ *
+ * @return A {@code PopupMenu} menu.
+ */
+ protected JPopupMenu getPopupMenu() {
+ return popupMenu;
+ }
+
+ /**
+ * Creates a {@code PopupMenu} to display when the login button is clicked.
+ * This popup menu does not include {@link #createLoginItem} objects.
+ *
+ * @return A {@code PopupMenu} menu.
+ */
+ protected JPopupMenu createPopupMenu() {
+ JPopupMenu menu = new JPopupMenu();
+
+ JMenuItem roleItem = createRoleItem();
+ menu.add(roleItem);
+
+ JMenuItem userItem = createUserItem();
+ menu.add(userItem);
+
+ JMenuItem adminItem = createAdminItem();
+ menu.addSeparator();
+ menu.add(adminItem);
+
+ clearMenuItem = createClearItem();
+ menu.addSeparator();
+ menu.add(clearMenuItem);
+
+ return menu;
+ }
+
+ /**
+ * Creates an admin {@code MenuItem} object for use with the
+ * {@link #getPopupMenu} popup menu.
+ *
+ * @return A {@code MenuItem} item.
+ */
+ protected JMenuItem createAdminItem() {
+ JMenuItem loginItem = new JMenuItem(Finder.getString(
+ "login.popup.admin"));
+ loginItem.addActionListener(
+ new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ ClientContext context = getClientContext();
+ promptForLogin(context,
+ createHostRequest(context.getConnectionInfo()));
+ }
+ });
+ return loginItem;
+ }
+
+ /**
+ * Creates a clear {@code MenuItem} object for use with the
+ * {@link #getPopupMenu} popup menu.
+ *
+ * @return A {@code MenuItem} item.
+ */
+ protected JMenuItem createClearItem() {
+ JMenuItem item = new JMenuItem(Finder.getString("login.popup.clear"));
+ item.addActionListener(
+ new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ EventQueue.invokeLater(
+ new Runnable() {
+ @Override
+ public void run() {
+ getClientContext().getLoginHistory().
+ clearLogins();
+ }
+ });
+ }
+ });
+ return item;
+ }
+
+ /**
+ * Creates {@link #createLoginItem} objects for the {@link #getPopupMenu}
+ * popup menu.
+ */
+ protected void createLoginItems() {
+ ClientContext context = getClientContext();
+ List<LoginInfo> logins = context.getLoginHistory().getLogins();
+
+ // Remove existing login menu items.
+ while (loginItemCount > 0) {
+ popupMenu.remove(0);
+ loginItemCount--;
+ }
+
+ // Add logins, if any.
+ for (LoginInfo info : logins) {
+ JMenuItem loginItem = createLoginItem(info);
+ if (loginItem != null) {
+ popupMenu.insert(loginItem, loginItemCount++);
+ }
+ }
+
+ // Add separator.
+ if (!logins.isEmpty()) {
+ popupMenu.insert(new JPopupMenu.Separator(), loginItemCount++);
+ }
+
+ // Enable clear menu item.
+ clearMenuItem.setEnabled(!logins.isEmpty());
+ }
+
+ /**
+ * Creates a login {@code MenuItem} object for use with the
+ * {@link #getPopupMenu} popup menu.
+ *
+ * @return A {@code MenuItem} item.
+ */
+ protected JMenuItem createLoginItem(final LoginInfo info) {
+ JMenuItem loginItem = new JMenuItem(AuthPanel.toString(info));
+ loginItem.addActionListener(
+ new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ promptForLogin(getClientContext(),
+ createStaticRequest(info));
+ }
+ });
+
+ return loginItem;
+ }
+
+ /**
+ * Creates a role {@code MenuItem} object for use with the
+ * {@link #getPopupMenu} popup menu.
+ *
+ * @return A {@code MenuItem} item.
+ */
+ protected JMenuItem createRoleItem() {
+ JMenuItem item = new JMenuItem(Finder.getString("login.popup.role"));
+ item.addActionListener(
+ new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ ClientContext context = getClientContext();
+ promptForLogin(context,
+ createRoleRequest(context.getConnectionInfo()));
+ }
+ });
+ return item;
+ }
+
+ /**
+ * Creates a user {@code MenuItem} object for use with the
+ * {@link #getPopupMenu} popup menu.
+ *
+ * @return A {@code MenuItem} item.
+ */
+ protected JMenuItem createUserItem() {
+ JMenuItem item = new JMenuItem(Finder.getString("login.popup.user"));
+ item.addActionListener(
+ new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ ClientContext context = getClientContext();
+ promptForLogin(context,
+ createUserRequest(context.getConnectionInfo()));
+ }
+ });
+ return item;
+ }
+
//
// Private methods
//
@@ -282,39 +485,63 @@
// Static methods
//
- /**
- * Asynchronously (on the given {@link ClientContext}'s {@link Navigator}'s
- * navigation thread) prompts the user to log in, then navigates any
- * resulting new {@link ClientContext} to the current path of given {@link
- * ClientContext}, ignoring any errors.
- */
- public static void promptForLogin(final ClientContext context) {
+ // Used when all properties are editable.
+ private static LoginRequest createHostRequest(final LoginInfo info) {
+ LoginProperty host = new LoginProperty(info.getHost(), true);
+ LoginProperty user = new LoginProperty(info.getUser(), true);
+ LoginProperty role = new LoginProperty(info.getRole(), true);
+ return new LoginRequest(host, user, role);
+ }
+
+ // Used when the role property is editable.
+ private static LoginRequest createRoleRequest(final LoginInfo info) {
+ LoginProperty host = new LoginProperty(info.getHost(), false);
+ LoginProperty user = new LoginProperty(info.getUser(), false);
+ LoginProperty role = new LoginProperty(info.getRole(), true);
+ return new LoginRequest(host, user, role);
+ }
+
+ // Used when no properties are editable.
+ private static LoginRequest createStaticRequest(final LoginInfo info) {
+ LoginProperty host = new LoginProperty(info.getHost(), false);
+ LoginProperty user = new LoginProperty(info.getUser(), false);
+ LoginProperty role = new LoginProperty(info.getRole(), false);
+
+ // Set editable for invalid properties.
+ host.setEditableOnError(true);
+ user.setEditableOnError(true);
+ role.setEditableOnError(true);
+
+ return new LoginRequest(host, user, role);
+ }
+
+ // Used when the user property is editable.
+ private static LoginRequest createUserRequest(final LoginInfo info) {
+ LoginProperty host = new LoginProperty(info.getHost(), false);
+ LoginProperty user = new LoginProperty(info.getUser(), true);
+ LoginProperty role = new LoginProperty(info.getRole(), true);
+ return new LoginRequest(host, user, role);
+ }
+
+ // Displays login panel per login request properties.
+ private static void promptForLogin(final ClientContext context,
+ final LoginRequest request) {
context.getNavigator().asyncExec(
new Runnable() {
@Override
public void run() {
- ConnectionInfo info = context.getConnectionInfo();
-
- LoginProperty host = new LoginProperty(info.getHost(),
- true);
- LoginProperty user = new LoginProperty(info.getUser(),
- true);
- LoginProperty role = new LoginProperty(info.getRole(),
- true);
- LoginRequest request = new LoginRequest(host, user, role);
-
try {
- ClientContext newContext = context.login(request,
+ ClientContext newContext = context.login(request,
false);
// New ClientContext?
if (newContext != context) {
// Duplicate path
- List<Control> path =
+ List<Control> path =
context.getNavigator().getPath();
Navigable[] array =
path.toArray(new Navigable[path.size()]);
- newContext.getNavigator().goToAsync(true, null,
+ newContext.getNavigator().goToAsync(true, null,
array);
}
} catch (ActionAbortedException ignore) {
@@ -327,4 +554,14 @@
}
});
}
+
+ /**
+ * Asynchronously (on the given {@link ClientContext}'s {@link Navigator}'s
+ * navigation thread) prompts the user to log in, then navigates any
+ * resulting new {@link ClientContext} to the current path of given {@link
+ * ClientContext}, ignoring any errors.
+ */
+ public static void promptForLogin(final ClientContext context) {
+ promptForLogin(context, createHostRequest(context.getConnectionInfo()));
+ }
}
--- a/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/swing/control/resources/Resources.properties Wed Nov 03 17:45:45 2010 -0700
+++ b/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/swing/control/resources/Resources.properties Fri Nov 05 15:51:25 2010 -0400
@@ -19,10 +19,7 @@
# CDDL HEADER END
#
-#
-# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
# Parameters: 0: title, 1: login
window.title.defaultlogin = {0}
@@ -56,3 +53,8 @@
connection.failed.message = The connection to {0} has been lost. Verify that {0} is reachable and its system/rad:default SMF service is enabled.
connection.failed.button.quit = Quit
connection.failed.button.reconnect = Reconnect...
+
+login.popup.admin = Administer New Host...
+login.popup.clear = Clear History...
+login.popup.role = Change Role...
+login.popup.user = Change User...
--- a/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/swing/view/AuthPanel.java Wed Nov 03 17:45:45 2010 -0700
+++ b/usr/src/java/vpanels/panel/org/opensolaris/os/vp/panel/swing/view/AuthPanel.java Fri Nov 05 15:51:25 2010 -0400
@@ -112,7 +112,7 @@
return Finder.getString(resource, host, user, role);
}
- public static String toString(ConnectionInfo info) {
+ public static String toString(LoginInfo info) {
if (info == null) {
return null;
}