FileDocCategorySizeDatePackage
ServerNotifForwarder.javaAPI DocJava SE 6 API15773Tue Jun 10 00:22:04 BST 2008com.sun.jmx.remote.internal

ServerNotifForwarder

public class ServerNotifForwarder extends Object

Fields Summary
private final NotificationBufferFilter
bufferFilter
private MBeanServer
mbeanServer
private final String
connectionId
private final long
connectionTimeout
private static int
listenerCounter
private static final int[]
listenerCounterLock
private NotificationBuffer
notifBuffer
private Map
listenerMap
private boolean
terminated
private final int[]
terminationLock
static final String
broadcasterClass
private final boolean
checkNotificationEmission
private final NotificationAccessController
notificationAccessController
private static final ClassLogger
logger
Constructors Summary
public ServerNotifForwarder(MBeanServer mbeanServer, Map env, NotificationBuffer notifBuffer, String connectionId)

        this.mbeanServer = mbeanServer;
        this.notifBuffer = notifBuffer;
        this.connectionId = connectionId;
        connectionTimeout = EnvHelp.getServerConnectionTimeout(env);
        checkNotificationEmission = EnvHelp.computeBooleanFromString(
            env,
            "jmx.remote.x.check.notification.emission");
        notificationAccessController = (NotificationAccessController)
            env.get("com.sun.jmx.remote.notification.access.controller");
    
Methods Summary
public java.lang.IntegeraddNotificationListener(javax.management.ObjectName name, javax.management.NotificationFilter filter)

        
        if (logger.traceOn()) {
            logger.trace("addNotificationListener",
                "Add a listener at " + name);
        }
        
        checkState();
        
        // Explicitly check MBeanPermission for addNotificationListener
        //
        checkMBeanPermission(name, "addNotificationListener");
        if (notificationAccessController != null) {
            notificationAccessController.addNotificationListener(
                connectionId,
                name,
                Subject.getSubject(AccessController.getContext()));
        }
        try {
            Boolean instanceOf = (Boolean)
            AccessController.doPrivileged(new PrivilegedExceptionAction() {
                public Object run() throws InstanceNotFoundException {
                    return new Boolean(
                        mbeanServer.isInstanceOf(name,
                        broadcasterClass));
                }
            });
            if (!instanceOf.booleanValue()) {
                throw new IllegalArgumentException("The specified MBean [" +
                    name + "] is not a " +
                    "NotificationBroadcaster " +
                    "object.");
            }
        } catch (PrivilegedActionException e) {
            throw (InstanceNotFoundException) extractException(e);
        }
        
        final Integer id = getListenerID();

	// 6238731: set the default domain if no domain is set.
	ObjectName nn = name;
	if (name.getDomain() == null || name.getDomain().equals("")) {
	    try {
		nn = ObjectName.getInstance(mbeanServer.getDefaultDomain(),
					    name.getKeyPropertyList());
	    } catch (MalformedObjectNameException mfoe) {
		// impossible, but...
		IOException ioe = new IOException(mfoe.getMessage());
		ioe.initCause(mfoe);
		throw ioe;
	    }
	}

        synchronized (listenerMap) {
            IdAndFilter idaf = new IdAndFilter(id, filter);
            Set<IdAndFilter> set = listenerMap.get(nn);
            // Tread carefully because if set.size() == 1 it may be the
            // Collections.singleton we make here, which is unmodifiable.
            if (set == null)
                set = Collections.singleton(idaf);
            else {
                if (set.size() == 1)
                    set = new HashSet<IdAndFilter>(set);
                set.add(idaf);
            }
            listenerMap.put(nn, set);
        }
        
        return id;
    
private booleanallowNotificationEmission(javax.management.ObjectName name, javax.management.remote.TargetedNotification tn)
Check if the caller has the right to get the following notifications.

        try {
            if (checkNotificationEmission) {
                checkMBeanPermission(name, "addNotificationListener");
            }
            if (notificationAccessController != null) {
                notificationAccessController.fetchNotification(
                        connectionId,
                        name,
                        tn.getNotification(),
                        Subject.getSubject(AccessController.getContext()));
            }
            return true;
        } catch (SecurityException e) {
            if (logger.debugOn()) {
                logger.debug("fetchNotifs", "Notification " +
                        tn.getNotification() + " not forwarded: the " +
                        "caller didn't have the required access rights");
            }
            return false;
        } catch (Exception e) {
            if (logger.debugOn()) {
                logger.debug("fetchNotifs", "Notification " +
                        tn.getNotification() + " not forwarded: " +
                        "got an unexpected exception: " + e);
            }
            return false;
        }
    
private voidcheckMBeanPermission(javax.management.ObjectName name, java.lang.String actions)
Explicitly check the MBeanPermission for the current access control context.

        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            AccessControlContext acc = AccessController.getContext();
            ObjectInstance oi = null;
            try {
                oi = (ObjectInstance) AccessController.doPrivileged(
                    new PrivilegedExceptionAction() {
                    public Object run()
                    throws InstanceNotFoundException {
                        return mbeanServer.getObjectInstance(name);
                    }
                });
            } catch (PrivilegedActionException e) {
                throw (InstanceNotFoundException) extractException(e);
            }
            String classname = oi.getClassName();
            MBeanPermission perm = new MBeanPermission(classname,
                null,
                name,
                actions);
            sm.checkPermission(perm, acc);
        }
    
private voidcheckState()

        synchronized(terminationLock) {
            if (terminated) {
                throw new IOException("The connection has been terminated.");
            }
        }
    
private static java.lang.ExceptionextractException(java.lang.Exception e)
Iterate until we extract the real exception from a stack of PrivilegedActionExceptions.

        while (e instanceof PrivilegedActionException) {
            e = ((PrivilegedActionException)e).getException();
        }
        return e;
    
public javax.management.remote.NotificationResultfetchNotifs(long startSequenceNumber, long timeout, int maxNotifications)

    
       
         
          
        if (logger.traceOn()) {
            logger.trace("fetchNotifs", "Fetching notifications, the " +
                "startSequenceNumber is " + startSequenceNumber +
                ", the timeout is " + timeout +
                ", the maxNotifications is " + maxNotifications);
        }
        
        NotificationResult nr = null;
        final long t = Math.min(connectionTimeout, timeout);
        try {
            nr = notifBuffer.fetchNotifications(bufferFilter,
                startSequenceNumber,
                t, maxNotifications);
        } catch (InterruptedException ire) {
            nr = new NotificationResult(0L, 0L, new TargetedNotification[0]);
        }

        if (logger.traceOn()) {
            logger.trace("fetchNotifs", "Forwarding the notifs: "+nr);
        }
        
        return nr;
    
private java.lang.IntegergetListenerID()

        synchronized(listenerCounterLock) {
            return new Integer(listenerCounter++);
        }
    
public voidremoveNotificationListener(javax.management.ObjectName name, java.lang.Integer[] listenerIDs)

        
        if (logger.traceOn()) {
            logger.trace("removeNotificationListener",
                "Remove some listeners from " + name);
        }
        
        checkState();
        
        // Explicitly check MBeanPermission for removeNotificationListener
        //
        checkMBeanPermission(name, "removeNotificationListener");
        if (notificationAccessController != null) {
            notificationAccessController.removeNotificationListener(
                connectionId,
                name,
                Subject.getSubject(AccessController.getContext()));
        }
        
        Exception re = null;
        for (int i = 0 ; i < listenerIDs.length ; i++) {
            try {
                removeNotificationListener(name, listenerIDs[i]);
            } catch (Exception e) {
                // Give back the first exception
                //
                if (re != null) {
                    re = e;
                }
            }
        }
        if (re != null) {
            throw re;
        }
    
public voidremoveNotificationListener(javax.management.ObjectName name, java.lang.Integer listenerID)

        
        if (logger.traceOn()) {
            logger.trace("removeNotificationListener",
                "Remove the listener " + listenerID + " from " + name);
        }
        
        checkState();
        
        if (name != null && !name.isPattern()) {
            if (!mbeanServer.isRegistered(name)) {
                throw new InstanceNotFoundException("The MBean " + name +
                    " is not registered.");
            }
        }
        
        synchronized (listenerMap) {
            // Tread carefully because if set.size() == 1 it may be a
            // Collections.singleton, which is unmodifiable.
            Set<IdAndFilter> set = listenerMap.get(name);
            IdAndFilter idaf = new IdAndFilter(listenerID, null);
            if (set == null || !set.contains(idaf))
                throw new ListenerNotFoundException("Listener not found");
            if (set.size() == 1)
                listenerMap.remove(name);
            else
                set.remove(idaf);
        }
    
public voidterminate()

        if (logger.traceOn()) {
            logger.trace("terminate", "Be called.");
        }
        
        synchronized(terminationLock) {
            if (terminated) {
                return;
            }
            
            terminated = true;
            
            synchronized(listenerMap) {
                listenerMap.clear();
            }
        }
        
        if (logger.traceOn()) {
            logger.trace("terminate", "Terminated.");
        }