# HG changeset patch
# User tbell
# Date 1220565312 25200
# Node ID cbfe7dbaf365a265fea531d1babcc44150e04867
# Parent 972c77670265d856704bd40b206283f719a763a0# Parent bbc2d15aaf7a52ca177bf9b4ad22aabdb273e5e0
Merge
diff -r 972c77670265 -r cbfe7dbaf365 jdk/make/docs/CORE_PKGS.gmk
--- a/jdk/make/docs/CORE_PKGS.gmk Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/make/docs/CORE_PKGS.gmk Thu Sep 04 14:55:12 2008 -0700
@@ -158,6 +158,7 @@
javax.management.event \
javax.management.loading \
javax.management.monitor \
+ javax.management.namespace \
javax.management.relation \
javax.management.openmbean \
javax.management.timer \
diff -r 972c77670265 -r cbfe7dbaf365 jdk/make/java/java/mapfile-vers
--- a/jdk/make/java/java/mapfile-vers Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/make/java/java/mapfile-vers Thu Sep 04 14:55:12 2008 -0700
@@ -222,8 +222,6 @@
Java_java_lang_UNIXProcess_waitForProcessExit;
Java_java_lang_UNIXProcess_forkAndExec;
Java_java_lang_UNIXProcess_destroyProcess;
- Java_java_nio_Bits_copyFromByteArray;
- Java_java_nio_Bits_copyToByteArray;
Java_java_nio_Bits_copyFromShortArray;
Java_java_nio_Bits_copyToShortArray;
Java_java_nio_Bits_copyFromIntArray;
diff -r 972c77670265 -r cbfe7dbaf365 jdk/make/java/nio/FILES_java.gmk
--- a/jdk/make/java/nio/FILES_java.gmk Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/make/java/nio/FILES_java.gmk Thu Sep 04 14:55:12 2008 -0700
@@ -39,6 +39,9 @@
java/nio/channels/FileLock.java \
java/nio/channels/GatheringByteChannel.java \
java/nio/channels/InterruptibleChannel.java \
+ java/nio/channels/MembershipKey.java \
+ java/nio/channels/MulticastChannel.java \
+ java/nio/channels/NetworkChannel.java \
java/nio/channels/ReadableByteChannel.java \
java/nio/channels/ScatteringByteChannel.java \
java/nio/channels/SelectableChannel.java \
@@ -73,6 +76,7 @@
sun/nio/ch/DatagramSocketAdaptor.java \
sun/nio/ch/DefaultSelectorProvider.java \
sun/nio/ch/DirectBuffer.java \
+ sun/nio/ch/ExtendedSocketOption.java \
sun/nio/ch/FileChannelImpl.java \
sun/nio/ch/FileDispatcher.java \
sun/nio/ch/FileKey.java \
@@ -80,12 +84,14 @@
sun/nio/ch/IOUtil.java \
sun/nio/ch/IOStatus.java \
sun/nio/ch/IOVecWrapper.java \
+ sun/nio/ch/MembershipKeyImpl.java \
+ sun/nio/ch/MembershipRegistry.java \
sun/nio/ch/NativeDispatcher.java \
sun/nio/ch/NativeObject.java \
sun/nio/ch/NativeThread.java \
sun/nio/ch/NativeThreadSet.java \
sun/nio/ch/Net.java \
- sun/nio/ch/OptionAdaptor.java \
+ sun/nio/ch/OptionKey.java \
sun/nio/ch/PipeImpl.java \
sun/nio/ch/PollArrayWrapper.java \
sun/nio/ch/Reflect.java \
@@ -99,8 +105,7 @@
sun/nio/ch/SocketAdaptor.java \
sun/nio/ch/SocketChannelImpl.java \
sun/nio/ch/SocketDispatcher.java \
- sun/nio/ch/SocketOpts.java \
- sun/nio/ch/SocketOptsImpl.java \
+ sun/nio/ch/SocketOptionRegistry.java \
sun/nio/ch/SourceChannelImpl.java \
sun/nio/ch/Util.java \
\
@@ -240,6 +245,7 @@
java/nio/InvalidMarkException.java \
java/nio/ReadOnlyBufferException.java \
\
+ java/nio/channels/AlreadyBoundException.java \
java/nio/channels/AlreadyConnectedException.java \
java/nio/channels/AsynchronousCloseException.java \
java/nio/channels/ClosedByInterruptException.java \
@@ -258,14 +264,15 @@
java/nio/channels/UnresolvedAddressException.java \
java/nio/channels/UnsupportedAddressTypeException.java \
\
- sun/nio/ch/AlreadyBoundException.java \
- \
java/nio/charset/CharacterCodingException.java \
java/nio/charset/IllegalCharsetNameException.java \
java/nio/charset/UnsupportedCharsetException.java
FILES_gen_csp = sun/nio/cs/StandardCharsets.java
-FILES_gen = $(FILES_gen_coder) $(FILES_gen_buffer) $(FILES_gen_ex) $(FILES_gen_csp)
+FILES_gen_sor = sun/nio/ch/SocketOptionRegistry.java
+
+FILES_gen = $(FILES_gen_coder) $(FILES_gen_buffer) $(FILES_gen_ex) \
+ $(FILES_gen_csp) $(FILES_gen_sor)
FILES_java = $(FILES_src) $(FILES_gen)
diff -r 972c77670265 -r cbfe7dbaf365 jdk/make/java/nio/Makefile
--- a/jdk/make/java/nio/Makefile Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/make/java/nio/Makefile Thu Sep 04 14:55:12 2008 -0700
@@ -56,18 +56,18 @@
sun/nio/ch/DevPollSelectorProvider.java \
sun/nio/ch/InheritedChannel.java \
sun/nio/ch/PollSelectorProvider.java \
- sun/nio/ch/PollSelectorImpl.java
+ sun/nio/ch/PollSelectorImpl.java
FILES_c += \
DevPollArrayWrapper.c \
InheritedChannel.c \
- PollArrayWrapper.c \
- NativeThread.c
+ NativeThread.c \
+ PollArrayWrapper.c
FILES_export += \
sun/nio/ch/DevPollArrayWrapper.java \
sun/nio/ch/InheritedChannel.java \
- sun/nio/ch/NativeThread.java
+ sun/nio/ch/NativeThread.java
endif # PLATFORM = solaris
ifeq ($(PLATFORM), windows)
@@ -94,14 +94,14 @@
FILES_c += \
EPollArrayWrapper.c \
- PollArrayWrapper.c \
InheritedChannel.c \
- NativeThread.c
+ NativeThread.c \
+ PollArrayWrapper.c
FILES_export += \
sun/nio/ch/EPollArrayWrapper.java \
sun/nio/ch/InheritedChannel.java \
- sun/nio/ch/NativeThread.java
+ sun/nio/ch/NativeThread.java
endif # PLATFORM = linux
# Find platform-specific C source files
@@ -618,12 +618,6 @@
@$(RM) $@.temp
$(GEN_EX_CMD) $(BUF_SRC)/exceptions $(BUF_GEN)
-$(SCH_GEN)/%Exception.java: genExceptions.sh $(SCH_SRC)/exceptions
- $(prep-target)
- @$(RM) $@.temp
- $(GEN_EX_CMD) $(SCH_SRC)/exceptions $(SCH_GEN)
-
-
#
# Generated charset-provider classes
#
@@ -638,4 +632,29 @@
HASHER="$(BOOT_JAVA_CMD) -jar $(HASHER_JARFILE)" \
$(SH) -e genCharsetProvider.sh $(SCS_SRC)/standard-charsets $(SCS_GEN)
+#
+# Generated channel implementation classes.
+# C source is compiled in TEMPDIR to avoid turds left by Windows compilers.
+#
+
+GENSOR_SRC = $(SHARE_SRC)/native/sun/nio/ch/genSocketOptionRegistry.c
+
+GENSOR_EXE = $(TEMPDIR)/genSocketOptionRegistry$(EXE_SUFFIX)
+
+SOR_COPYRIGHT_YEARS = $(shell $(CAT) $(GENSOR_SRC) | \
+ $(NAWK) '/^.*Copyright.*Sun/ { print $$3 }')
+
+$(TEMPDIR)/$(GENSOR_SRC) : $(GENSOR_SRC)
+ $(install-file)
+
+$(GENSOR_EXE) : $(TEMPDIR)/$(GENSOR_SRC)
+ $(prep-target)
+ ($(CD) $(TEMPDIR); $(CC) $(CPPFLAGS) $(LDDFLAGS) \
+ -o genSocketOptionRegistry$(EXE_SUFFIX) $(GENSOR_SRC))
+
+$(SCH_GEN)/SocketOptionRegistry.java: $(GENSOR_EXE)
+ $(prep-target)
+ NAWK="$(NAWK)" SH="$(SH)" $(SH) -e addNotices.sh $(SOR_COPYRIGHT_YEARS) > $@
+ $(GENSOR_EXE) >> $@
+
.PHONY: sources
diff -r 972c77670265 -r cbfe7dbaf365 jdk/make/java/nio/mapfile-linux
--- a/jdk/make/java/nio/mapfile-linux Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/make/java/nio/mapfile-linux Thu Sep 04 14:55:12 2008 -0700
@@ -1,3 +1,27 @@
+#
+# Copyright 2001-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.
+#
SUNWprivate_1.1 {
global:
@@ -61,20 +85,29 @@
Java_sun_nio_ch_NativeThread_init;
Java_sun_nio_ch_NativeThread_signal;
Java_sun_nio_ch_Net_socket0;
- Java_sun_nio_ch_Net_bind;
- Java_sun_nio_ch_Net_connect;
+ Java_sun_nio_ch_Net_bind0;
+ Java_sun_nio_ch_Net_connect0;
+ Java_sun_nio_ch_Net_listen;
Java_sun_nio_ch_Net_localPort;
Java_sun_nio_ch_Net_localInetAddress;
Java_sun_nio_ch_Net_getIntOption0;
Java_sun_nio_ch_Net_setIntOption0;
Java_sun_nio_ch_Net_initIDs;
+ Java_sun_nio_ch_Net_isIPv6Available0;
+ Java_sun_nio_ch_Net_joinOrDrop4;
+ Java_sun_nio_ch_Net_blockOrUnblock4;
+ Java_sun_nio_ch_Net_joinOrDrop6;
+ Java_sun_nio_ch_Net_blockOrUnblock6;
+ Java_sun_nio_ch_Net_setInterface4;
+ Java_sun_nio_ch_Net_getInterface4;
+ Java_sun_nio_ch_Net_setInterface6;
+ Java_sun_nio_ch_Net_getInterface6;
+ Java_sun_nio_ch_Net_shutdown;
Java_sun_nio_ch_PollArrayWrapper_interrupt;
Java_sun_nio_ch_PollArrayWrapper_poll0;
Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
Java_sun_nio_ch_ServerSocketChannelImpl_initIDs;
- Java_sun_nio_ch_ServerSocketChannelImpl_listen;
Java_sun_nio_ch_SocketChannelImpl_checkConnect;
- Java_sun_nio_ch_SocketChannelImpl_shutdown;
local:
*;
diff -r 972c77670265 -r cbfe7dbaf365 jdk/make/java/nio/mapfile-solaris
--- a/jdk/make/java/nio/mapfile-solaris Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/make/java/nio/mapfile-solaris Thu Sep 04 14:55:12 2008 -0700
@@ -1,3 +1,27 @@
+#
+# Copyright 2001-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.
+#
SUNWprivate_1.1 {
global:
@@ -59,20 +83,29 @@
Java_sun_nio_ch_NativeThread_init;
Java_sun_nio_ch_NativeThread_signal;
Java_sun_nio_ch_Net_socket0;
- Java_sun_nio_ch_Net_bind;
- Java_sun_nio_ch_Net_connect;
+ Java_sun_nio_ch_Net_bind0;
+ Java_sun_nio_ch_Net_connect0;
+ Java_sun_nio_ch_Net_listen;
Java_sun_nio_ch_Net_localPort;
Java_sun_nio_ch_Net_localInetAddress;
Java_sun_nio_ch_Net_getIntOption0;
Java_sun_nio_ch_Net_setIntOption0;
Java_sun_nio_ch_Net_initIDs;
+ Java_sun_nio_ch_Net_isIPv6Available0;
+ Java_sun_nio_ch_Net_joinOrDrop4;
+ Java_sun_nio_ch_Net_blockOrUnblock4;
+ Java_sun_nio_ch_Net_joinOrDrop6;
+ Java_sun_nio_ch_Net_blockOrUnblock6;
+ Java_sun_nio_ch_Net_setInterface4;
+ Java_sun_nio_ch_Net_getInterface4;
+ Java_sun_nio_ch_Net_setInterface6;
+ Java_sun_nio_ch_Net_getInterface6;
+ Java_sun_nio_ch_Net_shutdown;
Java_sun_nio_ch_PollArrayWrapper_interrupt;
Java_sun_nio_ch_PollArrayWrapper_poll0;
Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
Java_sun_nio_ch_ServerSocketChannelImpl_initIDs;
- Java_sun_nio_ch_ServerSocketChannelImpl_listen;
Java_sun_nio_ch_SocketChannelImpl_checkConnect;
- Java_sun_nio_ch_SocketChannelImpl_shutdown;
local:
*;
diff -r 972c77670265 -r cbfe7dbaf365 jdk/make/mksample/nio/Makefile
--- a/jdk/make/mksample/nio/Makefile Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/make/mksample/nio/Makefile Thu Sep 04 14:55:12 2008 -0700
@@ -31,7 +31,7 @@
PRODUCT = java
include $(BUILDDIR)/common/Defs.gmk
-SUBDIRS = server
+SUBDIRS = multicast server
all build clean clobber::
$(SUBDIRS-loop)
diff -r 972c77670265 -r cbfe7dbaf365 jdk/make/mksample/nio/multicast/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/mksample/nio/multicast/Makefile Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,52 @@
+#
+# Copyright 2007 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.
+#
+
+#
+# Makefile for the nio/multicast sample code
+#
+
+BUILDDIR = ../../..
+
+PRODUCT = java
+
+include $(BUILDDIR)/common/Defs.gmk
+
+SAMPLE_SRC_DIR = $(SHARE_SRC)/sample/nio/multicast
+SAMPLE_DST_DIR = $(SAMPLEDIR)/nio/multicast
+
+SAMPLE_FILES = \
+ $(SAMPLE_DST_DIR)/Reader.java \
+ $(SAMPLE_DST_DIR)/Sender.java \
+ $(SAMPLE_DST_DIR)/MulticastAddress.java
+
+all build: $(SAMPLE_FILES)
+
+$(SAMPLE_DST_DIR)/%: $(SAMPLE_SRC_DIR)/%
+ $(install-file)
+
+clean clobber:
+ $(RM) -r $(SAMPLE_DST_DIR)
+
+.PHONY: all build clean clobber
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/com/sun/jmx/defaults/JmxProperties.java
--- a/jdk/src/share/classes/com/sun/jmx/defaults/JmxProperties.java Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/defaults/JmxProperties.java Thu Sep 04 14:55:12 2008 -0700
@@ -177,6 +177,18 @@
"javax.management.relation";
/**
+ * Logger name for Namespaces.
+ */
+ public static final String NAMESPACE_LOGGER_NAME =
+ "javax.management.namespace";
+
+ /**
+ * Logger name for Namespaces.
+ */
+ public static final Logger NAMESPACE_LOGGER =
+ Logger.getLogger(NAMESPACE_LOGGER_NAME);
+
+ /**
* Logger for Relation Service.
*/
public static final Logger RELATION_LOGGER =
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java
--- a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java Thu Sep 04 14:55:12 2008 -0700
@@ -25,33 +25,49 @@
package com.sun.jmx.interceptor;
-// java import
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.WeakHashMap;
+
+// JMX RI
+import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
+import com.sun.jmx.mbeanserver.DynamicMBean2;
+import com.sun.jmx.mbeanserver.Introspector;
+import com.sun.jmx.mbeanserver.MBeanInjector;
+import com.sun.jmx.mbeanserver.MBeanInstantiator;
+import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository;
+import com.sun.jmx.mbeanserver.NamedObject;
+import com.sun.jmx.mbeanserver.NotifySupport;
+import com.sun.jmx.mbeanserver.Repository;
+import com.sun.jmx.mbeanserver.Repository.RegistrationContext;
+import com.sun.jmx.mbeanserver.Util;
+import com.sun.jmx.remote.util.EnvHelp;
+
import java.lang.ref.WeakReference;
import java.security.AccessControlContext;
+import java.security.AccessController;
import java.security.Permission;
+import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.logging.Level;
// JMX import
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
+import javax.management.DynamicWrapperMBean;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.InvalidAttributeValueException;
import javax.management.JMRuntimeException;
import javax.management.ListenerNotFoundException;
-import javax.management.MalformedObjectNameException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanPermission;
@@ -64,6 +80,7 @@
import javax.management.NotCompliantMBeanException;
import javax.management.Notification;
import javax.management.NotificationBroadcaster;
+import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationEmitter;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
@@ -75,22 +92,7 @@
import javax.management.RuntimeErrorException;
import javax.management.RuntimeMBeanException;
import javax.management.RuntimeOperationsException;
-
-// JMX RI
-import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
-import com.sun.jmx.mbeanserver.DynamicMBean2;
-import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository;
-import com.sun.jmx.mbeanserver.MBeanInstantiator;
-import com.sun.jmx.mbeanserver.Repository;
-import com.sun.jmx.mbeanserver.NamedObject;
-import com.sun.jmx.mbeanserver.Introspector;
-import com.sun.jmx.mbeanserver.MBeanInjector;
-import com.sun.jmx.mbeanserver.NotifySupport;
-import com.sun.jmx.mbeanserver.Repository.RegistrationContext;
-import com.sun.jmx.mbeanserver.Util;
-import com.sun.jmx.remote.util.EnvHelp;
-import javax.management.DynamicWrapperMBean;
-import javax.management.NotificationBroadcasterSupport;
+import javax.management.namespace.JMXNamespace;
/**
* This is the default class for MBean manipulation on the agent side. It
@@ -113,7 +115,8 @@
*
* @since 1.5
*/
-public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
+public class DefaultMBeanServerInterceptor
+ extends MBeanServerInterceptorSupport {
/** The MBeanInstantiator object used by the
* DefaultMBeanServerInterceptor */
@@ -123,7 +126,7 @@
* DefaultMBeanServerInterceptor */
private transient MBeanServer server = null;
- /** The MBean server object taht associated to the
+ /** The MBean server delegate object that is associated to the
* DefaultMBeanServerInterceptor */
private final transient MBeanServerDelegate delegate;
@@ -138,13 +141,15 @@
new WeakHashMap
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ * Adds a listener to a registered MBean. A notification emitted by an MBean will be forwarded by the
- * MBeanServer to the listener. If the source of the notification
- * is a reference to an MBean object, the MBean server will replace it
- * by that MBean's ObjectName. Otherwise the source is unchanged.
- *
- * @param name The name of the MBean on which the listener should
- * be added.
- * @param listener The listener object which will handle the
- * notifications emitted by the registered MBean.
- * @param filter The filter object. If filter is null, no
- * filtering will be performed before handling notifications.
- * @param handback The context to be sent to the listener when a
- * notification is emitted.
- *
- * @exception InstanceNotFoundException The MBean name provided
- * does not match any of the registered MBeans.
- */
- public void addNotificationListener(ObjectName name,
- NotificationListener listener,
- NotificationFilter filter,
- Object handback)
- throws InstanceNotFoundException;
-
-
- /**
- * Adds a listener to a registered MBean. A notification emitted by an MBean will be forwarded by the
- * MBeanServer to the listener. If the source of the notification
- * is a reference to an MBean object, the MBean server will
- * replace it by that MBean's ObjectName. Otherwise the source is
- * unchanged. The listener object that receives notifications is the one
- * that is registered with the given name at the time this method
- * is called. Even if it is subsequently unregistered, it will
- * continue to receive notifications. If the listener is registered more than once, perhaps with
- * different filters or callbacks, this method will remove all
- * those registrations.
- *
- * @param name The name of the MBean on which the listener should
- * be removed.
- * @param listener The object name of the listener to be removed.
- *
- * @exception InstanceNotFoundException The MBean name provided
- * does not match any of the registered MBeans.
- * @exception ListenerNotFoundException The listener is not
- * registered in the MBean.
+ * This method should never be called.
+ * Usually hrows UnsupportedOperationException.
*/
- public void removeNotificationListener(ObjectName name,
- ObjectName listener)
- throws InstanceNotFoundException, ListenerNotFoundException;
-
- /**
- * Removes a listener from a registered MBean. The MBean must have a listener that exactly matches the
- * given The Removes a listener from a registered MBean. If the listener is registered more than once, perhaps with
- * different filters or callbacks, this method will remove all
- * those registrations.
- *
- * @param name The name of the MBean on which the listener should
- * be removed.
- * @param listener The listener object which will handle the
- * notifications emitted by the registered MBean.
- *
- * @exception InstanceNotFoundException The MBean name provided
- * does not match any of the registered MBeans.
- * @exception ListenerNotFoundException The listener is not
- * registered in the MBean.
- */
- public void removeNotificationListener(ObjectName name,
- NotificationListener listener)
- throws InstanceNotFoundException, ListenerNotFoundException;
+ @Deprecated
+ public ObjectInputStream deserialize(String className,
+ ObjectName loaderName, byte[] data)
+ throws InstanceNotFoundException, OperationsException,
+ ReflectionException;
/**
- * Removes a listener from a registered MBean. The MBean must have a listener that exactly matches the
- * given The Return the {@link java.lang.ClassLoader} that was used for
- * loading the class of the named MBean.
- * @param mbeanName The ObjectName of the MBean.
- * @return The ClassLoader used for that MBean.
- * @exception InstanceNotFoundException if the named MBean is not found.
- */
- public ClassLoader getClassLoaderFor(ObjectName mbeanName)
- throws InstanceNotFoundException;
-
- /**
- * Return the named {@link java.lang.ClassLoader}.
- * @param loaderName The ObjectName of the ClassLoader.
- * @return The named ClassLoader.
- * @exception InstanceNotFoundException if the named ClassLoader is
- * not found.
- */
- public ClassLoader getClassLoader(ObjectName loaderName)
- throws InstanceNotFoundException;
+ public ClassLoaderRepository getClassLoaderRepository();
}
+
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,127 @@
+/*
+ * 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 java.io.ObjectInputStream;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.ReflectionException;
+import javax.management.loading.ClassLoaderRepository;
+
+/**
+ * An abstract class for MBeanServerInterceptorSupport.
+ * Some methods in MBeanServerInterceptor should never be called.
+ * This base class provides an implementation of these methods that simply
+ * throw an {@link UnsupportedOperationException}.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ * Base class for custom implementations of the {@link MBeanServer}
- * interface. The commonest use of this class is as the {@linkplain
- * JMXNamespace#getSourceServer() source server} for a {@link
- * JMXNamespace}, although this class can be used anywhere an {@code
- * MBeanServer} instance is required. Note that the usual ways to
- * obtain an {@code MBeanServer} instance are either to use {@link
- * java.lang.management.ManagementFactory#getPlatformMBeanServer()
- * ManagementFactory.getPlatformMBeanServer()} or to use the {@code
- * newMBeanServer} or {@code createMBeanServer} methods from {@link
- * javax.management.MBeanServerFactory MBeanServerFactory}. {@code
- * MBeanServerSupport} is for certain cases where those are not
- * appropriate. There are two main use cases for this class: special-purpose MBeanServer implementations,
- * and namespaces containing Virtual MBeans. The next
- * sections explain these use cases. In the simplest case, a subclass needs to implement only two methods: Subclasses can create such {@link DynamicMBean} MBeans on the fly - for
- * instance, using the class {@link javax.management.StandardMBean}, just for
- * the duration of an MBeanServer method call. In some cases
- * the general-purpose {@code MBeanServer} that you get from
- * {@link javax.management.MBeanServerFactory MBeanServerFactory} is not
- * appropriate. You might need different security checks, or you might
- * want a mock {@code MBeanServer} suitable for use in tests, or you might
- * want a simplified and optimized {@code MBeanServer} for a special purpose. As an example of a special-purpose {@code MBeanServer}, the class {@link
- * javax.management.QueryNotificationFilter QueryNotificationFilter} constructs
- * an {@code MBeanServer} instance every time it filters a notification,
- * with just one MBean that represents the notification. Although it could
- * use {@code MBeanServerFactory.newMBeanServer}, a special-purpose {@code
- * MBeanServer} will be quicker to create, use less memory, and have simpler
- * methods that execute faster. Here is an example of a special-purpose {@code MBeanServer}
- * implementation that contains exactly one MBean, which is specified at the
- * time of creation. Using this class, you could make an {@code MBeanServer} that contains
- * a {@link javax.management.timer.Timer Timer} MBean like this: When {@code getDynamicMBeanFor} always returns the same object for the
- * same name, as here, notifications work in the expected way: if the object
- * is a {@link NotificationEmitter} then listeners can be added using
- * {@link MBeanServer#addNotificationListener(ObjectName, NotificationListener,
- * NotificationFilter, Object) MBeanServer.addNotificationListener}. If
- * {@code getDynamicMBeanFor} does not always return the same object for the
- * same name, more work is needed to make notifications work, as described
- * below. Virtual MBeans are MBeans that do not exist as Java objects,
- * except transiently while they are being accessed. This is useful when
- * there might be very many of them, or when keeping track of their creation
- * and deletion might be expensive or hard. For example, you might have one
- * MBean per system process. With an ordinary {@code MBeanServer}, you would
- * have to list the system processes in order to create an MBean object for
- * each one, and you would have to track the arrival and departure of system
- * processes in order to create or delete the corresponding MBeans. With
- * Virtual MBeans, you only need the MBean for a given process at the exact
- * point where it is referenced with a call such as
- * {@link MBeanServer#getAttribute MBeanServer.getAttribute}. Here is an example of an {@code MBeanServer} implementation that has
- * one MBean for every system property. The system property {@code "java.home"}
- * is represented by the MBean called {@code
- * com.example:type=Property,name="java.home"}, with an attribute called
- * {@code Value} that is the value of the property. Because the {@code getDynamicMBeanFor} method
- * returns a different object every time it is called, the default handling
- * of notifications will not work, as explained below.
- * In this case it does not matter, because the object returned by {@code
- * getDynamicMBeanFor} is not a {@code NotificationEmitter}, so {@link
- * MBeanServer#addNotificationListener(ObjectName, NotificationListener,
- * NotificationFilter, Object) MBeanServer.addNotificationListener} will
- * always fail. But if we wanted to extend {@code PropsMBS} so that the MBean
- * for property {@code "foo"} emitted a notification every time that property
- * changed, we would need to do it as shown below. (Because there is no API to
- * be informed when a property changes, this code assumes that some other code
- * calls the {@code propertyChanged} method every time a property changes.) MBean creation through {@code MBeanServer.createMBean} is disabled
- * by default. Subclasses which need to support MBean creation
- * through {@code createMBean} need to implement a single method {@link
- * #createMBean(String, ObjectName, ObjectName, Object[], String[],
- * boolean)}. Similarly MBean registration and unregistration through {@code
- * registerMBean} and {@code unregisterMBean} are disabled by default.
- * Subclasses which need to support MBean registration and
- * unregistration will need to implement {@link #registerMBean registerMBean}
- * and {@link #unregisterMBean unregisterMBean}. By default {@link MBeanServer#addNotificationListener(ObjectName,
- * NotificationListener, NotificationFilter, Object) addNotificationListener}
- * is accepted for an MBean {@code name} if {@link #getDynamicMBeanFor
- * getDynamicMBeanFor} The simplest way for a subclass that defines Virtual MBeans
- * to support notifications is to create a private {@link VirtualEventManager}
- * and override the method {@link
- * #getNotificationEmitterFor getNotificationEmitterFor} as follows: A notification {@code n} can then be sent from the Virtual MBean
- * called {@code name} by calling {@link VirtualEventManager#publish
- * vem.publish} Make a new {@code MBeanServerSupport} instance. Returns a dynamically created handle that makes it possible to
- * access the named MBean for the duration of a method call. An easy way to create such a {@link DynamicMBean} handle is, for
- * instance, to create a temporary MXBean instance and to wrap it in
- * an instance of
- * {@link javax.management.StandardMBean}.
- * This handle should remain valid for the duration of the call
- * but can then be discarded. Subclasses should implement this method to return
- * the names of all MBeans handled by this object instance. The object returned by getNames() should be safely {@linkplain
- * Set#iterator iterable} even in the presence of other threads that may
- * cause the set of names to change. Typically this means one of the
- * following: List names matching the given pattern.
- * The default implementation of this method calls {@link #getNames()}
- * and returns the subset of those names matching {@code pattern}. Returns a {@link NotificationEmitter} which can be used to
- * subscribe or unsubscribe for notifications with the named
- * mbean. The default implementation of this method calls {@link
- * #getDynamicMBeanFor getDynamicMBeanFor(name)} and returns that object
- * if it is a {@code NotificationEmitter}, otherwise null. See above for further discussion of notification
- * handling. Creates a new MBean in the MBean name space.
- * This operation is not supported in this base class implementation.ObjectInstance
, containing the
- * ObjectName
and the Java class name of the newly
- * instantiated MBean.
- *
- * @exception ReflectionException Wraps a
- * java.lang.ClassNotFoundException
or a
- * java.lang.Exception
that occurred when trying to
- * invoke the MBean's constructor.
- * @exception InstanceAlreadyExistsException The MBean is already
- * under the control of the MBean server.
- * @exception MBeanRegistrationException The
- * preRegister
(MBeanRegistration
- * interface) method of the MBean has thrown an exception. The
- * MBean will not be registered.
- * @exception MBeanException The constructor of the MBean has
- * thrown an exception
- * @exception RuntimeOperationsException Wraps a
- * java.lang.IllegalArgumentException
: The className
- * passed in parameter is null, the ObjectName
passed
- * in parameter contains a pattern or no ObjectName
- * is specified for the MBean.
+ * This method should never be called.
+ * Usually hrows UnsupportedOperationException.
*/
- public ObjectInstance createMBean(String className, ObjectName name,
- Object params[], String signature[])
- throws ReflectionException, InstanceAlreadyExistsException,
- MBeanRegistrationException, MBeanException,
- NotCompliantMBeanException;
-
+ public Object instantiate(String className)
+ throws ReflectionException, MBeanException;
/**
- * Instantiates and registers an MBean in the MBean server. The
- * class loader to be used is identified by its object name. An
- * object name is associated to the MBean. If the object name of
- * the loader is not specified, the ClassLoader that loaded the
- * MBean server will be used. If the MBean object name given is
- * null, the MBean must provide its own name by implementing the
- * {@link javax.management.MBeanRegistration MBeanRegistration}
- * interface and returning the name from the {@link
- * javax.management.MBeanRegistration#preRegister preRegister} method.
- *
- * @param className The class name of the MBean to be instantiated.
- * @param name The object name of the MBean. May be null.
- * @param params An array containing the parameters of the
- * constructor to be invoked.
- * @param signature An array containing the signature of the
- * constructor to be invoked.
- * @param loaderName The object name of the class loader to be used.
- *
- * @return An ObjectInstance
, containing the
- * ObjectName
and the Java class name of the newly
- * instantiated MBean.
- *
- * @exception ReflectionException Wraps a
- * java.lang.ClassNotFoundException
or a
- * java.lang.Exception
that occurred when trying to
- * invoke the MBean's constructor.
- * @exception InstanceAlreadyExistsException The MBean is already
- * under the control of the MBean server.
- * @exception MBeanRegistrationException The
- * preRegister
(MBeanRegistration
- * interface) method of the MBean has thrown an exception. The
- * MBean will not be registered.
- * @exception MBeanException The constructor of the MBean has
- * thrown an exception
- * @exception InstanceNotFoundException The specified class loader
- * is not registered in the MBean server.
- * @exception RuntimeOperationsException Wraps a
- * java.lang.IllegalArgumentException
: The className
- * passed in parameter is null, the ObjectName
passed
- * in parameter contains a pattern or no ObjectName
- * is specified for the MBean.
- *
+ * This method should never be called.
+ * Usually throws UnsupportedOperationException.
*/
- public ObjectInstance createMBean(String className, ObjectName name,
- ObjectName loaderName, Object params[],
- String signature[])
- throws ReflectionException, InstanceAlreadyExistsException,
- MBeanRegistrationException, MBeanException,
- NotCompliantMBeanException, InstanceNotFoundException;
-
+ public Object instantiate(String className, ObjectName loaderName)
+ throws ReflectionException, MBeanException,
+ InstanceNotFoundException;
/**
- * Registers a pre-existing object as an MBean with the MBean
- * server. If the object name given is null, the MBean must
- * provide its own name by implementing the {@link
- * javax.management.MBeanRegistration MBeanRegistration} interface
- * and returning the name from the {@link
- * javax.management.MBeanRegistration#preRegister preRegister} method.
- *
- * @param object The MBean to be registered as an MBean.
- * @param name The object name of the MBean. May be null.
- *
- * @return The ObjectInstance
for the MBean that has
- * been registered.
- *
- * @exception InstanceAlreadyExistsException The MBean is already
- * under the control of the MBean server.
- * @exception MBeanRegistrationException The
- * preRegister
(MBeanRegistration
- * interface) method of the MBean has thrown an exception. The
- * MBean will not be registered.
- * @exception NotCompliantMBeanException This object is not a JMX
- * compliant MBean
- * @exception RuntimeOperationsException Wraps a
- * java.lang.IllegalArgumentException
: The object
- * passed in parameter is null or no object name is specified.
+ * This method should never be called.
+ * Usually throws UnsupportedOperationException.
*/
- public ObjectInstance registerMBean(Object object, ObjectName name)
- throws InstanceAlreadyExistsException, MBeanRegistrationException,
- NotCompliantMBeanException;
+ public Object instantiate(String className, Object[] params,
+ String[] signature) throws ReflectionException, MBeanException;
/**
- * Unregisters an MBean from the MBean server. The MBean is
- * identified by its object name. Once the method has been
- * invoked, the MBean may no longer be accessed by its object
- * name.
- *
- * @param name The object name of the MBean to be unregistered.
- *
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- * @exception MBeanRegistrationException The preDeregister
- * ((MBeanRegistration
interface) method of the MBean
- * has thrown an exception.
- * @exception RuntimeOperationsException Wraps a
- * java.lang.IllegalArgumentException
: The object
- * name in parameter is null or the MBean you are when trying to
- * unregister is the {@link javax.management.MBeanServerDelegate
- * MBeanServerDelegate} MBean.
- *
- */
- public void unregisterMBean(ObjectName name)
- throws InstanceNotFoundException, MBeanRegistrationException;
-
- /**
- * Gets the ObjectInstance
for a given MBean
- * registered with the MBean server.
- *
- * @param name The object name of the MBean.
- *
- * @return The ObjectInstance
associated to the MBean
- * specified by name.
- *
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- */
- public ObjectInstance getObjectInstance(ObjectName name)
- throws InstanceNotFoundException;
-
- /**
- * Gets MBeans controlled by the MBean server. This method allows
- * any of the following to be obtained: All MBeans, a set of
- * MBeans specified by pattern matching on the
- * ObjectName
and/or a Query expression, a specific
- * MBean. When the object name is null or no domain and key
- * properties are specified, all objects are to be selected (and
- * filtered if a query is specified). It returns the set of
- * ObjectInstance
objects (containing the
- * ObjectName
and the Java Class name) for the
- * selected MBeans.
- *
- * @param name The object name pattern identifying the MBeans to
- * be retrieved. If null or no domain and key properties are
- * specified, all the MBeans registered will be retrieved.
- * @param query The query expression to be applied for selecting
- * MBeans. If null no query expression will be applied for
- * selecting MBeans.
- *
- * @return A set containing the ObjectInstance
- * objects for the selected MBeans. If no MBean satisfies the
- * query an empty list is returned.
+ * This method should never be called.
+ * Usually throws UnsupportedOperationException.
*/
- public SetObjectName
and/or a Query
- * expression, a specific MBean name (equivalent to testing
- * whether an MBean is registered). When the object name is null
- * or no domain and key properties are specified, all objects are
- * selected (and filtered if a query is specified). It returns the
- * set of ObjectNames for the MBeans selected.
- *
- * @param name The object name pattern identifying the MBean names
- * to be retrieved. If null oror no domain and key properties are
- * specified, the name of all registered MBeans will be retrieved.
- * @param query The query expression to be applied for selecting
- * MBeans. If null no query expression will be applied for
- * selecting MBeans.
- *
- * @return A set containing the ObjectNames for the MBeans
- * selected. If no MBean satisfies the query, an empty list is
- * returned.
- */
- public Setjava.lang.IllegalArgumentException
: The object
- * name in parameter is null.
- */
- public boolean isRegistered(ObjectName name);
-
- /**
- * Returns the number of MBeans registered in the MBean server.
- */
- public Integer getMBeanCount();
-
- /**
- * Gets the value of a specific attribute of a named MBean. The MBean
- * is identified by its object name.
- *
- * @param name The object name of the MBean from which the
- * attribute is to be retrieved.
- * @param attribute A String specifying the name of the attribute
- * to be retrieved.
- *
- * @return The value of the retrieved attribute.
- *
- * @exception AttributeNotFoundException The attribute specified
- * is not accessible in the MBean.
- * @exception MBeanException Wraps an exception thrown by the
- * MBean's getter.
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- * @exception ReflectionException Wraps a
- * java.lang.Exception
thrown when trying to invoke
- * the setter.
- * @exception RuntimeOperationsException Wraps a
- * java.lang.IllegalArgumentException
: The object
- * name in parameter is null or the attribute in parameter is
- * null.
- */
- public Object getAttribute(ObjectName name, String attribute)
- throws MBeanException, AttributeNotFoundException,
- InstanceNotFoundException, ReflectionException;
-
- /**
- * Enables the values of several attributes of a named MBean. The MBean
- * is identified by its object name.
- *
- * @param name The object name of the MBean from which the
- * attributes are retrieved.
- * @param attributes A list of the attributes to be retrieved.
- *
- * @return The list of the retrieved attributes.
- *
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- * @exception ReflectionException An exception occurred when
- * trying to invoke the getAttributes method of a Dynamic MBean.
- * @exception RuntimeOperationsException Wrap a
- * java.lang.IllegalArgumentException
: The object
- * name in parameter is null or attributes in parameter is null.
- */
- public AttributeList getAttributes(ObjectName name, String[] attributes)
- throws InstanceNotFoundException, ReflectionException;
+ public Object instantiate(String className, ObjectName loaderName,
+ Object[] params, String[] signature)
+ throws ReflectionException, MBeanException,
+ InstanceNotFoundException;
/**
- * Sets the value of a specific attribute of a named MBean. The MBean
- * is identified by its object name.
- *
- * @param name The name of the MBean within which the attribute is
- * to be set.
- * @param attribute The identification of the attribute to be set
- * and the value it is to be set to.
- *
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- * @exception AttributeNotFoundException The attribute specified
- * is not accessible in the MBean.
- * @exception InvalidAttributeValueException The value specified
- * for the attribute is not valid.
- * @exception MBeanException Wraps an exception thrown by the
- * MBean's setter.
- * @exception ReflectionException Wraps a
- * java.lang.Exception
thrown when trying to invoke
- * the setter.
- * @exception RuntimeOperationsException Wraps a
- * java.lang.IllegalArgumentException
: The object
- * name in parameter is null or the attribute in parameter is
- * null.
+ * This method should never be called.
+ * Usually throws UnsupportedOperationException.
*/
- public void setAttribute(ObjectName name, Attribute attribute)
- throws InstanceNotFoundException, AttributeNotFoundException,
- InvalidAttributeValueException, MBeanException,
- ReflectionException;
-
-
-
- /**
- * Sets the values of several attributes of a named MBean. The MBean is
- * identified by its object name.
- *
- * @param name The object name of the MBean within which the
- * attributes are to be set.
- * @param attributes A list of attributes: The identification of
- * the attributes to be set and the values they are to be set to.
- *
- * @return The list of attributes that were set, with their new
- * values.
- *
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- * @exception ReflectionException An exception occurred when
- * trying to invoke the getAttributes method of a Dynamic MBean.
- * @exception RuntimeOperationsException Wraps a
- * java.lang.IllegalArgumentException
: The object
- * name in parameter is null or attributes in parameter is null.
- */
- public AttributeList setAttributes(ObjectName name,
- AttributeList attributes)
- throws InstanceNotFoundException, ReflectionException;
+ @Deprecated
+ public ObjectInputStream deserialize(ObjectName name, byte[] data)
+ throws InstanceNotFoundException, OperationsException;
/**
- * Invokes an operation on an MBean.
- *
- * @param name The object name of the MBean on which the method is
- * to be invoked.
- * @param operationName The name of the operation to be invoked.
- * @param params An array containing the parameters to be set when
- * the operation is invoked
- * @param signature An array containing the signature of the
- * operation. The class objects will be loaded using the same
- * class loader as the one used for loading the MBean on which the
- * operation was invoked.
- *
- * @return The object returned by the operation, which represents
- * the result ofinvoking the operation on the MBean specified.
- *
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- * @exception MBeanException Wraps an exception thrown by the
- * MBean's invoked method.
- * @exception ReflectionException Wraps a
- * java.lang.Exception
thrown while trying to invoke
- * the method.
- */
- public Object invoke(ObjectName name, String operationName,
- Object params[], String signature[])
- throws InstanceNotFoundException, MBeanException,
- ReflectionException;
-
- /**
- * Returns the default domain used for naming the MBean.
- * The default domain name is used as the domain part in the ObjectName
- * of MBeans if no domain is specified by the user.
- */
- public String getDefaultDomain();
-
- /**
- * Returns the list of domains in which any MBean is currently
- * registered.
+ * This method should never be called.
+ * Usually throws UnsupportedOperationException.
*/
- public String[] getDomains();
-
- /**
- * listener
exists but does not implement the {@link
- * NotificationListener} interface.
- * @exception IOException A communication problem occurred when
- * talking to the MBean server.
- */
- public void addNotificationListener(ObjectName name,
- ObjectName listener,
- NotificationFilter filter,
- Object handback)
- throws InstanceNotFoundException;
+ @Deprecated
+ public ObjectInputStream deserialize(String className, byte[] data)
+ throws OperationsException, ReflectionException;
/**
- * Removes a listener from a registered MBean.
- *
- * listener
, filter
, and
- * handback
parameters. If there is more than one
- * such listener, only one is removed.filter
and handback
parameters
- * may be null if and only if they are null in a listener to be
- * removed.listener
, filter
, and
- * handback
parameters. If there is more than one
- * such listener, only one is removed.filter
and handback
parameters
- * may be null if and only if they are null in a listener to be
- * removed.MBeanInfo
allowing the
- * retrieval of all attributes and operations of this MBean.
- *
- * @exception IntrospectionException An exception occurred during
- * introspection.
- * @exception InstanceNotFoundException The MBean specified was
- * not found.
- * @exception ReflectionException An exception occurred when
- * trying to invoke the getMBeanInfo of a Dynamic MBean.
- */
- public MBeanInfo getMBeanInfo(ObjectName name)
- throws InstanceNotFoundException, IntrospectionException,
- ReflectionException;
-
-
- /**
- * Returns true if the MBean specified is an instance of the
- * specified class, false otherwise.
- *
- * @param name The ObjectName
of the MBean.
- * @param className The name of the class.
- *
- * @return true if the MBean specified is an instance of the
- * specified class, false otherwise.
- *
- * @exception InstanceNotFoundException The MBean specified is not
- * registered in the MBean server.
- */
- public boolean isInstanceOf(ObjectName name, String className)
- throws InstanceNotFoundException;
-
- /**
- *
- *
- *
- * Special-purpose MBeanServer implementations
- *
- *
- * public class SingletonMBeanServer extends MBeanServerSupport {
- * private final ObjectName objectName;
- * private final DynamicMBean mbean;
- *
- * public SingletonMBeanServer(ObjectName objectName, DynamicMBean mbean) {
- * this.objectName = objectName;
- * this.mbean = mbean;
- * }
- *
- * @Override
- * protected {@code Set
- *
- *
- * Timer timer = new Timer();
- * DynamicMBean mbean = new {@link javax.management.StandardMBean
- * StandardMBean}(timer, TimerMBean.class);
- * ObjectName name = new ObjectName("com.example:type=Timer");
- * MBeanServer timerMBS = new SingletonMBeanServer(name, mbean);
- *
- *
- * Namespaces containing Virtual MBeans
- *
- *
- * public interface PropertyMBean {
- * public String getValue();
- * }
- *
- * public class PropsMBS extends MBeanServerSupport {
- * private static ObjectName newObjectName(String name) {
- * try {
- * return new ObjectName(name);
- * } catch (MalformedObjectNameException e) {
- * throw new AssertionError(e);
- * }
- * }
- *
- * public static class PropertyImpl implements PropertyMBean {
- * private final String name;
- *
- * public PropertyImpl(String name) {
- * this.name = name;
- * }
- *
- * public String getValue() {
- * return System.getProperty(name);
- * }
- * }
- *
- * @Override
- * public DynamicMBean {@link #getDynamicMBeanFor
- * getDynamicMBeanFor}(ObjectName name)
- * throws InstanceNotFoundException {
- *
- * // Check that the name is a legal one for a Property MBean
- * ObjectName namePattern = newObjectName(
- * "com.example:type=Property,name=\"*\"");
- * if (!namePattern.apply(name))
- * throw new InstanceNotFoundException(name);
- *
- * // Extract the name of the property that the MBean corresponds to
- * String propName = ObjectName.unquote(name.getKeyProperty("name"));
- * if (System.getProperty(propName) == null)
- * throw new InstanceNotFoundException(name);
- *
- * // Construct and return a transient MBean object
- * PropertyMBean propMBean = new PropertyImpl(propName);
- * return new StandardMBean(propMBean, PropertyMBean.class, false);
- * }
- *
- * @Override
- * protected {@code Set
- *
- *
- * public class PropsMBS {
- * ...as above...
- *
- * private final {@link VirtualEventManager} vem = new VirtualEventManager();
- *
- * @Override
- * public NotificationEmitter {@link #getNotificationEmitterFor
- * getNotificationEmitterFor}(
- * ObjectName name) throws InstanceNotFoundException {
- * getDynamicMBeanFor(name); // check that the name is valid
- * return vem.{@link VirtualEventManager#getNotificationEmitterFor
- * getNotificationEmitterFor}(name);
- * }
- *
- * public void propertyChanged(String name, String newValue) {
- * ObjectName objectName = newObjectName(
- * "com.example:type=Property,name=" + ObjectName.quote(name));
- * Notification n = new Notification(
- * "com.example.property.changed", objectName, 0L,
- * "Property " + name + " changed");
- * n.setUserData(newValue);
- * vem.{@link VirtualEventManager#publish publish}(objectName, n);
- * }
- * }
- *
- *
- * MBean creation and deletion
- *
- * Notifications
- *
- * (name)
returns an object that is a
- * {@link NotificationEmitter}. That is appropriate if
- * {@code getDynamicMBeanFor}(name)
always returns the
- * same object for the same {@code name}. But with
- * Virtual MBeans, every call to {@code getDynamicMBeanFor} returns a new object,
- * which is discarded as soon as the MBean request has finished.
- * So a listener added to that object would be immediately forgotten.
- * private final VirtualEventManager vem = new VirtualEventManager();
- *
- * @Override
- * public NotificationEmitter getNotificationEmitterFor(
- * ObjectName name) throws InstanceNotFoundException {
- * // Check that the name is a valid Virtual MBean.
- * // This is the easiest way to do that, but not always the
- * // most efficient:
- * getDynamicMBeanFor(name);
- *
- * // Return an object that supports add/removeNotificationListener
- * // through the VirtualEventManager.
- * return vem.getNotificationEmitterFor(name);
- * }
- *
- *
- * (name, n)
. See the example
- * above.
- *
- *
- * @return the names of all MBeans handled by this object.
- */
- protected abstract Set
Subclasses may redefine this method to provide an implementation.
- * All the various flavors of {@code MBeanServer.createMBean} methods
- * will eventually call this method. A subclass that wishes to
- * support MBean creation through {@code createMBean} thus only
- * needs to provide an implementation for this one method.
- *
- * @param className The class name of the MBean to be instantiated.
- * @param name The object name of the MBean. May be null.
- * @param params An array containing the parameters of the
- * constructor to be invoked.
- * @param signature An array containing the signature of the
- * constructor to be invoked.
- * @param loaderName The object name of the class loader to be used.
- * @param useCLR This parameter is {@code true} when this method
- * is called from one of the {@code MBeanServer.createMBean} methods
- * whose signature does not include the {@code ObjectName} of an
- * MBean class loader to use for loading the MBean class.
- *
- * @return An ObjectInstance
, containing the
- * ObjectName
and the Java class name of the newly
- * instantiated MBean. If the contained ObjectName
- * is n
, the contained Java class name is
- * {@link javax.management.MBeanServer#getMBeanInfo
- * getMBeanInfo(n)}.getClassName()
.
- *
- * @exception ReflectionException Wraps a
- * java.lang.ClassNotFoundException
or a
- * java.lang.Exception
that occurred when trying to
- * invoke the MBean's constructor.
- * @exception InstanceAlreadyExistsException The MBean is already
- * under the control of the MBean server.
- * @exception MBeanRegistrationException The
- * preRegister
(MBeanRegistration
- * interface) method of the MBean has thrown an exception. The
- * MBean will not be registered.
- * @exception MBeanException The constructor of the MBean has
- * thrown an exception
- * @exception NotCompliantMBeanException This class is not a JMX
- * compliant MBean
- * @exception InstanceNotFoundException The specified class loader
- * is not registered in the MBean server.
- * @exception RuntimeOperationsException Wraps either:
- *
java.lang.IllegalArgumentException
: The className
- * passed in parameter is null, the ObjectName
passed in
- * parameter contains a pattern or no ObjectName
is specified
- * for the MBean; orAttempts to determine whether the named MBean should be - * considered as an instance of a given class. The default implementation - * of this method calls {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} - * to get an MBean object. Then its behaviour is the same as the standard - * {@link MBeanServer#isInstanceOf MBeanServer.isInstanceOf} method.
- * - * {@inheritDoc} - */ - public boolean isInstanceOf(ObjectName name, String className) - throws InstanceNotFoundException { - - final DynamicMBean instance = nonNullMBeanFor(name); - - try { - final String mbeanClassName = instance.getMBeanInfo().getClassName(); - - if (mbeanClassName.equals(className)) - return true; - - final Object resource; - final ClassLoader cl; - if (instance instanceof DynamicWrapperMBean) { - DynamicWrapperMBean d = (DynamicWrapperMBean) instance; - resource = d.getWrappedObject(); - cl = d.getWrappedClassLoader(); - } else { - resource = instance; - cl = instance.getClass().getClassLoader(); - } - - final Class> classNameClass = Class.forName(className, false, cl); - - if (classNameClass.isInstance(resource)) - return true; - - if (classNameClass == NotificationBroadcaster.class || - classNameClass == NotificationEmitter.class) { - try { - getNotificationEmitterFor(name); - return true; - } catch (Exception x) { - LOG.finest("MBean " + name + - " is not a notification emitter. Ignoring: "+x); - return false; - } - } - - final Class> resourceClass = Class.forName(mbeanClassName, false, cl); - return classNameClass.isAssignableFrom(resourceClass); - } catch (Exception x) { - /* Could be SecurityException or ClassNotFoundException */ - LOG.logp(Level.FINEST, - MBeanServerSupport.class.getName(), - "isInstanceOf", "Exception calling isInstanceOf", x); - return false; - } - } - - /** - * {@inheritDoc} - * - *The default implementation of this method returns the string - * "DefaultDomain".
- */ - public String getDefaultDomain() { - return "DefaultDomain"; - } - - /** - * {@inheritDoc} - * - *The default implementation of this method returns - * {@link #getNames()}.size().
- */ - public Integer getMBeanCount() { - return getNames().size(); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method first calls {@link #getNames - * getNames()} to get a list of all MBean names, - * and from this set of names, derives the set of domains which contain - * MBeans.
- */ - public String[] getDomains() { - final SetThe default implementation of this method will first - * call {@link - * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle - * to the named MBean, - * and then call {@link DynamicMBean#getAttribute getAttribute} - * on that {@link DynamicMBean} handle.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public Object getAttribute(ObjectName name, String attribute) - throws MBeanException, AttributeNotFoundException, - InstanceNotFoundException, ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - return mbean.getAttribute(attribute); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} - * to obtain a handle to the named MBean, - * and then call {@link DynamicMBean#setAttribute setAttribute} - * on that {@link DynamicMBean} handle.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public void setAttribute(ObjectName name, Attribute attribute) - throws InstanceNotFoundException, AttributeNotFoundException, - InvalidAttributeValueException, MBeanException, - ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - mbean.setAttribute(attribute); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a - * handle to the named MBean, - * and then call {@link DynamicMBean#getAttributes getAttributes} - * on that {@link DynamicMBean} handle.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public AttributeList getAttributes(ObjectName name, - String[] attributes) throws InstanceNotFoundException, - ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - return mbean.getAttributes(attributes); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a - * handle to the named MBean, - * and then call {@link DynamicMBean#setAttributes setAttributes} - * on that {@link DynamicMBean} handle.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public AttributeList setAttributes(ObjectName name, AttributeList attributes) - throws InstanceNotFoundException, ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - return mbean.setAttributes(attributes); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a - * handle to the named MBean, - * and then call {@link DynamicMBean#invoke invoke} - * on that {@link DynamicMBean} handle.
- */ - public Object invoke(ObjectName name, String operationName, - Object[] params, String[] signature) - throws InstanceNotFoundException, MBeanException, - ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - return mbean.invoke(operationName, params, signature); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a - * handle to the named MBean, - * and then call {@link DynamicMBean#getMBeanInfo getMBeanInfo} - * on that {@link DynamicMBean} handle.
- */ - public MBeanInfo getMBeanInfo(ObjectName name) - throws InstanceNotFoundException, IntrospectionException, - ReflectionException { - final DynamicMBean mbean = nonNullMBeanFor(name); - return mbean.getMBeanInfo(); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will call - * {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}.{@link DynamicMBean#getMBeanInfo getMBeanInfo()}.{@link MBeanInfo#getClassName getClassName()} to get the - * class name to combine with {@code name} to produce a new - * {@code ObjectInstance}.
- */ - public ObjectInstance getObjectInstance(ObjectName name) - throws InstanceNotFoundException { - final DynamicMBean mbean = nonNullMBeanFor(name); - final String className = mbean.getMBeanInfo().getClassName(); - return new ObjectInstance(name, className); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method will first call {@link - * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle to the - * named MBean. If {@code getDynamicMBeanFor} returns an object, {@code - * isRegistered} will return true. If {@code getDynamicMBeanFor} returns - * null or throws {@link InstanceNotFoundException}, {@code isRegistered} - * will return false.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public boolean isRegistered(ObjectName name) { - try { - final DynamicMBean mbean = getDynamicMBeanFor(name); - return mbean!=null; - } catch (InstanceNotFoundException x) { - if (LOG.isLoggable(Level.FINEST)) - LOG.finest("MBean "+name+" is not registered: "+x); - return false; - } - } - - - /** - * {@inheritDoc} - * - *The default implementation of this method will first - * call {@link #queryNames queryNames} - * to get a list of all matching MBeans, and then, for each returned name, - * call {@link #getObjectInstance getObjectInstance(name)}.
- */ - public SetThe default implementation of this method calls {@link #getMatchingNames - * getMatchingNames(pattern)} to obtain a list of MBeans matching - * the given name pattern. If the {@code query} parameter is null, - * this will be the result. Otherwise, it will evaluate the - * {@code query} parameter for each of the returned names, exactly - * as an {@code MBeanServer} would. This might result in - * {@link #getDynamicMBeanFor getDynamicMBeanFor} being called - * several times for each returned name.
- */ - public SetAdds a listener to a registered MBean. A notification emitted by - * the MBean will be forwarded to the listener.
- * - *This implementation calls - * {@link #getNotificationEmitterFor getNotificationEmitterFor} - * and invokes {@code addNotificationListener} on the - * {@link NotificationEmitter} it returns. - * - * @see #getDynamicMBeanFor getDynamicMBeanFor - * @see #getNotificationEmitterFor getNotificationEmitterFor - */ - public void addNotificationListener(ObjectName name, - NotificationListener listener, NotificationFilter filter, - Object handback) throws InstanceNotFoundException { - final NotificationEmitter emitter = - getNonNullNotificationEmitterFor(name); - emitter.addNotificationListener(listener, filter, handback); - } - - /** - * {@inheritDoc} - * - *
This implementation calls - * {@link #getNotificationEmitterFor getNotificationEmitterFor} - * and invokes {@code removeNotificationListener} on the - * {@link NotificationEmitter} it returns. - * @see #getDynamicMBeanFor getDynamicMBeanFor - * @see #getNotificationEmitterFor getNotificationEmitterFor - */ - public void removeNotificationListener(ObjectName name, - NotificationListener listener) - throws InstanceNotFoundException, ListenerNotFoundException { - final NotificationEmitter emitter = - getNonNullNotificationEmitterFor(name); - emitter.removeNotificationListener(listener); - } - - /** - * {@inheritDoc} - * - *
This implementation calls - * {@link #getNotificationEmitterFor getNotificationEmitterFor} - * and invokes {@code removeNotificationListener} on the - * {@link NotificationEmitter} it returns. - * @see #getDynamicMBeanFor getDynamicMBeanFor - * @see #getNotificationEmitterFor getNotificationEmitterFor - */ - public void removeNotificationListener(ObjectName name, - NotificationListener listener, NotificationFilter filter, - Object handback) - throws InstanceNotFoundException, ListenerNotFoundException { - NotificationEmitter emitter = - getNonNullNotificationEmitterFor(name); - emitter.removeNotificationListener(listener); - } - - - /** - *
Adds a listener to a registered MBean.
- * - *The default implementation of this method first calls - * {@link #getDynamicMBeanFor getDynamicMBeanFor(listenerName)}. - * If that successfully returns an object, call it {@code - * mbean}, then (a) if {@code mbean} is an instance of {@link - * NotificationListener} then this method calls {@link - * #addNotificationListener(ObjectName, NotificationListener, - * NotificationFilter, Object) addNotificationListener(name, mbean, filter, - * handback)}, otherwise (b) this method throws an exception as specified - * for this case.
- * - *This default implementation is not appropriate for Virtual MBeans, - * although that only matters if the object returned by {@code - * getDynamicMBeanFor} can be an instance of - * {@code NotificationListener}.
- * - * @throws RuntimeOperationsException {@inheritDoc} - */ - public void addNotificationListener(ObjectName name, ObjectName listenerName, - NotificationFilter filter, Object handback) - throws InstanceNotFoundException { - NotificationListener listener = getListenerMBean(listenerName); - addNotificationListener(name, listener, filter, handback); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public void removeNotificationListener(ObjectName name, - ObjectName listenerName) - throws InstanceNotFoundException, ListenerNotFoundException { - NotificationListener listener = getListenerMBean(listenerName); - removeNotificationListener(name, listener); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public void removeNotificationListener(ObjectName name, - ObjectName listenerName, NotificationFilter filter, - Object handback) - throws InstanceNotFoundException, ListenerNotFoundException { - NotificationListener listener = getListenerMBean(listenerName); - removeNotificationListener(name, listener, filter, handback); - } - - private NotificationListener getListenerMBean(ObjectName listenerName) - throws InstanceNotFoundException { - Object mbean = getDynamicMBeanFor(listenerName); - if (mbean instanceof NotificationListener) - return (NotificationListener) mbean; - else { - throw newIllegalArgumentException( - "MBean is not a NotificationListener: " + listenerName); - } - } - - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link InstanceNotFoundException} wrapping - * {@link UnsupportedOperationException}.
- * - * @return the default implementation of this method never returns. - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public ClassLoader getClassLoader(ObjectName loaderName) - throws InstanceNotFoundException { - final UnsupportedOperationException failed = - new UnsupportedOperationException("getClassLoader"); - final InstanceNotFoundException x = - new InstanceNotFoundException(String.valueOf(loaderName)); - x.initCause(failed); - throw x; - } - - /** - * {@inheritDoc} - * - *The default implementation of this method calls - * {@link #getDynamicMBeanFor getDynamicMBeanFor(mbeanName)} and applies - * the logic just described to the result.
- */ - public ClassLoader getClassLoaderFor(ObjectName mbeanName) - throws InstanceNotFoundException { - final DynamicMBean mbean = nonNullMBeanFor(mbeanName); - if (mbean instanceof DynamicWrapperMBean) - return ((DynamicWrapperMBean) mbean).getWrappedClassLoader(); - else - return mbean.getClass().getClassLoader(); - } - - /** - * {@inheritDoc} - * - *The default implementation of this method returns a - * {@link ClassLoaderRepository} containing exactly one loader, - * the {@linkplain Thread#getContextClassLoader() context class loader} - * for the current thread. - * Subclasses can override this method to return a different - * {@code ClassLoaderRepository}.
- */ - public ClassLoaderRepository getClassLoaderRepository() { - // We return a new ClassLoaderRepository each time this - // method is called. This is by design, because the - // SingletonClassLoaderRepository is a very small object and - // getClassLoaderRepository() will not be called very often - // (the connector server calls it once) - in the context of - // MBeanServerSupport there's a very good chance that this method will - // *never* be called. - ClassLoader ccl = Thread.currentThread().getContextClassLoader(); - return Util.getSingleClassLoaderRepository(ccl); - } - - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public ObjectInstance registerMBean(Object object, ObjectName name) - throws InstanceAlreadyExistsException, MBeanRegistrationException, - NotCompliantMBeanException { - throw newUnsupportedException("registerMBean"); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}. - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public void unregisterMBean(ObjectName name) - throws InstanceNotFoundException, MBeanRegistrationException { - throw newUnsupportedException("unregisterMBean"); - } - - /** - * Calls {@link #createMBean(String, ObjectName, - * ObjectName, Object[], String[], boolean) - * createMBean(className, name, null, params, signature, true)}; - */ - public final ObjectInstance createMBean(String className, ObjectName name, - Object[] params, String[] signature) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException { - try { - return safeCreateMBean(className, name, null, params, signature, true); - } catch (InstanceNotFoundException ex) { - // should not happen! - throw new MBeanException(ex, "Unexpected exception: " + ex); - } - } - - /** - * Calls {@link #createMBean(String, ObjectName, - * ObjectName, Object[], String[], boolean) - * createMBean(className,name, loaderName, params, signature, false)}; - */ - public final ObjectInstance createMBean(String className, ObjectName name, - ObjectName loaderName, Object[] params, String[] signature) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException, InstanceNotFoundException { - return safeCreateMBean(className, name, loaderName, params, signature, false); - } - - /** - * Calls {@link #createMBean(String, ObjectName, - * ObjectName, Object[], String[], boolean) - * createMBean(className, name, null, null, null, true)}; - */ - public final ObjectInstance createMBean(String className, ObjectName name) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException { - try { - return safeCreateMBean(className, name, null, null, null, true); - } catch (InstanceNotFoundException ex) { - // should not happen! - throw new MBeanException(ex, "Unexpected exception: " + ex); - } - } - - /** - * Calls {@link #createMBean(String, ObjectName, - * ObjectName, Object[], String[], boolean) - * createMBean(className, name, loaderName, null, null, false)}; - */ - public final ObjectInstance createMBean(String className, ObjectName name, - ObjectName loaderName) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException, InstanceNotFoundException { - return safeCreateMBean(className, name, loaderName, null, null, false); - } - - // make sure all exceptions are correctly wrapped in a JMXException - private ObjectInstance safeCreateMBean(String className, - ObjectName name, ObjectName loaderName, Object[] params, - String[] signature, boolean useRepository) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException, InstanceNotFoundException { - try { - return createMBean(className, name, loaderName, params, - signature, useRepository); - } catch (ReflectionException x) { throw x; - } catch (InstanceAlreadyExistsException x) { throw x; - } catch (MBeanRegistrationException x) { throw x; - } catch (MBeanException x) { throw x; - } catch (NotCompliantMBeanException x) { throw x; - } catch (InstanceNotFoundException x) { throw x; - } catch (SecurityException x) { throw x; - } catch (JMRuntimeException x) { throw x; - } catch (RuntimeException x) { - throw new RuntimeOperationsException(x, x.toString()); - } catch (Exception x) { - throw new MBeanException(x, x.toString()); - } - } - - - /** - * {@inheritDoc} - * - *
This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public Object instantiate(String className) - throws ReflectionException, MBeanException { - throw new UnsupportedOperationException("Not applicable."); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public Object instantiate(String className, ObjectName loaderName) - throws ReflectionException, MBeanException, - InstanceNotFoundException { - throw new UnsupportedOperationException("Not applicable."); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public Object instantiate(String className, Object[] params, - String[] signature) throws ReflectionException, MBeanException { - throw new UnsupportedOperationException("Not applicable."); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - public Object instantiate(String className, ObjectName loaderName, - Object[] params, String[] signature) - throws ReflectionException, MBeanException, - InstanceNotFoundException { - throw new UnsupportedOperationException("Not applicable."); - } - - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - @Deprecated - public ObjectInputStream deserialize(ObjectName name, byte[] data) - throws InstanceNotFoundException, OperationsException { - throw new UnsupportedOperationException("Not applicable."); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - @Deprecated - public ObjectInputStream deserialize(String className, byte[] data) - throws OperationsException, ReflectionException { - throw new UnsupportedOperationException("Not applicable."); - } - - /** - * {@inheritDoc} - * - *This operation is not supported in this base class implementation. - * The default implementation of this method always throws - * {@link RuntimeOperationsException} wrapping - * {@link UnsupportedOperationException}.
- * - * @throws javax.management.RuntimeOperationsException wrapping - * {@link UnsupportedOperationException} - */ - @Deprecated - public ObjectInputStream deserialize(String className, - ObjectName loaderName, byte[] data) - throws InstanceNotFoundException, OperationsException, - ReflectionException { - throw new UnsupportedOperationException("Not applicable."); - } - - - // Calls getDynamicMBeanFor, and throws an InstanceNotFoundException - // if the returned mbean is null. - // The DynamicMBean returned by this method is thus guaranteed to be - // non null. - // - private DynamicMBean nonNullMBeanFor(ObjectName name) - throws InstanceNotFoundException { - if (name == null) - throw newIllegalArgumentException("Null ObjectName"); - if (name.getDomain().equals("")) { - String defaultDomain = getDefaultDomain(); - try { - // XXX change to ObjectName.switchDomain - // current code DOES NOT PRESERVE the order of keys - name = new ObjectName(defaultDomain, name.getKeyPropertyList()); - } catch (Exception e) { - throw newIllegalArgumentException( - "Illegal default domain: " + defaultDomain); - } - } - final DynamicMBean mbean = getDynamicMBeanFor(name); - if (mbean!=null) return mbean; - throw new InstanceNotFoundException(String.valueOf(name)); - } - - static RuntimeException newUnsupportedException(String operation) { - return new RuntimeOperationsException( - new UnsupportedOperationException( - operation+": Not supported in this namespace")); - } - - static RuntimeException newIllegalArgumentException(String msg) { - return new RuntimeOperationsException( - new IllegalArgumentException(msg)); - } - -} diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java Thu Sep 04 14:55:12 2008 -0700 @@ -0,0 +1,236 @@ +/* + * 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. + *+ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +public class NamespaceDispatchInterceptor + extends DispatchInterceptorDo not forget to call Return the MBeanServerDelegate representing the MBeanServer.
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java Thu Sep 04 14:55:12 2008 -0700
@@ -25,6 +25,8 @@
package com.sun.jmx.mbeanserver;
+import com.sun.jmx.defaults.JmxProperties;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -42,11 +44,22 @@
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.WeakHashMap;
+import java.util.logging.Level;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;
+import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.loading.ClassLoaderRepository;
+import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
public class Util {
+ private final static int NAMESPACE_SEPARATOR_LENGTH =
+ NAMESPACE_SEPARATOR.length();
+ public final static String ILLEGAL_MBEANSERVER_NAME_CHARS=";:*?";
+
+
static
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * Note: all the standard JMXConnector implementations are serializable.
+ * This implementation here is not. Should it be?
+ * I believe it must not be serializable unless it becomes
+ * part of a public API (either standard or officially exposed
+ * and supported in a documented com.sun package)
+ **/
+ static class JMXCachingConnector
+ implements JMXConnector {
+
+ // private static final long serialVersionUID = -2279076110599707875L;
+
+ final JMXConnector source;
+
+ // if this object is made serializable, then the variable below
+ // needs to become volatile transient and be lazyly-created...
+ private final
+ Map
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * By default, this method always returns {@code domains}
+ *
+ * @param domains The domains to return.
+ * @param action "getDomains"
+ * @return a filtered list of domains.
+ */
+ String[] checkDomains(String[] domains, String action) {
+ return domains;
+ }
+
+ // from MBeanServerConnection
+ public String getDefaultDomain() throws IOException {
+ try {
+ return source().getDefaultDomain();
+ } catch (RuntimeException ex) {
+ throw makeCompliantRuntimeException(ex);
+ }
+ }
+
+}
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,282 @@
+/*
+ * 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.namespace;
+
+import com.sun.jmx.defaults.JmxProperties;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanRegistrationException;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.namespace.JMXNamespaces;
+
+
+/**
+ * An RoutingProxy narrows on a given name space in a
+ * source object implementing MBeanServerConnection.
+ * It is used to implement
+ * {@code JMXNamespaces.narrowToNamespace(...)}.
+ * This abstract class has two concrete subclasses:
+ * {@link RoutingConnectionProxy}: to cd in an MBeanServerConnection. {@link RoutingServerProxy}: to cd in an MBeanServer.
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ * The DO NOT USE THESE CLASSES DIRECTLY
+ This API is a Sun internal API and is subject to changes without notice.
+ The public API through wich these proprietary classes can be
+ invoked is located in
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ *
+ * This class is consulted by {@link javax.management.ObjectName} at
+ * serialization / deserialization time.
+ * The serialization or deserialization context is established by
+ * by the {@link SerialRewritingProcessor} defined in this package.
+ *
+ * These classes are Sun proprietary APIs, subject to change without
+ * notice. Do not use these classes directly.
+ * The public API to rewrite ObjectNames embedded in parameters is
+ * defined in {@link javax.management.namespace.JMXNamespaces}.
+ *
+ *
+ * This API is a Sun internal API and is subject to changes without notice.
+ * When entering a {@link javax.management.namespace
+ * namespace}, the {@code namespace} prefix is stripped from
+ * ObjectNames contained in input parameters. When leaving a
+ * {@code namespace},
+ * the {@code namespace} prefix is prepended to the ObjectNames contained in
+ * the result parameters returned from that {@code namespace}.
+ * Objects that need to perform these operations usually use a
+ * {@code RewritingProcessor} for that purpose. A default implementation of {@code RewritingProcessor} based on
+ * Java Object Serialization can be
+ * obtained from {@link #newRewritingProcessor newRewritingProcessor}.
+ *
+ * By default, the instances of {@code RewritingProcessor} returned by
+ * {@link #newRewritingProcessor newRewritingProcessor} will rewrite
+ * ObjectNames contained in instances of classes they don't know about by
+ * serializing and then deserializing such object instances. This will
+ * happen even if such instances don't - or can't contain ObjectNames,
+ * because the default implementation of {@code RewritingProcessor} will
+ * not be able to determine whether instances of such classes can/do contain
+ * instance of ObjectNames before serializing/deserializing them.
+ * If you are using custom classes that the default implementation of
+ * {@code RewritingProcessor} don't know about, it can be interesting to
+ * prevent an instance of {@code RewritingProcessor} to serialize/deserialize
+ * instances of such classes for nothing. In that case, you could customize
+ * the behavior of such a {@code RewritingProcessor} by wrapping it in a
+ * custom subclass of {@code RewritingProcessor} as shown below:
+ * Such a subclass may also provide an alternate way of rewriting
+ * custom subclasses for which rewriting is needed - for instance:
+ * initialize(outer,delegate)
+ * 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?
, standing for any one
- character, and *
, standing for any string of
- characters, including the empty string.
-
- @param str the string to match, as a character array.
- @param pat the pattern to match the string against, as a
- character array.
-
- @return true if and only if the string matches the pattern.
- */
- /* The algorithm is a classical one. We advance pointers in
- parallel through str and pat. If we encounter a star in pat,
- we remember its position and continue advancing. If at any
- stage we get a mismatch between str and pat, we look to see if
- there is a remembered star. If not, we fail. If so, we
- retreat pat to just past that star and str to the position
- after the last one we tried, and we let the match advance
- again.
-
- Even though there is only one remembered star position, the
- algorithm works when there are several stars in the pattern.
- When we encounter the second star, we forget the first one.
- This is OK, because if we get to the second star in A*B*C
- (where A etc are arbitrary strings), we have already seen AXB.
- We're therefore setting up a match of *C against the remainder
- of the string, which will match if that remainder looks like
- YC, so the whole string looks like AXBYC.
- */
- public static boolean wildmatch(char[] str, char[] pat) {
- int stri; // index in str
- int pati; // index in pat
- int starstri; // index for backtrack if "*" attempt fails
- int starpati; // index for backtrack if "*" attempt fails, +1
- final int strlen = str.length;
- final int patlen = pat.length;
-
- stri = pati = 0;
- starstri = starpati = -1;
-
- /* On each pass through this loop, we either advance pati,
- or we backtrack pati and advance starstri. Since starstri
- is only ever assigned from pati, the loop must terminate. */
- while (true) {
- if (pati < patlen) {
- final char patc = pat[pati];
- switch (patc) {
- case '?':
- if (stri == strlen)
- break;
- stri++;
- pati++;
- continue;
- case '*':
- pati++;
- starpati = pati;
- starstri = stri;
- continue;
- default:
- if (stri < strlen && str[stri] == patc) {
- stri++;
- pati++;
- continue;
- }
- break;
- }
- } else if (stri == strlen)
- return true;
-
- // Mismatched, can we backtrack to a "*"?
- if (starpati < 0 || starstri == strlen)
- return false;
-
- // Retry the match one position later in str
- pati = starpati;
- starstri++;
- stri = starstri;
- }
- }
-
private void addNewDomMoi(final DynamicMBean object,
final String dom,
final ObjectName name,
@@ -370,7 +289,7 @@
if (name.isPattern()) return null;
// Extract the domain name.
- String dom= name.getDomain().intern();
+ String dom = name.getDomain().intern();
// Default domain case
if (dom.length() == 0) {
@@ -480,7 +399,7 @@
name = Util.newObjectName(domain + name.toString());
// Do we have default domain ?
- if (dom == domain) {
+ if (dom == domain) { // ES: OK (dom & domain are interned)
to_default_domain = true;
dom = domain;
} else {
@@ -652,10 +571,9 @@
}
// Pattern matching in the domain name (*, ?)
- char[] dom2Match = name.getDomain().toCharArray();
+ final String dom2Match = name.getDomain();
for (String dom : domainTb.keySet()) {
- char[] theDom = dom.toCharArray();
- if (wildmatch(theDom, dom2Match)) {
+ if (Util.wildpathmatch(dom, dom2Match)) {
final Map?
,
+ standing for any one character,
+ and *
, standing for any string of
+ characters, including the empty string. For instance,
+ {@code wildmatch("sandwich","sa?d*ch",1,4,1,4)} will match
+ {@code "and"} against {@code "a?d"}.
+
+ @param str the string containing the sequence to match.
+ @param pat a string containing a pattern to match the sub string
+ against.
+ @param stri the index in the string at which matching should begin.
+ @param strend the index in the string at which the matching should
+ end.
+ @param pati the index in the pattern at which matching should begin.
+ @param patend the index in the pattern at which the matching should
+ end.
+
+ @return true if and only if the string matches the pattern.
+ */
+ /* The algorithm is a classical one. We advance pointers in
+ parallel through str and pat. If we encounter a star in pat,
+ we remember its position and continue advancing. If at any
+ stage we get a mismatch between str and pat, we look to see if
+ there is a remembered star. If not, we fail. If so, we
+ retreat pat to just past that star and str to the position
+ after the last one we tried, and we let the match advance
+ again.
+
+ Even though there is only one remembered star position, the
+ algorithm works when there are several stars in the pattern.
+ When we encounter the second star, we forget the first one.
+ This is OK, because if we get to the second star in A*B*C
+ (where A etc are arbitrary strings), we have already seen AXB.
+ We're therefore setting up a match of *C against the remainder
+ of the string, which will match if that remainder looks like
+ YC, so the whole string looks like AXBYC.
+ */
+ private static boolean wildmatch(final String str, final String pat,
+ int stri, final int strend, int pati, final int patend) {
+
+ // System.out.println("matching "+pat.substring(pati,patend)+
+ // " against "+str.substring(stri, strend));
+ int starstri; // index for backtrack if "*" attempt fails
+ int starpati; // index for backtrack if "*" attempt fails, +1
+
+ starstri = starpati = -1;
+
+ /* On each pass through this loop, we either advance pati,
+ or we backtrack pati and advance starstri. Since starstri
+ is only ever assigned from pati, the loop must terminate. */
+ while (true) {
+ if (pati < patend) {
+ final char patc = pat.charAt(pati);
+ switch (patc) {
+ case '?':
+ if (stri == strend)
+ break;
+ stri++;
+ pati++;
+ continue;
+ case '*':
+ pati++;
+ starpati = pati;
+ starstri = stri;
+ continue;
+ default:
+ if (stri < strend && str.charAt(stri) == patc) {
+ stri++;
+ pati++;
+ continue;
+ }
+ break;
+ }
+ } else if (stri == strend)
+ return true;
+
+ // Mismatched, can we backtrack to a "*"?
+ if (starpati < 0 || starstri == strend)
+ return false;
+
+ // Retry the match one position later in str
+ pati = starpati;
+ starstri++;
+ stri = starstri;
+ }
+ }
+
+ /** Match a string against a shell-style pattern. The only pattern
+ characters recognized are ?
, standing for any one
+ character, and *
, standing for any string of
+ characters, including the empty string.
+
+ @param str the string to match.
+ @param pat the pattern to match the string against.
+
+ @return true if and only if the string matches the pattern.
+ */
+ public static boolean wildmatch(String str, String pat) {
+ return wildmatch(str,pat,0,str.length(),0,pat.length());
+ }
+
+ /**
+ * Matches a string against a pattern, as a name space path.
+ * This is a special matching where * and ?? don't match //.
+ * The string is split in sub-strings separated by //, and the
+ * pattern is split in sub-patterns separated by //. Each sub-string
+ * is matched against its corresponding sub-pattern.
+ * so com.sun.jmx.namespace
packagecom.sun.jmx.namespace
package contains
+ sun specific implementation classes used to implement the
+ JMX namespaces.
+ javax.management.namespace
+ package.
+
+ * The {@code RewritingProcessor} allows a somewhat larger
+ * transformation in which part of a prefix {@link #newRewritingProcessor
+ * remove} can be replaced by another prefix {@link #newRewritingProcessor
+ * add}. The transformation described above correspond to the case where
+ * {@code remove} is the stripped {@link javax.management.namespace
+ * namespace} prefix (removed when entering the {@code namespace}) and
+ * {@code add} is the empty String {@code ""}.
+ *
+ * It is interesting to note that {@link
+ * javax.management.JMXNamespaces#narrowToNamespace narrowToNamespace}
+ * operations use the inverse transformation (that is, {@code remove} is
+ * the empty String {@code ""} and {@code add} is the {@link
+ * javax.management.namespace namespace} prefix).
+ *
+ * On a more general scale, {@link #rewriteInput rewriteInput} removes
+ * {@link #newRewritingProcessor remove} and the prepend {@link
+ * #newRewritingProcessor add}, and {@link #rewriteOutput rewriteOutput}
+ * does the opposite, removing {@link #newRewritingProcessor add}, and
+ * then adding {@link #newRewritingProcessor remove}.
+ *
+ * An implementation of {@code RewritingProcessor} should make sure that
+ * rewriteInput(rewriteOutput(x,clp),clp)
and
+ * rewriteOutput(rewriteInput(x,clp),clp)
always return
+ * {@code x} or an exact clone of {@code x}.
+ *
+ * public class MyRewritingProcessor extends RewritingProcessor {
+ * MyRewritingProcessor(String remove, String add) {
+ * this(RewritingProcessor.newRewritingProcessor(remove,add));
+ * }
+ * MyRewritingProcessor(RewritingProcessor delegate) {
+ * super(delegate);
+ * }
+ *
+ *
+ *
+ * public class MyRewritingProcessor extends RewritingProcessor {
+ * MyRewritingProcessor(String remove, String add) {
+ * this(RewritingProcessor.newRewritingProcessor(remove,add));
+ * }
+ * MyRewritingProcessor(RewritingProcessor delegate) {
+ * super(delegate);
+ * }
+ *
+ *
+ *
If your application only uses {@link javax.management.MXBean MXBeans}, + * or MBeans using simple types, and doesn't define any custom subclass of + * {@link javax.management.Notification}, you should never write such + * such {@code RewitingProcessor} implementations. + *
+ *+ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +public abstract class RewritingProcessor { + /** + * A logger for this class. + **/ + private final RewritingProcessor delegate; + + /** + * Creates a new instance of RewritingProcessor. + *This is equivalent to calling {@link + * #RewritingProcessor(RewritingProcessor) RewritingProcessor(null)}. + *
+ **/ + protected RewritingProcessor() { + this(null); + } + + /** + * Creates a new instance of RewritingProcessor, with a delegate. + * @param delegate a {@code RewritingProcessor} to which all the + * calls will be delegated. When implementing a subclass + * of {@code RewritingProcessor}, calling {@link + * #rewriteInput super.rewriteInput} will invoke + * {@code delegate.rewriteInput} and calling {@link + * #rewriteOutput super.rewriteOutput} will invoke + * {@code delegate.rewriteOutput}. + * + **/ + protected RewritingProcessor(RewritingProcessor delegate) { + this.delegate = delegate; + } + + /** + * Rewrites ObjectNames when {@link RewritingProcessor leaving} a {@link + * javax.management.namespace namespace}. + *+ * Returns {@code obj}, if it is known that {@code obj} doesn't contain + * any ObjectName, or a new copied instance of {@code obj} in which + * ObjectNames (if any) will have been rewritten, if {@code obj} contains + * ObjectNames, or if it is not known whether {@code obj} contains + * ObjectNames or not. + *
+ *+ * The default implementation of this method is as follows: if the + * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code + * null}, throws an {@link IllegalArgumentException}. Otherwise, + * returns {@code delegate.rewriteOutput(obj)}. + *
+ *This behavior can be overridden by subclasses as shown in this + * class {@link RewritingProcessor description}. + *
+ * @param obj The result to be rewritten if needed. + * + * @return {@code obj}, or a clone of {@code obj} in which ObjectNames + * have been rewritten. See this class {@link RewritingProcessor + * description} for more details. + * @throws IllegalArgumentException if this implementation does not know + * how to rewrite the object. + **/ + public+ * Returns {@code obj}, if it is known that {@code obj} doesn't contain + * any ObjectName, or a new copied instance of {@code obj} in which + * ObjectNames (if any) will have been rewritten, if {@code obj} contains + * ObjectNames, or if it is not known whether {@code obj} contains + * ObjectNames or not. + *
+ *+ * The default implementation of this method is as follows: if the + * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code + * null}, throws an {@link IllegalArgumentException}. Otherwise, + * returns {@code delegate.rewriteInput(obj)}. + *
+ *This behavior can be overridden by subclasses as shown in this + * class {@link RewritingProcessor description}. + *
+ * @param obj The result to be rewritten if needed. + * @return {@code obj}, or a clone of {@code obj} in which ObjectNames + * have been rewritten. See this class {@link RewritingProcessor + * description} for more details. + * @throws IllegalArgumentException if this implementation does not know + * how to rewrite the object. + **/ + public+ * The default implementation of this method is as follows: if the + * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code + * null}, throws an {@link IllegalArgumentException}. Otherwise, + * returns {@code delegate.toSourceContext(targetName)}. + *
+ *This behavior can be overridden by subclasses as shown in this + * class {@link RewritingProcessor description}. + *
+ * @param targetName The routing target ObjectName to translate. + * @return The ObjectName translated to the source context. + * @throws IllegalArgumentException if this implementation does not know + * how to rewrite the object. + **/ + public ObjectName toSourceContext(ObjectName targetName) { + if (delegate != null) + return delegate.toSourceContext(targetName); + throw new IllegalArgumentException("can't rewrite targetName: "+ + " no delegate."); + } + + /** + * Translate an ObjectName returned from the source context into + * the target (calling) context when {@link RewritingProcessor leaving} a + * {@link javax.management.namespace namespace}. + *+ * The default implementation of this method is as follows: if the + * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code + * null}, throws an {@link IllegalArgumentException}. Otherwise, + * returns {@code delegate.toTargetContext(sourceName)}. + *
+ *This behavior can be overridden by subclasses as shown in this + * class {@link RewritingProcessor description}. + *
+ * @param sourceName The routing source ObjectName to translate to the + * target context. + * @return The ObjectName translated to the target context. + * @throws IllegalArgumentException if this implementation does not know + * how to rewrite the object. + **/ + public ObjectName toTargetContext(ObjectName sourceName) { + if (delegate != null) + return delegate.toTargetContext(sourceName); + throw new IllegalArgumentException("can't rewrite sourceName: "+ + " no delegate."); + } + + /** + * Translate an ObjectInstance returned from the source context into + * the target (calling) context when {@link RewritingProcessor leaving} a + * {@link javax.management.namespace namespace}. + *+ * The default implementation of this method is as follows: if the + * {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code + * null}, throws an {@link IllegalArgumentException}. Otherwise, + * returns {@code delegate.toTargetContext(sourceMoi)}. + *
+ *This behavior can be overridden by subclasses as shown in this + * class {@link RewritingProcessor description}. + *
+ * @param sourceMoi The routing source ObjectInstance to translate. + * @return The ObjectInstance translated to the target context. + * @throws IllegalArgumentException if this implementation does not know + * how to rewrite the object. + **/ + public ObjectInstance toTargetContext(ObjectInstance sourceMoi) { + if (delegate != null) + return delegate.toTargetContext(sourceMoi); + throw new IllegalArgumentException("can't rewrite sourceName: "+ + " no delegate."); + } + + /** + * Creates a new default instance of {@link RewritingProcessor}. + * @param remove The prefix to remove from {@link ObjectName ObjectNames} + * when {@link RewritingProcessor entering} the {@link + * javax.management.namespace namespace}. + * @param add The prefix to add to {@link ObjectName ObjectNames} + * when {@link RewritingProcessor entering} the {@link + * javax.management.namespace namespace} (this is performed + * after having removed the {@code remove} prefix. + * @return A new {@link RewritingProcessor} processor object that will + * perform the requested operation, using Java serialization if + * necessary. + **/ + public static RewritingProcessor newRewritingProcessor(String remove, + String add) { + return new DefaultRewritingProcessor(remove,add); + } + +} diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java Thu Sep 04 14:55:12 2008 -0700 @@ -0,0 +1,74 @@ +/* + * 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.namespace.serial; + +import com.sun.jmx.namespace.ObjectNameRouter; + + +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +/** + * Class RoutingOnlyProcessor. A RewritingProcessor that uses + * Java Serialization to rewrite ObjectNames contained in + * input and results... + * + *+ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +class RoutingOnlyProcessor extends RewritingProcessor { + + final ObjectNameRouter router; + + public RoutingOnlyProcessor(String targetDirName) { + this(targetDirName,null); + } + + /** Creates a new instance of RoutingOnlyProcessor */ + public RoutingOnlyProcessor(final String remove, final String add) { + super(new IdentityProcessor()); + if (remove == null || add == null) + throw new IllegalArgumentException("Null argument"); + router = new ObjectNameRouter(remove,add); + } + + @Override + public final ObjectName toTargetContext(ObjectName sourceName) { + return router.toTargetContext(sourceName,false); + } + + @Override + public final ObjectName toSourceContext(ObjectName targetName) { + return router.toSourceContext(targetName,false); + } + + @Override + public final ObjectInstance toTargetContext(ObjectInstance sourceMoi) { + return router.toTargetContext(sourceMoi,false); + } +} diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java Thu Sep 04 14:55:12 2008 -0700 @@ -0,0 +1,172 @@ +/* + * 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.namespace.serial; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; +import java.io.OutputStream; +import java.util.LinkedList; +import java.util.Queue; + +import javax.management.ObjectName; + +/** + * Class SerialRewritingProcessor. A RewritingProcessor that uses + * Java Serialization to rewrite ObjectNames contained in + * input & results... + *+ * This API is a Sun internal API and is subject to changes without notice. + *
+ * @since 1.7 + */ +class SerialRewritingProcessor extends RewritingProcessor { + + + private static class CloneOutput extends ObjectOutputStream { + Queuecom.sun.jmx.namespace.serial
packageThe com.sun.jmx.namespace.serial
package contains
+ sun specific implementation classes used to switch namespace
+ prefixes in ObjectName during serialization.
+
NEVER USE THESE CLASSES DIRECTLY
++ This API is a Sun internal API and is subject to changes without notice. +
+The public API through which these proprietary classes can be invoked is
+ located in javax.management.namespace.JMXNamespaces
+
In the {@link java.nio.channels channels} package, the {@link
+ * java.nio.channels.NetworkChannel} interface defines the {@link
+ * java.nio.channels.NetworkChannel#setOption(SocketOption,Object) setOption}
+ * and {@link java.nio.channels.NetworkChannel#getOption(SocketOption) getOption}
+ * methods to set and query the channel's socket options.
+ *
+ * @param The {@link SocketOption#name name} of each socket option defined by this
+ * class is its field name.
+ *
+ * In this release, the socket options defined here are used by {@link
+ * java.nio.channels.NetworkChannel network} channels in the {@link
+ * java.nio.channels channels} package.
+ *
+ * @since 1.7
+ */
+
+public final class StandardSocketOption {
+ private StandardSocketOption() { }
+
+ // -- SOL_SOCKET --
+
+ /**
+ * Allow transmission of broadcast datagrams.
+ *
+ * The value of this socket option is a {@code Boolean} that represents
+ * whether the option is enabled or disabled. The option is specific to
+ * datagram-oriented sockets sending to {@link java.net.Inet4Address IPv4}
+ * broadcast addresses. When the socket option is enabled then the socket
+ * can be used to send broadcast datagrams.
+ *
+ * The initial value of this socket option is {@code FALSE}. The socket
+ * option may be enabled or disabled at any time. Some operating systems may
+ * require that the Java virtual machine be started with implementation
+ * specific privileges to enable this option or send broadcast datagrams.
+ *
+ * @see RFC 929:
+ * Broadcasting Internet Datagrams
+ */
+ public static final SocketOption The value of this socket option is a {@code Boolean} that represents
+ * whether the option is enabled or disabled. When the {@code SO_KEEPALIVE}
+ * option is enabled the operating system may use a keep-alive
+ * mechanism to periodically probe the other end of a connection when the
+ * connection is otherwise idle. The exact semantics of the keep alive
+ * mechanism is system dependent and therefore unspecified.
+ *
+ * The initial value of this socket option is {@code FALSE}. The socket
+ * option may be enabled or disabled at any time.
+ *
+ * @see RFC 1122
+ * Requirements for Internet Hosts -- Communication Layers
+ */
+ public static final SocketOption The value of this socket option is an {@code Integer} that is the
+ * size of the socket send buffer in bytes. The socket send buffer is an
+ * output buffer used by the networking implementation. It may need to be
+ * increased for high-volume connections. The value of the socket option is
+ * a hint to the implementation to size the buffer and the actual
+ * size may differ. The socket option can be queried to retrieve the actual
+ * size.
+ *
+ * For datagram-oriented sockets, the size of the send buffer may limit
+ * the size of the datagrams that may be sent by the socket. Whether
+ * datagrams larger than the buffer size are sent or discarded is system
+ * dependent.
+ *
+ * The initial/default size of the socket send buffer and the range of
+ * allowable values is system dependent although a negative size is not
+ * allowed. An attempt to set the socket send buffer to larger than its
+ * maximum size causes it to be set to its maximum size.
+ *
+ * An implementation allows this socket option to be set before the
+ * socket is bound or connected. Whether an implementation allows the
+ * socket send buffer to be changed after the socket is bound is system
+ * dependent.
+ */
+ public static final SocketOption The value of this socket option is an {@code Integer} that is the
+ * size of the socket receive buffer in bytes. The socket receive buffer is
+ * an input buffer used by the networking implementation. It may need to be
+ * increased for high-volume connections or decreased to limit the possible
+ * backlog of incoming data. The value of the socket option is a
+ * hint to the implementation to size the buffer and the actual
+ * size may differ.
+ *
+ * For datagram-oriented sockets, the size of the receive buffer may
+ * limit the size of the datagrams that can be received. Whether datagrams
+ * larger than the buffer size can be received is system dependent.
+ * Increasing the socket receive buffer may be important for cases where
+ * datagrams arrive in bursts faster than they can be processed.
+ *
+ * In the case of stream-oriented sockets and the TCP/IP protocol, the
+ * size of the socket receive buffer may be used when advertising the size
+ * of the TCP receive window to the remote peer.
+ *
+ * The initial/default size of the socket receive buffer and the range
+ * of allowable values is system dependent although a negative size is not
+ * allowed. An attempt to set the socket receive buffer to larger than its
+ * maximum size causes it to be set to its maximum size.
+ *
+ * An implementation allows this socket option to be set before the
+ * socket is bound or connected. Whether an implementation allows the
+ * socket receive buffer to be changed after the socket is bound is system
+ * dependent.
+ *
+ * @see RFC 1323: TCP
+ * Extensions for High Performance
+ */
+ public static final SocketOption The value of this socket option is a {@code Boolean} that represents
+ * whether the option is enabled or disabled. The exact semantics of this
+ * socket option are socket type and system dependent.
+ *
+ * In the case of stream-oriented sockets, this socket option will
+ * usually determine whether the socket can be bound to a socket address
+ * when a previous connection involving that socket address is in the
+ * TIME_WAIT state. On implementations where the semantics differ,
+ * and the socket option is not required to be enabled in order to bind the
+ * socket when a previous connection is in this state, then the
+ * implementation may choose to ignore this option.
+ *
+ * For datagram-oriented sockets the socket option is used to allow
+ * multiple programs bind to the same address. This option should be enabled
+ * when the socket is to be used for Internet Protocol (IP) multicasting.
+ *
+ * An implementation allows this socket option to be set before the
+ * socket is bound or connected. Changing the value of this socket option
+ * after the socket is bound has no effect. The default value of this
+ * socket option is system dependent.
+ *
+ * @see RFC 793: Transmission
+ * Control Protocol
+ */
+ public static final SocketOption The value of this socket option is an {@code Integer} that controls
+ * the action taken when unsent data is queued on the socket and a method
+ * to close the socket is invoked. If the value of the socket option is zero
+ * or greater, then it represents a timeout value, in seconds, known as the
+ * linger interval. The linger interval is the timeout for the
+ * {@code close} method to block while the operating system attempts to
+ * transmit the unsent data or it decides that it is unable to transmit the
+ * data. If the value of the socket option is less than zero then the option
+ * is disabled. In that case the {@code close} method does not wait until
+ * unsent data is transmitted; if possible the operating system will transmit
+ * any unsent data before the connection is closed.
+ *
+ * This socket option is intended for use with sockets that are configured
+ * in {@link java.nio.channels.SelectableChannel#isBlocking() blocking} mode
+ * only. The behavior of the {@code close} method when this option is
+ * enabled on a non-blocking socket is not defined.
+ *
+ * The initial value of this socket option is a negative value, meaning
+ * that the option is disabled. The option may be enabled, or the linger
+ * interval changed, at any time. The maximum value of the linger interval
+ * is system dependent. Setting the linger interval to a value that is
+ * greater than its maximum value causes the linger interval to be set to
+ * its maximum value.
+ */
+ public static final SocketOption The value of this socket option is an {@code Integer}, the least
+ * significant 8 bits of which represents the value of the ToS octet in IP
+ * packets sent by sockets to an {@link StandardProtocolFamily#INET IPv4}
+ * socket. The interpretation of the ToS octet is network specific and
+ * is not defined by this class. Further information on the ToS octet can be
+ * found in RFC 1349
+ * and RFC 2474. The
+ * value of the socket option is a hint. An implementation may
+ * ignore the value, or ignore specific values.
+ *
+ * The initial/default value of the TOS field in the ToS octet is
+ * implementation specific but will typically be {@code 0}. For
+ * datagram-oriented sockets the option may be configured at any time after
+ * the socket has been bound. The new value of the octet is used when sending
+ * subsequent datagrams. It is system dependent whether this option can be
+ * queried or changed prior to binding the socket.
+ *
+ * The behavior of this socket option on a stream-oriented socket, or an
+ * {@link StandardProtocolFamily#INET6 IPv6} socket, is not defined in this
+ * release.
+ */
+ public static final SocketOption The value of this socket option is a {@link NetworkInterface} that
+ * represents the outgoing interface for multicast datagrams sent by the
+ * datagram-oriented socket. For {@link StandardProtocolFamily#INET6 IPv6}
+ * sockets then it is system dependent whether setting this option also
+ * sets the outgoing interface for multlicast datagrams sent to IPv4
+ * addresses.
+ *
+ * The initial/default value of this socket option may be {@code null}
+ * to indicate that outgoing interface will be selected by the operating
+ * system, typically based on the network routing tables. An implementation
+ * allows this socket option to be set after the socket is bound. Whether
+ * the socket option can be queried or changed prior to binding the socket
+ * is system dependent.
+ *
+ * @see java.nio.channels.MulticastChannel
+ */
+ public static final SocketOption The value of this socket option is an {@code Integer} in the range
+ * 0 <= value <= 255. It is used to control
+ * the scope of multicast datagrams sent by the datagram-oriented socket.
+ * In the case of an {@link StandardProtocolFamily#INET IPv4} socket
+ * the option is the time-to-live (TTL) on multicast datagrams sent by the
+ * socket. Datagrams with a TTL of zero are not transmitted on the network
+ * but may be delivered locally. In the case of an {@link
+ * StandardProtocolFamily#INET6 IPv6} socket the option is the
+ * hop limit which is number of hops that the datagram can
+ * pass through before expiring on the network. For IPv6 sockets it is
+ * system dependent whether the option also sets the time-to-live
+ * on multicast datagrams sent to IPv4 addresses.
+ *
+ * The initial/default value of the time-to-live setting is typically
+ * {@code 1}. An implementation allows this socket option to be set after
+ * the socket is bound. Whether the socket option can be queried or changed
+ * prior to binding the socket is system dependent.
+ *
+ * @see java.nio.channels.MulticastChannel
+ */
+ public static final SocketOption The value of this socket option is a {@code Boolean} that controls
+ * the loopback of multicast datagrams. The value of the socket
+ * option represents if the option is enabled or disabled.
+ *
+ * The exact semantics of this socket options are system dependent.
+ * In particular, it is system dependent whether the loopback applies to
+ * multicast datagrams sent from the socket or received by the socket.
+ * For {@link StandardProtocolFamily#INET6 IPv6} sockets then it is
+ * system dependent whether the option also applies to multicast datagrams
+ * sent to IPv4 addresses.
+ *
+ * The initial/default value of this socket option is {@code TRUE}. An
+ * implementation allows this socket option to be set after the socket is
+ * bound. Whether the socket option can be queried or changed prior to
+ * binding the socket is system dependent.
+ *
+ * @see java.nio.channels.MulticastChannel
+ */
+ public static final SocketOption The value of this socket option is a {@code Boolean} that represents
+ * whether the option is enabled or disabled. The socket option is specific to
+ * stream-oriented sockets using the TCP/IP protocol. TCP/IP uses an algorithm
+ * known as The Nagle Algorithm to coalesce short segments and
+ * improve network efficiency.
+ *
+ * The default value of this socket option is {@code FALSE}. The
+ * socket option should only be enabled in cases where it is known that the
+ * coalescing impacts performance. The socket option may be enabled at any
+ * time. In other words, the Nagle Algorithm can be disabled. Once the option
+ * is enabled, it is system dependent whether it can be subsequently
+ * disabled. In that case, invoking the {@code setOption} method to disable
+ * the option has no effect.
+ *
+ * @see RFC 1122:
+ * Requirements for Internet Hosts -- Communication Layers
+ */
+ public static final SocketOption Datagram channels are not a complete abstraction of network datagram
- * sockets. Binding and the manipulation of socket options must be done
- * through an associated {@link java.net.DatagramSocket} object obtained by
- * invoking the {@link #socket() socket} method. It is not possible to create
- * a channel for an arbitrary, pre-existing datagram socket, nor is it possible
- * to specify the {@link java.net.DatagramSocketImpl} object to be used by a
- * datagram socket associated with a datagram channel.
- *
- * A datagram channel is created by invoking the {@link #open open} method
- * of this class. A newly-created datagram channel is open but not connected.
- * A datagram channel need not be connected in order for the {@link #send send}
- * and {@link #receive receive} methods to be used. A datagram channel may be
+ * A datagram channel is created by invoking one of the {@link #open open} methods
+ * of this class. It is not possible to create a channel for an arbitrary,
+ * pre-existing datagram socket. A newly-created datagram channel is open but not
+ * connected. A datagram channel need not be connected in order for the {@link #send
+ * send} and {@link #receive receive} methods to be used. A datagram channel may be
* connected, by invoking its {@link #connect connect} method, in order to
* avoid the overhead of the security checks are otherwise performed as part of
* every send and receive operation. A datagram channel must be connected in
@@ -59,11 +52,57 @@
* disconnected or closed. Whether or not a datagram channel is connected may
* be determined by invoking its {@link #isConnected isConnected} method.
*
+ * Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. Datagram channels support the following options:
+ * Datagram channels are safe for use by multiple concurrent threads. They
* support concurrent reading and writing, though at most one thread may be
* reading and at most one thread may be writing at any given time. The {@link ProtocolFamily ProtocolFamily} of the channel's socket
+ * is platform (and possibly configuration) dependent and therefore unspecified.
+ * The {@link #open(ProtocolFamily) open} allows the protocol family to be
+ * selected when opening a datagram channel, and should be used to open
+ * datagram channels that are intended for Internet Protocol multicasting.
*
* @return A new datagram channel
*
@@ -100,6 +145,39 @@
}
/**
+ * Opens a datagram channel.
+ *
+ * The {@code family} parameter is used to specify the {@link
+ * ProtocolFamily}. If the datagram channel is to be used for IP multicasing
+ * then this should correspond to the address type of the multicast groups
+ * that this channel will join.
+ *
+ * The new channel is created by invoking the {@link
+ * java.nio.channels.spi.SelectorProvider#openDatagramChannel(ProtocolFamily)
+ * openDatagramChannel} method of the system-wide default {@link
+ * java.nio.channels.spi.SelectorProvider} object. The channel will not be
+ * connected.
+ *
+ * @param family
+ * The protocol family
+ *
+ * @return A new datagram channel
+ *
+ * @throws UnsupportedOperationException
+ * If the specified protocol family is not supported. For example,
+ * suppose the parameter is specified as {@link
+ * java.net.StandardProtocolFamily#INET6 StandardProtocolFamily.INET6}
+ * but IPv6 is not enabled on the platform.
+ * @throws IOException
+ * If an I/O error occurs
+ *
+ * @since 1.7
+ */
+ public static DatagramChannel open(ProtocolFamily family) throws IOException {
+ return SelectorProvider.provider().openDatagramChannel(family);
+ }
+
+ /**
* Returns an operation set identifying this channel's supported
* operations.
*
@@ -118,6 +196,32 @@
// -- Socket-specific operations --
/**
+ * @throws AlreadyBoundException {@inheritDoc}
+ * @throws UnsupportedAddressTypeException {@inheritDoc}
+ * @throws ClosedChannelException {@inheritDoc}
+ * @throws IOException {@inheritDoc}
+ * @throws SecurityException
+ * If a security manager has been installed and its {@link
+ * SecurityManager#checkListen checkListen} method denies the
+ * operation
+ *
+ * @since 1.7
+ */
+ public abstract DatagramChannel bind(SocketAddress local)
+ throws IOException;
+
+ /**
+ * @throws IllegalArgumentException {@inheritDoc}
+ * @throws ClosedChannelException {@inheritDoc}
+ * @throws IOException {@inheritDoc}
+ *
+ * @since 1.7
+ */
+ public abstract The returned object will not declare any public methods that are not
@@ -128,10 +232,10 @@
public abstract DatagramSocket socket();
/**
- * Tells whether or not this channel's socket is connected. If a datagram is immediately available, or if this channel is in
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/java/nio/channels/MembershipKey.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/channels/MembershipKey.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2007-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 java.nio.channels;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * A token representing the membership of an Internet Protocol (IP) multicast
+ * group.
+ *
+ * A membership key may represent a membership to receive all datagrams sent
+ * to the group, or it may be source-specific, meaning that it
+ * represents a membership that receives only datagrams from a specific source
+ * address. Whether or not a membership key is source-specific may be determined
+ * by invoking its {@link #getSourceAddress() getSourceAddress} method.
+ *
+ * A membership key is valid upon creation and remains valid until the
+ * membership is dropped by invoking the {@link #drop() drop} method, or
+ * the channel is closed. The validity of the membership key may be tested
+ * by invoking its {@link #isValid() isValid} method.
+ *
+ * Where a membership key is not source-specific and the underlying operation
+ * system supports source filtering, then the {@link #block block} and {@link
+ * #unblock unblock} methods can be used to block or unblock multicast datagrams
+ * from particular source addresses.
+ *
+ * @see MulticastChannel
+ *
+ * @since 1.7
+ */
+public abstract class MembershipKey {
+
+ /**
+ * Initializes a new instance of this class.
+ */
+ protected MembershipKey() {
+ }
+
+ /**
+ * Tells whether or not this membership is valid.
+ *
+ * A multicast group membership is valid upon creation and remains
+ * valid until the membership is dropped by invoking the {@link #drop() drop}
+ * method, or the channel is closed.
+ *
+ * @return {@code true} if this membership key is valid, {@code false}
+ * otherwise
+ */
+ public abstract boolean isValid();
+
+ /**
+ * Drop membership.
+ *
+ * If the membership key represents a membership to receive all datagrams
+ * then the membership is dropped and the channel will no longer receive any
+ * datagrams sent to the group. If the membership key is source-specific
+ * then the channel will no longer receive datagrams sent to the group from
+ * that source address.
+ *
+ * After membership is dropped it may still be possible to receive
+ * datagrams sent to the group. This can arise when datagrams are waiting to
+ * be received in the socket's receive buffer. After membership is dropped
+ * then the channel may {@link MulticastChannel#join join} the group again
+ * in which case a new membership key is returned.
+ *
+ * Upon return, this membership object will be {@link #isValid() invalid}.
+ * If the multicast group membership is already invalid then invoking this
+ * method has no effect. Once a multicast group membership is invalid,
+ * it remains invalid forever.
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public abstract void drop() throws IOException;
+
+ /**
+ * Block multicast datagrams from the given source address.
+ *
+ * If this membership key is not source-specific, and the underlying
+ * operating system supports source filtering, then this method blocks
+ * multicast datagrams from the given source address. If the given source
+ * address is already blocked then this method has no effect.
+ * After a source address is blocked it may still be possible to receive
+ * datagams from that source. This can arise when datagrams are waiting to
+ * be received in the socket's receive buffer.
+ *
+ * @param source
+ * The source address to block
+ *
+ * @return This membership key
+ *
+ * @throws IllegalArgumentException
+ * If the {@code source} parameter is not a unicast address or
+ * is not the same address type as the multicast group
+ * @throws IllegalStateException
+ * If this membership key is source-specific or is no longer valid
+ * @throws UnsupportedOperationException
+ * If the underlying operating system does not support source
+ * filtering
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public abstract MembershipKey block(InetAddress source) throws IOException;
+
+ /**
+ * Unblock multicast datagrams from the given source address that was
+ * previously blocked using the {@link #block(InetAddress) block} method.
+ *
+ * @param source
+ * The source address to unblock
+ *
+ * @return This membership key
+ *
+ * @throws IllegalStateException
+ * If the given source address is not currently blocked or the
+ * membership key is no longer valid
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public abstract MembershipKey unblock(InetAddress source) throws IOException;
+
+ /**
+ * Returns the channel for which this membership key was created. This
+ * method will continue to return the channel even after the membership
+ * becomes {@link #isValid invalid}.
+ *
+ * @return the channel
+ */
+ public abstract MulticastChannel getChannel();
+
+ /**
+ * Returns the multicast group for which this membership key was created.
+ * This method will continue to return the group even after the membership
+ * becomes {@link #isValid invalid}.
+ *
+ * @return the multicast group
+ */
+ public abstract InetAddress getGroup();
+
+ /**
+ * Returns the network interface for which this membership key was created.
+ * This method will continue to return the network interface even after the
+ * membership becomes {@link #isValid invalid}.
+ *
+ * @return the network interface
+ */
+ public abstract NetworkInterface getNetworkInterface();
+
+ /**
+ * Returns the source address if this membership key is source-specific,
+ * or {@code null} if this membership is not source-specific.
+ *
+ * @return The source address if this membership key is source-specific,
+ * otherwise {@code null}
+ */
+ public abstract InetAddress getSourceAddress();
+}
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/java/nio/channels/MulticastChannel.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/channels/MulticastChannel.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2007-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 java.nio.channels;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.io.IOException;
+import java.net.ProtocolFamily; // javadoc
+import java.net.StandardProtocolFamily; // javadoc
+import java.net.StandardSocketOption; // javadoc
+
+/**
+ * A network channel that supports Internet Protocol (IP) multicasting.
+ *
+ * IP multicasting is the transmission of IP datagrams to members of
+ * a group that is zero or more hosts identified by a single destination
+ * address.
+ *
+ * In the case of a channel to an {@link StandardProtocolFamily#INET IPv4} socket,
+ * the underlying operating system supports
+ * RFC 2236: Internet Group Management Protocol, Version 2 (IGMPv2).
+ * It may optionally support source filtering as specified by RFC 3376: Internet Group
+ * Management Protocol, Version 3 (IGMPv3).
+ * For channels to an {@link StandardProtocolFamily#INET6 IPv6} socket, the equivalent
+ * standards are RFC 2710:
+ * Multicast Listener Discovery (MLD) for IPv6 and RFC 3810: Multicast Listener
+ * Discovery Version 2 (MLDv2) for IPv6.
+ *
+ * The {@link #join(InetAddress,NetworkInterface)} method is used to
+ * join a group and receive all multicast datagrams sent to the group. A channel
+ * may join several multicast groups and may join the same group on several
+ * {@link NetworkInterface interfaces}. Membership is dropped by invoking the {@link
+ * MembershipKey#drop drop} method on the returned {@link MembershipKey}. If the
+ * underlying platform supports source filtering then the {@link MembershipKey#block
+ * block} and {@link MembershipKey#unblock unblock} methods can be used to block or
+ * unblock multicast datagrams from particular source addresses.
+ *
+ * The {@link #join(InetAddress,NetworkInterface,InetAddress)} method
+ * is used to begin receiving datagrams sent to a group whose source address matches
+ * a given source address. This method throws {@link UnsupportedOperationException}
+ * if the underlying platform does not support source filtering. Membership is
+ * cumulative and this method may be invoked again with the same group
+ * and interface to allow receiving datagrams from other source addresses. The
+ * method returns a {@link MembershipKey} that represents membership to receive
+ * datagrams from the given source address. Invoking the key's {@link
+ * MembershipKey#drop drop} method drops membership so that datagrams from the
+ * source address can no longer be received.
+ *
+ * The creation of the channel should specify the {@link ProtocolFamily}
+ * that corresponds to the address type of the multicast groups that the channel
+ * will join. There is no guarantee that a channel to a socket in one protocol
+ * family can join and receive multicast datagrams when the address of the
+ * multicast group corresponds to another protocol family. For example, it is
+ * implementation specific if a channel to an {@link StandardProtocolFamily#INET6 IPv6}
+ * socket can join an {@link StandardProtocolFamily#INET IPv4} multicast group and receive
+ * multicast datagrams sent to the group. The channel's socket should be bound to the {@link
+ * InetAddress#isAnyLocalAddress wildcard} address. If the socket is bound to
+ * a specific address, rather than the wildcard address then it is implementation
+ * specific if multicast datagrams are received by the socket. The {@link StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} option should be
+ * enabled prior to {@link NetworkChannel#bind binding} the socket. This is
+ * required to allow multiple members of the group to bind to the same
+ * address. Usage Example:
+ * If this channel is currently a member of the group on the given
+ * interface to receive all datagrams then the membership key, representing
+ * that membership, is returned. Otherwise this channel joins the group and
+ * the resulting new membership key is returned. The resulting membership key
+ * is not {@link MembershipKey#getSourceAddress source-specific}.
+ *
+ * A multicast channel may join several multicast groups, including
+ * the same group on more than one interface. An implementation may impose a
+ * limit on the number of groups that may be joined at the same time.
+ *
+ * @param group
+ * The multicast address to join
+ * @param interf
+ * The network interface on which to join the group
+ *
+ * @return The membership key
+ *
+ * @throws IllegalArgumentException
+ * If the group parameter is not a {@link InetAddress#isMulticastAddress
+ * multicast} address, or the group parameter is an address type
+ * that is not supported by this channel
+ * @throws IllegalStateException
+ * If the channel already has source-specific membership of the
+ * group on the interface
+ * @throws ClosedChannelException
+ * If this channel is closed
+ * @throws IOException
+ * If an I/O error occurs
+ * @throws SecurityException
+ * If a security manager is set, and its
+ * {@link SecurityManager#checkMulticast(InetAddress) checkMulticast}
+ * method denies access to the multiast group
+ */
+ MembershipKey join(InetAddress group, NetworkInterface interf)
+ throws IOException;
+
+ /**
+ * Joins a multicast group to begin receiving datagrams sent to the group
+ * from a given source address.
+ *
+ * If this channel is currently a member of the group on the given
+ * interface to receive datagrams from the given source address then the
+ * membership key, representing that membership, is returned. Otherwise this
+ * channel joins the group and the resulting new membership key is returned.
+ * The resulting membership key is {@link MembershipKey#getSourceAddress
+ * source-specific}.
+ *
+ * Membership is cumulative and this method may be invoked
+ * again with the same group and interface to allow receiving datagrams sent
+ * by other source addresses to the group.
+ *
+ * @param group
+ * The multicast address to join
+ * @param interf
+ * The network interface on which to join the group
+ * @param source
+ * The source address
+ *
+ * @return The membership key
+ *
+ * @throws IllegalArgumentException
+ * If the group parameter is not a {@link
+ * InetAddress#isMulticastAddress multicast} address, the
+ * source parameter is not a unicast address, the group
+ * parameter is an address type that is not supported by this channel,
+ * or the source parameter is not the same address type as the group
+ * @throws IllegalStateException
+ * If the channel is currently a member of the group on the given
+ * interface to receive all datagrams
+ * @throws UnsupportedOperationException
+ * If the underlying operation system does not support source filtering
+ * @throws ClosedChannelException
+ * If this channel is closed
+ * @throws IOException
+ * If an I/O error occurs
+ * @throws SecurityException
+ * If a security manager is set, and its
+ * {@link SecurityManager#checkMulticast(InetAddress) checkMulticast}
+ * method denies access to the multiast group
+ */
+ MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source)
+ throws IOException;
+}
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/java/nio/channels/NetworkChannel.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/channels/NetworkChannel.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2007-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 java.nio.channels;
+
+import java.net.SocketOption;
+import java.net.SocketAddress;
+import java.util.Set;
+import java.io.IOException;
+
+/**
+ * A channel to a network socket.
+ *
+ * A channel that implements this interface is a channel to a network
+ * socket. The {@link #bind(SocketAddress) bind} method is used to bind the
+ * socket to a local {@link SocketAddress address}, the {@link #getLocalAddress()
+ * getLocalAddress} method returns the address that the socket is bound to, and
+ * the {@link #setOption(SocketOption,Object) setOption} and {@link
+ * #getOption(SocketOption) getOption} methods are used to set and query socket
+ * options. An implementation of this interface should specify the socket options
+ * that it supports.
+ *
+ * The {@link #bind bind} and {@link #setOption setOption} methods that do
+ * not otherwise have a value to return are specified to return the network
+ * channel upon which they are invoked. This allows method invocations to be
+ * chained. Implementations of this interface should specialize the return type
+ * so that method invocations on the implementation class can be chained.
+ *
+ * @since 1.7
+ */
+
+public interface NetworkChannel
+ extends Channel
+{
+ /**
+ * Binds the channel's socket to a local address.
+ *
+ * This method is used to establish an association between the socket and
+ * a local address. Once an association is established then the socket remains
+ * bound until the channel is closed. If the {@code local} parameter has the
+ * value {@code null} then the socket will be bound to an address that is
+ * assigned automatically.
+ *
+ * @param local
+ * The address to bind the socket, or {@code null} to bind the socket
+ * to an automatically assigned socket address
+ *
+ * @return This channel
+ *
+ * @throws AlreadyBoundException
+ * If the socket is already bound
+ * @throws UnsupportedAddressTypeException
+ * If the type of the given address is not supported
+ * @throws ClosedChannelException
+ * If the channel is closed
+ * @throws IOException
+ * If some other I/O error occurs
+ * @throws SecurityException
+ * If a security manager is installed and it denies an unspecified
+ * permission. An implementation of this interface should specify
+ * any required permissions.
+ *
+ * @see #getLocalAddress
+ */
+ NetworkChannel bind(SocketAddress local) throws IOException;
+
+ /**
+ * Returns the socket address that this channel's socket is bound to, or
+ * {@code null} if the socket is not bound.
+ *
+ * Where the channel is {@link #bind bound} to an Internet Protocol
+ * socket address then the return value from this method is of type {@link
+ * java.net.InetSocketAddress}.
+ *
+ * @return The socket address that the socket is bound to, or {@code null}
+ * if the channel is not {@link #isOpen open} or the channel's socket
+ * is not bound
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ SocketAddress getLocalAddress() throws IOException;
+
+ /**
+ * Sets the value of a socket option.
+ *
+ * @param name
+ * The socket option
+ * @param value
+ * The value of the socket option. A value of {@code null} may be
+ * a valid value for some socket options.
+ *
+ * @return This channel
+ *
+ * @throws IllegalArgumentException
+ * If the socket option is not supported by this channel, or
+ * the value is not a valid value for this socket option
+ * @throws ClosedChannelException
+ * If this channel is closed
+ * @throws IOException
+ * If an I/O error occurs
+ *
+ * @see java.net.StandardSocketOption
+ */
+ This method will continue to return the set of options even after the
+ * channel has been closed.
+ *
+ * @return A set of the socket options supported by this channel
+ */
+ Set Server-socket channels are not a complete abstraction of listening
- * network sockets. Binding and the manipulation of socket options must be
- * done through an associated {@link java.net.ServerSocket} object obtained by
- * invoking the {@link #socket() socket} method. It is not possible to create
- * a channel for an arbitrary, pre-existing server socket, nor is it possible
- * to specify the {@link java.net.SocketImpl} object to be used by a server
- * socket associated with a server-socket channel.
+ * A server-socket channel is created by invoking the {@link #open() open}
+ * method of this class. It is not possible to create a channel for an arbitrary,
+ * pre-existing {@link ServerSocket}. A newly-created server-socket channel is
+ * open but not yet bound. An attempt to invoke the {@link #accept() accept}
+ * method of an unbound server-socket channel will cause a {@link NotYetBoundException}
+ * to be thrown. A server-socket channel can be bound by invoking one of the
+ * {@link #bind(java.net.SocketAddress,int) bind} methods defined by this class.
*
- * A server-socket channel is created by invoking the {@link #open() open}
- * method of this class. A newly-created server-socket channel is open but not
- * yet bound. An attempt to invoke the {@link #accept() accept} method of an
- * unbound server-socket channel will cause a {@link NotYetBoundException} to
- * be thrown. A server-socket channel can be bound by invoking one of the
- * {@link java.net.ServerSocket#bind(java.net.SocketAddress,int) bind} methods
- * of an associated server socket.
+ * Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. Server-socket channels support the following options:
+ * Server-socket channels are safe for use by multiple concurrent threads.
* An invocation of this method is equivalent to the following:
+ * This method is used to establish an association between the socket and
+ * a local address. Once an association is established then the socket remains
+ * bound until the channel is closed.
+ *
+ * The {@code backlog} parameter is the maximum number of pending
+ * connections on the socket. Its exact semantics are implementation specific.
+ * In particular, an implementation may impose a maximum length or may choose
+ * to ignore the parameter altogther. If the {@code backlog} parameter has
+ * the value {@code 0}, or a negative value, then an implementation specific
+ * default is used.
+ *
+ * @param local
+ * The address to bind the socket, or {@code null} to bind to an
+ * automatically assigned socket address
+ * @param backlog
+ * The maximum number of pending connections
+ *
+ * @return This channel
+ *
+ * @throws AlreadyBoundException
+ * If the socket is already bound
+ * @throws UnsupportedAddressTypeException
+ * If the type of the given address is not supported
+ * @throws ClosedChannelException
+ * If this channel is closed
+ * @throws IOException
+ * If some other I/O error occurs
+ * @throws SecurityException
+ * If a security manager has been installed and its {@link
+ * SecurityManager#checkListen checkListen} method denies the
+ * operation
+ *
+ * @since 1.7
+ */
+ public abstract ServerSocketChannel bind(SocketAddress local, int backlog)
+ throws IOException;
+
+ /**
+ * @throws IllegalArgumentException {@inheritDoc}
+ * @throws ClosedChannelException {@inheritDoc}
+ * @throws IOException {@inheritDoc}
+ *
+ * @since 1.7
+ */
+ public abstract The returned object will not declare any public methods that are not
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/java/nio/channels/SocketChannel.java
--- a/jdk/src/share/classes/java/nio/channels/SocketChannel.java Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/src/share/classes/java/nio/channels/SocketChannel.java Thu Sep 04 14:55:12 2008 -0700
@@ -27,24 +27,17 @@
import java.io.IOException;
import java.net.Socket;
+import java.net.SocketOption;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.spi.*;
-
/**
* A selectable channel for stream-oriented connecting sockets.
*
- * Socket channels are not a complete abstraction of connecting network
- * sockets. Binding, shutdown, and the manipulation of socket options must be
- * done through an associated {@link java.net.Socket} object obtained by
- * invoking the {@link #socket() socket} method. It is not possible to create
- * a channel for an arbitrary, pre-existing socket, nor is it possible to
- * specify the {@link java.net.SocketImpl} object to be used by a socket
- * associated with a socket channel.
- *
* A socket channel is created by invoking one of the {@link #open open}
- * methods of this class. A newly-created socket channel is open but not yet
+ * methods of this class. It is not possible to create a channel for an arbitrary,
+ * pre-existing socket. A newly-created socket channel is open but not yet
* connected. An attempt to invoke an I/O operation upon an unconnected
* channel will cause a {@link NotYetConnectedException} to be thrown. A
* socket channel can be connected by invoking its {@link #connect connect}
@@ -59,16 +52,6 @@
* Whether or not a connection operation is in progress may be determined by
* invoking the {@link #isConnectionPending isConnectionPending} method.
*
- * The input and output sides of a socket channel may independently be
- * shut down without actually closing the channel. Shutting down the
- * input side of a channel by invoking the {@link java.net.Socket#shutdownInput
- * shutdownInput} method of an associated socket object will cause further
- * reads on the channel to return -1, the end-of-stream indication.
- * Shutting down the output side of the channel by invoking the {@link
- * java.net.Socket#shutdownOutput shutdownOutput} method of an associated
- * socket object will cause further writes on the channel to throw a {@link
- * ClosedChannelException}.
- *
* Socket channels support asynchronous shutdown, which is similar
* to the asynchronous close operation specified in the {@link Channel} class.
* If the input side of a socket is shut down by one thread while another
@@ -79,6 +62,43 @@
* channel, then the blocked thread will receive an {@link
* AsynchronousCloseException}.
*
+ * Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. Socket channels support the following options:
+ * Socket channels are safe for use by multiple concurrent threads. They
* support concurrent reading and writing, though at most one thread may be
* reading and at most one thread may be writing at any given time. The {@link
@@ -87,7 +107,6 @@
* or write operation while an invocation of one of these methods is in
* progress will block until that invocation is complete. Once shutdown for reading then further reads on the channel will
+ * return {@code -1}, the end-of-stream indication. If the input side of the
+ * connection is already shutdown then invoking this method has no effect.
+ *
+ * @return The channel
+ *
+ * @throws NotYetConnectedException
+ * If this channel is not yet connected
+ * @throws ClosedChannelException
+ * If this channel is closed
+ * @throws IOException
+ * If some other I/O error occurs
+ *
+ * @since 1.7
+ */
+ public abstract SocketChannel shutdownInput() throws IOException;
+
+ /**
+ * Shutdown the connection for writing without closing the channel.
+ *
+ * Once shutdown for writing then further attempts to write to the
+ * channel will throw {@link ClosedChannelException}. If the output side of
+ * the connection is already shutdown then invoking this method has no
+ * effect.
+ *
+ * @return The channel
+ *
+ * @throws NotYetConnectedException
+ * If this channel is not yet connected
+ * @throws ClosedChannelException
+ * If this channel is closed
+ * @throws IOException
+ * If some other I/O error occurs
+ *
+ * @since 1.7
+ */
+ public abstract SocketChannel shutdownOutput() throws IOException;
+
+ /**
* Retrieves a socket associated with this channel.
*
* The returned object will not declare any public methods that are not
@@ -202,10 +288,10 @@
public abstract Socket socket();
/**
- * Tells whether or not this channel's network socket is connected. Where the channel is bound and connected to an Internet Protocol
+ * socket address then the return value from this method is of type {@link
+ * java.net.InetSocketAddress}.
+ *
+ * @return The remote address; {@code null} if the channel is not {@link
+ * #isOpen open} or the channel's socket is not connected
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ *
+ * @since 1.7
+ */
+ public abstract SocketAddress getConnectedAddress() throws IOException;
// -- ByteChannel operations --
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/java/nio/channels/exceptions
--- a/jdk/src/share/classes/java/nio/channels/exceptions Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/src/share/classes/java/nio/channels/exceptions Thu Sep 04 14:55:12 2008 -0700
@@ -146,3 +146,14 @@
* virtual machine, or when another thread is already waiting to lock an
* overlapping region of the same file." \
2047812138163068433L
+
+
+SINCE=1.7
+
+SUPER=IllegalStateException
+
+gen AlreadyBoundException "
+ * Unchecked exception thrown when an attempt is made to bind the socket a
+ * network oriented channel that is already bound." \
+ 6796072983322737592L
+
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/java/nio/channels/package-info.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/channels/package-info.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2001-2005 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.
+ */
+
+/**
+ * Defines channels, which represent connections to entities that are capable of
+ * performing I/O operations, such as files and sockets; defines selectors, for
+ * multiplexed, non-blocking I/O operations.
+ *
+ *
+ *
+ * Channels Description A channel represents an open connection to an entity such as a
+ * hardware device, a file, a network socket, or a program component that is
+ * capable of performing one or more distinct I/O operations, for example reading
+ * or writing. As specified in the {@link java.nio.channels.Channel} interface,
+ * channels are either open or closed, and they are both asynchronously
+ * closeable and interruptible.
+ *
+ * The {@link java.nio.channels.Channel} interface is extended by several
+ * other interfaces.
+ *
+ * The {@link java.nio.channels.ReadableByteChannel} interface specifies a
+ * {@link java.nio.channels.ReadableByteChannel#read read} method that reads bytes
+ * from the channel into a buffer; similarly, the {@link
+ * java.nio.channels.WritableByteChannel} interface specifies a {@link
+ * java.nio.channels.WritableByteChannel#write write} method that writes bytes
+ * from a buffer to the channel. The {@link java.nio.channels.ByteChannel}
+ * interface unifies these two interfaces for the common case of channels that can
+ * both read and write bytes. The {@link java.nio.channels.SeekableByteChannel}
+ * interface extends the {@code ByteChannel} interface with methods to {@link
+ * java.nio.channels.SeekableByteChannel#position() query} and {@link
+ * java.nio.channels.SeekableByteChannel#position(long) modify} the channel's
+ * current position, and its {@link java.nio.channels.SeekableByteChannel#size
+ * size}.
+ *
+ * The {@link java.nio.channels.ScatteringByteChannel} and {@link
+ * java.nio.channels.GatheringByteChannel} interfaces extend the {@link
+ * java.nio.channels.ReadableByteChannel} and {@link
+ * java.nio.channels.WritableByteChannel} interfaces, respectively, adding {@link
+ * java.nio.channels.ScatteringByteChannel#read read} and {@link
+ * java.nio.channels.GatheringByteChannel#write write} methods that take a
+ * sequence of buffers rather than a single buffer.
+ *
+ * The {@link java.nio.channels.NetworkChannel} interface specifies methods
+ * to {@link java.nio.channels.NetworkChannel#bind bind} the channel's socket,
+ * obtain the address to which the socket is bound, and methods to {@link
+ * java.nio.channels.NetworkChannel#getOption get} and {@link
+ * java.nio.channels.NetworkChannel#setOption set} socket options. The {@link
+ * java.nio.channels.MulticastChannel} interface specifies methods to join
+ * Internet Protocol (IP) multicast groups.
+ *
+ * The {@link java.nio.channels.Channels} utility class defines static methods
+ * that support the interoperation of the stream classes of the {@link
+ * java.io} package with the channel classes of this package. An appropriate
+ * channel can be constructed from an {@link java.io.InputStream} or an {@link
+ * java.io.OutputStream}, and conversely an {@link java.io.InputStream} or an
+ * {@link java.io.OutputStream} can be constructed from a channel. A {@link
+ * java.io.Reader} can be constructed that uses a given charset to decode bytes
+ * from a given readable byte channel, and conversely a {@link java.io.Writer} can
+ * be constructed that uses a given charset to encode characters into bytes and
+ * write them to a given writable byte channel.
+ *
+ * File channels Description The {@link java.nio.channels.FileChannel} class supports the usual
+ * operations of reading bytes from, and writing bytes to, a channel connected to
+ * a file, as well as those of querying and modifying the current file position
+ * and truncating the file to a specific size. It defines methods for acquiring
+ * locks on the whole file or on a specific region of a file; these methods return
+ * instances of the {@link java.nio.channels.FileLock} class. Finally, it defines
+ * methods for forcing updates to the file to be written to the storage device that
+ * contains it, for efficiently transferring bytes between the file and other
+ * channels, and for mapping a region of the file directly into memory.
+ *
+ * A {@code FileChannel} is created by invoking one of its static {@link
+ * java.nio.channels.FileChannel#open open} methods, or by invoking the {@code
+ * getChannel} method of a {@link java.io.FileInputStream}, {@link
+ * java.io.FileOutputStream}, or {@link java.io.RandomAccessFile} to return a
+ * file channel connected to the same underlying file as the {@link java.io}
+ * class.
+ *
+ *
+ * Multiplexed, non-blocking I/O Description Multiplexed, non-blocking I/O, which is much more scalable than
+ * thread-oriented, blocking I/O, is provided by selectors, selectable
+ * channels, and selection keys.
+ *
+ * A selector is a multiplexor of selectable channels, which in turn are
+ * a special type of channel that can be put into non-blocking mode. To perform
+ * multiplexed I/O operations, one or more selectable channels are first created,
+ * put into non-blocking mode, and {@link
+ * java.nio.channels.SelectableChannel#register registered}
+ * with a selector. Registering a channel specifies the set of I/O operations
+ * that will be tested for readiness by the selector, and returns a selection key that represents the
+ * registration.
+ *
+ * Once some channels have been registered with a selector, a selection operation can be performed in
+ * order to discover which channels, if any, have become ready to perform one or
+ * more of the operations in which interest was previously declared. If a channel
+ * is ready then the key returned when it was registered will be added to the
+ * selector's selected-key set. The key set, and the keys within it, can
+ * be examined in order to determine the operations for which each channel is
+ * ready. From each key one can retrieve the corresponding channel in order to
+ * perform whatever I/O operations are required.
+ *
+ * That a selection key indicates that its channel is ready for some operation
+ * is a hint, but not a guarantee, that such an operation can be performed by a
+ * thread without causing the thread to block. It is imperative that code that
+ * performs multiplexed I/O be written so as to ignore these hints when they prove
+ * to be incorrect.
+ *
+ * This package defines selectable-channel classes corresponding to the {@link
+ * java.net.DatagramSocket}, {@link java.net.ServerSocket}, and {@link
+ * java.net.Socket} classes defined in the {@link java.net} package.
+ * Minor changes to these classes have been made in order to support sockets that
+ * are associated with channels. This package also defines a simple class that
+ * implements unidirectional pipes. In all cases, a new selectable channel is
+ * created by invoking the static open method of the corresponding class.
+ * If a channel needs an associated socket then a socket will be created as a side
+ * effect of this operation.
+ *
+ * The implementation of selectors, selectable channels, and selection keys
+ * can be replaced by "plugging in" an alternative definition or instance of the
+ * {@link java.nio.channels.spi.SelectorProvider} class defined in the {@link
+ * java.nio.channels.spi} package. It is not expected that many developers
+ * will actually make use of this facility; it is provided primarily so that
+ * sophisticated users can take advantage of operating-system-specific
+ * I/O-multiplexing mechanisms when very high performance is required.
+ *
+ * Much of the bookkeeping and synchronization required to implement the
+ * multiplexed-I/O abstractions is performed by the {@link
+ * java.nio.channels.spi.AbstractInterruptibleChannel}, {@link
+ * java.nio.channels.spi.AbstractSelectableChannel}, {@link
+ * java.nio.channels.spi.AbstractSelectionKey}, and {@link
+ * java.nio.channels.spi.AbstractSelector} classes in the {@link
+ * java.nio.channels.spi} package. When defining a custom selector provider,
+ * only the {@link java.nio.channels.spi.AbstractSelector} and {@link
+ * java.nio.channels.spi.AbstractSelectionKey} classes should be subclassed
+ * directly; custom channel classes should extend the appropriate {@link
+ * java.nio.channels.SelectableChannel} subclasses defined in this package.
+ *
+ * Unless otherwise noted, passing a null argument to a constructor
+ * or method in any class or interface in this package will cause a {@link
+ * java.lang.NullPointerException NullPointerException} to be thrown.
+ *
+ * @since 1.4
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ */
+
+package java.nio.channels;
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/java/nio/channels/package.html
--- a/jdk/src/share/classes/java/nio/channels/package.html Sun Aug 31 11:59:20 2008 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,222 +0,0 @@
-
-
-
-
- Channels Description A channel represents an open connection to an entity such as a
-hardware device, a file, a network socket, or a program component that is
-capable of performing one or more distinct I/O operations, for example reading
-or writing. As specified in the {@link java.nio.channels.Channel} interface,
-channels are either open or closed, and they are both asynchronously
-closeable and interruptible.
-
- The {@link java.nio.channels.Channel} interface is extended by several
-other interfaces, each of which specifies a new I/O operation.
-
- The {@link java.nio.channels.ReadableByteChannel} interface specifies a
-{@link java.nio.channels.ReadableByteChannel#read read} method that reads bytes
-from the channel into a buffer; similarly, the {@link
-java.nio.channels.WritableByteChannel} interface specifies a {@link
-java.nio.channels.WritableByteChannel#write write} method that writes bytes
-from a buffer to the channel. The {@link java.nio.channels.ByteChannel}
-interface unifies these two interfaces for the common case of channels that can
-both read and write bytes.
-
- The {@link java.nio.channels.ScatteringByteChannel} and {@link
-java.nio.channels.GatheringByteChannel} interfaces extend the {@link
-java.nio.channels.ReadableByteChannel} and {@link
-java.nio.channels.WritableByteChannel} interfaces, respectively, adding {@link
-java.nio.channels.ScatteringByteChannel#read read} and {@link
-java.nio.channels.GatheringByteChannel#write write} methods that take a
-sequence of buffers rather than a single buffer.
-
- The {@link java.nio.channels.Channels} utility class defines static methods
-that support the interoperation of the stream classes of the {@link
-java.io} package with the channel classes of this package. An appropriate
-channel can be constructed from an {@link java.io.InputStream} or an {@link
-java.io.OutputStream}, and conversely an {@link java.io.InputStream} or an
-{@link java.io.OutputStream} can be constructed from a channel. A {@link
-java.io.Reader} can be constructed that uses a given charset to decode bytes
-from a given readable byte channel, and conversely a {@link java.io.Writer} can
-be constructed that uses a given charset to encode characters into bytes and
-write them to a given writable byte channel.
-
-
- File channels Description The {@link java.nio.channels.FileChannel} class supports the usual
-operations of reading bytes from, and writing bytes to, a channel connected to
-a file, as well as those of querying and modifying the current file position
-and truncating the file to a specific size. It defines methods for acquiring
-locks on the whole file or on a specific region of a file; these methods return
-instances of the {@link java.nio.channels.FileLock} class. Finally, it defines
-methods for forcing updates to the file to be written to the storage device that
-contains it, for efficiently transferring bytes between the file and other
-channels, and for mapping a region of the file directly into memory. This last
-operation creates an instance of the {@link java.nio.MappedByteBuffer}
-class, which extends the {@link java.nio.ByteBuffer} class with several
-file-related operations.
-
- A getChannel method has been added to each of the {@link
-java.io.FileInputStream#getChannel FileInputStream}, {@link
-java.io.FileOutputStream#getChannel FileOutputStream}, and {@link
-java.io.RandomAccessFile#getChannel RandomAccessFile} classes of the {@link
-java.io java.io} package. Invoking this method upon an instance of one of
-these classes will return a file channel connected to the underlying file.
-
-
-
-
- Multiplexed, non-blocking I/O Description Multiplexed, non-blocking I/O, which is much more scalable than
-thread-oriented, blocking I/O, is provided by selectors, selectable
-channels, and selection keys.
-
- A selector is a multiplexor of selectable channels, which in turn are
-a special type of channel that can be put into non-blocking mode. To perform
-multiplexed I/O operations, one or more selectable channels are first created,
-put into non-blocking mode, and {@link
-java.nio.channels.SelectableChannel#register registered Once some channels have been registered with a selector, a selection operation can be performed in
-order to discover which channels, if any, have become ready to perform one or
-more of the operations in which interest was previously declared. If a channel
-is ready then the key returned when it was registered will be added to the
-selector's selected-key set. The key set, and the keys within it, can
-be examined in order to determine the operations for which each channel is
-ready. From each key one can retrieve the corresponding channel in order to
-perform whatever I/O operations are required.
-
- That a selection key indicates that its channel is ready for some operation
-is a hint, but not a guarantee, that such an operation can be performed by a
-thread without causing the thread to block. It is imperative that code that
-performs multiplexed I/O be written so as to ignore these hints when they prove
-to be incorrect.
-
- This package defines selectable-channel classes corresponding to the {@link
-java.net.DatagramSocket}, {@link java.net.ServerSocket}, and {@link
-java.net.Socket} classes defined in the {@link java.net} package.
-Minor changes to these classes have been made in order to support sockets that
-are associated with channels. This package also defines a simple class that
-implements unidirectional pipes. In all cases, a new selectable channel is
-created by invoking the static open method of the corresponding class.
-If a channel needs an associated socket then a socket will be created as a side
-effect of this operation.
-
- The implementation of selectors, selectable channels, and selection keys
-can be replaced by "plugging in" an alternative definition or instance of the
-{@link java.nio.channels.spi.SelectorProvider} class defined in the {@link
-java.nio.channels.spi} package. It is not expected that many developers
-will actually make use of this facility; it is provided primarily so that
-sophisticated users can take advantage of operating-system-specific
-I/O-multiplexing mechanisms when very high performance is required.
-
- Much of the bookkeeping and synchronization required to implement the
-multiplexed-I/O abstractions is performed by the {@link
-java.nio.channels.spi.AbstractInterruptibleChannel}, {@link
-java.nio.channels.spi.AbstractSelectableChannel}, {@link
-java.nio.channels.spi.AbstractSelectionKey}, and {@link
-java.nio.channels.spi.AbstractSelector} classes in the {@link
-java.nio.channels.spi} package. When defining a custom selector provider,
-only the {@link java.nio.channels.spi.AbstractSelector} and {@link
-java.nio.channels.spi.AbstractSelectionKey} classes should be subclassed
-directly; custom channel classes should extend the appropriate {@link
-java.nio.channels.SelectableChannel} subclasses defined in this package.
-
- Unless otherwise noted, passing a null argument to a constructor
-or method in any class or interface in this package will cause a {@link
-java.lang.NullPointerException NullPointerException} to be thrown.
-
-
-@since 1.4
-@author Mark Reinhold
-@author JSR-51 Expert Group
-
-
-
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java
--- a/jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java Thu Sep 04 14:55:12 2008 -0700
@@ -25,10 +25,8 @@
package java.nio.channels.spi;
-import java.io.FileDescriptor;
import java.io.IOException;
-import java.net.ServerSocket;
-import java.net.Socket;
+import java.net.ProtocolFamily;
import java.nio.channels.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -190,7 +188,25 @@
throws IOException;
/**
- * Opens a pipe. An MBeanPermission contains four items of information: An MBeanPermission contains five items of information: The action is returned by {@link #getActions()}. The MBean Server name. For a permission you need, this is the {@linkplain
+ * javax.management.MBeanServerFactory#getMBeanServerName
+ * name of the MBeanServer}
+ * containing the MBean for which the MBean
+ * permission is checked. For a permission you have, this is either the {@linkplain
+ * javax.management.MBeanServerFactory#getMBeanServerName
+ * name of the MBeanServer} in which the MBean
+ * you have this permission for must be registered,
+ * or a pattern against which that MBean Server name will be matched. The class name. For a permission you need, this is the class name of an MBean
@@ -88,7 +106,7 @@
* or operation you can access, or it is empty or the single character
* " The object name. The object name. For a permission you need, this is the {@link ObjectName} of the
* MBean you are accessing. For operations that do not reference a
@@ -103,15 +121,15 @@
* If you have an MBeanPermission, it allows operations only if all
- * four of the items match. The class name, member, and object name can be written together
- * as a single string, which is the name of this permission.
+ * The MBean Server name, class name, member, and object name can be written
+ * together as a single string, which is the name of this permission.
* The name of the permission is the string returned by {@link
* Permission#getName() getName()}. The format of the string is: The object name is written using the usual syntax for {@link
@@ -119,15 +137,18 @@
* One or more of the One or more of the One or more of the One or more of the Create a new MBeanPermission object with the specified target name
* and actions. The target name is of the form
- * " The actions parameter contains a comma-separated list of the
* desired actions granted on the target name. It must not be
* empty or null. This corresponds to a permission granted for all
+ * MBean servers present in the JVM and is equivalent to
+ * {@link #MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission("*",className,member,objectName,actions)}.
+ * The actions parameter contains a comma-separated list of the
* desired actions granted on the target name. It must not be
* empty or null. Create a new MBeanPermission object with the specified target name
+ * (MBean Server name, class name, member, object name) and actions. The MBean Server name, class name, member and object name
+ * parameters define a target name of the form
+ * " The actions parameter contains a comma-separated list of the
+ * desired actions granted on the target name. It must not be
+ * empty or null. If this object's mbeanServerName is a pattern, then p's
+ * mbeanServerName is matched against that pattern. An empty
+ * mbeanServerName is equivalent to "{@code *}". A null
+ * mbeanServerName is equivalent to "{@code -}". If this object's mbeanServerName is " If this object's className is " User code does not usually implement this interface. Instead,
* an object that implements this interface is obtained with one of
- * the methods in the {@link MBeanServerFactory} class. Every MBean which is added to the MBean server becomes
* manageable: its attributes and operations become remotely
@@ -62,8 +62,12 @@
* An object obtained from the {@link
- * MBeanServerFactory#createMBeanServer(String) createMBeanServer} or
- * {@link MBeanServerFactory#newMBeanServer(String) newMBeanServer}
+ * MBeanServerFactory#createMBeanServer(String) createMBeanServer}, {@link
+ * MBeanServerFactory#createNamedMBeanServer(String,String) createNamedMBeanServer},
+ * {@link
+ * MBeanServerFactory#newMBeanServer(String) newMBeanServer}, or
+ * {@link
+ * MBeanServerFactory#newNamedMBeanServer(String,String) newNamedMBeanServer}
* methods of the {@link MBeanServerFactory} class applies security
* checks to its methods, as follows. Assuming that there is a security manager, or that the
* implementation chooses to make checks anyway, the checks are made
- * as detailed below. In what follows, If a security check fails, the method throws {@link
* SecurityException}. For the {@link #invoke invoke} method, the caller's
* permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, operationName, name, "invoke")}. For the {@link #getAttribute getAttribute} method, the
* caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, attribute, name, "getAttribute")}. For the {@link #getAttributes getAttributes} method, the
* caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, name, "getAttribute")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName,className, null, name, "getAttribute")}.
* Additionally, for each attribute a in the {@link
* AttributeList}, if the caller's permissions do not imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, a, name, "getAttribute")}, the
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, className, a, name,
+ * "getAttribute")}, the
* MBean server will behave as if that attribute had not been in the
* supplied list. For the {@link #setAttribute setAttribute} method, the
* caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, attrName, name, "setAttribute")}, where
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, className, attrName, name,
+ * "setAttribute")}, where
* For the {@link #setAttributes setAttributes} method, the
* caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, name, "setAttribute")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, className, null, name, "setAttribute")}.
* Additionally, for each attribute a in the {@link
* AttributeList}, if the caller's permissions do not imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, a, name, "setAttribute")}, the
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, className, a, name,
+ * "setAttribute")}, the
* MBean server will behave as if that attribute had not been in the
* supplied list. For the For the For the {@link #getMBeanInfo getMBeanInfo} method, the
* caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, name, "getMBeanInfo")}. For the {@link #getObjectInstance getObjectInstance} method,
* the caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, name, "getObjectInstance")}. For the {@link #isInstanceOf isInstanceOf} method, the
* caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, name, "isInstanceOf")}. For the {@link #queryMBeans queryMBeans} method, the
* caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(null, null, name, "queryMBeans")}.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, null, null, null, "queryMBeans")}.
* Additionally, for each MBean that matches Certain query elements perform operations on the MBean server.
@@ -179,10 +208,10 @@
*
* For the {@link #getDomains getDomains} method, the caller's
* permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(null, null, name, "getDomains")}. Additionally,
- * for each domain d in the returned array, if the caller's
- * permissions do not imply {@link
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, null, null, null, "getDomains")}.
+ * Additionally, for each domain d in the returned array, if the
+ * caller's permissions do not imply {@link
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
* MBeanPermission(null, null, new ObjectName("d:x=x"),
* "getDomains")}, the domain is eliminated from the array. Here,
@@ -191,21 +220,22 @@
*
* For the {@link #getClassLoader getClassLoader} method, the
* caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, loaderName,
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, className, null, loaderName,
* "getClassLoader")}. For the {@link #getClassLoaderFor getClassLoaderFor} method,
* the caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, mbeanName,
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, className, null, mbeanName,
* "getClassLoaderFor")}. For the {@link #getClassLoaderRepository
* getClassLoaderRepository} method, the caller's permissions must
* imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(null, null, null, "getClassLoaderRepository")}. For the deprecated For the For the {@link #registerMBean registerMBean} method, the
* caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, name, "registerMBean")}. Here
- * If the For the {@link #unregisterMBean unregisterMBean} method,
* the caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, name, "unregisterMBean")}.
+ *
+ * Additional (implementation specific) options may also be supported.
+ *
*
+ *
+ *
+ *
+ * Option Name
+ * Description
+ *
+ *
+ * {@link java.net.StandardSocketOption#SO_SNDBUF SO_SNDBUF}
+ * The size of the socket send buffer
+ *
+ *
+ * {@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF}
+ * The size of the socket receive buffer
+ *
+ *
+ * {@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR}
+ * Re-use address
+ *
+ *
+ * {@link java.net.StandardSocketOption#SO_BROADCAST SO_BROADCAST}
+ * Allow transmission of broadcast datagrams
+ *
+ *
+ * {@link java.net.StandardSocketOption#IP_TOS IP_TOS}
+ * The Type of Service (ToS) octet in the Internet Protocol (IP) header
+ *
+ *
+ * {@link java.net.StandardSocketOption#IP_MULTICAST_IF IP_MULTICAST_IF}
+ * The network interface for Internet Protocol (IP) multicast datagrams
+ *
+ *
+ * {@link java.net.StandardSocketOption#IP_MULTICAST_TTL
+ * IP_MULTICAST_TTL}
+ * The time-to-live for Internet Protocol (IP) multicast
+ * datagrams
+ *
+ *
+ * {@link java.net.StandardSocketOption#IP_MULTICAST_LOOP
+ * IP_MULTICAST_LOOP}
+ * Loopback for Internet Protocol (IP) multicast datagrams
+ * Platform dependencies
+ *
+ * The multicast implementation is intended to map directly to the native
+ * multicasting facility. Consequently, the following items should be considered
+ * when developing an application that receives IP multicast datagrams:
+ *
+ *
+ *
+ *
+ *
+ *
+ * // join multicast group on this interface, and also use this
+ * // interface for outgoing multicast datagrams
+ * NetworkInterface ni = NetworkInterface.getByName("hme0");
+ *
+ * DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)
+ * .setOption(StandardSocketOption.SO_REUSEADDR, true)
+ * .bind(new InetSocketAddress(5000))
+ * .setOption(StandardSocketOption.IP_MULTICAST_IF, ni);
+ *
+ * InetAddress group = InetAddress.getByName("225.4.5.6");
+ *
+ * MembershipKey key = dc.join(group, ni);
+ *
+ *
+ * @since 1.7
+ */
+
+public interface MulticastChannel
+ extends NetworkChannel
+{
+ /**
+ * Joins a multicast group to begin receiving all datagrams sent to the group,
+ * returning a membership key.
+ *
+ *
+ *
+ * Additional (implementation specific) options may also be supported.
*
*
+ *
+ *
+ *
+ * Option Name
+ * Description
+ *
+ *
+ * {@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF}
+ * The size of the socket receive buffer
+ *
+ *
+ * {@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR}
+ * Re-use address
+ *
+ *
+ * @param local
+ * The local address to bind the socket, or {@code null} to bind
+ * to an automatically assigned socket address
+ *
+ * @return This channel
+ *
+ * @throws AlreadyBoundException {@inheritDoc}
+ * @throws UnsupportedAddressTypeException {@inheritDoc}
+ * @throws ClosedChannelException {@inheritDoc}
+ * @throws IOException {@inheritDoc}
+ * @throws SecurityException
+ * If a security manager has been installed and its {@link
+ * SecurityManager#checkListen checkListen} method denies the
+ * operation
+ *
+ * @since 1.7
+ */
+ public final ServerSocketChannel bind(SocketAddress local)
+ throws IOException
+ {
+ return bind(local, 0);
+ }
+
+ /**
+ * Binds the channel's socket to a local address and configures the socket to
+ * listen for connections.
+ *
+ *
+ * bind(local, 0);
+ *
+ *
+ * Additional (implementation specific) options may also be supported.
+ *
*
+ *
+ *
+ *
+ * Option Name
+ * Description
+ *
+ *
+ * {@link java.net.StandardSocketOption#SO_SNDBUF SO_SNDBUF}
+ * The size of the socket send buffer
+ *
+ *
+ * {@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF}
+ * The size of the socket receive buffer
+ *
+ *
+ * {@link java.net.StandardSocketOption#SO_KEEPALIVE SO_KEEPALIVE}
+ * Keep connection alive
+ *
+ *
+ * {@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR}
+ * Re-use address
+ *
+ *
+ * {@link java.net.StandardSocketOption#SO_LINGER SO_LINGER}
+ * Linger on close if data is present (when configured in blocking mode
+ * only)
+ *
+ *
+ * {@link java.net.StandardSocketOption#TCP_NODELAY TCP_NODELAY}
+ * Disable the Nagle algorithm
+ *
+ *
+ *
+ *
+ *
+ * {@link java.nio.channels.Channel}
+ * A nexus for I/O operations
+ * {@link java.nio.channels.ReadableByteChannel}
+ * Can read into a buffer
+ * {@link java.nio.channels.ScatteringByteChannel}
+ * Can read into a sequence of buffers
+ * {@link java.nio.channels.WritableByteChannel}
+ * Can write from a buffer
+ * {@link java.nio.channels.GatheringByteChannel}
+ * Can write from a sequence of buffers
+ * {@link java.nio.channels.ByteChannel}
+ * Can read/write to/from a buffer
+ * {@link java.nio.channels.SeekableByteChannel}
+ * A {@code ByteChannel} connected to an entity that contains a variable-length sequence of bytes
+ * {@link java.nio.channels.NetworkChannel}
+ * A channel to a network socket
+ * {@link java.nio.channels.MulticastChannel}
+ * Can join Internet Protocol (IP) multicast groups
+ * {@link java.nio.channels.Channels}
+ * Utility methods for channel/stream interoperation
+ *
+ *
+ *
+ *
+ * {@link java.nio.channels.FileChannel}
+ * Reads, writes, maps, and manipulates files
+ * {@link java.nio.channels.FileLock}
+ * A lock on a (region of a) file
+ * {@link java.nio.MappedByteBuffer}/{@link java.nio.MappedBigByteBuffer}
+ * A direct byte buffer or big byte buffer mapped to a region of a file
+ *
+ *
+ *
+ *
+ * {@link java.nio.channels.SelectableChannel}
+ * A channel that can be multiplexed
+ * {@link java.nio.channels.DatagramChannel}
+ * A channel to a datagram-oriented socket
+ * {@link java.nio.channels.Pipe.SinkChannel}
+ * The write end of a pipe
+ * {@link java.nio.channels.Pipe.SourceChannel}
+ * The read end of a pipe
+ * {@link java.nio.channels.ServerSocketChannel}
+ * A channel to a stream-oriented listening socket
+ * {@link java.nio.channels.SocketChannel}
+ * A channel for a stream-oriented connecting socket
+ * {@link java.nio.channels.Selector}
+ * A multiplexor of selectable channels
+ * {@link java.nio.channels.SelectionKey}
+ * A token representing the registration
of a channel
+ * with a selector
+ * {@link java.nio.channels.Pipe}
+ * Two channels that form a unidirectional pipe
+ *
-
-
-
-
- {@link java.nio.channels.Channel}
- A nexus for I/O operations
- {@link java.nio.channels.ReadableByteChannel}
- Can read into a buffer
- {@link java.nio.channels.ScatteringByteChannel}
- Can read into a sequence of buffers
- {@link java.nio.channels.WritableByteChannel}
- Can write from a buffer
- {@link java.nio.channels.GatheringByteChannel}
- Can write from a sequence of buffers
- {@link java.nio.channels.ByteChannel}
- Can read/write to/from a buffer
-{@link java.nio.channels.Channels}
- Utility methods for channel/stream interoperation
-
-
-
-
- {@link java.nio.channels.FileChannel}
- Reads, writes, maps, and manipulates files
- {@link java.nio.channels.FileLock}
- A lock on a (region of a) file
-{@link java.nio.MappedByteBuffer}
- A direct byte buffer mapped to a region of a file
-
-
-
-
- {@link java.nio.channels.SelectableChannel}
- A channel that can be multiplexed
- {@link java.nio.channels.DatagramChannel}
- A channel for a {@link java.net.DatagramSocket java.net.DatagramSocket}
- {@link java.nio.channels.Pipe.SinkChannel}
- The write end of a pipe
- {@link java.nio.channels.Pipe.SourceChannel}
- The read end of a pipe
- {@link java.nio.channels.ServerSocketChannel}
- A channel for a {@link java.net.ServerSocket java.net.ServerSocket}
- {@link java.nio.channels.SocketChannel}
- A channel for a {@link java.net.Socket java.net.Socket}
- {@link java.nio.channels.Selector}
- A multiplexor of selectable channels
- {@link java.nio.channels.SelectionKey}
- A token representing the registration
of a channel
- with a selector
-{@link java.nio.channels.Pipe}
- Two channels that form a unidirectional pipe }
-with a selector. Registering a channel specifies the set of I/O operations
-that will be tested for readiness by the selector, and returns a selection key that represents the
-registration.
-
-
*
@@ -57,6 +58,23 @@
*
*
*
*
+ * An {@code mbeanServerName} pattern can also be empty or the single
+ * character {@code "*"}, both of which will match any {@code MBeanServer} name.
+ * *
", both of which grant access to any member.
- *
*
* className#member[objectName]
+ * mbeanServerName::className#member[objectName]
* ]
. It is terminated by a ]
character
* that is the last character in the string.className
, member
,
- * or objectName
may be omitted. If the
- * member
is omitted, the #
may be too (but
+ * mbeanServerName
, className
,
+ * member
, or objectName
may be omitted. If the
+ * mbeanServerName
is omitted, the ::
may be too (but
+ * does not have to be).
+ * If the member
is omitted, the #
may be too (but
* does not have to be). If the objectName
is omitted,
* the []
may be too (but does not have to be). It is
- * not legal to omit all three items, that is to have a name
+ * not legal to omit all four items, that is to have a name
* that is the empty string.className
, member
,
+ * mbeanServerName
, className
,
+ * member
,
* or objectName
may be the character "-
",
* which is equivalent to a null value. A null value is implied by
* any value (including another null value) but does not imply any
@@ -247,6 +268,13 @@
private transient ObjectName objectName;
/**
+ * The name of the MBeanServer in which this permission is checked, or
+ * granted. If null, is implied by any MBean Server name
+ * but does not imply any non-null MBean Server name.
+ */
+ private transient String mbeanServerName;
+
+ /**
* Parse actions
parameter.
*/
private void parseActions() {
@@ -283,6 +311,13 @@
throw new IllegalArgumentException("MBeanPermission name " +
"cannot be empty");
+ final int sepIndex = name.indexOf("::");
+ if (sepIndex < 0) {
+ setMBeanServerName("*");
+ } else {
+ setMBeanServerName(name.substring(0,sepIndex));
+ }
+
/* The name looks like "class#member[objectname]". We subtract
elements from the right as we parse, so after parsing the
objectname we have "class#member" and after parsing the
@@ -290,11 +325,14 @@
// Parse ObjectName
- int openingBracket = name.indexOf("[");
+
+ final int start = (sepIndex<0)?0:sepIndex+2;
+ int openingBracket = name.indexOf("[",start);
if (openingBracket == -1) {
// If "[on]" missing then ObjectName("*:*")
//
objectName = ObjectName.WILDCARD;
+ name = name.substring(start);
} else {
if (!name.endsWith("]")) {
throw new IllegalArgumentException("MBeanPermission: " +
@@ -305,11 +343,11 @@
} else {
// Create ObjectName
//
+ String on = name.substring(openingBracket + 1,
+ name.length() - 1);
try {
// If "[]" then ObjectName("*:*")
//
- String on = name.substring(openingBracket + 1,
- name.length() - 1);
if (on.equals(""))
objectName = ObjectName.WILDCARD;
else if (on.equals("-"))
@@ -320,11 +358,11 @@
throw new IllegalArgumentException("MBeanPermission: " +
"The target name does " +
"not specify a valid " +
- "ObjectName");
+ "ObjectName", e);
}
}
- name = name.substring(0, openingBracket);
+ name = name.substring(start, openingBracket);
}
// Parse member
@@ -348,8 +386,9 @@
* Assign fields based on className, member, and objectName
* parameters.
*/
- private void initName(String className, String member,
- ObjectName objectName) {
+ private void initName(String mbeanServerName, String className,
+ String member, ObjectName objectName) {
+ setMBeanServerName(mbeanServerName);
setClassName(className);
setMember(member);
this.objectName = objectName;
@@ -381,19 +420,30 @@
this.member = member;
}
+ private void setMBeanServerName(String mbeanServerName) {
+ if (mbeanServerName == null || mbeanServerName.equals("-")) {
+ this.mbeanServerName = null;
+ } else if (mbeanServerName.equals("")) {
+ this.mbeanServerName = "*";
+ } else {
+ this.mbeanServerName = mbeanServerName;
+ }
+ }
+
+
/**
* className#member[objectName]
" where each part is
- * optional. It must not be empty or null.mbeanServerName::className#member[objectName]
" where
+ * each part is optional. It must not be empty or null.name
or
@@ -418,6 +468,12 @@
* optional. This will be the result of {@link #getName()} on the
* resultant MBeanPermission.mbeanServerName::className#member[objectName]
" where each
+ * part is optional. This will be the result of {@link #getName()} on the
+ * resultant MBeanPermission.
+ * If the mbeanServerName
is empty or exactly {@code "*"}, then
+ * "{@code mbeanServerName::}" is omitted in that result.
+ * "-"
, which represents an MBeanServer name
+ * that is implied by any MBeanServer name but does not imply any other
+ * MBeanServer name.
+ * @param className the class name to which this permission applies.
+ * May be null or "-"
, which represents a class name
+ * that is implied by any class name but does not imply any other
+ * class name.
+ * @param member the member to which this permission applies. May
+ * be null or "-"
, which represents a member that is
+ * implied by any member but does not imply any other member.
+ * @param objectName the object name to which this permission
+ * applies. May be null, which represents an object name that is
+ * implied by any object name but does not imply any other object
+ * name.
+ * @param actions the action string.
+ *
+ * @since 1.7
+ */
+ public MBeanPermission(String mbeanServerName,
+ String className,
+ String member,
+ ObjectName objectName,
+ String actions) {
+
+ super(makeName(mbeanServerName,className, member, objectName));
+ initName(mbeanServerName,className, member, objectName);
this.actions = actions;
parseActions();
}
- private static String makeName(String className, String member,
+ private static String makeName(String mbeanServerName, String className,
+ String member,
ObjectName objectName) {
final StringBuilder name = new StringBuilder();
+ if (mbeanServerName == null)
+ mbeanServerName = "-";
+ if (!mbeanServerName.equals("") && !mbeanServerName.equals("*"))
+ name.append(mbeanServerName).append("::");
if (className == null)
className = "-";
name.append(className);
@@ -991,6 +1097,9 @@
*
* *
" or is
+ * empty, p's mbeanServerName always matches it.*
", p's
* className always matches it. If it is "a.*
", p's
* className matches it if it begins with "a.
".JMImplementation:type=MBeanServerDelegate
.className
is the
+ * as detailed below.
+ * In what follows, and unless otherwise specified:
+ * className
is the
* string returned by {@link MBeanInfo#getClassName()} for the target
- * MBean.attrName
is {@link Attribute#getName()
* attribute.getName()}.addNotificationListener
methods,
* the caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, name,
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, className, null, name,
* "addNotificationListener")}.removeNotificationListener
methods,
* the caller's permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, name,
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, className, null, name,
* "removeNotificationListener")}.name
,
* if the caller's permissions do not imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, name, "queryMBeans")}, the
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, className, null, name, "queryMBeans")}, the
* MBean server will behave as if that MBean did not exist.deserialize
methods, the
* required permissions are the same as for the methods that replace
@@ -213,15 +243,15 @@
*
* instantiate
methods, the caller's
* permissions must imply {@link
- * MBeanPermission#MBeanPermission(String,String,ObjectName,String)
- * MBeanPermission(className, null, null, "instantiate")}.className
is the string returned by {@link
- * MBeanInfo#getClassName()} for an object of this class.
+ * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
+ * MBeanPermission(mbeanServerName, className, null, name, "registerMBean")}.
*
* MBeanPermission
check succeeds, the MBean's
* class is validated by checking that its {@link
@@ -241,8 +271,9 @@
*
*
postRegister
* (MBeanRegistration
interface) method of the MBean throws a
- * RuntimeException
, the createMBean method will
+ * RuntimeException
, the createMBean
method will
* throw a RuntimeMBeanException
, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
- * registered even though the createMBean method
+ * registered even though the createMBean
method
* threw an exception. Note that RuntimeMBeanException
can
* also be thrown by preRegister
, in which case the MBean
* will not be registered.
* @exception RuntimeErrorException If the postRegister
* (MBeanRegistration
interface) method of the MBean throws an
- * Error
, the createMBean method will
+ * Error
, the createMBean
method will
* throw a RuntimeErrorException
, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
- * registered even though the createMBean method
+ * registered even though the createMBean
method
* threw an exception. Note that RuntimeErrorException
can
* also be thrown by preRegister
, in which case the MBean
* will not be registered.
@@ -150,19 +150,19 @@
* MBean will not be registered.
* @exception RuntimeMBeanException If the postRegister
* (MBeanRegistration
interface) method of the MBean throws a
- * RuntimeException
, the createMBean method will
+ * RuntimeException
, the createMBean
method will
* throw a RuntimeMBeanException
, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
- * registered even though the createMBean method
+ * registered even though the createMBean
method
* threw an exception. Note that RuntimeMBeanException
can
* also be thrown by preRegister
, in which case the MBean
* will not be registered.
* @exception RuntimeErrorException If the postRegister
* (MBeanRegistration
interface) method of the MBean throws an
- * Error
, the createMBean method will
+ * Error
, the createMBean
method will
* throw a RuntimeErrorException
, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
- * registered even though the createMBean method
+ * registered even though the createMBean
method
* threw an exception. Note that RuntimeErrorException
can
* also be thrown by preRegister
, in which case the MBean
* will not be registered.
@@ -225,19 +225,19 @@
* MBean will not be registered.
* @exception RuntimeMBeanException If the postRegister
* (MBeanRegistration
interface) method of the MBean throws a
- * RuntimeException
, the createMBean method will
+ * RuntimeException
, the createMBean
method will
* throw a RuntimeMBeanException
, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
- * registered even though the createMBean method
+ * registered even though the createMBean
method
* threw an exception. Note that RuntimeMBeanException
can
* also be thrown by preRegister
, in which case the MBean
* will not be registered.
* @exception RuntimeErrorException If the postRegister
* (MBeanRegistration
interface) method of the MBean throws an
- * Error
, the createMBean method will
+ * Error
, the createMBean
method will
* throw a RuntimeErrorException
, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
- * registered even though the createMBean method
+ * registered even though the createMBean
method
* threw an exception. Note that RuntimeErrorException
can
* also be thrown by preRegister
, in which case the MBean
* will not be registered.
@@ -297,19 +297,19 @@
* MBean will not be registered.
* @exception RuntimeMBeanException If the postRegister
* (MBeanRegistration
interface) method of the MBean throws a
- * RuntimeException
, the createMBean method will
+ * RuntimeException
, the createMBean
method will
* throw a RuntimeMBeanException
, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
- * registered even though the createMBean method
+ * registered even though the createMBean
method
* threw an exception. Note that RuntimeMBeanException
can
* also be thrown by preRegister
, in which case the MBean
* will not be registered.
* @exception RuntimeErrorException If the postRegister
method
* (MBeanRegistration
interface) method of the MBean throws an
- * Error
, the createMBean method will
+ * Error
, the createMBean
method will
* throw a RuntimeErrorException
, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
- * registered even though the createMBean method
+ * registered even though the createMBean
method
* threw an exception. Note that RuntimeErrorException
can
* also be thrown by preRegister
, in which case the MBean
* will not be registered.
@@ -351,19 +351,19 @@
* has thrown an exception.
* @exception RuntimeMBeanException If the postDeregister
* (MBeanRegistration
interface) method of the MBean throws a
- * RuntimeException
, the unregisterMBean method
+ * RuntimeException
, the unregisterMBean
method
* will throw a RuntimeMBeanException
, although the MBean
* unregistration succeeded. In such a case, the MBean will be actually
- * unregistered even though the unregisterMBean method
+ * unregistered even though the unregisterMBean
method
* threw an exception. Note that RuntimeMBeanException
can
* also be thrown by preDeregister
, in which case the MBean
* will remain registered.
* @exception RuntimeErrorException If the postDeregister
* (MBeanRegistration
interface) method of the MBean throws an
- * Error
, the unregisterMBean method will
+ * Error
, the unregisterMBean
method will
* throw a RuntimeErrorException
, although the MBean
* unregistration succeeded. In such a case, the MBean will be actually
- * unregistered even though the unregisterMBean method
+ * unregistered even though the unregisterMBean
method
* threw an exception. Note that RuntimeMBeanException
can
* also be thrown by preDeregister
, in which case the MBean
* will remain registered.
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/MBeanServerDelegate.java
--- a/jdk/src/share/classes/javax/management/MBeanServerDelegate.java Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/src/share/classes/javax/management/MBeanServerDelegate.java Thu Sep 04 14:55:12 2008 -0700
@@ -25,7 +25,9 @@
package javax.management;
+import com.sun.jmx.defaults.JmxProperties;
import com.sun.jmx.defaults.ServiceName;
+import com.sun.jmx.mbeanserver.Util;
/**
* Represents the MBean server from the management point of view.
@@ -39,6 +41,7 @@
/** The MBean server agent identification.*/
private String mbeanServerId ;
+ private String mbeanServerName;
/** The NotificationBroadcasterSupport object that sends the
notifications */
@@ -68,6 +71,7 @@
public MBeanServerDelegate () {
stamp = getStamp();
broadcaster = new NotificationBroadcasterSupport() ;
+ mbeanServerName=null;
}
@@ -82,14 +86,103 @@
try {
localHost = java.net.InetAddress.getLocalHost().getHostName();
} catch (java.net.UnknownHostException e) {
+ JmxProperties.MISC_LOGGER.finest("Can't get local host name, " +
+ "using \"localhost\" instead. Cause is: "+e);
localHost = "localhost";
}
- mbeanServerId = localHost + "_" + stamp;
+ mbeanServerId =
+ Util.insertMBeanServerName(localHost + "_" + stamp,
+ mbeanServerName);
}
return mbeanServerId;
}
/**
+ * The name of the MBeanServer.
+ * @return The name of the MBeanServer, or {@value
+ * javax.management.MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if no
+ * name was specified.
+ *
+ * @since 1.7
+ * @see #setMBeanServerName
+ */
+ public synchronized String getMBeanServerName() {
+ if (Util.isMBeanServerNameUndefined(mbeanServerName))
+ return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME;
+ return mbeanServerName;
+ }
+
+ /**
+ * Sets the name of the MBeanServer. The name will be embedded into the
+ * {@link #getMBeanServerId MBeanServerId} using the following format:
+ * {@code mbeanServerId: ;mbeanServerName=}
+ * The characters {@code ':'} (colon), {@code ';'} (semicolon ),
+ * {@code '*'} (star) and {@code '?'} (question mark) are not legal in an
+ * MBean Server name.
+ * For instance, if the {@code mbeanServerName} provided is
+ * {@code "com.mycompany.myapp.server1"}, and the original
+ * {@code MBeanServerId} was {@code "myhost_1213353064145"},
+ * then {@code mbeanServerName} will be
+ * embedded in the {@code MBeanServerId} - and the new value of the
+ * {@code MBeanServerId} will be:
+ *
+ *
+ * "myhost_1213353064145;mbeanServerName=com.mycompany.myapp.server1"
+ *
+ * Note: The {@code mbeanServerName} is usually set by the
+ * {@code MBeanServerFactory}. It is set only once, before the
+ * MBean Server is returned by the factory. Once the MBean Server name is
+ * set, it is not possible to change it.
+ *
+ * @param mbeanServerName The MBeanServer name.
+ * @throws IllegalArgumentException if the MBeanServerName is already set
+ * to a different value, or if the provided name contains
+ * illegal characters, or if the provided name is {@code ""}
+ * (the empty string) or "-" (dash).
+ * @throws UnsupportedOperationException if this object is of a legacy
+ * subclass of MBeanServerDelegate which overrides {@link
+ * #getMBeanServerId()}
+ * in a way that doesn't support setting an MBeanServer name.
+ * @see MBeanServerFactory#getMBeanServerName
+ * @since 1.7
+ */
+ public synchronized void setMBeanServerName(String mbeanServerName) {
+ // Sets the name on the delegate. For complex backward
+ // compatibility reasons it is not possible to give the
+ // name to the MBeanServerDelegate constructor.
+ //
+ // The method setMBeanServerName() will call getMBeanServerId()
+ // to check that the name is accurately set in the MBeanServerId.
+ // If not (which could happen if a custom MBeanServerDelegate
+ // implementation overrides getMBeanServerId() and was not updated
+ // with respect to JMX 2.0 spec), this method will throw an
+ // IllegalStateException...
+
+ // will fail if mbeanServerName is illegal
+ final String name = Util.checkServerName(mbeanServerName);
+
+ // can only set mbeanServerDelegate once.
+ if (this.mbeanServerName != null && !this.mbeanServerName.equals(name))
+ throw new IllegalArgumentException(
+ "MBeanServerName already set to a different value");
+
+ this.mbeanServerName = name;
+
+ // will fail if mbeanServerId already has a different mbeanServerName
+ mbeanServerId =
+ Util.insertMBeanServerName(getMBeanServerId(),name);
+
+ // check that we don't have a subclass which overrides
+ // getMBeanServerId() without setting mbeanServerName
+ if (!name.equals(
+ Util.extractMBeanServerName(getMBeanServerId())))
+ throw new UnsupportedOperationException(
+ "Can't set MBeanServerName in MBeanServerId - " +
+ "unsupported by "+this.getClass().getName()+"?");
+ // OK: at this point we know that we have correctly set mbeanServerName.
+ }
+
+ /**
* Returns the full name of the JMX specification implemented
* by this product.
*
@@ -210,15 +303,8 @@
*
* @since 1.6
*/
- public static final ObjectName DELEGATE_NAME;
- static {
- try {
- DELEGATE_NAME =
- new ObjectName("JMImplementation:type=MBeanServerDelegate");
- } catch (MalformedObjectNameException e) {
- throw new Error("Can't initialize delegate name", e);
- }
- }
+ public static final ObjectName DELEGATE_NAME =
+ Util.newObjectName("JMImplementation:type=MBeanServerDelegate");
/* Return a timestamp that is monotonically increasing even if
System.currentTimeMillis() isn't (for example, if you call this
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/MBeanServerFactory.java
--- a/jdk/src/share/classes/javax/management/MBeanServerFactory.java Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/src/share/classes/javax/management/MBeanServerFactory.java Thu Sep 04 14:55:12 2008 -0700
@@ -25,16 +25,19 @@
package javax.management;
+import com.sun.jmx.defaults.JmxProperties;
import static com.sun.jmx.defaults.JmxProperties.JMX_INITIAL_BUILDER;
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
-import com.sun.jmx.interceptor.DefaultMBeanServerInterceptor;
import com.sun.jmx.mbeanserver.GetPropertyAction;
+import com.sun.jmx.mbeanserver.Util;
import java.security.AccessController;
import java.security.Permission;
import java.util.ArrayList;
+import java.util.List;
import java.util.logging.Level;
import javax.management.loading.ClassLoaderRepository;
+
/**
* Provides MBean server references. There are no instances of
* this class.
@@ -80,10 +83,53 @@
* returned by the default MBeanServerBuilder implementation, for the purpose
* of e.g. adding an additional security layer.
*
+ * Since version 2.0 of the JMX API, when creating
+ * an MBeanServer,
+ * it is possible to specify an {@linkplain #getMBeanServerName
+ * MBean Server name}.
+ * To create an MBean Server with a name, the MBeanServerFactory provides two
+ * new methods:
+ * - {@link #createNamedMBeanServer
+ * createNamedMBeanServer(mbeanServerName, defaultDomain)}: creates a named
+ * MBeanServer and keeps an internal reference to the created object. The
+ * MBeanServer can be later retrieved using {@link #findMBeanServer
+ * findMBeanServer(mbeanServerId)} or
+ * {@link #findMBeanServerByName findMBeanServerByName(mbeanServerName)}, and
+ * can be released through {@link
+ * #releaseMBeanServer releaseMBeanServer(mbeanServer)}.
+ * - {@link #newNamedMBeanServer
+ * newNamedMBeanServer(mbeanServerName, defaultDomain)}:
+ * creates a named MBeanServer without keeping any internal reference to the
+ * named server.
+ *
+ * The name of the MBeanServer is stored in the
+ * {@linkplain MBeanServerDelegate MBean Server delegate MBean}
+ * and is embedded in its {@link MBeanServerDelegate#getMBeanServerId
+ * MBeanServerId} attribute.
+ * The name of the MBeanServer is particularly useful when
+ * MBean permissions are checked:
+ * it makes it
+ * possible to distinguish between an MBean named "X" in MBeanServer named
+ * "M1", and another MBean of the same name "X" in another MBeanServer named
+ * "M2".
+ * When naming MBean servers it is recommended to use a name that starts
+ * with a Java package name. It is also recommended that the default domain and
+ * the MBeanServer name be the same.
+ *
* @since 1.5
*/
public class MBeanServerFactory {
+ /**
+ * The MBean Server name that will be
+ * checked by a permission you need
+ * when checking access to an MBean registered in an MBeanServer for
+ * which no MBeanServer name was specified.
+ *
+ * @since 1.7
+ */
+ public final static String DEFAULT_MBEANSERVER_NAME = "default";
+
/*
* There are no instances of this class so don't generate the
* default public constructor.
@@ -222,13 +268,78 @@
* javax.management.builder.initial
exists and can be
* instantiated but is not assignment compatible with {@link
* MBeanServerBuilder}.
+ *
+ * @see #createNamedMBeanServer
*/
public static MBeanServer createMBeanServer(String domain) {
- checkPermission("createMBeanServer");
+ return createMBeanServer(null,domain);
+ }
- final MBeanServer mBeanServer = newMBeanServer(domain);
- addMBeanServer(mBeanServer);
- return mBeanServer;
+ /**
+ * Return a new object implementing the {@link MBeanServer}
+ * interface with the specified
+ * MBean Server name
+ * and default domain name. The given MBean server name
+ * is used in security checks, and
+ * can also be used to {@linkplain #findMBeanServerByName(java.lang.String)
+ * find an MBeanServer by name}. The given
+ * domain name is used as the domain part in the ObjectName of
+ * MBeans when the domain is specified by the user is null.
+ *
+ * The MBeanServer reference is internally kept. This will
+ * allow findMBeanServer
to return a reference to
+ * this MBeanServer object.
+ *
+ * @param mbeanServerName the name for the created
+ * MBeanServer. This is the name that will be included in the
+ * {@linkplain MBeanPermission permission you need} when checking
+ * MBean Permissions for accessing
+ * an MBean registered in the returned MBeanServer. The characters
+ * {@code ':'} (colon), {@code ';'} (semicolon), {@code '*'} (star)
+ * and {@code '?'} are not legal.
+ * It is recommended that the {@code mbeanServerName}
+ * be unique in the context of a JVM, and in the form of a java package
+ * identifier. If {@code mbeanServerName} is {@code null} then the created
+ * MBean Server has no name - and {@value #DEFAULT_MBEANSERVER_NAME} is used.
+ * Calling {@code createNamedMBeanServer(null,domain)} is equivalent
+ * to calling {@link #createMBeanServer(String) createMBeanServer(domain)}.
+ *
+ * @param domain the default domain name for the created
+ * MBeanServer. This is the value that will be returned by {@link
+ * MBeanServer#getDefaultDomain}. If a non null mbeanServerName is given,
+ * it is recommended to pass the same value as default domain.
+ *
+ * @return the newly created MBeanServer.
+ *
+ * @exception SecurityException if there is a SecurityManager and
+ * the caller's permissions do not include or imply {@link
+ * MBeanServerPermission}("createMBeanServer")
.
+ *
+ * @exception JMRuntimeException if the property
+ * javax.management.builder.initial
exists but the
+ * class it names cannot be instantiated through a public
+ * no-argument constructor; or if the instantiated builder returns
+ * null from its {@link MBeanServerBuilder#newMBeanServerDelegate
+ * newMBeanServerDelegate} or {@link
+ * MBeanServerBuilder#newMBeanServer newMBeanServer} methods.
+ *
+ * @exception ClassCastException if the property
+ * javax.management.builder.initial
exists and can be
+ * instantiated but is not assignment compatible with {@link
+ * MBeanServerBuilder}.
+ *
+ * @exception IllegalArgumentException if the specified
+ * {@code mbeanServerName} is empty, or is {@code "-"}, or contains a
+ * character which is not legal.
+ *
+ * @exception UnsupportedOperationException if the specified
+ * {@code mbeanServerName} cannot be set.
+ *
+ * @since 1.7
+ */
+ public static MBeanServer createNamedMBeanServer(String mbeanServerName,
+ String domain) {
+ return createMBeanServer(mbeanServerName, domain);
}
/**
@@ -307,6 +418,88 @@
* MBeanServerBuilder}.
*/
public static MBeanServer newMBeanServer(String domain) {
+ return newMBeanServer(null,domain);
+ }
+
+ /**
+ * Return a new object implementing the MBeanServer interface
+ * with the specified MBean server name
+ * and default domain name, without keeping an
+ * internal reference to this new object. The given MBean server name
+ * is used in security checks.
+ * The given domain name
+ * is used as the domain part in the ObjectName of MBeans when the
+ * domain is specified by the user is null.
+ *
+ * No reference is kept. findMBeanServer
and
+ * findMBeanServerByName
will not
+ * be able to return a reference to this MBeanServer object, but
+ * the garbage collector will be able to remove the MBeanServer
+ * object when it is no longer referenced.
+ *
+ * @param mbeanServerName the name for the created
+ * MBeanServer. This is the name that will be included in the
+ * {@linkplain MBeanPermission permission you need} when checking
+ * MBean Permissions for accessing
+ * an MBean registered in the returned MBeanServer. The characters
+ * {@code ':'} (colon), {@code ';'} (semicolon), {@code '*'} (star)
+ * and {@code '?'} are not legal.
+ * It is recommended that the mbeanServerName
+ * be unique in the context of a JVM, and in the form of a java package
+ * identifier. If {@code mbeanServerName} is {@code null} then the created
+ * MBean Server has no name - and {@value #DEFAULT_MBEANSERVER_NAME} is used.
+ * Calling {@code newNamedMBeanServer(null,domain)} is equivalent
+ * to calling {@link #newMBeanServer(String) newMBeanServer(domain)}.
+ *
+ * @param domain the default domain name for the created
+ * MBeanServer. This is the value that will be returned by {@link
+ * MBeanServer#getDefaultDomain}.
+ *
+ * @return the newly created MBeanServer.
+ *
+ * @exception SecurityException if there is a SecurityManager and the
+ * caller's permissions do not include or imply {@link
+ * MBeanServerPermission}("newMBeanServer")
.
+ *
+ * @exception JMRuntimeException if the property
+ * javax.management.builder.initial
exists but the
+ * class it names cannot be instantiated through a public
+ * no-argument constructor; or if the instantiated builder returns
+ * null from its {@link MBeanServerBuilder#newMBeanServerDelegate
+ * newMBeanServerDelegate} or {@link
+ * MBeanServerBuilder#newMBeanServer newMBeanServer} methods.
+ *
+ * @exception ClassCastException if the property
+ * javax.management.builder.initial
exists and can be
+ * instantiated but is not assignment compatible with {@link
+ * MBeanServerBuilder}.
+ *
+ * @exception IllegalArgumentException if the specified
+ * {@code mbeanServerName} is empty, or is {@code "-"},
+ * or contains a character which is not legal.
+ *
+ * @exception UnsupportedOperationException if the specified
+ * {@code mbeanServerName} cannot be set.
+ *
+ * @since 1.7
+ */
+ public static MBeanServer newNamedMBeanServer(String mbeanServerName,
+ String domain) {
+ return newMBeanServer(mbeanServerName, domain);
+ }
+
+ private static MBeanServer createMBeanServer(String mbeanServerName,
+ String domain) {
+ checkPermission("createMBeanServer");
+
+ final MBeanServer mBeanServer =
+ newMBeanServer(mbeanServerName,domain);
+ addMBeanServer(mBeanServer);
+ return mBeanServer;
+ }
+
+ private static MBeanServer newMBeanServer(String mbeanServerName,
+ String domain) {
checkPermission("newMBeanServer");
// Get the builder. Creates a new one if necessary.
@@ -316,20 +509,50 @@
synchronized(mbsBuilder) {
final MBeanServerDelegate delegate =
- mbsBuilder.newMBeanServerDelegate();
+ mbsBuilder.newMBeanServerDelegate();
if (delegate == null) {
final String msg =
- "MBeanServerBuilder.newMBeanServerDelegate() " +
- "returned null";
+ "MBeanServerBuilder.newMBeanServerDelegate() " +
+ "returned null";
throw new JMRuntimeException(msg);
}
+
+ // Sets the name on the delegate. For complex backward
+ // compatibility reasons it is not possible to give the
+ // name to the MBeanServerDelegate constructor.
+ //
+ // The method setMBeanServerName() will call getMBeanServerId()
+ // to check that the name is accurately set in the MBeanServerId.
+ // If not (which could happen if a custom MBeanServerDelegate
+ // implementation overrides getMBeanServerId() and was not updated
+ // with respect to JMX 2.0 spec, this method will throw an
+ // IllegalStateException...
+ //
+ if (!Util.isMBeanServerNameUndefined(mbeanServerName)) {
+ delegate.setMBeanServerName(mbeanServerName);
+ }
+
final MBeanServer mbeanServer =
- mbsBuilder.newMBeanServer(domain,null,delegate);
+ mbsBuilder.newMBeanServer(domain,null,delegate);
if (mbeanServer == null) {
final String msg =
- "MBeanServerBuilder.newMBeanServer() returned null";
+ "MBeanServerBuilder.newMBeanServer() returned null";
throw new JMRuntimeException(msg);
}
+
+ // double check that the MBeanServer name is correctly set.
+ // "*" might mean that the caller doesn't have the permission
+ // to see the MBeanServer name.
+ //
+ final String mbsName = Util.getMBeanServerSecurityName(mbeanServer);
+ if (!mbsName.equals(Util.checkServerName(mbeanServerName))
+ && !mbsName.equals("*")) {
+ throw new UnsupportedOperationException(
+ "can't create MBeanServer with name \""+
+ mbeanServerName+"\" using "+
+ builder.getClass().getName());
+ }
+
return mbeanServer;
}
}
@@ -363,7 +586,7 @@
ArrayList result = new ArrayList();
for (MBeanServer mbs : mBeanServerList) {
- String name = mBeanServerName(mbs);
+ String name = mBeanServerId(mbs);
if (agentId.equals(name))
result.add(mbs);
}
@@ -371,8 +594,99 @@
}
/**
+ * Returns a list of registered MBeanServer objects with the given name. A
+ * registered MBeanServer object is one that was created by one of
+ * the createMBeanServer
or createNamedMBeanServer
+ * methods and not subsequently released with releaseMBeanServer
.
+ * See the section about MBean Server names
+ * above.
+ *
+ * @param mbeanServerName The name of the MBeanServer to
+ * retrieve. If this parameter is null, all registered MBeanServers
+ * in this JVM are returned.
+ * Otherwise, only those MBeanServers that have a name
+ * matching mbeanServerName
are returned: this
+ * parameter can be a pattern, where {@code '*'} matches any
+ * sequence of characters and {@code '?'} matches any character.
+ * The name of an MBeanServer, if specified, is embedded in the
+ * MBeanServerId
attribute of its delegate MBean:
+ * this method will parse the MBeanServerId
to get the
+ * MBeanServer name. If this parameter is equal to {@code "*"} then
+ * all registered MBeanServers in this JVM are returned, whether they have
+ * a name or not: {@code findMBeanServerByName(null)},
+ * {@code findMBeanServerByName("*")} and {@code findMBeanServer(null)},
+ * are equivalent. It is also possible to get all MBeanServers for which
+ * no name was specified by calling findMBeanServerByName({@value
+ * #DEFAULT_MBEANSERVER_NAME})
.
+ *
+ * @return A list of MBeanServer objects.
+ *
+ * @exception SecurityException if there is a SecurityManager and the
+ * caller's permissions do not include or imply {@link
+ * MBeanServerPermission}("findMBeanServer")
.
+ *
+ * @see #getMBeanServerName(MBeanServer)
+ * @since 1.7
+ */
+ public synchronized static
+ List findMBeanServerByName(String mbeanServerName) {
+
+ checkPermission("findMBeanServer");
+
+ if (mbeanServerName==null || "*".equals(mbeanServerName))
+ return new ArrayList(mBeanServerList);
+
+ // noname=true iff we are looking for MBeanServers for which no name
+ // were specified.
+ ArrayList result = new ArrayList();
+ for (MBeanServer mbs : mBeanServerList) {
+ final String name = Util.getMBeanServerSecurityName(mbs);
+ if (Util.wildmatch(name, mbeanServerName)) result.add(mbs);
+ }
+ return result;
+ }
+
+ /**
+ * Returns the name of the MBeanServer embedded in the MBeanServerId of
+ * the given {@code server}. If the given MBeanServerId doesn't contain
+ * any name, {@value #DEFAULT_MBEANSERVER_NAME} is returned.
+ * The MBeanServerId is expected to be of the form:
+ * {@code *[;mbeanServerName=[;*]]}
+ *
where {@code *} denotes any sequence of characters, and {@code [ ]}
+ * indicate optional parts.
+ *
+ * For instance, if an MBeanServer is created using {@link
+ * #createNamedMBeanServer(java.lang.String, java.lang.String)
+ * server =
+ * MBeanServerFactory.createNamedMBeanServer("com.mycompany.myapp.server1",
+ * null)} then {@code MBeanServerFactory.getMBeanServerName(server)}
+ * will return {@code "com.mycompany.myapp.server1"} and
+ * server.getAttribute({@link
+ * javax.management.MBeanServerDelegate#DELEGATE_NAME
+ * MBeanServerDelegate.DELEGATE_NAME}, "MBeanServerId")
will return
+ * something like
+ * {@code "myhost_1213353064145;mbeanServerName=com.mycompany.myapp.server1"}.
+ *
+ * See the section about MBean Server names
+ * above.
+ * @param server A named (or unnamed) MBeanServer.
+ * @return the name of the MBeanServer if found, or
+ * {@value #DEFAULT_MBEANSERVER_NAME} if no name is
+ * present in its MBeanServerId, or "*" if its
+ * MBeanServerId couldn't be obtained. Returning "*" means that
+ * only {@link MBeanPermission}s that allow all MBean Server names
+ * will apply to this MBean Server.
+ * @see MBeanServerDelegate
+ * @since 1.7
+ */
+ public static String getMBeanServerName(MBeanServer server) {
+ return Util.getMBeanServerSecurityName(server);
+ }
+
+ /**
* Return the ClassLoaderRepository used by the given MBeanServer.
- * This method is equivalent to {@link MBeanServer#getClassLoaderRepository() server.getClassLoaderRepository()}.
+ * This method is equivalent to {@link
+ * MBeanServer#getClassLoaderRepository() server.getClassLoaderRepository()}.
* @param server The MBeanServer under examination. Since JMX 1.2,
* if server
is null
, the result is a
* {@link NullPointerException}. This behavior differs from what
@@ -387,21 +701,23 @@
*
**/
public static ClassLoaderRepository getClassLoaderRepository(
- MBeanServer server) {
+ MBeanServer server) {
return server.getClassLoaderRepository();
}
- private static String mBeanServerName(MBeanServer mbs) {
+ private static String mBeanServerId(MBeanServer mbs) {
try {
return (String) mbs.getAttribute(MBeanServerDelegate.DELEGATE_NAME,
- "MBeanServerId");
+ "MBeanServerId");
} catch (JMException e) {
+ JmxProperties.MISC_LOGGER.finest(
+ "Ignoring exception while getting MBeanServerId: "+e);
return null;
}
}
private static void checkPermission(String action)
- throws SecurityException {
+ throws SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
Permission perm = new MBeanServerPermission(action);
@@ -425,16 +741,16 @@
}
private static final ArrayList mBeanServerList =
- new ArrayList();
+ new ArrayList();
/**
* Load the builder class through the context class loader.
* @param builderClassName The name of the builder class.
**/
private static Class loadBuilderClass(String builderClassName)
- throws ClassNotFoundException {
+ throws ClassNotFoundException {
final ClassLoader loader =
- Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().getContextClassLoader();
if (loader != null) {
// Try with context class loader
@@ -453,14 +769,14 @@
**/
private static MBeanServerBuilder newBuilder(Class builderClass) {
try {
- final Object builder = builderClass.newInstance();
- return (MBeanServerBuilder)builder;
+ final Object abuilder = builderClass.newInstance();
+ return (MBeanServerBuilder)abuilder;
} catch (RuntimeException x) {
throw x;
} catch (Exception x) {
final String msg =
- "Failed to instantiate a MBeanServerBuilder from " +
- builderClass + ": " + x;
+ "Failed to instantiate a MBeanServerBuilder from " +
+ builderClass + ": " + x;
throw new JMRuntimeException(msg, x);
}
}
@@ -472,7 +788,7 @@
private static synchronized void checkMBeanServerBuilder() {
try {
GetPropertyAction act =
- new GetPropertyAction(JMX_INITIAL_BUILDER);
+ new GetPropertyAction(JMX_INITIAL_BUILDER);
String builderClassName = AccessController.doPrivileged(act);
try {
@@ -493,8 +809,8 @@
builder = newBuilder(newBuilderClass);
} catch (ClassNotFoundException x) {
final String msg =
- "Failed to load MBeanServerBuilder class " +
- builderClassName + ": " + x;
+ "Failed to load MBeanServerBuilder class " +
+ builderClassName + ": " + x;
throw new JMRuntimeException(msg, x);
}
} catch (RuntimeException x) {
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/MXBean.java
--- a/jdk/src/share/classes/javax/management/MXBean.java Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/src/share/classes/javax/management/MXBean.java Thu Sep 04 14:55:12 2008 -0700
@@ -469,8 +469,8 @@
J, then J cannot be the type of a method
parameter or return value in an MXBean interface.
- If there is a way to convert opendata(J) back to
- J then we say that J is
+
If there is a way to convert
+ opendata(J) back to J then we say that J is
reconstructible. All method parameters in an MXBean
interface must be reconstructible, because when the MXBean
framework is invoking a method it will need to convert those
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/ObjectName.java
--- a/jdk/src/share/classes/javax/management/ObjectName.java Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/src/share/classes/javax/management/ObjectName.java Thu Sep 04 14:55:12 2008 -0700
@@ -27,6 +27,8 @@
import com.sun.jmx.mbeanserver.GetPropertyAction;
import com.sun.jmx.mbeanserver.Util;
+import com.sun.jmx.namespace.serial.JMXNamespaceContext;
+
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
@@ -223,6 +225,17 @@
public class ObjectName implements Comparable, QueryExp {
/**
+ * The sequence of characters used to separate name spaces in a name space
+ * path.
+ *
+ * @see javax.management.namespace
+ * @since 1.7
+ **/
+ public static final String NAMESPACE_SEPARATOR = "//";
+ private static final int NAMESPACE_SEPARATOR_LENGTH =
+ NAMESPACE_SEPARATOR.length();
+
+ /**
* A structure recording property structure and
* proposing minimal services
*/
@@ -251,16 +264,17 @@
/**
* Returns a key string for receiver key
*/
- String getKeyString(String name) {
- return name.substring(_key_index, _key_index + _key_length);
+ String getKeyString(String name, int offset) {
+ final int start = _key_index+offset;
+ return name.substring(start, start + _key_length);
}
/**
* Returns a value string for receiver key
*/
- String getValueString(String name) {
- int in_begin = _key_index + _key_length + 1;
- int out_end = in_begin + _value_length;
+ String getValueString(String name, int offset) {
+ final int in_begin = _key_index + offset + _key_length + 1;
+ final int out_end = in_begin + _value_length;
return name.substring(in_begin, out_end);
}
}
@@ -393,6 +407,45 @@
*/
private transient boolean _property_value_pattern = false;
+ private ObjectName(String newDomain, ObjectName aname)
+ throws MalformedObjectNameException{
+ copyToOtherDomain(newDomain,aname);
+ }
+
+ private void copyToOtherDomain(String domain, ObjectName aname)
+ throws MalformedObjectNameException, NullPointerException {
+
+ // The domain cannot be null
+ if (domain == null)
+ throw new NullPointerException("domain cannot be null");
+
+ // The key property list cannot be null
+ if (aname == null)
+ throw new MalformedObjectNameException(
+ "key property list cannot be empty");
+
+ // checks domain validity. A side effect of this method is also to
+ // set the _domain_pattern flag.
+ if (!isDomain(domain))
+ throw new MalformedObjectNameException("Invalid domain: " + domain);
+
+ // init canonicalname
+ _domain_length = domain.length();
+
+ _canonicalName = (domain +
+ aname._canonicalName.substring(aname._domain_length)).intern();
+ _kp_array = aname._kp_array;
+ _ca_array = aname._ca_array;
+ _propertyList = aname._propertyList;
+ _property_list_pattern = aname._property_list_pattern;
+ _property_value_pattern = aname._property_value_pattern;
+ // TODO remove this hack
+ // if (toString().endsWith("//javax.management.service:type1=event_client_delegeate_mbean,type2=default")) {
+ // Thread.currentThread().dumpStack();
+ // throw new Error("************************ Gotcha!");
+ //}
+ }
+
// Instance private fields <=======================================
// Private fields <========================================
@@ -435,10 +488,10 @@
}
// initialize parsing of the string
- char[] name_chars = name.toCharArray();
- int len = name_chars.length;
- char[] canonical_chars = new char[len]; // canonical form will be same
- // length at most
+ final char[] name_chars = name.toCharArray();
+ final int len = name_chars.length;
+ final char[] canonical_chars = new char[len]; // canonical form will
+ // be same length at most
int cname_index = 0;
int index = 0;
char c, c1;
@@ -637,10 +690,12 @@
// we got the key and value part, prepare a property for this
if (!value_pattern) {
- prop = new Property(key_index, key_length, value_length);
+ prop = new Property(key_index-_domain_length,
+ key_length, value_length);
} else {
_property_value_pattern = true;
- prop = new PatternProperty(key_index, key_length, value_length);
+ prop = new PatternProperty(key_index-_domain_length,
+ key_length, value_length);
}
key_name = name.substring(key_index, key_index + key_length);
@@ -725,12 +780,12 @@
boolean value_pattern = checkValue(value);
sb.append(value);
if (!value_pattern) {
- prop = new Property(key_index,
+ prop = new Property(key_index-_domain_length,
key.length(),
value.length());
} else {
_property_value_pattern = true;
- prop = new PatternProperty(key_index,
+ prop = new PatternProperty(key_index-_domain_length,
key.length(),
value.length());
}
@@ -810,9 +865,9 @@
prop = _ca_array[i];
// length of prop including '=' char
prop_len = prop._key_length + prop._value_length + 1;
- System.arraycopy(specified_chars, prop._key_index,
+ System.arraycopy(specified_chars, prop._key_index+_domain_length,
canonical_chars, prop_index, prop_len);
- prop.setKeyIndex(prop_index);
+ prop.setKeyIndex(prop_index-_domain_length);
prop_index += prop_len;
if (i != last_index) {
canonical_chars[prop_index] = ',';
@@ -1031,33 +1086,6 @@
k[endKey] + "'");
}
- /*
- * Tests whether string s is matched by pattern p.
- * Supports "?", "*" each of which may be escaped with "\";
- * Not yet supported: internationalization; "\" inside brackets.
- * Wildcard matching routine by Karl Heuer. Public Domain.
- */
- private static boolean wildmatch(char[] s, char[] p, int si, int pi) {
- char c;
- final int slen = s.length;
- final int plen = p.length;
-
- while (pi < plen) { // While still string
- c = p[pi++];
- if (c == '?') {
- if (++si > slen) return false;
- } else if (c == '*') { // Wildcard
- if (pi >= plen) return true;
- do {
- if (wildmatch(s,p,si,pi)) return true;
- } while (++si < slen);
- return false;
- } else {
- if (si >= slen || c != s[si++]) return false;
- }
- }
- return (si == slen);
- }
// Category : Internal utilities <==============================
@@ -1177,15 +1205,43 @@
cn = (String)in.readObject();
}
+ final JMXNamespaceContext ctxt =
+ JMXNamespaceContext.getDeserializationContext();
try {
- construct(cn);
+ construct(changeContext(ctxt,cn));
} catch (NullPointerException e) {
throw new InvalidObjectException(e.toString());
+ } catch (IllegalArgumentException e) {
+ throw new InvalidObjectException(e.toString());
} catch (MalformedObjectNameException e) {
throw new InvalidObjectException(e.toString());
}
}
+ private String changeContext(JMXNamespaceContext context, String nameString) {
+ final String old = context.prefixToRemove;
+ final String nw = context.prefixToAdd;
+ final int ol = old.length();
+ if (nameString.startsWith(NAMESPACE_SEPARATOR)) return nameString;
+ if (ol>0) {
+ if (!nameString.startsWith(old) ||
+ !nameString.startsWith(NAMESPACE_SEPARATOR,ol))
+ throw new IllegalArgumentException(
+ "Serialized ObjectName does not start with " + old +
+ ": " + nameString);
+ nameString = nameString.substring(ol+NAMESPACE_SEPARATOR_LENGTH);
+ }
+ if (!nw.equals("")) {
+ nameString = nw + NAMESPACE_SEPARATOR + nameString;
+ }
+ // TODO remove this hack
+ // if (nameString.endsWith("//javax.management.service:type1=event_client_delegeate_mbean,type2=default")) {
+ // System.err.println("old="+old+", nw="+nw);
+ // Thread.currentThread().dumpStack();
+ // throw new Error("************************ Gotcha!");
+ // }
+ return nameString;
+ }
/**
* Serializes an {@link ObjectName} to an {@link ObjectOutputStream}.
@@ -1248,15 +1304,22 @@
private void writeObject(ObjectOutputStream out)
throws IOException {
+ final JMXNamespaceContext ctxt =
+ JMXNamespaceContext.getSerializationContext();
+
if (compat)
{
// Serializes this instance in the old serial form
// Read CR 6441274 before making any changes to this code
ObjectOutputStream.PutField fields = out.putFields();
- fields.put("domain", _canonicalName.substring(0, _domain_length));
+ final String domain =
+ changeContext(ctxt,_canonicalName.substring(0, _domain_length));
+ final String cn =
+ changeContext(ctxt,_canonicalName);
+ fields.put("domain", domain);
fields.put("propertyList", getKeyPropertyList());
fields.put("propertyListString", getKeyPropertyListString());
- fields.put("canonicalName", _canonicalName);
+ fields.put("canonicalName", cn);
fields.put("pattern", (_domain_pattern || _property_list_pattern));
fields.put("propertyPattern", _property_list_pattern);
out.writeFields();
@@ -1266,7 +1329,8 @@
// Serializes this instance in the new serial form
//
out.defaultWriteObject();
- out.writeObject(getSerializedNameString());
+
+ out.writeObject(changeContext(ctxt,getSerializedNameString()));
}
}
@@ -1397,6 +1461,27 @@
}
/**
+ * Returns an {@code ObjectName} that is the same as this one but
+ * with the specified domain.
+ * This method preserves the original key order in the new instance.
+ * If the provided name has a key property pattern, it will also be
+ * preserved in the returned instance.
+ *
+ * @param newDomain The new domain for the returned instance;
+ * must not be null.
+ * @return A new {@code ObjectName} that is the same as {@code this}
+ * except the domain is {@code newDomain}.
+ * @throws NullPointerException if {@code newDomain} is null.
+ * @throws MalformedObjectNameException if the new domain is syntactically
+ * illegal.
+ * @since 1.7
+ **/
+ public final ObjectName withDomain(String newDomain)
+ throws NullPointerException, MalformedObjectNameException {
+ return new ObjectName(newDomain, this);
+ }
+
+ /**
* Construct an object name from the given string.
*
* @param name A string representation of the object name.
@@ -1550,7 +1635,7 @@
throw new NullPointerException("key property can't be null");
for (int i = 0; i < _ca_array.length; i++) {
Property prop = _ca_array[i];
- String key = prop.getKeyString(_canonicalName);
+ String key = prop.getKeyString(_canonicalName,_domain_length);
if (key.equals(property))
return (prop instanceof PatternProperty);
}
@@ -1630,8 +1715,10 @@
Property prop;
for (int i = len - 1; i >= 0; i--) {
prop = _ca_array[i];
- _propertyList.put(prop.getKeyString(_canonicalName),
- prop.getValueString(_canonicalName));
+ _propertyList.put(prop.getKeyString(_canonicalName,
+ _domain_length),
+ prop.getValueString(_canonicalName,
+ _domain_length));
}
}
}
@@ -1716,7 +1803,8 @@
}
}
- return new String(dest_chars);
+ final String name = new String(dest_chars);
+ return name;
}
/**
@@ -1734,7 +1822,7 @@
if (_kp_array.length == 0) return offset;
final char[] dest_chars = data;
- final char[] value = _canonicalName.toCharArray();
+ final char[] value = canonicalChars;
int index = offset;
final int len = _kp_array.length;
@@ -1742,7 +1830,7 @@
for (int i = 0; i < len; i++) {
final Property prop = _kp_array[i];
final int prop_len = prop._key_length + prop._value_length + 1;
- System.arraycopy(value, prop._key_index, dest_chars, index,
+ System.arraycopy(value, prop._key_index+_domain_length, dest_chars, index,
prop_len);
index += prop_len;
if (i < last ) dest_chars[index++] = ',';
@@ -1816,7 +1904,7 @@
// (because usage of intern())
ObjectName on = (ObjectName) object;
String on_string = on._canonicalName;
- if (_canonicalName == on_string) return true;
+ if (_canonicalName == on_string) return true; // ES: OK
// Because we are sharing canonical form between object names,
// we have finished the comparison at this stage ==> unequal
@@ -1997,9 +2085,9 @@
private final boolean matchDomains(ObjectName name) {
if (_domain_pattern) {
// wildmatch domains
- final char[] dom_pattern = getDomain().toCharArray();
- final char[] dom_string = name.getDomain().toCharArray();
- return wildmatch(dom_string,dom_pattern,0,0);
+ // This ObjectName is the pattern
+ // The other ObjectName is the string.
+ return Util.wildpathmatch(name.getDomain(),getDomain());
}
return getDomain().equals(name.getDomain());
}
@@ -2025,7 +2113,7 @@
// index in receiver
//
final Property p = props[i];
- final String k = p.getKeyString(cn);
+ final String k = p.getKeyString(cn,_domain_length);
final String v = nameProps.get(k);
// Did we find a value for this key ?
//
@@ -2034,15 +2122,13 @@
//
if (_property_value_pattern && (p instanceof PatternProperty)) {
// wildmatch key property values
- final char[] val_pattern =
- p.getValueString(cn).toCharArray();
- final char[] val_string = v.toCharArray();
- if (wildmatch(val_string,val_pattern,0,0))
+ // p is the property pattern, v is the string
+ if (Util.wildmatch(v,p.getValueString(cn,_domain_length)))
continue;
else
return false;
}
- if (v.equals(p.getValueString(cn))) continue;
+ if (v.equals(p.getValueString(cn,_domain_length))) continue;
return false;
}
return true;
@@ -2109,6 +2195,10 @@
* @since 1.6
*/
public int compareTo(ObjectName name) {
+ // Quick optimization:
+ //
+ if (name == this) return 0;
+
// (1) Compare domains
//
int domainValue = this.getDomain().compareTo(name.getDomain());
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/event/EventClient.java
--- a/jdk/src/share/classes/javax/management/event/EventClient.java Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/src/share/classes/javax/management/event/EventClient.java Thu Sep 04 14:55:12 2008 -0700
@@ -29,6 +29,7 @@
import com.sun.jmx.event.LeaseRenewer;
import com.sun.jmx.event.ReceiverBuffer;
import com.sun.jmx.event.RepeatedSingletonJob;
+import com.sun.jmx.namespace.JMXNamespaceUtils;
import com.sun.jmx.mbeanserver.PerThreadGroupPool;
import com.sun.jmx.remote.util.ClassLogger;
@@ -1063,6 +1064,24 @@
return clientId;
}
+ /**
+ * Returns a JMX Connector that will use an {@link EventClient}
+ * to subscribe for notifications. If the server doesn't have
+ * an {@link EventClientDelegateMBean}, then the connector will
+ * use the legacy notification mechanism instead.
+ *
+ * @param wrapped The underlying JMX Connector wrapped by the returned
+ * connector.
+ *
+ * @return A JMX Connector that will uses an {@link EventClient}, if
+ * available.
+ *
+ * @see EventClient#getEventClientConnection(MBeanServerConnection)
+ */
+ public static JMXConnector withEventClient(final JMXConnector wrapped) {
+ return JMXNamespaceUtils.withEventClient(wrapped);
+ }
+
private static final PerThreadGroupPool
leaseRenewerThreadPool = PerThreadGroupPool.make();
}
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/event/EventClientDelegate.java
--- a/jdk/src/share/classes/javax/management/event/EventClientDelegate.java Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/src/share/classes/javax/management/event/EventClientDelegate.java Thu Sep 04 14:55:12 2008 -0700
@@ -721,7 +721,10 @@
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
try {
- ObjectInstance oi = (ObjectInstance) AccessController.doPrivileged(
+ final String serverName = getMBeanServerName();
+
+ ObjectInstance oi = (ObjectInstance)
+ AccessController.doPrivileged(
new PrivilegedExceptionAction
+ *
+ * Note: A JMXNamespace MBean cannot be registered
+ * simultaneously in two different
+ * MBean servers, or indeed in the same MBean Server with two
+ * different names. It is however possible to give the same MBeanServer
+ * instance to two different JMXNamespace MBeans, and thus create a graph
+ * rather than a tree.
+ *
+ *
+ * To view the content of a namespace, you will usually use an
+ * instance of {@link JMXNamespaceView}. For instance, given the
+ * namespace {@code "foo"} created above, you would do:
+ *
+ *
+ * final JMXNamespaceView view = new JMXNamespaceView(server);
+ * System.out.println("List of namespaces: "+Arrays.toString({@link JMXNamespaceView#list() view.list()}));
+ *
+ * final JMXNamespaceView foo = {@link JMXNamespaceView#down view.down("foo")};
+ * System.out.println({@link JMXNamespaceView#where() foo.where()}+" contains: " +
+ * {@link JMXNamespaceView#getMBeanServerConnection foo.getMBeanServerConnection()}.queryNames(null,null));
+ *
+ *
+ * JMX Namespace Permission Checks
+ *
+ * A special {@link JMXNamespacePermission} is defined to check access
+ * to MBean within namespaces.
+ * When a JMXNamespace MBean is registered in an
+ * MBean server created through the default {@link
+ * javax.management.MBeanServerBuilder}, and if a {@link
+ * SecurityManager SecurityManager} is
+ * {@linkplain System#getSecurityManager() present}, the MBeanServer will
+ * check a {@link JMXNamespacePermission} before invoking
+ * any method on the {@linkplain #getSourceServer source MBeanServer} of the
+ * JMXNamespace.
+ * {@linkplain JMXNamespacePermission JMX Namespace Permissions} are similar to
+ * {@linkplain javax.management.MBeanPermission MBean Permissions}, except
+ * that you usually cannot specify an MBean class name. You can however
+ * specify object name patterns - which will allow you for example to only grant
+ * permissions for MBeans having a specific {@code type=} key
+ * in their object name.
+ *
+ * Another difference is that {@link JMXNamespacePermission
+ * JMXNamespacePermission} also specifies from which namespace and which
+ * MBean server the permission is granted.
+ *
+ * In the rest of this document, the following terms are used:
+ *
+ * {@code server name} is the
+ * name of the
+ * MBeanServer in which the permission is granted.
+ * The name of an {@code MBeanServer} can be obtained by calling {@link
+ * javax.management.MBeanServerFactory#getMBeanServerName
+ * MBeanServerFactory.getMBeanServerName(mbeanServer)}
+ *
+ * {@code namespace} is the name of the namespace
+ * in the named MBean server for which the
+ * permission is granted. It doesn't contain any
+ * {@link JMXNamespaces#NAMESPACE_SEPARATOR namespace separator}.
+ *
+ * {@code mbean} is the name
+ * of the MBean in that {@code namespace}. This is the name of the MBean
+ * in the namespace's {@link JMXNamespace#getSourceServer() source mbean server}.
+ * It might contain no, one, or several {@link
+ * JMXNamespaces#NAMESPACE_SEPARATOR namespace separators}.
+ *
+ *
+ *
+ * For instance let's assume that some piece of code calls:
+ *
+ * final MBeanServer mbeanServer = ...;
+ * final ObjectName name = new ObjectName("a//b//c//D:k=v");
+ * mbeanServer.getAttribute(name,"Foo");
+ *
+ *
+ * Assuming that there is a security manager, or that the
+ * implementation chooses to make checks anyway, the checks that will
+ * be made in that case are:
+ *
+ *
+ * -
+ *
JMXNamespacePermission(mbeanServerName, "Foo", "a//b//c//D:k=v",
+ * "getAttribute")
+ * (where {@code mbeanServerName=MBeanServerFactory.getMBeanServerName(mbeanServer)},
+ * namespace="a"
, and {@code mbean="b//c//D:k=v"})
+ *
+ * - and in addition if namespace {@code "a"} is local,
+ *
JMXNamespacePermission(aSourceServerName,"Foo","b//c//D:k=v",
+ * "getAttribute")}
+ * (where
+ * {@code aSourceServerName=MBeanServerFactory.getMBeanServerName(sourceServer(a))},
+ * namespace="b"
, and {@code mbean="c//D:k=v"}),
+ *
+ * - and in addition if namespace {@code "b"} is also local,
+ *
JMXNamespacePermission(bSourceServerName,"Foo","c//D:k=v",
+ * "getAttribute")}
+ * (where
+ * {@code bSourceServerName=MBeanServerFactory.getMBeanServerName(sourceServer(b))},
+ * namespace="c"
, and {@code mbean="D:k=v"}),
+ *
+ * - and in addition if the source mbean server of namespace
+ * {@code "c"} is a also a local MBeanServer in this JVM,
+ * {@code MBeanPermission(cSourceServerName,
,"Foo","D:k=v","getAttrinute")},
+ * (where
+ * {@code cSourceServerName=MBeanServerFactory.getMBeanServerName(sourceServer(c))}).
+ *
+ *
+ * For any of these MBean servers, if no name was supplied when
+ * creating that MBeanServer the {@link JMXNamespacePermission} is
+ * created with an {@code mbeanServerName} equal to
+ * {@value javax.management.MBeanServerFactory#DEFAULT_MBEANSERVER_NAME}.
+ *
+ * If the namespace {@code a} is in fact a remote {@code MBeanServer},
+ * for instance because namespace {@code a} is implemented by a {@link
+ * JMXRemoteNamespace} pointing to a distant MBeanServer located in
+ * another JMX agent, then checks 2,
+ * 3, and 4 will not
+ * be performed in the local JVM. They might or might not be performed in
+ * the remote agent, depending on how access control and permission
+ * checking are configured in the remote agent, and how authentication
+ * is configured in the connector used by the {@link
+ * JMXRemoteNamespace}.
+ *
+ * In all cases, {@linkplain JMXNamespacePermission JMX Namespace Permissions}
+ * are checked as follows:
+ * First, if there is no security manager ({@link
+ * System#getSecurityManager()} is null), then an implementation of
+ * of MBeanServer that supports JMX namespaces is free not to make any
+ * checks.
+ *
+ * Assuming that there is a security manager, or that the
+ * implementation chooses to make checks anyway, the checks are made
+ * as detailed below.
+ *
+ * If a security check fails, the method throws {@link
+ * SecurityException}.
+ *
+ *
+ *
+ * For the {@link MBeanServer#invoke invoke} method, the caller's
+ * permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, <operation name>, <namespace>//<mbean>, "invoke")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ *
+ *
+ * For the {@link MBeanServer#getAttribute getAttribute} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, <attribute>, <namespace>//<mbean>, "getAttribute")}.
+ *
+ *
+ * For the {@link MBeanServer#getAttributes getAttributes} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, <null>, <namespace>//<mbean>, "getAttribute")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ * Additionally, for each attribute att in the {@link
+ * javax.management.AttributeList}, if the caller's permissions do not
+ * imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, att,
+ * <namespace>//<mbean>, "getAttribute")}, the
+ * MBean server will behave as if that attribute had not been in the
+ * supplied list.
+ *
+ * For the {@link MBeanServer#setAttribute setAttribute} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, <attrName>, <namespace>//<mbean>, "setAttribute")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace, and
+ * attrName
is {@link javax.management.Attribute#getName()
+ * attribute.getName()}.
+ *
+ * For the {@link MBeanServer#setAttributes setAttributes} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>, "setAttribute")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ * Additionally, for each attribute att in the {@link
+ * javax.management.AttributeList}, if the caller's permissions do not
+ * imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, att, <namespace>//<mbean>, "setAttribute")},
+ * the MBean server will behave as if that attribute had not been in the
+ * supplied list.
+ *
+ * For the addNotificationListener
methods,
+ * the caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "addNotificationListener")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ *
+ *
+ * For the removeNotificationListener
methods,
+ * the caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "removeNotificationListener")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ *
+ *
+ * For the {@link MBeanServer#getMBeanInfo getMBeanInfo} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "getMBeanInfo")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ *
+ *
+ * For the {@link MBeanServer#getObjectInstance getObjectInstance} method,
+ * the caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "getObjectInstance")},
+ * where mbean server name/a> is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ *
+ *
+ * For the {@link MBeanServer#isInstanceOf isInstanceOf} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "isInstanceOf")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ *
+ *
+ * For the {@link MBeanServer#queryMBeans queryMBeans} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, null,
+ * "queryMBeans")}.
+ * Additionally, for each MBean {@code mbean} that matches {@code pattern},
+ * if the caller's permissions do not imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "queryMBeans")}, the
+ * MBean server will behave as if that MBean did not exist.
+ *
+ * Certain query elements perform operations on the MBean server.
+ * However these operations are usually performed by the MBeanServer at the
+ * bottom of the namespace path, and therefore, do not involve any
+ * {@link JMXNamespacePermission} permission check. They might involve
+ * {@link javax.management.MBeanPermission} checks depending on how security
+ * in the JVM in which the bottom MBeanServer resides is implemented.
+ * See {@link javax.management.MBeanServer} for more details.
+ *
+ *
+ * For the {@link MBeanServer#queryNames queryNames} method, the checks
+ * are the same as for queryMBeans
except that
+ * "queryNames"
is used instead of
+ * "queryMBeans"
in the JMXNamespacePermission
+ * objects. Note that a "queryMBeans"
permission implies
+ * the corresponding "queryNames"
permission.
+ *
+ * For the {@link MBeanServer#getClassLoader getClassLoader} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<loaderName>,
+ * "getClassLoader")},
+ * where mbean server name/a> is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * loaderName is the name of the ClassLoader MBean
+ * which is accessed, in that namespace.
+ *
+ *
+ * For the {@link MBeanServer#getClassLoaderFor getClassLoaderFor} method,
+ * the caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "getClassLoaderFor")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which the action
+ * is performed, in that namespace.
+ *
+ *
+ * For the {@link MBeanServer#registerMBean registerMBean} method, the
+ * caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, <class name>, <namespace>//<mbean>,
+ * "registerMBean")}. Here
+ * class name
is the string returned by {@code
+ * obj.getClass().getName()} where {@code obj} is the mbean reference,
+ * is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean which is being
+ * registered, relative to that namespace.
+ *
+ *
For the createMBean
methods, the caller's
+ * permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, <class name>, <namespace>//<mbean>,
+ * "instantiate")} and
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, <class name>, <namespace>//<mbean>,
+ * "registerMBean")}, where
+ * class name
is the string passed as first argument to the {@code
+ * createMBean} method,
+ * mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean which is being
+ * created, relative to that namespace.
+ *
+ *
For the {@link MBeanServer#unregisterMBean unregisterMBean} method,
+ * the caller's permissions must imply {@link
+ * JMXNamespacePermission#JMXNamespacePermission(String,String,ObjectName,String)
+ * JMXNamespacePermission(<mbean server name>, null, <namespace>//<mbean>,
+ * "unregisterMBean")},
+ * where mbean server name is the name of the
+ * {@code MBeanServer} in which the {@code JMXNamespace} MBean in charge of
+ * namespace is registered, and
+ * mbean is the name of the MBean on which is
+ * being unregistered, relative to that namespace.
+ *
+ *
+ *
+ * It must be noted that if all namespaces are local, and all
+ * local namespaces are implemented by regular MBean servers, that is, there
+ * are no {@linkplain MBeanServerSupport Virtual Namespaces}, then
+ * simple {@linkplain javax.management.MBeanPermission MBean Permission}
+ * checks might be enough to secure an application.
+ * In that case, it is possible to specify the following {@link
+ * JMXNamespacePermission} permission in the policy file, which implies all
+ * other JMX namespace permissions:
+ *
+ *
+ * permission javax.management.namespace.JMXNamespacePermission "*::*[]", "*";
+ *
+ *
+ * @since 1.7
+ */
+public class JMXNamespace
+ implements JMXNamespaceMBean, MBeanRegistration {
+
+ /**
+ * The standard value of the {@code type}
+ * property key that must be used to construct valid {@link
+ * JMXNamespaceMBean} ObjectNames.
+ * This is {@value #TYPE}.
+ **/
+ public static final String TYPE = "JMXNamespace";
+
+ /**
+ * The {@link ObjectName#getKeyPropertyListString keyPropertyListString}
+ * that must be used to construct valid {@link JMXNamespaceMBean}
+ * ObjectNames.
+ * This is
+ * {@value #TYPE_ASSIGNMENT}
.
+ **/
+ public static final String TYPE_ASSIGNMENT = "type="+TYPE;
+
+ private volatile MBeanServer mbeanServer; // the mbean server in which
+ // this MBean is registered.
+ private volatile ObjectName objectName; // the ObjectName of this MBean.
+ private final MBeanServer sourceServer; // the MBeanServer within = the
+ // name space (or the MBean server
+ // that contains it).
+ private final String uuid;
+
+ /**
+ * Creates a new JMXNamespace implemented by means of an MBean Server.
+ * A namespace is equivalent to an MBeanServer within an MBean Server.
+ * The {@code sourceServer} provided to this constructor is the MBean Server
+ * within.
+ * @param sourceServer the MBean server that implemented by this namespace.
+ * @see #getSourceServer
+ */
+ public JMXNamespace(MBeanServer sourceServer) {
+ this.sourceServer = sourceServer;
+ this.uuid = UUID.randomUUID().toString();
+ }
+
+ /**
+ * This method is part of the {@link MBeanRegistration} interface.
+ * The {@link JMXNamespace} class uses the {@link MBeanRegistration}
+ * interface in order to get a handle to the MBean server in which it is
+ * registered. It also check the validity of its own ObjectName.
+ *
+ * This method is called by the MBean server.
+ * Application classes should never call this method directly.
+ *
+ * If this method is overridden, the overriding method should call
+ * {@code super.preRegister(server,name)}.
+ * @see MBeanRegistration#preRegister MBeanRegistration
+ * @see JMXNamespaces#getNamespaceObjectName getNamespaceObjectName
+ * @param name The object name of the MBean. name must be a
+ * syntactically valid JMXNamespace name, as returned by
+ * {@link JMXNamespaces#getNamespaceObjectName(java.lang.String)
+ * getNamespaceObjectName(namespace)}.
+ * @return The name under which the MBean is to be registered.
+ * @throws IllegalArgumentException if the name supplied is not valid.
+ * @throws Exception can be thrown by subclasses.
+ */
+ public ObjectName preRegister(MBeanServer server, ObjectName name)
+ throws Exception {
+ if (objectName != null && ! objectName.equals(name))
+ throw new IllegalStateException(
+ "Already registered under another name: " + objectName);
+ objectName = validateHandlerName(name);
+ mbeanServer = server;
+ return name;
+ }
+
+ /**
+ * Validate the ObjectName supplied to preRegister.
+ * This method is introduced to allow standard subclasses to use
+ * an alternate naming scheme. For instance - if we want to
+ * reuse JMXNamespace in order to implement sessions...
+ * It is however only available for subclasses in this package.
+ **/
+ ObjectName validateHandlerName(ObjectName supliedName) {
+ if (supliedName == null)
+ throw new IllegalArgumentException("Must supply a valid name");
+ final String dirName = JMXNamespaces.
+ normalizeNamespaceName(supliedName.getDomain());
+ final ObjectName handlerName =
+ JMXNamespaces.getNamespaceObjectName(dirName);
+ if (!supliedName.equals(handlerName))
+ throw new IllegalArgumentException("invalid name space name: "+
+ supliedName);
+ return supliedName;
+ }
+
+ /**
+ * This method is part of the {@link MBeanRegistration} interface.
+ * The {@link JMXNamespace} class uses the {@link MBeanRegistration}
+ * interface in order to get a handle to the MBean server in which it is
+ * registered.
+ *
+ * This method is called by the MBean server. Application classes should
+ * not call this method directly. Subclasses are free to override this
+ * method with their own specific behavior - but the overriding method
+ * shoud still call {@code super.postRegister(registrationDone)}.
+ * @see MBeanRegistration#postRegister MBeanRegistration
+ */
+ public void postRegister(Boolean registrationDone) {
+ // nothing to do
+ }
+
+ /**
+ * This method is part of the {@link MBeanRegistration} interface.
+ * The {@link JMXNamespace} class uses the {@link MBeanRegistration}
+ * interface in order to get a handle to the MBean server in which it is
+ * registered.
+ *
+ * This method is called by the MBean server. Application classes should
+ * not call this method directly. Subclasses are free to override this
+ * method with their own specific behavior - but the overriding method
+ * shoud still call {@code super.preDeregister()}.
+ * @see MBeanRegistration#preDeregister MBeanRegistration
+ */
+ public void preDeregister() throws Exception {
+ // nothing to do
+ }
+
+ /**
+ * This method is part of the {@link MBeanRegistration} interface.
+ * It allows the {@code JMXNamespace} MBean to perform any operations
+ * needed after having been unregistered in the MBean server.
+ *
+ * This method is called by the MBean server. Application classes should
+ * not call this method directly. If a subclass overrides this
+ * method, the overriding method shoud call {@code super.postDeregister()}.
+ * @see MBeanRegistration#postDeregister MBeanRegistration
+ */
+ public void postDeregister() {
+ mbeanServer = null;
+ objectName = null;
+ }
+
+
+ /**
+ * Returns the MBeanServer in which this MBean is registered,
+ * or null. Chiefly of interest for subclasses.
+ * @return the MBeanServer supplied to {@link #preRegister}.
+ **/
+ public final MBeanServer getMBeanServer() {
+ return mbeanServer;
+ }
+
+ /**
+ * Returns the MBeanServer that contains or emulates the source
+ * namespace. When a JMXNamespace MBean is registered in an
+ * MBean server created through the default {@link
+ * javax.management.MBeanServerBuilder}, the MBeanServer will
+ * check {@link JMXNamespacePermission} before invoking
+ * any method on the source MBeanServer of the JMXNamespace.
+ * See JMX Namespace Permission Checks
+ * above.
+ * @return an MBeanServer view of the source namespace
+ **/
+ public MBeanServer getSourceServer() {
+ return sourceServer;
+ }
+
+ /**
+ * Returns the ObjectName with which this MBean was registered,
+ * or null. Chiefly of interest for subclasses.
+ * @return the ObjectName supplied to {@link #preRegister}.
+ **/
+ public final ObjectName getObjectName() {
+ return objectName;
+ }
+
+ /**
+ * HandlerName used in traces.
+ **/
+ String getHandlerName() {
+ final ObjectName name = getObjectName();
+ if (name != null) return name.toString();
+ return this.toString();
+ }
+
+ /**
+ * In this class, this method returns {@link #getSourceServer
+ * getSourceServer()}.{@link javax.management.MBeanServer#getMBeanCount
+ * getMBeanCount()}.
+ *
This default behaviour may be redefined in subclasses.
+ * @throws java.io.IOException can be thrown by subclasses.
+ */
+ public Integer getMBeanCount() throws IOException {
+ return getSourceServer().getMBeanCount();
+ }
+
+ /**
+ * In this class, this method returns {@link #getSourceServer
+ * getSourceServer()}.{@link javax.management.MBeanServer#getDomains
+ * getDomains()}.
+ *
This default behaviour may be redefined in subclasses.
+ * @throws java.io.IOException can be thrown by subclasses.
+ */
+ public String[] getDomains() throws IOException {
+ return getSourceServer().getDomains();
+ }
+
+ /**
+ * In this class, this method returns {@link #getSourceServer
+ * getSourceServer()}.{@link javax.management.MBeanServer#getDefaultDomain
+ * getDefaultDomain()}.
+ *
This default behaviour may be redefined in subclasses.
+ * @throws java.io.IOException can be thrown by subclasses.
+ */
+ public String getDefaultDomain() throws IOException {
+ return getSourceServer().getDefaultDomain();
+ }
+
+ public final String getUUID() {
+ return uuid;
+ }
+
+}
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/namespace/JMXNamespaceMBean.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespaceMBean.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,96 @@
+/*
+ * 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 javax.management.namespace;
+
+import java.io.IOException;
+import java.util.UUID;
+
+/**
+ * A {@link JMXNamespace} is an MBean that handles a name space in the
+ * MBeanServer hierarchical name space.
+ * @see JMXNamespace
+ * @since 1.7
+ */
+public interface JMXNamespaceMBean {
+
+ // Note: since getDomains(), getDefaultDomain(), and getMBeanCount()
+ // don't take any ObjectName parameters, the only efficient way
+ // to get these data is to call the corresponding method on the
+ // JMXNamespaceMBean that handles the name space.
+ //
+ // We need these methods to implement 'cd' (JMXNamespaces.narrowToNamespace)
+ // correctly.
+ //
+
+ /**
+ * Returns the list of domains currently implemented in the name space
+ * handled by this {@link JMXNamespace}.
+ * @throws IOException if the domain list cannot be obtained due to
+ * I/O problems (communication failures etc...).
+ * @return the list of domains currently implemented in the name space
+ * handled by this {@link JMXNamespace}.
+ * @see javax.management.MBeanServerConnection#getDomains
+ * MBeanServerConnection.getDomains
+ **/
+ public String[] getDomains() throws IOException;
+
+ /**
+ * Returns the default domain for the name space handled by
+ * this {@link JMXNamespace}.
+ * @throws IOException if the default domain cannot be obtained due to
+ * I/O problems (communication failures etc...).
+ * @return the default domain for the name space handled by
+ * this {@link JMXNamespace}.
+ * @see javax.management.MBeanServerConnection#getDefaultDomain
+ * MBeanServerConnection.getDefaultDomain
+ **/
+ public String getDefaultDomain() throws IOException;
+
+ /**
+ * Returns the number of MBeans registered in the name space handled by
+ * this {@link JMXNamespace}.
+ *
+ * @return the number of MBeans registered in the name space handled by
+ * this {@link JMXNamespace}.
+ *
+ * @throws IOException if the MBean count cannot be obtained due to
+ * I/O problems (communication failures etc...).
+ * @see javax.management.MBeanServerConnection#getMBeanCount
+ * MBeanServerConnection.getMBeanCount
+ */
+ public Integer getMBeanCount() throws IOException;
+
+ /**
+ * Returns a {@link java.util.UUID UUID string} which uniquely identifies
+ * this {@linkplain JMXNamespace} MBean.
+ * This information can be used to detect loops in the JMX name space graph.
+ * @return A unique ID identifying this MBean.
+ * @throws IOException if the MBean UUID cannot be obtained due to
+ * I/O problems (communication failures etc...).
+ */
+ public String getUUID() throws IOException;
+
+}
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/namespace/JMXNamespacePermission.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespacePermission.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,1474 @@
+/*
+ * Copyright 2002-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 javax.management.namespace;
+
+import javax.management.*;
+import com.sun.jmx.mbeanserver.Util;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.security.Permission;
+
+/**
+ *
A permission controlling access to MBeans located in namespaces.
+ * If a security manager has been set using {@link
+ * System#setSecurityManager}, most operations on an MBean mounted in a
+ * namespace require that the caller's permissions imply a
+ * JMXNamespacePermission appropriate for the operation.
+ * This is described in detail in the
+ * documentation for the
+ * JMXNamespace
+ * class.
+ *
+ * As with other {@link Permission} objects,
+ * a JMXNamespacePermission can represent either a permission that
+ * you have or a permission that you need.
+ * When a sensitive operation is being checked for permission,
+ * a JMXNamespacePermission is constructed
+ * representing the permission you need. The operation is only
+ * allowed if the permissions you have {@linkplain #implies imply} the
+ * permission you need.
+ *
+ * A JMXNamespacePermission contains four items of information:
+ *
+ *
+ *
+ * The action.
+ * For a permission you need,
+ * this is one of the actions in the list below. For a permission you have, this is
+ * a comma-separated list of those actions, or *
,
+ * representing all actions.
+ *
+ * The action is returned by {@link #getActions()}.
+ *
+ * The MBean Server name.
+ *
+ * For a permission you need, this is the {@linkplain
+ * javax.management.MBeanServerFactory#getMBeanServerName
+ * name of the MBeanServer}
+ * from which the MBean is accessed.
+ *
+ * For a permission you have, this is either the {@linkplain
+ * javax.management.MBeanServerFactory#getMBeanServerName
+ * name of the MBeanServer} from which the MBean
+ * for which you have this permission is accessed,
+ * or a pattern against which that MBean Server name will be matched.
+ * An {@code mbeanServername} pattern can also be empty, or the single
+ * character {@code "*"}, both of which match any {@code MBeanServer} name.
+ * The string {@code "-"} doesn't match any MBeanServer name.
+ *
+ *
+ * Example:
+ *
+ * // grant permission to invoke the operation "stop" on any MBean
+ * // whose name matches "a//**//*:type=JMXConnectorServer" when
+ * // accessed from any MBeanServer whose name matches myapp.*"
+ * permission javax.management.namespace.JMXNamespacePermission "myapp.*::stop[a//**//*:type=JMXConnectorServer]", "invoke";
+ *
+ *
+ * The member.
+ *
+ * For a permission you need, this is the name of the attribute or
+ * operation you are accessing. For operations that do not reference
+ * an attribute or operation, the member is null.
+ *
+ * For a permission you have, this is either the name of an attribute
+ * or operation you can access, or it is empty or the single character
+ * "*
", both of which grant access to any member.
+ *
+ * There is a special case for actions {@code registerMBean} and
+ * {@code instantiate}, where for a permission you need, {@code member}
+ * indicates the name of the class for which you are trying
+ * to create, instantiate, or register an MBean instance. For a
+ * permission you have, it is a pattern that will be matched against
+ * the full class name of the MBean being created, instantiated, or
+ * registered.
+ *
+ *
+ *
+ * The object name.
+ *
+ * For a permission you need, this is the {@link ObjectName} of the
+ * MBean you are accessing. It is of the form {@code //}
+ * where {@code } is the name of the name space for which the
+ * permission is checked, and {@code } is the name of the MBean
+ * within that namespace.
+ *
+ * For operations that do not reference a
+ * single MBean, the object name is null. It is never an object
+ * name pattern.
+ *
+ *
+ * For a permission you have, this is the {@link ObjectName} of the
+ * MBean or MBeans you can access. It is of the form
+ * {@code //}
+ * where {@code } is the name of the name space for which the
+ * permission is checked, and
+ * {@code } is the name of the MBean
+ * within that namespace. Both {@code } and {@code }
+ * can be patterns. The object name
+ * may also be empty, which grants access to all MBeans whatever their
+ * name and namespace.
+ * When included in a namespace path the special path element
+ * **
matches any number of sub namespaces
+ * recursively, but only if used as a complete namespace path element,
+ * as in **//b//c//D:k=v
or a//**//c//D:k=v
+ * - see below.
+ *
+ *
+ *
+ *
+ *
+ * If you have a JMXNamespacePermission, it allows operations only
+ * if all four of the items match.
+ *
+ * The MBeanServer name,
+ * member, and object name
+ * can be written together
+ * as a single string, which is the name of this permission.
+ * The name of the permission is the string returned by {@link
+ * java.security.Permission#getName() getName()}.
+ * The format of the string is:
+ *
+ *
+ * {@code ::[//]}
+ *
+ *
+ *
+ * The {@code } is optional. If omitted, {@code "*"} is
+ * assumed, and these three permission names
+ * are thus equivalent:
+ *
+ *
+ * {@code *::[//]}
+ * {@code ::[//]}
+ * {@code [//]}
+ *
+ *
+ * The {@code //} string can be in the form
+ * of a traditional ObjectName
+ * pattern - meaning that ?
will match any single
+ * character, and *
will match any sequence of characters,
+ * except {@value
+ * javax.management.namespace.JMXNamespaces#NAMESPACE_SEPARATOR}
+ * In addition, when included in a namespace path the special
+ * path element **
matches any number of sub namespaces
+ * recursively.
+ * A {@code //} string of the form
+ * **//*:*
thus means that the permission is
+ * granted for all MBeans in all namespaces, recursively (see
+ * below for more details.
+ *
+ * Namespace permission checking may be tricky to configure, depending
+ * on whether the namespaces crossed to reach the MBean are local or
+ * remote.
+ * For instance, let a//b//D:k=v
be an MBean exposing an
+ * attribute Foo
.
+ * If namespace a
is a plain JMXNamespace pointing to
+ * a local MBeanServer in the same JVM, then the permissions you need
+ * to get the attribute Foo
will be:
+ *
+ *
+ * // granting permission to access attribute 'Foo' of MBean a//b//D:k=v
+ * // from MBeanServer named 'srv1'
+ * // This permission will be checked by the MBeanServer that contains 'a'.
+ * srv1::Foo[a//b//D:k=v]
+ *
+ * // Since a is local, you also need the following additional permission,
+ * // which will be checked by the MBeanServer 'srv2' that contains 'b':
+ * //
+ * // granting permission to access attribute 'Foo' of MBean b//D:k=v from
+ * // 'srv2'
+ * srv2::Foo[b//D:k=v]
+ *
+ * On the other hand, if namespace a
is a JMXRemoteNamespace
+ * pointing to an MBeanServer in a remote JVM, then the only permission you
+ * need to get the attribute Foo
will be:
+ *
+ *
+ * // granting permission to access attribute 'Foo' of MBean a//b//D:k=v
+ * // from 'srv1'
+ * srv1::Foo[a//b//D:k=v]
+ *
+ * The namespace b
resides in the remote JVM, and
+ * therefore the permissions concerning access to MBeans from
+ * namespace 'b' will only be checked in the remote JVM, if that JVM is
+ * configured to do so.
+ *
+ *
+ * The {@code } is written using the usual syntax for {@link
+ * ObjectName}. It may contain any legal characters, including
+ * ]
. It is terminated by a ]
character
+ * that is the last character in the string.
+ *
+ * Below are some examples of permission names:
+ *
+ * // allows access to Foo in 'a//b//*:*' from any MBeanServer in the JVM.
+ * Foo[a//b//*:*]
+ *
+ * // allows access to Foo in all subnamespaces of 'a//b', but only for
+ * // MBeanServers whose name matches 'myapp.*'
+ * myapp.*::Foo[a//b//**//*:*]
+ *
+ * // allows access to Foo from all namespaces in the MBeanServer named
+ * // 'myapp.srv1' - but not recursively.
+ * myapp.srv1::Foo[*//*:*]
+ *
+ * For instance, the first two permissions listed above
+ * will let through {@code getAttribute("a//b//D:k=v","Foo");} in
+ * all MBeanServers, but will block access to
+ * {@code getAttribute("a//b//c//D:k=v","Foo");} in MBeanServers whose
+ * name do not start with {@code "myapp."}.
+ *
+ *
+ *
+ * // allows access to Foo in all namespaces, recursively.
+ * //
+ * *::Foo[**//*:*]
+ *
+ * // This permission name is the equivalent to the permission names above:
+ * // Foo[**//*:*] and Foo[] are equivalent.
+ * //
+ * Foo[]
+ *
+ * // This permission name is the equivalent to the two permission names
+ * // above:
+ * // Foo[**//*:*], Foo[], Foo are equivalent.
+ * //
+ * Foo
+ *
+ * // allows access to Foo from all namespaces - but not recursively.
+ * // This wildcard permission complements the previous one: it allows
+ * // access to 'Foo' from an MBean directly registered in any local namespace.
+ * //
+ * Foo[*//*:*]
+ *
+ *
+ * Note on wildcards: In an object name pattern, a path element
+ * of exactly **
corresponds to a meta
+ * wildcard that will match any number of sub namespaces. Hence:
+ *
+ *
+ * pattern matches doesn't match
+ *
+ * **//D:k=v
+ * a//D:k=v
+ * a//b//D:k=v
+ * a//b//c//D:k=v
+ * D:k=v
+ * a//**//D:k=v
+ * a//b//D:k=v
+ * a//b//c//D:k=v
+ * b//b//c//D:k=v
+ * a//D:k=v
+ * D:k=v
+ * a//**//e//D:k=v
+ * a//b//e//D:k=v
+ * a//b//c//e//D:k=v
+ * a//b//c//c//D:k=v
+ * b//b//c//e//D:k=v
+ * a//e//D:k=v
+ * e//D:k=v
+ * a//b**//e//D:k=v
+ * a//b//e//D:k=v
+ * a//b//c//e//D:k=v
+ * because in that case b**
+ * is not a meta-wildcard - and b**
+ * is thus equivalent to b*
.
+ *
+ *
+ *
+ *
+ * If {@code ::} is omitted, then one of
+ * member
or object name
may be omitted.
+ * If the object name
is omitted,
+ * the []
may be too (but does not have to be). It is
+ * not legal to omit all items, that is to have a name
+ * which is the empty string.
+ * If {@code } is present, it must be followed by
+ * the {@code "::"} separator - otherwise it will be interpreted as
+ * a {@code member name}.
+ *
+ *
+ *
+ * One or more of the MBean Server name,
+ * member
+ * or object name may be the character "-
",
+ * which is equivalent to a null value. A null value is implied by
+ * any value (including another null value) but does not imply any
+ * other value.
+ *
+ *
+ * The possible actions are these:
+ *
+ *
+ * - addNotificationListener
+ * - getAttribute
+ * - getClassLoader
+ * - getClassLoaderFor
+ * - getClassLoaderRepository
+ * - getMBeanInfo
+ * - getObjectInstance
+ * - instantiate
+ * - invoke
+ * - isInstanceOf
+ * - queryMBeans
+ * - queryNames
+ * - registerMBean
+ * - removeNotificationListener
+ * - setAttribute
+ * - unregisterMBean
+ *
+ *
+ * In a comma-separated list of actions, spaces are allowed before
+ * and after each action.
+ *
+ * @since 1.7
+ */
+public class JMXNamespacePermission extends Permission {
+
+ private static final long serialVersionUID = -2416928705275160661L;
+
+ private static final String WILDPATH = "**" +
+ JMXNamespaces.NAMESPACE_SEPARATOR + "*";
+
+ /**
+ * Actions list.
+ */
+ private static final int AddNotificationListener = 0x00001;
+ private static final int GetAttribute = 0x00002;
+ private static final int GetClassLoader = 0x00004;
+ private static final int GetClassLoaderFor = 0x00008;
+ private static final int GetClassLoaderRepository = 0x00010;
+ // No GetDomains because it is not possible to route a call to
+ // getDomains() on a NamespaceInterceptor - getDomains() doesn't
+ // have any ObjectName.
+ // private static final int GetDomains = 0x00020;
+ private static final int GetMBeanInfo = 0x00040;
+ private static final int GetObjectInstance = 0x00080;
+ private static final int Instantiate = 0x00100;
+ private static final int Invoke = 0x00200;
+ private static final int IsInstanceOf = 0x00400;
+ private static final int QueryMBeans = 0x00800;
+ private static final int QueryNames = 0x01000;
+ private static final int RegisterMBean = 0x02000;
+ private static final int RemoveNotificationListener = 0x04000;
+ private static final int SetAttribute = 0x08000;
+ private static final int UnregisterMBean = 0x10000;
+
+ /**
+ * No actions.
+ */
+ private static final int NONE = 0x00000;
+
+ /**
+ * All actions.
+ */
+ // No GetDomains because it is not possible to route a call to
+ // getDomains() on a NamespaceInterceptor - getDomains() doesn't
+ // have any ObjectName.
+ //
+ private static final int ALL =
+ AddNotificationListener |
+ GetAttribute |
+ GetClassLoader |
+ GetClassLoaderFor |
+ GetClassLoaderRepository |
+ GetMBeanInfo |
+ GetObjectInstance |
+ Instantiate |
+ Invoke |
+ IsInstanceOf |
+ QueryMBeans |
+ QueryNames |
+ RegisterMBean |
+ RemoveNotificationListener |
+ SetAttribute |
+ UnregisterMBean;
+
+ /**
+ * The actions string.
+ */
+ private String actions;
+
+ /**
+ * The actions mask.
+ */
+ private transient int mask;
+
+ /**
+ * The name of the MBeanServer in which this permission is checked, or
+ * granted. If null, is implied by any MBean server name
+ * but does not imply any non-null MBean server name.
+ */
+ private transient String mbeanServerName;
+
+ /**
+ * The member that must match. If null, is implied by any member
+ * but does not imply any non-null member.
+ */
+ private transient String member;
+
+ /**
+ * The objectName that must match. If null, is implied by any
+ * objectName but does not imply any non-null objectName.
+ */
+ private transient ObjectName objectName;
+
+ /**
+ * If objectName is missing from name, then allnames will be
+ * set to true.
+ */
+ private transient boolean allnames = false;
+
+ /**
+ * Parse actions
parameter.
+ */
+ private void parseActions() {
+
+ int amask;
+
+ if (actions == null)
+ throw new IllegalArgumentException("JMXNamespaceAccessPermission: " +
+ "actions can't be null");
+ if (actions.equals(""))
+ throw new IllegalArgumentException("JMXNamespaceAccessPermission: " +
+ "actions can't be empty");
+
+ amask = getMask(actions);
+
+ if ((amask & ALL) != amask)
+ throw new IllegalArgumentException("Invalid actions mask");
+ if (amask == NONE)
+ throw new IllegalArgumentException("Invalid actions mask");
+ this.mask = amask;
+ }
+
+ /**
+ * Parse name
parameter.
+ */
+ private void parseName() {
+ String name = getName();
+
+ if (name == null)
+ throw new IllegalArgumentException("JMXNamespaceAccessPermission name " +
+ "cannot be null");
+
+ if (name.equals(""))
+ throw new IllegalArgumentException("JMXNamespaceAccessPermission name " +
+ "cannot be empty");
+ final int sepIndex = name.indexOf("::");
+ if (sepIndex < 0) {
+ setMBeanServerName("*");
+ } else {
+ setMBeanServerName(name.substring(0,sepIndex));
+ }
+
+ /* The name looks like "mbeanServerName::member[objectname]".
+ We subtract elements from the right as we parse, so after
+ parsing the objectname we have "class#member" and after parsing the
+ member we have "class". Each element is optional. */
+
+ // Parse ObjectName
+
+ final int start = (sepIndex<0)?0:sepIndex+2;
+ int openingBracket = name.indexOf("[",start);
+ if (openingBracket == -1) {
+ // If "[on]" missing then ObjectName("*:*")
+ //
+ objectName = null;
+ allnames = true;
+ openingBracket=name.length();
+ } else {
+ if (!name.endsWith("]")) {
+ throw new IllegalArgumentException("JMXNamespaceAccessPermission: " +
+ "The ObjectName in the " +
+ "target name must be " +
+ "included in square " +
+ "brackets");
+ } else {
+ // Create ObjectName
+ //
+ String on = name.substring(openingBracket + 1,
+ name.length() - 1);
+ try {
+ // If "[]" then allnames are implied
+ //
+ final ObjectName target;
+ final boolean all;
+ if (on.equals("")) {
+ target = null;
+ all = true;
+ } else if (on.equals("-")) {
+ target = null;
+ all = false;
+ } else {
+ target = new ObjectName(on);
+ all = false;
+ }
+ setObjectName(target,all);
+ } catch (MalformedObjectNameException e) {
+ throw new IllegalArgumentException(
+ "JMXNamespaceAccessPermission: " +
+ "The target name does " +
+ "not specify a valid " +
+ "ObjectName", e);
+ }
+ }
+ }
+
+ final String memberName = name.substring(start,openingBracket);
+ setMember(memberName);
+ }
+
+ private void setObjectName(ObjectName target, boolean all) {
+ if (target != null &&
+ !Util.wildpathmatch(target.getDomain(), WILDPATH)) {
+ throw new IllegalArgumentException(
+ "The target name does not contain " +
+ "any namespace: "+String.valueOf(target));
+ } else if (target != null) {
+ final String domain = target.getDomain();
+ final int seplen = JMXNamespaces.NAMESPACE_SEPARATOR.length();
+ final int sepc = domain.indexOf(JMXNamespaces.NAMESPACE_SEPARATOR);
+ if (sepc < 0 || (sepc+seplen)==domain.length()) {
+ throw new IllegalArgumentException(String.valueOf(target)+
+ ": no namespace in domain");
+ }
+ }
+ objectName = target;
+ allnames = all;
+ }
+
+ /**
+ * Assign fields based on className, member, and objectName
+ * parameters.
+ */
+// private void initName(String namespaceName, String member,
+// ObjectName objectName, boolean allnames) {
+// setNamespace(namespaceName);
+ private void initName(String mbeanServerName, String member,
+ ObjectName mbeanName, boolean all) {
+ setMBeanServerName(mbeanServerName);
+ setMember(member);
+ setObjectName(mbeanName, all);
+ }
+
+ private void setMBeanServerName(String mbeanServerName) {
+ if (mbeanServerName == null || mbeanServerName.equals("-")) {
+ this.mbeanServerName = null;
+ } else if (mbeanServerName.equals("")) {
+ this.mbeanServerName = "*";
+ } else {
+ this.mbeanServerName = mbeanServerName;
+ }
+ }
+
+ private void setMember(String member) {
+ if (member == null || member.equals("-"))
+ this.member = null;
+ else if (member.equals(""))
+ this.member = "*";
+ else
+ this.member = member;
+ }
+
+ /**
+ * Create a new JMXNamespacePermission object with the
+ * specified target name and actions.
+ *
+ * The target name is of the form
+ * "mbeanServerName::member[objectName]
" where each part is
+ * optional. This target name must not be empty or null.
+ * If objectName
is present, it is of
+ * the form namespace//MBeanName
.
+ *
+ *
+ * For a permission you need, {@code mbeanServerName} is the
+ * name of the MBeanServer from
+ * which {@code objectName} is being accessed.
+ *
+ *
+ * For a permission you have, {@code mbeanServerName} is the
+ * name of the MBeanServer from
+ * which access to {@code objectName} is granted.
+ * It can also be a pattern, and if omitted, {@code "*"} is assumed,
+ * meaning that access to {@code objectName} is granted in all
+ * MBean servers in the JVM.
+ *
+ *
+ * The actions parameter contains a comma-separated list of the
+ * desired actions granted on the target name. It must not be
+ * empty or null.
+ *
+ * @param name the triplet "mbeanServerName::member[objectName]".
+ * If objectName
is present, it is of
+ * the form namespace//MBeanName
.
+ * @param actions the action string.
+ *
+ * @exception IllegalArgumentException if the name
or
+ * actions
is invalid.
+ */
+ public JMXNamespacePermission(String name, String actions) {
+ super(name);
+
+ parseName();
+
+ this.actions = actions;
+ parseActions();
+ }
+
+ /**
+ * Create a new JMXNamespacePermission object with the specified
+ * target name (namespace name, member, object name) and actions.
+ *
+ * The {@code MBeanServer} name, member and object name
+ * parameters define a target name of the form
+ * "mbeanServerName::member[objectName]
" where each
+ * part is optional. This will be the result of {@link #getName()} on the
+ * resultant JMXNamespacePermission.
+ * If the mbeanServerName
is empty or exactly {@code "*"}, then
+ * "{@code mbeanServerName::}" is omitted in that result.
+ *
+ *
+ * The actions parameter contains a comma-separated list of the
+ * desired actions granted on the target name. It must not be
+ * empty or null.
+ *
+ * @param mbeanServerName the name of the {@code MBeanServer} to which this
+ * permission applies.
+ * May be null or "-"
, which represents an MBeanServer name
+ * that is implied by any MBeanServer name but does not imply any other
+ * MBeanServer name.
+ * @param member the member to which this permission applies. May
+ * be null or "-"
, which represents a member that is
+ * implied by any member but does not imply any other member.
+ * @param objectName the object name to which this permission
+ * applies.
+ * May be null, which represents an object name that is
+ * implied by any object name but does not imply any other object
+ * name. If not null, the {@code objectName} must be of the
+ * form {@code //} - where {@code }
+ * can be a domain pattern, and {@code } can be an ObjectName
+ * pattern.
+ * For a permission you need, {@code } is the name of the
+ * name space for which the permission is checked, and {@code }
+ * is the name of the MBean in that namespace.
+ * The composed name {@code //} thus represents the
+ * name of the MBean as seen by the {@code mbeanServerName} containing
+ * {@code }.
+ *
+ * @param actions the action string.
+ */
+ public JMXNamespacePermission(
+ String mbeanServerName,
+ String member,
+ ObjectName objectName,
+ String actions) {
+ this(mbeanServerName, member, objectName, false, actions);
+// this(member, objectName, false, actions);
+ }
+
+ /**
+ * Create a new JMXNamespacePermission object with the specified
+ * MBean Server name, member, and actions.
+ *
+ * The {@code MBeanServer} name and member
+ * parameters define a target name of the form
+ * "mbeanServerName::member[]
" where each
+ * part is optional. This will be the result of {@link #getName()} on the
+ * resultant JMXNamespacePermission.
+ * If the mbeanServerName
is empty or exactly {@code "*"}, then
+ * "{@code mbeanServerName::}" is omitted in that result.
+ *
+ *
+ * The actions parameter contains a comma-separated list of the
+ * desired actions granted on the target name. It must not be
+ * empty or null.
+ *
+ * @param mbeanServerName the name of the {@code MBeanServer} to which this
+ * permission applies.
+ * May be null or "-"
, which represents an MBeanServer name
+ * that is implied by any MBeanServer name but does not imply any other
+ * MBeanServer name.
+ * @param member the member to which this permission applies. May
+ * be null or "-"
, which represents a member that is
+ * implied by any member but does not imply any other member.
+ * @param actions the action string.
+ */
+ public JMXNamespacePermission(String mbeanServerName,
+ String member,
+ String actions) {
+ this(mbeanServerName,member,null,true,actions);
+ // this(member,null,allnames,actions);
+ }
+
+ /**
+ * Create a new JMXNamespacePermission object with the specified
+ * target name (namespace name, member, object name) and actions.
+ *
+ * The MBean Server name, member and object name parameters define a
+ * target name of the form
+ * "mbeanServerName::member[objectName]
" where each part is
+ * optional. This will be the result of {@link
+ * java.security.Permission#getName() getName()} on the
+ * resultant JMXNamespacePermission.
+ *
+ * The actions parameter contains a comma-separated list of the
+ * desired actions granted on the target name. It must not be
+ * empty or null.
+ *
+ * @param mbeanServerName the name of the {@code MBeanServer} to which this
+ * permission applies.
+ * May be null or "-"
, which represents an MBeanServer name
+ * that is implied by any MBeanServer name but does not imply any other
+ * MBeanServer name.
+ * @param member the member to which this permission applies. May
+ * be null or "-"
, which represents a member that is
+ * implied by any member but does not imply any other member.
+ * @param objectName the object name to which this permission
+ * applies. If null, and allnames is false, represents an object
+ * name that is implied by any object name but does not imply any
+ * other object name. Otherwise, if allnames is true, it represents
+ * a meta wildcard that matches all object names. It is equivalent to
+ * a missing objectName ("[]") in the {@link
+ * java.security.Permission#getName() name} property.
+ * @param allnames represent a meta wildcard indicating that the
+ * objectName was not specified. This implies all objectnames
+ * that match "*:*" and all object names that match
+ * "**//*:*"
+ * @param actions the action string.
+ */
+ private JMXNamespacePermission(String mbeanServerName,
+ String member,
+ ObjectName objectName,
+ boolean allnames,
+ String actions) {
+
+ super(makeName(mbeanServerName,
+ member, objectName, allnames));
+ initName(mbeanServerName,
+ member, objectName, allnames);
+
+ this.actions = actions;
+ parseActions();
+ }
+
+ private static String makeName(String mbeanServerName,
+ String memberName, ObjectName objName, boolean allMBeans) {
+ final StringBuilder name = new StringBuilder();
+ if (mbeanServerName == null)
+ mbeanServerName = "-";
+ if (!mbeanServerName.equals("") && !mbeanServerName.equals("*"))
+ name.append(mbeanServerName).append("::");
+ if (memberName == null)
+ memberName = "-";
+ name.append(memberName);
+ if (objName == null) {
+ if (allMBeans)
+ name.append("[]");
+ else
+ name.append("[-]");
+ } else {
+ final String domain = objName.getDomain();
+ final int seplen = JMXNamespaces.NAMESPACE_SEPARATOR.length();
+ final int sepc = domain.indexOf(JMXNamespaces.NAMESPACE_SEPARATOR);
+ if (sepc < 0 || (sepc+seplen)==domain.length()) {
+ throw new IllegalArgumentException(String.valueOf(objName)+
+ ": no namespace in domain");
+ }
+ final String can = objName.getCanonicalName();
+ name.append("[").append(can).append("]");
+ }
+ return name.toString();
+ }
+
+ /**
+ * Returns the "canonical string representation" of the actions. That is,
+ * this method always returns actions in alphabetical order.
+ *
+ * @return the canonical string representation of the actions.
+ */
+ public String getActions() {
+
+ if (actions == null)
+ actions = getActions(this.mask);
+
+ return actions;
+ }
+
+ /**
+ * Returns the "canonical string representation"
+ * of the actions from the mask.
+ */
+ private static String getActions(int mask) {
+ final StringBuilder sb = new StringBuilder();
+ boolean comma = false;
+
+ if ((mask & AddNotificationListener) == AddNotificationListener) {
+ comma = true;
+ sb.append("addNotificationListener");
+ }
+
+ if ((mask & GetAttribute) == GetAttribute) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("getAttribute");
+ }
+
+ if ((mask & GetClassLoader) == GetClassLoader) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("getClassLoader");
+ }
+
+ if ((mask & GetClassLoaderFor) == GetClassLoaderFor) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("getClassLoaderFor");
+ }
+
+ if ((mask & GetClassLoaderRepository) == GetClassLoaderRepository) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("getClassLoaderRepository");
+ }
+
+ if ((mask & GetMBeanInfo) == GetMBeanInfo) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("getMBeanInfo");
+ }
+
+ if ((mask & GetObjectInstance) == GetObjectInstance) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("getObjectInstance");
+ }
+
+ if ((mask & Instantiate) == Instantiate) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("instantiate");
+ }
+
+ if ((mask & Invoke) == Invoke) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("invoke");
+ }
+
+ if ((mask & IsInstanceOf) == IsInstanceOf) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("isInstanceOf");
+ }
+
+ if ((mask & QueryMBeans) == QueryMBeans) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("queryMBeans");
+ }
+
+ if ((mask & QueryNames) == QueryNames) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("queryNames");
+ }
+
+ if ((mask & RegisterMBean) == RegisterMBean) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("registerMBean");
+ }
+
+ if ((mask & RemoveNotificationListener) == RemoveNotificationListener) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("removeNotificationListener");
+ }
+
+ if ((mask & SetAttribute) == SetAttribute) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("setAttribute");
+ }
+
+ if ((mask & UnregisterMBean) == UnregisterMBean) {
+ if (comma) sb.append(',');
+ else comma = true;
+ sb.append("unregisterMBean");
+ }
+
+ // No GetDomains because it is not possible to route a call to
+ // getDomains() on a NamespaceInterceptor - getDomains() doesn't
+ // have any ObjectName.
+
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return this.getName().hashCode() + this.getActions().hashCode();
+ }
+
+ /**
+ * Converts an action String to an integer action mask.
+ *
+ * @param action the action string.
+ * @return the action mask.
+ */
+ private static int getMask(String action) {
+
+ /*
+ * BE CAREFUL HERE! PARSING ORDER IS IMPORTANT IN THIS ALGORITHM.
+ *
+ * The 'string length' test must be performed for the lengthiest
+ * strings first.
+ *
+ * In this permission if the "unregisterMBean" string length test is
+ * performed after the "registerMBean" string length test the algorithm
+ * considers the 'unregisterMBean' action as being the 'registerMBean'
+ * action and a parsing error is returned.
+ */
+
+ int mask = NONE;
+
+ if (action == null) {
+ return mask;
+ }
+
+ if (action.equals("*")) {
+ return ALL;
+ }
+
+ char[] a = action.toCharArray();
+
+ int i = a.length - 1;
+ if (i < 0)
+ return mask;
+
+ while (i != -1) {
+ char c;
+
+ // skip whitespace
+ while ((i!=-1) && ((c = a[i]) == ' ' ||
+ c == '\r' ||
+ c == '\n' ||
+ c == '\f' ||
+ c == '\t'))
+ i--;
+
+ // check for the known strings
+ int matchlen;
+
+ // No GetDomains because it is not possible to route a call to
+ // getDomains() on a NamespaceInterceptor - getDomains() doesn't
+ // have any ObjectName.
+
+ if (i >= 25 && /* removeNotificationListener */
+ (a[i-25] == 'r') &&
+ (a[i-24] == 'e') &&
+ (a[i-23] == 'm') &&
+ (a[i-22] == 'o') &&
+ (a[i-21] == 'v') &&
+ (a[i-20] == 'e') &&
+ (a[i-19] == 'N') &&
+ (a[i-18] == 'o') &&
+ (a[i-17] == 't') &&
+ (a[i-16] == 'i') &&
+ (a[i-15] == 'f') &&
+ (a[i-14] == 'i') &&
+ (a[i-13] == 'c') &&
+ (a[i-12] == 'a') &&
+ (a[i-11] == 't') &&
+ (a[i-10] == 'i') &&
+ (a[i-9] == 'o') &&
+ (a[i-8] == 'n') &&
+ (a[i-7] == 'L') &&
+ (a[i-6] == 'i') &&
+ (a[i-5] == 's') &&
+ (a[i-4] == 't') &&
+ (a[i-3] == 'e') &&
+ (a[i-2] == 'n') &&
+ (a[i-1] == 'e') &&
+ (a[i] == 'r')) {
+ matchlen = 26;
+ mask |= RemoveNotificationListener;
+ } else if (i >= 23 && /* getClassLoaderRepository */
+ (a[i-23] == 'g') &&
+ (a[i-22] == 'e') &&
+ (a[i-21] == 't') &&
+ (a[i-20] == 'C') &&
+ (a[i-19] == 'l') &&
+ (a[i-18] == 'a') &&
+ (a[i-17] == 's') &&
+ (a[i-16] == 's') &&
+ (a[i-15] == 'L') &&
+ (a[i-14] == 'o') &&
+ (a[i-13] == 'a') &&
+ (a[i-12] == 'd') &&
+ (a[i-11] == 'e') &&
+ (a[i-10] == 'r') &&
+ (a[i-9] == 'R') &&
+ (a[i-8] == 'e') &&
+ (a[i-7] == 'p') &&
+ (a[i-6] == 'o') &&
+ (a[i-5] == 's') &&
+ (a[i-4] == 'i') &&
+ (a[i-3] == 't') &&
+ (a[i-2] == 'o') &&
+ (a[i-1] == 'r') &&
+ (a[i] == 'y')) {
+ matchlen = 24;
+ mask |= GetClassLoaderRepository;
+ } else if (i >= 22 && /* addNotificationListener */
+ (a[i-22] == 'a') &&
+ (a[i-21] == 'd') &&
+ (a[i-20] == 'd') &&
+ (a[i-19] == 'N') &&
+ (a[i-18] == 'o') &&
+ (a[i-17] == 't') &&
+ (a[i-16] == 'i') &&
+ (a[i-15] == 'f') &&
+ (a[i-14] == 'i') &&
+ (a[i-13] == 'c') &&
+ (a[i-12] == 'a') &&
+ (a[i-11] == 't') &&
+ (a[i-10] == 'i') &&
+ (a[i-9] == 'o') &&
+ (a[i-8] == 'n') &&
+ (a[i-7] == 'L') &&
+ (a[i-6] == 'i') &&
+ (a[i-5] == 's') &&
+ (a[i-4] == 't') &&
+ (a[i-3] == 'e') &&
+ (a[i-2] == 'n') &&
+ (a[i-1] == 'e') &&
+ (a[i] == 'r')) {
+ matchlen = 23;
+ mask |= AddNotificationListener;
+ } else if (i >= 16 && /* getClassLoaderFor */
+ (a[i-16] == 'g') &&
+ (a[i-15] == 'e') &&
+ (a[i-14] == 't') &&
+ (a[i-13] == 'C') &&
+ (a[i-12] == 'l') &&
+ (a[i-11] == 'a') &&
+ (a[i-10] == 's') &&
+ (a[i-9] == 's') &&
+ (a[i-8] == 'L') &&
+ (a[i-7] == 'o') &&
+ (a[i-6] == 'a') &&
+ (a[i-5] == 'd') &&
+ (a[i-4] == 'e') &&
+ (a[i-3] == 'r') &&
+ (a[i-2] == 'F') &&
+ (a[i-1] == 'o') &&
+ (a[i] == 'r')) {
+ matchlen = 17;
+ mask |= GetClassLoaderFor;
+ } else if (i >= 16 && /* getObjectInstance */
+ (a[i-16] == 'g') &&
+ (a[i-15] == 'e') &&
+ (a[i-14] == 't') &&
+ (a[i-13] == 'O') &&
+ (a[i-12] == 'b') &&
+ (a[i-11] == 'j') &&
+ (a[i-10] == 'e') &&
+ (a[i-9] == 'c') &&
+ (a[i-8] == 't') &&
+ (a[i-7] == 'I') &&
+ (a[i-6] == 'n') &&
+ (a[i-5] == 's') &&
+ (a[i-4] == 't') &&
+ (a[i-3] == 'a') &&
+ (a[i-2] == 'n') &&
+ (a[i-1] == 'c') &&
+ (a[i] == 'e')) {
+ matchlen = 17;
+ mask |= GetObjectInstance;
+ } else if (i >= 14 && /* unregisterMBean */
+ (a[i-14] == 'u') &&
+ (a[i-13] == 'n') &&
+ (a[i-12] == 'r') &&
+ (a[i-11] == 'e') &&
+ (a[i-10] == 'g') &&
+ (a[i-9] == 'i') &&
+ (a[i-8] == 's') &&
+ (a[i-7] == 't') &&
+ (a[i-6] == 'e') &&
+ (a[i-5] == 'r') &&
+ (a[i-4] == 'M') &&
+ (a[i-3] == 'B') &&
+ (a[i-2] == 'e') &&
+ (a[i-1] == 'a') &&
+ (a[i] == 'n')) {
+ matchlen = 15;
+ mask |= UnregisterMBean;
+ } else if (i >= 13 && /* getClassLoader */
+ (a[i-13] == 'g') &&
+ (a[i-12] == 'e') &&
+ (a[i-11] == 't') &&
+ (a[i-10] == 'C') &&
+ (a[i-9] == 'l') &&
+ (a[i-8] == 'a') &&
+ (a[i-7] == 's') &&
+ (a[i-6] == 's') &&
+ (a[i-5] == 'L') &&
+ (a[i-4] == 'o') &&
+ (a[i-3] == 'a') &&
+ (a[i-2] == 'd') &&
+ (a[i-1] == 'e') &&
+ (a[i] == 'r')) {
+ matchlen = 14;
+ mask |= GetClassLoader;
+ } else if (i >= 12 && /* registerMBean */
+ (a[i-12] == 'r') &&
+ (a[i-11] == 'e') &&
+ (a[i-10] == 'g') &&
+ (a[i-9] == 'i') &&
+ (a[i-8] == 's') &&
+ (a[i-7] == 't') &&
+ (a[i-6] == 'e') &&
+ (a[i-5] == 'r') &&
+ (a[i-4] == 'M') &&
+ (a[i-3] == 'B') &&
+ (a[i-2] == 'e') &&
+ (a[i-1] == 'a') &&
+ (a[i] == 'n')) {
+ matchlen = 13;
+ mask |= RegisterMBean;
+ } else if (i >= 11 && /* getAttribute */
+ (a[i-11] == 'g') &&
+ (a[i-10] == 'e') &&
+ (a[i-9] == 't') &&
+ (a[i-8] == 'A') &&
+ (a[i-7] == 't') &&
+ (a[i-6] == 't') &&
+ (a[i-5] == 'r') &&
+ (a[i-4] == 'i') &&
+ (a[i-3] == 'b') &&
+ (a[i-2] == 'u') &&
+ (a[i-1] == 't') &&
+ (a[i] == 'e')) {
+ matchlen = 12;
+ mask |= GetAttribute;
+ } else if (i >= 11 && /* getMBeanInfo */
+ (a[i-11] == 'g') &&
+ (a[i-10] == 'e') &&
+ (a[i-9] == 't') &&
+ (a[i-8] == 'M') &&
+ (a[i-7] == 'B') &&
+ (a[i-6] == 'e') &&
+ (a[i-5] == 'a') &&
+ (a[i-4] == 'n') &&
+ (a[i-3] == 'I') &&
+ (a[i-2] == 'n') &&
+ (a[i-1] == 'f') &&
+ (a[i] == 'o')) {
+ matchlen = 12;
+ mask |= GetMBeanInfo;
+ } else if (i >= 11 && /* isInstanceOf */
+ (a[i-11] == 'i') &&
+ (a[i-10] == 's') &&
+ (a[i-9] == 'I') &&
+ (a[i-8] == 'n') &&
+ (a[i-7] == 's') &&
+ (a[i-6] == 't') &&
+ (a[i-5] == 'a') &&
+ (a[i-4] == 'n') &&
+ (a[i-3] == 'c') &&
+ (a[i-2] == 'e') &&
+ (a[i-1] == 'O') &&
+ (a[i] == 'f')) {
+ matchlen = 12;
+ mask |= IsInstanceOf;
+ } else if (i >= 11 && /* setAttribute */
+ (a[i-11] == 's') &&
+ (a[i-10] == 'e') &&
+ (a[i-9] == 't') &&
+ (a[i-8] == 'A') &&
+ (a[i-7] == 't') &&
+ (a[i-6] == 't') &&
+ (a[i-5] == 'r') &&
+ (a[i-4] == 'i') &&
+ (a[i-3] == 'b') &&
+ (a[i-2] == 'u') &&
+ (a[i-1] == 't') &&
+ (a[i] == 'e')) {
+ matchlen = 12;
+ mask |= SetAttribute;
+ } else if (i >= 10 && /* instantiate */
+ (a[i-10] == 'i') &&
+ (a[i-9] == 'n') &&
+ (a[i-8] == 's') &&
+ (a[i-7] == 't') &&
+ (a[i-6] == 'a') &&
+ (a[i-5] == 'n') &&
+ (a[i-4] == 't') &&
+ (a[i-3] == 'i') &&
+ (a[i-2] == 'a') &&
+ (a[i-1] == 't') &&
+ (a[i] == 'e')) {
+ matchlen = 11;
+ mask |= Instantiate;
+ } else if (i >= 10 && /* queryMBeans */
+ (a[i-10] == 'q') &&
+ (a[i-9] == 'u') &&
+ (a[i-8] == 'e') &&
+ (a[i-7] == 'r') &&
+ (a[i-6] == 'y') &&
+ (a[i-5] == 'M') &&
+ (a[i-4] == 'B') &&
+ (a[i-3] == 'e') &&
+ (a[i-2] == 'a') &&
+ (a[i-1] == 'n') &&
+ (a[i] == 's')) {
+ matchlen = 11;
+ mask |= QueryMBeans;
+ } else if (i >= 9 && /* queryNames */
+ (a[i-9] == 'q') &&
+ (a[i-8] == 'u') &&
+ (a[i-7] == 'e') &&
+ (a[i-6] == 'r') &&
+ (a[i-5] == 'y') &&
+ (a[i-4] == 'N') &&
+ (a[i-3] == 'a') &&
+ (a[i-2] == 'm') &&
+ (a[i-1] == 'e') &&
+ (a[i] == 's')) {
+ matchlen = 10;
+ mask |= QueryNames;
+ } else if (i >= 5 && /* invoke */
+ (a[i-5] == 'i') &&
+ (a[i-4] == 'n') &&
+ (a[i-3] == 'v') &&
+ (a[i-2] == 'o') &&
+ (a[i-1] == 'k') &&
+ (a[i] == 'e')) {
+ matchlen = 6;
+ mask |= Invoke;
+ } else {
+ // parse error
+ throw new IllegalArgumentException("Invalid permission: " +
+ action);
+ }
+
+ // make sure we didn't just match the tail of a word
+ // like "ackbarfaccept". Also, skip to the comma.
+ boolean seencomma = false;
+ while (i >= matchlen && !seencomma) {
+ switch(a[i-matchlen]) {
+ case ',':
+ seencomma = true;
+ break;
+ case ' ': case '\r': case '\n':
+ case '\f': case '\t':
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid permission: " +
+ action);
+ }
+ i--;
+ }
+
+ // point i at the location of the comma minus one (or -1).
+ i -= matchlen;
+ }
+
+ return mask;
+ }
+
+ /**
+ * Checks if this JMXNamespacePermission object "implies" the
+ * specified permission.
+ *
+ * More specifically, this method returns true if:
+ *
+ *
+ *
+ * - p is an instance of JMXNamespacePermission; and
+ *
+ * - p has a null mbeanServerName or p's mbeanServerName
+ * matches this object's mbeanServerName; and
+ *
+ * - p has a null member or p's member matches this
+ * object's member; and
+ *
+ * - p has a null object name or p's
+ * object name matches this object's object name; and
+ *
+ * - p's actions are a subset of this object's actions
+ *
+ *
+ *
+ * If this object's mbeanServerName is a pattern, then p's
+ * mbeanServerName is matched against that pattern. An empty
+ * mbeanServerName is equivalent to "{@code *}". A null
+ * mbeanServerName is equivalent to "{@code -}".
+ * If this object's mbeanServerName is "*
" or is
+ * empty, p's mbeanServerName always matches it.
+ *
+ * If this object's member is "*
", p's
+ * member always matches it.
+ *
+ * If this object's objectName n1 is an object name pattern,
+ * p's objectName n2 matches it if
+ * {@link ObjectName#equals n1.equals(n2)} or if
+ * {@link ObjectName#apply n1.apply(n2)}.
+ *
+ * A permission that includes the queryMBeans
action
+ * is considered to include queryNames
as well.
+ *
+ * @param p the permission to check against.
+ * @return true if the specified permission is implied by this object,
+ * false if not.
+ */
+ public boolean implies(Permission p) {
+ if (!(p instanceof JMXNamespacePermission))
+ return false;
+
+ JMXNamespacePermission that = (JMXNamespacePermission) p;
+
+ // Actions
+ //
+ // The actions in 'this' permission must be a
+ // superset of the actions in 'that' permission
+ //
+
+ /* "queryMBeans" implies "queryNames" */
+ if ((this.mask & QueryMBeans) == QueryMBeans) {
+ if (((this.mask | QueryNames) & that.mask) != that.mask) {
+ //System.out.println("action [with QueryNames] does not imply");
+ return false;
+ }
+ } else {
+ if ((this.mask & that.mask) != that.mask) {
+ //System.out.println("action does not imply");
+ return false;
+ }
+ }
+
+ // Target name
+ //
+ // The 'mbeanServerName' check is true iff:
+ // 1) the mbeanServerName in 'this' permission is omitted or "*", or
+ // 2) the mbeanServerName in 'that' permission is omitted or "*", or
+ // 3) the mbeanServerName in 'this' permission does pattern
+ // matching with the mbeanServerName in 'that' permission.
+ //
+ // The 'member' check is true iff:
+ // 1) the member in 'this' member is omitted or "*", or
+ // 2) the member in 'that' member is omitted or "*", or
+ // 3) the member in 'this' permission equals the member in
+ // 'that' permission.
+ //
+ // The 'object name' check is true iff:
+ // 1) the object name in 'this' permission is omitted, or
+ // 2) the object name in 'that' permission is omitted, or
+ // 3) the object name in 'this' permission does pattern
+ // matching with the object name in 'that' permission.
+ //
+
+ if (that.mbeanServerName == null) {
+ // bottom is implied
+ } else if (this.mbeanServerName == null) {
+ // bottom implies nothing but itself
+ return false;
+ } else if (that.mbeanServerName.equals(this.mbeanServerName)) {
+ // exact match
+ } else if (!Util.wildmatch(that.mbeanServerName,this.mbeanServerName)) {
+ return false; // no match
+ }
+
+ /* Check if this.member implies that.member */
+
+ if (that.member == null) {
+ // bottom is implied
+ } else if (this.member == null) {
+ // bottom implies nothing but itself
+ return false;
+ } else if (this.member.equals("*")) {
+ // wildcard implies everything (including itself)
+ } else if (this.member.equals(that.member)) {
+ // exact match
+ } else if (!Util.wildmatch(that.member,this.member)) {
+ return false; // no match
+ }
+
+ /* Check if this.objectName implies that.objectName */
+
+ if (that.objectName == null) {
+ // bottom is implied
+ } else if (this.objectName == null) {
+ // bottom implies nothing but itself
+ if (allnames == false) return false;
+ } else if (!this.objectName.apply(that.objectName)) {
+ /* ObjectName.apply returns false if that.objectName is a
+ wildcard so we also allow equals for that case. This
+ never happens during real permission checks, but means
+ the implies relation is reflexive. */
+ if (!this.objectName.equals(that.objectName))
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks two JMXNamespacePermission objects for equality. Checks
+ * that obj is an JMXNamespacePermission, and has the same
+ * name and actions as this object.
+ *
+ * @param obj the object we are testing for equality with this object.
+ * @return true if obj is an JMXNamespacePermission, and has the
+ * same name and actions as this JMXNamespacePermission object.
+ */
+ public boolean equals(Object obj) {
+ if (obj == this)
+ return true;
+
+ if (! (obj instanceof JMXNamespacePermission))
+ return false;
+
+ JMXNamespacePermission that = (JMXNamespacePermission) obj;
+
+ return (this.mask == that.mask) &&
+ (this.getName().equals(that.getName()));
+ }
+
+ /**
+ * Deserialize this object based on its name and actions.
+ */
+ private void readObject(ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ parseName();
+ parseActions();
+ }
+}
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/namespace/JMXNamespaceView.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespaceView.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,300 @@
+/*
+ * 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 javax.management.namespace;
+
+import java.io.IOException;
+import java.util.Set;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+/**
+ * This class makes it possible to navigate easily within a hierarchical
+ * namespace view.
+ *
+ *
+ * MBeanServerConnnection rootConnection = ...;
+ *
+ * // create a view at the local root of the namespace hierarchy.
+ * //
+ * JMXNamespaceView view = new JMXNamespaceView(rootConnection);
+ *
+ * // list all top level namespaces
+ * String[] list = view.list();
+ *
+ * // select one namespace from the list
+ * String whereToGo = ... ;
+ *
+ * // go down to the selected namespace:
+ * view = view.down(whereToGo);
+ * System.out.println("I am now in: " + view.where());
+ * System.out.println("I can see these MBeans:" +
+ * view.getMBeanServerConnection().queryNames(null,null));
+ *
+ * // list sub namespaces in current view ('whereToGo')
+ * list = view.list();
+ * System.out.println("Here are the sub namespaces of "+view.where()+": "+
+ * Arrays.toString(list));
+ *
+ * // go up one level
+ * view = view.up();
+ * System.out.println("I am now back to: " +
+ * (view.isRoot() ? "root namespace" : view.where()));
+ *
+ * @since 1.7
+ */
+public class JMXNamespaceView {
+
+ private static final ObjectName ALL_NAMESPACES;
+ static {
+ try {
+ ALL_NAMESPACES = ObjectName.getInstance("*" +
+ JMXNamespaces.NAMESPACE_SEPARATOR + ":"+
+ JMXNamespace.TYPE_ASSIGNMENT);
+ } catch (MalformedObjectNameException x) {
+ throw new ExceptionInInitializerError(x);
+ }
+ }
+ private static final int NAMESPACE_SEPARATOR_LENGTH =
+ JMXNamespaces.NAMESPACE_SEPARATOR.length();
+
+ private final JMXNamespaceView parent;
+ private final MBeanServerConnection here;
+ private final String where;
+
+ private static MBeanServerConnection checkRoot(MBeanServerConnection root) {
+ if (root == null)
+ throw new IllegalArgumentException(
+ "namespaceRoot: null is not a valid value");
+ return root;
+ }
+
+ /**
+ * Creates a view at the top of a JMX namespace hierarchy.
+ * @param namespaceRoot The {@code MBeanServerConnection} at the
+ * top of the hierarchy.
+ */
+ public JMXNamespaceView(MBeanServerConnection namespaceRoot) {
+ this(null,checkRoot(namespaceRoot),"");
+ }
+
+ // This constructor should remain private. A user can only create
+ // JMXNamespaceView at the top of the hierarchy.
+ // JMXNamespaceView sub nodes are created by their parent nodes.
+ private JMXNamespaceView(JMXNamespaceView parent,
+ MBeanServerConnection here, String where) {
+ this.parent = parent;
+ this.here = here;
+ this.where = where;
+ }
+
+ /**
+ * Returns the path leading to the namespace in this view, from
+ * the top of the hierarchy.
+ * @return The path to the namespace in this view.
+ */
+ public String where() {
+ return where;
+ }
+
+ /**
+ * Lists all direct sub namespaces in this view. The returned strings
+ * do not contain the {@code //} separator.
+ *
+ * @return A list of direct sub name spaces accessible from this
+ * namespace.
+ * @throws IOException if the attempt to list the namespaces fails because
+ * of a communication problem.
+ */
+ public String[] list() throws IOException {
+ final Set names =
+ here.queryNames(ALL_NAMESPACES,null);
+ final String[] res = new String[names.size()];
+ int i = 0;
+ for (ObjectName dirName : names) {
+ final String dir = dirName.getDomain();
+ res[i++]=dir.substring(0,dir.length()-NAMESPACE_SEPARATOR_LENGTH);
+ }
+ return res;
+ }
+
+ /**
+ * Go down into a sub namespace.
+ * @param namespace the namespace to go down to. It can contain one or
+ * more {@code //} separators, to traverse intermediate namespaces, but
+ * it must not begin or end with {@code //} or contain an empty
+ * intermediate namespace. If it is the empty string, then {@code this} is
+ * returned.
+ * @return A view of the named sub namespace.
+ * @throws IllegalArgumentException if the {@code namespace} begins or
+ * ends with {@code //}.
+ */
+ public JMXNamespaceView down(String namespace) {
+ if (namespace.equals("")) return this;
+ if (namespace.startsWith(JMXNamespaces.NAMESPACE_SEPARATOR))
+ throw new IllegalArgumentException(namespace+": can't start with "+
+ JMXNamespaces.NAMESPACE_SEPARATOR);
+
+ // This is a convenience to handle paths like xxx//yyy
+ final String[] elts =
+ namespace.split(JMXNamespaces.NAMESPACE_SEPARATOR);
+
+ // Go down the path, creating all sub namespaces along the way.
+ // Usually there will be a single element in the given namespace
+ // name, but we don't want to forbid things like
+ // down("xxx//yyy/www");
+ //
+ JMXNamespaceView previous = this;
+ String cursor = where;
+ for (String elt : elts) {
+ // empty path elements are not allowed. It means we
+ // had something like "xxx////yyy"
+ if (elt.equals(""))
+ throw new IllegalArgumentException(namespace+
+ ": invalid path element");
+
+ // compute the "where" for the child.
+ cursor = JMXNamespaces.concat(cursor, elt);
+
+ // create the child...
+ final JMXNamespaceView next =
+ makeJMXNamespaceView(root(), previous, cursor);
+
+ // the current child will be the parent of the next child...
+ previous = next;
+ }
+
+ // We return the last child that was created.
+ return previous;
+ }
+
+ /**
+ * Go back up one level. If this view is at the root of the
+ * hierarchy, returns {@code null}.
+ * @return A view of the parent namespace, or {@code null} if we're at
+ * the root of the hierarchy.
+ */
+ public JMXNamespaceView up() {
+ return parent;
+ }
+
+ /**
+ * Tells whether this view is at the root of the hierarchy.
+ * @return {@code true} if this view is at the root of the hierachy.
+ */
+ public boolean isRoot() {
+ return parent == null;
+ }
+
+ /**
+ * Returns the view at the root of the hierarchy.
+ * If we are already at the root, this is {@code this}.
+ * @return the view at the root of the hierarchy.
+ */
+ public JMXNamespaceView root() {
+ if (parent == null) return this;
+ return parent.root();
+ }
+
+ /**
+ * A MBeanServerConnection to the namespace shown by this view.
+ * This is what would have been obtained by doing:
+ *
+ * JMX.narrowToNamespace(this.root().getMBeanServerConnection(),
+ * this.where());
+ *
+ * @return A MBeanServerConnection to the namespace shown by this view.
+ */
+ public MBeanServerConnection getMBeanServerConnection() {
+ return here;
+ }
+
+ /**
+ * Get the name of the JMXNamespaceMBean handling the namespace shown by
+ * this view, relative to the root of the hierarchy. If we are at the root
+ * of the hierarchy, this method returns {@code null}.
+ *
+ * You can use this method to make a proxy for the JMXNamespaceMBean
+ * as follows:
+ *
+ *
+ * JMXNamespaceView view = ...;
+ * ObjectName namespaceMBeanName = view.getJMXNamespaceMBeanName();
+ * JMXNamespaceMBean namespaceMBean = JMX.newMBeanProxy(
+ * view.root().getMBeanServerConnection(), namespaceMBeanName,
+ * JMXNamespaceMBean.class);
+ *
+ *
+ * @return The name of the {@code JMXNamespaceMBean} handling the namespace
+ * shown by this view, or {@code null}.
+ */
+ public ObjectName getJMXNamespaceMBeanName() {
+ if (parent == null)
+ return null;
+ else
+ return JMXNamespaces.getNamespaceObjectName(where);
+ }
+
+ @Override
+ public int hashCode() {
+ return where.hashCode();
+ }
+
+ /**
+ * Returns true if this object is equal to the given object. The
+ * two objects are equal if the other object is also a {@code
+ * JMXNamespaceView} and both objects have the same {@linkplain #root root}
+ * MBeanServerConnection and the same {@linkplain #where path}.
+ * @param o the other object to compare to.
+ * @return true if both objects are equal.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o==this) return true;
+ if (! (o instanceof JMXNamespaceView)) return false;
+ if (!where.equals(((JMXNamespaceView)o).where)) return false;
+ return root().getMBeanServerConnection().equals(
+ ((JMXNamespaceView)o).root().getMBeanServerConnection());
+ }
+
+ private JMXNamespaceView makeJMXNamespaceView(final JMXNamespaceView root,
+ final JMXNamespaceView directParent, final String pathFromRoot) {
+ if (pathFromRoot.equals("")) return root;
+
+ return new JMXNamespaceView(directParent,
+ narrowToNamespace(root.getMBeanServerConnection(),
+ pathFromRoot),pathFromRoot);
+ }
+
+ private MBeanServerConnection narrowToNamespace(MBeanServerConnection root,
+ String path) {
+ if (root instanceof MBeanServer)
+ return JMXNamespaces.narrowToNamespace((MBeanServer)root, path);
+ return JMXNamespaces.narrowToNamespace(root, path);
+ }
+
+}
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,374 @@
+/*
+ * 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 javax.management.namespace;
+
+import com.sun.jmx.defaults.JmxProperties;
+import com.sun.jmx.namespace.JMXNamespaceUtils;
+import com.sun.jmx.namespace.ObjectNameRouter;
+import com.sun.jmx.namespace.serial.RewritingProcessor;
+import com.sun.jmx.namespace.RoutingConnectionProxy;
+import com.sun.jmx.namespace.RoutingServerProxy;
+
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+
+/**
+ * Static constants and utility methods to help work with
+ * JMX name spaces. There are no instances of this class.
+ * @since 1.7
+ */
+public class JMXNamespaces {
+
+ /**
+ * A logger for this class.
+ **/
+ private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
+
+ /** Creates a new instance of JMXNamespaces */
+ private JMXNamespaces() {
+ }
+
+ /**
+ * The name space separator. This is an alias for {@link
+ * ObjectName#NAMESPACE_SEPARATOR}.
+ **/
+ public static final String NAMESPACE_SEPARATOR =
+ ObjectName.NAMESPACE_SEPARATOR;
+ private static final int NAMESPACE_SEPARATOR_LENGTH =
+ NAMESPACE_SEPARATOR.length();
+
+
+ /**
+ * Returns a connector connected to a sub name space exposed through
+ * the parent connector.
+ * @param parent the parent connector.
+ * @param namespace the {@linkplain javax.management.namespace name space}
+ * to which the returned connector is
+ * connected.
+ * @return A connector connected to a sub name space exposed through
+ * the parent connector.
+ **/
+ public static JMXConnector narrowToNamespace(final JMXConnector parent,
+ final String namespace)
+ throws IOException {
+
+ return JMXNamespaceUtils.cd(parent,namespace,true);
+ }
+
+ /**
+ * Creates a new {@code MBeanServerConnection} proxy on a
+ * {@linkplain javax.management.namespace sub name space}
+ * of the given parent.
+ *
+ * @param parent The parent {@code MBeanServerConnection} that contains
+ * the name space.
+ * @param namespace The {@linkplain javax.management.namespace
+ * name space} in which to narrow.
+ * @return A new {@code MBeanServerConnection} proxy that shows the content
+ * of that name space.
+ * @throws IllegalArgumentException if the name space does not exist, or
+ * if a proxy for that name space cannot be created.
+ */
+ public static MBeanServerConnection narrowToNamespace(
+ MBeanServerConnection parent,
+ String namespace) {
+ if (LOG.isLoggable(Level.FINER))
+ LOG.finer("Making MBeanServerConnection for: " +namespace);
+ return RoutingConnectionProxy.cd(parent,namespace);
+ }
+
+ /**
+ * Creates a new {@code MBeanServer} proxy on a
+ * {@linkplain javax.management.namespace sub name space}
+ * of the given parent.
+ *
+ * @param parent The parent {@code MBeanServer} that contains
+ * the name space.
+ * @param namespace The {@linkplain javax.management.namespace
+ * name space} in which to narrow.
+ * @return A new {@code MBeanServer} proxy that shows the content
+ * of that name space.
+ * @throws IllegalArgumentException if either argument is null,
+ * or the name space does not exist, or if a proxy for that name space
+ * cannot be created.
+ */
+ public static MBeanServer narrowToNamespace(MBeanServer parent,
+ String namespace) {
+ if (LOG.isLoggable(Level.FINER))
+ LOG.finer("Making NamespaceServerProxy for: " +namespace);
+ return RoutingServerProxy.cd(parent,namespace);
+ }
+
+ /**
+ * Returns an object that is the same as the given object except that
+ * any {@link ObjectName} it might contain has its domain modified.
+ * The returned object might be identical to the given object if it
+ * does not contain any {@code ObjectName} values or if none of them
+ * were modified.
+ * This method will replace a prefix ({@code toRemove}) from the path of
+ * the ObjectNames contained in {@code obj} by another prefix
+ * ({@code toAdd}).
+ * Therefore, all contained ObjectNames must have a path that start with
+ * the given {@code toRemove} prefix. If one of them doesn't, an {@link
+ * IllegalArgumentException} is thrown.
+ *
+ * For instance, if {@code obj} contains the ObjectName
+ * {@code x//y//z//d:k=x}, and {@code toAdd} is {@code v//w}, and
+ * {@code toRemove}
+ * is {@code x//y} this method will return a copy of {@code obj} that
+ * contains {@code v//w//z//d:k=x}.
+ * On the other hand, if {@code obj} contains the ObjectName
+ * {@code x//y//z//d:k=x}, and {@code toAdd} is {@code v//w}, and
+ * {@code toRemove} is {@code v} this method
+ * will raise an exception, because {@code x//y//z//d:k=x} doesn't start
+ * with {@code v}
+ *
+ * Note: the default implementation of this method can use the
+ * Java serialization framework to clone and replace ObjectNames in the
+ * provided {@code obj}. It will usually fail if {@code obj} is not
+ * Java serializable, or contains objects which are not Java
+ * serializable.
+ *
+ * @param obj The object to deep-rewrite
+ * @param toRemove a prefix already present in contained ObjectNames.
+ * If {@code toRemove} is the empty string {@code ""}, nothing
+ * will be removed from the contained ObjectNames.
+ * @param toAdd the prefix that will replace (@code toRemove} in contained
+ * ObjectNames.
+ * If {@code toAdd} is the empty string {@code ""}, nothing
+ * will be added to the contained ObjectNames.
+ * @return the rewritten object, or possibly {@code obj} if nothing needed
+ * to be changed.
+ * @throws IllegalArgumentException if {@code obj} couldn't be rewritten or
+ * if {@code toRemove} or {@code toAdd} is null.
+ **/
+ public static T deepReplaceHeadNamespace(T obj, String toRemove, String toAdd) {
+ final RewritingProcessor processor =
+ RewritingProcessor.newRewritingProcessor(toAdd,toRemove);
+ return processor.rewriteOutput(obj);
+ }
+
+ /**
+ * Appends {@code namespace} to {@code path}.
+ * This methods appends {@code namespace} to {@code path} to obtain a
+ * a full path, and normalizes the result thus obtained:
+ *
+ * - If {@code path} is empty, the full path is
+ * {@code namespace}.
+ * - Otherwise, if {@code namespace} is empty,
+ * the full path is {@code path}
+ * - Otherwise, and this is the regular case, the full path is the
+ * result of the concatenation of
+ * {@code path}+{@value #NAMESPACE_SEPARATOR}+{@code namespace}
+ * - finally, the full path is normalized: multiple consecutive
+ * occurrences of {@value #NAMESPACE_SEPARATOR} are replaced by a
+ * single {@value #NAMESPACE_SEPARATOR} in the result, and trailing
+ * occurences of {@value #NAMESPACE_SEPARATOR} are removed.
+ *
+ *
+ * @param path a name space path prefix
+ * @param namespace a name space name to append to the path
+ * @return a syntactically valid name space path, or "" if both parameters
+ * are null or empty.
+ * @throws IllegalArgumentException if either argument is null or ends with
+ * an odd number of {@code /} characters.
+ **/
+ public static String concat(String path, String namespace) {
+ if (path == null || namespace == null)
+ throw new IllegalArgumentException("Null argument");
+ checkTrailingSlashes(path);
+ checkTrailingSlashes(namespace);
+ final String result;
+ if (path.equals("")) result=namespace;
+ else if (namespace.equals("")) result=path;
+ else result=path+NAMESPACE_SEPARATOR+namespace;
+ return ObjectNameRouter.normalizeNamespacePath(result,false,true,false);
+ }
+
+ /**
+ * Returns a syntactically valid name space path.
+ * If the provided {@code namespace} ends with {@code "//"},
+ * recursively strips trailing {@code "//"}. Each sequence of an
+ * even number of {@code "/"} characters is also replaced by {@code "//"},
+ * for example {@code "foo//bar////baz/////buh"} will become
+ * {@code "foo//bar//baz///buh"}.
+ *
+ * @param namespace A name space path
+ * @return {@code ""} - if the provided {@code namespace} resolves to
+ * the empty string; otherwise a syntactically valid name space string
+ * stripped of trailing and redundant {@code "//"}.
+ * @throws IllegalArgumentException if {@code namespace} is null or
+ * is not syntactically valid (e.g. it contains
+ * invalid characters like ':', or it ends with an odd
+ * number of '/').
+ */
+ public static String normalizeNamespaceName(String namespace) {
+ if (namespace == null)
+ throw new IllegalArgumentException("Null namespace");
+ final String sourcePath =
+ ObjectNameRouter.normalizeNamespacePath(namespace,false,true,false);
+ if (sourcePath.equals("")) return sourcePath;
+
+ // Will throw an IllegalArgumentException if the namespace name
+ // is not syntactically valid...
+ //
+ getNamespaceObjectName(sourcePath);
+ return sourcePath;
+ }
+
+
+ /**
+ * Return a canonical handler name for the provided {@code namespace},
+ * The handler name returned will be
+ * {@link #normalizeNamespaceName normalizeNamespaceName}{@code (namespace) +
+ * "//:type=JMXNamespace"}.
+ *
+ * @param namespace A name space path
+ * @return a canonical ObjectName for a name space handler.
+ * @see #normalizeNamespaceName
+ * @throws IllegalArgumentException if the provided
+ * {@code namespace} is null or not valid.
+ */
+ public static ObjectName getNamespaceObjectName(String namespace) {
+ if (namespace == null || namespace.equals(""))
+ throw new IllegalArgumentException("Null or empty namespace");
+ final String sourcePath =
+ ObjectNameRouter.normalizeNamespacePath(namespace,false,
+ true,false);
+ try {
+ return ObjectName.getInstance(sourcePath+
+ NAMESPACE_SEPARATOR+":"+
+ JMXNamespace.TYPE_ASSIGNMENT);
+ } catch (MalformedObjectNameException x) {
+ throw new IllegalArgumentException(namespace,x);
+ }
+ }
+
+ /**
+ * Returns an ObjectName pattern that can be used to query for all MBeans
+ * contained in the given name space.
+ * For instance, if {@code namespace="foo//bar"}, this method will
+ * return {@code "foo//bar//*:*"}
+ * @return an ObjectName pattern that selects all MBeans in the given
+ * name space.
+ **/
+ public static ObjectName getWildcardFor(String namespace) {
+ return insertPath(namespace,ObjectName.WILDCARD);
+ }
+
+
+ /**
+ * Returns an ObjectName that can be used to access an MBean
+ * contained in the given name space.
+ * For instance, if {@code path="foo//bar"}, and
+ * {@code to="domain:type=Thing"} this method will
+ * return {@code "foo//bar//domain:type=Thing"}
+ * @return an ObjectName that can be used to invoke an MBean located in a
+ * sub name space.
+ * @throws IllegalArgumentException if {@code path} ends with an
+ * odd number of {@code /} characters.
+ **/
+ public static ObjectName insertPath(String path, ObjectName to) {
+ if (path == null || to == null)
+ throw new IllegalArgumentException("Null argument");
+ checkTrailingSlashes(path);
+ try {
+ String prefix = path;
+ if (!prefix.equals("")) prefix =
+ ObjectNameRouter.normalizeNamespacePath(
+ prefix + NAMESPACE_SEPARATOR,false,false,false);
+ return to.withDomain(
+ ObjectNameRouter.normalizeDomain(
+ prefix+to.getDomain(),false));
+ } catch (MalformedObjectNameException x) {
+ throw new IllegalArgumentException(path+": "+x,x);
+ }
+ }
+
+ /**
+ * Returns the normalized name space path of the name space expected to
+ * contain {@code ObjectName}.
+ * For instance, for {@code "foo//domain:type=Thing"} this will be
+ * {@code "foo"}. For {@code "//foo//bar//domain:type=Thing"} this will be
+ * {@code "foo//bar"}. For {@code //foo//bar//baz//domain:type=Thing}
+ * this will be {@code "foo//bar//baz"}. For
+ * {@code //foo//bar//baz//:type=JMXNamespace}
+ * this will be {@code "foo//bar"}.
+ *
+ * @param name an {@code ObjectName}
+ * @return the name space path of the name space that could contain such
+ * a name. If {@code name} has no name space, returns {@code ""}.
+ * @throws IllegalArgumentException if {@code name} is null.
+ **/
+ public static String getContainingNamespace(ObjectName name) {
+ return getNormalizedPath(name,true);
+ }
+
+
+ static String getNormalizedPath(ObjectName name,
+ boolean removeLeadingSep) {
+ if (name == null)
+ throw new IllegalArgumentException("Null name");
+ String domain =
+ ObjectNameRouter.normalizeDomain(name.getDomain(),removeLeadingSep);
+ int end = domain.length();
+
+ // special case of domain part being a single '/'
+ //
+ if (domain.endsWith(NAMESPACE_SEPARATOR+"/"))
+ return domain.substring(0,end-NAMESPACE_SEPARATOR_LENGTH-1);
+
+ // special case of namespace handler
+ //
+ if (domain.endsWith(NAMESPACE_SEPARATOR))
+ domain = domain.substring(0,end-NAMESPACE_SEPARATOR_LENGTH);
+
+ int last = domain.lastIndexOf(NAMESPACE_SEPARATOR);
+ if (last < 0) return "";
+ if (last == 0) return domain;
+
+ // special case of domain part starting with '/'
+ // last=0 is not possible - we took care of this above.
+ if (domain.charAt(last-1) == '/') last--;
+
+ return domain.substring(0,last);
+ }
+
+ private static void checkTrailingSlashes(String path) {
+ int i;
+ for (i = path.length() - 1; i >= 0 && path.charAt(i) == '/'; i--)
+ continue;
+ if (path.length() - i % 2 == 0)
+ throw new IllegalArgumentException("Path ends with odd number of /");
+ }
+}
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,837 @@
+/*
+ * 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 javax.management.namespace;
+
+import com.sun.jmx.defaults.JmxProperties;
+import com.sun.jmx.mbeanserver.Util;
+import com.sun.jmx.namespace.JMXNamespaceUtils;
+import com.sun.jmx.namespace.NamespaceInterceptor.DynamicProbe;
+import com.sun.jmx.remote.util.EnvHelp;
+
+import java.io.IOException;
+import java.security.AccessControlException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.management.AttributeChangeNotification;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanPermission;
+import javax.management.MBeanServerConnection;
+import javax.management.MalformedObjectNameException;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventClient;
+import javax.management.remote.JMXConnectionNotification;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+
+/**
+ * A {@link JMXNamespace} that will connect to a remote MBeanServer
+ * by creating a {@link javax.management.remote.JMXConnector} from a
+ * {@link javax.management.remote.JMXServiceURL}.
+ *
+ * You can call {@link #connect() connect()} and {@link #close close()}
+ * several times. This MBean will emit an {@link AttributeChangeNotification}
+ * when the value of its {@link #isConnected Connected} attribute changes.
+ *
+ *
+ * The JMX Remote Namespace MBean is not connected until {@link
+ * #connect() connect()} is explicitly called. The usual sequence of code to
+ * create a JMX Remote Namespace is thus:
+ *
+ *
+ * final String namespace = "mynamespace";
+ * final ObjectName name = {@link JMXNamespaces#getNamespaceObjectName
+ * JMXNamespaces.getNamespaceObjectName(namespace)};
+ * final JMXServiceURL remoteServerURL = .... ;
+ * final Map optionsMap = .... ;
+ * final MBeanServer masterMBeanServer = .... ;
+ * final JMXRemoteNamespace namespaceMBean = {@link #newJMXRemoteNamespace
+ * JMXRemoteNamespace.newJMXRemoteNamespace(remoteServerURL, optionsMap)};
+ * masterMBeanServer.registerMBean(namespaceMBean, name);
+ * namespaceMBean.connect();
+ * // or: masterMBeanServer.invoke(name, {@link #connect() "connect"}, null, null);
+ *
+ *
+ * The JMX Remote Namespace MBean will register for {@linkplain
+ * JMXConnectionNotification JMX Connection Notifications} with its underlying
+ * {@link JMXConnector}. When a JMX Connection Notification indicates that
+ * the underlying connection has failed, the JMX Remote Namespace MBean
+ * closes its underlying connector and switches its {@link #isConnected
+ * Connected} attribute to false, emitting an {@link
+ * AttributeChangeNotification}.
+ *
+ *
+ * At this point, a managing application (or an administrator connected
+ * through a management console) can attempt to reconnect the
+ * JMX Remote Namespace MBean by calling its {@link #connect() connect()} method
+ * again.
+ *
+ * Note that when the connection with the remote namespace fails, or when
+ * {@link #close} is called, then any notification subscription to
+ * MBeans registered in that namespace will be lost - unless a custom
+ * {@linkplain javax.management.event event service} supporting connection-less
+ * mode was used.
+ *
+ * @since 1.7
+ */
+public class JMXRemoteNamespace
+ extends JMXNamespace
+ implements JMXRemoteNamespaceMBean, NotificationEmitter {
+
+ /**
+ * A logger for this class.
+ */
+ private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
+
+ private static final Logger PROBE_LOG = Logger.getLogger(
+ JmxProperties.NAMESPACE_LOGGER_NAME+".probe");
+
+
+ // This connection listener is used to listen for connection events from
+ // the underlying JMXConnector. It is used in particular to maintain the
+ // "connected" state in this MBean.
+ //
+ private static class ConnectionListener implements NotificationListener {
+ private final JMXRemoteNamespace handler;
+ private ConnectionListener(JMXRemoteNamespace handler) {
+ this.handler = handler;
+ }
+ public void handleNotification(Notification notification,
+ Object handback) {
+ if (!(notification instanceof JMXConnectionNotification))
+ return;
+ final JMXConnectionNotification cn =
+ (JMXConnectionNotification)notification;
+ handler.checkState(this,cn,(JMXConnector)handback);
+ }
+ }
+
+ // When the JMXRemoteNamespace is originally created, it is not connected,
+ // which means that the source MBeanServer should be one that throws
+ // exceptions for most methods. When it is subsequently connected,
+ // the methods should be forwarded to the MBeanServerConnection.
+ // We handle this using MBeanServerConnectionWrapper. The
+ // MBeanServerConnection that is supplied to the constructor of
+ // MBeanServerConnectionWrapper is ignored (and in fact it is null)
+ // because the one that is actually used is the one supplied by the
+ // override of getMBeanServerConnection().
+ private static class JMXRemoteNamespaceDelegate
+ extends MBeanServerConnectionWrapper
+ implements DynamicProbe {
+ private volatile JMXRemoteNamespace parent=null;
+
+ JMXRemoteNamespaceDelegate() {
+ super(null,null);
+ }
+ @Override
+ public MBeanServerConnection getMBeanServerConnection() {
+ return parent.getMBeanServerConnection();
+ }
+ @Override
+ public ClassLoader getDefaultClassLoader() {
+ return parent.getDefaultClassLoader();
+ }
+
+ // Because this class is instantiated in the super() call from the
+ // constructor of JMXRemoteNamespace, it cannot be an inner class.
+ // This method achieves the effect that an inner class would have
+ // had, of giving the class a reference to the outer "this".
+ synchronized void initParentOnce(JMXRemoteNamespace parent) {
+ if (this.parent != null)
+ throw new UnsupportedOperationException("parent already set");
+ this.parent=parent;
+
+ }
+
+ public boolean isProbeRequested() {
+ return this.parent.isProbeRequested();
+ }
+ }
+
+ private static final MBeanNotificationInfo connectNotification =
+ new MBeanNotificationInfo(new String[] {
+ AttributeChangeNotification.ATTRIBUTE_CHANGE},
+ "Connected",
+ "Emitted when the Connected state of this object changes");
+
+ private static long seqNumber=0;
+
+ private final NotificationBroadcasterSupport broadcaster;
+ private final ConnectionListener listener;
+ private final JMXServiceURL jmxURL;
+ private final Map optionsMap;
+
+ private volatile MBeanServerConnection server = null;
+ private volatile JMXConnector conn = null;
+ private volatile ClassLoader defaultClassLoader = null;
+ private volatile boolean probed;
+
+ /**
+ * Creates a new instance of {@code JMXRemoteNamespace}.
+ *
+ * This constructor is provided for subclasses.
+ * To create a new instance of {@code JMXRemoteNamespace} call
+ * {@link #newJMXRemoteNamespace
+ * JMXRemoteNamespace.newJMXRemoteNamespace(sourceURL, optionsMap)}.
+ *
+ * @param sourceURL a JMX service URL that can be used to {@linkplain
+ * #connect() connect} to the
+ * source MBean Server. The source MBean Server is the remote
+ * MBean Server which contains the MBeans that will be mirrored
+ * in this namespace.
+ * @param optionsMap the options map that will be passed to the
+ * {@link JMXConnectorFactory} when {@linkplain
+ * JMXConnectorFactory#newJMXConnector creating} the
+ * {@link JMXConnector} used to {@linkplain #connect() connect}
+ * to the remote source MBean Server. Can be null, which is
+ * equivalent to an empty map.
+ * @see #newJMXRemoteNamespace JMXRemoteNamespace.newJMXRemoteNamespace
+ * @see #connect
+ */
+ protected JMXRemoteNamespace(JMXServiceURL sourceURL,
+ Map optionsMap) {
+ super(new JMXRemoteNamespaceDelegate());
+ ((JMXRemoteNamespaceDelegate)super.getSourceServer()).
+ initParentOnce(this);
+
+ // URL must not be null.
+ this.jmxURL = JMXNamespaceUtils.checkNonNull(sourceURL,"url");
+ this.broadcaster =
+ new NotificationBroadcasterSupport(connectNotification);
+
+ // handles options
+ this.optionsMap = JMXNamespaceUtils.unmodifiableMap(optionsMap);
+
+ // handles (dis)connection events
+ this.listener = new ConnectionListener(this);
+
+ // XXX TODO: remove the probe, or simplify it.
+ this.probed = false;
+ }
+
+ /**
+ * Returns the {@code JMXServiceURL} that is (or will be) used to
+ * connect to the remote name space.
+ * @see #connect
+ * @return The {@code JMXServiceURL} used to connect to the remote
+ * name space.
+ */
+ public JMXServiceURL getJMXServiceURL() {
+ return jmxURL;
+ }
+
+ /**
+ * In this class, this method never returns {@code null}, and the
+ * address returned is the {@link #getJMXServiceURL JMXServiceURL}
+ * that is used by this object to {@linkplain #connect} to the remote
+ * name space.
+ * This behaviour might be overriden by subclasses, if needed.
+ * For instance, a subclass might want to return {@code null} if it
+ * doesn't want to expose that JMXServiceURL.
+ */
+ public JMXServiceURL getAddress() {
+ return getJMXServiceURL();
+ }
+
+ private Map getEnvMap() {
+ return optionsMap;
+ }
+
+ boolean isProbeRequested() {
+ return probed==false;
+ }
+
+ public void addNotificationListener(NotificationListener listener,
+ NotificationFilter filter, Object handback) {
+ broadcaster.addNotificationListener(listener, filter, handback);
+ }
+
+ /**
+ * A subclass that needs to send its own notifications must override
+ * this method in order to return an {@link MBeanNotificationInfo
+ * MBeanNotificationInfo[]} array containing both its own notification
+ * infos and the notification infos of its super class.
+ * The implementation should probably look like:
+ *
+ * final MBeanNotificationInfo[] myOwnNotifs = { .... };
+ * final MBeanNotificationInfo[] parentNotifs =
+ * super.getNotificationInfo();
+ * final Set mergedResult =
+ * new HashSet();
+ * mergedResult.addAll(Arrays.asList(myOwnNotifs));
+ * mergedResult.addAll(Arrays.asList(parentNotifs));
+ * return mergeResult.toArray(
+ * new MBeanNotificationInfo[mergedResult.size()]);
+ *
+ */
+ public MBeanNotificationInfo[] getNotificationInfo() {
+ return broadcaster.getNotificationInfo();
+ }
+
+ public void removeNotificationListener(NotificationListener listener)
+ throws ListenerNotFoundException {
+ broadcaster.removeNotificationListener(listener);
+ }
+
+ public void removeNotificationListener(NotificationListener listener,
+ NotificationFilter filter, Object handback)
+ throws ListenerNotFoundException {
+ broadcaster.removeNotificationListener(listener, filter, handback);
+ }
+
+ private static synchronized long getNextSeqNumber() {
+ return seqNumber++;
+ }
+
+
+ /**
+ * Sends a notification to registered listeners. Before the notification
+ * is sent, the following steps are performed:
+ * -
+ * If {@code n.getSequenceNumber() <= 0} set it to the next available
+ * sequence number.
+ * - If {@code n.getSource() == null}, set it to the value returned by {@link
+ * #getObjectName getObjectName()}.
+ *
+ * This method can be called by subclasses in order to send their own
+ * notifications.
+ * In that case, these subclasses might also need to override
+ * {@link #getNotificationInfo} in order to declare their own
+ * {@linkplain MBeanNotificationInfo notification types}.
+ *
+ * @param n The notification to send to registered listeners.
+ * @see javax.management.NotificationBroadcasterSupport
+ * @see #getNotificationInfo
+ **/
+ protected void sendNotification(Notification n) {
+ if (n.getSequenceNumber()<=0)
+ n.setSequenceNumber(getNextSeqNumber());
+ if (n.getSource()==null)
+ n.setSource(getObjectName());
+ broadcaster.sendNotification(n);
+ }
+
+ private void checkState(ConnectionListener listener,
+ JMXConnectionNotification cn,
+ JMXConnector emittingConnector) {
+
+ // Due to the asynchronous handling of notifications, it is
+ // possible that this method is called for a JMXConnector
+ // (or connection) which is already closed and replaced by a newer
+ // one.
+ //
+ // This method attempts to determine the real state of the
+ // connection - which might be different from what the notification
+ // says.
+ //
+ // This is quite complex logic - because we try not to hold any
+ // lock while evaluating the true value of the connected state,
+ // while anyone might also call close() or connect() from a
+ // different thread.
+ //
+ // The method switchConnection() (called from here too) also has the
+ // same kind of complex logic.
+ //
+ // We use the JMXConnector has a handback to the notification listener
+ // (emittingConnector) in order to be able to determine whether the
+ // notification concerns the current connector in use, or an older
+ // one.
+ //
+ boolean remove = false;
+
+ // whether the emittingConnector is already 'removed'
+ synchronized (this) {
+ if (this.conn != emittingConnector ||
+ JMXConnectionNotification.FAILED.equals(cn.getType()))
+ remove = true;
+ }
+
+ // We need to unregister our listener from this 'removed' connector.
+ // This is the only place where we remove the listener.
+ //
+ if (remove) {
+ try {
+ // This may fail if the connector is already closed.
+ // But better unregister anyway...
+ //
+ emittingConnector.removeConnectionNotificationListener(
+ listener,null,
+ emittingConnector);
+ } catch (Exception x) {
+ LOG.log(Level.FINE,
+ "Failed to unregister connection listener"+x);
+ LOG.log(Level.FINEST,
+ "Failed to unregister connection listener",x);
+ }
+ try {
+ // This may fail if the connector is already closed.
+ // But better call close twice and get an exception than
+ // leaking...
+ //
+ emittingConnector.close();
+ } catch (Exception x) {
+ LOG.log(Level.FINEST,
+ "Failed to close old connector " +
+ "(failure was expected): "+x);
+ }
+ }
+
+ // Now we checked whether our current connector is still alive.
+ //
+ boolean closed = false;
+ final JMXConnector thisconn = this.conn;
+ try {
+ if (thisconn != null)
+ thisconn.getConnectionId();
+ } catch (IOException x) {
+ LOG.finest("Connector already closed: "+x);
+ closed = true;
+ }
+
+ // We got an IOException - the connector is not connected.
+ // Need to forget it and switch our state to closed.
+ //
+ if (closed) {
+ switchConnection(thisconn,null,null);
+ try {
+ // Usually this will fail... Better call close twice
+ // and get an exception than leaking...
+ //
+ if (thisconn != emittingConnector || !remove)
+ thisconn.close();
+ } catch (IOException x) {
+ LOG.log(Level.FINEST,
+ "Failed to close connector (failure was expected): "
+ +x);
+ }
+ }
+ }
+
+ private final void switchConnection(JMXConnector oldc,
+ JMXConnector newc,
+ MBeanServerConnection mbs) {
+ boolean connect = false;
+ boolean close = false;
+ synchronized (this) {
+ if (oldc != conn) {
+ if (newc != null) {
+ try {
+ newc.close();
+ } catch (IOException x) {
+ LOG.log(Level.FINEST,
+ "Failed to close connector",x);
+ }
+ }
+ return;
+ }
+ if (conn == null && newc != null) connect=true;
+ if (newc == null && conn != null) close = true;
+ conn = newc;
+ server = mbs;
+ }
+ if (connect || close) {
+ boolean oldstate = close;
+ boolean newstate = connect;
+ final ObjectName myName = getObjectName();
+
+ // In the uncommon case where the MBean is connected before
+ // being registered, myName can be null...
+ // If myName is null - we use 'this' as the source instead...
+ //
+ final Object source = (myName==null)?this:myName;
+ final AttributeChangeNotification acn =
+ new AttributeChangeNotification(source,
+ getNextSeqNumber(),System.currentTimeMillis(),
+ String.valueOf(source)+
+ (newstate?" connected":" closed"),
+ "Connected",
+ "boolean",
+ Boolean.valueOf(oldstate),
+ Boolean.valueOf(newstate));
+ sendNotification(acn);
+ }
+ }
+
+ private void closeall(JMXConnector... a) {
+ for (JMXConnector c : a) {
+ try {
+ if (c != null) c.close();
+ } catch (Exception x) {
+ // OK: we're gonna throw the original exception later.
+ LOG.finest("Ignoring exception when closing connector: "+x);
+ }
+ }
+ }
+
+ JMXConnector connect(JMXServiceURL url, Map env)
+ throws IOException {
+ final JMXConnector c = newJMXConnector(jmxURL, env);
+ c.connect(env);
+ return c;
+ }
+
+ /**
+ * Creates a new JMXConnector with the specified {@code url} and
+ * {@code env} options map.
+ *
+ * This method first calls {@link JMXConnectorFactory#newJMXConnector
+ * JMXConnectorFactory.newJMXConnector(jmxURL, env)} to obtain a new
+ * JMX connector, and returns that.
+ *
+ *
+ * A subclass of {@link JMXRemoteNamespace} can provide an implementation
+ * that connects to a sub namespace of the remote server by subclassing
+ * this class in the following way:
+ *
+ * class JMXRemoteSubNamespace extends JMXRemoteNamespace {
+ * private final String subnamespace;
+ * JMXRemoteSubNamespace(JMXServiceURL url,
+ * Map{@code } env, String subnamespace) {
+ * super(url,options);
+ * this.subnamespace = subnamespace;
+ * }
+ * protected JMXConnector newJMXConnector(JMXServiceURL url,
+ * Map env) throws IOException {
+ * final JMXConnector inner = super.newJMXConnector(url,env);
+ * return {@link JMXNamespaces#narrowToNamespace(JMXConnector,String)
+ * JMXNamespaces.narrowToNamespace(inner,subnamespace)};
+ * }
+ * }
+ *
+ *
+ *
+ * Some connectors, like the JMXMP connector server defined by the
+ * version 1.2 of the JMX API may not have been upgraded to use the
+ * new {@linkplain javax.management.event Event Service} defined in this
+ * version of the JMX API.
+ *
+ * In that case, and if the remote server to which this JMXRemoteNamespace
+ * connects also contains namespaces, it may be necessary to configure
+ * explicitly an {@linkplain
+ * javax.management.event.EventClientDelegate#newForwarder()
+ * Event Client Forwarder} on the remote server side, and to force the use
+ * of an {@link EventClient} on this client side.
+ *
+ * A subclass of {@link JMXRemoteNamespace} can provide an implementation
+ * of {@code newJMXConnector} that will force notification subscriptions
+ * to flow through an {@link EventClient} over a legacy protocol by
+ * overriding this method in the following way:
+ *
+ *
+ * class JMXRemoteEventClientNamespace extends JMXRemoteNamespace {
+ * JMXRemoteSubNamespaceConnector(JMXServiceURL url,
+ * Map env) {
+ * super(url,options);
+ * }
+ * protected JMXConnector newJMXConnector(JMXServiceURL url,
+ * Map env) throws IOException {
+ * final JMXConnector inner = super.newJMXConnector(url,env);
+ * return {@link EventClient#withEventClient(
+ * JMXConnector) EventClient.withEventClient(inner)};
+ * }
+ * }
+ *
+ *
+ * Note that the remote server also needs to provide an {@link
+ * javax.management.event.EventClientDelegateMBean}: only configuring
+ * the client side (this object) is not enough.
+ * In summary, this technique should be used if the remote server
+ * supports JMX namespaces, but uses a JMX Connector Server whose
+ * implementation does not transparently use the new Event Service
+ * (as would be the case with the JMXMPConnectorServer implementation
+ * from the reference implementation of the JMX Remote API 1.0
+ * specification).
+ *
+ * @param url The JMXServiceURL of the remote server.
+ * @param optionsMap An unmodifiable options map that will be passed to the
+ * {@link JMXConnectorFactory} when {@linkplain
+ * JMXConnectorFactory#newJMXConnector creating} the
+ * {@link JMXConnector} that can connect to the remote source
+ * MBean Server.
+ * @return An unconnected JMXConnector to use to connect to the remote
+ * server
+ * @throws java.io.IOException if the connector could not be created.
+ * @see JMXConnectorFactory#newJMXConnector(javax.management.remote.JMXServiceURL, java.util.Map)
+ * @see #JMXRemoteNamespace
+ */
+ protected JMXConnector newJMXConnector(JMXServiceURL url,
+ Map optionsMap) throws IOException {
+ final JMXConnector c =
+ JMXConnectorFactory.newJMXConnector(jmxURL, optionsMap);
+// TODO: uncomment this when contexts are added
+// return ClientContext.withDynamicContext(c);
+ return c;
+ }
+
+ public void connect() throws IOException {
+ if (conn != null) {
+ try {
+ // This is much too fragile. It must go away!
+ PROBE_LOG.finest("Probing again...");
+ triggerProbe(getMBeanServerConnection());
+ } catch(Exception x) {
+ close();
+ Throwable cause = x;
+ // if the cause is a security exception - rethrows it...
+ while (cause != null) {
+ if (cause instanceof SecurityException)
+ throw (SecurityException) cause;
+ cause = cause.getCause();
+ }
+ throw new IOException("connection failed: cycle?",x);
+ }
+ }
+ LOG.fine("connecting...");
+ // TODO remove these traces
+ // System.err.println(getInitParameter()+" connecting");
+ final Map env =
+ new HashMap(getEnvMap());
+ try {
+ // XXX: We should probably document this...
+ // This allows to specify a loader name - which will be
+ // retrieved from the paret MBeanServer.
+ defaultClassLoader =
+ EnvHelp.resolveServerClassLoader(env,getMBeanServer());
+ } catch (InstanceNotFoundException x) {
+ final IOException io =
+ new IOException("ClassLoader not found");
+ io.initCause(x);
+ throw io;
+ }
+ env.put(JMXConnectorFactory.DEFAULT_CLASS_LOADER,defaultClassLoader);
+ final JMXServiceURL url = getJMXServiceURL();
+ final JMXConnector aconn = connect(url,env);
+ final MBeanServerConnection msc;
+ try {
+ msc = aconn.getMBeanServerConnection();
+ aconn.addConnectionNotificationListener(listener,null,aconn);
+ } catch (IOException io) {
+ closeall(aconn);
+ throw io;
+ } catch (RuntimeException x) {
+ closeall(aconn);
+ throw x;
+ }
+
+
+ // XXX Revisit here
+ // Note from the author: This business of switching connection is
+ // incredibly complex. Isn't there any means to simplify it?
+ //
+ switchConnection(conn,aconn,msc);
+ try {
+ triggerProbe(msc);
+ } catch(Exception x) {
+ close();
+ Throwable cause = x;
+ // if the cause is a security exception - rethrows it...
+ while (cause != null) {
+ if (cause instanceof SecurityException)
+ throw (SecurityException) cause;
+ cause = cause.getCause();
+ }
+ throw new IOException("connection failed: cycle?",x);
+ }
+ LOG.fine("connected.");
+ }
+
+ // If this is a self-linking namespace, this method should trigger
+ // the emission of a probe in the wrapping NamespaceInterceptor.
+ // The first call to source() in the wrapping NamespaceInterceptor
+ // causes the emission of the probe.
+ //
+ // Note: the MBeanServer returned by getSourceServer
+ // (our private JMXRemoteNamespaceDelegate inner class)
+ // implements a sun private interface (DynamicProbe) which is
+ // used by the NamespaceInterceptor to determine whether it should
+ // send a probe or not.
+ // We needed this interface here because the NamespaceInterceptor
+ // has otherwise no means to knows that this object has just
+ // connected, and that a new probe should be sent.
+ //
+ // Probes work this way: the NamespaceInterceptor sets a flag and sends
+ // a queryNames() request. If a queryNames() request comes in when the flag
+ // is on, then it deduces that there is a self-linking loop - and instead
+ // of calling queryNames() on the JMXNamespace (which would cause the
+ // loop to go on) it breaks the recursion by returning the probe ObjectName.
+ // If the NamespaceInterceptor receives the probe ObjectName as result of
+ // its original queryNames() it knows that it has been looping back on
+ // itslef and throws an Exception - which will be raised through this
+ // method, thus preventing the connection to be established...
+ //
+ // More info in the com.sun.jmx.namespace.NamespaceInterceptor class
+ //
+ // XXX: TODO this probe thing is way too complex and fragile.
+ // This *must* go away or be replaced by something simpler.
+ // ideas are welcomed.
+ //
+ private void triggerProbe(final MBeanServerConnection msc)
+ throws MalformedObjectNameException, IOException {
+ // Query Pattern that we will send through the source server in order
+ // to detect self-linking namespaces.
+ //
+ //
+ final ObjectName pattern;
+ pattern = ObjectName.getInstance("*" +
+ JMXNamespaces.NAMESPACE_SEPARATOR + ":" +
+ JMXNamespace.TYPE_ASSIGNMENT);
+ probed = false;
+ try {
+ msc.queryNames(pattern, null);
+ probed = true;
+ } catch (AccessControlException x) {
+ // if we have an MBeanPermission missing then do nothing...
+ if (!(x.getPermission() instanceof MBeanPermission))
+ throw x;
+ PROBE_LOG.finer("Can't check for cycles: " + x);
+ probed = false; // no need to do it again...
+ }
+ }
+
+ public void close() throws IOException {
+ if (conn == null) return;
+ LOG.fine("closing...");
+ // System.err.println(toString()+": closing...");
+ conn.close();
+ // System.err.println(toString()+": connector closed");
+ switchConnection(conn,null,null);
+ LOG.fine("closed.");
+ // System.err.println(toString()+": closed");
+ }
+
+ MBeanServerConnection getMBeanServerConnection() {
+ if (conn == null)
+ throw newRuntimeIOException("getMBeanServerConnection: not connected");
+ return server;
+ }
+
+ // Better than throwing UndeclaredThrowableException ...
+ private RuntimeException newRuntimeIOException(String msg) {
+ final IllegalStateException illegal = new IllegalStateException(msg);
+ return Util.newRuntimeIOException(new IOException(msg,illegal));
+ }
+
+ /**
+ * Returns the default class loader used by the underlying
+ * {@link JMXConnector}.
+ * @return the default class loader used when communicating with the
+ * remote source MBean server.
+ **/
+ ClassLoader getDefaultClassLoader() {
+ if (conn == null)
+ throw newRuntimeIOException("getMBeanServerConnection: not connected");
+ return defaultClassLoader;
+ }
+
+ public boolean isConnected() {
+ // This is a pleonasm
+ return (conn != null) && (server != null);
+ }
+
+
+ /**
+ * This name space handler will automatically {@link #close} its
+ * connection with the remote source in {@code preDeregister}.
+ **/
+ @Override
+ public void preDeregister() throws Exception {
+ try {
+ close();
+ } catch (IOException x) {
+ LOG.fine("Failed to close properly - exception ignored: " + x);
+ LOG.log(Level.FINEST,
+ "Failed to close properly - exception ignored",x);
+ }
+ super.preDeregister();
+ }
+
+ /**
+ * This method calls {@link
+ * javax.management.MBeanServerConnection#getMBeanCount
+ * getMBeanCount()} on the remote namespace.
+ * @throws java.io.IOException if an {@link IOException} is raised when
+ * communicating with the remote source namespace.
+ */
+ @Override
+ public Integer getMBeanCount() throws IOException {
+ return getMBeanServerConnection().getMBeanCount();
+ }
+
+ /**
+ * This method returns the result of calling {@link
+ * javax.management.MBeanServerConnection#getDomains
+ * getDomains()} on the remote namespace.
+ * @throws java.io.IOException if an {@link IOException} is raised when
+ * communicating with the remote source namespace.
+ */
+ @Override
+ public String[] getDomains() throws IOException {
+ return getMBeanServerConnection().getDomains();
+ }
+
+ /**
+ * This method returns the result of calling {@link
+ * javax.management.MBeanServerConnection#getDefaultDomain
+ * getDefaultDomain()} on the remote namespace.
+ * @throws java.io.IOException if an {@link IOException} is raised when
+ * communicating with the remote source namespace.
+ */
+ @Override
+ public String getDefaultDomain() throws IOException {
+ return getMBeanServerConnection().getDefaultDomain();
+ }
+
+ /**
+ * Creates a new instance of {@code JMXRemoteNamespace}.
+ * @param sourceURL a JMX service URL that can be used to connect to the
+ * source MBean Server. The source MBean Server is the remote
+ * MBean Server which contains the MBeans that will be mirrored
+ * in this namespace.
+ * @param optionsMap An options map that will be passed to the
+ * {@link JMXConnectorFactory} when {@linkplain
+ * JMXConnectorFactory#newJMXConnector creating} the
+ * {@link JMXConnector} used to connect to the remote source
+ * MBean Server. Can be null, which is equivalent to an empty map.
+ * @see #JMXRemoteNamespace JMXRemoteNamespace(sourceURL,optionsMap)
+ * @see JMXConnectorFactory#newJMXConnector(javax.management.remote.JMXServiceURL, java.util.Map)
+ */
+ public static JMXRemoteNamespace newJMXRemoteNamespace(
+ JMXServiceURL sourceURL,
+ Map optionsMap) {
+ return new JMXRemoteNamespace(sourceURL, optionsMap);
+ }
+}
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/namespace/JMXRemoteNamespaceMBean.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/namespace/JMXRemoteNamespaceMBean.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,96 @@
+/*
+ * 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 javax.management.namespace;
+
+import java.io.IOException;
+import javax.management.remote.JMXServiceURL;
+
+/**
+ * A {@link JMXNamespaceMBean} that will connect to a remote MBeanServer
+ * by creating a {@link javax.management.remote.JMXConnector} from a
+ * {@link javax.management.remote.JMXServiceURL}.
+ * You can call {@link #connect connect()} and {@link #close close()}
+ * several times.
+ * @since 1.7
+ */
+public interface JMXRemoteNamespaceMBean
+ extends JMXNamespaceMBean {
+
+ /**
+ * Connects to the underlying remote source name space, if not already
+ * {@link #isConnected connected}.
+ * If connected, do nothing. Otherwise, creates a new connector from the
+ * {@link javax.management.remote.JMXServiceURL JMXServiceURL} provided at
+ * creation time, and connects to the remote source name space.
+ *
+ * The source MBeans will not appear in the target name space until the
+ * JMXRemoteNamespaceMBean is connected.
+ *
+ * It is possible to call {@code connect()}, {@link #close close()}, and
+ * {@code connect()} again.
+ * However, closing the connection with the remote name space may cause
+ * notification listeners to be lost, unless the client explicitly uses
+ * the new {@linkplain javax.management.event JMX event service}.
+ *
+ * @throws IOException if connection to the remote source name space fails.
+ * @see #isConnected isConnected
+ **/
+ public void connect()
+ throws IOException;
+
+ /**
+ * Closes the connection with the remote source name space.
+ * If the connection is already closed, do nothing.
+ * Otherwise, closes the underlying {@link
+ * javax.management.remote.JMXConnector}.
+ *
Once closed, it is possible to reopen the connection by
+ * calling {@link #connect connect}.
+ *
+ * @throws IOException if the connection to the remote source name space
+ * can't be closed properly.
+ * @see #isConnected isConnected
+ **/
+ public void close()
+ throws IOException;
+
+ /**
+ * Tells whether the connection to the remote source name space is opened.
+ * @see #connect connect
+ * @see #close close
+ * @return {@code true} if connected.
+ **/
+ public boolean isConnected();
+
+ /**
+ * Returns the {@link JMXServiceURL} address that points to the remote name
+ * space mirrored by this {@link JMXNamespaceMBean JMXNamespace MBean},
+ * if available.
+ * @return The {@link JMXServiceURL} address that points to the remote name
+ * space mirrored by this {@link JMXNamespaceMBean JMXNamespace MBean},
+ * or {@code null}.
+ */
+ public JMXServiceURL getAddress();
+}
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/namespace/MBeanServerConnectionWrapper.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/namespace/MBeanServerConnectionWrapper.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,703 @@
+/*
+ * 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 javax.management.namespace;
+
+import com.sun.jmx.mbeanserver.Util;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.security.AccessController;
+import java.util.Set;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.NotCompliantMBeanException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.QueryExp;
+import javax.management.ReflectionException;
+import javax.management.loading.ClassLoaderRepository;
+
+/**
+ * An object of this class implements the MBeanServer interface
+ * and, for each of its methods forwards the request to a wrapped
+ * {@link MBeanServerConnection} object.
+ * Some methods of the {@link MBeanServer} interface do not have
+ * any equivalent in {@link MBeanServerConnection}. In that case, an
+ * {@link UnsupportedOperationException} will be thrown.
+ *
+ *
A typical use of this class is to apply a {@link QueryExp} object locally,
+ * on an MBean that resides in a remote MBeanServer. Since an
+ * MBeanServerConnection is not an MBeanServer, it cannot be passed
+ * to the setMBeanServer()
method of the {@link QueryExp}
+ * object. However, this object can.
+ *
+ * @since 1.7
+ */
+public class MBeanServerConnectionWrapper
+ implements MBeanServer {
+
+ private final MBeanServerConnection wrapped;
+ private final ClassLoader defaultCl;
+
+ /**
+ * Construct a new object that implements {@link MBeanServer} by
+ * forwarding its methods to the given {@link MBeanServerConnection}.
+ * This constructor is equivalent to {@link #MBeanServerConnectionWrapper(
+ * MBeanServerConnection, ClassLoader) MBeanServerConnectionWrapper(wrapped,
+ * null)}.
+ *
+ * @param wrapped the {@link MBeanServerConnection} to which methods
+ * are to be forwarded. This parameter can be null, in which case the
+ * {@code MBeanServerConnection} will typically be supplied by overriding
+ * {@link #getMBeanServerConnection}.
+ */
+ public MBeanServerConnectionWrapper(MBeanServerConnection wrapped) {
+ this(wrapped, null);
+ }
+
+ /**
+ * Construct a new object that implements {@link MBeanServer} by
+ * forwarding its methods to the given {@link MBeanServerConnection}.
+ * The {@code defaultCl} parameter specifies the value to be returned
+ * by {@link #getDefaultClassLoader}. A null value is equivalent to
+ * {@link Thread#getContextClassLoader()}.
+ *
+ * @param wrapped the {@link MBeanServerConnection} to which methods
+ * are to be forwarded. This parameter can be null, in which case the
+ * {@code MBeanServerConnection} will typically be supplied by overriding
+ * {@link #getMBeanServerConnection}.
+ * @param defaultCl the value to be returned by {@link
+ * #getDefaultClassLoader}. A null value is equivalent to the current
+ * thread's {@linkplain Thread#getContextClassLoader()}.
+ */
+ public MBeanServerConnectionWrapper(MBeanServerConnection wrapped,
+ ClassLoader defaultCl) {
+ this.wrapped = wrapped;
+ this.defaultCl = (defaultCl == null) ?
+ Thread.currentThread().getContextClassLoader() : defaultCl;
+ }
+
+ /**
+ * Returns an MBeanServerConnection. This method is called each time
+ * an operation must be invoked on the underlying MBeanServerConnection.
+ * The default implementation returns the MBeanServerConnection that
+ * was supplied to the constructor of this MBeanServerConnectionWrapper.
+ **/
+ protected MBeanServerConnection getMBeanServerConnection() {
+ return wrapped;
+ }
+
+ /**
+ * Returns the default class loader passed to the constructor. If the
+ * value passed was null, then the returned value will be the
+ * {@linkplain Thread#getContextClassLoader() context class loader} at the
+ * time this object was constructed.
+ *
+ * @return the ClassLoader that was passed to the constructor.
+ **/
+ public ClassLoader getDefaultClassLoader() {
+ return defaultCl;
+ }
+
+ /**
+ * This method is called each time an IOException is raised when
+ * trying to forward an operation to the underlying
+ * MBeanServerConnection, as a result of calling
+ * {@link #getMBeanServerConnection()} or as a result of invoking the
+ * operation on the returned connection. Since the methods in
+ * {@link MBeanServer} are not declared to throw {@code IOException},
+ * this method must return a {@code RuntimeException} to be thrown
+ * instead. Typically, the original {@code IOException} will be in the
+ * {@linkplain Throwable#getCause() cause chain} of the {@code
+ * RuntimeException}.
+ *
+ * Subclasses may redefine this method if they need to perform any
+ * specific handling of IOException (logging etc...).
+ *
+ * @param x The raised IOException.
+ * @param method The name of the method in which the exception was
+ * raised. This is one of the methods of the MBeanServer
+ * interface.
+ *
+ * @return A RuntimeException that should be thrown by the caller.
+ * In this default implementation, this is a
+ * {@link RuntimeException} wrapping x.
+ **/
+ protected RuntimeException wrapIOException(IOException x, String method) {
+ return Util.newRuntimeIOException(x);
+ }
+
+ // Take care of getMBeanServerConnection returning null.
+ //
+ private synchronized MBeanServerConnection connection()
+ throws IOException {
+ final MBeanServerConnection c = getMBeanServerConnection();
+ if (c == null)
+ throw new IOException("MBeanServerConnection unavailable");
+ return c;
+ }
+
+ //--------------------------------------------
+ //--------------------------------------------
+ //
+ // Implementation of the MBeanServer interface
+ //
+ //--------------------------------------------
+ //--------------------------------------------
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public void addNotificationListener(ObjectName name,
+ NotificationListener listener,
+ NotificationFilter filter,
+ Object handback)
+ throws InstanceNotFoundException {
+ try {
+ connection().addNotificationListener(name, listener,
+ filter, handback);
+ } catch (IOException x) {
+ throw wrapIOException(x,"addNotificationListener");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public void addNotificationListener(ObjectName name,
+ ObjectName listener,
+ NotificationFilter filter,
+ Object handback)
+ throws InstanceNotFoundException {
+ try {
+ connection().addNotificationListener(name, listener,
+ filter, handback);
+ } catch (IOException x) {
+ throw wrapIOException(x,"addNotificationListener");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public ObjectInstance createMBean(String className, ObjectName name)
+ throws
+ ReflectionException,
+ InstanceAlreadyExistsException,
+ MBeanRegistrationException,
+ MBeanException,
+ NotCompliantMBeanException {
+ try {
+ return connection().createMBean(className, name);
+ } catch (IOException x) {
+ throw wrapIOException(x,"createMBean");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public ObjectInstance createMBean(String className, ObjectName name,
+ Object params[], String signature[])
+ throws
+ ReflectionException,
+ InstanceAlreadyExistsException,
+ MBeanRegistrationException,
+ MBeanException,
+ NotCompliantMBeanException {
+ try {
+ return connection().createMBean(className, name,
+ params, signature);
+ } catch (IOException x) {
+ throw wrapIOException(x,"createMBean");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public ObjectInstance createMBean(String className,
+ ObjectName name,
+ ObjectName loaderName)
+ throws
+ ReflectionException,
+ InstanceAlreadyExistsException,
+ MBeanRegistrationException,
+ MBeanException,
+ NotCompliantMBeanException,
+ InstanceNotFoundException {
+ try {
+ return connection().createMBean(className, name, loaderName);
+ } catch (IOException x) {
+ throw wrapIOException(x,"createMBean");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public ObjectInstance createMBean(String className,
+ ObjectName name,
+ ObjectName loaderName,
+ Object params[],
+ String signature[])
+ throws
+ ReflectionException,
+ InstanceAlreadyExistsException,
+ MBeanRegistrationException,
+ MBeanException,
+ NotCompliantMBeanException,
+ InstanceNotFoundException {
+ try {
+ return connection().createMBean(className, name, loaderName,
+ params, signature);
+ } catch (IOException x) {
+ throw wrapIOException(x,"createMBean");
+ }
+ }
+
+ /**
+ * Throws an {@link UnsupportedOperationException}. This behavior can
+ * be changed by subclasses.
+ * @deprecated see {@link MBeanServer#deserialize(ObjectName,byte[])
+ * MBeanServer}
+ */
+ @Deprecated
+ public ObjectInputStream deserialize(ObjectName name, byte[] data)
+ throws InstanceNotFoundException, OperationsException {
+ throw new UnsupportedOperationException("deserialize");
+ }
+
+ /**
+ * Throws an {@link UnsupportedOperationException}. This behavior can
+ * be changed by subclasses.
+ * @deprecated see {@link MBeanServer#deserialize(String,byte[])
+ * MBeanServer}
+ */
+ @Deprecated
+ public ObjectInputStream deserialize(String className, byte[] data)
+ throws OperationsException, ReflectionException {
+ throw new UnsupportedOperationException("deserialize");
+ }
+
+ /**
+ * Throws an {@link UnsupportedOperationException}. This behavior can
+ * be changed by subclasses.
+ * @deprecated see {@link MBeanServer#deserialize(String,ObjectName,byte[])
+ * MBeanServer}
+ */
+ @Deprecated
+ public ObjectInputStream deserialize(String className,
+ ObjectName loaderName,
+ byte[] data)
+ throws
+ InstanceNotFoundException,
+ OperationsException,
+ ReflectionException {
+ throw new UnsupportedOperationException("deserialize");
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public Object getAttribute(ObjectName name, String attribute)
+ throws
+ MBeanException,
+ AttributeNotFoundException,
+ InstanceNotFoundException,
+ ReflectionException {
+ try {
+ return connection().getAttribute(name, attribute);
+ } catch (IOException x) {
+ throw wrapIOException(x,"getAttribute");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public AttributeList getAttributes(ObjectName name, String[] attributes)
+ throws InstanceNotFoundException, ReflectionException {
+ try {
+ return connection().getAttributes(name, attributes);
+ } catch (IOException x) {
+ throw wrapIOException(x,"getAttributes");
+ }
+ }
+
+ /**
+ * Throws an {@link UnsupportedOperationException}. This behavior can
+ * be changed by subclasses.
+ */
+ public ClassLoader getClassLoader(ObjectName loaderName)
+ throws InstanceNotFoundException {
+ throw new UnsupportedOperationException("getClassLoader");
+ }
+
+ /**
+ * Returns the {@linkplain #getDefaultClassLoader() default class loader}.
+ * This behavior can be changed by subclasses.
+ */
+ public ClassLoader getClassLoaderFor(ObjectName mbeanName)
+ throws InstanceNotFoundException {
+ return getDefaultClassLoader();
+ }
+
+ /**
+ * Returns a {@link ClassLoaderRepository} based on the class loader
+ * returned by {@link #getDefaultClassLoader()}.
+ * @return a {@link ClassLoaderRepository} that contains a single
+ * class loader, returned by {@link #getDefaultClassLoader()}.
+ **/
+ public ClassLoaderRepository getClassLoaderRepository() {
+ // We return a new ClassLoaderRepository each time this method is
+ // called. This is by design, because there's no guarantee that
+ // getDefaultClassLoader() will always return the same class loader.
+ return Util.getSingleClassLoaderRepository(getDefaultClassLoader());
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public String getDefaultDomain() {
+ try {
+ return connection().getDefaultDomain();
+ } catch (IOException x) {
+ throw wrapIOException(x,"getDefaultDomain");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public String[] getDomains() {
+ try {
+ return connection().getDomains();
+ } catch (IOException x) {
+ throw wrapIOException(x,"getDomains");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public Integer getMBeanCount() {
+ try {
+ return connection().getMBeanCount();
+ } catch (IOException x) {
+ throw wrapIOException(x,"getMBeanCount");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public MBeanInfo getMBeanInfo(ObjectName name)
+ throws
+ InstanceNotFoundException,
+ IntrospectionException,
+ ReflectionException {
+ try {
+ return connection().getMBeanInfo(name);
+ } catch (IOException x) {
+ throw wrapIOException(x,"getMBeanInfo");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public ObjectInstance getObjectInstance(ObjectName name)
+ throws InstanceNotFoundException {
+ try {
+ return connection().getObjectInstance(name);
+ } catch (IOException x) {
+ throw wrapIOException(x,"getObjectInstance");
+ }
+ }
+
+ /**
+ * Throws an {@link UnsupportedOperationException}. This behavior can
+ * be changed by subclasses.
+ */
+ public Object instantiate(String className)
+ throws ReflectionException, MBeanException {
+ throw new UnsupportedOperationException("instantiate");
+ }
+
+ /**
+ * Throws an {@link UnsupportedOperationException}. This behavior can
+ * be changed by subclasses.
+ */
+ public Object instantiate(String className,
+ Object params[],
+ String signature[])
+ throws ReflectionException, MBeanException {
+ throw new UnsupportedOperationException("instantiate");
+ }
+
+ /**
+ * Throws an {@link UnsupportedOperationException}. This behavior can
+ * be changed by subclasses.
+ */
+ public Object instantiate(String className, ObjectName loaderName)
+ throws ReflectionException, MBeanException,
+ InstanceNotFoundException {
+ throw new UnsupportedOperationException("instantiate");
+ }
+
+ /**
+ * Throws an {@link UnsupportedOperationException}. This behavior can
+ * be changed by subclasses.
+ */
+ public Object instantiate(String className, ObjectName loaderName,
+ Object params[], String signature[])
+ throws ReflectionException, MBeanException,
+ InstanceNotFoundException {
+ throw new UnsupportedOperationException("instantiate");
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public Object invoke(ObjectName name, String operationName,
+ Object params[], String signature[])
+ throws
+ InstanceNotFoundException,
+ MBeanException,
+ ReflectionException {
+ try {
+ return connection().invoke(name,operationName,params,signature);
+ } catch (IOException x) {
+ throw wrapIOException(x,"invoke");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public boolean isInstanceOf(ObjectName name, String className)
+ throws InstanceNotFoundException {
+ try {
+ return connection().isInstanceOf(name, className);
+ } catch (IOException x) {
+ throw wrapIOException(x,"isInstanceOf");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public boolean isRegistered(ObjectName name) {
+ try {
+ return connection().isRegistered(name);
+ } catch (IOException x) {
+ throw wrapIOException(x,"isRegistered");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ * If an IOException is raised, returns an empty Set.
+ */
+ public Set queryMBeans(ObjectName name, QueryExp query) {
+ try {
+ return connection().queryMBeans(name, query);
+ } catch (IOException x) {
+ throw wrapIOException(x,"queryMBeans");
+ //return Collections.emptySet();
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ * If an IOException is raised, returns an empty Set.
+ */
+ public Set queryNames(ObjectName name, QueryExp query) {
+ try {
+ return connection().queryNames(name, query);
+ } catch (IOException x) {
+ throw wrapIOException(x,"queryNames");
+ //return Collections.emptySet();
+ }
+ }
+
+ /**
+ * Throws an {@link UnsupportedOperationException}. This behavior can
+ * be changed by subclasses.
+ */
+ public ObjectInstance registerMBean(Object object, ObjectName name)
+ throws
+ InstanceAlreadyExistsException,
+ MBeanRegistrationException,
+ NotCompliantMBeanException {
+ throw new UnsupportedOperationException("registerMBean");
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public void removeNotificationListener(ObjectName name,
+ NotificationListener listener)
+ throws InstanceNotFoundException, ListenerNotFoundException {
+ try {
+ connection().removeNotificationListener(name, listener);
+ } catch (IOException x) {
+ throw wrapIOException(x,"removeNotificationListener");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public void removeNotificationListener(ObjectName name,
+ NotificationListener listener,
+ NotificationFilter filter,
+ Object handback)
+ throws InstanceNotFoundException, ListenerNotFoundException {
+ try {
+ connection().removeNotificationListener(name, listener,
+ filter, handback);
+ } catch (IOException x) {
+ throw wrapIOException(x,"removeNotificationListener");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public void removeNotificationListener(ObjectName name,
+ ObjectName listener)
+ throws InstanceNotFoundException, ListenerNotFoundException {
+ try {
+ connection().removeNotificationListener(name, listener);
+ } catch (IOException x) {
+ throw wrapIOException(x,"removeNotificationListener");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public void removeNotificationListener(ObjectName name,
+ ObjectName listener,
+ NotificationFilter filter,
+ Object handback)
+ throws InstanceNotFoundException, ListenerNotFoundException {
+ try {
+ connection().removeNotificationListener(name, listener,
+ filter, handback);
+ } catch (IOException x) {
+ throw wrapIOException(x,"removeNotificationListener");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public void setAttribute(ObjectName name, Attribute attribute)
+ throws
+ InstanceNotFoundException,
+ AttributeNotFoundException,
+ InvalidAttributeValueException,
+ MBeanException,
+ ReflectionException {
+ try {
+ connection().setAttribute(name, attribute);
+ } catch (IOException x) {
+ throw wrapIOException(x,"setAttribute");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public AttributeList setAttributes(ObjectName name,
+ AttributeList attributes)
+ throws InstanceNotFoundException, ReflectionException {
+ try {
+ return connection().setAttributes(name, attributes);
+ } catch (IOException x) {
+ throw wrapIOException(x,"setAttributes");
+ }
+ }
+
+ /**
+ * Forward this method to the
+ * wrapped object.
+ */
+ public void unregisterMBean(ObjectName name)
+ throws InstanceNotFoundException, MBeanRegistrationException {
+ try {
+ connection().unregisterMBean(name);
+ } catch (IOException x) {
+ throw wrapIOException(x,"unregisterMBean");
+ }
+ }
+
+ //----------------
+ // PRIVATE METHODS
+ //----------------
+
+}
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/namespace/MBeanServerSupport.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/namespace/MBeanServerSupport.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,1339 @@
+/*
+ * 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 javax.management.namespace;
+
+import com.sun.jmx.defaults.JmxProperties;
+import com.sun.jmx.mbeanserver.Util;
+import java.io.ObjectInputStream;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.DynamicMBean;
+import javax.management.DynamicWrapperMBean;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.JMRuntimeException;
+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.NotificationBroadcaster;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.QueryEval;
+import javax.management.QueryExp;
+import javax.management.ReflectionException;
+import javax.management.RuntimeOperationsException;
+import javax.management.loading.ClassLoaderRepository;
+
+/**
+ * Base class for custom implementations of the {@link MBeanServer}
+ * interface. The commonest use of this class is as the {@linkplain
+ * JMXNamespace#getSourceServer() source server} for a {@link
+ * JMXNamespace}, although this class can be used anywhere an {@code
+ * MBeanServer} instance is required. Note that the usual ways to
+ * obtain an {@code MBeanServer} instance are either to use {@link
+ * java.lang.management.ManagementFactory#getPlatformMBeanServer()
+ * ManagementFactory.getPlatformMBeanServer()} or to use the {@code
+ * newMBeanServer} or {@code createMBeanServer} methods from {@link
+ * javax.management.MBeanServerFactory MBeanServerFactory}. {@code
+ * MBeanServerSupport} is for certain cases where those are not
+ * appropriate.
+ *
+ * There are two main use cases for this class: special-purpose MBeanServer implementations,
+ * and namespaces containing Virtual MBeans. The next
+ * sections explain these use cases.
+ *
+ * In the simplest case, a subclass needs to implement only two methods:
+ *
+ *
+ * -
+ * {@link #getNames getNames} which returns the name of
+ * all MBeans handled by this {@code MBeanServer}.
+ *
+ * -
+ * {@link #getDynamicMBeanFor getDynamicMBeanFor} which returns a
+ * {@link DynamicMBean} that can be used to invoke operations and
+ * obtain meta data (MBeanInfo) on a given MBean.
+ *
+ *
+ *
+ * Subclasses can create such {@link DynamicMBean} MBeans on the fly - for
+ * instance, using the class {@link javax.management.StandardMBean}, just for
+ * the duration of an MBeanServer method call.
+ *
+ * Special-purpose MBeanServer implementations
+ *
+ * In some cases
+ * the general-purpose {@code MBeanServer} that you get from
+ * {@link javax.management.MBeanServerFactory MBeanServerFactory} is not
+ * appropriate. You might need different security checks, or you might
+ * want a mock {@code MBeanServer} suitable for use in tests, or you might
+ * want a simplified and optimized {@code MBeanServer} for a special purpose.
+ *
+ * As an example of a special-purpose {@code MBeanServer}, the class {@link
+ * javax.management.QueryNotificationFilter QueryNotificationFilter} constructs
+ * an {@code MBeanServer} instance every time it filters a notification,
+ * with just one MBean that represents the notification. Although it could
+ * use {@code MBeanServerFactory.newMBeanServer}, a special-purpose {@code
+ * MBeanServer} will be quicker to create, use less memory, and have simpler
+ * methods that execute faster.
+ *
+ * Here is an example of a special-purpose {@code MBeanServer}
+ * implementation that contains exactly one MBean, which is specified at the
+ * time of creation.
+ *
+ *
+ * public class SingletonMBeanServer extends MBeanServerSupport {
+ * private final ObjectName objectName;
+ * private final DynamicMBean mbean;
+ *
+ * public SingletonMBeanServer(ObjectName objectName, DynamicMBean mbean) {
+ * this.objectName = objectName;
+ * this.mbean = mbean;
+ * }
+ *
+ * @Override
+ * protected {@code Set} {@link #getNames getNames}() {
+ * return Collections.singleton(objectName);
+ * }
+ *
+ * @Override
+ * public DynamicMBean {@link #getDynamicMBeanFor
+ * getDynamicMBeanFor}(ObjectName name)
+ * throws InstanceNotFoundException {
+ * if (objectName.equals(name))
+ * return mbean;
+ * else
+ * throw new InstanceNotFoundException(name);
+ * }
+ * }
+ *
+ *
+ * Using this class, you could make an {@code MBeanServer} that contains
+ * a {@link javax.management.timer.Timer Timer} MBean like this:
+ *
+ *
+ * Timer timer = new Timer();
+ * DynamicMBean mbean = new {@link javax.management.StandardMBean
+ * StandardMBean}(timer, TimerMBean.class);
+ * ObjectName name = new ObjectName("com.example:type=Timer");
+ * MBeanServer timerMBS = new SingletonMBeanServer(name, mbean);
+ *
+ *
+ * When {@code getDynamicMBeanFor} always returns the same object for the
+ * same name, as here, notifications work in the expected way: if the object
+ * is a {@link NotificationEmitter} then listeners can be added using
+ * {@link MBeanServer#addNotificationListener(ObjectName, NotificationListener,
+ * NotificationFilter, Object) MBeanServer.addNotificationListener}. If
+ * {@code getDynamicMBeanFor} does not always return the same object for the
+ * same name, more work is needed to make notifications work, as described
+ * below.
+ *
+ * Namespaces containing Virtual MBeans
+ *
+ * Virtual MBeans are MBeans that do not exist as Java objects,
+ * except transiently while they are being accessed. This is useful when
+ * there might be very many of them, or when keeping track of their creation
+ * and deletion might be expensive or hard. For example, you might have one
+ * MBean per system process. With an ordinary {@code MBeanServer}, you would
+ * have to list the system processes in order to create an MBean object for
+ * each one, and you would have to track the arrival and departure of system
+ * processes in order to create or delete the corresponding MBeans. With
+ * Virtual MBeans, you only need the MBean for a given process at the exact
+ * point where it is referenced with a call such as
+ * {@link MBeanServer#getAttribute MBeanServer.getAttribute}.
+ *
+ * Here is an example of an {@code MBeanServer} implementation that has
+ * one MBean for every system property. The system property {@code "java.home"}
+ * is represented by the MBean called {@code
+ * com.example:type=Property,name="java.home"}, with an attribute called
+ * {@code Value} that is the value of the property.
+ *
+ *
+ * public interface PropertyMBean {
+ * public String getValue();
+ * }
+ *
+ * public class PropsMBS extends MBeanServerSupport {
+ * private static ObjectName newObjectName(String name) {
+ * try {
+ * return new ObjectName(name);
+ * } catch (MalformedObjectNameException e) {
+ * throw new AssertionError(e);
+ * }
+ * }
+ *
+ * public static class PropertyImpl implements PropertyMBean {
+ * private final String name;
+ *
+ * public PropertyImpl(String name) {
+ * this.name = name;
+ * }
+ *
+ * public String getValue() {
+ * return System.getProperty(name);
+ * }
+ * }
+ *
+ * @Override
+ * public DynamicMBean {@link #getDynamicMBeanFor
+ * getDynamicMBeanFor}(ObjectName name)
+ * throws InstanceNotFoundException {
+ *
+ * // Check that the name is a legal one for a Property MBean
+ * ObjectName namePattern = newObjectName(
+ * "com.example:type=Property,name=\"*\"");
+ * if (!namePattern.apply(name))
+ * throw new InstanceNotFoundException(name);
+ *
+ * // Extract the name of the property that the MBean corresponds to
+ * String propName = ObjectName.unquote(name.getKeyProperty("name"));
+ * if (System.getProperty(propName) == null)
+ * throw new InstanceNotFoundException(name);
+ *
+ * // Construct and return a transient MBean object
+ * PropertyMBean propMBean = new PropertyImpl(propName);
+ * return new StandardMBean(propMBean, PropertyMBean.class, false);
+ * }
+ *
+ * @Override
+ * protected {@code Set} {@link #getNames getNames}() {
+ * {@code Set names = new TreeSet();}
+ * Properties props = System.getProperties();
+ * for (String propName : props.stringPropertyNames()) {
+ * ObjectName objectName = newObjectName(
+ * "com.example:type=Property,name=" +
+ * ObjectName.quote(propName));
+ * names.add(objectName);
+ * }
+ * return names;
+ * }
+ * }
+ *
+ *
+ * Because the {@code getDynamicMBeanFor} method
+ * returns a different object every time it is called, the default handling
+ * of notifications will not work, as explained below.
+ * In this case it does not matter, because the object returned by {@code
+ * getDynamicMBeanFor} is not a {@code NotificationEmitter}, so {@link
+ * MBeanServer#addNotificationListener(ObjectName, NotificationListener,
+ * NotificationFilter, Object) MBeanServer.addNotificationListener} will
+ * always fail. But if we wanted to extend {@code PropsMBS} so that the MBean
+ * for property {@code "foo"} emitted a notification every time that property
+ * changed, we would need to do it as shown below. (Because there is no API to
+ * be informed when a property changes, this code assumes that some other code
+ * calls the {@code propertyChanged} method every time a property changes.)
+ *
+ *
+ * public class PropsMBS {
+ * ...as above...
+ *
+ * private final {@link VirtualEventManager} vem = new VirtualEventManager();
+ *
+ * @Override
+ * public NotificationEmitter {@link #getNotificationEmitterFor
+ * getNotificationEmitterFor}(
+ * ObjectName name) throws InstanceNotFoundException {
+ * getDynamicMBeanFor(name); // check that the name is valid
+ * return vem.{@link VirtualEventManager#getNotificationEmitterFor
+ * getNotificationEmitterFor}(name);
+ * }
+ *
+ * public void propertyChanged(String name, String newValue) {
+ * ObjectName objectName = newObjectName(
+ * "com.example:type=Property,name=" + ObjectName.quote(name));
+ * Notification n = new Notification(
+ * "com.example.property.changed", objectName, 0L,
+ * "Property " + name + " changed");
+ * n.setUserData(newValue);
+ * vem.{@link VirtualEventManager#publish publish}(objectName, n);
+ * }
+ * }
+ *
+ *
+ * MBean creation and deletion
+ *
+ * MBean creation through {@code MBeanServer.createMBean} is disabled
+ * by default. Subclasses which need to support MBean creation
+ * through {@code createMBean} need to implement a single method {@link
+ * #createMBean(String, ObjectName, ObjectName, Object[], String[],
+ * boolean)}.
+ *
+ * Similarly MBean registration and unregistration through {@code
+ * registerMBean} and {@code unregisterMBean} are disabled by default.
+ * Subclasses which need to support MBean registration and
+ * unregistration will need to implement {@link #registerMBean registerMBean}
+ * and {@link #unregisterMBean unregisterMBean}.
+ *
+ * Notifications
+ *
+ * By default {@link MBeanServer#addNotificationListener(ObjectName,
+ * NotificationListener, NotificationFilter, Object) addNotificationListener}
+ * is accepted for an MBean {@code name} if {@link #getDynamicMBeanFor
+ * getDynamicMBeanFor}(name)
returns an object that is a
+ * {@link NotificationEmitter}. That is appropriate if
+ * {@code getDynamicMBeanFor}(name)
always returns the
+ * same object for the same {@code name}. But with
+ * Virtual MBeans, every call to {@code getDynamicMBeanFor} returns a new object,
+ * which is discarded as soon as the MBean request has finished.
+ * So a listener added to that object would be immediately forgotten.
+ *
+ * The simplest way for a subclass that defines Virtual MBeans
+ * to support notifications is to create a private {@link VirtualEventManager}
+ * and override the method {@link
+ * #getNotificationEmitterFor getNotificationEmitterFor} as follows:
+ *
+ *
+ * private final VirtualEventManager vem = new VirtualEventManager();
+ *
+ * @Override
+ * public NotificationEmitter getNotificationEmitterFor(
+ * ObjectName name) throws InstanceNotFoundException {
+ * // Check that the name is a valid Virtual MBean.
+ * // This is the easiest way to do that, but not always the
+ * // most efficient:
+ * getDynamicMBeanFor(name);
+ *
+ * // Return an object that supports add/removeNotificationListener
+ * // through the VirtualEventManager.
+ * return vem.getNotificationEmitterFor(name);
+ * }
+ *
+ *
+ * A notification {@code n} can then be sent from the Virtual MBean
+ * called {@code name} by calling {@link VirtualEventManager#publish
+ * vem.publish}(name, n)
. See the example
+ * above.
+ *
+ * @since 1.7
+ */
+public abstract class MBeanServerSupport implements MBeanServer {
+
+ /**
+ * A logger for this class.
+ */
+ private static final Logger LOG =
+ JmxProperties.NAMESPACE_LOGGER;
+
+ /**
+ * Make a new {@code MBeanServerSupport} instance.
+ */
+ protected MBeanServerSupport() {
+ }
+
+ /**
+ * Returns a dynamically created handle that makes it possible to
+ * access the named MBean for the duration of a method call.
+ *
+ * An easy way to create such a {@link DynamicMBean} handle is, for
+ * instance, to create a temporary MXBean instance and to wrap it in
+ * an instance of
+ * {@link javax.management.StandardMBean}.
+ * This handle should remain valid for the duration of the call
+ * but can then be discarded.
+ * @param name the name of the MBean for which a request was received.
+ * @return a {@link DynamicMBean} handle that can be used to invoke
+ * operations on the named MBean.
+ * @throws InstanceNotFoundException if no such MBean is supposed
+ * to exist.
+ */
+ public abstract DynamicMBean getDynamicMBeanFor(ObjectName name)
+ throws InstanceNotFoundException;
+
+ /**
+ * Subclasses should implement this method to return
+ * the names of all MBeans handled by this object instance.
+ *
+ * The object returned by getNames() should be safely {@linkplain
+ * Set#iterator iterable} even in the presence of other threads that may
+ * cause the set of names to change. Typically this means one of the
+ * following:
+ *
+ *
+ * - the returned set of names is always the same; or
+ *
- the returned set of names is an object such as a {@link
+ * java.util.concurrent.CopyOnWriteArraySet CopyOnWriteArraySet} that is
+ * safely iterable even if the set is changed by other threads; or
+ *
- a new Set is constructed every time this method is called.
+ *
+ *
+ * @return the names of all MBeans handled by this object.
+ */
+ protected abstract Set getNames();
+
+ /**
+ * List names matching the given pattern.
+ * The default implementation of this method calls {@link #getNames()}
+ * and returns the subset of those names matching {@code pattern}.
+ *
+ * @param pattern an ObjectName pattern
+ * @return the list of MBean names that match the given pattern.
+ */
+ protected Set getMatchingNames(ObjectName pattern) {
+ return Util.filterMatchingNames(pattern, getNames());
+ }
+
+ /**
+ * Returns a {@link NotificationEmitter} which can be used to
+ * subscribe or unsubscribe for notifications with the named
+ * mbean.
+ *
+ * The default implementation of this method calls {@link
+ * #getDynamicMBeanFor getDynamicMBeanFor(name)} and returns that object
+ * if it is a {@code NotificationEmitter}, otherwise null. See above for further discussion of notification
+ * handling.
+ *
+ * @param name The name of the MBean whose notifications are being
+ * subscribed, or unsuscribed.
+ *
+ * @return A {@link NotificationEmitter} that can be used to subscribe or
+ * unsubscribe for notifications emitted by the named MBean, or {@code
+ * null} if the MBean does not emit notifications and should not be
+ * considered as a {@code NotificationEmitter}.
+ *
+ * @throws InstanceNotFoundException if {@code name} is not the name of
+ * an MBean in this {@code MBeanServer}.
+ */
+ public NotificationEmitter getNotificationEmitterFor(ObjectName name)
+ throws InstanceNotFoundException {
+ DynamicMBean mbean = getDynamicMBeanFor(name);
+ if (mbean instanceof NotificationEmitter)
+ return (NotificationEmitter) mbean;
+ else
+ return null;
+ }
+
+ private NotificationEmitter getNonNullNotificationEmitterFor(
+ ObjectName name)
+ throws InstanceNotFoundException {
+ NotificationEmitter emitter = getNotificationEmitterFor(name);
+ if (emitter == null) {
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "Not a NotificationEmitter: " + name);
+ throw new RuntimeOperationsException(iae);
+ }
+ return emitter;
+ }
+
+ /**
+ * Creates a new MBean in the MBean name space.
+ * This operation is not supported in this base class implementation.
+ * The default implementation of this method always throws an {@link
+ * UnsupportedOperationException}
+ * wrapped in a {@link RuntimeOperationsException}.
+ *
+ * Subclasses may redefine this method to provide an implementation.
+ * All the various flavors of {@code MBeanServer.createMBean} methods
+ * will eventually call this method. A subclass that wishes to
+ * support MBean creation through {@code createMBean} thus only
+ * needs to provide an implementation for this one method.
+ *
+ * @param className The class name of the MBean to be instantiated.
+ * @param name The object name of the MBean. May be null.
+ * @param params An array containing the parameters of the
+ * constructor to be invoked.
+ * @param signature An array containing the signature of the
+ * constructor to be invoked.
+ * @param loaderName The object name of the class loader to be used.
+ * @param useCLR This parameter is {@code true} when this method
+ * is called from one of the {@code MBeanServer.createMBean} methods
+ * whose signature does not include the {@code ObjectName} of an
+ * MBean class loader to use for loading the MBean class.
+ *
+ * @return An ObjectInstance
, containing the
+ * ObjectName
and the Java class name of the newly
+ * instantiated MBean. If the contained ObjectName
+ * is n
, the contained Java class name is
+ * {@link javax.management.MBeanServer#getMBeanInfo
+ * getMBeanInfo(n)}.getClassName()
.
+ *
+ * @exception ReflectionException Wraps a
+ * java.lang.ClassNotFoundException
or a
+ * java.lang.Exception
that occurred when trying to
+ * invoke the MBean's constructor.
+ * @exception InstanceAlreadyExistsException The MBean is already
+ * under the control of the MBean server.
+ * @exception MBeanRegistrationException The
+ * preRegister
(MBeanRegistration
+ * interface) method of the MBean has thrown an exception. The
+ * MBean will not be registered.
+ * @exception MBeanException The constructor of the MBean has
+ * thrown an exception
+ * @exception NotCompliantMBeanException This class is not a JMX
+ * compliant MBean
+ * @exception InstanceNotFoundException The specified class loader
+ * is not registered in the MBean server.
+ * @exception RuntimeOperationsException Wraps either:
+ *
+ * - a
java.lang.IllegalArgumentException
: The className
+ * passed in parameter is null, the ObjectName
passed in
+ * parameter contains a pattern or no ObjectName
is specified
+ * for the MBean; or
+ * - an {@code UnsupportedOperationException} if creating MBeans is not
+ * supported by this {@code MBeanServer} implementation.
+ *
+ */
+ public ObjectInstance createMBean(String className,
+ ObjectName name, ObjectName loaderName, Object[] params,
+ String[] signature, boolean useCLR)
+ throws ReflectionException, InstanceAlreadyExistsException,
+ MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException, InstanceNotFoundException {
+ throw newUnsupportedException("createMBean");
+ }
+
+
+ /**
+ * Attempts to determine whether the named MBean should be
+ * considered as an instance of a given class. The default implementation
+ * of this method calls {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}
+ * to get an MBean object. Then its behaviour is the same as the standard
+ * {@link MBeanServer#isInstanceOf MBeanServer.isInstanceOf} method.
+ *
+ * {@inheritDoc}
+ */
+ public boolean isInstanceOf(ObjectName name, String className)
+ throws InstanceNotFoundException {
+
+ final DynamicMBean instance = nonNullMBeanFor(name);
+
+ try {
+ final String mbeanClassName = instance.getMBeanInfo().getClassName();
+
+ if (mbeanClassName.equals(className))
+ return true;
+
+ final Object resource;
+ final ClassLoader cl;
+ if (instance instanceof DynamicWrapperMBean) {
+ DynamicWrapperMBean d = (DynamicWrapperMBean) instance;
+ resource = d.getWrappedObject();
+ cl = d.getWrappedClassLoader();
+ } else {
+ resource = instance;
+ cl = instance.getClass().getClassLoader();
+ }
+
+ final Class> classNameClass = Class.forName(className, false, cl);
+
+ if (classNameClass.isInstance(resource))
+ return true;
+
+ if (classNameClass == NotificationBroadcaster.class ||
+ classNameClass == NotificationEmitter.class) {
+ try {
+ getNotificationEmitterFor(name);
+ return true;
+ } catch (Exception x) {
+ LOG.finest("MBean " + name +
+ " is not a notification emitter. Ignoring: "+x);
+ return false;
+ }
+ }
+
+ final Class> resourceClass = Class.forName(mbeanClassName, false, cl);
+ return classNameClass.isAssignableFrom(resourceClass);
+ } catch (Exception x) {
+ /* Could be SecurityException or ClassNotFoundException */
+ LOG.logp(Level.FINEST,
+ MBeanServerSupport.class.getName(),
+ "isInstanceOf", "Exception calling isInstanceOf", x);
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation of this method returns the string
+ * "DefaultDomain".
+ */
+ public String getDefaultDomain() {
+ return "DefaultDomain";
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation of this method returns
+ * {@link #getNames()}.size().
+ */
+ public Integer getMBeanCount() {
+ return getNames().size();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation of this method first calls {@link #getNames
+ * getNames()} to get a list of all MBean names,
+ * and from this set of names, derives the set of domains which contain
+ * MBeans.
+ */
+ public String[] getDomains() {
+ final Set names = getNames();
+ final Set res = new TreeSet();
+ for (ObjectName n : names) {
+ if (n == null) continue; // not allowed but you never know.
+ res.add(n.getDomain());
+ }
+ return res.toArray(new String[res.size()]);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation of this method will first
+ * call {@link
+ * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle
+ * to the named MBean,
+ * and then call {@link DynamicMBean#getAttribute getAttribute}
+ * on that {@link DynamicMBean} handle.
+ *
+ * @throws RuntimeOperationsException {@inheritDoc}
+ */
+ public Object getAttribute(ObjectName name, String attribute)
+ throws MBeanException, AttributeNotFoundException,
+ InstanceNotFoundException, ReflectionException {
+ final DynamicMBean mbean = nonNullMBeanFor(name);
+ return mbean.getAttribute(attribute);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation of this method will first
+ * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}
+ * to obtain a handle to the named MBean,
+ * and then call {@link DynamicMBean#setAttribute setAttribute}
+ * on that {@link DynamicMBean} handle.
+ *
+ * @throws RuntimeOperationsException {@inheritDoc}
+ */
+ public void setAttribute(ObjectName name, Attribute attribute)
+ throws InstanceNotFoundException, AttributeNotFoundException,
+ InvalidAttributeValueException, MBeanException,
+ ReflectionException {
+ final DynamicMBean mbean = nonNullMBeanFor(name);
+ mbean.setAttribute(attribute);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation of this method will first
+ * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
+ * handle to the named MBean,
+ * and then call {@link DynamicMBean#getAttributes getAttributes}
+ * on that {@link DynamicMBean} handle.
+ *
+ * @throws RuntimeOperationsException {@inheritDoc}
+ */
+ public AttributeList getAttributes(ObjectName name,
+ String[] attributes) throws InstanceNotFoundException,
+ ReflectionException {
+ final DynamicMBean mbean = nonNullMBeanFor(name);
+ return mbean.getAttributes(attributes);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation of this method will first
+ * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
+ * handle to the named MBean,
+ * and then call {@link DynamicMBean#setAttributes setAttributes}
+ * on that {@link DynamicMBean} handle.
+ *
+ * @throws RuntimeOperationsException {@inheritDoc}
+ */
+ public AttributeList setAttributes(ObjectName name, AttributeList attributes)
+ throws InstanceNotFoundException, ReflectionException {
+ final DynamicMBean mbean = nonNullMBeanFor(name);
+ return mbean.setAttributes(attributes);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation of this method will first
+ * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
+ * handle to the named MBean,
+ * and then call {@link DynamicMBean#invoke invoke}
+ * on that {@link DynamicMBean} handle.
+ */
+ public Object invoke(ObjectName name, String operationName,
+ Object[] params, String[] signature)
+ throws InstanceNotFoundException, MBeanException,
+ ReflectionException {
+ final DynamicMBean mbean = nonNullMBeanFor(name);
+ return mbean.invoke(operationName, params, signature);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation of this method will first
+ * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
+ * handle to the named MBean,
+ * and then call {@link DynamicMBean#getMBeanInfo getMBeanInfo}
+ * on that {@link DynamicMBean} handle.
+ */
+ public MBeanInfo getMBeanInfo(ObjectName name)
+ throws InstanceNotFoundException, IntrospectionException,
+ ReflectionException {
+ final DynamicMBean mbean = nonNullMBeanFor(name);
+ return mbean.getMBeanInfo();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation of this method will call
+ * {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}.{@link DynamicMBean#getMBeanInfo getMBeanInfo()}.{@link MBeanInfo#getClassName getClassName()} to get the
+ * class name to combine with {@code name} to produce a new
+ * {@code ObjectInstance}.
+ */
+ public ObjectInstance getObjectInstance(ObjectName name)
+ throws InstanceNotFoundException {
+ final DynamicMBean mbean = nonNullMBeanFor(name);
+ final String className = mbean.getMBeanInfo().getClassName();
+ return new ObjectInstance(name, className);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation of this method will first call {@link
+ * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle to the
+ * named MBean. If {@code getDynamicMBeanFor} returns an object, {@code
+ * isRegistered} will return true. If {@code getDynamicMBeanFor} returns
+ * null or throws {@link InstanceNotFoundException}, {@code isRegistered}
+ * will return false.
+ *
+ * @throws RuntimeOperationsException {@inheritDoc}
+ */
+ public boolean isRegistered(ObjectName name) {
+ try {
+ final DynamicMBean mbean = getDynamicMBeanFor(name);
+ return mbean!=null;
+ } catch (InstanceNotFoundException x) {
+ if (LOG.isLoggable(Level.FINEST))
+ LOG.finest("MBean "+name+" is not registered: "+x);
+ return false;
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation of this method will first
+ * call {@link #queryNames queryNames}
+ * to get a list of all matching MBeans, and then, for each returned name,
+ * call {@link #getObjectInstance getObjectInstance(name)}.
+ */
+ public Set queryMBeans(ObjectName pattern, QueryExp query) {
+ final Set names = queryNames(pattern, query);
+ if (names.isEmpty()) return Collections.emptySet();
+ final Set mbeans = new HashSet();
+ for (ObjectName name : names) {
+ try {
+ mbeans.add(getObjectInstance(name));
+ } catch (SecurityException x) { // DLS: OK
+ continue;
+ } catch (InstanceNotFoundException x) { // DLS: OK
+ continue;
+ }
+ }
+ return mbeans;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation of this method calls {@link #getMatchingNames
+ * getMatchingNames(pattern)} to obtain a list of MBeans matching
+ * the given name pattern. If the {@code query} parameter is null,
+ * this will be the result. Otherwise, it will evaluate the
+ * {@code query} parameter for each of the returned names, exactly
+ * as an {@code MBeanServer} would. This might result in
+ * {@link #getDynamicMBeanFor getDynamicMBeanFor} being called
+ * several times for each returned name.
+ */
+ public Set queryNames(ObjectName pattern, QueryExp query) {
+ try {
+ final Set res = getMatchingNames(pattern);
+ return filterListOfObjectNames(res, query);
+ } catch (Exception x) {
+ LOG.fine("Unexpected exception raised in queryNames: "+x);
+ LOG.log(Level.FINEST, "Unexpected exception raised in queryNames", x);
+ }
+ // We reach here only when an exception was raised.
+ //
+ return Collections.emptySet();
+ }
+
+ private final static boolean apply(final QueryExp query,
+ final ObjectName on,
+ final MBeanServer srv) {
+ boolean res = false;
+ MBeanServer oldServer = QueryEval.getMBeanServer();
+ query.setMBeanServer(srv);
+ try {
+ res = query.apply(on);
+ } catch (Exception e) {
+ LOG.finest("QueryExp.apply threw exception, returning false." +
+ " Cause: "+e);
+ res = false;
+ } finally {
+ /*
+ * query.setMBeanServer is probably
+ * QueryEval.setMBeanServer so put back the old
+ * value. Since that method uses a ThreadLocal
+ * variable, this code is only needed for the
+ * unusual case where the user creates a custom
+ * QueryExp that calls a nested query on another
+ * MBeanServer.
+ */
+ query.setMBeanServer(oldServer);
+ }
+ return res;
+ }
+
+ /**
+ * Filters a {@code Set} according to a pattern and a query.
+ * This might be quite inefficient for virtual name spaces.
+ */
+ Set
+ filterListOfObjectNames(Set list,
+ QueryExp query) {
+ if (list.isEmpty() || query == null)
+ return list;
+
+ // create a new result set
+ final Set result = new HashSet();
+
+ for (ObjectName on : list) {
+ // if on doesn't match query exclude it.
+ if (apply(query, on, this))
+ result.add(on);
+ }
+ return result;
+ }
+
+
+ // Don't use {@inheritDoc}, because we don't want to say that the
+ // MBeanServer replaces a reference to the MBean by its ObjectName.
+ /**
+ * Adds a listener to a registered MBean. A notification emitted by
+ * the MBean will be forwarded to the listener.
+ *
+ * This implementation calls
+ * {@link #getNotificationEmitterFor getNotificationEmitterFor}
+ * and invokes {@code addNotificationListener} on the
+ * {@link NotificationEmitter} it returns.
+ *
+ * @see #getDynamicMBeanFor getDynamicMBeanFor
+ * @see #getNotificationEmitterFor getNotificationEmitterFor
+ */
+ public void addNotificationListener(ObjectName name,
+ NotificationListener listener, NotificationFilter filter,
+ Object handback) throws InstanceNotFoundException {
+ final NotificationEmitter emitter =
+ getNonNullNotificationEmitterFor(name);
+ emitter.addNotificationListener(listener, filter, handback);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ *
This implementation calls
+ * {@link #getNotificationEmitterFor getNotificationEmitterFor}
+ * and invokes {@code removeNotificationListener} on the
+ * {@link NotificationEmitter} it returns.
+ * @see #getDynamicMBeanFor getDynamicMBeanFor
+ * @see #getNotificationEmitterFor getNotificationEmitterFor
+ */
+ public void removeNotificationListener(ObjectName name,
+ NotificationListener listener)
+ throws InstanceNotFoundException, ListenerNotFoundException {
+ final NotificationEmitter emitter =
+ getNonNullNotificationEmitterFor(name);
+ emitter.removeNotificationListener(listener);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ *
This implementation calls
+ * {@link #getNotificationEmitterFor getNotificationEmitterFor}
+ * and invokes {@code removeNotificationListener} on the
+ * {@link NotificationEmitter} it returns.
+ * @see #getDynamicMBeanFor getDynamicMBeanFor
+ * @see #getNotificationEmitterFor getNotificationEmitterFor
+ */
+ public void removeNotificationListener(ObjectName name,
+ NotificationListener listener, NotificationFilter filter,
+ Object handback)
+ throws InstanceNotFoundException, ListenerNotFoundException {
+ NotificationEmitter emitter =
+ getNonNullNotificationEmitterFor(name);
+ emitter.removeNotificationListener(listener);
+ }
+
+
+ /**
+ *
Adds a listener to a registered MBean.
+ *
+ * The default implementation of this method first calls
+ * {@link #getDynamicMBeanFor getDynamicMBeanFor(listenerName)}.
+ * If that successfully returns an object, call it {@code
+ * mbean}, then (a) if {@code mbean} is an instance of {@link
+ * NotificationListener} then this method calls {@link
+ * #addNotificationListener(ObjectName, NotificationListener,
+ * NotificationFilter, Object) addNotificationListener(name, mbean, filter,
+ * handback)}, otherwise (b) this method throws an exception as specified
+ * for this case.
+ *
+ * This default implementation is not appropriate for Virtual MBeans,
+ * although that only matters if the object returned by {@code
+ * getDynamicMBeanFor} can be an instance of
+ * {@code NotificationListener}.
+ *
+ * @throws RuntimeOperationsException {@inheritDoc}
+ */
+ public void addNotificationListener(ObjectName name, ObjectName listenerName,
+ NotificationFilter filter, Object handback)
+ throws InstanceNotFoundException {
+ NotificationListener listener = getListenerMBean(listenerName);
+ addNotificationListener(name, listener, filter, handback);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This operation is not supported in this base class implementation.
+ * The default implementation of this method always throws
+ * {@link RuntimeOperationsException} wrapping
+ * {@link UnsupportedOperationException}.
+ *
+ * @throws javax.management.RuntimeOperationsException wrapping
+ * {@link UnsupportedOperationException}
+ */
+ public void removeNotificationListener(ObjectName name,
+ ObjectName listenerName)
+ throws InstanceNotFoundException, ListenerNotFoundException {
+ NotificationListener listener = getListenerMBean(listenerName);
+ removeNotificationListener(name, listener);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This operation is not supported in this base class implementation.
+ * The default implementation of this method always throws
+ * {@link RuntimeOperationsException} wrapping
+ * {@link UnsupportedOperationException}.
+ *
+ * @throws javax.management.RuntimeOperationsException wrapping
+ * {@link UnsupportedOperationException}
+ */
+ public void removeNotificationListener(ObjectName name,
+ ObjectName listenerName, NotificationFilter filter,
+ Object handback)
+ throws InstanceNotFoundException, ListenerNotFoundException {
+ NotificationListener listener = getListenerMBean(listenerName);
+ removeNotificationListener(name, listener, filter, handback);
+ }
+
+ private NotificationListener getListenerMBean(ObjectName listenerName)
+ throws InstanceNotFoundException {
+ Object mbean = getDynamicMBeanFor(listenerName);
+ if (mbean instanceof NotificationListener)
+ return (NotificationListener) mbean;
+ else {
+ throw newIllegalArgumentException(
+ "MBean is not a NotificationListener: " + listenerName);
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ *
+ * This operation is not supported in this base class implementation.
+ * The default implementation of this method always throws
+ * {@link InstanceNotFoundException} wrapping
+ * {@link UnsupportedOperationException}.
+ *
+ * @return the default implementation of this method never returns.
+ * @throws javax.management.RuntimeOperationsException wrapping
+ * {@link UnsupportedOperationException}
+ */
+ public ClassLoader getClassLoader(ObjectName loaderName)
+ throws InstanceNotFoundException {
+ final UnsupportedOperationException failed =
+ new UnsupportedOperationException("getClassLoader");
+ final InstanceNotFoundException x =
+ new InstanceNotFoundException(String.valueOf(loaderName));
+ x.initCause(failed);
+ throw x;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation of this method calls
+ * {@link #getDynamicMBeanFor getDynamicMBeanFor(mbeanName)} and applies
+ * the logic just described to the result.
+ */
+ public ClassLoader getClassLoaderFor(ObjectName mbeanName)
+ throws InstanceNotFoundException {
+ final DynamicMBean mbean = nonNullMBeanFor(mbeanName);
+ if (mbean instanceof DynamicWrapperMBean)
+ return ((DynamicWrapperMBean) mbean).getWrappedClassLoader();
+ else
+ return mbean.getClass().getClassLoader();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The default implementation of this method returns a
+ * {@link ClassLoaderRepository} containing exactly one loader,
+ * the {@linkplain Thread#getContextClassLoader() context class loader}
+ * for the current thread.
+ * Subclasses can override this method to return a different
+ * {@code ClassLoaderRepository}.
+ */
+ public ClassLoaderRepository getClassLoaderRepository() {
+ // We return a new ClassLoaderRepository each time this
+ // method is called. This is by design, because the
+ // SingletonClassLoaderRepository is a very small object and
+ // getClassLoaderRepository() will not be called very often
+ // (the connector server calls it once) - in the context of
+ // MBeanServerSupport there's a very good chance that this method will
+ // *never* be called.
+ ClassLoader ccl = Thread.currentThread().getContextClassLoader();
+ return Util.getSingleClassLoaderRepository(ccl);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ *
+ * This operation is not supported in this base class implementation.
+ * The default implementation of this method always throws
+ * {@link RuntimeOperationsException} wrapping
+ * {@link UnsupportedOperationException}.
+ * @throws javax.management.RuntimeOperationsException wrapping
+ * {@link UnsupportedOperationException}
+ */
+ public ObjectInstance registerMBean(Object object, ObjectName name)
+ throws InstanceAlreadyExistsException, MBeanRegistrationException,
+ NotCompliantMBeanException {
+ throw newUnsupportedException("registerMBean");
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This operation is not supported in this base class implementation.
+ * The default implementation of this method always throws
+ * {@link RuntimeOperationsException} wrapping
+ * {@link UnsupportedOperationException}.
+ * @throws javax.management.RuntimeOperationsException wrapping
+ * {@link UnsupportedOperationException}
+ */
+ public void unregisterMBean(ObjectName name)
+ throws InstanceNotFoundException, MBeanRegistrationException {
+ throw newUnsupportedException("unregisterMBean");
+ }
+
+ /**
+ * Calls {@link #createMBean(String, ObjectName,
+ * ObjectName, Object[], String[], boolean)
+ * createMBean(className, name, null, params, signature, true)};
+ */
+ public final ObjectInstance createMBean(String className, ObjectName name,
+ Object[] params, String[] signature)
+ throws ReflectionException, InstanceAlreadyExistsException,
+ MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException {
+ try {
+ return safeCreateMBean(className, name, null, params, signature, true);
+ } catch (InstanceNotFoundException ex) {
+ // should not happen!
+ throw new MBeanException(ex, "Unexpected exception: " + ex);
+ }
+ }
+
+ /**
+ * Calls {@link #createMBean(String, ObjectName,
+ * ObjectName, Object[], String[], boolean)
+ * createMBean(className,name, loaderName, params, signature, false)};
+ */
+ public final ObjectInstance createMBean(String className, ObjectName name,
+ ObjectName loaderName, Object[] params, String[] signature)
+ throws ReflectionException, InstanceAlreadyExistsException,
+ MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException, InstanceNotFoundException {
+ return safeCreateMBean(className, name, loaderName, params, signature, false);
+ }
+
+ /**
+ * Calls {@link #createMBean(String, ObjectName,
+ * ObjectName, Object[], String[], boolean)
+ * createMBean(className, name, null, null, null, true)};
+ */
+ public final ObjectInstance createMBean(String className, ObjectName name)
+ throws ReflectionException, InstanceAlreadyExistsException,
+ MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException {
+ try {
+ return safeCreateMBean(className, name, null, null, null, true);
+ } catch (InstanceNotFoundException ex) {
+ // should not happen!
+ throw new MBeanException(ex, "Unexpected exception: " + ex);
+ }
+ }
+
+ /**
+ * Calls {@link #createMBean(String, ObjectName,
+ * ObjectName, Object[], String[], boolean)
+ * createMBean(className, name, loaderName, null, null, false)};
+ */
+ public final ObjectInstance createMBean(String className, ObjectName name,
+ ObjectName loaderName)
+ throws ReflectionException, InstanceAlreadyExistsException,
+ MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException, InstanceNotFoundException {
+ return safeCreateMBean(className, name, loaderName, null, null, false);
+ }
+
+ // make sure all exceptions are correctly wrapped in a JMXException
+ private ObjectInstance safeCreateMBean(String className,
+ ObjectName name, ObjectName loaderName, Object[] params,
+ String[] signature, boolean useRepository)
+ throws ReflectionException, InstanceAlreadyExistsException,
+ MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException, InstanceNotFoundException {
+ try {
+ return createMBean(className, name, loaderName, params,
+ signature, useRepository);
+ } catch (ReflectionException x) { throw x;
+ } catch (InstanceAlreadyExistsException x) { throw x;
+ } catch (MBeanRegistrationException x) { throw x;
+ } catch (MBeanException x) { throw x;
+ } catch (NotCompliantMBeanException x) { throw x;
+ } catch (InstanceNotFoundException x) { throw x;
+ } catch (SecurityException x) { throw x;
+ } catch (JMRuntimeException x) { throw x;
+ } catch (RuntimeException x) {
+ throw new RuntimeOperationsException(x, x.toString());
+ } catch (Exception x) {
+ throw new MBeanException(x, x.toString());
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ *
+ *
This operation is not supported in this base class implementation.
+ * The default implementation of this method always throws
+ * {@link RuntimeOperationsException} wrapping
+ * {@link UnsupportedOperationException}.
+ *
+ * @throws javax.management.RuntimeOperationsException wrapping
+ * {@link UnsupportedOperationException}
+ */
+ public Object instantiate(String className)
+ throws ReflectionException, MBeanException {
+ throw new UnsupportedOperationException("Not applicable.");
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This operation is not supported in this base class implementation.
+ * The default implementation of this method always throws
+ * {@link RuntimeOperationsException} wrapping
+ * {@link UnsupportedOperationException}.
+ *
+ * @throws javax.management.RuntimeOperationsException wrapping
+ * {@link UnsupportedOperationException}
+ */
+ public Object instantiate(String className, ObjectName loaderName)
+ throws ReflectionException, MBeanException,
+ InstanceNotFoundException {
+ throw new UnsupportedOperationException("Not applicable.");
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This operation is not supported in this base class implementation.
+ * The default implementation of this method always throws
+ * {@link RuntimeOperationsException} wrapping
+ * {@link UnsupportedOperationException}.
+ *
+ * @throws javax.management.RuntimeOperationsException wrapping
+ * {@link UnsupportedOperationException}
+ */
+ public Object instantiate(String className, Object[] params,
+ String[] signature) throws ReflectionException, MBeanException {
+ throw new UnsupportedOperationException("Not applicable.");
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This operation is not supported in this base class implementation.
+ * The default implementation of this method always throws
+ * {@link RuntimeOperationsException} wrapping
+ * {@link UnsupportedOperationException}.
+ *
+ * @throws javax.management.RuntimeOperationsException wrapping
+ * {@link UnsupportedOperationException}
+ */
+ public Object instantiate(String className, ObjectName loaderName,
+ Object[] params, String[] signature)
+ throws ReflectionException, MBeanException,
+ InstanceNotFoundException {
+ throw new UnsupportedOperationException("Not applicable.");
+ }
+
+
+ /**
+ * {@inheritDoc}
+ *
+ * This operation is not supported in this base class implementation.
+ * The default implementation of this method always throws
+ * {@link RuntimeOperationsException} wrapping
+ * {@link UnsupportedOperationException}.
+ *
+ * @throws javax.management.RuntimeOperationsException wrapping
+ * {@link UnsupportedOperationException}
+ */
+ @Deprecated
+ public ObjectInputStream deserialize(ObjectName name, byte[] data)
+ throws InstanceNotFoundException, OperationsException {
+ throw new UnsupportedOperationException("Not applicable.");
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This operation is not supported in this base class implementation.
+ * The default implementation of this method always throws
+ * {@link RuntimeOperationsException} wrapping
+ * {@link UnsupportedOperationException}.
+ *
+ * @throws javax.management.RuntimeOperationsException wrapping
+ * {@link UnsupportedOperationException}
+ */
+ @Deprecated
+ public ObjectInputStream deserialize(String className, byte[] data)
+ throws OperationsException, ReflectionException {
+ throw new UnsupportedOperationException("Not applicable.");
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This operation is not supported in this base class implementation.
+ * The default implementation of this method always throws
+ * {@link RuntimeOperationsException} wrapping
+ * {@link UnsupportedOperationException}.
+ *
+ * @throws javax.management.RuntimeOperationsException wrapping
+ * {@link UnsupportedOperationException}
+ */
+ @Deprecated
+ public ObjectInputStream deserialize(String className,
+ ObjectName loaderName, byte[] data)
+ throws InstanceNotFoundException, OperationsException,
+ ReflectionException {
+ throw new UnsupportedOperationException("Not applicable.");
+ }
+
+
+ // Calls getDynamicMBeanFor, and throws an InstanceNotFoundException
+ // if the returned mbean is null.
+ // The DynamicMBean returned by this method is thus guaranteed to be
+ // non null.
+ //
+ private DynamicMBean nonNullMBeanFor(ObjectName name)
+ throws InstanceNotFoundException {
+ if (name == null)
+ throw newIllegalArgumentException("Null ObjectName");
+ if (name.getDomain().equals("")) {
+ String defaultDomain = getDefaultDomain();
+ try {
+ name = name.withDomain(getDefaultDomain());
+ } catch (Exception e) {
+ throw newIllegalArgumentException(
+ "Illegal default domain: " + defaultDomain);
+ }
+ }
+ final DynamicMBean mbean = getDynamicMBeanFor(name);
+ if (mbean!=null) return mbean;
+ throw new InstanceNotFoundException(String.valueOf(name));
+ }
+
+ static RuntimeException newUnsupportedException(String operation) {
+ return new RuntimeOperationsException(
+ new UnsupportedOperationException(
+ operation+": Not supported in this namespace"));
+ }
+
+ static RuntimeException newIllegalArgumentException(String msg) {
+ return new RuntimeOperationsException(
+ new IllegalArgumentException(msg));
+ }
+
+}
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/namespace/VirtualEventManager.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/namespace/VirtualEventManager.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,378 @@
+/*
+ * 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 javax.management.namespace;
+
+import com.sun.jmx.remote.util.ClassLogger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import javax.management.InstanceNotFoundException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.Notification;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.event.EventConsumer;
+
+/**
+ * This class maintains a list of subscribers for ObjectName patterns and
+ * allows a notification to be sent to all subscribers for a given ObjectName.
+ * It is typically used in conjunction with {@link MBeanServerSupport}
+ * to implement a namespace with Virtual MBeans that can emit notifications.
+ * The {@code VirtualEventManager} keeps track of the listeners that have been
+ * added to each Virtual MBean. When an event occurs that should trigger a
+ * notification from a Virtual MBean, the {@link #publish publish} method can
+ * be used to send it to the appropriate listeners.
+ * @since 1.7
+ */
+public class VirtualEventManager implements EventConsumer {
+ /**
+ * Create a new {@code VirtualEventManager}.
+ */
+ public VirtualEventManager() {
+ }
+
+ public void subscribe(
+ ObjectName name,
+ NotificationListener listener,
+ NotificationFilter filter,
+ Object handback) {
+
+ if (logger.traceOn())
+ logger.trace("subscribe", "" + name);
+
+ if (name == null)
+ throw new IllegalArgumentException("Null MBean name");
+
+ if (listener == null)
+ throw new IllegalArgumentException("Null listener");
+
+ Map> map =
+ name.isPattern() ? patternSubscriptionMap : exactSubscriptionMap;
+
+ final ListenerInfo li = new ListenerInfo(listener, filter, handback);
+ List list;
+
+ synchronized (map) {
+ list = map.get(name);
+ if (list == null) {
+ list = new ArrayList();
+ map.put(name, list);
+ }
+ list.add(li);
+ }
+ }
+
+ public void unsubscribe(
+ ObjectName name, NotificationListener listener)
+ throws ListenerNotFoundException {
+
+ if (logger.traceOn())
+ logger.trace("unsubscribe2", "" + name);
+
+ if (name == null)
+ throw new IllegalArgumentException("Null MBean name");
+
+ if (listener == null)
+ throw new ListenerNotFoundException();
+
+ Map> map =
+ name.isPattern() ? patternSubscriptionMap : exactSubscriptionMap;
+
+ final ListenerInfo li = new ListenerInfo(listener, null, null);
+ List list;
+ synchronized (map) {
+ list = map.get(name);
+ if (list == null || !list.remove(li))
+ throw new ListenerNotFoundException();
+
+ if (list.isEmpty())
+ map.remove(name);
+ }
+ }
+
+ /**
+ * Unsubscribes a listener which is listening to an MBean or a set of
+ * MBeans represented by an {@code ObjectName} pattern.
+ *
+ * The listener to be removed must have been added by the {@link
+ * #subscribe subscribe} method with the given {@code name}, {@code filter},
+ * and {@code handback}. If the {@code
+ * name} is a pattern, then the {@code subscribe} must have used the same
+ * pattern. If the same listener has been subscribed more than once to the
+ * {@code name} with the same filter and handback, only one listener is
+ * removed.
+ *
+ * @param name The name of the MBean or an {@code ObjectName} pattern
+ * representing a set of MBeans to which the listener was subscribed.
+ * @param listener A listener that was previously subscribed to the
+ * MBean(s).
+ *
+ * @throws ListenerNotFoundException The given {@code listener} was not
+ * subscribed to the given {@code name}.
+ *
+ * @see #subscribe
+ */
+ public void unsubscribe(
+ ObjectName name, NotificationListener listener,
+ NotificationFilter filter, Object handback)
+ throws ListenerNotFoundException {
+
+ if (logger.traceOn())
+ logger.trace("unsubscribe4", "" + name);
+
+ if (name == null)
+ throw new IllegalArgumentException("Null MBean name");
+
+ if (listener == null)
+ throw new ListenerNotFoundException();
+
+ Map> map =
+ name.isPattern() ? patternSubscriptionMap : exactSubscriptionMap;
+
+ List list;
+ synchronized (map) {
+ list = map.get(name);
+ boolean removed = false;
+ for (Iterator it = list.iterator(); it.hasNext(); ) {
+ ListenerInfo li = it.next();
+ if (li.equals(listener, filter, handback)) {
+ it.remove();
+ removed = true;
+ break;
+ }
+ }
+ if (!removed)
+ throw new ListenerNotFoundException();
+
+ if (list.isEmpty())
+ map.remove(name);
+ }
+ }
+
+ /**
+ * Sends a notification to the subscribers for a given MBean.
+ *
+ * For each listener subscribed with an {@code ObjectName} that either
+ * is equal to {@code emitterName} or is a pattern that matches {@code
+ * emitterName}, if the associated filter accepts the notification then it
+ * is forwarded to the listener.
+ *
+ * @param emitterName The name of the MBean emitting the notification.
+ * @param n The notification being sent by the MBean called
+ * {@code emitterName}.
+ *
+ * @throws IllegalArgumentException If the emitterName of the
+ * notification is null or is an {@code ObjectName} pattern.
+ */
+ public void publish(ObjectName emitterName, Notification n) {
+ if (logger.traceOn())
+ logger.trace("publish", "" + emitterName);
+
+ if (n == null)
+ throw new IllegalArgumentException("Null notification");
+
+ if (emitterName == null) {
+ throw new IllegalArgumentException(
+ "Null emitter name");
+ } else if (emitterName.isPattern()) {
+ throw new IllegalArgumentException(
+ "The emitter must not be an ObjectName pattern");
+ }
+
+ final List listeners = new ArrayList();
+
+ // If there are listeners for this exact name, add them.
+ synchronized (exactSubscriptionMap) {
+ List exactListeners =
+ exactSubscriptionMap.get(emitterName);
+ if (exactListeners != null)
+ listeners.addAll(exactListeners);
+ }
+
+ // Loop over subscription patterns, and add all listeners for each
+ // one that matches the emitterName name.
+ synchronized (patternSubscriptionMap) {
+ for (ObjectName on : patternSubscriptionMap.keySet()) {
+ if (on.apply(emitterName))
+ listeners.addAll(patternSubscriptionMap.get(on));
+ }
+ }
+
+ // Send the notification to all the listeners we found.
+ sendNotif(listeners, n);
+ }
+
+ /**
+ * Returns a {@link NotificationEmitter} object which can be used to
+ * subscribe or unsubscribe for notifications with the named
+ * mbean. The returned object implements {@link
+ * NotificationEmitter#addNotificationListener
+ * addNotificationListener(listener, filter, handback)} as
+ * {@link #subscribe this.subscribe(name, listener, filter, handback)}
+ * and the two {@code removeNotificationListener} methods from {@link
+ * NotificationEmitter} as the corresponding {@code unsubscribe} methods
+ * from this class.
+ *
+ * @param name The name of the MBean whose notifications are being
+ * subscribed, or unsuscribed.
+ *
+ * @return A {@link NotificationEmitter}
+ * that can be used to subscribe or unsubscribe for
+ * notifications emitted by the named MBean, or {@code null} if
+ * the MBean does not emit notifications and should not
+ * be considered as a {@code NotificationBroadcaster}. This class
+ * never returns null but a subclass is allowed to.
+ *
+ * @throws InstanceNotFoundException if {@code name} does not exist.
+ * This implementation never throws {@code InstanceNotFoundException} but
+ * a subclass is allowed to override this method to do so.
+ */
+ public NotificationEmitter
+ getNotificationEmitterFor(final ObjectName name)
+ throws InstanceNotFoundException {
+ final NotificationEmitter emitter = new NotificationEmitter() {
+ public void addNotificationListener(NotificationListener listener,
+ NotificationFilter filter, Object handback)
+ throws IllegalArgumentException {
+ subscribe(name, listener, filter, handback);
+ }
+
+ public void removeNotificationListener(
+ NotificationListener listener)
+ throws ListenerNotFoundException {
+ unsubscribe(name, listener);
+ }
+
+ public void removeNotificationListener(NotificationListener listener,
+ NotificationFilter filter,
+ Object handback)
+ throws ListenerNotFoundException {
+ unsubscribe(name, listener, filter, handback);
+ }
+
+ public MBeanNotificationInfo[] getNotificationInfo() {
+ // Never called.
+ return null;
+ }
+ };
+ return emitter;
+ }
+
+ // ---------------------------------
+ // private stuff
+ // ---------------------------------
+
+ private static class ListenerInfo {
+ public final NotificationListener listener;
+ public final NotificationFilter filter;
+ public final Object handback;
+
+ public ListenerInfo(NotificationListener listener,
+ NotificationFilter filter,
+ Object handback) {
+
+ if (listener == null) {
+ throw new IllegalArgumentException("Null listener.");
+ }
+
+ this.listener = listener;
+ this.filter = filter;
+ this.handback = handback;
+ }
+
+ /* Two ListenerInfo instances are equal if they have the same
+ * NotificationListener. This means that we can use List.remove
+ * to implement the two-argument removeNotificationListener.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (!(o instanceof ListenerInfo)) {
+ return false;
+ }
+
+ return listener.equals(((ListenerInfo)o).listener);
+ }
+
+ /* Method that compares all four fields, appropriate for the
+ * four-argument removeNotificationListener.
+ */
+ boolean equals(
+ NotificationListener listener,
+ NotificationFilter filter,
+ Object handback) {
+ return (this.listener == listener && same(this.filter, filter)
+ && same(this.handback, handback));
+ }
+
+ private static boolean same(Object x, Object y) {
+ if (x == y)
+ return true;
+ if (x == null)
+ return false;
+ return x.equals(y);
+ }
+
+ @Override
+ public int hashCode() {
+ return listener.hashCode();
+ }
+ }
+
+ private static void sendNotif(List listeners, Notification n) {
+ for (ListenerInfo li : listeners) {
+ if (li.filter == null ||
+ li.filter.isNotificationEnabled(n)) {
+ try {
+ li.listener.handleNotification(n, li.handback);
+ } catch (Exception e) {
+ logger.trace("sendNotif", "handleNotification", e);
+ }
+ }
+ }
+ }
+
+ // ---------------------------------
+ // private variables
+ // ---------------------------------
+
+ private final Map> exactSubscriptionMap =
+ new HashMap>();
+ private final Map> patternSubscriptionMap =
+ new HashMap>();
+
+ // trace issue
+ private static final ClassLogger logger =
+ new ClassLogger("javax.management.event", "EventManager");
+}
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/namespace/package-info.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/namespace/package-info.java Thu Sep 04 14:55:12 2008 -0700
@@ -0,0 +1,597 @@
+/*
+ * 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.
+ */
+
+/**
+ * The javax.management.namespace
package makes it possible
+ * to federate MBeanServers into a hierarchical name space.
+ *
+ * What Is a Name Space?
+ *
+ * A name space is like an {@link javax.management.MBeanServer} within
+ * an {@code MBeanServer}. Just as a file system folder can contain
+ * another file system folder, an {@code MBeanServer} can contain another
+ * {@code MBeanServer}. Similarly, just as a remote folder on a remote
+ * disk can be mounted on a parent folder on a local disk, a remote name
+ * space in a remote {@code MBeanServer} can be mounted on a name
+ * space in a local parent {@code MBeanServer}.
+ *
+ *
+ * The javax.management.namespace
API thus makes it possible to
+ * create a hierarchy of MBean servers federated in a hierarchical name
+ * space inside a single {@code MBeanServer}.
+ *
+ * How To Create a Name Space?
+ *
+ * To create a name space, you only need to register a
+ * {@link javax.management.namespace.JMXNamespace} MBean in
+ * an MBean server. We have seen that a namespace is like
+ * an {@code MBeanServer} within an {@code MBeanServer}, and
+ * therefore, it is possible to create a namespace that shows the
+ * content of another {@code MBeanServer}. The simplest case is
+ * when that {@code MBeanServer} is another {@code MBeanServer}
+ * created by the {@link javax.management.MBeanServerFactory} as
+ * shown in the extract below:
+ *
+ *
+ * final MBeanServer server = ....;
+ * final String namespace = "foo";
+ * final ObjectName namespaceName = {@link javax.management.namespace.JMXNamespaces#getNamespaceObjectName
+ * JMXNamespaces.getNamespaceObjectName(namespace)};
+ * server.registerMBean(new JMXNamespace(MBeanServerFactory.newMBeanServer()),
+ * namespaceName);
+ *
+ *
+ * To navigate in namespaces and view their content, the easiest way is
+ * to use an instance of {@link javax.management.namespace.JMXNamespaceView}. For instance, given
+ * the {@code server} above, in which we created a namespace {@code "foo"},
+ * it is possible to create a {@code JMXNamespaceView} that will make it
+ * possible to navigate easily in the namespaces and sub-namespaces of that
+ * server:
+ *
+ *
+ * // create a namespace view for 'server'
+ * final JMXNamespaceView view = new JMXNamespaceView(server);
+ *
+ * // list all top level namespaces in 'server'
+ * System.out.println("List of namespaces: " + Arrays.toString({@link javax.management.namespace.JMXNamespaceView#list() view.list()}));
+ *
+ * // go down into namespace 'foo': provides a namespace view of 'foo' and its
+ * // sub namespaces...
+ * final JMXNamespaceView foo = {@link javax.management.namespace.JMXNamespaceView#down view.down("foo")};
+ *
+ * // list all MBeans contained in namespace 'foo'
+ * System.out.println({@link javax.management.namespace.JMXNamespaceView#where() foo.where()} + " contains: " +
+ * {@link javax.management.namespace.JMXNamespaceView#getMBeanServerConnection foo.getMBeanServerConnection()}.queryNames(null,null));
+ *
+ *
+ * It is also possible to create more complex namespaces, such as namespaces
+ * that point to MBean servers located in remote JVMs.
+ *
+ *
+ * For instance, to mount the MBeanServer accessible
+ * at service:jmx:rmi:///jndi/rmi://localhost:9000/jmxrmi
+ * in a name space {@code "foo"} inside the {@linkplain
+ * java.lang.management.ManagementFactory#getPlatformMBeanServer platform
+ * MBeanServer} you would write the following piece of code:
+ *
+ *
+ * final JMXServiceURL sourceURL =
+ * new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9000/jmxrmi");
+ * final MBeanServer platform = ManagementFactory.getPlatformMBeanServer();
+ * final Map<String,Object> options = Collections.emptyMap();
+ * final JMXRemoteNamespace mbean = {@link
+ * javax.management.namespace.JMXRemoteNamespace JMXRemoteNamespace}.
+ * {@link javax.management.namespace.JMXRemoteNamespace#newJMXRemoteNamespace newJMXRemoteNamespace(sourceURL, options)};
+ * final ObjectName name = {@link javax.management.namespace.JMXNamespaces JMXNamespaces}.{@link javax.management.namespace.JMXNamespaces#getNamespaceObjectName(String) getNamespaceObjectName("foo")};
+ * final ObjectInstance ref = platform.registerMBean(mbean,name);
+ * platform.invoke(ref.getObjectName(),"connect",null,null);
+ *
+ *
+ * What Does a Name Space Look Like?
+ *
+ *
+ * We have seen that {@link javax.management.namespace.JMXNamespaceView} class
+ * provides an easy way to navigate within namespaces. It is however also
+ * possible to interact with namespaces directly from the top level
+ * {@code MBeanServer} in which they have been created.
+ * From the outside, a name space only appears as a special MBean in
+ * the MBean server. There's nothing much you can do with this MBean
+ * directly.
+ *
+ *
+ * For instance, let's assume you have registered a {@link
+ * javax.management.namespace.JMXRemoteNamespaceMBean
+ * JMXRemoteNamespaceMBean} to manage the name space {@code "foo"}.
+ *
If you query for
+ * platform.queryNames("*//:*",null)
, then you will see
+ * one MBean named {@code "foo//:type=JMXNamespace"}.
+ *
This is the {@link javax.management.namespace.JMXNamespace}
+ * MBean which is in charge of handling the namespace {@code "foo"}.
+ *
+ *
+ * In fact, name space handler MBeans are instances of
+ * the class {@link javax.management.namespace.JMXNamespace} - or
+ * instances of a subclass of that class.
+ * They have a special {@link javax.management.ObjectName} defined by
+ * {@link javax.management.namespace.JMXNamespaces#getNamespaceObjectName
+ * JMXNamespaces.getNamespaceObjectName}.
+ * {@link javax.management.namespace.JMXNamespace} instances are able
+ * to return an {@link
+ * javax.management.namespace.JMXNamespace#getSourceServer MBeanServer}
+ * which corresponds to the MBeanServer within (= the name space itself).
+ *
+ *
+ * So how does it work? How can you see the MBeans contained in the new
+ * name space?
+ *
+ * In order to address scalability issues, MBeans registered in
+ * namespaces (such as our namespace {@code "foo"} above) can not be
+ * seen with {@code mbeanServer.queryNames("*:*",null)}. To see the MBeans
+ * contained in a namespace, you can use one of these methods:
+ *
+ *
+ * -
+ * You can use the {@link javax.management.namespace.JMXNamespaceView}
+ * class shown above,
+ *
+ * -
+ * or you can directly look for MBeans
+ * whose names match
+ * {@code "foo//*:*"},
+ *
+ * -
+ * or you can narrow down to the namespace
+ * and obtain an MBeanServer
+ * proxy that corresponds to an MBeanServer view of that namespace.
+ * The JMXNamespaces class provides a static method that
+ * allows you to narrow down to a name space, by calling
+ * {@link javax.management.namespace.JMXNamespaces#narrowToNamespace(MBeanServer,String)
+ * JMXNamespaces.narrowToNamespace}.
+ *
+ *
+ *
+ * Using Name Space Prefixes
+ *
+ * As we have explained above, MBeans contained in name
+ * spaces are not returned by {@code server.queryNames(null,null)} - or
+ * server.queryNames({@link javax.management.ObjectName#WILDCARD ObjectName.WILDCARD},null)
.
+ *
+ * However, these MBeans can still be accessed from the top level
+ * {@code MBeanServer} interface, without using any API specific to the
+ * version 2.0 of the JMX API, simply by using object names with
+ * name space prefixes:
+ *
To list MBeans contained in a namespace {@code "foo"} you can
+ * query for MBeans whose names match {@code "foo//*:*"}, as shown
+ * earlier in this document:
+ *
+ * server.queryNames(new ObjectName("foo//*:*", null);
+ * // or equivalently:
+ * server.queryNames(JMXNamespaces.getWildcardFor("foo"), null);
+ *
+ * This will return a list of MBean names whose domain name starts
+ * with {@code foo//}.
+ *
+ * Using these names, you can invoke any operation on the corresponding
+ * MBeans. For instance, to get the {@link javax.management.MBeanInfo
+ * MBeanInfo} of an MBean
+ * contained in name space {@code "foo"} (assuming
+ * the name of the MBean within its name space is domain:type=Thing,
+ * then simply call:
+ *
+ * server.getMBeanInfo(new ObjectName("foo//domain:type=Thing"));
+ *
+ * An easier way to access MBeans contained in a name space is to
+ * cd inside the name space, as shown in the following paragraph.
+ *
+ *
+ * Narrowing Down Into a Name Spaces
+ *
+ * As we have seen, name spaces are like MBean servers within MBean servers.
+ * Therefore, it is possible to view a name space just as if it were
+ * an other MBean server. This is similar to opening a sub
+ * folder from a parent folder.
+ * This operation is illustrated in the code extract below:
+ *
+ * final MBeanServer foo =
+ * JMXNamespaces.narrowToNamespace(platform, "foo");
+ * final MBeanInfo info =
+ * foo.getMBeanInfo(new ObjectName("domain:type=Thing"));
+ *
+ * The {@code MBeanServer} returned by {@link
+ * javax.management.namespace.JMXNamespaces#narrowToNamespace(MBeanServer,String)
+ * JMXNamespaces.narrowToNamespace} is an {@code MBeanServer} view that
+ * narrows down into a given namespace. The MBeans contained inside that
+ * namespace can now be accessed by their regular local name.
+ * The MBean server obtained by narrowing down
+ * to name space {@code "foo"} behaves just like a regular MBean server.
+ * However, it may sometimes throw an {@link
+ * java.lang.UnsupportedOperationException UnsupportedOperationException}
+ * wrapped in a JMX exception if you try to call an operation which is not
+ * supported by the underlying name space handler.
+ *
For instance, {@link javax.management.MBeanServer#registerMBean
+ * registerMBean} is not supported for name spaces mounted from remote
+ * MBean servers.
+ *
+ *
+ * Note: If you have a deep hierarchy of namespaces, and if you
+ * are switching from one namespace to another in the course of your
+ * application, it might be more convenient to use a
+ * {@link javax.management.namespace.JMXNamespaceView}
+ * in order to navigate in your namespaces.
+ *
+ *
+ * Different Types of Name Spaces
+ *
+ * This API lets you create several types of name spaces:
+ *
+ * -
+ * You can use the {@link
+ * javax.management.namespace.JMXRemoteNamespace
+ * JMXRemoteNamespace} to create
+ * remote name spaces, mounted from
+ * a remote sub {@code MBeanServer} source, as shown
+ * earlier in this document.
+ *
+ * -
+ * You can also use {@link
+ * javax.management.namespace.JMXNamespace
+ * JMXNamespace} to create
+ * local name spaces,
+ * by providing a direct reference to another {@code MBeanServer}
+ * instance living in the same JVM.
+ *
+ * -
+ * Finally, you can create
+ * name spaces containing virtual MBeans,
+ * by subclassing the {@link
+ * javax.management.namespace.MBeanServerSupport
+ * MBeanServerSupport}, and passing an instance of
+ * your own subclass to a {@link
+ * javax.management.namespace.JMXNamespace JMXNamespace}.
+ *
+ * -
+ * If none of these classes suit your needs, you can also provide
+ * your own subclass of {@link
+ * javax.management.namespace.JMXNamespace
+ * JMXNamespace}. This is however discouraged.
+ *
+ *
+ *
+ *
+ * Name Spaces And Special Operations
+ *
+ * MBean Naming considerations aside, Name Spaces are transparent for
+ * most {@code MBeanServer} operations. There are however a few
+ * exceptions:
+ *
+ *
+ * -
+ *
MBeanServer only operations - these are the operations which are
+ * supported by {@link javax.management.MBeanServer MBeanServer} but
+ * are not present in {@link
+ * javax.management.MBeanServerConnection
+ * MBeanServerConnection}. Since a name space can be a local view of
+ * a remote {@code MBeanServer}, accessible only through an
+ * {@code MBeanServerConnection}, these
+ * kinds of operations are not always supported.
+ *
+ * -
+ *
registerMBean:
+ * The {@link javax.management.MBeanServer#registerMBean
+ * registerMBean}
+ * operation is not supported by most name spaces. A call
+ * to
+ *
+ * MBeanServer server = ....;
+ * ThingMBean mbean = new Thing(...);
+ * ObjectName name = new ObjectName("foo//domain:type=Thing");
+ * server.registerMBean(mbean, name);
+ *
+ * will usually fail, unless the name space
+ * {@code "foo"} is a local name
+ * space. In the case where you attempt to cross
+ * multiple name spaces, then all name spaces in the
+ * path must support the {@code registerMBean} operation
+ * in order for it to succeed.
+ * To create an MBean inside a name space, it is
+ * usually safer to use {@code createMBean} -
+ * although some special
+ * considerations can also apply.
+ *
+ *
+ *
+ * -
+ *
getClassLoader:
+ * Similarly to registerMBean,
+ * and for the same reasons, {@link
+ * javax.management.MBeanServer#getClassLoader
+ * getClassLoader} will usually fail, unless the
+ * class loader is an MBean registered in a
+ * local name space.
+ *
+ *
+ * -
+ *
getClassLoaderFor:
+ * The implementation of {@link
+ * javax.management.MBeanServer#getClassLoaderFor
+ * getClassLoaderFor} also depends on which
+ * type of name space
+ * handler is used across the namespace path.
+ *
+ *
+ * A local name space will usually
+ * be able to implement this method just as a real
+ * {@code MBeanServer} would. A
+ * remote name space will usually
+ * return the default class loader configured on the
+ * internal {@link javax.management.remote.JMXConnector
+ * JMXConnector} used to connect to the remote server.
+ * When a {@link
+ * javax.management.namespace.JMXRemoteNamespace
+ * JMXRemoteNamespace} is used to connect to a
+ * remote server that contains MBeans which export
+ * custom types, the {@link
+ * javax.management.namespace.JMXRemoteNamespace
+ * JMXRemoteNamespace} must thus be configured with
+ * an options map such that the underlying connector
+ * can obtain a default class loader able
+ * to handle those types.
+ *
+ *
+ * Other types of name spaces
+ * may implement this method
+ * as best as they can.
+ *
+ *
+ *
+ *
+ * -
+ *
MBean creation
+ * MBean creation through {@link
+ * javax.management.MBeanServerConnection#createMBean
+ * createMBean} might not be supported by all
+ * name spaces: local name spaces and
+ * remote name spaces will usually
+ * support it, but virtual name
+ * spaces and custom name
+ * spaces might not.
+ *
+ *
+ * In that case, they will throw an {@link
+ * java.lang.UnsupportedOperationException
+ * UnsupportedOperationException} usually wrapped into an {@link
+ * javax.management.MBeanRegistrationException}.
+ *
+ *
+ * -
+ *
Notifications
+ * Some namespaces might not support JMX Notifications. In that
+ * case, a call to add or remove notification listener for an
+ * MBean contained in that name space will raise a
+ * {@link javax.management.RuntimeOperationsException
+ * RuntimeOperationsException} wrapping an {@link
+ * java.lang.UnsupportedOperationException
+ * UnsupportedOperationException} exception.
+ *
+ *
+ *
+ *
+ * Crossing Several Name Spaces
+ *
+ * Just as folders can contain other folders, name spaces can contain
+ * other name spaces. For instance, if an {@code MBeanServer} S1
+ * containing a name space {@code "bar"} is mounted in another
+ * {@code MBeanServer} S2 with name space {@code "foo"}, then
+ * an MBean M1 named {@code "domain:type=Thing"} in namespace
+ * {@code "bar"} will appear as {@code "foo//bar//domain:type=Thing"} in
+ * {@code MBeanServer} S2.
+ *
+ *
+ * When accessing the MBean M1 from server S2, the
+ * method call will traverse in a cascade {@code MBeanServer} S2,
+ * then the name space handler for name space {@code "foo"}, then
+ * {@code MBeanServer} S1, before coming to the name space
+ * handler for name space {@code "bar"}. Any operation invoked
+ * on the MBean from a "top-level" name space will therefore need to
+ * traverse all the name spaces along the name space path until
+ * it eventually reaches the named MBean. This means that an operation
+ * like registerMBean for instance,
+ * can only succeed if all the name spaces along the path support it.
+ *
+ *
+ * Narrowing to a nested name space works just the same as narrowing
+ * to a top level name space:
+ *
+ * final MBeanServer S2 = .... ;
+ * final MBeanServer bar =
+ * JMXNamespaces.narrowToNamespace(S2, "foo//bar");
+ * final MBeanInfo info =
+ * foo.getMBeanInfo(new ObjectName("domain:type=Thing"));
+ *
+ *
+ *
+ * Name Spaces And Operation Results
+ *
+ * Operation results, as well as attribute values returned by an MBean
+ * contained in a name space must be interpreted in the context of that
+ * name space.
+ * In other words, if an MBean in name space "foo" has an attribute of
+ * type {@code ObjectName}, then it must be assumed that the
+ * {@code ObjectName} returned by that MBean is relative to
+ * name space "foo".
+ * The same rule aplies for MBean names that can be returned by
+ * operations invoked on such an MBean. If one of the MBean operations
+ * return, say, a {@code Set} then those MBean names must
+ * also be assumed to be relative to name space "foo".
+ *
+ *
+ * In the usual case, a JMX client will first
+ * narrow to a name space before invoking
+ * any operation on the MBeans it contains. In that case the names
+ * returned by the MBean invoked can be directly fed back to the
+ * narrowed connection.
+ *
+ * If however, the JMX client directly invoked the MBean from a higher
+ * name space, without having narrowed to that name space first, then
+ * the names that might be returned by that MBean will not be directly
+ * usable - the JMX client will need to either
+ * narrow to the name space before using the
+ * returned names, or convert the names to the higher level name space
+ * context.
+ *
+ * The {@link javax.management.namespace.JMXNamespaces JMXNamespaces}
+ * class provides methods that can be used to perform that conversion.
+ *
+ *
+ * Name Spaces And Notifications
+ *
+ * As already explained, name spaces are very
+ * similar to {@code MBeanServer}s. It is thus possible to get
+ * {@link javax.management.MBeanServerNotification MBeanServerNotifications}
+ * when MBeans are added or removed within a name space, by registering
+ * with the {@link javax.management.MBeanServerDelegate
+ * MBeanServerDelegate} MBean of the corresponding name space.
+ * However, it must be noted that the notifications emitted by a
+ * name space must be interpreted in the context of that name space.
+ * For instance, if an MBean {@code "domain:type=Thing"} contained in
+ * namespace "foo//bar" emits a notification, the source of the
+ * notification will be {@code "domain:type=Thing"}, not
+ * {@code "foo//bar//domain:type=Thing"}.
+ * It is therefore recommended to keep track of the name space
+ * information when registering a listener with an MBean contained in
+ * a name space, especially if the same listener is used to receive
+ * notifications from different name spaces. An easy solution is to
+ * use the handback, as illustrated in the code below.
+ *
+ * final MBeanServer server = ...;
+ * final NotificationListener listener = new NotificationListener() {
+ * public void handleNotification(Notification n, Object handback) {
+ * if (!(n instanceof MBeanServerNotification)) {
+ * System.err.println("Error: expected MBeanServerNotification");
+ * return;
+ * }
+ * final MBeanServerNotification mbsn =
+ * (MBeanServerNotification) n;
+ *
+ * // We will pass the namespace path in the handback.
+ * //
+ * // The received notification must be interpreted in
+ * // the context of its source - therefore
+ * // mbsn.getMBeanName() does not include the name space
+ * // path...
+ * //
+ * final String namespace = (String) handback;
+ * System.out.println("Received " + mbsn.getType() +
+ * " for MBean " + mbsn.getMBeanName() +
+ * " from name space " + namespace);
+ * }
+ * };
+ * server.addNotificationListener(JMXNamespaces.insertPath("foo//bar",
+ * MBeanServerDelegate.DELEGATE_NAME),listener,null,"foo//bar");
+ * server.addNotificationListener(JMXNamespaces.insertPath("foo//joe",
+ * MBeanServerDelegate.DELEGATE_NAME),listener,null,"foo//joe");
+ *
+ *
+ *
+ * JMX Connectors may require some configuration in order to be able
+ * to forward notifications from MBeans located in name spaces.
+ * The RMI JMX Connector Server
+ * in the Java SE 7 platform is configured by default to internally
+ * use the new {@linkplain javax.management.event event service} on
+ * the server side.
+ * When the connector server is configured in this way, JMX clients
+ * which use the old JMX Notifications mechanism (such as clients
+ * running on prior versions of the JDK) will be able to
+ * to receive notifications from MBeans located in sub name spaces.
+ * This is because the connector server will transparently delegate
+ * their subscriptions to the underlying {@linkplain
+ * javax.management.event event service}. In summary:
+ *
+ * -
+ * On the server side: When exporting an {@code MBeanServer}
+ * through a JMX Connector, you will need to make sure that the
+ * connector server uses the new {@linkplain javax.management.event
+ * event service} in order to register for notifications. If the
+ * connector server doesn't use the event service, only clients
+ * which explicitly use the new {@linkplain javax.management.event
+ * event service} will be able to register for notifications
+ * with MBeans located in sub name spaces.
+ *
+ * -
+ * On the client side: if the JMX Connector server (on the remote
+ * server side) was configured to internally use the new
+ * {@linkplain javax.management.event
+ * event service}, then clients can continue to use the old
+ * {@code MBeanServerConnection} add / remove notification
+ * listener methods transparently. Otherwise, only clients which
+ * explicitly use the new {@linkplain javax.management.event
+ * event service} will be able to receive notifications from
+ * MBeans contained in sub name spaces.
+ *
+ *
+ *
+ *
+ * These configuration issues apply at each node in the name space path,
+ * whenever the name space points to a remote server. The
+ * {@link javax.management.namespace.JMXRemoteNamespace
+ * JMXRemoteNamespace} can be configured in such a way that it will
+ * explicitly use an {@link javax.management.event.EventClient EventClient}
+ * when forwarding subscription to the remote side. Note that this can be
+ * unnecessary (and a waste of resources) if the underlying JMXConnector
+ * returned by the JMXConnectorFactory (client side) already uses the
+ * {@linkplain javax.management.event event service} to register for
+ * notifications with the server side.
+ *
+ *
+ * Name Spaces And Access Control
+ *
+ * Access to MBeans exposed through JMX namespaces is controlled by
+ * {@linkplain javax.management.namespace.JMXNamespacePermission
+ * jmx namespace permissions}. These permissions are checked by the
+ * MBeanServer in which the {@link
+ * javax.management.namespace.JMXNamespace JMXNamespace} MBean is registered.
+ * This is described in
+ * details in the {@link
+ * javax.management.namespace.JMXNamespace JMXNamespace} class.
+ *
+ *
+ * To implement a "firewall-like" access control in a JMX agent you
+ * can also place an {@link
+ * javax.management.remote.MBeanServerForwarder} in the JMX Connector
+ * Server which exposes the top-level MBeanServer of your application.
+ * This {@code MBeanServerForwarder} will be able to perform
+ * authorization checks for all MBeans, including those located in
+ * sub name spaces.
+ *
+ *
+ * For a tighter access control we recommend using a {@link
+ * java.lang.SecurityManager security manager}.
+ *
+ * @since 1.7
+ *
+ **/
+
+package javax.management.namespace;
+
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/openmbean/CompositeType.java
--- a/jdk/src/share/classes/javax/management/openmbean/CompositeType.java Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/src/share/classes/javax/management/openmbean/CompositeType.java Thu Sep 04 14:55:12 2008 -0700
@@ -89,7 +89,7 @@
*
* @param itemNames The names of the items contained in the
* composite data values described by this CompositeType
instance;
- * cannot be null and should contain at least one element; no element can be a null or empty string.
+ * cannot be null; no element can be null or an empty string.
* Note that the order in which the item names are given is not important to differentiate a
* CompositeType
instance from another;
* the item names are internally stored sorted in ascending alphanumeric order.
@@ -97,7 +97,7 @@
* @param itemDescriptions The descriptions, in the same order as itemNames, of the items contained in the
* composite data values described by this CompositeType
instance;
* should be of the same size as itemNames;
- * no element can be a null or empty string.
+ * no element can be null or an empty string.
*
* @param itemTypes The open type instances, in the same order as itemNames, describing the items contained
* in the composite data values described by this CompositeType
instance;
@@ -125,7 +125,7 @@
//
super(CompositeData.class.getName(), typeName, description, false);
- // Check the 3 arrays are not null or empty (ie length==0) and that there is no null element or empty string in them
+ // Check the 3 arrays are not null and that there is no null element or empty string in them
//
checkForNullElement(itemNames, "itemNames");
checkForNullElement(itemDescriptions, "itemDescriptions");
diff -r 972c77670265 -r cbfe7dbaf365 jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java
--- a/jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java Sun Aug 31 11:59:20 2008 -0700
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java Thu Sep 04 14:55:12 2008 -0700
@@ -268,6 +268,14 @@
return conn;
}
+ private static Map newHashMap() {
+ return new HashMap();
+ }
+
+ private static Map newHashMap(Map map) {
+ return new HashMap(map);
+ }
+
/**
* Creates a connector client for the connector server at the
* given address. The resultant client is not connected until its
@@ -300,16 +308,18 @@
public static JMXConnector newJMXConnector(JMXServiceURL serviceURL,
Map environment)
throws IOException {
- Map envcopy;
+
+ final Map envcopy;
if (environment == null)
- envcopy = new HashMap();
+ envcopy = newHashMap();
else {
EnvHelp.checkAttributes(environment);
- envcopy = new HashMap(environment);
+ envcopy = newHashMap(environment);
}
final ClassLoader loader = resolveClassLoader(envcopy);
- final Class targetInterface = JMXConnectorProvider.class;
+ final Class targetInterface =
+ JMXConnectorProvider.class;
final String protocol = serviceURL.getProtocol();
final String providerClassName = "ClientProvider";
@@ -351,9 +361,10 @@
}
}
- envcopy = Collections.unmodifiableMap(envcopy);
+ final Map fixedenv =
+ Collections.unmodifiableMap(envcopy);
- return provider.newJMXConnector(serviceURL, envcopy);
+ return provider.newJMXConnector(serviceURL, fixedenv);
}
private static String resolvePkgs(Map env) throws JMXProviderException {
@@ -365,8 +376,8 @@
if (pkgsObject == null)
pkgsObject =
- AccessController.doPrivileged(new PrivilegedAction