jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java
author xdono
Wed, 02 Jul 2008 12:55:45 -0700
changeset 715 f16baef3a20e
parent 526 61ba2d5ea9da
child 1004 5ba8217eb504
permissions -rw-r--r--
6719955: Update copyright year Summary: Update copyright year for files that have been modified in 2008 Reviewed-by: ohair, tbell
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
715
f16baef3a20e 6719955: Update copyright year
xdono
parents: 526
diff changeset
     2
 * Copyright 2002-2008 Sun Microsystems, Inc.  All Rights Reserved.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
90ce3da70b43 Initial load
duke
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Sun designates this
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
90ce3da70b43 Initial load
duke
parents:
diff changeset
     9
 * by Sun in the LICENSE file that accompanied this code.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    21
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    22
 * CA 95054 USA or visit www.sun.com if you need additional information or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    23
 * have any questions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
package com.sun.jmx.remote.internal;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
import com.sun.jmx.remote.security.NotificationAccessController;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
import com.sun.jmx.remote.util.ClassLogger;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
import com.sun.jmx.remote.util.EnvHelp;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
import java.io.IOException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
import java.security.AccessControlContext;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
import java.security.AccessController;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
import java.security.PrivilegedActionException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
import java.security.PrivilegedExceptionAction;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
import java.util.ArrayList;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
import java.util.Arrays;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
import java.util.Collections;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
import java.util.HashMap;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
import java.util.HashSet;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
import java.util.List;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
import java.util.Map;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
import java.util.Set;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
import javax.management.InstanceNotFoundException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
import javax.management.ListenerNotFoundException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
import javax.management.MBeanPermission;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
import javax.management.MBeanServer;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
import javax.management.Notification;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
import javax.management.NotificationBroadcaster;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
import javax.management.NotificationFilter;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
import javax.management.ObjectInstance;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
import javax.management.ObjectName;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
import javax.management.remote.NotificationResult;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
import javax.management.remote.TargetedNotification;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
import javax.management.MalformedObjectNameException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
import javax.security.auth.Subject;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
public class ServerNotifForwarder {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
    public ServerNotifForwarder(MBeanServer mbeanServer,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
                                Map env,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
                                NotificationBuffer notifBuffer,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
                                String connectionId) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
        this.mbeanServer = mbeanServer;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
        this.notifBuffer = notifBuffer;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
        this.connectionId = connectionId;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
        connectionTimeout = EnvHelp.getServerConnectionTimeout(env);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
        checkNotificationEmission = EnvHelp.computeBooleanFromString(
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
            env,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
            "jmx.remote.x.check.notification.emission");
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
        notificationAccessController = (NotificationAccessController)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
            env.get("com.sun.jmx.remote.notification.access.controller");
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
    public Integer addNotificationListener(final ObjectName name,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
        final NotificationFilter filter)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
        throws InstanceNotFoundException, IOException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
        if (logger.traceOn()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
            logger.trace("addNotificationListener",
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
                "Add a listener at " + name);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
        checkState();
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
        // Explicitly check MBeanPermission for addNotificationListener
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
        //
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
        checkMBeanPermission(name, "addNotificationListener");
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
        if (notificationAccessController != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
            notificationAccessController.addNotificationListener(
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
                connectionId,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
                name,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
                Subject.getSubject(AccessController.getContext()));
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
        try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
            boolean instanceOf =
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
            AccessController.doPrivileged(
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
                    new PrivilegedExceptionAction<Boolean>() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
                        public Boolean run() throws InstanceNotFoundException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
                            return mbeanServer.isInstanceOf(name, broadcasterClass);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
            });
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
            if (!instanceOf) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
                throw new IllegalArgumentException("The specified MBean [" +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
                    name + "] is not a " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
                    "NotificationBroadcaster " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
                    "object.");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
        } catch (PrivilegedActionException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
            throw (InstanceNotFoundException) extractException(e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
        final Integer id = getListenerID();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
        // 6238731: set the default domain if no domain is set.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
        ObjectName nn = name;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
        if (name.getDomain() == null || name.getDomain().equals("")) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
                nn = ObjectName.getInstance(mbeanServer.getDefaultDomain(),
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
                                            name.getKeyPropertyList());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
            } catch (MalformedObjectNameException mfoe) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
                // impossible, but...
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
                IOException ioe = new IOException(mfoe.getMessage());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
                ioe.initCause(mfoe);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
                throw ioe;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
        synchronized (listenerMap) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
            IdAndFilter idaf = new IdAndFilter(id, filter);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
            Set<IdAndFilter> set = listenerMap.get(nn);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
            // Tread carefully because if set.size() == 1 it may be the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
            // Collections.singleton we make here, which is unmodifiable.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
            if (set == null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
                set = Collections.singleton(idaf);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
            else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
                if (set.size() == 1)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
                    set = new HashSet<IdAndFilter>(set);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
                set.add(idaf);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
            listenerMap.put(nn, set);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
        return id;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
    public void removeNotificationListener(ObjectName name,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
        Integer[] listenerIDs)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
        throws Exception {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
        if (logger.traceOn()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
            logger.trace("removeNotificationListener",
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
                "Remove some listeners from " + name);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
        checkState();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
        // Explicitly check MBeanPermission for removeNotificationListener
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
        //
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
        checkMBeanPermission(name, "removeNotificationListener");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   161
        if (notificationAccessController != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
            notificationAccessController.removeNotificationListener(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
                connectionId,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
                name,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
                Subject.getSubject(AccessController.getContext()));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
        Exception re = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   169
        for (int i = 0 ; i < listenerIDs.length ; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   170
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
                removeNotificationListener(name, listenerIDs[i]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   172
            } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   173
                // Give back the first exception
90ce3da70b43 Initial load
duke
parents:
diff changeset
   174
                //
90ce3da70b43 Initial load
duke
parents:
diff changeset
   175
                if (re != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   176
                    re = e;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   177
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   178
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   179
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   180
        if (re != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   181
            throw re;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   183
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   184
90ce3da70b43 Initial load
duke
parents:
diff changeset
   185
    public void removeNotificationListener(ObjectName name, Integer listenerID)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   186
    throws
90ce3da70b43 Initial load
duke
parents:
diff changeset
   187
        InstanceNotFoundException,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   188
        ListenerNotFoundException,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   189
        IOException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   190
90ce3da70b43 Initial load
duke
parents:
diff changeset
   191
        if (logger.traceOn()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   192
            logger.trace("removeNotificationListener",
90ce3da70b43 Initial load
duke
parents:
diff changeset
   193
                "Remove the listener " + listenerID + " from " + name);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   194
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   195
90ce3da70b43 Initial load
duke
parents:
diff changeset
   196
        checkState();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   197
90ce3da70b43 Initial load
duke
parents:
diff changeset
   198
        if (name != null && !name.isPattern()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   199
            if (!mbeanServer.isRegistered(name)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   200
                throw new InstanceNotFoundException("The MBean " + name +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   201
                    " is not registered.");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   202
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   203
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   204
90ce3da70b43 Initial load
duke
parents:
diff changeset
   205
        synchronized (listenerMap) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   206
            // Tread carefully because if set.size() == 1 it may be a
90ce3da70b43 Initial load
duke
parents:
diff changeset
   207
            // Collections.singleton, which is unmodifiable.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   208
            Set<IdAndFilter> set = listenerMap.get(name);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   209
            IdAndFilter idaf = new IdAndFilter(listenerID, null);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   210
            if (set == null || !set.contains(idaf))
90ce3da70b43 Initial load
duke
parents:
diff changeset
   211
                throw new ListenerNotFoundException("Listener not found");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   212
            if (set.size() == 1)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   213
                listenerMap.remove(name);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   214
            else
90ce3da70b43 Initial load
duke
parents:
diff changeset
   215
                set.remove(idaf);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   216
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   217
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   218
90ce3da70b43 Initial load
duke
parents:
diff changeset
   219
    /* This is the object that will apply our filtering to candidate
90ce3da70b43 Initial load
duke
parents:
diff changeset
   220
     * notifications.  First of all, if there are no listeners for the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   221
     * ObjectName that the notification is coming from, we go no further.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   222
     * Then, for each listener, we must apply the corresponding filter (if any)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   223
     * and ignore the listener if the filter rejects.  Finally, we apply
90ce3da70b43 Initial load
duke
parents:
diff changeset
   224
     * some access checks which may also reject the listener.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   225
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   226
     * A given notification may trigger several listeners on the same MBean,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   227
     * which is why listenerMap is a Map<ObjectName, Set<IdAndFilter>> and
90ce3da70b43 Initial load
duke
parents:
diff changeset
   228
     * why we add the found notifications to a supplied List rather than
90ce3da70b43 Initial load
duke
parents:
diff changeset
   229
     * just returning a boolean.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   230
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   231
    private final NotificationBufferFilter bufferFilter =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   232
            new NotificationBufferFilter() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   233
        public void apply(List<TargetedNotification> targetedNotifs,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   234
                          ObjectName source, Notification notif) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   235
            // We proceed in two stages here, to avoid holding the listenerMap
90ce3da70b43 Initial load
duke
parents:
diff changeset
   236
            // lock while invoking the filters (which are user code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
   237
            final IdAndFilter[] candidates;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   238
            synchronized (listenerMap) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   239
                final Set<IdAndFilter> set = listenerMap.get(source);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   240
                if (set == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   241
                    logger.debug("bufferFilter", "no listeners for this name");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   242
                    return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   243
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   244
                candidates = new IdAndFilter[set.size()];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   245
                set.toArray(candidates);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   246
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   247
            // We don't synchronize on targetedNotifs, because it is a local
90ce3da70b43 Initial load
duke
parents:
diff changeset
   248
            // variable of our caller and no other thread can see it.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   249
            for (IdAndFilter idaf : candidates) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   250
                final NotificationFilter nf = idaf.getFilter();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   251
                if (nf == null || nf.isNotificationEnabled(notif)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   252
                    logger.debug("bufferFilter", "filter matches");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   253
                    final TargetedNotification tn =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   254
                            new TargetedNotification(notif, idaf.getId());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   255
                    if (allowNotificationEmission(source, tn))
90ce3da70b43 Initial load
duke
parents:
diff changeset
   256
                        targetedNotifs.add(tn);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   257
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   258
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   259
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   260
    };
90ce3da70b43 Initial load
duke
parents:
diff changeset
   261
90ce3da70b43 Initial load
duke
parents:
diff changeset
   262
    public NotificationResult fetchNotifs(long startSequenceNumber,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   263
        long timeout,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   264
        int maxNotifications) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   265
        if (logger.traceOn()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   266
            logger.trace("fetchNotifs", "Fetching notifications, the " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   267
                "startSequenceNumber is " + startSequenceNumber +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   268
                ", the timeout is " + timeout +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   269
                ", the maxNotifications is " + maxNotifications);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   270
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   271
526
61ba2d5ea9da 6701459: Synchronization bug pattern found in javax.management.relation.RelationService
emcmanus
parents: 2
diff changeset
   272
        NotificationResult nr;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   273
        final long t = Math.min(connectionTimeout, timeout);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   274
        try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   275
            nr = notifBuffer.fetchNotifications(bufferFilter,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   276
                startSequenceNumber,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   277
                t, maxNotifications);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   278
        } catch (InterruptedException ire) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   279
            nr = new NotificationResult(0L, 0L, new TargetedNotification[0]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   280
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   281
90ce3da70b43 Initial load
duke
parents:
diff changeset
   282
        if (logger.traceOn()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   283
            logger.trace("fetchNotifs", "Forwarding the notifs: "+nr);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   284
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   285
90ce3da70b43 Initial load
duke
parents:
diff changeset
   286
        return nr;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   287
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   288
90ce3da70b43 Initial load
duke
parents:
diff changeset
   289
    public void terminate() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   290
        if (logger.traceOn()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   291
            logger.trace("terminate", "Be called.");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   292
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   293
90ce3da70b43 Initial load
duke
parents:
diff changeset
   294
        synchronized(terminationLock) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   295
            if (terminated) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   296
                return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   297
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   298
90ce3da70b43 Initial load
duke
parents:
diff changeset
   299
            terminated = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   300
90ce3da70b43 Initial load
duke
parents:
diff changeset
   301
            synchronized(listenerMap) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   302
                listenerMap.clear();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   303
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   304
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   305
90ce3da70b43 Initial load
duke
parents:
diff changeset
   306
        if (logger.traceOn()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   307
            logger.trace("terminate", "Terminated.");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   308
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   309
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   310
90ce3da70b43 Initial load
duke
parents:
diff changeset
   311
    //----------------
90ce3da70b43 Initial load
duke
parents:
diff changeset
   312
    // PRIVATE METHODS
90ce3da70b43 Initial load
duke
parents:
diff changeset
   313
    //----------------
90ce3da70b43 Initial load
duke
parents:
diff changeset
   314
90ce3da70b43 Initial load
duke
parents:
diff changeset
   315
    private void checkState() throws IOException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   316
        synchronized(terminationLock) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   317
            if (terminated) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   318
                throw new IOException("The connection has been terminated.");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   319
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   320
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   321
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   322
90ce3da70b43 Initial load
duke
parents:
diff changeset
   323
    private Integer getListenerID() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   324
        synchronized(listenerCounterLock) {
526
61ba2d5ea9da 6701459: Synchronization bug pattern found in javax.management.relation.RelationService
emcmanus
parents: 2
diff changeset
   325
            return listenerCounter++;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   326
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   327
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   328
90ce3da70b43 Initial load
duke
parents:
diff changeset
   329
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   330
     * Explicitly check the MBeanPermission for
90ce3da70b43 Initial load
duke
parents:
diff changeset
   331
     * the current access control context.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   332
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   333
    private void checkMBeanPermission(final ObjectName name,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   334
        final String actions)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   335
        throws InstanceNotFoundException, SecurityException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   336
        SecurityManager sm = System.getSecurityManager();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   337
        if (sm != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   338
            AccessControlContext acc = AccessController.getContext();
526
61ba2d5ea9da 6701459: Synchronization bug pattern found in javax.management.relation.RelationService
emcmanus
parents: 2
diff changeset
   339
            ObjectInstance oi;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   340
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   341
                oi = AccessController.doPrivileged(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   342
                    new PrivilegedExceptionAction<ObjectInstance>() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   343
                        public ObjectInstance run()
90ce3da70b43 Initial load
duke
parents:
diff changeset
   344
                        throws InstanceNotFoundException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   345
                            return mbeanServer.getObjectInstance(name);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   346
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   347
                });
90ce3da70b43 Initial load
duke
parents:
diff changeset
   348
            } catch (PrivilegedActionException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   349
                throw (InstanceNotFoundException) extractException(e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   350
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   351
            String classname = oi.getClassName();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   352
            MBeanPermission perm = new MBeanPermission(classname,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   353
                null,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   354
                name,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   355
                actions);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   356
            sm.checkPermission(perm, acc);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   357
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   358
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   359
90ce3da70b43 Initial load
duke
parents:
diff changeset
   360
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   361
     * Check if the caller has the right to get the following notifications.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   362
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   363
    private boolean allowNotificationEmission(ObjectName name,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   364
                                              TargetedNotification tn) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   365
        try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   366
            if (checkNotificationEmission) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   367
                checkMBeanPermission(name, "addNotificationListener");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   368
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   369
            if (notificationAccessController != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   370
                notificationAccessController.fetchNotification(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   371
                        connectionId,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   372
                        name,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   373
                        tn.getNotification(),
90ce3da70b43 Initial load
duke
parents:
diff changeset
   374
                        Subject.getSubject(AccessController.getContext()));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   375
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   376
            return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   377
        } catch (SecurityException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   378
            if (logger.debugOn()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   379
                logger.debug("fetchNotifs", "Notification " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   380
                        tn.getNotification() + " not forwarded: the " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   381
                        "caller didn't have the required access rights");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   382
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   383
            return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   384
        } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   385
            if (logger.debugOn()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   386
                logger.debug("fetchNotifs", "Notification " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   387
                        tn.getNotification() + " not forwarded: " +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   388
                        "got an unexpected exception: " + e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   389
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   390
            return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   391
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   392
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   393
90ce3da70b43 Initial load
duke
parents:
diff changeset
   394
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   395
     * Iterate until we extract the real exception
90ce3da70b43 Initial load
duke
parents:
diff changeset
   396
     * from a stack of PrivilegedActionExceptions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   397
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   398
    private static Exception extractException(Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   399
        while (e instanceof PrivilegedActionException) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   400
            e = ((PrivilegedActionException)e).getException();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   401
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   402
        return e;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   403
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   404
90ce3da70b43 Initial load
duke
parents:
diff changeset
   405
    private static class IdAndFilter {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   406
        private Integer id;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   407
        private NotificationFilter filter;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   408
90ce3da70b43 Initial load
duke
parents:
diff changeset
   409
        IdAndFilter(Integer id, NotificationFilter filter) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   410
            this.id = id;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   411
            this.filter = filter;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   412
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   413
90ce3da70b43 Initial load
duke
parents:
diff changeset
   414
        Integer getId() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   415
            return this.id;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   416
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   417
90ce3da70b43 Initial load
duke
parents:
diff changeset
   418
        NotificationFilter getFilter() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   419
            return this.filter;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   420
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   421
90ce3da70b43 Initial load
duke
parents:
diff changeset
   422
        public int hashCode() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   423
            return id.hashCode();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   424
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   425
90ce3da70b43 Initial load
duke
parents:
diff changeset
   426
        public boolean equals(Object o) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   427
            return ((o instanceof IdAndFilter) &&
90ce3da70b43 Initial load
duke
parents:
diff changeset
   428
                    ((IdAndFilter) o).getId().equals(getId()));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   429
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   430
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   431
90ce3da70b43 Initial load
duke
parents:
diff changeset
   432
    //------------------
90ce3da70b43 Initial load
duke
parents:
diff changeset
   433
    // PRIVATE VARIABLES
90ce3da70b43 Initial load
duke
parents:
diff changeset
   434
    //------------------
90ce3da70b43 Initial load
duke
parents:
diff changeset
   435
90ce3da70b43 Initial load
duke
parents:
diff changeset
   436
    private MBeanServer mbeanServer;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   437
90ce3da70b43 Initial load
duke
parents:
diff changeset
   438
    private final String connectionId;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   439
90ce3da70b43 Initial load
duke
parents:
diff changeset
   440
    private final long connectionTimeout;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   441
90ce3da70b43 Initial load
duke
parents:
diff changeset
   442
    private static int listenerCounter = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   443
    private final static int[] listenerCounterLock = new int[0];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   444
90ce3da70b43 Initial load
duke
parents:
diff changeset
   445
    private NotificationBuffer notifBuffer;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   446
    private Map<ObjectName, Set<IdAndFilter>> listenerMap =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   447
            new HashMap<ObjectName, Set<IdAndFilter>>();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   448
90ce3da70b43 Initial load
duke
parents:
diff changeset
   449
    private boolean terminated = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   450
    private final int[] terminationLock = new int[0];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   451
90ce3da70b43 Initial load
duke
parents:
diff changeset
   452
    static final String broadcasterClass =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   453
        NotificationBroadcaster.class.getName();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   454
90ce3da70b43 Initial load
duke
parents:
diff changeset
   455
    private final boolean checkNotificationEmission;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   456
90ce3da70b43 Initial load
duke
parents:
diff changeset
   457
    private final NotificationAccessController notificationAccessController;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   458
90ce3da70b43 Initial load
duke
parents:
diff changeset
   459
    private static final ClassLogger logger =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   460
        new ClassLogger("javax.management.remote.misc", "ServerNotifForwarder");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   461
}