jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java
author dfuchs
Thu, 04 Sep 2008 14:46:36 +0200
changeset 1156 bbc2d15aaf7a
child 1222 78e3d021d528
permissions -rw-r--r--
5072476: RFE: support cascaded (federated) MBean Servers 6299231: Add support for named MBean Servers Summary: New javax.management.namespace package. Reviewed-by: emcmanus

/*
 * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

package com.sun.jmx.interceptor;

import com.sun.jmx.defaults.JmxProperties;
import com.sun.jmx.mbeanserver.MBeanInstantiator;
import com.sun.jmx.mbeanserver.Repository;
import com.sun.jmx.mbeanserver.Util;
import com.sun.jmx.namespace.NamespaceInterceptor;

import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.management.MBeanServer;
import javax.management.MBeanServerDelegate;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.namespace.JMXDomain;
import javax.management.namespace.JMXNamespace;
import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;

/**
 * A dispatcher that dispatches to NamespaceInterceptors.
 * <p><b>
 * This API is a Sun internal API and is subject to changes without notice.
 * </b></p>
 * @since 1.7
 */
public class NamespaceDispatchInterceptor
        extends DispatchInterceptor<NamespaceInterceptor, JMXNamespace> {

    /**
     * A logger for this class.
     **/
    private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;

    private static final int NAMESPACE_SEPARATOR_LENGTH =
            NAMESPACE_SEPARATOR.length();

    private final DomainDispatchInterceptor localNamespace;
    private final String           serverName;

    /**
     * Creates a NamespaceDispatchInterceptor with the specified
     * repository instance.
     * <p>Do not forget to call <code>initialize(outer,delegate)</code>
     * before using this object.
     *
     * @param outer A pointer to the MBeanServer object that must be
     *        passed to the MBeans when invoking their
     *        {@link javax.management.MBeanRegistration} interface.
     * @param delegate A pointer to the MBeanServerDelegate associated
     *        with the new MBeanServer. The new MBeanServer must register
     *        this MBean in its MBean repository.
     * @param instantiator The MBeanInstantiator that will be used to
     *        instantiate MBeans and take care of class loading issues.
     * @param repository The repository to use for this MBeanServer
     */
    public NamespaceDispatchInterceptor(MBeanServer         outer,
                               MBeanServerDelegate delegate,
                               MBeanInstantiator   instantiator,
                               Repository          repository)  {
           localNamespace = new DomainDispatchInterceptor(outer,delegate,
                   instantiator,repository,this);
           serverName = Util.getMBeanServerSecurityName(delegate);
    }

    // TODO: Should move that to JMXNamespace? or to ObjectName?
    /**
     * Get first name space in ObjectName path. Ignore leading namespace
     * separators.
     **/
    public static String getFirstNamespace(ObjectName name) {
        if (name == null) return "";
        final String domain = name.getDomain();
        if (domain.equals("")) return "";

        int first = 0;
        int end = domain.indexOf(NAMESPACE_SEPARATOR,first);
        while (end == first) {
            first = end+NAMESPACE_SEPARATOR_LENGTH;
            end = domain.indexOf(NAMESPACE_SEPARATOR,first);
            if (end == -1) break;
        }

        if (end == -1) return "";

        final String namespace = domain.substring(first,end);

        return namespace;
    }

    /**
     * Called by the DefaultMBeanServerInterceptor, just before adding an
     * MBean to the repository.
     *
     * @param resource the MBean to be registered.
     * @param logicalName the name of the MBean to be registered.
     */
    final void checkLocallyRegistrable(Object resource,
            ObjectName logicalName) {
        if (!(resource instanceof JMXNamespace) &&
                logicalName.getDomain().contains(NAMESPACE_SEPARATOR))
            throw new IllegalArgumentException(String.valueOf(logicalName)+
                    ": Invalid ObjectName for an instance of " +
                    resource.getClass().getName());
    }

    final boolean isLocalHandlerNameFor(String namespace,
            ObjectName handlerName) {
        return handlerName.getDomain().equals(namespace+NAMESPACE_SEPARATOR) &&
               JMXNamespace.TYPE_ASSIGNMENT.equals(
               handlerName.getKeyPropertyListString());
    }

    @Override
    final MBeanServer getInterceptorOrNullFor(ObjectName name) {
        final String namespace = getFirstNamespace(name);
        if (namespace.equals("") || isLocalHandlerNameFor(namespace,name) ||
            name.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) {
            LOG.finer("dispatching to local name space");
            return localNamespace;
        }
        final NamespaceInterceptor ns = getInterceptor(namespace);
        if (LOG.isLoggable(Level.FINER)) {
            if (ns != null) {
                LOG.finer("dispatching to name space: " + namespace);
            } else {
                LOG.finer("no handler for: " + namespace);
            }
        }
        return ns;
    }

    @Override
    final QueryInterceptor getInterceptorForQuery(ObjectName pattern) {
        final String namespace = getFirstNamespace(pattern);
        if (namespace.equals("") || isLocalHandlerNameFor(namespace,pattern) ||
            pattern.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) {
            LOG.finer("dispatching to local name space");
            return new QueryInterceptor(localNamespace);
        }
        final NamespaceInterceptor ns = getInterceptor(namespace);
        if (LOG.isLoggable(Level.FINER)) {
            if (ns != null) {
                LOG.finer("dispatching to name space: " + namespace);
            } else {
                LOG.finer("no handler for: " + namespace);
            }
        }
        if (ns == null) return null;
        return new QueryInterceptor(ns);
    }

    @Override
    final ObjectName getHandlerNameFor(String key)
        throws MalformedObjectNameException {
        return ObjectName.getInstance(key+NAMESPACE_SEPARATOR,
                    "type", JMXNamespace.TYPE);
    }

    @Override
    final public String getHandlerKey(ObjectName name) {
        return getFirstNamespace(name);
    }

    @Override
    final NamespaceInterceptor createInterceptorFor(String key,
            ObjectName name, JMXNamespace handler,
            Queue<Runnable> postRegisterQueue) {
        final NamespaceInterceptor ns =
                new NamespaceInterceptor(serverName,handler,key);
        if (LOG.isLoggable(Level.FINER)) {
            LOG.finer("NamespaceInterceptor created: "+ns);
        }
        return ns;
    }

    @Override
    final DomainDispatchInterceptor getNextInterceptor() {
        return localNamespace;
    }

    /**
     * Returns the list of domains in which any MBean is currently
     * registered.
     */
    @Override
    public String[] getDomains() {
        return localNamespace.getDomains();
    }

    @Override
    public void addNamespace(ObjectName name, JMXNamespace handler,
            Queue<Runnable> postRegisterQueue) {
        if (handler instanceof JMXDomain)
            localNamespace.addNamespace(name,
                    (JMXDomain)handler,postRegisterQueue);
        else super.addNamespace(name,handler,postRegisterQueue);
    }

    @Override
    public void removeNamespace(ObjectName name, JMXNamespace handler,
            Queue<Runnable> postDeregisterQueue) {
        if (handler instanceof JMXDomain)
            localNamespace.removeNamespace(name,(JMXDomain)handler,
                    postDeregisterQueue);
        else super.removeNamespace(name,handler,postDeregisterQueue);
    }


}