--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/components/visual-panels/core/src/java/vpanels/panel/com/oracle/solaris/vp/panel/common/ConnectionTracker.java Thu May 24 04:16:47 2012 -0400
@@ -0,0 +1,523 @@
+/*
+ * 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, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+
+package com.oracle.solaris.vp.panel.common;
+
+import java.beans.*;
+import java.io.IOException;
+import java.util.*;
+import java.util.logging.*;
+import javax.management.*;
+import com.oracle.solaris.vp.util.misc.ObjectUtil;
+import com.oracle.solaris.vp.util.misc.event.PropertyChangeListeners;
+
+/**
+ * The {@code ConnectionTracker} class manages listeners that depend on
+ * connections.
+ * </p>
+ * {@code ConnectionListener}s that depend on a {@link ClientContext} are
+ * automatically removed/added when the tracked {@code ClientContext}
+ * fails/changes.
+ * </p>
+ * {@code NotificationListener}s that depend on an {@code MBeanServerConnection}
+ * are automatically removed/added when the tracked {@code
+ * MBeanServerConnection} or {@code ObjectName} changes.
+ * </p>
+ * Property change notifications are sent out when the tracked {@code
+ * ClientContext}, {@code ConnectionInfo}, {@code MBeanServerConnection}, or
+ * {@code ObjectName} changes.
+ */
+public class ConnectionTracker implements ConnectionListener {
+ //
+ // Inner classes
+ //
+
+ private abstract class NotifyParams<O> {
+ private O listener;
+ private NotificationFilter filter;
+ private Object handback;
+
+ //
+ // Constructors
+ //
+
+ public NotifyParams(O listener, NotificationFilter filter,
+ Object handback) {
+
+ this.listener = listener;
+ this.filter = filter;
+ this.handback = handback;
+ }
+
+ //
+ // NotifyParams methods
+ //
+
+ public boolean equals(Object listener) {
+ return ObjectUtil.equals(this.listener, listener);
+ }
+
+ public boolean equals(Object listener, NotificationFilter filter,
+ Object handback) {
+
+ return ObjectUtil.equals(this.listener, listener) &&
+ ObjectUtil.equals(this.filter, filter) &&
+ ObjectUtil.equals(this.handback, handback);
+ }
+
+ public O getListener() {
+ return listener;
+ }
+
+ public NotificationFilter getFilter() {
+ return filter;
+ }
+
+ public Object getHandback() {
+ return handback;
+ }
+
+ public abstract void add()
+ throws InstanceNotFoundException, IOException;
+
+ public abstract void remove()
+ throws InstanceNotFoundException, IOException;
+ }
+
+ private class ListenerNotifyParams
+ extends NotifyParams<NotificationListener> {
+ //
+ // Constructors
+ //
+
+ public ListenerNotifyParams(NotificationListener listener,
+ NotificationFilter filter, Object handback) {
+ super(listener, filter, handback);
+ }
+
+ //
+ // ListenerNotifyParams methods
+ //
+
+ @Override
+ public void add() throws InstanceNotFoundException, IOException {
+ if (mbsc != null && oName != null) {
+ mbsc.addNotificationListener(oName, getListener(), getFilter(),
+ getHandback());
+ }
+ }
+
+ @Override
+ public void remove() throws InstanceNotFoundException,
+ IOException {
+
+ if (mbsc != null && oName != null) {
+ try {
+ mbsc.removeNotificationListener(oName, getListener(),
+ getFilter(), getHandback());
+ } catch (ListenerNotFoundException ignore) {
+ }
+ }
+ }
+ }
+
+ private class ObjectNameNotifyParams extends NotifyParams<ObjectName> {
+ //
+ // Constructors
+ //
+
+ public ObjectNameNotifyParams(ObjectName listener,
+ NotificationFilter filter, Object handback) {
+ super(listener, filter, handback);
+ }
+
+ //
+ // ObjectNameNotifyParams methods
+ //
+
+ @Override
+ public void add() throws InstanceNotFoundException, IOException {
+ if (mbsc != null && oName != null) {
+ mbsc.addNotificationListener(oName, getListener(), getFilter(),
+ getHandback());
+ }
+ }
+
+ @Override
+ public void remove() throws InstanceNotFoundException,
+ IOException {
+
+ if (mbsc != null && oName != null) {
+ try {
+ mbsc.removeNotificationListener(oName, getListener(),
+ getFilter(), getHandback());
+ } catch (ListenerNotFoundException ignore) {
+ }
+ }
+ }
+ }
+
+ //
+ // Static data
+ //
+
+ /**
+ * The name of the property that changes with {@link #setClientContext}.
+ */
+ public static final String PROPERTY_CONTEXT = "context";
+
+ /**
+ * The name of the property that changes with {@link #setConnectionInfo}.
+ */
+ public static final String PROPERTY_INFO = "info";
+
+ /**
+ * The name of the property that changes with {@link
+ * #setMBeanServerConnection}.
+ */
+ public static final String PROPERTY_MBSC = "mbsc";
+
+ /**
+ * The name of the property that changes with {@link #setObjectName}.
+ */
+ public static final String PROPERTY_OBJECTNAME = "objectname";
+
+ //
+ // Instance data
+ //
+
+ private ClientContext context;
+ private ConnectionInfo info;
+ private MBeanServerConnection mbsc;
+ private ObjectName oName;
+ private PropertyChangeListeners pListeners = new PropertyChangeListeners();
+ private List<NotifyParams> nListeners = new LinkedList<NotifyParams>();
+
+ //
+ // Constructors
+ //
+
+ public ConnectionTracker(ObjectName oName) {
+ try {
+ setObjectName(oName);
+
+ // Impossible because no NotificationListeners have been added yet
+ } catch (TrackerException impossible) {
+ }
+ }
+
+ public ConnectionTracker(ObjectName oName, ClientContext context)
+ throws TrackerException {
+
+ this(oName);
+ setClientContext(context);
+ }
+
+ //
+ // ConnectionListener methods
+ //
+
+ @Override
+ public void connectionChanged(ConnectionEvent event) {
+ ConnectionInfo info = event.getConnectionInfo();
+
+ try {
+ setConnectionInfo(info);
+ } catch (TrackerException e) {
+ Logger.getLogger(getClass().getName()).log(
+ Level.SEVERE, "could not communicate with remote host", e);
+ }
+ }
+
+ @Override
+ public void connectionFailed(ConnectionEvent event) {
+ try {
+ setConnectionInfo(null);
+ } catch (Throwable ignore) {
+ }
+ }
+
+ //
+ // ConnectionTracker methods
+ //
+
+ public void addNotificationListener(NotificationListener listener,
+ NotificationFilter filter, Object handback)
+ throws InstanceNotFoundException, IOException {
+
+ NotifyParams params = new ListenerNotifyParams(listener, filter,
+ handback);
+
+ params.add();
+ nListeners.add(params);
+ }
+
+ public void addNotificationListener(ObjectName listener,
+ NotificationFilter filter, Object handback)
+ throws InstanceNotFoundException, IOException {
+
+ NotifyParams params = new ObjectNameNotifyParams(listener, filter,
+ handback);
+
+ params.add();
+ nListeners.add(params);
+ }
+
+ public void addPropertyChangeListener(String propName,
+ PropertyChangeListener listener) {
+ pListeners.add(propName, listener);
+ }
+
+ public void addPropertyChangeListener(PropertyChangeListener listener) {
+ pListeners.add(listener);
+ }
+
+ /**
+ * Sets the {@link #getClientContext ClientContext} to {@code null} and
+ * removes all listeners, ignoring any exceptions along the way.
+ */
+ public void dispose() {
+ try {
+ setClientContext(null);
+
+ // If something prevented us from removing a notification listener, it
+ // probably doesn't matter anymore.
+ } catch (TrackerException ignore) {
+ }
+
+ pListeners.clear();
+ nListeners.clear();
+ }
+
+ public ClientContext getClientContext() {
+ return context;
+ }
+
+ public ConnectionInfo getConnectionInfo() {
+ return info;
+ }
+
+ public MBeanServerConnection getMBeanServerConnection() {
+ return mbsc;
+ }
+
+ public ObjectName getObjectName() {
+ return oName;
+ }
+
+ protected PropertyChangeListeners getPropertyChangeListeners() {
+ return pListeners;
+ }
+
+ public void removeNotificationListener(NotificationListener listener)
+ throws InstanceNotFoundException, IOException {
+
+ for (Iterator<NotifyParams> i = nListeners.iterator(); i.hasNext();) {
+ NotifyParams params = i.next();
+ if (params.equals(listener)) {
+ params.remove();
+ i.remove();
+ }
+ }
+ }
+
+ public void removeNotificationListener(NotificationListener listener,
+ NotificationFilter filter, Object handback)
+ throws InstanceNotFoundException, IOException {
+
+ for (Iterator<NotifyParams> i = nListeners.iterator(); i.hasNext();) {
+ NotifyParams params = i.next();
+ if (params.equals(listener, filter, handback)) {
+ params.remove();
+ i.remove();
+ return;
+ }
+ }
+ }
+
+ public void removeNotificationListener(ObjectName listener)
+ throws InstanceNotFoundException, IOException {
+
+ for (Iterator<NotifyParams> i = nListeners.iterator(); i.hasNext();) {
+ NotifyParams params = i.next();
+ if (params.equals(listener)) {
+ params.remove();
+ i.remove();
+ }
+ }
+ }
+
+ public void removeNotificationListener(ObjectName name, ObjectName listener,
+ NotificationFilter filter, Object handback)
+ throws InstanceNotFoundException, IOException {
+
+ for (Iterator<NotifyParams> i = nListeners.iterator(); i.hasNext();) {
+ NotifyParams params = i.next();
+ if (params.equals(listener, filter, handback)) {
+ params.remove();
+ i.remove();
+ return;
+ }
+ }
+ }
+
+ public void removePropertyChangeListener(String propName,
+ PropertyChangeListener listener) {
+ pListeners.remove(propName, listener);
+ }
+
+ public void removePropertyChangeListener(PropertyChangeListener listener) {
+ pListeners.remove(listener);
+ }
+
+ /**
+ * Sets the {@code ClientContext}, then calls {@link #setConnectionInfo}.
+ *
+ * @exception TrackerException
+ * if an error occurred during initialization
+ */
+ public void setClientContext(ClientContext context)
+ throws TrackerException {
+
+ if (this.context != context) {
+ if (this.context != null) {
+ this.context.removeConnectionListener(this);
+ }
+
+ PropertyChangeEvent e = new PropertyChangeEvent(
+ this, PROPERTY_CONTEXT, this.context, context);
+ this.context = context;
+ pListeners.propertyChange(e);
+
+ setConnectionInfo(context == null ? null :
+ context.getConnectionInfo());
+
+ if (context != null) {
+ context.addConnectionListener(this);
+ }
+ }
+ }
+
+ /**
+ * Sets the {@code ConnectionInfo}, then calls {@link
+ * #setMBeanServerConnection}.
+ *
+ * @exception TrackerException
+ * if an error occurred during initialization
+ */
+ public void setConnectionInfo(ConnectionInfo info)
+ throws TrackerException {
+
+ if (this.info != info) {
+ PropertyChangeEvent e = new PropertyChangeEvent(
+ this, PROPERTY_INFO, this.info, info);
+ this.info = info;
+ pListeners.propertyChange(e);
+
+ try {
+ setMBeanServerConnection(info == null ? null :
+ info.getConnector().getMBeanServerConnection());
+ } catch (IOException ex) {
+ throw new TrackerException(ex);
+ }
+ }
+ }
+
+ /**
+ * Sets the {@code MBeanServerConnection}.
+ *
+ * @exception TrackerException
+ * if an error occurred during initialization
+ */
+ public void setMBeanServerConnection(MBeanServerConnection mbsc)
+ throws TrackerException {
+
+ if (this.mbsc != mbsc) {
+ removeNotificationListeners();
+
+ PropertyChangeEvent e = new PropertyChangeEvent(
+ this, PROPERTY_MBSC, this.mbsc, mbsc);
+ this.mbsc = mbsc;
+ pListeners.propertyChange(e);
+
+ addNotificationListeners();
+ }
+ }
+
+ /**
+ * Sets the {@code ObjectName}.
+ *
+ * @exception TrackerException
+ * if an error occurred during initialization
+ */
+ public void setObjectName(ObjectName oName)
+ throws TrackerException {
+
+ if (!ObjectUtil.equals(this.oName, oName)) {
+ removeNotificationListeners();
+
+ PropertyChangeEvent e = new PropertyChangeEvent(
+ this, PROPERTY_OBJECTNAME, this.oName, oName);
+ this.oName = oName;
+ pListeners.propertyChange(e);
+
+ addNotificationListeners();
+ }
+ }
+
+ //
+ // Private methods
+ //
+
+ private void addNotificationListeners()
+ throws TrackerException {
+
+ if (mbsc != null && oName != null) {
+ for (NotifyParams params : nListeners) {
+ try {
+ params.add();
+ } catch (InstanceNotFoundException e) {
+ throw new TrackerException(e);
+ } catch (IOException e) {
+ throw new TrackerException(e);
+ }
+ }
+ }
+ }
+
+ private void removeNotificationListeners() {
+ if (mbsc != null && oName != null) {
+ for (NotifyParams params : nListeners) {
+ try {
+ params.remove();
+
+ // If something prevented us from removing a notification
+ // listener, it probably doesn't matter anymore.
+ } catch (Throwable ignore) {
+ }
+ }
+ }
+ }
+}