jdk/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java
changeset 4156 acaa49a2768a
parent 1510 e747d3193ef2
child 5175 56d64b1e78f9
--- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java	Wed Oct 21 16:28:57 2009 +0200
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java	Wed Oct 21 17:33:18 2009 +0200
@@ -25,12 +25,10 @@
 
 package javax.management.remote.rmi;
 
-import com.sun.jmx.mbeanserver.Util;
 import static com.sun.jmx.mbeanserver.Util.cast;
 import com.sun.jmx.remote.internal.ServerCommunicatorAdmin;
 import com.sun.jmx.remote.internal.ServerNotifForwarder;
 import com.sun.jmx.remote.security.JMXSubjectDomainCombiner;
-import com.sun.jmx.remote.security.NotificationAccessController;
 import com.sun.jmx.remote.security.SubjectDelegator;
 import com.sun.jmx.remote.util.ClassLoaderWithRepository;
 import com.sun.jmx.remote.util.ClassLogger;
@@ -38,7 +36,6 @@
 import com.sun.jmx.remote.util.OrderClassLoaders;
 
 import java.io.IOException;
-import java.lang.reflect.UndeclaredThrowableException;
 import java.rmi.MarshalledObject;
 import java.rmi.UnmarshalException;
 import java.rmi.server.Unreferenced;
@@ -59,25 +56,18 @@
 import javax.management.InstanceNotFoundException;
 import javax.management.IntrospectionException;
 import javax.management.InvalidAttributeValueException;
-import javax.management.JMX;
 import javax.management.ListenerNotFoundException;
 import javax.management.MBeanException;
 import javax.management.MBeanInfo;
 import javax.management.MBeanRegistrationException;
 import javax.management.MBeanServer;
 import javax.management.NotCompliantMBeanException;
-import javax.management.Notification;
 import javax.management.NotificationFilter;
 import javax.management.ObjectInstance;
 import javax.management.ObjectName;
 import javax.management.QueryExp;
 import javax.management.ReflectionException;
 import javax.management.RuntimeOperationsException;
-import javax.management.event.EventClientDelegate;
-import javax.management.event.EventClientDelegateMBean;
-import javax.management.event.EventClientNotFoundException;
-import javax.management.event.FetchingEventForwarder;
-import javax.management.namespace.JMXNamespaces;
 import javax.management.remote.JMXServerErrorException;
 import javax.management.remote.NotificationResult;
 import javax.management.remote.TargetedNotification;
@@ -168,6 +158,17 @@
         this.env = env;
     }
 
+    private synchronized ServerNotifForwarder getServerNotifFwd() {
+        // Lazily created when first use. Mainly when
+        // addNotificationListener is first called.
+        if (serverNotifForwarder == null)
+            serverNotifForwarder =
+                new ServerNotifForwarder(mbeanServer,
+                                         env,
+                                         rmiServer.getNotifBuffer(),
+                                         connectionId);
+        return serverNotifForwarder;
+    }
 
     public String getConnectionId() throws IOException {
         // We should call reqIncomming() here... shouldn't we?
@@ -178,7 +179,6 @@
         final boolean debug = logger.debugOn();
         final String  idstr = (debug?"["+this.toString()+"]":null);
 
-        final SubscriptionManager mgr;
         synchronized (this) {
             if (terminated) {
                 if (debug) logger.debug("close",idstr + " already terminated.");
@@ -193,12 +193,11 @@
                 serverCommunicatorAdmin.terminate();
             }
 
-            mgr = subscriptionManager;
-            subscriptionManager = null;
+            if (serverNotifForwarder != null) {
+                serverNotifForwarder.terminate();
+            }
         }
 
-        if (mgr != null) mgr.terminate();
-
         rmiServer.clientClosed(this);
 
         if (debug) logger.debug("close",idstr + " closed.");
@@ -997,7 +996,8 @@
             // remove all registered listeners
             for (int j=0; j<i; j++) {
                 try {
-                    doRemoveListener(names[j],ids[j]);
+                    getServerNotifFwd().removeNotificationListener(names[j],
+                                                                   ids[j]);
                 } catch (Exception eee) {
                     // strange
                 }
@@ -1247,330 +1247,22 @@
             final long csn = clientSequenceNumber;
             final int mn = maxNotifications;
             final long t = timeout;
-
-            final PrivilegedExceptionAction<NotificationResult> action =
-                new PrivilegedExceptionAction<NotificationResult>() {
-                    public NotificationResult run() throws IOException {
-                            return doFetchNotifs(csn, t, mn);
+            PrivilegedAction<NotificationResult> action =
+                new PrivilegedAction<NotificationResult>() {
+                    public NotificationResult run() {
+                        return getServerNotifFwd().fetchNotifs(csn, t, mn);
                     }
             };
-            try {
-                if (acc == null)
-                    return action.run();
-                else
-                    return AccessController.doPrivileged(action, acc);
-            } catch (IOException x) {
-                throw x;
-            } catch (RuntimeException x) {
-                throw x;
-            } catch (Exception x) {
-                // should not happen
-                throw new UndeclaredThrowableException(x);
-            }
-
+            if (acc == null)
+                return action.run();
+            else
+                return AccessController.doPrivileged(action, acc);
         } finally {
             serverCommunicatorAdmin.rspOutgoing();
         }
     }
 
     /**
-     * This is an abstraction class that let us use the legacy
-     * ServerNotifForwarder and the new EventClientDelegateMBean
-     * indifferently.
-     **/
-    private static interface SubscriptionManager {
-        public void removeNotificationListener(ObjectName name, Integer id)
-            throws InstanceNotFoundException, ListenerNotFoundException, IOException;
-        public void removeNotificationListener(ObjectName name, Integer[] ids)
-            throws Exception;
-        public NotificationResult fetchNotifications(long csn, long timeout, int maxcount)
-            throws IOException;
-        public Integer addNotificationListener(ObjectName name, NotificationFilter filter)
-            throws InstanceNotFoundException, IOException;
-        public void terminate()
-            throws IOException;
-    }
-
-    /**
-     * A SubscriptionManager that uses a ServerNotifForwarder.
-     **/
-    private static class LegacySubscriptionManager implements SubscriptionManager {
-        private final ServerNotifForwarder forwarder;
-        LegacySubscriptionManager(ServerNotifForwarder forwarder) {
-            this.forwarder = forwarder;
-        }
-
-        public void removeNotificationListener(ObjectName name, Integer id)
-            throws InstanceNotFoundException, ListenerNotFoundException,
-                IOException {
-            if (!JMXNamespaces.getContainingNamespace(name).equals("")) {
-                logger.debug("removeNotificationListener",
-                        "This connector server is not configured to support " +
-                        "forwarding of notification subscriptions to name spaces");
-                throw new RuntimeOperationsException(
-                    new UnsupportedOperationException(
-                    "removeNotificationListener on name space MBeans. "));
-                }
-            forwarder.removeNotificationListener(name,id);
-        }
-
-        public void removeNotificationListener(ObjectName name, Integer[] ids)
-            throws Exception {
-            if (!JMXNamespaces.getContainingNamespace(name).equals("")) {
-                logger.debug("removeNotificationListener",
-                        "This connector server is not configured to support " +
-                        "forwarding of notification subscriptions to name spaces");
-                throw new RuntimeOperationsException(
-                    new UnsupportedOperationException(
-                    "removeNotificationListener on name space MBeans. "));
-            }
-            forwarder.removeNotificationListener(name,ids);
-        }
-
-        public NotificationResult fetchNotifications(long csn, long timeout, int maxcount) {
-            return forwarder.fetchNotifs(csn,timeout,maxcount);
-        }
-
-        public Integer addNotificationListener(ObjectName name,
-                NotificationFilter filter)
-            throws InstanceNotFoundException, IOException {
-            if (!JMXNamespaces.getContainingNamespace(name).equals("")) {
-                logger.debug("addNotificationListener",
-                        "This connector server is not configured to support " +
-                        "forwarding of notification subscriptions to name spaces");
-                throw new RuntimeOperationsException(
-                    new UnsupportedOperationException(
-                    "addNotificationListener on name space MBeans. "));
-            }
-            return forwarder.addNotificationListener(name,filter);
-        }
-
-        public void terminate() {
-            forwarder.terminate();
-        }
-    }
-
-    /**
-     * A SubscriptionManager that uses an EventClientDelegateMBean.
-     **/
-    private static class EventSubscriptionManager
-            implements SubscriptionManager {
-        private final MBeanServer mbeanServer;
-        private final EventClientDelegateMBean delegate;
-        private final NotificationAccessController notifAC;
-        private final boolean checkNotificationEmission;
-        private final String clientId;
-        private final String connectionId;
-        private volatile String mbeanServerName;
-
-        EventSubscriptionManager(
-                MBeanServer mbeanServer,
-                EventClientDelegateMBean delegate,
-                Map<String, ?> env,
-                String clientId,
-                String connectionId) {
-            this.mbeanServer = mbeanServer;
-            this.delegate = delegate;
-            this.notifAC = EnvHelp.getNotificationAccessController(env);
-            this.checkNotificationEmission =
-                EnvHelp.computeBooleanFromString(
-                    env, "jmx.remote.x.check.notification.emission", false);
-            this.clientId = clientId;
-            this.connectionId = connectionId;
-        }
-
-        private String mbeanServerName() {
-            if (mbeanServerName != null) return mbeanServerName;
-            else return (mbeanServerName = getMBeanServerName(mbeanServer));
-        }
-
-        @SuppressWarnings("serial")  // no serialVersionUID
-        private class AccessControlFilter implements NotificationFilter {
-            private final NotificationFilter wrapped;
-            private final ObjectName name;
-
-            AccessControlFilter(ObjectName name, NotificationFilter wrapped) {
-                this.name = name;
-                this.wrapped = wrapped;
-            }
-
-            public boolean isNotificationEnabled(Notification notification) {
-                try {
-                    if (checkNotificationEmission) {
-                        ServerNotifForwarder.checkMBeanPermission(
-                                mbeanServerName(), mbeanServer, name,
-                                "addNotificationListener");
-                    }
-                    notifAC.fetchNotification(
-                            connectionId, name, notification, getSubject());
-                    return (wrapped == null) ? true :
-                        wrapped.isNotificationEnabled(notification);
-                } catch (InstanceNotFoundException e) {
-                    return false;
-                } catch (SecurityException e) {
-                    return false;
-                }
-            }
-
-        }
-
-        public Integer addNotificationListener(
-                ObjectName name, NotificationFilter filter)
-                throws InstanceNotFoundException, IOException {
-            if (notifAC != null) {
-                notifAC.addNotificationListener(connectionId, name, getSubject());
-                filter = new AccessControlFilter(name, filter);
-            }
-            try {
-                return delegate.addListener(clientId,name,filter);
-            } catch (EventClientNotFoundException x) {
-                throw new IOException("Unknown clientId: "+clientId,x);
-            }
-        }
-
-        public void removeNotificationListener(ObjectName name, Integer id)
-                throws InstanceNotFoundException, ListenerNotFoundException,
-                       IOException {
-            if (notifAC != null)
-                notifAC.removeNotificationListener(connectionId, name, getSubject());
-            try {
-                delegate.removeListenerOrSubscriber(clientId, id);
-            } catch (EventClientNotFoundException x) {
-                throw new IOException("Unknown clientId: "+clientId,x);
-            }
-        }
-
-        public void removeNotificationListener(ObjectName name, Integer[] ids)
-                throws InstanceNotFoundException, ListenerNotFoundException,
-                       IOException {
-            if (notifAC != null)
-                notifAC.removeNotificationListener(connectionId, name, getSubject());
-            try {
-                for (Integer id : ids)
-                    delegate.removeListenerOrSubscriber(clientId, id);
-            } catch (EventClientNotFoundException x) {
-                throw new IOException("Unknown clientId: "+clientId,x);
-            }
-        }
-
-        public NotificationResult fetchNotifications(long csn, long timeout,
-                int maxcount)
-            throws IOException {
-            try {
-                // For some reason the delegate doesn't accept a negative
-                // sequence number. However legacy clients will always call
-                // fetchNotifications with a negative sequence number, when
-                // they call it for the first time.
-                // In that case, we will use 0 instead.
-                //
-                return delegate.fetchNotifications(
-                        clientId, Math.max(csn, 0), maxcount, timeout);
-            } catch (EventClientNotFoundException x) {
-                throw new IOException("Unknown clientId: "+clientId,x);
-            }
-        }
-
-        public void terminate()
-            throws IOException {
-            try {
-                delegate.removeClient(clientId);
-            } catch (EventClientNotFoundException x) {
-                throw new IOException("Unknown clientId: "+clientId,x);
-            }
-        }
-
-        private static Subject getSubject() {
-            return Subject.getSubject(AccessController.getContext());
-        }
-    }
-
-    /**
-     * Creates a SubscriptionManager that uses either the legacy notifications
-     * mechanism (ServerNotifForwarder) or the new event service
-     * (EventClientDelegateMBean) depending on which option was passed in
-     * the connector's map.
-     **/
-    private SubscriptionManager createSubscriptionManager()
-        throws IOException {
-        if (EnvHelp.delegateToEventService(env) &&
-                mbeanServer.isRegistered(EventClientDelegate.OBJECT_NAME)) {
-            final EventClientDelegateMBean mbean =
-                    JMX.newMBeanProxy(mbeanServer,
-                        EventClientDelegate.OBJECT_NAME,
-                        EventClientDelegateMBean.class);
-            String clientId;
-            try {
-                 clientId =
-                    mbean.addClient(
-                FetchingEventForwarder.class.getName(),
-                new Object[] {EnvHelp.getNotifBufferSize(env)},
-                new String[] {int.class.getName()});
-            } catch (Exception e) {
-                if (e instanceof IOException)
-                    throw (IOException) e;
-                else
-                    throw new IOException(e);
-            }
-
-            // we're going to call remove client...
-            try {
-                mbean.lease(clientId, Long.MAX_VALUE);
-            } catch (EventClientNotFoundException x) {
-                throw new IOException("Unknown clientId: "+clientId,x);
-            }
-            return new EventSubscriptionManager(mbeanServer, mbean, env,
-                    clientId, connectionId);
-        } else {
-            final ServerNotifForwarder serverNotifForwarder =
-                new ServerNotifForwarder(mbeanServer,
-                                         env,
-                                         rmiServer.getNotifBuffer(),
-                                         connectionId);
-             return new LegacySubscriptionManager(serverNotifForwarder);
-        }
-    }
-
-    /**
-     * Lazy creation of a  SubscriptionManager.
-     **/
-    private synchronized SubscriptionManager getSubscriptionManager()
-        throws IOException {
-        // Lazily created when first use. Mainly when
-        // addNotificationListener is first called.
-
-        if (subscriptionManager == null) {
-             subscriptionManager = createSubscriptionManager();
-        }
-        return subscriptionManager;
-    }
-
-    // calls SubscriptionManager.
-    private void doRemoveListener(ObjectName name, Integer id)
-        throws InstanceNotFoundException, ListenerNotFoundException,
-            IOException {
-           getSubscriptionManager().removeNotificationListener(name,id);
-    }
-
-    // calls SubscriptionManager.
-    private void doRemoveListener(ObjectName name, Integer[] ids)
-        throws Exception {
-           getSubscriptionManager().removeNotificationListener(name,ids);
-    }
-
-    // calls SubscriptionManager.
-    private NotificationResult doFetchNotifs(long csn, long timeout, int maxcount)
-         throws IOException {
-         return getSubscriptionManager().fetchNotifications(csn, timeout, maxcount);
-    }
-
-    // calls SubscriptionManager.
-    private Integer doAddListener(ObjectName name, NotificationFilter filter)
-         throws InstanceNotFoundException, IOException {
-         return getSubscriptionManager().addNotificationListener(name,filter);
-    }
-
-
-    /**
      * <p>Returns a string representation of this object.  In general,
      * the <code>toString</code> method returns a string that
      * "textually represents" this object. The result should be a
@@ -1787,8 +1479,9 @@
             return null;
 
         case ADD_NOTIFICATION_LISTENERS:
-            return doAddListener((ObjectName)params[0],
-                                 (NotificationFilter)params[1]);
+            return getServerNotifFwd().addNotificationListener(
+                                                (ObjectName)params[0],
+                                                (NotificationFilter)params[1]);
 
         case ADD_NOTIFICATION_LISTENER_OBJECTNAME:
             mbeanServer.addNotificationListener((ObjectName)params[0],
@@ -1798,7 +1491,9 @@
             return null;
 
         case REMOVE_NOTIFICATION_LISTENER:
-            doRemoveListener((ObjectName)params[0],(Integer[])params[1]);
+            getServerNotifFwd().removeNotificationListener(
+                                                   (ObjectName)params[0],
+                                                   (Integer[])params[1]);
             return null;
 
         case REMOVE_NOTIFICATION_LISTENER_OBJECTNAME:
@@ -1909,15 +1604,6 @@
         return e;
     }
 
-    private static String getMBeanServerName(final MBeanServer server) {
-        final PrivilegedAction<String> action = new PrivilegedAction<String>() {
-            public String run() {
-                return Util.getMBeanServerSecurityName(server);
-            }
-        };
-        return AccessController.doPrivileged(action);
-    }
-
     private static final Object[] NO_OBJECTS = new Object[0];
     private static final String[] NO_STRINGS = new String[0];
 
@@ -2033,7 +1719,7 @@
     // SERVER NOTIFICATION
     //--------------------
 
-    private SubscriptionManager subscriptionManager;
+    private ServerNotifForwarder serverNotifForwarder;
     private Map<String, ?> env;
 
     // TRACES & DEBUG