diff --git a/.hgtags b/.hgtags index 75a9825e99c3ee88565553aaacbccaf33e07a592..5a4391f4df5a7edb593299553f18709e723fd3a9 100644 --- a/.hgtags +++ b/.hgtags @@ -8,3 +8,5 @@ b6d6877c1155621a175dccd12dc14c54f938fb8b jdk7-b30 b7474b739d13bacd9972f88ac91f6350b7b0be12 jdk7-b31 c51121419e30eac5f0fbbce45ff1711c4ce0de28 jdk7-b32 fa4c0a6cdd25d97d4e6f5d7aa180bcbb0e0d56af jdk7-b33 +434055a0716ee44bca712ebca02fc04b20e6e288 jdk7-b34 +cf4894b78ceb966326e93bf221db0c2d14d59218 jdk7-b35 diff --git a/make/common/Defs.gmk b/make/common/Defs.gmk index a0cb9481c038c9f13ef0dd7dab3823e8e597405a..0c7e34014dfe62a10115186a83e586545ebea4d6 100644 --- a/make/common/Defs.gmk +++ b/make/common/Defs.gmk @@ -451,7 +451,7 @@ vpath %.$(OBJECT_SUFFIX) $(OBJDIR) # namely jni.h, jvm.h, and jni_utils.h, plus their platform-specific # relatives. # -VPATH.h = $(PLATFORM_SRC)/javavm/export$(CLASSPATH_SEPARATOR)$(SHARE_SRC)/javavm/export$(CLASSPATH_SEPARATOR)$(SHARE_SRC)/javavm/include$(CLASSPATH_SEPARATOR)$(PLATFORM_SRC)/javavm/include +VPATH.h = $(PLATFORM_SRC)/javavm/export$(CLASSPATH_SEPARATOR)$(SHARE_SRC)/javavm/export vpath %.h $(VPATH.h) # diff --git a/make/common/shared/Defs-windows.gmk b/make/common/shared/Defs-windows.gmk index 250604136bc3141a57fc737d75610d51b10dc64b..d0be243d8e1b37f457f2194a661a4e064dc54581 100644 --- a/make/common/shared/Defs-windows.gmk +++ b/make/common/shared/Defs-windows.gmk @@ -539,6 +539,8 @@ else WSCRIPT :=$(call FileExists,$(_WSCRIPT1),$(_WSCRIPT2)) endif WSCRIPT:=$(call AltCheckSpaces,WSCRIPT) +# batch mode no modal dialogs on errors, please. +WSCRIPT += -B # CSCRIPT: path to cscript.exe (used in creating install bundles) ifdef ALT_CSCRIPT @@ -561,6 +563,10 @@ else MSIVAL2 :=$(call FileExists,$(_MSIVAL2_1),$(_MSIVAL2_2)) endif MSIVAL2:=$(call AltCheckSpaces,MSIVAL2) +# suppress msival2 checks, as it hangs jprt builds +ifdef SKIP_MSIVAL2 + MSIVAL2 := $(ECHO) +endif # LOGOCUB: path to cub file for (used in validating install msi files) ifdef ALT_LOGOCUB diff --git a/make/docs/CORE_PKGS.gmk b/make/docs/CORE_PKGS.gmk index dfedc7e123781eb3cad4458ce62fee3f603d8fc6..4a41a2005bf6b361f6c223ae355cb07e085a36c2 100644 --- a/make/docs/CORE_PKGS.gmk +++ b/make/docs/CORE_PKGS.gmk @@ -158,6 +158,7 @@ CORE_PKGS = \ javax.management.event \ javax.management.loading \ javax.management.monitor \ + javax.management.namespace \ javax.management.relation \ javax.management.openmbean \ javax.management.timer \ diff --git a/make/java/java/FILES_java.gmk b/make/java/java/FILES_java.gmk index b4a07fc352f3ec59bef6222693f542b5d7942110..2531ce7230ce3ffb1573b2ab1ad3c29e1537ad81 100644 --- a/make/java/java/FILES_java.gmk +++ b/make/java/java/FILES_java.gmk @@ -449,6 +449,7 @@ JAVA_JAVA_java = \ sun/misc/JavaLangAccess.java \ sun/misc/JavaIOAccess.java \ sun/misc/JavaIODeleteOnExitAccess.java \ - sun/misc/JavaIOFileDescriptorAccess.java + sun/misc/JavaIOFileDescriptorAccess.java \ + sun/misc/JavaNioAccess.java FILES_java = $(JAVA_JAVA_java) diff --git a/make/java/java/mapfile-vers b/make/java/java/mapfile-vers index ad0380979a94984fccef0db39553da27bfb8d6ad..77a78301af721f9aca72358a1b4ae554bbf2bc49 100644 --- a/make/java/java/mapfile-vers +++ b/make/java/java/mapfile-vers @@ -222,8 +222,6 @@ SUNWprivate_1.1 { 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 --git a/make/java/jli/Makefile b/make/java/jli/Makefile index 5a1c312d7abb07298a283e6afc5257c38e5b70b7..7a0c53f1ce2f72caa677630e274ebe77fa0ef88e 100644 --- a/make/java/jli/Makefile +++ b/make/java/jli/Makefile @@ -113,7 +113,11 @@ ifeq ($(PLATFORM), windows) JAVALIB = OTHER_LCF = -export:JLI_Launch \ -export:JLI_ManifestIterate \ - -export:JLI_SetTraceLauncher + -export:JLI_SetTraceLauncher \ + -export:JLI_ReportErrorMessage \ + -export:JLI_ReportErrorMessageSys \ + -export:JLI_ReportMessage \ + -export:JLI_ReportExceptionDescription endif diff --git a/make/java/jli/mapfile-vers b/make/java/jli/mapfile-vers index a9e8198dea1e7b06a810053f26de00bf8bbf3ef1..e04e4f13db94dc582bb3a426b1b777be03fb747f 100644 --- a/make/java/jli/mapfile-vers +++ b/make/java/jli/mapfile-vers @@ -1,5 +1,5 @@ # -# Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2005-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 @@ -30,6 +30,10 @@ SUNWprivate_1.1 { JLI_Launch; JLI_ManifestIterate; JLI_SetTraceLauncher; + JLI_ReportErrorMessage; + JLI_ReportErrorMessageSys; + JLI_ReportMessage; + JLI_ReportExceptionDescription; local: *; }; diff --git a/make/java/net/mapfile-vers b/make/java/net/mapfile-vers index 86cb351c9f935c9a60bf540146d400328f7ac62e..e7da6186ecc9dbcc7056b18984663553b3d63c95 100644 --- a/make/java/net/mapfile-vers +++ b/make/java/net/mapfile-vers @@ -57,7 +57,7 @@ SUNWprivate_1.1 { Java_java_net_Inet6AddressImpl_isReachable0; Java_java_net_NetworkInterface_init; Java_java_net_NetworkInterface_getByName0; - Java_java_net_NetworkInterface_getByIndex; + Java_java_net_NetworkInterface_getByIndex0; Java_java_net_NetworkInterface_getByInetAddress0; Java_java_net_NetworkInterface_getAll; Java_java_net_NetworkInterface_isUp0; diff --git a/make/java/nio/FILES_java.gmk b/make/java/nio/FILES_java.gmk index 5958812adfb55160c41b3319254debce3320e52b..8a6177b0a0ba9c99ff85c03f856026b9f9be4d7d 100644 --- a/make/java/nio/FILES_java.gmk +++ b/make/java/nio/FILES_java.gmk @@ -26,6 +26,7 @@ FILES_src = \ java/nio/Bits.java \ java/nio/Buffer.java \ + java/nio/BufferPoolMXBean.java \ java/nio/ByteOrder.java \ java/nio/MappedByteBuffer.java \ java/nio/StringCharBuffer.java \ @@ -38,6 +39,9 @@ FILES_src = \ 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 \ @@ -72,6 +76,7 @@ FILES_src = \ 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 \ @@ -79,12 +84,14 @@ FILES_src = \ 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 \ @@ -98,8 +105,7 @@ FILES_src = \ 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 \ \ @@ -239,6 +245,7 @@ FILES_gen_ex = \ 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 \ @@ -257,14 +264,15 @@ FILES_gen_ex = \ 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 --git a/make/java/nio/Makefile b/make/java/nio/Makefile index cff9ce5ceb29648f2bc50564199cf18c009f59c4..26c2f2fc68d0218fc30fad31bbaa39959878b1d6 100644 --- a/make/java/nio/Makefile +++ b/make/java/nio/Makefile @@ -56,18 +56,18 @@ FILES_java += \ 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_java += \ 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 @@ $(BUF_GEN)/%Exception.java: genExceptions.sh $(BUF_SRC)/exceptions @$(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 @@ $(SCS_GEN)/StandardCharsets.java: genCharsetProvider.sh \ 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 --git a/make/java/nio/mapfile-linux b/make/java/nio/mapfile-linux index dc2044c9d7925ccbced446ad4654cebc307ddc79..3fb47b0eb7c0e42107f01113f529ee39b96726f9 100644 --- a/make/java/nio/mapfile-linux +++ b/make/java/nio/mapfile-linux @@ -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: @@ -18,6 +42,8 @@ SUNWprivate_1.1 { Java_sun_nio_ch_EPollArrayWrapper_fdLimit; Java_sun_nio_ch_EPollArrayWrapper_init; Java_sun_nio_ch_EPollArrayWrapper_interrupt; + Java_sun_nio_ch_EPollArrayWrapper_offsetofData; + Java_sun_nio_ch_EPollArrayWrapper_sizeofEPollEvent; Java_sun_nio_ch_FileChannelImpl_close0; Java_sun_nio_ch_FileChannelImpl_force0; Java_sun_nio_ch_FileChannelImpl_initIDs; @@ -59,20 +85,29 @@ SUNWprivate_1.1 { 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 --git a/make/java/nio/mapfile-solaris b/make/java/nio/mapfile-solaris index 77ef8ea2ad9083b9d1cc08411a70facd251fe6f4..6e109e2fabaf9be9aed350acf55ece2eb833265f 100644 --- a/make/java/nio/mapfile-solaris +++ b/make/java/nio/mapfile-solaris @@ -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 @@ SUNWprivate_1.1 { 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 --git a/make/java/verify/Makefile b/make/java/verify/Makefile index c647d5085693035387ecd17c4025a2fe4b215cb6..24bcc0f48d4aa17f70190b3b69c9997e610bd543 100644 --- a/make/java/verify/Makefile +++ b/make/java/verify/Makefile @@ -1,5 +1,5 @@ # -# Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1999-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 @@ -52,12 +52,6 @@ FILES_c = \ check_code.c \ check_format.c -# -# libverify.so needs these 2 header files (opcodes.h opcodes.length) -# from the VM. -# -CPPFLAGS += -I$(SHARE_SRC)/javavm/include - # # Targets. # diff --git a/make/jprt.properties b/make/jprt.properties index 06abef8c8e6a1bb4bf13b4d4b072f34a63a918b4..e6666cb1d6c5e528ca8d0b95a0387ef2b31171a4 100644 --- a/make/jprt.properties +++ b/make/jprt.properties @@ -55,6 +55,5 @@ jprt.solaris_x64.build.platform.match32=solaris_i586_5.10 jprt.test.targets=*-*-*-jvm98 # Directories needed to build -jprt.bundle.src.dirs=make src jprt.bundle.exclude.src.dirs=build diff --git a/make/mksample/nio/Makefile b/make/mksample/nio/Makefile index a6e8fc46d964f8d3ddd066164374ca867014bd17..1f17a4cce20ab844cb7fa0c29d3b3c50466f9c55 100644 --- a/make/mksample/nio/Makefile +++ b/make/mksample/nio/Makefile @@ -31,7 +31,7 @@ BUILDDIR = ../.. PRODUCT = java include $(BUILDDIR)/common/Defs.gmk -SUBDIRS = server +SUBDIRS = multicast server all build clean clobber:: $(SUBDIRS-loop) diff --git a/src/share/classes/sun/nio/ch/exceptions b/make/mksample/nio/multicast/Makefile similarity index 65% rename from src/share/classes/sun/nio/ch/exceptions rename to make/mksample/nio/multicast/Makefile index 55d295f871d4c5b03273f102d2c7d9188c975916..05a153a13150cef106a6ec44498f12f4e059b1db 100644 --- a/src/share/classes/sun/nio/ch/exceptions +++ b/make/mksample/nio/multicast/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved. +# 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 @@ -23,17 +23,30 @@ # have any questions. # -# Generated exception classes for sun.nio.ch +# +# 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 -SINCE=1.4 -PACKAGE=sun.nio.ch -# This year should only change if the generated source is modified. -COPYRIGHT_YEARS=2000-2007 +all build: $(SAMPLE_FILES) +$(SAMPLE_DST_DIR)/%: $(SAMPLE_SRC_DIR)/% + $(install-file) -SUPER=IllegalStateException +clean clobber: + $(RM) -r $(SAMPLE_DST_DIR) -gen AlreadyBoundException " - * Unchecked exception thrown when an attempt is made to bind a {@link - * SocketChannel} that is already bound." \ - 9002280723481772026L +.PHONY: all build clean clobber diff --git a/make/netbeans/awt2d/README b/make/netbeans/awt2d/README index a990726b787c7d8b9d1aa1ad3c7b1c8275425d27..040c9e76919d4ad76f903542cf6a7e1905c3a091 100644 --- a/make/netbeans/awt2d/README +++ b/make/netbeans/awt2d/README @@ -145,7 +145,6 @@ Notes on using CND (C/C++ pack) with this project and NetBeans. (a somewhat complete list of awt and 2d native directories on windows): ../../src/share/javavm/export; - ../../src/share/javavm/include; ../../src/share/native/common; ../../src/share/native/sun/awt/debug; ../../src/share/native/sun/awt/image/cvutils; diff --git a/make/sun/net/spi/Makefile b/make/sun/net/spi/Makefile index 20583bc4eb73ef7018a4800c7f4e4f85acabc2cf..f969b87992acf8228384a1386ad924abb94b3b81 100644 --- a/make/sun/net/spi/Makefile +++ b/make/sun/net/spi/Makefile @@ -23,10 +23,6 @@ # have any questions. # -# -# Makefile for building com/sun -# - BUILDDIR = ../../.. include $(BUILDDIR)/common/Defs.gmk diff --git a/make/sun/net/spi/nameservice/Makefile b/make/sun/net/spi/nameservice/Makefile index b6593c71d559b5160360493991d1708244ba387b..b0ff374de3d09be753c34964cf9d298fd9ffb8f2 100644 --- a/make/sun/net/spi/nameservice/Makefile +++ b/make/sun/net/spi/nameservice/Makefile @@ -23,10 +23,6 @@ # have any questions. # -# -# Makefile for building com/sun -# - BUILDDIR = ../../../.. include $(BUILDDIR)/common/Defs.gmk diff --git a/make/sun/net/spi/nameservice/dns/Makefile b/make/sun/net/spi/nameservice/dns/Makefile index a882eada97a423cee91478836fa7057eff15e1d4..daf35125d110223c05b67a36c7bdc616b07de137 100644 --- a/make/sun/net/spi/nameservice/dns/Makefile +++ b/make/sun/net/spi/nameservice/dns/Makefile @@ -24,7 +24,7 @@ # # -# Makefile for building JNDI service provider toolkit +# Makefile for building JNDI DNS name service provider # BUILDDIR = ../../../../.. diff --git a/make/tools/GenerateCharacter/check_class.c.template b/make/tools/GenerateCharacter/check_class.c.template index d9a880f09707a7e6a8376aed94dd036367a1698c..02307e02a6beed7efab207038488a3bd48af814c 100644 --- a/make/tools/GenerateCharacter/check_class.c.template +++ b/make/tools/GenerateCharacter/check_class.c.template @@ -1,5 +1,5 @@ /* - * Copyright 2002 Sun Microsystems, Inc. All Rights Reserved. + * 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 @@ -37,7 +37,6 @@ #include "bool.h" #include "utf.h" #include "tree.h" -#include "sys_api.h" extern bool_t verify_class_codes(ClassClass *cb); diff --git a/src/share/back/debugDispatch.c b/src/share/back/debugDispatch.c index 98a86fe588956e54b85244f852979091a79311ab..fa633799061d4db55119980f9b8890cfa2b5f47d 100644 --- a/src/share/back/debugDispatch.c +++ b/src/share/back/debugDispatch.c @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-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 @@ -41,7 +41,6 @@ #include "ArrayReferenceImpl.h" #include "EventRequestImpl.h" #include "StackFrameImpl.h" -#include "typedefs.h" static void **l1Array; diff --git a/src/share/back/error_messages.c b/src/share/back/error_messages.c index f40af69a335682f7779e8ccd92b96af89a44777d..30acacd4ef27966a80fa81da4670c993b5c593d3 100644 --- a/src/share/back/error_messages.c +++ b/src/share/back/error_messages.c @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-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 @@ -48,7 +48,6 @@ #include "util.h" #include "proc_md.h" -#include "typedefs.h" /* Maximim length of a message */ #define MAX_MESSAGE_LEN MAXPATHLEN*2+512 diff --git a/src/share/back/inStream.c b/src/share/back/inStream.c index 45534fcdc546d4ccbe82e16db1712cff79ac84c5..1f5b685c5adf5cca5d6a762df2dff9353f52b332 100644 --- a/src/share/back/inStream.c +++ b/src/share/back/inStream.c @@ -1,5 +1,5 @@ /* - * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-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 @@ -30,7 +30,6 @@ #include "bag.h" #include "commonRef.h" #include "FrameID.h" -#include "typedefs.h" #define INITIAL_REF_ALLOC 50 #define SMALLEST(a, b) ((a) < (b)) ? (a) : (b) diff --git a/src/share/back/outStream.h b/src/share/back/outStream.h index a57cc47115175140f8bc2708e3ff8b6482a224c2..83d1eb10ffebdc4bfcf71373471ac131de118033 100644 --- a/src/share/back/outStream.h +++ b/src/share/back/outStream.h @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-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 @@ -26,8 +26,6 @@ #ifndef JDWP_OUTSTREAM_H #define JDWP_OUTSTREAM_H -#include "typedefs.h" - #include "transport.h" #include "FrameID.h" diff --git a/src/share/bin/emessages.h b/src/share/bin/emessages.h index 03824bba5d1570138953afcd333d194c5257f263..008cc1f906a6e93cb7894c92ae9bbba7d8b7c3e0 100644 --- a/src/share/bin/emessages.h +++ b/src/share/bin/emessages.h @@ -25,8 +25,8 @@ /* * This file primarily consists of all the error and warning messages, that - * are used in ReportErrorMessage. All message must be defined here, in order - * to help in I18N/L10N the messages. + * are used in JLI_ReportErrorMessage. All message must be defined here, in + * order to help with localizing the messages. */ #ifndef _EMESSAGES_H diff --git a/src/share/bin/java.c b/src/share/bin/java.c index f7cbcdc95bce46ab467dd1af347b882dd9ac5c95..89ae857b1366baadcd4ee0ba7c82b818b59e0db0 100644 --- a/src/share/bin/java.c +++ b/src/share/bin/java.c @@ -148,7 +148,7 @@ static void ShowSplashScreen(); static jboolean IsWildCardEnabled(); #define ARG_CHECK(n, f, a) if (n < 1) { \ - ReportErrorMessage(f, a); \ + JLI_ReportErrorMessage(f, a); \ printUsage = JNI_TRUE; \ *pret = 1; \ return JNI_TRUE; \ @@ -326,15 +326,15 @@ JavaMain(void * _args) start = CounterGet(); if (!InitializeJVM(&vm, &env, &ifn)) { - ReportErrorMessage(JVM_ERROR1); + JLI_ReportErrorMessage(JVM_ERROR1); exit(1); } if (printVersion || showVersion) { PrintJavaVersion(env, showVersion); if ((*env)->ExceptionOccurred(env)) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); goto leave; } if (printVersion) { @@ -347,8 +347,8 @@ JavaMain(void * _args) if (printXUsage || printUsage || (jarfile == 0 && classname == 0)) { PrintUsage(env, printXUsage); if ((*env)->ExceptionOccurred(env)) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); ret=1; } goto leave; @@ -397,43 +397,43 @@ JavaMain(void * _args) if (jarfile != 0) { mainClassName = GetMainClassName(env, jarfile); if ((*env)->ExceptionOccurred(env)) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); goto leave; } if (mainClassName == NULL) { - ReportErrorMessage(JAR_ERROR1,jarfile, GEN_ERROR); + JLI_ReportErrorMessage(JAR_ERROR1,jarfile, GEN_ERROR); goto leave; } classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); if (classname == NULL) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); goto leave; } mainClass = LoadClass(env, classname); if(mainClass == NULL) { /* exception occured */ - ReportExceptionDescription(env); - ReportErrorMessage(CLS_ERROR1, classname); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(CLS_ERROR1, classname); goto leave; } (*env)->ReleaseStringUTFChars(env, mainClassName, classname); } else { mainClassName = NewPlatformString(env, classname); if (mainClassName == NULL) { - ReportErrorMessage(CLS_ERROR2, classname, GEN_ERROR); + JLI_ReportErrorMessage(CLS_ERROR2, classname, GEN_ERROR); goto leave; } classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); if (classname == NULL) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); goto leave; } mainClass = LoadClass(env, classname); if(mainClass == NULL) { /* exception occured */ - ReportExceptionDescription(env); - ReportErrorMessage(CLS_ERROR1, classname); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(CLS_ERROR1, classname); goto leave; } (*env)->ReleaseStringUTFChars(env, mainClassName, classname); @@ -444,10 +444,10 @@ JavaMain(void * _args) "([Ljava/lang/String;)V"); if (mainID == NULL) { if ((*env)->ExceptionOccurred(env)) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); } else { - ReportErrorMessage(CLS_ERROR3); + JLI_ReportErrorMessage(CLS_ERROR3); } goto leave; } @@ -459,8 +459,8 @@ JavaMain(void * _args) mainID, JNI_TRUE); if( obj == NULL) { /* exception occurred */ - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); goto leave; } @@ -469,14 +469,14 @@ JavaMain(void * _args) (*env)->GetObjectClass(env, obj), "getModifiers", "()I"); if ((*env)->ExceptionOccurred(env)) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); goto leave; } mods = (*env)->CallIntMethod(env, obj, mid); if ((mods & 1) == 0) { /* if (!Modifier.isPublic(mods)) ... */ - ReportErrorMessage(CLS_ERROR4); + JLI_ReportErrorMessage(CLS_ERROR4); goto leave; } } @@ -484,8 +484,8 @@ JavaMain(void * _args) /* Build argument array */ mainArgs = NewPlatformStringArray(env, argv, argc); if (mainArgs == NULL) { - ReportExceptionDescription(env); - ReportErrorMessage(JNI_ERROR); + JLI_ReportExceptionDescription(env); + JLI_ReportErrorMessage(JNI_ERROR); goto leave; } @@ -506,7 +506,7 @@ JavaMain(void * _args) * launcher's return code except by calling System.exit. */ if ((*vm)->DetachCurrentThread(vm) != 0) { - ReportErrorMessage(JVM_ERROR2); + JLI_ReportErrorMessage(JVM_ERROR2); ret = 1; goto leave; } @@ -635,7 +635,7 @@ CheckJvmType(int *pargc, char ***argv, jboolean speculative) { if (loopCount > knownVMsCount) { if (!speculative) { - ReportErrorMessage(CFG_ERROR1); + JLI_ReportErrorMessage(CFG_ERROR1); exit(1); } else { return "ERROR"; @@ -645,7 +645,7 @@ CheckJvmType(int *pargc, char ***argv, jboolean speculative) { if (nextIdx < 0) { if (!speculative) { - ReportErrorMessage(CFG_ERROR2, knownVMs[jvmidx].alias); + JLI_ReportErrorMessage(CFG_ERROR2, knownVMs[jvmidx].alias); exit(1); } else { return "ERROR"; @@ -660,7 +660,7 @@ CheckJvmType(int *pargc, char ***argv, jboolean speculative) { switch (knownVMs[jvmidx].flag) { case VM_WARN: if (!speculative) { - ReportErrorMessage(CFG_WARN1, jvmtype, knownVMs[0].name + 1); + JLI_ReportErrorMessage(CFG_WARN1, jvmtype, knownVMs[0].name + 1); } /* fall through */ case VM_IGNORE: @@ -670,7 +670,7 @@ CheckJvmType(int *pargc, char ***argv, jboolean speculative) { break; case VM_ERROR: if (!speculative) { - ReportErrorMessage(CFG_ERROR3, jvmtype); + JLI_ReportErrorMessage(CFG_ERROR3, jvmtype); exit(1); } else { return "ERROR"; @@ -879,9 +879,9 @@ SelectVersion(int argc, char **argv, char **main_class) if (jarflag && operand) { if ((res = JLI_ParseManifest(operand, &info)) != 0) { if (res == -1) - ReportErrorMessage(JAR_ERROR2, operand); + JLI_ReportErrorMessage(JAR_ERROR2, operand); else - ReportErrorMessage(JAR_ERROR3, operand); + JLI_ReportErrorMessage(JAR_ERROR3, operand); exit(1); } @@ -948,7 +948,7 @@ SelectVersion(int argc, char **argv, char **main_class) * Check for correct syntax of the version specification (JSR 56). */ if (!JLI_ValidVersionString(info.jre_version)) { - ReportErrorMessage(SPC_ERROR1, info.jre_version); + JLI_ReportErrorMessage(SPC_ERROR1, info.jre_version); exit(1); } @@ -970,7 +970,7 @@ SelectVersion(int argc, char **argv, char **main_class) JLI_MemFree(new_argv); return; } else { - ReportErrorMessage(CFG_ERROR4, info.jre_version); + JLI_ReportErrorMessage(CFG_ERROR4, info.jre_version); exit(1); } } @@ -1040,7 +1040,7 @@ ParseArguments(int *pargc, char ***pargv, char **pjarfile, * command line options. */ } else if (JLI_StrCmp(arg, "-fullversion") == 0) { - ReportMessage("%s full version \"%s\"", _launcher_name, GetFullVersion()); + JLI_ReportMessage("%s full version \"%s\"", _launcher_name, GetFullVersion()); return JNI_FALSE; } else if (JLI_StrCmp(arg, "-verbosegc") == 0) { AddOption("-verbose:gc", NULL); @@ -1080,7 +1080,7 @@ ParseArguments(int *pargc, char ***pargv, char **pjarfile, JLI_StrCmp(arg, "-cs") == 0 || JLI_StrCmp(arg, "-noasyncgc") == 0) { /* No longer supported */ - ReportErrorMessage(ARG_WARN, arg); + JLI_ReportErrorMessage(ARG_WARN, arg); } else if (JLI_StrCCmp(arg, "-version:") == 0 || JLI_StrCmp(arg, "-no-jre-restrict-search") == 0 || JLI_StrCmp(arg, "-jre-restrict-search") == 0 || @@ -1143,12 +1143,12 @@ InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn) #define NULL_CHECK0(e) if ((e) == 0) { \ - ReportErrorMessage(JNI_ERROR); \ + JLI_ReportErrorMessage(JNI_ERROR); \ return 0; \ } #define NULL_CHECK(e) if ((e) == 0) { \ - ReportErrorMessage(JNI_ERROR); \ + JLI_ReportErrorMessage(JNI_ERROR); \ return; \ } @@ -1351,7 +1351,7 @@ TranslateApplicationArgs(int jargc, const char **jargv, int *pargc, char ***parg char *arg = argv[i]; if (arg[0] == '-' && arg[1] == 'J') { if (arg[2] == '\0') { - ReportErrorMessage(ARG_ERROR3); + JLI_ReportErrorMessage(ARG_ERROR3); exit(1); } *nargv++ = arg + 2; @@ -1418,7 +1418,7 @@ AddApplicationOptions(int cpathc, const char **cpathv) } if (!GetApplicationHome(home, sizeof(home))) { - ReportErrorMessage(CFG_ERROR5); + JLI_ReportErrorMessage(CFG_ERROR5); return JNI_FALSE; } @@ -1691,7 +1691,7 @@ ReadKnownVMs(const char *jrepath, const char * arch, jboolean speculative) jvmCfg = fopen(jvmCfgName, "r"); if (jvmCfg == NULL) { if (!speculative) { - ReportErrorMessage(CFG_ERROR6, jvmCfgName); + JLI_ReportErrorMessage(CFG_ERROR6, jvmCfgName); exit(1); } else { return -1; @@ -1703,7 +1703,7 @@ ReadKnownVMs(const char *jrepath, const char * arch, jboolean speculative) if (line[0] == '#') continue; if (line[0] != '-') { - ReportErrorMessage(CFG_WARN2, lineno, jvmCfgName); + JLI_ReportErrorMessage(CFG_WARN2, lineno, jvmCfgName); } if (cnt >= knownVMsLimit) { GrowKnownVMs(cnt); @@ -1711,13 +1711,13 @@ ReadKnownVMs(const char *jrepath, const char * arch, jboolean speculative) line[JLI_StrLen(line)-1] = '\0'; /* remove trailing newline */ tmpPtr = line + JLI_StrCSpn(line, whiteSpace); if (*tmpPtr == 0) { - ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName); + JLI_ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName); } else { /* Null-terminate this string for JLI_StringDup below */ *tmpPtr++ = 0; tmpPtr += JLI_StrSpn(tmpPtr, whiteSpace); if (*tmpPtr == 0) { - ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName); + JLI_ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName); } else { if (!JLI_StrCCmp(tmpPtr, "KNOWN")) { vmType = VM_KNOWN; @@ -1727,7 +1727,7 @@ ReadKnownVMs(const char *jrepath, const char * arch, jboolean speculative) tmpPtr += JLI_StrSpn(tmpPtr, whiteSpace); } if (*tmpPtr == 0) { - ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName); + JLI_ReportErrorMessage(CFG_WARN3, lineno, jvmCfgName); } else { /* Null terminate altVMName */ altVMName = tmpPtr; @@ -1747,7 +1747,7 @@ ReadKnownVMs(const char *jrepath, const char * arch, jboolean speculative) tmpPtr += JLI_StrSpn(tmpPtr, whiteSpace); } if (*tmpPtr == 0) { - ReportErrorMessage(CFG_WARN4, lineno, jvmCfgName); + JLI_ReportErrorMessage(CFG_WARN4, lineno, jvmCfgName); } else { /* Null terminate server class VM name */ serverClassVMName = tmpPtr; @@ -1756,7 +1756,7 @@ ReadKnownVMs(const char *jrepath, const char * arch, jboolean speculative) vmType = VM_IF_SERVER_CLASS; } } else { - ReportErrorMessage(CFG_WARN5, lineno, &jvmCfgName[0]); + JLI_ReportErrorMessage(CFG_WARN5, lineno, &jvmCfgName[0]); vmType = VM_KNOWN; } } @@ -2019,7 +2019,7 @@ RemovableOption(char * option) * A utility procedure to always print to stderr */ void -ReportMessage(const char* fmt, ...) +JLI_ReportMessage(const char* fmt, ...) { va_list vl; va_start(vl, fmt); diff --git a/src/share/bin/java.h b/src/share/bin/java.h index e6a08f3cf009b00ea68a6282164d4e5585745ec0..23871b5d2a1a045285a52da918417349e846935a 100644 --- a/src/share/bin/java.h +++ b/src/share/bin/java.h @@ -121,24 +121,20 @@ void CreateExecutionEnvironment(int *_argc, char jvmpath[], jint so_jvmpath, char **original_argv); +/* Reports an error message to stderr or a window as appropriate. */ +void JLI_ReportErrorMessage(const char * message, ...); -/* - * Report an error message to stderr or a window as appropriate. - */ -void ReportErrorMessage(const char * message, ...); -void ReportErrorMessageSys(const char * format, ...); +/* Reports a system error message to stderr or a window */ +void JLI_ReportErrorMessageSys(const char * message, ...); -/* - * Report an error message only to stderr. - */ -void ReportMessage(const char * message, ...); +/* Reports an error message only to stderr. */ +void JLI_ReportMessage(const char * message, ...); /* - * Report an exception which terminates the vm to stderr or a window + * Reports an exception which terminates the vm to stderr or a window * as appropriate. */ -void ReportExceptionDescription(JNIEnv * env); - +void JLI_ReportExceptionDescription(JNIEnv * env); void PrintMachineDependentOptions(); const char *jlong_format_specifier(); diff --git a/src/share/classes/com/sun/jmx/defaults/JmxProperties.java b/src/share/classes/com/sun/jmx/defaults/JmxProperties.java index 89cd5bf16bf0c814cc1bc4e70134fe070db5e99a..b4bbbb78d49aff6ba1ae07daf04006033d53d7d8 100644 --- a/src/share/classes/com/sun/jmx/defaults/JmxProperties.java +++ b/src/share/classes/com/sun/jmx/defaults/JmxProperties.java @@ -176,6 +176,18 @@ public class JmxProperties { public static final String RELATION_LOGGER_NAME = "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. */ diff --git a/src/share/classes/com/sun/jmx/event/LeaseManager.java b/src/share/classes/com/sun/jmx/event/LeaseManager.java index cb1b88bf514919d30f0065f4bd52e1299f3033ed..33409a06ce93e22f932a96ccd60e9835ab709a87 100644 --- a/src/share/classes/com/sun/jmx/event/LeaseManager.java +++ b/src/share/classes/com/sun/jmx/event/LeaseManager.java @@ -27,7 +27,6 @@ package com.sun.jmx.event; import com.sun.jmx.remote.util.ClassLogger; import java.util.concurrent.Executors; -import java.util.concurrent.FutureTask; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -115,6 +114,7 @@ public class LeaseManager { scheduled = null; } callback.run(); + executor.shutdown(); } } @@ -131,6 +131,13 @@ public class LeaseManager { logger.trace("stop", "canceling lease"); scheduled.cancel(false); scheduled = null; + try { + executor.shutdown(); + } catch (SecurityException e) { + // OK: caller doesn't have RuntimePermission("modifyThread") + // which is unlikely in reality but triggers a test failure otherwise + logger.trace("stop", "exception from executor.shutdown", e); + } } private final Runnable callback; @@ -138,7 +145,7 @@ public class LeaseManager { private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1, - new DaemonThreadFactory("LeaseManager")); + new DaemonThreadFactory("JMX LeaseManager %d")); private static final ClassLogger logger = new ClassLogger("javax.management.event", "LeaseManager"); diff --git a/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java b/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java index 7de1b40e92d4f41ebfb2fe1ffb77428d6fb6f6ad..2fe4a3a152b8f54fa3557944cfdcc24a7b52f3de 100644 --- a/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java +++ b/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java @@ -95,7 +95,9 @@ public abstract class RepeatedSingletonJob implements Runnable { executor.execute(this); } catch (RejectedExecutionException e) { logger.warning( - "setEventReceiver", "Executor threw exception", e); + "execute", + "Executor threw exception (" + this.getClass().getName() + ")", + e); throw new RejectedExecutionException( "Executor.execute threw exception -" + "should not be possible", e); diff --git a/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java b/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java index 8bd6cba27ce4e676c75e5f9eafb7d408f2b536cb..7da3406b911e0a06c681c3afe6b61d55487258ba 100644 --- a/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java +++ b/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java @@ -25,33 +25,49 @@ package com.sun.jmx.interceptor; -// java import + +// 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.util.ArrayList; +import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; -import java.util.logging.Level; +import java.util.Queue; import java.util.Set; -import java.util.HashSet; import java.util.WeakHashMap; -import java.lang.ref.WeakReference; -import java.security.AccessControlContext; -import java.security.Permission; -import java.security.ProtectionDomain; -import java.security.AccessController; -import java.security.PrivilegedAction; +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.MBeanTrustPermission; 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.ReflectionException; 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 @@ import javax.management.NotificationBroadcasterSupport; * * @since 1.5 */ -public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { +public class DefaultMBeanServerInterceptor + extends MBeanServerInterceptorSupport { /** The MBeanInstantiator object used by the * DefaultMBeanServerInterceptor */ @@ -123,7 +126,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { * 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 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { new WeakHashMap>(); + private final NamespaceDispatchInterceptor dispatcher; + /** The default domain of the object names */ private final String domain; - /** True if the repository perform queries, false otherwise */ - private boolean queryByRepo; + /** The mbeanServerName */ + private final String mbeanServerName; - /** The sequence number identifyng the notifications sent */ + /** The sequence number identifying the notifications sent */ // Now sequence number is handled by MBeanServerDelegate. // private int sequenceNumber=0; @@ -162,11 +167,13 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { * @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. + * @param dispatcher The dispatcher used by this MBeanServer */ public DefaultMBeanServerInterceptor(MBeanServer outer, MBeanServerDelegate delegate, MBeanInstantiator instantiator, - Repository repository) { + Repository repository, + NamespaceDispatchInterceptor dispatcher) { if (outer == null) throw new IllegalArgumentException("outer MBeanServer cannot be null"); if (delegate == null) throw new @@ -181,6 +188,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { this.instantiator = instantiator; this.repository = repository; this.domain = repository.getDefaultDomain(); + this.dispatcher = dispatcher; + this.mbeanServerName = Util.getMBeanServerSecurityName(delegate); } public ObjectInstance createMBean(String className, ObjectName name) @@ -259,8 +268,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { name = nonDefaultDomain(name); } - checkMBeanPermission(className, null, null, "instantiate"); - checkMBeanPermission(className, null, name, "registerMBean"); + checkMBeanPermission(mbeanServerName,className, null, null, "instantiate"); + checkMBeanPermission(mbeanServerName,className, null, name, "registerMBean"); /* Load the appropriate class. */ if (withDefaultLoaderRepository) { @@ -324,7 +333,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { final String infoClassName = getNewMBeanClassName(object); - checkMBeanPermission(infoClassName, null, name, "registerMBean"); + checkMBeanPermission(mbeanServerName,infoClassName, null, name, "registerMBean"); checkMBeanTrustPermission(theClass); return registerObject(infoClassName, object, name); @@ -433,7 +442,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { DynamicMBean instance = getMBean(name); // may throw InstanceNotFoundException - checkMBeanPermission(instance, null, name, "unregisterMBean"); + checkMBeanPermission(mbeanServerName, instance, null, name, + "unregisterMBean"); if (instance instanceof MBeanRegistration) preDeregisterInvoke((MBeanRegistration) instance); @@ -467,7 +477,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { name = nonDefaultDomain(name); DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, null, name, "getObjectInstance"); + checkMBeanPermission(mbeanServerName, + instance, null, name, "getObjectInstance"); final String className = getClassName(instance); @@ -479,7 +490,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { if (sm != null) { // Check if the caller has the right to invoke 'queryMBeans' // - checkMBeanPermission((String) null, null, null, "queryMBeans"); + checkMBeanPermission(mbeanServerName,(String) null, null, null, "queryMBeans"); // Perform query without "query". // @@ -492,7 +503,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { new HashSet(list.size()); for (ObjectInstance oi : list) { try { - checkMBeanPermission(oi.getClassName(), null, + checkMBeanPermission(mbeanServerName,oi.getClassName(), null, oi.getObjectName(), "queryMBeans"); allowedList.add(oi); } catch (SecurityException e) { @@ -516,11 +527,6 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { // Set list = repository.query(name, query); - if (queryByRepo) { - // The repository performs the filtering - query = null; - } - return (objectInstancesFromFilteredNamedObjects(list, query)); } @@ -530,7 +536,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { if (sm != null) { // Check if the caller has the right to invoke 'queryNames' // - checkMBeanPermission((String) null, null, null, "queryNames"); + checkMBeanPermission(mbeanServerName,(String) null, null, null, "queryNames"); // Perform query without "query". // @@ -543,7 +549,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { new HashSet(list.size()); for (ObjectInstance oi : list) { try { - checkMBeanPermission(oi.getClassName(), null, + checkMBeanPermission(mbeanServerName, oi.getClassName(), null, oi.getObjectName(), "queryNames"); allowedList.add(oi); } catch (SecurityException e) { @@ -572,11 +578,6 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { // Set list = repository.query(name, query); - if (queryByRepo) { - // The repository performs the filtering - query = null; - } - return (objectNamesFromFilteredNamedObjects(list, query)); } @@ -589,8 +590,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { name = nonDefaultDomain(name); -// /* Permission check */ -// checkMBeanPermission(null, null, name, "isRegistered"); + /* No Permission check */ + // isRegistered is always unchecked as per JMX spec. return (repository.contains(name)); } @@ -600,7 +601,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { if (sm != null) { // Check if the caller has the right to invoke 'getDomains' // - checkMBeanPermission((String) null, null, null, "getDomains"); + checkMBeanPermission(mbeanServerName, (String) null, null, null, "getDomains"); // Return domains // @@ -612,8 +613,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { List result = new ArrayList(domains.length); for (int i = 0; i < domains.length; i++) { try { - ObjectName domain = Util.newObjectName(domains[i] + ":x=x"); - checkMBeanPermission((String) null, null, domain, "getDomains"); + ObjectName dom = ObjectName.valueOf(domains[i] + ":x=x"); + checkMBeanPermission(mbeanServerName, (String) null, null, dom, "getDomains"); result.add(domains[i]); } catch (SecurityException e) { // OK: Do not add this domain to the list @@ -657,7 +658,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { } final DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, attribute, name, "getAttribute"); + checkMBeanPermission(mbeanServerName, instance, attribute, + name, "getAttribute"); try { return instance.getAttribute(attribute); @@ -702,7 +704,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { // Check if the caller has the right to invoke 'getAttribute' // - checkMBeanPermission(classname, null, name, "getAttribute"); + checkMBeanPermission(mbeanServerName, classname, null, name, "getAttribute"); // Check if the caller has the right to invoke 'getAttribute' // on each specific attribute @@ -711,14 +713,15 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { new ArrayList(attributes.length); for (String attr : attributes) { try { - checkMBeanPermission(classname, attr, + checkMBeanPermission(mbeanServerName, classname, attr, name, "getAttribute"); allowedList.add(attr); } catch (SecurityException e) { // OK: Do not add this attribute to the list } } - allowedAttributes = allowedList.toArray(new String[0]); + allowedAttributes = + allowedList.toArray(new String[allowedList.size()]); } try { @@ -756,7 +759,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { } DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, attribute.getName(), + checkMBeanPermission(mbeanServerName, instance, attribute.getName(), name, "setAttribute"); try { @@ -799,7 +802,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { // Check if the caller has the right to invoke 'setAttribute' // - checkMBeanPermission(classname, null, name, "setAttribute"); + checkMBeanPermission(mbeanServerName, classname, null, name, "setAttribute"); // Check if the caller has the right to invoke 'setAttribute' // on each specific attribute @@ -808,7 +811,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { for (Iterator i = attributes.iterator(); i.hasNext();) { try { Attribute attribute = (Attribute) i.next(); - checkMBeanPermission(classname, attribute.getName(), + checkMBeanPermission(mbeanServerName, classname, attribute.getName(), name, "setAttribute"); allowedAttributes.add(attribute); } catch (SecurityException e) { @@ -832,7 +835,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { name = nonDefaultDomain(name); DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, operationName, name, "invoke"); + checkMBeanPermission(mbeanServerName, instance, operationName, + name, "invoke"); try { return instance.invoke(operationName, params, signature); } catch (Throwable t) { @@ -934,8 +938,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { "registerMBean", "ObjectName = " + name); } - ObjectName logicalName = name; - logicalName = preRegister(mbean, server, name); + ObjectName logicalName = preRegister(mbean, server, name); // preRegister returned successfully, so from this point on we // must call postRegister(false) if there is any problem. @@ -961,16 +964,17 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { if (logicalName != name && logicalName != null) { logicalName = - ObjectName.getInstance(nonDefaultDomain(logicalName)); + ObjectName.getInstance(nonDefaultDomain(logicalName)); } - checkMBeanPermission(classname, null, logicalName, "registerMBean"); + checkMBeanPermission(mbeanServerName, classname, null, logicalName, + "registerMBean"); if (logicalName == null) { final RuntimeException wrapped = - new IllegalArgumentException("No object name specified"); + new IllegalArgumentException("No object name specified"); throw new RuntimeOperationsException(wrapped, - "Exception occurred trying to register the MBean"); + "Exception occurred trying to register the MBean"); } final Object resource = getResource(mbean); @@ -987,13 +991,15 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { // context = registerWithRepository(resource, mbean, logicalName); + registerFailed = false; registered = true; + } finally { try { postRegister(logicalName, mbean, registered, registerFailed); } finally { - if (registered) context.done(); + if (registered && context!=null) context.done(); } } return new ObjectInstance(logicalName, classname); @@ -1001,20 +1007,19 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { private static void throwMBeanRegistrationException(Throwable t, String where) throws MBeanRegistrationException { - try { - throw t; - } catch (RuntimeException e) { - throw new RuntimeMBeanException( - e, "RuntimeException thrown " + where); - } catch (Error er) { - throw new RuntimeErrorException(er, "Error thrown " + where); - } catch (MBeanRegistrationException r) { - throw r; - } catch (Exception ex) { - throw new MBeanRegistrationException(ex, "Exception thrown " + where); - } catch (Throwable t1) { - throw new RuntimeException(t); // neither Error nor Exception?? - } + if (t instanceof RuntimeException) { + throw new RuntimeMBeanException((RuntimeException)t, + "RuntimeException thrown " + where); + } else if (t instanceof Error) { + throw new RuntimeErrorException((Error)t, + "Error thrown " + where); + } else if (t instanceof MBeanRegistrationException) { + throw (MBeanRegistrationException)t; + } else if (t instanceof Exception) { + throw new MBeanRegistrationException((Exception)t, + "Exception thrown " + where); + } else // neither Error nor Exception?? + throw new RuntimeException(t); } private static ObjectName preRegister( @@ -1164,7 +1169,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { if one is supplied where it shouldn't be). */ final String completeName = domain + name; - return Util.newObjectName(completeName); + return ObjectName.valueOf(completeName); } public String getDefaultDomain() { @@ -1230,7 +1235,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { } DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, null, name, "addNotificationListener"); + checkMBeanPermission(mbeanServerName, instance, null, + name, "addNotificationListener"); NotificationBroadcaster broadcaster = getNotificationBroadcaster(name, instance, @@ -1367,7 +1373,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { } DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, null, name, + checkMBeanPermission(mbeanServerName, instance, null, name, "removeNotificationListener"); /* We could simplify the code by assigning broadcaster after @@ -1438,7 +1444,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { throw new JMRuntimeException("MBean " + name + "has no MBeanInfo"); - checkMBeanPermission(mbi.getClassName(), null, name, "getMBeanInfo"); + checkMBeanPermission(mbeanServerName, mbi.getClassName(), null, name, "getMBeanInfo"); return mbi; } @@ -1446,8 +1452,9 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { public boolean isInstanceOf(ObjectName name, String className) throws InstanceNotFoundException { - DynamicMBean instance = getMBean(name); - checkMBeanPermission(instance, null, name, "isInstanceOf"); + final DynamicMBean instance = getMBean(name); + checkMBeanPermission(mbeanServerName, + instance, null, name, "isInstanceOf"); try { Object resource = getResource(instance); @@ -1498,7 +1505,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { throws InstanceNotFoundException { DynamicMBean instance = getMBean(mbeanName); - checkMBeanPermission(instance, null, mbeanName, "getClassLoaderFor"); + checkMBeanPermission(mbeanServerName, instance, null, mbeanName, + "getClassLoaderFor"); return getResourceLoader(instance); } @@ -1513,12 +1521,13 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { throws InstanceNotFoundException { if (loaderName == null) { - checkMBeanPermission((String) null, null, null, "getClassLoader"); + checkMBeanPermission(mbeanServerName, (String) null, null, null, "getClassLoader"); return server.getClass().getClassLoader(); } DynamicMBean instance = getMBean(loaderName); - checkMBeanPermission(instance, null, loaderName, "getClassLoader"); + checkMBeanPermission(mbeanServerName, instance, null, loaderName, + "getClassLoader"); Object resource = getResource(instance); @@ -1568,7 +1577,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { } } else { // Access the filter - MBeanServer oldServer = QueryEval.getMBeanServer(); + final MBeanServer oldServer = QueryEval.getMBeanServer(); query.setMBeanServer(server); try { for (NamedObject no : list) { @@ -1817,26 +1826,30 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { return mbean.getMBeanInfo().getClassName(); } - private static void checkMBeanPermission(DynamicMBean mbean, + private static void checkMBeanPermission(String mbeanServerName, + DynamicMBean mbean, String member, ObjectName objectName, String actions) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - checkMBeanPermission(safeGetClassName(mbean), + checkMBeanPermission(mbeanServerName, + safeGetClassName(mbean), member, objectName, actions); } } - private static void checkMBeanPermission(String classname, + private static void checkMBeanPermission(String mbeanServerName, + String classname, String member, ObjectName objectName, String actions) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - Permission perm = new MBeanPermission(classname, + Permission perm = new MBeanPermission(mbeanServerName, + classname, member, objectName, actions); @@ -1902,6 +1915,12 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { throws InstanceAlreadyExistsException, MBeanRegistrationException { + // this will throw an exception if the pair (resource, logicalName) + // violates namespace conventions - for instance, if logicalName + // ends with // but resource is not a JMXNamespace. + // + checkResourceObjectNameConstraints(resource, logicalName); + // Creates a registration context, if needed. // final ResourceContext context = @@ -1967,6 +1986,57 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { return context; } + + /** + * Checks that the ObjectName is legal with regards to the + * type of the MBean resource. + * If the MBean name is domain:type=JMXDomain, the + * MBean must be a JMXDomain. + * If the MBean name is namespace//:type=JMXNamespace, the + * MBean must be a JMXNamespace. + * If the MBean is a JMXDomain, its name + * must be domain:type=JMXDomain. + * If the MBean is a JMXNamespace, its name + * must be namespace//:type=JMXNamespace. + */ + private void checkResourceObjectNameConstraints(Object resource, + ObjectName logicalName) + throws MBeanRegistrationException { + try { + dispatcher.checkLocallyRegistrable(resource, logicalName); + } catch (Throwable x) { + DefaultMBeanServerInterceptor.throwMBeanRegistrationException(x, "validating ObjectName"); + } + } + + /** + * Registers a JMXNamespace with the dispatcher. + * This method is called by the ResourceContext from within the + * repository lock. + * @param namespace The JMXNamespace + * @param logicalName The JMXNamespaceMBean ObjectName + * @param postQueue A queue that will be processed after postRegister. + */ + private void addJMXNamespace(JMXNamespace namespace, + final ObjectName logicalName, + final Queue postQueue) { + dispatcher.addInterceptorFor(logicalName, namespace, postQueue); + } + + /** + * Unregisters a JMXNamespace from the dispatcher. + * This method is called by the ResourceContext from within the + * repository lock. + * @param namespace The JMXNamespace + * @param logicalName The JMXNamespaceMBean ObjectName + * @param postQueue A queue that will be processed after postDeregister. + */ + private void removeJMXNamespace(JMXNamespace namespace, + final ObjectName logicalName, + final Queue postQueue) { + dispatcher.removeInterceptorFor(logicalName, namespace, postQueue); + } + /** * Registers a ClassLoader with the CLR. * This method is called by the ResourceContext from within the @@ -2020,6 +2090,52 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { } } + + /** + * Creates a ResourceContext for a JMXNamespace MBean. + * The resource context makes it possible to add the JMXNamespace to + * (ResourceContext.registering) or resp. remove the JMXNamespace from + * (ResourceContext.unregistered) the NamespaceDispatchInterceptor + * when the associated MBean is added to or resp. removed from the + * repository. + * Note: JMXDomains are special sub classes of JMXNamespaces and + * are also handled by this object. + * + * @param namespace The JMXNamespace MBean being registered or + * unregistered. + * @param logicalName The name of the JMXNamespace MBean. + * @return a ResourceContext that takes in charge the addition or removal + * of the namespace to or from the NamespaceDispatchInterceptor. + */ + private ResourceContext createJMXNamespaceContext( + final JMXNamespace namespace, + final ObjectName logicalName) { + final Queue doneTaskQueue = new LinkedList(); + return new ResourceContext() { + + public void registering() { + addJMXNamespace(namespace, logicalName, doneTaskQueue); + } + + public void unregistered() { + removeJMXNamespace(namespace, logicalName, + doneTaskQueue); + } + + public void done() { + for (Runnable r : doneTaskQueue) { + try { + r.run(); + } catch (RuntimeException x) { + MBEANSERVER_LOGGER.log(Level.FINE, + "Failed to process post queue for "+ + logicalName, x); + } + } + } + }; + } + /** * Creates a ResourceContext for a ClassLoader MBean. * The resource context makes it possible to add the ClassLoader to @@ -2065,10 +2181,16 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { */ private ResourceContext makeResourceContextFor(Object resource, ObjectName logicalName) { + if (resource instanceof JMXNamespace) { + return createJMXNamespaceContext((JMXNamespace) resource, + logicalName); + } if (resource instanceof ClassLoader) { return createClassLoaderContext((ClassLoader) resource, logicalName); } return ResourceContext.NONE; } + + } diff --git a/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java b/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..4a79567fed14e7941bc69d16a24c041481a26a88 --- /dev/null +++ b/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java @@ -0,0 +1,557 @@ +/* + * 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.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Queue; +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.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.QueryExp; +import javax.management.ReflectionException; +import javax.management.namespace.JMXNamespace; + +/** + * A dispatcher that dispatches to MBeanServers. + *

+ * This API is a Sun internal API and is subject to changes without notice. + *

+ * @since 1.7 + */ +// +// This is the base class for implementing dispatchers. We have two concrete +// dispatcher implementations: +// +// * A NamespaceDispatchInterceptor, which dispatch calls to existing +// namespace interceptors +// * A DomainDispatchInterceptor, which dispatch calls to existing domain +// interceptors. +// +// With the JMX Namespaces feature, the JMX MBeanServer is now structured +// as follows: +// +// The JMX MBeanServer delegates to a NamespaceDispatchInterceptor, +// which either dispatches to a namespace, or delegates to the +// DomainDispatchInterceptor (if the object name contained no namespace). +// The DomainDispatchInterceptor in turn either dispatches to a domain (if +// there is a JMXDomain for that domain) or delegates to the +// DefaultMBeanServerInterceptor (if there is no JMXDomain for that +// domain). This makes the following picture: +// +// JMX MBeanServer (outer shell) +// | +// | +// NamespaceDispatchInterceptor +// / \ +// no namespace in object name? \ +// / \ +// / dispatch to namespace +// DomainDispatchInterceptor +// / \ +// no JMXDomain for domain? \ +// / \ +// / dispatch to domain +// DefaultMBeanServerInterceptor +// / +// invoke locally registered MBean +// +// The logic for maintaining a map of interceptors +// and dispatching to impacted interceptor, is implemented in this +// base class, which both NamespaceDispatchInterceptor and +// DomainDispatchInterceptor extend. +// +public abstract class DispatchInterceptor + + extends MBeanServerInterceptorSupport { + + /** + * This is an abstraction which allows us to handle queryNames + * and queryMBeans with the same algorithm. There are some subclasses + * where we need to override both queryNames & queryMBeans to apply + * the same transformation (usually aggregation of results when + * several namespaces/domains are impacted) to both algorithms. + * Usually the only thing that varies between the algorithm of + * queryNames & the algorithm of queryMBean is the type of objects + * in the returned Set. By using a QueryInvoker we can implement the + * transformation only once and apply it to both queryNames & + * queryMBeans. + * @see QueryInterceptor below, and its subclass in + * {@link DomainDispatcher}. + **/ + static abstract class QueryInvoker { + abstract Set query(MBeanServer mbs, + ObjectName pattern, QueryExp query); + } + + /** + * Used to perform queryNames. A QueryInvoker that invokes + * queryNames on an MBeanServer. + **/ + final static QueryInvoker queryNamesInvoker = + new QueryInvoker() { + Set query(MBeanServer mbs, + ObjectName pattern, QueryExp query) { + return mbs.queryNames(pattern,query); + } + }; + + /** + * Used to perform queryMBeans. A QueryInvoker that invokes + * queryMBeans on an MBeanServer. + **/ + final static QueryInvoker queryMBeansInvoker = + new QueryInvoker() { + Set query(MBeanServer mbs, + ObjectName pattern, QueryExp query) { + return mbs.queryMBeans(pattern,query); + } + }; + + /** + * We use this class to intercept queries. + * There's a special case for JMXNamespace MBeans, because + * "namespace//*:*" matches both "namespace//domain:k=v" and + * "namespace//:type=JMXNamespace". + * Therefore, queries may need to be forwarded to more than + * on interceptor and the results aggregated... + */ + static class QueryInterceptor { + final MBeanServer wrapped; + QueryInterceptor(MBeanServer mbs) { + wrapped = mbs; + } + Set query(ObjectName pattern, QueryExp query, + QueryInvoker invoker, MBeanServer server) { + return invoker.query(server, pattern, query); + } + + public Set queryNames(ObjectName pattern, QueryExp query) { + return query(pattern,query,queryNamesInvoker,wrapped); + } + + public Set queryMBeans(ObjectName pattern, + QueryExp query) { + return query(pattern,query,queryMBeansInvoker,wrapped); + } + } + + // We don't need a ConcurrentHashMap here because getkeys() returns + // an array of keys. Therefore there's no risk to have a + // ConcurrentModificationException. We must however take into + // account the fact that there can be no interceptor for + // some of the returned keys if the map is being modified by + // another thread, or by a callback within the same thread... + // See getKeys() in this class and query() in DomainDispatcher. + // + private final Map handlerMap = + Collections.synchronizedMap( + new HashMap()); + + // The key at which an interceptor for accessing the named MBean can be + // found in the handlerMap. Note: there doesn't need to be an interceptor + // for that key in the Map. + // + abstract String getHandlerKey(ObjectName name); + + // Returns an interceptor for that name, or null if there's no interceptor + // for that name. + abstract MBeanServer getInterceptorOrNullFor(ObjectName name); + + // Returns a QueryInterceptor for that pattern. + abstract QueryInterceptor getInterceptorForQuery(ObjectName pattern); + + // Returns the ObjectName of the JMXNamespace (or JMXDomain) for that + // key (a namespace or a domain name). + abstract ObjectName getHandlerNameFor(String key) + throws MalformedObjectNameException; + + // Creates an interceptor for the given key, name, JMXNamespace (or + // JMXDomain). Note: this will be either a NamespaceInterceptor + // wrapping a JMXNamespace, if this object is an instance of + // NamespaceDispatchInterceptor, or a DomainInterceptor wrapping a + // JMXDomain, if this object is an instance of DomainDispatchInterceptor. + abstract T createInterceptorFor(String key, ObjectName name, + N jmxNamespace, Queue postRegisterQueue); + // + // The next interceptor in the chain. + // + // For the NamespaceDispatchInterceptor, this the DomainDispatchInterceptor. + // For the DomainDispatchInterceptor, this is the + // DefaultMBeanServerInterceptor. + // + // The logic of when to invoke the next interceptor in the chain depends + // on the logic of the concrete dispatcher class. + // + // For instance, the NamespaceDispatchInterceptor invokes the next + // interceptor when the object name doesn't contain any namespace. + // + // On the other hand, the DomainDispatchInterceptor invokes the + // next interceptor when there's no interceptor for the accessed domain. + // + abstract MBeanServer getNextInterceptor(); + + // hook for cleanup in subclasses. + void interceptorReleased(T interceptor, + Queue postDeregisterQueue) { + // hook + } + + // Hook for subclasses. + MBeanServer getInterceptorForCreate(ObjectName name) + throws MBeanRegistrationException { + final MBeanServer ns = getInterceptorOrNullFor(name); + if (ns == null) // name cannot be null here. + throw new MBeanRegistrationException( + new IllegalArgumentException("No such MBean handler: " + + getHandlerKey(name) + " for " +name)); + return ns; + } + + // Hook for subclasses. + MBeanServer getInterceptorForInstance(ObjectName name) + throws InstanceNotFoundException { + final MBeanServer ns = getInterceptorOrNullFor(name); + if (ns == null) // name cannot be null here. + throw new InstanceNotFoundException(String.valueOf(name)); + return ns; + } + + // sanity checks + void validateHandlerNameFor(String key, ObjectName name) { + if (key == null || key.equals("")) + throw new IllegalArgumentException("invalid key for "+name+": "+key); + try { + final ObjectName handlerName = getHandlerNameFor(key); + if (!name.equals(handlerName)) + throw new IllegalArgumentException("bad handler name: "+name+ + ". Should be: "+handlerName); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(name.toString(),x); + } + } + + // Called by the DefaultMBeanServerInterceptor when an instance + // of JMXNamespace (or a subclass of it) is registered as an MBean. + // This method is usually invoked from within the repository lock, + // hence the necessity of the postRegisterQueue. + public void addInterceptorFor(ObjectName name, N jmxNamespace, + Queue postRegisterQueue) { + final String key = getHandlerKey(name); + validateHandlerNameFor(key,name); + synchronized (handlerMap) { + final T exists = + handlerMap.get(key); + if (exists != null) + throw new IllegalArgumentException(key+ + ": handler already exists"); + + final T ns = createInterceptorFor(key,name,jmxNamespace, + postRegisterQueue); + handlerMap.put(key,ns); + } + } + + // Called by the DefaultMBeanServerInterceptor when an instance + // of JMXNamespace (or a subclass of it) is deregistered. + // This method is usually invoked from within the repository lock, + // hence the necessity of the postDeregisterQueue. + public void removeInterceptorFor(ObjectName name, N jmxNamespace, + Queue postDeregisterQueue) { + final String key = getHandlerKey(name); + final T ns; + synchronized(handlerMap) { + ns = handlerMap.remove(key); + } + interceptorReleased(ns,postDeregisterQueue); + } + + // Get the interceptor for that key. + T getInterceptor(String key) { + synchronized (handlerMap) { + return handlerMap.get(key); + } + } + + // We return an array of keys, which makes it possible to make + // concurrent modifications of the handlerMap, provided that + // the code which loops over the keys is prepared to handle null + // interceptors. + // See declaration of handlerMap above, and see also query() in + // DomainDispatcher + // + public String[] getKeys() { + synchronized (handlerMap) { + final int size = handlerMap.size(); + return handlerMap.keySet().toArray(new String[size]); + } + } + + // From MBeanServer + public final ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + return getInterceptorForCreate(name).createMBean(className,name); + } + + // From MBeanServer + public final ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException{ + return getInterceptorForCreate(name).createMBean(className,name,loaderName); + } + + // From MBeanServer + public final ObjectInstance createMBean(String className, ObjectName name, + Object params[], String signature[]) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException{ + return getInterceptorForCreate(name). + createMBean(className,name,params,signature); + } + + // From MBeanServer + public final ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName, Object params[], + String signature[]) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException{ + return getInterceptorForCreate(name).createMBean(className,name,loaderName, + params,signature); + } + + // From MBeanServer + public final ObjectInstance registerMBean(Object object, ObjectName name) + throws InstanceAlreadyExistsException, MBeanRegistrationException, + NotCompliantMBeanException { + return getInterceptorForCreate(name).registerMBean(object,name); + } + + // From MBeanServer + public final void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException { + getInterceptorForInstance(name).unregisterMBean(name); + } + + // From MBeanServer + public final ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException { + return getInterceptorForInstance(name).getObjectInstance(name); + } + + // From MBeanServer + public final Set queryMBeans(ObjectName name, + QueryExp query) { + final QueryInterceptor queryInvoker = + getInterceptorForQuery(name); + if (queryInvoker == null) return Collections.emptySet(); + else return queryInvoker.queryMBeans(name,query); + } + + // From MBeanServer + public final Set queryNames(ObjectName name, QueryExp query) { + final QueryInterceptor queryInvoker = + getInterceptorForQuery(name); + if (queryInvoker == null) return Collections.emptySet(); + else return queryInvoker.queryNames(name,query); + } + + // From MBeanServer + public final boolean isRegistered(ObjectName name) { + final MBeanServer mbs = getInterceptorOrNullFor(name); + if (mbs == null) return false; + else return mbs.isRegistered(name); + } + + // From MBeanServer + public Integer getMBeanCount() { + return getNextInterceptor().getMBeanCount(); + } + + // From MBeanServer + public final Object getAttribute(ObjectName name, String attribute) + throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException { + return getInterceptorForInstance(name).getAttribute(name,attribute); + } + + // From MBeanServer + public final AttributeList getAttributes(ObjectName name, + String[] attributes) + throws InstanceNotFoundException, ReflectionException { + return getInterceptorForInstance(name).getAttributes(name,attributes); + } + + // From MBeanServer + public final void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException { + getInterceptorForInstance(name).setAttribute(name,attribute); + } + + // From MBeanServer + public final AttributeList setAttributes(ObjectName name, + AttributeList attributes) + throws InstanceNotFoundException, ReflectionException { + return getInterceptorForInstance(name).setAttributes(name,attributes); + } + + // From MBeanServer + public final Object invoke(ObjectName name, String operationName, + Object params[], String signature[]) + throws InstanceNotFoundException, MBeanException, + ReflectionException { + return getInterceptorForInstance(name).invoke(name,operationName,params, + signature); + } + + // From MBeanServer + public String getDefaultDomain() { + return getNextInterceptor().getDefaultDomain(); + } + + /** + * Returns the list of domains in which any MBean is currently + * registered. + */ + public abstract String[] getDomains(); + + // From MBeanServer + public final void addNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + getInterceptorForInstance(name). + addNotificationListener(name,listener,filter, + handback); + } + + + // From MBeanServer + public final void addNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + getInterceptorForInstance(name). + addNotificationListener(name,listener,filter, + handback); + } + + // From MBeanServer + public final void removeNotificationListener(ObjectName name, + ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException { + getInterceptorForInstance(name). + removeNotificationListener(name,listener); + } + + // From MBeanServer + public final void removeNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + getInterceptorForInstance(name). + removeNotificationListener(name,listener,filter, + handback); + } + + + // From MBeanServer + public final void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException { + getInterceptorForInstance(name). + removeNotificationListener(name,listener); + } + + // From MBeanServer + public final void removeNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + getInterceptorForInstance(name). + removeNotificationListener(name,listener,filter, + handback); + } + + // From MBeanServer + public final MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, IntrospectionException, + ReflectionException { + return getInterceptorForInstance(name).getMBeanInfo(name); + } + + + // From MBeanServer + public final boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException { + return getInterceptorForInstance(name).isInstanceOf(name,className); + } + + // From MBeanServer + public final ClassLoader getClassLoaderFor(ObjectName mbeanName) + throws InstanceNotFoundException { + return getInterceptorForInstance(mbeanName). + getClassLoaderFor(mbeanName); + } + + // From MBeanServer + public final ClassLoader getClassLoader(ObjectName loaderName) + throws InstanceNotFoundException { + return getInterceptorForInstance(loaderName). + getClassLoader(loaderName); + } + +} diff --git a/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java b/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..9b9b1d6b19c72d5e78ea02c0b0430c1217cfd5fe --- /dev/null +++ b/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java @@ -0,0 +1,356 @@ +/* + * 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.DomainInterceptor; +import java.util.Queue; +import java.util.Set; + +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.QueryExp; +import javax.management.namespace.JMXDomain; +import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR; + +/** + * A dispatcher that dispatch incoming MBeanServer requests to + * DomainInterceptors. + *

+ * This API is a Sun internal API and is subject to changes without notice. + *

+ * @since 1.7 + */ +// +// See comments in DispatchInterceptor. +// +class DomainDispatchInterceptor + extends DispatchInterceptor { + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + private static final ObjectName ALL_DOMAINS = + JMXDomain.getDomainObjectName("*"); + + + /** + * A QueryInterceptor that perform & aggregates queries spanning several + * domains. + */ + final static class AggregatingQueryInterceptor extends QueryInterceptor { + + private final DomainDispatchInterceptor parent; + AggregatingQueryInterceptor(DomainDispatchInterceptor dispatcher) { + super(dispatcher.nextInterceptor); + parent = dispatcher; + } + + /** + * Perform queryNames or queryMBeans, depending on which QueryInvoker + * is passed as argument. This is closures without closures. + **/ + @Override + Set query(ObjectName pattern, QueryExp query, + QueryInvoker invoker, MBeanServer localNamespace) { + final Set local = invoker.query(localNamespace, pattern, query); + + // Add all matching MBeans from local namespace. + final Set res = Util.cloneSet(local); + + if (pattern == null) pattern = ObjectName.WILDCARD; + final boolean all = pattern.getDomain().equals("*"); + + final String domain = pattern.getDomain(); + + // If there's no domain pattern, just include the pattern's domain. + // Otherwiae, loop over all virtual domains (parent.getKeys()). + final String[] keys = + (pattern.isDomainPattern() ? + parent.getKeys() : new String[]{domain}); + + // Add all matching MBeans from each virtual domain + // + for (String key : keys) { + // Only invoke those virtual domain which are selected + // by the domain pattern + // + if (!all && !Util.isDomainSelected(key, domain)) + continue; + + try { + final MBeanServer mbs = parent.getInterceptor(key); + + // mbs can be null if the interceptor was removed + // concurrently... + // See handlerMap and getKeys() in DispatchInterceptor + // + if (mbs == null) continue; + + // If the domain is selected, we can replace the pattern + // by the actual domain. This is safer if we want to avoid + // a domain (which could be backed up by an MBeanServer) to + // return names from outside the domain. + // So instead of asking the domain handler for "foo" to + // return all names which match "?o*:type=Bla,*" we're + // going to ask it to return all names which match + // "foo:type=Bla,*" + // + final ObjectName subPattern = pattern.withDomain(key); + res.addAll(invoker.query(mbs, subPattern, query)); + } catch (Exception x) { + LOG.finest("Ignoring exception " + + "when attempting to query namespace "+key+": "+x); + continue; + } + } + return res; + } + } + + private final DefaultMBeanServerInterceptor nextInterceptor; + private final String mbeanServerName; + private final MBeanServerDelegate delegate; + + /** + * Creates a DomainDispatchInterceptor with the specified + * repository instance. + * + * @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 DomainDispatchInterceptor(MBeanServer outer, + MBeanServerDelegate delegate, + MBeanInstantiator instantiator, + Repository repository, + NamespaceDispatchInterceptor namespaces) { + nextInterceptor = new DefaultMBeanServerInterceptor(outer, + delegate, instantiator,repository,namespaces); + mbeanServerName = Util.getMBeanServerSecurityName(delegate); + this.delegate = delegate; + } + + final boolean isLocalHandlerNameFor(String domain, + ObjectName handlerName) { + if (domain == null) return true; + return handlerName.getDomain().equals(domain) && + JMXDomain.TYPE_ASSIGNMENT.equals( + handlerName.getKeyPropertyListString()); + } + + @Override + void validateHandlerNameFor(String key, ObjectName name) { + super.validateHandlerNameFor(key,name); + final String[] domains = nextInterceptor.getDomains(); + for (int i=0;i postRegisterQueue) { + final DomainInterceptor ns = + new DomainInterceptor(mbeanServerName,handler,key); + ns.addPostRegisterTask(postRegisterQueue, delegate); + if (LOG.isLoggable(Level.FINER)) { + LOG.finer("DomainInterceptor created: "+ns); + } + return ns; + } + + @Override + final void interceptorReleased(DomainInterceptor interceptor, + Queue postDeregisterQueue) { + interceptor.addPostDeregisterTask(postDeregisterQueue, delegate); + } + + @Override + final DefaultMBeanServerInterceptor getNextInterceptor() { + return nextInterceptor; + } + + /** + * Returns the list of domains in which any MBean is currently + * registered. + */ + @Override + public String[] getDomains() { + // A JMXDomain is registered in its own domain. + // Therefore, nextInterceptor.getDomains() contains all domains. + // In addition, nextInterceptor will perform the necessary + // MBeanPermission checks for getDomains(). + // + return nextInterceptor.getDomains(); + } + + /** + * Returns the number of MBeans registered in the MBean server. + */ + @Override + public Integer getMBeanCount() { + int count = getNextInterceptor().getMBeanCount(); + final String[] keys = getKeys(); + for (String key:keys) { + final MBeanServer mbs = getInterceptor(key); + if (mbs == null) continue; + count += mbs.getMBeanCount(); + } + return count; + } +} diff --git a/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptor.java b/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptor.java index c0a1844f0cc4be552da3bc886dee624b83a6dd57..7b2d836a621b457030f8b0dd997f0925dd41e80a 100644 --- a/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptor.java +++ b/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2005 Sun Microsystems, Inc. All Rights Reserved. + * 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 @@ -25,35 +25,14 @@ package com.sun.jmx.interceptor; -import java.util.Set; -// RI import -import javax.management.DynamicMBean; -import javax.management.AttributeNotFoundException; -import javax.management.MBeanException; -import javax.management.ReflectionException; -import javax.management.MBeanAttributeInfo; -import javax.management.MBeanInfo; -import javax.management.QueryExp; -import javax.management.NotificationListener; -import javax.management.NotificationFilter; -import javax.management.ListenerNotFoundException; -import javax.management.IntrospectionException; -import javax.management.OperationsException; -import javax.management.MBeanNotificationInfo; -import javax.management.JMRuntimeException; +import java.io.ObjectInputStream; import javax.management.InstanceNotFoundException; -import javax.management.NotCompliantMBeanException; -import javax.management.MBeanRegistrationException; -import javax.management.InstanceAlreadyExistsException; -import javax.management.InvalidAttributeValueException; +import javax.management.MBeanException; +import javax.management.MBeanServer; import javax.management.ObjectName; -import javax.management.ObjectInstance; -import javax.management.Attribute; -import javax.management.AttributeList; -import javax.management.RuntimeOperationsException; -import javax.management.MBeanServerConnection; -import javax.management.MBeanServerDelegate; +import javax.management.OperationsException; +import javax.management.ReflectionException; import javax.management.loading.ClassLoaderRepository; /** @@ -85,618 +64,67 @@ import javax.management.loading.ClassLoaderRepository; * * @since 1.5 */ -public interface MBeanServerInterceptor extends MBeanServerConnection { - /** - * Instantiates and registers an MBean in the MBean server. The - * MBean server will use its {@link - * javax.management.loading.ClassLoaderRepository Default Loader - * Repository} to load the class of the MBean. An object name is - * associated to the MBean. 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 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. - * - * @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 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. - */ - public ObjectInstance createMBean(String className, ObjectName name, - Object params[], String signature[]) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException; - - /** - * 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. - * - */ - public ObjectInstance createMBean(String className, ObjectName name, - ObjectName loaderName, Object params[], - String signature[]) - throws ReflectionException, InstanceAlreadyExistsException, - MBeanRegistrationException, MBeanException, - NotCompliantMBeanException, 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. - */ - public ObjectInstance registerMBean(Object object, ObjectName name) - throws InstanceAlreadyExistsException, MBeanRegistrationException, - NotCompliantMBeanException; - - /** - * 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. - */ - public Set queryMBeans(ObjectName name, QueryExp query); - - /** - * Gets the names of MBeans controlled by the MBean server. This - * method enables any of the following to be obtained: The names - * of all MBeans, the names of a set of MBeans specified by - * pattern matching on the ObjectName 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 Set queryNames(ObjectName name, QueryExp query); - - /** - * Checks whether an MBean, identified by its object name, is - * already registered with the MBean server. - * - * @param name The object name of the MBean to be checked. - * - * @return True if the MBean is already registered in the MBean - * server, false otherwise. - * - * @exception RuntimeOperationsException Wraps a - * java.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; - - /** - * 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. - */ - 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; - - /** - * 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(); - +public interface MBeanServerInterceptor extends MBeanServer { /** - * Returns the list of domains in which any MBean is currently - * registered. + * This method should never be called. + * Usually hrows UnsupportedOperationException. */ - public String[] getDomains(); - + public Object instantiate(String className) + throws ReflectionException, MBeanException; /** - *

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. + * This method should never be called. + * Usually throws UnsupportedOperationException. */ - public void addNotificationListener(ObjectName name, - NotificationListener listener, - NotificationFilter filter, - Object handback) - throws InstanceNotFoundException; - - + public Object instantiate(String className, ObjectName loaderName) + throws ReflectionException, MBeanException, + 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.

- * - * @param name The name of the MBean on which the listener should - * be added. - * @param listener The object name of the listener 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 of the - * notification listener or of the notification broadcaster does - * not match any of the registered MBeans. - * @exception RuntimeOperationsException Wraps an {@link - * IllegalArgumentException}. The MBean named by - * listener exists but does not implement the {@link - * NotificationListener} interface. - * @exception IOException A communication problem occurred when - * talking to the MBean server. + * This method should never be called. + * Usually throws UnsupportedOperationException. */ - public void addNotificationListener(ObjectName name, - ObjectName listener, - NotificationFilter filter, - Object handback) - throws InstanceNotFoundException; + public Object instantiate(String className, Object[] params, + String[] signature) throws ReflectionException, MBeanException; /** - * 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 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 throws UnsupportedOperationException. */ - public void removeNotificationListener(ObjectName name, - ObjectName listener) - throws InstanceNotFoundException, ListenerNotFoundException; + public Object instantiate(String className, ObjectName loaderName, + Object[] params, String[] signature) + throws ReflectionException, MBeanException, + InstanceNotFoundException; /** - *

Removes a listener from a registered MBean.

- * - *

The MBean must have a listener that exactly matches the - * given listener, filter, and - * handback parameters. If there is more than one - * such listener, only one is removed.

- * - *

The filter and handback parameters - * may be null if and only if they are null in a listener to be - * removed.

- * - * @param name The name of the MBean on which the listener should - * be removed. - * @param listener A listener that was previously added to this - * MBean. - * @param filter The filter that was specified when the listener - * was added. - * @param handback The handback that was specified when the - * listener was added. - * - * @exception InstanceNotFoundException The MBean name provided - * does not match any of the registered MBeans. - * @exception ListenerNotFoundException The listener is not - * registered in the MBean, or it is not registered with the given - * filter and handback. + * This method should never be called. + * Usually throws UnsupportedOperationException. */ - public void removeNotificationListener(ObjectName name, - ObjectName listener, - NotificationFilter filter, - Object handback) - throws InstanceNotFoundException, ListenerNotFoundException; - + @Deprecated + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException; /** - *

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. + * This method should never be called. + * Usually throws UnsupportedOperationException. */ - public void removeNotificationListener(ObjectName name, - NotificationListener listener) - throws InstanceNotFoundException, ListenerNotFoundException; + @Deprecated + public ObjectInputStream deserialize(String className, byte[] data) + throws OperationsException, ReflectionException; /** - *

Removes a listener from a registered MBean.

- * - *

The MBean must have a listener that exactly matches the - * given listener, filter, and - * handback parameters. If there is more than one - * such listener, only one is removed.

- * - *

The filter and handback parameters - * may be null if and only if they are null in a listener to be - * removed.

- * - * @param name The name of the MBean on which the listener should - * be removed. - * @param listener A listener that was previously added to this - * MBean. - * @param filter The filter that was specified when the listener - * was added. - * @param handback The handback that was specified when the - * listener was added. - * - * @exception InstanceNotFoundException The MBean name provided - * does not match any of the registered MBeans. - * @exception ListenerNotFoundException The listener is not - * registered in the MBean, or it is not registered with the given - * filter and handback. + * This method should never be called. + * Usually hrows UnsupportedOperationException. */ - public void removeNotificationListener(ObjectName name, - NotificationListener listener, - NotificationFilter filter, - Object handback) - throws InstanceNotFoundException, ListenerNotFoundException; + @Deprecated + public ObjectInputStream deserialize(String className, + ObjectName loaderName, byte[] data) + throws InstanceNotFoundException, OperationsException, + ReflectionException; /** - * This method discovers the attributes and operations that an - * MBean exposes for management. - * - * @param name The name of the MBean to analyze - * - * @return An instance of 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. + * This method should never be called. + * Usually throws UnsupportedOperationException. */ - 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; - - /** - *

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 --git a/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java b/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java new file mode 100644 index 0000000000000000000000000000000000000000..8e1cf681e864caa3980b69f3faf62622a09c2069 --- /dev/null +++ b/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java @@ -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. + *

+ * @since 1.7 + */ +public abstract class MBeanServerInterceptorSupport + implements MBeanServerInterceptor { + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className) + throws ReflectionException, MBeanException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className, ObjectName loaderName) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className, Object[] params, + String[] signature) throws ReflectionException, MBeanException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className, ObjectName loaderName, + Object[] params, String[] signature) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + @Deprecated + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + @Deprecated + public ObjectInputStream deserialize(String className, byte[] data) + throws OperationsException, ReflectionException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + @Deprecated + public ObjectInputStream deserialize(String className, + ObjectName loaderName, byte[] data) + throws InstanceNotFoundException, OperationsException, + ReflectionException { + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public ClassLoaderRepository getClassLoaderRepository() { + throw new UnsupportedOperationException("Not applicable."); + } + +} diff --git a/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java b/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..d86c787b8985f6bad3b2757e299e0fbea45de46a --- /dev/null +++ b/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java @@ -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 DispatchInterceptor { + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + private static final int NAMESPACE_SEPARATOR_LENGTH = + NAMESPACE_SEPARATOR.length(); + + private final DomainDispatchInterceptor nextInterceptor; + private final String serverName; + + /** + * Creates a NamespaceDispatchInterceptor with the specified + * repository instance. + *

Do not forget to call 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) { + nextInterceptor = 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. + **/ + static String getFirstNamespace(ObjectName name) { + if (name == null) return ""; + final String domain = name.getDomain(); + if (domain.equals("")) return ""; + + // skip leading separators + int first = 0; + while (domain.startsWith(NAMESPACE_SEPARATOR,first)) + first += NAMESPACE_SEPARATOR_LENGTH; + + // go to next separator + final int end = domain.indexOf(NAMESPACE_SEPARATOR,first); + if (end == -1) return ""; // no namespace + + // This is the first element in the namespace path. + 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 nextInterceptor; + } + 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(nextInterceptor); + } + 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 postRegisterQueue) { + final NamespaceInterceptor ns = + new NamespaceInterceptor(serverName,handler,key); + if (LOG.isLoggable(Level.FINER)) { + LOG.finer("NamespaceInterceptor created: "+ns); + } + return ns; + } + + @Override + final DomainDispatchInterceptor getNextInterceptor() { + return nextInterceptor; + } + + /** + * Returns the list of domains in which any MBean is currently + * registered. + */ + @Override + public String[] getDomains() { + return nextInterceptor.getDomains(); + } + + @Override + public void addInterceptorFor(ObjectName name, JMXNamespace handler, + Queue postRegisterQueue) { + if (handler instanceof JMXDomain) + nextInterceptor.addInterceptorFor(name, + (JMXDomain)handler,postRegisterQueue); + else super.addInterceptorFor(name,handler,postRegisterQueue); + } + + @Override + public void removeInterceptorFor(ObjectName name, JMXNamespace handler, + Queue postDeregisterQueue) { + if (handler instanceof JMXDomain) + nextInterceptor.removeInterceptorFor(name,(JMXDomain)handler, + postDeregisterQueue); + else super.removeInterceptorFor(name,handler,postDeregisterQueue); + } + + +} diff --git a/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java b/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java index ec53998f51acd7103d9deb12ec7d4b5e053b2f42..4a47d4ce3aafae60874c18aada3f193fda185fa6 100644 --- a/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java +++ b/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java @@ -51,6 +51,8 @@ import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.QueryExp; import javax.management.ReflectionException; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.MBeanServerSupport; import javax.management.remote.IdentityMBeanServerForwarder; public class SingleMBeanForwarder extends IdentityMBeanServerForwarder { @@ -285,14 +287,14 @@ public class SingleMBeanForwarder extends IdentityMBeanServerForwarder { if (!pattern.apply(mbeanName)) return false; -// final String dompat = pattern.getDomain(); -// if (!dompat.contains(JMXNamespaces.NAMESPACE_SEPARATOR)) -// return true; // We already checked that patterns apply. -// -// if (mbeanName.getDomain().endsWith(JMXNamespaces.NAMESPACE_SEPARATOR)) { -// // only matches if pattern ends with // -// return dompat.endsWith(JMXNamespaces.NAMESPACE_SEPARATOR); -// } + final String dompat = pattern.getDomain(); + if (!dompat.contains(JMXNamespaces.NAMESPACE_SEPARATOR)) + return true; // We already checked that patterns apply. + + if (mbeanName.getDomain().endsWith(JMXNamespaces.NAMESPACE_SEPARATOR)) { + // only matches if pattern ends with // + return dompat.endsWith(JMXNamespaces.NAMESPACE_SEPARATOR); + } // should not come here, unless mbeanName contains a // in the // middle of its domain, which would be weird. diff --git a/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java b/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java index 3509c40f3c2e6d28f3c8a556dc9a73b85603b797..b86b2e001283a55f9345d2e78350a4df96f8dfe4 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java @@ -1172,10 +1172,10 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { final Class propertyNamesClass = ConstructorProperties.class; Class targetClass = getTargetClass(); - Constructor[] constrs = targetClass.getConstructors(); + Constructor[] constrs = targetClass.getConstructors(); // Applicable if and only if there are any annotated constructors - List annotatedConstrList = newList(); + List> annotatedConstrList = newList(); for (Constructor constr : constrs) { if (Modifier.isPublic(constr.getModifiers()) && constr.getAnnotation(propertyNamesClass) != null) @@ -1206,7 +1206,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { // Also remember the set of properties in that constructor // so we can test unambiguity. Set getterIndexSets = newSet(); - for (Constructor constr : annotatedConstrList) { + for (Constructor constr : annotatedConstrList) { String[] propertyNames = constr.getAnnotation(propertyNamesClass).value(); @@ -1363,10 +1363,10 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { } private static class Constr { - final Constructor constructor; + final Constructor constructor; final int[] paramIndexes; final BitSet presentParams; - Constr(Constructor constructor, int[] paramIndexes, + Constr(Constructor constructor, int[] paramIndexes, BitSet presentParams) { this.constructor = constructor; this.paramIndexes = paramIndexes; diff --git a/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java b/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java index 1095897d99b4536f0121d2c4c687dd526fb48775..777cd1cce65461b641dc5ca217dd3bf5ca0a7b3f 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-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 @@ -25,44 +25,42 @@ package com.sun.jmx.mbeanserver; -import java.util.Iterator; -import java.util.logging.Level; -import java.util.Set; +import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER; +import com.sun.jmx.interceptor.NamespaceDispatchInterceptor; + import java.io.ObjectInputStream; import java.security.AccessController; import java.security.Permission; import java.security.PrivilegedExceptionAction; +import java.util.Iterator; +import java.util.Set; +import java.util.logging.Level; -// RI import -import javax.management.MBeanPermission; +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.ReflectionException; import javax.management.MBeanInfo; -import javax.management.QueryExp; -import javax.management.NotificationListener; -import javax.management.NotificationFilter; -import javax.management.ListenerNotFoundException; -import javax.management.IntrospectionException; -import javax.management.OperationsException; -import javax.management.InstanceNotFoundException; -import javax.management.NotCompliantMBeanException; +import javax.management.MBeanPermission; import javax.management.MBeanRegistrationException; -import javax.management.InstanceAlreadyExistsException; -import javax.management.InvalidAttributeValueException; -import javax.management.ObjectName; -import javax.management.ObjectInstance; -import javax.management.Attribute; -import javax.management.AttributeList; -import javax.management.RuntimeOperationsException; import javax.management.MBeanServer; import javax.management.MBeanServerDelegate; +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.RuntimeOperationsException; import javax.management.loading.ClassLoaderRepository; -import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER; -import com.sun.jmx.interceptor.DefaultMBeanServerInterceptor; -import com.sun.jmx.interceptor.MBeanServerInterceptor; - /** * This is the base class for MBean manipulation on the agent side. It * contains the methods necessary for the creation, registration, and @@ -102,15 +100,14 @@ public final class JmxMBeanServer /** true if interceptors are enabled **/ private final boolean interceptorsEnabled; - /** Revisit: transient ??? **/ - private final transient MBeanServer outerShell; + private final MBeanServer outerShell; - /** Revisit: transient ??? **/ - private transient MBeanServerInterceptor mbsInterceptor = null; + private volatile MBeanServer mbsInterceptor = null; - /** Revisit: transient ??? **/ /** The MBeanServerDelegate object representing the MBean Server */ - private final transient MBeanServerDelegate mBeanServerDelegateObject; + private final MBeanServerDelegate mBeanServerDelegateObject; + + private final String mbeanServerName; /** * Package: Creates an MBeanServer with the @@ -243,9 +240,10 @@ public final class JmxMBeanServer final Repository repository = new Repository(domain,fairLock); this.mbsInterceptor = - new DefaultMBeanServerInterceptor(outer, delegate, instantiator, + new NamespaceDispatchInterceptor(outer, delegate, instantiator, repository); this.interceptorsEnabled = interceptors; + this.mbeanServerName = Util.getMBeanServerSecurityName(delegate); initialize(); } @@ -941,7 +939,8 @@ public final class JmxMBeanServer throws ReflectionException, MBeanException { /* Permission check */ - checkMBeanPermission(className, null, null, "instantiate"); + checkMBeanPermission(mbeanServerName, className, null, null, + "instantiate"); return instantiator.instantiate(className); } @@ -978,7 +977,8 @@ public final class JmxMBeanServer InstanceNotFoundException { /* Permission check */ - checkMBeanPermission(className, null, null, "instantiate"); + checkMBeanPermission(mbeanServerName, className, null, + null, "instantiate"); ClassLoader myLoader = outerShell.getClass().getClassLoader(); return instantiator.instantiate(className, loaderName, myLoader); @@ -1016,7 +1016,8 @@ public final class JmxMBeanServer throws ReflectionException, MBeanException { /* Permission check */ - checkMBeanPermission(className, null, null, "instantiate"); + checkMBeanPermission(mbeanServerName, className, null, null, + "instantiate"); ClassLoader myLoader = outerShell.getClass().getClassLoader(); return instantiator.instantiate(className, params, signature, @@ -1059,7 +1060,8 @@ public final class JmxMBeanServer InstanceNotFoundException { /* Permission check */ - checkMBeanPermission(className, null, null, "instantiate"); + checkMBeanPermission(mbeanServerName, className, null, + null, "instantiate"); ClassLoader myLoader = outerShell.getClass().getClassLoader(); return instantiator.instantiate(className,loaderName,params,signature, @@ -1236,7 +1238,7 @@ public final class JmxMBeanServer "Unexpected exception occurred", e); } throw new - IllegalStateException("Can't register delegate."); + IllegalStateException("Can't register delegate.",e); } @@ -1278,7 +1280,7 @@ public final class JmxMBeanServer * are not enabled on this object. * @see #interceptorsEnabled **/ - public synchronized MBeanServerInterceptor getMBeanServerInterceptor() { + public synchronized MBeanServer getMBeanServerInterceptor() { if (interceptorsEnabled) return mbsInterceptor; else throw new UnsupportedOperationException( "MBeanServerInterceptors are disabled."); @@ -1292,7 +1294,7 @@ public final class JmxMBeanServer * @see #interceptorsEnabled **/ public synchronized void - setMBeanServerInterceptor(MBeanServerInterceptor interceptor) { + setMBeanServerInterceptor(MBeanServer interceptor) { if (!interceptorsEnabled) throw new UnsupportedOperationException( "MBeanServerInterceptors are disabled."); if (interceptor == null) throw new @@ -1330,7 +1332,8 @@ public final class JmxMBeanServer **/ public ClassLoaderRepository getClassLoaderRepository() { /* Permission check */ - checkMBeanPermission(null, null, null, "getClassLoaderRepository"); + checkMBeanPermission(mbeanServerName, null, null, + null, "getClassLoaderRepository"); return secureClr; } @@ -1484,14 +1487,16 @@ public final class JmxMBeanServer // SECURITY CHECKS //---------------- - private static void checkMBeanPermission(String classname, + private static void checkMBeanPermission(String serverName, + String classname, String member, ObjectName objectName, String actions) throws SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - Permission perm = new MBeanPermission(classname, + Permission perm = new MBeanPermission(serverName, + classname, member, objectName, actions); diff --git a/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java b/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java index 725292bca36c05174c5b092c5e5373d84a734add..99aaa85466d9e30dcc178fe9377b15bef449afd7 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java @@ -623,7 +623,7 @@ abstract class MBeanIntrospector { } private static MBeanConstructorInfo[] findConstructors(Class c) { - Constructor[] cons = c.getConstructors(); + Constructor[] cons = c.getConstructors(); MBeanConstructorInfo[] mbc = new MBeanConstructorInfo[cons.length]; for (int i = 0; i < cons.length; i++) { String descr = "Public constructor of the MBean"; diff --git a/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java b/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java index 41b3b98916078d59882f7a17961e740935354070..227c1eec9908f865c653d677594dde41b832ce86 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java @@ -224,7 +224,7 @@ public abstract class MXBeanLookup { throws InvalidObjectException { String domain = prefix + name.getDomain(); try { - name = switchDomain(domain, name); + name = name.withDomain(domain); } catch (MalformedObjectNameException e) { throw EnvHelp.initCause( new InvalidObjectException(e.getMessage()), e); @@ -242,7 +242,7 @@ public abstract class MXBeanLookup { "Proxy's name does not start with " + prefix + ": " + name); } try { - name = switchDomain(domain.substring(prefix.length()), name); + name = name.withDomain(domain.substring(prefix.length())); } catch (MalformedObjectNameException e) { throw EnvHelp.initCause(new OpenDataException(e.getMessage()), e); } @@ -269,14 +269,6 @@ public abstract class MXBeanLookup { currentLookup.set(lookup); } - // Method temporarily added until we have ObjectName.switchDomain in the - // public API. Note that this method DOES NOT PRESERVE the order of - // keys in the ObjectName so it must not be used in the final release. - static ObjectName switchDomain(String domain, ObjectName name) - throws MalformedObjectNameException { - return new ObjectName(domain, name.getKeyPropertyList()); - } - private static final ThreadLocal currentLookup = new ThreadLocal(); diff --git a/src/share/classes/com/sun/jmx/mbeanserver/Repository.java b/src/share/classes/com/sun/jmx/mbeanserver/Repository.java index f41079912fb2a81a0e3a76d6ea9f86505c8c4e29..03f3e5277bd7ba8a9382fd7fdae44fdeb0c8b495 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/Repository.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/Repository.java @@ -45,7 +45,6 @@ import javax.management.QueryExp; import javax.management.RuntimeOperationsException; /** - * The RepositorySupport implements the Repository interface. * This repository does not support persistency. * * @since 1.5 @@ -197,9 +196,9 @@ public class Repository { if (isPropertyValuePattern && pattern.isPropertyValuePattern(keys[i])) { // wildmatch key property values - final char[] val_pattern = values[i].toCharArray(); - final char[] val_string = v.toCharArray(); - if (wildmatch(val_string,val_pattern)) + // values[i] is the pattern; + // v is the string + if (Util.wildmatch(v,values[i])) continue; else return false; @@ -236,86 +235,6 @@ public class Repository { } } - /** Match a string against a shell-style pattern. The only pattern - characters recognised are ?, 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 @@ public class Repository { 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) { @@ -477,10 +396,10 @@ public class Repository { // Set domain to default if domain is empty and not already set if (dom.length() == 0) - name = Util.newObjectName(domain + name.toString()); + name = ObjectName.valueOf(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 @@ public class Repository { } // 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 moiTb = domainTb.get(dom); if (allNames) result.addAll(moiTb.values()); @@ -726,7 +644,7 @@ public class Repository { // need to reinstantiate a hashtable because of possible // big buckets array size inside table, never cleared, // thus the new ! - if (dom == domain) + if (dom == domain) // ES: OK dom and domain are interned. domainTb.put(domain, new HashMap()); } diff --git a/src/share/classes/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java b/src/share/classes/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java index 6c338387d0e19dd57e83d9a292f81d01f2720c01..0a1ab72aec2d524fd2b91086d8a961ec80bfd371 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/SunJmxMBeanServer.java @@ -28,17 +28,16 @@ package com.sun.jmx.mbeanserver; import javax.management.MBeanServer; import javax.management.MBeanServerDelegate; -import com.sun.jmx.interceptor.MBeanServerInterceptor; /** - * Extends the MBeanServer and MBeanServerInterceptor interface to + * Extends the MBeanServer interface to * provide methods for getting the MetaData and MBeanServerInstantiator * objects associated with an MBeanServer. * * @since 1.5 */ public interface SunJmxMBeanServer - extends MBeanServerInterceptor, MBeanServer { + extends MBeanServer { /** * Return the MBeanInstantiator associated to this MBeanServer. @@ -68,7 +67,7 @@ public interface SunJmxMBeanServer * are not enabled on this object. * @see #interceptorsEnabled **/ - public MBeanServerInterceptor getMBeanServerInterceptor(); + public MBeanServer getMBeanServerInterceptor(); /** * Set the MBeanServerInterceptor. @@ -77,7 +76,7 @@ public interface SunJmxMBeanServer * are not enabled on this object. * @see #interceptorsEnabled **/ - public void setMBeanServerInterceptor(MBeanServerInterceptor interceptor); + public void setMBeanServerInterceptor(MBeanServer interceptor); /** *

Return the MBeanServerDelegate representing the MBeanServer. diff --git a/src/share/classes/com/sun/jmx/mbeanserver/Util.java b/src/share/classes/com/sun/jmx/mbeanserver/Util.java index b0f4f1dbfdec1668e1eea9dca1457d1734d5ce60..6307adbf8d92442278539c4377a7fe6d3d386c67 100644 --- a/src/share/classes/com/sun/jmx/mbeanserver/Util.java +++ b/src/share/classes/com/sun/jmx/mbeanserver/Util.java @@ -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,23 @@ import java.util.SortedSet; 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 char[] ILLEGAL_MBEANSERVER_NAME_CHARS=";:*?". + toCharArray(); + + static Map newMap() { return new HashMap(); } @@ -96,14 +110,6 @@ public class Util { return new ArrayList(c); } - public static ObjectName newObjectName(String s) { - try { - return new ObjectName(s); - } catch (MalformedObjectNameException e) { - throw new IllegalArgumentException(e); - } - } - /* This method can be used by code that is deliberately violating the * allowed checked casts. Rather than marking the whole method containing * the code with @SuppressWarnings, you can use a call to this method for @@ -145,6 +151,270 @@ public class Util { return hash; } + /** Match a part of 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. 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 ////...// matches ////...// + * only if n==q and for ( i = 1 => n) elt-i matches pat-i. + * + * In addition, if we encounter a pattern element which is exactly + * **, it can match any number of path-elements - but it must match at + * least one element. + * When we encounter such a meta-wildcard, we remember its position + * and the position in the string path, and we advance both the pattern + * and the string. Later, if we encounter a mismatch in pattern & string, + * we rewind the position in pattern to just after the meta-wildcard, + * and we backtrack the string to i+1 element after the position + * we had when we first encountered the meta-wildcard, i being the + * position when we last backtracked the string. + * + * The backtracking logic is an adaptation of the logic in wildmatch + * above. + * See test/javax/mangement/ObjectName/ApplyWildcardTest.java + * + * Note: this thing is called 'wild' - and that's for a reason ;-) + **/ + public static boolean wildpathmatch(String str, String pat) { + final int strlen = str.length(); + final int patlen = pat.length(); + int stri = 0; + int pati = 0; + + int starstri; // index for backtrack if "**" attempt fails + int starpati; // index for backtrack if "**" attempt fails + + starstri = starpati = -1; + + while (true) { + // System.out.println("pati="+pati+", stri="+stri); + final int strend = str.indexOf(NAMESPACE_SEPARATOR, stri); + final int patend = pat.indexOf(NAMESPACE_SEPARATOR, pati); + + // no // remaining in either string or pattern: simple wildmatch + // until end of string. + if (strend == -1 && patend == -1) { + // System.out.println("last sub pattern, last sub element..."); + // System.out.println("wildmatch("+str.substring(stri,strlen)+ + // ","+pat.substring(pati,patlen)+")"); + return wildmatch(str,pat,stri,strlen,pati,patlen); + } + + // no // remaining in string, but at least one remaining in + // pattern + // => no match + if (strend == -1) { + // System.out.println("pattern has more // than string..."); + return false; + } + + // strend is != -1, but patend might. + // detect wildcard ** + if (patend == pati+2 && pat.charAt(pati)=='*' && + pat.charAt(pati+1)=='*') { + // if we reach here we know that neither strend nor patend are + // equals to -1. + stri = strend + NAMESPACE_SEPARATOR_LENGTH; + pati = patend + NAMESPACE_SEPARATOR_LENGTH; + starpati = pati; // position just after **// in pattern + starstri = stri; // we eat 1 element in string, and remember + // the position for backtracking and eating + // one more element if needed. + // System.out.println("starpati="+pati); + continue; + } + + // This is a bit hacky: * can match // when // is at the end + // of the string, so we include the // delimiter in the pattern + // matching. Either we're in the middle of the path, so including + // // both at the end of the pattern and at the end of the string + // has no effect - match(*//,dfsd//) is equivalent to match(*,dfsd) + // or we're at the end of the pattern path, in which case + // including // at the end of the string will have the desired + // effect (provided that we detect the end of matching correctly, + // see further on). + // + final int endpat = + ((patend > -1)?patend+NAMESPACE_SEPARATOR_LENGTH:patlen); + final int endstr = + ((strend > -1)?strend+NAMESPACE_SEPARATOR_LENGTH:strlen); + + // if we reach the end of the pattern, or if elt-i & pat-i + // don't match, we have a mismatch. + + // Note: we know that strend != -1, therefore patend==-1 + // indicates a mismatch unless pattern can match + // a // at the end, and strend+2=strlen. + // System.out.println("wildmatch("+str.substring(stri,endstr)+","+ + // pat.substring(pati,endpat)+")"); + if (!wildmatch(str,pat,stri,endstr,pati,endpat)) { + + // System.out.println("nomatch"); + // if we have a mismatch and didn't encounter any meta-wildcard, + // we return false. String & pattern don't match. + if (starpati < 0) return false; + + // If we reach here, we had a meta-wildcard. + // We need to backtrack to the wildcard, and make it eat an + // additional string element. + // + stri = str.indexOf(NAMESPACE_SEPARATOR, starstri); + // System.out.println("eating one additional element? "+stri); + + // If there's no more elements to eat, string and pattern + // don't match => return false. + if (stri == -1) return false; + + // Backtrack to where we were when we last matched against + // the meta-wildcard, make it eat an additional path element, + // remember the new positions, and continue from there... + // + stri = stri + NAMESPACE_SEPARATOR_LENGTH; + starstri = stri; + pati = starpati; + // System.out.println("skiping to stri="+stri); + continue; + } + + // Here we know that strend > -1 but we can have patend == -1. + // + // So if we reach here, we know pat-i+//? has matched + // elt-i+// + // + // If patend==-1, we know that there was no delimiter + // at the end of the pattern, that we are at the last pattern, + // and therefore that pat-i has matched elt-i+// + // + // In that case we can consider that we have a match only if + // elt-i is also the last path element in the string, which is + // equivalent to saying that strend+2==strlen. + // + if (patend == -1 && starpati == -1) + return (strend+NAMESPACE_SEPARATOR_LENGTH==strlen); + + // patend != -1, or starpati > -1 so there remains something + // to match. + + // go to next pair: elt-(i+1) pat-(i+1); + stri = strend + NAMESPACE_SEPARATOR_LENGTH; + pati = (patend==-1)?pati:(patend + NAMESPACE_SEPARATOR_LENGTH); + } + } + + /** + * Returns true if the ObjectName's {@code domain} is selected by the + * given {@code pattern}. + */ + public static boolean isDomainSelected(String domain, String pattern) { + if (domain == null || pattern == null) + throw new IllegalArgumentException("null"); + return Util.wildpathmatch(domain,pattern); + } + /** * Filters a set of ObjectName according to a given pattern. * @@ -167,6 +437,34 @@ public class Util { return res; } + + /** + * Filters a set of ObjectInstance according to a given pattern. + * + * @param pattern the pattern that the returned names must match. + * @param all the set of instances to filter. + * @return a set of ObjectInstance from which non matching instances + * have been removed. + */ + public static Set + filterMatchingInstances(ObjectName pattern, + Set all) { + // If no pattern, just return all names + if (pattern == null + || all.isEmpty() + || ObjectName.WILDCARD.equals(pattern)) + return all; + + // If there's a pattern, do the matching. + final Set res = equivalentEmptySet(all); + for (ObjectInstance n : all) { + if (n == null) continue; + if (pattern.apply(n.getObjectName())) + res.add(n); + } + return res; + } + /** * An abstract ClassLoaderRepository that contains a single class loader. **/ @@ -216,6 +514,160 @@ public class Util { return new SingleClassLoaderRepository(loader); } + /** + * Returns the name of the given MBeanServer that should be put in a + * permission you need. + * This corresponds to the + * {@code *[;mbeanServerName=[;*]]} property + * embedded in the MBeanServerId attribute of the + * server's {@link MBeanServerDelegate}. + * + * @param server The MBean server + * @return the name of the MBeanServer, or "*" if the name couldn't be + * obtained, or {@value MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} + * if there was no name. + */ + public static String getMBeanServerSecurityName(MBeanServer server) { + final String notfound = "*"; + try { + final String mbeanServerId = (String) + server.getAttribute(MBeanServerDelegate.DELEGATE_NAME, + "MBeanServerId"); + final String found = extractMBeanServerName(mbeanServerId); + if (found.length()==0) + return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME; + return found; + } catch (Exception x) { + logshort("Failed to retrieve MBeanServerName for server, " + + "using \"*\"",x); + return notfound; + } + } + + /** + * Returns the name of the MBeanServer embedded in the given + * mbeanServerId. If the given mbeanServerId doesn't contain any name, + * an empty String is returned. + * The MBeanServerId is expected to be of the form: + * {@code *[;mbeanServerName=[;*]]} + * @param mbeanServerId The MBean server ID + * @return the name of the MBeanServer if found, or "" if the name was + * not present in the mbeanServerId. + */ + public static String extractMBeanServerName(String mbeanServerId) { + if (mbeanServerId==null) return ""; + final String beginMarker=";mbeanServerName="; + final String endMarker=";"; + final int found = mbeanServerId.indexOf(beginMarker); + if (found < 0) return ""; + final int start = found + beginMarker.length(); + final int stop = mbeanServerId.indexOf(endMarker, start); + return mbeanServerId.substring(start, + (stop < 0 ? mbeanServerId.length() : stop)); + } + + /** + * Insert the given mbeanServerName into the given mbeanServerId. + * If mbeanServerName is null, empty, or equals to "-", the returned + * mbeanServerId will not contain any mbeanServerName. + * @param mbeanServerId The mbeanServerId in which to insert + * mbeanServerName + * @param mbeanServerName The mbeanServerName + * @return an mbeanServerId containing the given mbeanServerName + * @throws IllegalArgumentException if mbeanServerId already contains + * a different name, or if the given mbeanServerName is not valid. + */ + public static String insertMBeanServerName(String mbeanServerId, + String mbeanServerName) { + final String found = extractMBeanServerName(mbeanServerId); + if (found.length() > 0 && + found.equals(checkServerName(mbeanServerName))) + return mbeanServerId; + if (found.length() > 0 && !isMBeanServerNameUndefined(found)) + throw new IllegalArgumentException( + "MBeanServerName already defined"); + if (isMBeanServerNameUndefined(mbeanServerName)) + return mbeanServerId; + final String beginMarker=";mbeanServerName="; + return mbeanServerId+beginMarker+checkServerName(mbeanServerName); + } + + /** + * Returns true if the given mbeanServerName corresponds to an + * undefined MBeanServerName. + * The mbeanServerName is considered undefined if it is one of: + * {@code null} or {@value MBeanServerFactory#DEFAULT_MBEANSERVER_NAME}. + * @param mbeanServerName The mbeanServerName, as returned by + * {@link #extractMBeanServerName(String)}. + * @return true if the given name corresponds to one of the forms that + * denotes an undefined MBeanServerName. + */ + public static boolean isMBeanServerNameUndefined(String mbeanServerName) { + return mbeanServerName == null || + MBeanServerFactory.DEFAULT_MBEANSERVER_NAME.equals(mbeanServerName); + } + /** + * Check that the provided mbeanServername is syntactically valid. + * @param mbeanServerName An mbeanServerName, or {@code null}. + * @return mbeanServerName, or {@value + * MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if {@code mbeanServerName} + * is {@code null}. + * @throws IllegalArgumentException if mbeanServerName contains illegal + * characters, or is empty, or is {@code "-"}. + * Illegal characters are {@link #ILLEGAL_MBEANSERVER_NAME_CHARS}. + */ + public static String checkServerName(String mbeanServerName) { + if ("".equals(mbeanServerName)) + throw new IllegalArgumentException( + "\"\" is not a valid MBean server name"); + if ("-".equals(mbeanServerName)) + throw new IllegalArgumentException( + "\"-\" is not a valid MBean server name"); + if (isMBeanServerNameUndefined(mbeanServerName)) + return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME; + for (char c : ILLEGAL_MBEANSERVER_NAME_CHARS) { + if (mbeanServerName.indexOf(c) >= 0) + throw new IllegalArgumentException( + "invalid character in MBeanServer name: "+c); + } + return mbeanServerName; + } + + /** + * Get the MBeanServer name that should be put in a permission you need. + * + * @param delegate The MBeanServerDelegate + * @return The MBeanServer name - or {@value + * MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if there was no name. + */ + public static String getMBeanServerSecurityName( + MBeanServerDelegate delegate) { + try { + final String serverName = delegate.getMBeanServerName(); + if (isMBeanServerNameUndefined(serverName)) + return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME; + return serverName; + } catch (Exception x) { + logshort("Failed to retrieve MBeanServerName from delegate, " + + "using \"*\"",x); + return "*"; + } + } + + // Log the exception and its causes without logging the stack trace. + // Use with care - it is usually preferable to log the whole stack trace! + // We don't want to log the whole stack trace here: logshort() is + // called in those cases where the exception might not be abnormal. + private static void logshort(String msg, Throwable t) { + if (JmxProperties.MISC_LOGGER.isLoggable(Level.FINE)) { + StringBuilder toprint = new StringBuilder(msg); + do { + toprint.append("\nCaused By: ").append(String.valueOf(t)); + } while ((t=t.getCause())!=null); + JmxProperties.MISC_LOGGER.fine(toprint.toString()); + } + } + public static Set cloneSet(Set set) { if (set instanceof SortedSet) { @SuppressWarnings("unchecked") @@ -232,10 +684,19 @@ public class Util { @SuppressWarnings("unchecked") SortedSet sset = (SortedSet) set; set = new TreeSet(sset.comparator()); - } else if (set != null) { - set = new HashSet(set.size()); } else set = new HashSet(); return set; } + + // This exception is used when wrapping a class that throws IOException + // in a class that doesn't. + // The typical example for this are JMXNamespaces, when the sub + // MBeanServer can be remote. + // + public static RuntimeException newRuntimeIOException(IOException io) { + final String msg = "Communication failed with underlying resource: "+ + io.getMessage(); + return new RuntimeException(msg,io); + } } diff --git a/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java b/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..7b88087a81c6ddc8bf19a64e8fab63a671a62f9f --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java @@ -0,0 +1,468 @@ +/* + * 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 com.sun.jmx.mbeanserver.Util; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.InstanceNotFoundException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanPermission; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerNotification; +import javax.management.MalformedObjectNameException; +import javax.management.Notification; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.QueryExp; +import javax.management.namespace.JMXDomain; + +/** + * A DomainInterceptor wraps a JMXDomain. + *

+ * This API is a Sun internal API and is subject to changes without notice. + *

+ * @since 1.7 + */ +public class DomainInterceptor extends HandlerInterceptor { + + // TODO: Ideally DomainInterceptor should be replaced by + // something at Repository level. + // The problem there will be that we may need to + // reinstantiate the 'queryPerformedByRepos' boolean + // [or we will need to wrap the repository in + // a 'RepositoryInterceptor'?] + // Also there's no real need for a DomainInterceptor to + // extend RewritingMBeanServerConnection. + + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + private final String domainName; + private volatile ObjectName ALL; + private final String serverName; + private volatile NotificationListener mbsListener; + + private static class PatternNotificationFilter + implements NotificationFilter { + + final ObjectName pattern; + public PatternNotificationFilter(ObjectName pattern) { + this.pattern = pattern==null?ObjectName.WILDCARD:pattern; + } + + public boolean isNotificationEnabled(Notification notification) { + if (!(notification instanceof MBeanServerNotification)) + return false; + final MBeanServerNotification mbsn = + (MBeanServerNotification) notification; + if (pattern.apply(mbsn.getMBeanName())) + return true; + return false; + } + + static final long serialVersionUID = 7409950927025262111L; + } + + /** + * Creates a new instance of NamespaceInterceptor + */ + public DomainInterceptor(String serverName, + JMXDomain handler, + String domainName) { + super(handler); + this.domainName = domainName; + this.serverName = serverName; + ALL = ObjectName.valueOf(domainName+":*"); + } + + @Override + public String toString() { + return this.getClass().getName()+"(parent="+serverName+ + ", domain="+this.domainName+")"; + } + + final void connectDelegate(final MBeanServerDelegate delegate) + throws InstanceNotFoundException { + final NotificationFilter filter = + new PatternNotificationFilter(getPatternFor(null)); + synchronized (this) { + if (mbsListener == null) { + mbsListener = new NotificationListener() { + public void handleNotification(Notification notification, + Object handback) { + if (filter.isNotificationEnabled(notification)) + delegate.sendNotification(notification); + } + }; + } + } + + getHandlerInterceptorMBean(). + addMBeanServerNotificationListener(mbsListener, filter); + } + + final void disconnectDelegate() + throws InstanceNotFoundException, ListenerNotFoundException { + final NotificationListener l; + synchronized (this) { + l = mbsListener; + if (l == null) return; + mbsListener = null; + } + getHandlerInterceptorMBean().removeMBeanServerNotificationListener(l); + } + + public final void addPostRegisterTask(Queue queue, + final MBeanServerDelegate delegate) { + if (queue == null) + throw new IllegalArgumentException("task queue must not be null"); + final Runnable task1 = new Runnable() { + public void run() { + try { + connectDelegate(delegate); + } catch (Exception x) { + throw new UnsupportedOperationException( + "notification forwarding",x); + } + } + }; + queue.add(task1); + } + + public final void addPostDeregisterTask(Queue queue, + final MBeanServerDelegate delegate) { + if (queue == null) + throw new IllegalArgumentException("task queue must not be null"); + final Runnable task1 = new Runnable() { + public void run() { + try { + disconnectDelegate(); + } catch (Exception x) { + throw new UnsupportedOperationException( + "notification forwarding",x); + } + } + }; + queue.add(task1); + } + + // No name conversion for JMXDomains... + // Throws IllegalArgumentException if targetName.getDomain() is not + // in the domain handled. + // + @Override + protected ObjectName toSource(ObjectName targetName) { + if (targetName == null) return null; + if (targetName.isDomainPattern()) return targetName; + final String targetDomain = targetName.getDomain(); + + // TODO: revisit this. RuntimeOperationsException may be better? + // + if (!targetDomain.equals(domainName)) + throw new IllegalArgumentException(targetName.toString()); + return targetName; + } + + // No name conversion for JMXDomains... + @Override + protected ObjectName toTarget(ObjectName sourceName) { + return sourceName; + } + + + + /** + * No rewriting: always return sources - stripping instances for which + * the caller doesn't have permissions. + **/ + @Override + Set processOutputInstances(Set sources) { + if (sources == null || sources.isEmpty() || !checkOn()) + return sources; + final Set res = Util.equivalentEmptySet(sources); + for (ObjectInstance o : sources) { + if (checkQuery(o.getObjectName(), "queryMBeans")) + res.add(o); + } + return res; + } + + + /** + * No rewriting: always return sourceNames - stripping names for which + * the caller doesn't have permissions. + **/ + @Override + Set processOutputNames(Set sourceNames) { + if (sourceNames == null || sourceNames.isEmpty() || !checkOn()) + return sourceNames; + final Set res = Util.equivalentEmptySet(sourceNames); + for (ObjectName o : sourceNames) { + if (checkQuery(o, "queryNames")) + res.add(o); + } + return res; + } + + /** No rewriting: always return source **/ + @Override + ObjectInstance processOutputInstance(ObjectInstance source) { + return source; + } + + @Override + public Set queryNames(ObjectName name, QueryExp query) { + try { + // We don't trust the wrapped JMXDomain... + final ObjectName pattern = getPatternFor(name); + final Set res = super.queryNames(pattern,query); + return Util.filterMatchingNames(pattern,res); + } catch (Exception x) { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("Unexpected exception raised in queryNames: "+x); + LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x); + return Collections.emptySet(); + } + } + + // Compute a new pattern which is a sub pattern of 'name' but only selects + // the MBeans in domain 'domainName' + // When we reach here, it has been verified that 'name' matches our domain + // name (done by DomainDispatchInterceptor) + private ObjectName getPatternFor(final ObjectName name) { + try { + if (name == null) return ALL; + if (name.getDomain().equals(domainName)) return name; + return name.withDomain(domainName); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(String.valueOf(name),x); + } + } + + @Override + public Set queryMBeans(ObjectName name, QueryExp query) { + try { + // We don't trust the wrapped JMXDomain... + final ObjectName pattern = getPatternFor(name); + final Set res = super.queryMBeans(pattern,query); + return Util.filterMatchingInstances(pattern,res); + } catch (Exception x) { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("Unexpected exception raised in queryNames: "+x); + LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x); + return Collections.emptySet(); + } + } + + @Override + public String getDefaultDomain() { + return domainName; + } + + @Override + public String[] getDomains() { + return new String[] {domainName}; + } + + // We call getMBeanCount() on the namespace rather than on the + // source server in order to avoid counting MBeans which are not + // in the domain. + @Override + public Integer getMBeanCount() { + return getHandlerInterceptorMBean().getMBeanCount(); + } + + private boolean checkOn() { + final SecurityManager sm = System.getSecurityManager(); + return (sm != null); + } + + // + // Implements permission checks. + // + @Override + void check(ObjectName routingName, String member, String action) { + if (!checkOn()) return; + final String act = (action==null)?"-":action; + if("queryMBeans".equals(act) || "queryNames".equals(act)) { + // This is tricky. check with 3 parameters is called + // by queryNames/queryMBeans before performing the query. + // At this point we must check with no class name. + // Therefore we pass a className of "-". + // The filtering will be done later - processOutputNames and + // processOutputInstance will call checkQuery. + // + check(routingName, "-", "-", act); + } else { + // This is also tricky: + // passing null here will cause check to retrieve the classname, + // if needed. + check(routingName, null, member, act); + } + } + + // + // Implements permission checks. + // + @Override + void checkCreate(ObjectName routingName, String className, String action) { + if (!checkOn()) return; + check(routingName,className,"-",action); + } + + // + // Implements permission checks. + // + void check(ObjectName routingName, String className, String member, + String action) { + if (!checkOn()) return; + final MBeanPermission perm; + + final String act = (action==null)?"-":action; + if ("getDomains".equals(act)) { // ES: OK + perm = new MBeanPermission(serverName,"-",member, + routingName,act); + } else { + final String clazz = + (className==null)?getClassName(routingName):className; + perm = new MBeanPermission(serverName,clazz,member, + routingName,act); + } + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(perm); + } + + String getClassName(ObjectName routingName) { + if (routingName == null || routingName.isPattern()) return "-"; + try { + return getHandlerInterceptorMBean().getSourceServer(). + getObjectInstance(routingName).getClassName(); + } catch (InstanceNotFoundException ex) { + LOG.finest("Can't get class name for "+routingName+ + ", using \"-\". Cause is: "+ex); + return "-"; + } + } + + // + // Implements permission filters for attributes... + // + @Override + AttributeList checkAttributes(ObjectName routingName, + AttributeList attributes, String action) { + if (!checkOn()) return attributes; + final String className = getClassName(routingName); + check(routingName,className,"-",action); + if (attributes == null || attributes.isEmpty()) return attributes; + final AttributeList res = new AttributeList(); + for (Attribute at : attributes.asList()) { + try { + check(routingName,className,at.getName(),action); + res.add(at); + } catch (SecurityException x) { // DLS: OK + continue; + } + } + return res; + } + + // + // Implements permission filters for attributes... + // + @Override + String[] checkAttributes(ObjectName routingName, String[] attributes, + String action) { + if (!checkOn()) return attributes; + final String className = getClassName(routingName); + check(routingName,className,"-",action); + if (attributes == null || attributes.length==0) return attributes; + final List res = new ArrayList(attributes.length); + for (String at : attributes) { + try { + check(routingName,className,at,action); + res.add(at); + } catch (SecurityException x) { // DLS: OK + continue; + } + } + return res.toArray(new String[res.size()]); + } + + // + // Implements permission filters for domains... + // + @Override + String[] checkDomains(String[] domains, String action) { + if (domains == null || domains.length==0 || !checkOn()) + return domains; + int count=0; + for (int i=0;i + * This API is a Sun internal API and is subject to changes without notice. + *

+ * @since 1.7 + */ +public abstract class HandlerInterceptor + extends RoutingMBeanServerConnection + implements MBeanServerInterceptor { + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + // The wrapped JMXNamespace + private final T handler; + + /** + * Creates a new instance of HandlerInterceptor + */ + public HandlerInterceptor(T handler) { + if (handler == null) throw new IllegalArgumentException("null"); + this.handler = handler; + } + + // + // The {@code source} connection is a connection to the MBeanServer + // that contains the actual MBeans. + // In the case of cascading, that would be a connection to the sub + // agent. Practically, this is JMXNamespace.getSourceServer(); + // + @Override + protected MBeanServer source() { + return handler.getSourceServer(); + } + + // The MBeanServer on which getClassLoader / getClassLoaderFor + // will be called. + // The NamespaceInterceptor overrides this method - so that it + // getClassLoader / getClassLoaderFor don't trigger the loop + // detection mechanism. + // + MBeanServer getServerForLoading() { + return source(); + } + + // The namespace or domain handler - this either a JMXNamespace or a + // a JMXDomain + T getHandlerInterceptorMBean() { + return handler; + } + + // If the underlying JMXNamespace throws an IO, the IO will be + // wrapped in a RuntimeOperationsException. + RuntimeException handleIOException(IOException x,String fromMethodName, + Object... params) { + // Must do something here? + if (LOG.isLoggable(Level.FINEST)) { + LOG.finest("IO Exception in "+fromMethodName+": "+x+ + " - "+" rethrowing as RuntimeOperationsException."); + } + throw new RuntimeOperationsException( + Util.newRuntimeIOException(x)); + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public AttributeList getAttributes(ObjectName name, String[] attributes) + throws InstanceNotFoundException, ReflectionException { + try { + final String[] authorized = + checkAttributes(name,attributes,"getAttribute"); + final AttributeList attrList = + super.getAttributes(name,authorized); + return attrList; + } catch (IOException ex) { + throw handleIOException(ex,"getAttributes",name,attributes); + } + } + + // From MBeanServer + public ClassLoader getClassLoaderFor(ObjectName mbeanName) + throws InstanceNotFoundException { + final ObjectName sourceName = toSourceOrRuntime(mbeanName); + try { + check(mbeanName,null,"getClassLoaderFor"); + return getServerForLoading().getClassLoaderFor(sourceName); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + + // From MBeanServer + public ClassLoader getClassLoader(ObjectName loaderName) + throws InstanceNotFoundException { + final ObjectName sourceName = toSourceOrRuntime(loaderName); + try { + check(loaderName,null,"getClassLoader"); + return getServerForLoading().getClassLoader(sourceName); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // From MBeanServer + public ObjectInstance registerMBean(Object object, ObjectName name) + throws InstanceAlreadyExistsException, MBeanRegistrationException, + NotCompliantMBeanException { + final ObjectName sourceName = newSourceMBeanName(name); + try { + checkCreate(name,object.getClass().getName(),"registerMBean"); + return processOutputInstance( + source().registerMBean(object,sourceName)); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public void removeNotificationListener(ObjectName name, ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + check(name,null,"removeNotificationListener"); + super.removeNotificationListener(name,listener); + } catch (IOException ex) { + throw handleIOException(ex,"removeNotificationListener",name,listener); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public String getDefaultDomain() { + try { + return super.getDefaultDomain(); + } catch (IOException ex) { + throw handleIOException(ex,"getDefaultDomain"); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public String[] getDomains() { + try { + check(null,null,"getDomains"); + final String[] domains = super.getDomains(); + return checkDomains(domains,"getDomains"); + } catch (IOException ex) { + throw handleIOException(ex,"getDomains"); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public Integer getMBeanCount() { + try { + return super.getMBeanCount(); + } catch (IOException ex) { + throw handleIOException(ex,"getMBeanCount"); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException { + try { + check(name, + (attribute==null?null:attribute.getName()), + "setAttribute"); + super.setAttribute(name,attribute); + } catch (IOException ex) { + throw handleIOException(ex,"setAttribute",name, attribute); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public Set queryNames(ObjectName name, QueryExp query) { + if (name == null) name=ObjectName.WILDCARD; + try { + checkPattern(name,null,"queryNames"); + return super.queryNames(name,query); + } catch (IOException ex) { + throw handleIOException(ex,"queryNames",name, query); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public Set queryMBeans(ObjectName name, QueryExp query) { + if (name == null) name=ObjectName.WILDCARD; + try { + checkPattern(name,null,"queryMBeans"); + return super.queryMBeans(name,query); + } catch (IOException ex) { + throw handleIOException(ex,"queryMBeans",name, query); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException { + try { + check(name, null, "isInstanceOf"); + return super.isInstanceOf(name, className); + } catch (IOException ex) { + throw handleIOException(ex,"isInstanceOf",name, className); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + try { + checkCreate(name, className, "instantiate"); + checkCreate(name, className, "registerMBean"); + return super.createMBean(className, name); + } catch (IOException ex) { + throw handleIOException(ex,"createMBean",className, name); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + try { + checkCreate(name, className, "instantiate"); + checkCreate(name, className, "registerMBean"); + return super.createMBean(className, name, loaderName); + } catch (IOException ex) { + throw handleIOException(ex,"createMBean",className, name, loaderName); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public Object getAttribute(ObjectName name, String attribute) + throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException { + try { + check(name, attribute, "getAttribute"); + return super.getAttribute(name, attribute); + } catch (IOException ex) { + throw handleIOException(ex,"getAttribute",name, attribute); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public void removeNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + check(name,null,"removeNotificationListener"); + super.removeNotificationListener(name, listener, filter, handback); + } catch (IOException ex) { + throw handleIOException(ex,"removeNotificationListener",name, + listener, filter, handback); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public void removeNotificationListener(ObjectName name, + NotificationListener listener, NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + check(name,null,"removeNotificationListener"); + super.removeNotificationListener(name, listener, filter, handback); + } catch (IOException ex) { + throw handleIOException(ex,"removeNotificationListener",name, + listener, filter, handback); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + check(name,null,"removeNotificationListener"); + super.removeNotificationListener(name, listener); + } catch (IOException ex) { + throw handleIOException(ex,"removeNotificationListener",name, + listener); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public void addNotificationListener(ObjectName name, + NotificationListener listener, NotificationFilter filter, + Object handback) throws InstanceNotFoundException { + try { + check(name,null,"addNotificationListener"); + super.addNotificationListener(name, listener, filter, handback); + } catch (IOException ex) { + throw handleIOException(ex,"addNotificationListener",name, + listener, filter, handback); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public void addNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException { + try { + check(name,null,"addNotificationListener"); + super.addNotificationListener(name, listener, filter, handback); + } catch (IOException ex) { + throw handleIOException(ex,"addNotificationListener",name, + listener, filter, handback); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public boolean isRegistered(ObjectName name) { + try { + return super.isRegistered(name); + } catch (IOException ex) { + throw handleIOException(ex,"isRegistered",name); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException { + try { + check(name, null, "unregisterMBean"); + super.unregisterMBean(name); + } catch (IOException ex) { + throw handleIOException(ex,"unregisterMBean",name); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, IntrospectionException, + ReflectionException { + try { + check(name, null, "getMBeanInfo"); + return super.getMBeanInfo(name); + } catch (IOException ex) { + throw handleIOException(ex,"getMBeanInfo",name); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException { + try { + check(name, null, "getObjectInstance"); + return super.getObjectInstance(name); + } catch (IOException ex) { + throw handleIOException(ex,"getObjectInstance",name); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public ObjectInstance createMBean(String className, ObjectName name, + Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException { + try { + checkCreate(name, className, "instantiate"); + checkCreate(name, className, "registerMBean"); + return super.createMBean(className, name, params, signature); + } catch (IOException ex) { + throw handleIOException(ex,"createMBean",className, name, + params, signature); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName, Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + try { + checkCreate(name, className, "instantiate"); + checkCreate(name, className, "registerMBean"); + return super.createMBean(className, name, loaderName, params, + signature); + } catch (IOException ex) { + throw handleIOException(ex,"createMBean",className, name,loaderName, + params, signature); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public AttributeList setAttributes(ObjectName name,AttributeList attributes) + throws InstanceNotFoundException, ReflectionException { + try { + final AttributeList authorized = + checkAttributes(name, attributes, "setAttribute"); + return super.setAttributes(name, authorized); + } catch (IOException ex) { + throw handleIOException(ex,"setAttributes",name, attributes); + } + } + + // From MBeanServerConnection: catch & handles IOException + @Override + public Object invoke(ObjectName name, String operationName, Object[] params, + String[] signature) + throws InstanceNotFoundException, MBeanException, ReflectionException { + try { + check(name, operationName, "invoke"); + return super.invoke(name, operationName, params, signature); + } catch (IOException ex) { + throw handleIOException(ex,"invoke",name, operationName, + params, signature); + } + } + + // + // These methods are inherited from MBeanServer.... + // + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className) + throws ReflectionException, MBeanException { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported instantiate method: " + + "trowing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className, ObjectName loaderName) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported method: instantiate(...) -" + + "throwing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className, Object[] params, + String[] signature) throws ReflectionException, MBeanException { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported method: instantiate(...) -" + + "throwing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public Object instantiate(String className, ObjectName loaderName, + Object[] params, String[] signature) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported method: instantiate(...) -" + + "throwing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + @Deprecated + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported method: deserialize(...) -" + + "throwing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + @Deprecated + public ObjectInputStream deserialize(String className, byte[] data) + throws OperationsException, ReflectionException { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported method: deserialize(...) -" + + "throwing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + @Deprecated + public ObjectInputStream deserialize(String className, + ObjectName loaderName, byte[] data) + throws InstanceNotFoundException, OperationsException, + ReflectionException { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported method: deserialize(...) -" + + "throwing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + /** + * This method should never be called. + * Throws UnsupportedOperationException. + */ + public ClassLoaderRepository getClassLoaderRepository() { + if (LOG.isLoggable(Level.FINE)) + LOG.fine("call to unsupported method: getClassLoaderRepository() -" + + "throwing UnsupportedOperationException"); + throw new UnsupportedOperationException("Not applicable."); + } + + static RuntimeException newUnsupportedException(String namespace) { + return new RuntimeOperationsException( + new UnsupportedOperationException( + "Not supported in this namespace: "+namespace)); + } + + /** + * A result might be excluded for security reasons. + */ + @Override + boolean excludesFromResult(ObjectName targetName, String queryMethod) { + return !checkQuery(targetName, queryMethod); + } + + + //---------------------------------------------------------------------- + // Hooks for checking permissions + //---------------------------------------------------------------------- + + /** + * This method is a hook to implement permission checking in subclasses. + * A subclass may override this method and throw a {@link + * SecurityException} if the permission is denied. + * + * @param routingName The name of the MBean in the enclosing context. + * This is of the form {@code //}. + * @param member The {@link + * javax.management.namespace.JMXNamespacePermission#getMember member} + * name. + * @param action The {@link + * javax.management.namespace.JMXNamespacePermission#getActions action} + * name. + * @throws SecurityException if the caller doesn't have the permission + * to perform the given action on the MBean pointed to + * by routingName. + */ + abstract void check(ObjectName routingName, + String member, String action); + + // called in createMBean and registerMBean + abstract void checkCreate(ObjectName routingName, String className, + String action); + + /** + * This is a hook to implement permission checking in subclasses. + * + * Checks that the caller has sufficient permission for returning + * information about {@code sourceName} in {@code action}. + * + * Subclass may override this method and return false if the caller + * doesn't have sufficient permissions. + * + * @param routingName The name of the MBean to include or exclude from + * the query, expressed in the enclosing context. + * This is of the form {@code //}. + * @param action one of "queryNames" or "queryMBeans" + * @return true if {@code sourceName} can be returned. + */ + abstract boolean checkQuery(ObjectName routingName, String action); + + /** + * This method is a hook to implement permission checking in subclasses. + * + * @param routingName The name of the MBean in the enclosing context. + * This is of the form {@code //}. + * @param attributes The list of attributes to check permission for. + * @param action one of "getAttribute" or "setAttribute" + * @return The list of attributes for which the callers has the + * appropriate {@link + * javax.management.namespace.JMXNamespacePermission}. + * @throws SecurityException if the caller doesn't have the permission + * to perform {@code action} on the MBean pointed to by routingName. + */ + abstract String[] checkAttributes(ObjectName routingName, + String[] attributes, String action); + + /** + * This method is a hook to implement permission checking in subclasses. + * + * @param routingName The name of the MBean in the enclosing context. + * This is of the form {@code //}. + * @param attributes The list of attributes to check permission for. + * @param action one of "getAttribute" or "setAttribute" + * @return The list of attributes for which the callers has the + * appropriate {@link + * javax.management.namespace.JMXNamespacePermission}. + * @throws SecurityException if the caller doesn't have the permission + * to perform {@code action} on the MBean pointed to by routingName. + */ + abstract AttributeList checkAttributes(ObjectName routingName, + AttributeList attributes, String action); + + /** + * This method is a hook to implement permission checking in subclasses. + * Checks that the caller as the necessary permissions to view the + * given domain. If not remove the domains for which the caller doesn't + * have permission from the list. + *

+ * 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; + } + + // A priori check for queryNames/queryMBeans/ + void checkPattern(ObjectName routingPattern, + String member, String action) { + // pattern is checked only at posteriori by checkQuery. + // checking it a priori usually doesn't work, because ObjectName.apply + // does not work between two patterns. + // We only check that we have the permission requested for 'action'. + check(null,null,action); + } + + + +} diff --git a/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java b/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..49f875144f2751604094023018b1c2678ba3dd06 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java @@ -0,0 +1,354 @@ +/* + * 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.Collections; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.ListenerNotFoundException; +import javax.management.MBeanServerConnection; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.event.EventClient; +import javax.management.event.EventClientDelegateMBean; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.remote.JMXAddressable; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXServiceURL; +import javax.security.auth.Subject; + +/** + * A collection of methods that provide JMXConnector wrappers for + * JMXRemoteNamepaces underlying connectors. + *

+ * This API is a Sun internal API and is subject to changes without notice. + *

+ * @since 1.7 + */ +public final class JMXNamespaceUtils { + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + + private static Map newWeakHashMap() { + return new WeakHashMap(); + } + + /** There are no instances of this class */ + private JMXNamespaceUtils() { + } + + // returns un unmodifiable view of a map. + public static Map unmodifiableMap(Map aMap) { + if (aMap == null || aMap.isEmpty()) + return Collections.emptyMap(); + return Collections.unmodifiableMap(aMap); + } + + + /** + * A base class that helps writing JMXConnectors that return + * MBeanServerConnection wrappers. + * This base class wraps an inner JMXConnector (the source), and preserve + * its caching policy. If a connection is cached in the source, its wrapper + * will be cached in this connector too. + * Author's note: rewriting this with java.lang.reflect.Proxy could be + * envisaged. It would avoid the combinatory sub-classing introduced by + * JMXAddressable. + *

+ * 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 connectionMap; + + + public JMXCachingConnector(JMXConnector source) { + this.source = checkNonNull(source, "source"); + connectionMap = newWeakHashMap(); + } + + private MBeanServerConnection + getCached(MBeanServerConnection inner) { + return connectionMap.get(inner); + } + + private MBeanServerConnection putCached(final MBeanServerConnection inner, + final MBeanServerConnection wrapper) { + if (inner == wrapper) return wrapper; + synchronized (this) { + final MBeanServerConnection concurrent = + connectionMap.get(inner); + if (concurrent != null) return concurrent; + connectionMap.put(inner,wrapper); + } + return wrapper; + } + + public void addConnectionNotificationListener(NotificationListener + listener, NotificationFilter filter, Object handback) { + source.addConnectionNotificationListener(listener,filter,handback); + } + + public void close() throws IOException { + source.close(); + } + + public void connect() throws IOException { + source.connect(); + } + + public void connect(Map env) throws IOException { + source.connect(env); + } + + public String getConnectionId() throws IOException { + return source.getConnectionId(); + } + + /** + * Preserve caching policy of the underlying connector. + **/ + public MBeanServerConnection + getMBeanServerConnection() throws IOException { + final MBeanServerConnection inner = + source.getMBeanServerConnection(); + final MBeanServerConnection cached = getCached(inner); + if (cached != null) return cached; + final MBeanServerConnection wrapper = wrap(inner); + return putCached(inner,wrapper); + } + + public MBeanServerConnection + getMBeanServerConnection(Subject delegationSubject) + throws IOException { + final MBeanServerConnection wrapped = + source.getMBeanServerConnection(delegationSubject); + synchronized (this) { + final MBeanServerConnection cached = getCached(wrapped); + if (cached != null) return cached; + final MBeanServerConnection wrapper = + wrapWithSubject(wrapped,delegationSubject); + return putCached(wrapped,wrapper); + } + } + + public void removeConnectionNotificationListener( + NotificationListener listener) + throws ListenerNotFoundException { + source.removeConnectionNotificationListener(listener); + } + + public void removeConnectionNotificationListener( + NotificationListener l, NotificationFilter f, + Object handback) throws ListenerNotFoundException { + source.removeConnectionNotificationListener(l,f,handback); + } + + /** + * This is the method that subclass will redefine. This method + * is called by {@code this.getMBeanServerConnection()}. + * {@code inner} is the connection returned by + * {@code source.getMBeanServerConnection()}. + **/ + protected MBeanServerConnection wrap(MBeanServerConnection inner) + throws IOException { + return inner; + } + + /** + * Subclass may also want to redefine this method. + * By default it calls wrap(inner). This method + * is called by {@code this.getMBeanServerConnection(Subject)}. + * {@code inner} is the connection returned by + * {@code source.getMBeanServerConnection(Subject)}. + **/ + protected MBeanServerConnection wrapWithSubject( + MBeanServerConnection inner, Subject delegationSubject) + throws IOException { + return wrap(inner); + } + + @Override + public String toString() { + if (source instanceof JMXAddressable) { + final JMXServiceURL address = + ((JMXAddressable)source).getAddress(); + if (address != null) + return address.toString(); + } + return source.toString(); + } + + } + + + /** + * The name space connector can do 'cd' + **/ + static class JMXNamespaceConnector extends JMXCachingConnector { + + // private static final long serialVersionUID = -4813611540843020867L; + + private final String toDir; + private final boolean closeable; + + public JMXNamespaceConnector(JMXConnector source, String toDir, + boolean closeable) { + super(source); + this.toDir = toDir; + this.closeable = closeable; + } + + @Override + public void close() throws IOException { + if (!closeable) + throw new UnsupportedOperationException("close"); + else super.close(); + } + + @Override + protected MBeanServerConnection wrap(MBeanServerConnection wrapped) + throws IOException { + if (LOG.isLoggable(Level.FINER)) + LOG.finer("Creating name space proxy connection for source: "+ + "namespace="+toDir); + return JMXNamespaces.narrowToNamespace(wrapped,toDir); + } + + @Override + public String toString() { + return "JMXNamespaces.narrowToNamespace("+ + super.toString()+ + ", \""+toDir+"\")"; + } + + } + + static class JMXEventConnector extends JMXCachingConnector { + + // private static final long serialVersionUID = 4742659236340242785L; + + JMXEventConnector(JMXConnector wrapped) { + super(wrapped); + } + + @Override + protected MBeanServerConnection wrap(MBeanServerConnection inner) + throws IOException { + return EventClient.getEventClientConnection(inner); + } + + + @Override + public String toString() { + return "EventClient.withEventClient("+super.toString()+")"; + } + } + + static class JMXAddressableEventConnector extends JMXEventConnector + implements JMXAddressable { + + // private static final long serialVersionUID = -9128520234812124712L; + + JMXAddressableEventConnector(JMXConnector wrapped) { + super(wrapped); + } + + public JMXServiceURL getAddress() { + return ((JMXAddressable)source).getAddress(); + } + } + + /** + * Creates a connector whose MBeamServerConnection will point to the + * given sub name space inside the source connector. + * @see JMXNamespace + **/ + public static JMXConnector cd(final JMXConnector source, + final String toNamespace, + final boolean closeable) + throws IOException { + + checkNonNull(source, "JMXConnector"); + + if (toNamespace == null || toNamespace.equals("")) + return source; + + return new JMXNamespaceConnector(source,toNamespace,closeable); + } + + + /** + * 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 source 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 source) { + checkNonNull(source, "JMXConnector"); + if (source instanceof JMXAddressable) + return new JMXAddressableEventConnector(source); + else + return new JMXEventConnector(source); + } + + public static T checkNonNull(T parameter, String name) { + if (parameter == null) + throw new IllegalArgumentException(name+" must not be null"); + return parameter; + } + + +} diff --git a/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java b/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..6862066d2bcd523eaae6e47ff3e462564eb5f828 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java @@ -0,0 +1,225 @@ +/* + * 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.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespacePermission; + +/** + * A NamespaceInterceptor wraps a JMXNamespace, performing + * ObjectName rewriting. + *

+ * This API is a Sun internal API and is subject to changes without notice. + *

+ * @since 1.7 + */ +public class NamespaceInterceptor extends HandlerInterceptor { + + + // The target name space in which the NamepsaceHandler is mounted. + private final String targetNs; + + private final String serverName; + + private final ObjectNameRouter proc; + + /** + * Creates a new instance of NamespaceInterceptor + */ + public NamespaceInterceptor( + String serverName, + JMXNamespace handler, + String targetNamespace) { + super(handler); + this.serverName = serverName; + this.targetNs = + ObjectNameRouter.normalizeNamespacePath(targetNamespace, + true, true, false); + proc = new ObjectNameRouter(targetNamespace, ""); + } + + @Override + public String toString() { + return this.getClass().getName()+"(parent="+serverName+ + ", namespace="+this.targetNs+")"; + } + + /** + * This method will send a probe to detect self-linking name spaces. + * A self linking namespace is a namespace that links back directly + * on itslef. Calling a method on such a name space always results + * in an infinite loop going through: + * [1]MBeanServer -> [2]NamespaceDispatcher -> [3]NamespaceInterceptor + * [4]JMXNamespace -> { network // or cd // or ... } -> [5]MBeanServer + * with exactly the same request than [1]... + * + * The namespace interceptor [2] tries to detect such condition the + * *first time* that the connection is used. It does so by setting + * a flag, and sending a queryNames() through the name space. If the + * queryNames comes back, it knows that there's a loop. + * + * The DynamicProbe interface can also be used by a Sun JMXNamespace + * implementation to request the emission of a probe at any time + * (see JMXRemoteNamespace implementation). + */ + private MBeanServer connection() { + final MBeanServer c = super.source(); + if (c != null) return c; + // should not come here + throw new NullPointerException("getMBeanServerConnection"); + } + + + @Override + protected MBeanServer source() { + return connection(); + } + + @Override + protected MBeanServer getServerForLoading() { + // don't want to send probe on getClassLoader/getClassLoaderFor + return super.source(); + } + + @Override + protected ObjectName toSource(ObjectName targetName) + throws MalformedObjectNameException { + return proc.toSourceContext(targetName, true); + } + + @Override + protected ObjectName toTarget(ObjectName sourceName) + throws MalformedObjectNameException { + return proc.toTargetContext(sourceName, false); + } + + // + // Implements permission checks. + // + @Override + void check(ObjectName routingName, String member, String action) { + final SecurityManager sm = System.getSecurityManager(); + if (sm == null) return; + if ("getDomains".equals(action)) return; + final JMXNamespacePermission perm = + new JMXNamespacePermission(serverName,member, + routingName,action); + sm.checkPermission(perm); + } + + @Override + void checkCreate(ObjectName routingName, String className, String action) { + final SecurityManager sm = System.getSecurityManager(); + if (sm == null) return; + final JMXNamespacePermission perm = + new JMXNamespacePermission(serverName,className, + routingName,action); + sm.checkPermission(perm); + } + + // + // Implements permission filters for attributes... + // + @Override + AttributeList checkAttributes(ObjectName routingName, + AttributeList attributes, String action) { + check(routingName,null,action); + if (attributes == null || attributes.isEmpty()) return attributes; + final SecurityManager sm = System.getSecurityManager(); + if (sm == null) return attributes; + final AttributeList res = new AttributeList(); + for (Attribute at : attributes.asList()) { + try { + check(routingName,at.getName(),action); + res.add(at); + } catch (SecurityException x) { // DLS: OK + continue; + } + } + return res; + } + + // + // Implements permission filters for attributes... + // + @Override + String[] checkAttributes(ObjectName routingName, String[] attributes, + String action) { + check(routingName,null,action); + if (attributes == null || attributes.length==0) return attributes; + final SecurityManager sm = System.getSecurityManager(); + if (sm == null) return attributes; + final List res = new ArrayList(attributes.length); + for (String at : attributes) { + try { + check(routingName,at,action); + res.add(at); + } catch (SecurityException x) { // DLS: OK + continue; + } + } + return res.toArray(new String[res.size()]); + } + + // + // Implements permission filters for domains... + // + @Override + String[] checkDomains(String[] domains, String action) { + // in principle, this method is never called because + // getDomains() will never be called - since there's + // no way that MBeanServer.getDomains() can be routed + // to a NamespaceInterceptor. + // + // This is also why there's no getDomains() in a + // JMXNamespacePermission... + // + return super.checkDomains(domains, action); + } + + // + // Implements permission filters for queries... + // + @Override + boolean checkQuery(ObjectName routingName, String action) { + try { + check(routingName,null,action); + return true; + } catch (SecurityException x) { // DLS: OK + return false; + } + } + +} diff --git a/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java b/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java new file mode 100644 index 0000000000000000000000000000000000000000..3c7065c478e323ad4f6262e8960424450e17851d --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java @@ -0,0 +1,191 @@ +/* + * 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 static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR; + +import javax.management.MalformedObjectNameException; +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +/** + * The ObjectNameRouter is used to rewrite routing object names. + *

+ * This API is a Sun internal API and is subject to changes without notice. + *

+ * @since 1.7 + */ +public class ObjectNameRouter { + + private static final int NAMESPACE_SEPARATOR_LENGTH = + NAMESPACE_SEPARATOR.length(); + + final String targetPrefix; + final String sourcePrefix; + final int slen; + final int tlen; + final boolean identity; + + + public ObjectNameRouter(String targetDirName) { + this(targetDirName,null); + } + + /** Creates a new instance of ObjectNameRouter */ + public ObjectNameRouter(final String remove, final String add) { + this.targetPrefix = (remove==null?"":remove); + this.sourcePrefix = (add==null?"":add); + tlen = targetPrefix.length(); + slen = sourcePrefix.length(); + identity = targetPrefix.equals(sourcePrefix); + } + + public final ObjectName toTargetContext(ObjectName sourceName, + boolean removeLeadingSeparators) { + if (sourceName == null) return null; + if (identity) return sourceName; + String srcDomain = sourceName.getDomain(); + + // if the ObjectName starts with // and removeLeadingSeparators is + // true, then recursively strip leading //. + // Otherwise, do not rewrite ObjectName. + // + if (srcDomain.startsWith(NAMESPACE_SEPARATOR)) { + if (!removeLeadingSeparators) return sourceName; + else srcDomain = normalizeDomain(srcDomain,true); + } + if (slen != 0) { + if (!srcDomain.startsWith(sourcePrefix) || + !srcDomain.startsWith(NAMESPACE_SEPARATOR,slen)) + throw new IllegalArgumentException( + "ObjectName does not start with expected prefix " + + sourcePrefix + ": " + + String.valueOf(sourceName)); + srcDomain = srcDomain.substring(slen+NAMESPACE_SEPARATOR_LENGTH); + } + final String targetDomain = + (tlen>0?targetPrefix+NAMESPACE_SEPARATOR+srcDomain:srcDomain); + try { + return sourceName.withDomain(targetDomain); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(String.valueOf(sourceName),x); + } + } + + public final ObjectName toSourceContext(ObjectName targetName, + boolean removeLeadingSeparators) { + if (targetName == null) return null; + if (identity) return targetName; + String targetDomain = targetName.getDomain(); + if (targetDomain.startsWith(NAMESPACE_SEPARATOR)) { + if (!removeLeadingSeparators) return targetName; + else targetDomain = + normalizeDomain(targetDomain,true); + } + if (tlen != 0) { + if (!targetDomain.startsWith(targetPrefix) || + !targetDomain.startsWith(NAMESPACE_SEPARATOR,tlen)) + throw new IllegalArgumentException( + "ObjectName does not start with expected prefix " + + targetPrefix + ": " + + String.valueOf(targetName)); + targetDomain = targetDomain. + substring(tlen+NAMESPACE_SEPARATOR_LENGTH); + } + final String sourceDomain = + (slen>0?sourcePrefix+NAMESPACE_SEPARATOR+targetDomain: + targetDomain); + try { + return targetName.withDomain(sourceDomain); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(String.valueOf(targetName),x); + } + } + + public final ObjectInstance toTargetContext(ObjectInstance sourceMoi, + boolean removeLeadingSeparators) { + if (sourceMoi == null) return null; + if (identity) return sourceMoi; + return new ObjectInstance( + toTargetContext(sourceMoi.getObjectName(), + removeLeadingSeparators), + sourceMoi.getClassName()); + } + + /** + * Removes leading, trailing, or duplicate // in a name space path. + **/ + public static String normalizeDomain(String domain, + boolean removeLeadingSep) { + return normalizeNamespacePath(domain,removeLeadingSep,false,true); + } + + /** + * Removes leading, trailing, or duplicate // in a name space path. + **/ + public static String normalizeNamespacePath(String namespacePath, + boolean removeLeadingSep, + boolean removeTrailingSep, + boolean endsWithDomain) { + if (namespacePath.equals("")) + return ""; + final String[] components = namespacePath.split(NAMESPACE_SEPARATOR); + final StringBuilder b = + new StringBuilder(namespacePath.length()+NAMESPACE_SEPARATOR_LENGTH); + String sep = null; + if (!removeLeadingSep && namespacePath.startsWith(NAMESPACE_SEPARATOR)) + b.append(NAMESPACE_SEPARATOR); + int count = 0; + for (int i=0; i 0) + b.append(NAMESPACE_SEPARATOR); + return b.toString(); + } + + +} diff --git a/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java b/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java new file mode 100644 index 0000000000000000000000000000000000000000..443c80f2ae56ad118e4d065d368ff72ac955746e --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java @@ -0,0 +1,123 @@ +/* + * 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.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.MBeanServerConnection; +import javax.management.namespace.JMXNamespaces; + + +/** + * A RoutingConnectionProxy is an MBeanServerConnection proxy that proxies a + * source name space in a source MBeanServerConnection. + * It wraps a source MBeanServerConnection, and rewrites routing + * ObjectNames. It is used to implement + * {@code JMXNamespaces.narrowToNamespace(MBeanServerConnection)}. + *

+ * This API is a Sun internal API and is subject to changes without notice. + *

+ * @since 1.7 + */ +// See class hierarchy and detailled explanations in RoutingProxy in this +// package. +// +public class RoutingConnectionProxy + extends RoutingProxy { + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + + /** + * Creates a new instance of RoutingConnectionProxy + */ + public RoutingConnectionProxy(MBeanServerConnection source, + String sourceDir) { + this(source,sourceDir,"",false); + } + + /** + * Creates a new instance of RoutingConnectionProxy + */ + public RoutingConnectionProxy(MBeanServerConnection source, + String sourceDir, + String targetDir, + boolean forwardsContext) { + super(source,sourceDir,targetDir,forwardsContext); + + if (LOG.isLoggable(Level.FINER)) + LOG.finer("RoutingConnectionProxy for " + getSourceNamespace() + + " created"); + } + + @Override + public String toString() { + final String targetNs = getTargetNamespace(); + final String sourceNs = getSourceNamespace(); + String wrapped = String.valueOf(source()); + if ("".equals(targetNs)) { + if (forwardsContext) + wrapped = "ClientContext.withDynamicContext("+wrapped+")"; + return "JMXNamespaces.narrowToNamespace("+ + wrapped+", \""+ + sourceNs+"\")"; + } + return this.getClass().getSimpleName()+"("+wrapped+", \""+ + sourceNs+"\", \""+ + targetNs+"\", "+forwardsContext+")"; + } + + static final RoutingProxyFactory + + FACTORY = new RoutingProxyFactory + () { + + public RoutingConnectionProxy newInstance(MBeanServerConnection source, + String sourcePath, String targetPath, + boolean forwardsContext) { + return new RoutingConnectionProxy(source,sourcePath, + targetPath,forwardsContext); + } + + public RoutingConnectionProxy newInstance( + MBeanServerConnection source, String sourcePath) { + return new RoutingConnectionProxy(source,sourcePath); + } + }; + + public static MBeanServerConnection cd(MBeanServerConnection source, + String sourcePath) { + return RoutingProxy.cd(RoutingConnectionProxy.class, FACTORY, + source, sourcePath); + } + +} diff --git a/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java b/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java new file mode 100644 index 0000000000000000000000000000000000000000..7022e7e297371a93b67530f23c791d870b3e3a47 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java @@ -0,0 +1,567 @@ +/* + * 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 com.sun.jmx.mbeanserver.Util; +import java.io.IOException; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.Set; +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.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.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.QueryExp; +import javax.management.ReflectionException; +import javax.management.RuntimeMBeanException; +import javax.management.RuntimeOperationsException; + +/** + * A RoutingMBeanServerConnection wraps a MBeanServerConnection, defining + * abstract methods that can be implemented by subclasses to rewrite + * routing ObjectNames. It is used to implement + * HandlerInterceptors (wrapping JMXNamespace instances) and routing + * proxies (used to implement cd operations). + *

+ * This API is a Sun internal API and is subject to changes without notice. + *

+ * @since 1.7 + */ +public abstract class RoutingMBeanServerConnection + implements MBeanServerConnection { + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + /** + * Creates a new instance of RoutingMBeanServerConnection + */ + public RoutingMBeanServerConnection() { + } + + /** + * Returns the wrapped source connection. The {@code source} connection + * is a connection to the MBeanServer that contains the actual MBean. + * In the case of cascading, that would be a connection to the sub + * agent. + **/ + protected abstract T source() throws IOException; + + /** + * Converts a target ObjectName to a source ObjectName. + * The target ObjectName is the name of the MBean in the mount point + * target. In the case of cascading, that would be the name of the + * MBean in the master agent. So if a subagent S containing an MBean + * named "X" is mounted in the target namespace "foo//" of a master agent M, + * the source is S, the target is "foo//" in M, the source name is "X", and + * the target name is "foo//X". + * In the case of cascading - such as in NamespaceInterceptor, this method + * will convert "foo//X" (the targetName) into "X", the source name. + **/ + protected abstract ObjectName toSource(ObjectName targetName) + throws MalformedObjectNameException; + + /** + * Converts a source ObjectName to a target ObjectName. + * (see description of toSource above for explanations) + * In the case of cascading - such as in NamespaceInterceptor, this method + * will convert "X" (the sourceName) into "foo//X", the target name. + **/ + protected abstract ObjectName toTarget(ObjectName sourceName) + throws MalformedObjectNameException; + + /** + * Can be overridden by subclasses to check the validity of a new + * ObjectName used in createMBean or registerMBean. + * This method is typically used by subclasses which might require + * special handling for "null"; + **/ + protected ObjectName newSourceMBeanName(ObjectName targetName) + throws MBeanRegistrationException { + try { + return toSource(targetName); + } catch (Exception x) { + throw new MBeanRegistrationException(x,"Illegal MBean Name"); + } + } + + // Calls toSource(), Wraps MalformedObjectNameException. + ObjectName toSourceOrRuntime(ObjectName targetName) + throws RuntimeOperationsException { + try { + return toSource(targetName); + } catch (MalformedObjectNameException x) { + final IllegalArgumentException x2 = + new IllegalArgumentException(String.valueOf(targetName),x); + final RuntimeOperationsException x3 = + new RuntimeOperationsException(x2); + throw x3; + } + } + + + // Wraps given exception if needed. + RuntimeException makeCompliantRuntimeException(Exception x) { + if (x instanceof SecurityException) return (SecurityException)x; + if (x instanceof JMRuntimeException) return (JMRuntimeException)x; + if (x instanceof RuntimeException) + return new RuntimeOperationsException((RuntimeException)x); + if (x instanceof IOException) + return Util.newRuntimeIOException((IOException)x); + // shouldn't come here... + final RuntimeException x2 = new UndeclaredThrowableException(x); + return new RuntimeOperationsException(x2); + } + + // from MBeanServerConnection + public AttributeList getAttributes(ObjectName name, String[] attributes) + throws InstanceNotFoundException, ReflectionException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + return source().getAttributes(sourceName, attributes); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public Object invoke(ObjectName name, String operationName, Object[] params, + String[] signature) + throws InstanceNotFoundException, MBeanException, ReflectionException, + IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + final Object result = + source().invoke(sourceName,operationName,params, + signature); + return result; + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException, + IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + source().unregisterMBean(sourceName); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, IntrospectionException, + ReflectionException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + return source().getMBeanInfo(sourceName); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + return processOutputInstance( + source().getObjectInstance(sourceName)); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public boolean isRegistered(ObjectName name) throws IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + return source().isRegistered(sourceName); + } catch (RuntimeMBeanException x) { + throw new RuntimeOperationsException(x.getTargetException()); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + // from MBeanServerConnection + public void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + source().setAttribute(sourceName,attribute); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public ObjectInstance createMBean(String className, + ObjectName name, ObjectName loaderName, + Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException, IOException { + final ObjectName sourceName = newSourceMBeanName(name); + // Loader Name is already a sourceLoaderName. + final ObjectName sourceLoaderName = loaderName; + try { + final ObjectInstance instance = + source().createMBean(className,sourceName, + sourceLoaderName, + params,signature); + return processOutputInstance(instance); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public ObjectInstance createMBean(String className, ObjectName name, + Object[] params, String[] signature) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, IOException { + final ObjectName sourceName = newSourceMBeanName(name); + try { + return processOutputInstance(source().createMBean(className, + sourceName,params,signature)); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException, IOException { + final ObjectName sourceName = newSourceMBeanName(name); + // Loader Name is already a source Loader Name. + final ObjectName sourceLoaderName = loaderName; + try { + return processOutputInstance(source().createMBean(className, + sourceName,sourceLoaderName)); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, IOException { + final ObjectName sourceName = newSourceMBeanName(name); + try { + return processOutputInstance(source(). + createMBean(className,sourceName)); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public Object getAttribute(ObjectName name, String attribute) + throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + return source().getAttribute(sourceName,attribute); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + return source().isInstanceOf(sourceName,className); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public AttributeList setAttributes(ObjectName name, AttributeList attributes) + throws InstanceNotFoundException, ReflectionException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + return source(). + setAttributes(sourceName,attributes); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // Return names in the target's context. + Set processOutputInstances(Set sources) { + + final Set result = Util.equivalentEmptySet(sources); + for (ObjectInstance i : sources) { + try { + final ObjectInstance target = processOutputInstance(i); + if (excludesFromResult(target.getObjectName(), "queryMBeans")) + continue; + result.add(target); + } catch (Exception x) { + if (LOG.isLoggable(Level.FINE)) { + LOG.fine("Skiping returned item: " + + "Unexpected exception while processing " + + "ObjectInstance: " + x); + } + continue; + } + } + return result; + } + + + // Return names in the target's context. + ObjectInstance processOutputInstance(ObjectInstance source) { + if (source == null) return null; + final ObjectName sourceName = source.getObjectName(); + try { + final ObjectName targetName = toTarget(sourceName); + return new ObjectInstance(targetName,source.getClassName()); + } catch (MalformedObjectNameException x) { + final IllegalArgumentException x2 = + new IllegalArgumentException(String.valueOf(sourceName),x); + final RuntimeOperationsException x3 = + new RuntimeOperationsException(x2); + throw x3; + } + } + + // Returns names in the target's context. + Set processOutputNames(Set sourceNames) { + + final Set names = Util.equivalentEmptySet(sourceNames); + for (ObjectName n : sourceNames) { + try { + final ObjectName targetName = toTarget(n); + if (excludesFromResult(targetName, "queryNames")) continue; + names.add(targetName); + } catch (Exception x) { + if (LOG.isLoggable(Level.FINE)) { + LOG.fine("Skiping returned item: " + + "Unexpected exception while processing " + + "ObjectInstance: " + x); + } + continue; + } + } + return names; + } + + // from MBeanServerConnection + public Set queryMBeans(ObjectName name, + QueryExp query) throws IOException { + if (name == null) name=ObjectName.WILDCARD; + final ObjectName sourceName = toSourceOrRuntime(name); + try { + return processOutputInstances( + source().queryMBeans(sourceName,query)); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + + public Set queryNames(ObjectName name, QueryExp query) + throws IOException { + if (name == null) name=ObjectName.WILDCARD; + final ObjectName sourceName = toSourceOrRuntime(name); + try { + final Set tmp = source().queryNames(sourceName,query); + final Set out = processOutputNames(tmp); + //System.err.println("queryNames: out: "+out); + return out; + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, + ListenerNotFoundException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + source().removeNotificationListener(sourceName,listener); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public void addNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + // Listener name is already a source listener name. + try { + source().addNotificationListener(sourceName,listener, + filter,handback); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public void addNotificationListener(ObjectName name, + NotificationListener listener, NotificationFilter filter, + Object handback) throws InstanceNotFoundException, IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + source().addNotificationListener(sourceName, listener, filter, + handback); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + + // from MBeanServerConnection + public void removeNotificationListener(ObjectName name, + NotificationListener listener, NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException, + IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + source().removeNotificationListener(sourceName,listener,filter, + handback); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public void removeNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, Object handback) + throws InstanceNotFoundException, ListenerNotFoundException, + IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + source().removeNotificationListener(sourceName,listener, + filter,handback); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public void removeNotificationListener(ObjectName name, ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException, + IOException { + final ObjectName sourceName = toSourceOrRuntime(name); + // listener name is already a source name... + final ObjectName sourceListener = listener; + try { + source().removeNotificationListener(sourceName,sourceListener); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public Integer getMBeanCount() throws IOException { + try { + return source().getMBeanCount(); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public String[] getDomains() throws IOException { + try { + return source().getDomains(); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // from MBeanServerConnection + public String getDefaultDomain() throws IOException { + try { + return source().getDefaultDomain(); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + /** + * Returns true if the given targetName must be excluded from the + * query result. + * In this base class, always return {@code false}. + * By default all object names returned by the sources are + * transmitted to the caller - there is no filtering. + * + * @param name A target object name expressed in the caller's + * context. In the case of cascading, where the source + * is a sub agent mounted on e.g. namespace "foo", + * that would be a name prefixed by "foo//"... + * @param queryMethod either "queryNames" or "queryMBeans". + * @return true if the name must be excluded. + */ + boolean excludesFromResult(ObjectName targetName, String queryMethod) { + return false; + } + +} diff --git a/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java b/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java new file mode 100644 index 0000000000000000000000000000000000000000..aa35c5bdaed56754d2591ed463b6632dc3a6f533 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java @@ -0,0 +1,413 @@ +/* + * 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.MBeanException; +import javax.management.MBeanRegistrationException; + +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespaces; + + +/** + * A 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 narrow down into an + * MBeanServerConnection.

+ *

{@link RoutingServerProxy}: to narrow down into an MBeanServer.

+ * + *

This class can also be used to "broaden" from a namespace. The same + * class is used for both purposes because in both cases all that happens + * is that ObjectNames are rewritten in one way on the way in (e.g. the + * parameter of getMBeanInfo) and another way on the way out (e.g. the + * return value of queryNames).

+ * + *

Specifically, if you narrow into "a//" then you want to add the + * "a//" prefix to ObjectNames on the way in and subtract it on the way + * out. But ClientContext uses this class to subtract the + * "jmx.context//foo=bar//" prefix on the way in and add it back on the + * way out.

+ * + *

+ * This API is a Sun internal API and is subject to changes without notice. + *

+ * @since 1.7 + */ +// +// RoutingProxies are client side objects which are used to narrow down +// into a namespace. They are used to perform ObjectName translation, +// adding the namespace to the routing ObjectName before sending it over +// to the source connection, and removing that prefix from results of +// queries, createMBean, registerMBean, and getObjectInstance. +// This translation is the opposite to that which is performed by +// NamespaceInterceptors. +// +// There is however a special case where routing proxies are used on the +// 'server' side to remove a namespace - rather than to add it: +// This the case of ClientContext. +// When an ObjectName like "jmx.context//c1=v1,c2=v2//D:k=v" reaches the +// jmx.context namespace, a routing proxy is used to remove the prefix +// c1=v1,c2=v2// from the routing objectname. +// +// For a RoutingProxy used in a narrowDownToNamespace operation, we have: +// targetNs="" // targetNS is the namespace 'to remove' +// sourceNS= // namespace 'to add' +// +// For a RoutingProxy used in a ClientContext operation, we have: +// targetNs= // context must be removed from object name +// sourceNs="" // nothing to add... +// +// RoutingProxies can also be used on the client side to implement +// "withClientContext" operations. In that case, the boolean parameter +// 'forwards context' is set to true, targetNs is "", and sourceNS may +// also be "". When forwardsContext is true, the RoutingProxy dynamically +// creates an ObjectNameRouter for each operation - in order to dynamically add +// the context attached to the thread to the routing ObjectName. This is +// performed in the getObjectNameRouter() method. +// +// Finally, in order to avoid too many layers of wrapping, +// RoutingConnectionProxy and RoutingServerProxy can be created through a +// factory method that can concatenate namespace pathes in order to +// return a single RoutingProxy - rather than wrapping a RoutingProxy inside +// another RoutingProxy. See RoutingConnectionProxy.cd and +// RoutingServerProxy.cd +// +// The class hierarchy is as follows: +// +// RoutingMBeanServerConnection +// [abstract class for all routing interceptors, +// such as RoutingProxies and HandlerInterceptors] +// / \ +// / \ +// RoutingProxy HandlerInterceptor +// [base class for [base class for server side +// client-side objects used objects, created by +// in narrowDownTo] DispatchInterceptors] +// / \ | \ +// RoutingConnectionProxy \ | NamespaceInterceptor +// [wraps MBeanServerConnection \ | [used to remove +// objects] \ | namespace prefix and +// RoutingServerProxy | wrap JMXNamespace] +// [wraps MBeanServer | +// Objects] | +// DomainInterceptor +// [used to wrap JMXDomain] +// +// RoutingProxies also differ from HandlerInterceptors in that they transform +// calls to MBeanServerConnection operations that do not have any parameters +// into a call to the underlying JMXNamespace MBean. +// So for instance a call to: +// JMXNamespaces.narrowDownToNamespace(conn,"foo").getDomains() +// is transformed into +// conn.getAttribute("foo//type=JMXNamespace","Domains"); +// +public abstract class RoutingProxy + extends RoutingMBeanServerConnection { + + /** + * A logger for this class. + **/ + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + // The source MBeanServerConnection + private final T source; + + // The name space we're narrowing to (usually some name space in + // the source MBeanServerConnection + private final String sourceNs; + + // The name space we pretend to be mounted in (usually "") + private final String targetNs; + + // The name of the JMXNamespace that handles the source name space + private final ObjectName handlerName; + private final ObjectNameRouter router; + final boolean forwardsContext; + private volatile String defaultDomain = null; + + /** + * Creates a new instance of RoutingProxy + */ + protected RoutingProxy(T source, + String sourceNs, + String targetNs, + boolean forwardsContext) { + if (source == null) throw new IllegalArgumentException("null"); + this.sourceNs = JMXNamespaces.normalizeNamespaceName(sourceNs); + + // Usually sourceNs is not null, except when implementing + // Client Contexts + // + if (sourceNs.equals("")) { + this.handlerName = null; + } else { + // System.err.println("sourceNs: "+sourceNs); + this.handlerName = + JMXNamespaces.getNamespaceObjectName(this.sourceNs); + try { + // System.err.println("handlerName: "+handlerName); + if (!source.isRegistered(handlerName)) + throw new IllegalArgumentException(sourceNs + + ": no such name space"); + } catch (IOException x) { + throw new IllegalArgumentException("source stale: "+x,x); + } + } + this.source = source; + this.targetNs = (targetNs==null?"": + JMXNamespaces.normalizeNamespaceName(targetNs)); + this.router = + new ObjectNameRouter(this.targetNs,this.sourceNs); + this.forwardsContext = forwardsContext; + + if (LOG.isLoggable(Level.FINER)) + LOG.finer("RoutingProxy for " + this.sourceNs + " created"); + } + + @Override + public T source() { return source; } + + ObjectNameRouter getObjectNameRouter() { +// TODO: uncomment this when contexts are added +// if (forwardsContext) +// return ObjectNameRouter.wrapWithContext(router); +// else + return router; + } + + @Override + public ObjectName toSource(ObjectName targetName) + throws MalformedObjectNameException { + if (targetName == null) return null; + if (targetName.getDomain().equals("") && targetNs.equals("")) { + try { + if (defaultDomain == null) + defaultDomain = getDefaultDomain(); + } catch(Exception x) { + LOG.log(Level.FINEST,"Failed to get default domain",x); + } + if (defaultDomain != null) + targetName = targetName.withDomain(defaultDomain); + } + final ObjectNameRouter r = getObjectNameRouter(); + return r.toSourceContext(targetName,true); + } + + @Override + protected ObjectName newSourceMBeanName(ObjectName targetName) + throws MBeanRegistrationException { + if (targetName != null) return super.newSourceMBeanName(targetName); + + // OK => we can accept null if sourceNs is empty. + if (sourceNs.equals("")) return null; + + throw new MBeanRegistrationException( + new IllegalArgumentException( + "Can't use null ObjectName with namespaces")); + } + + @Override + public ObjectName toTarget(ObjectName sourceName) + throws MalformedObjectNameException { + if (sourceName == null) return null; + final ObjectNameRouter r = getObjectNameRouter(); + return r.toTargetContext(sourceName,false); + } + + private Object getAttributeFromHandler(String attributeName) + throws IOException { + + try { + return source().getAttribute(handlerName,attributeName); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } catch (IOException x) { + throw x; + } catch (MBeanException ex) { + throw new IOException("Failed to get "+attributeName+": "+ + ex.getCause(), + ex.getCause()); + } catch (Exception ex) { + throw new IOException("Failed to get "+attributeName+": "+ + ex,ex); + } + } + + // We cannot call getMBeanCount() on the underlying + // MBeanServerConnection, because it would return the number of + // 'top-level' MBeans, not the number of MBeans in the name space + // we are narrowing to. Instead we're calling getMBeanCount() on + // the JMXNamespace that handles the source name space. + // + // There is however one particular case when the sourceNs is empty. + // In that case, there's no handler - and the 'source' is the top + // level namespace. In that particular case, handlerName will be null, + // and we directly invoke the top level source(). + // This later complex case is only used when implementing ClientContexts. + // + @Override + public Integer getMBeanCount() throws IOException { + try { + if (handlerName == null) return source().getMBeanCount(); + return (Integer) getAttributeFromHandler("MBeanCount"); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // We cannot call getDomains() on the underlying + // MBeanServerConnection, because it would return the domains of + // 'top-level' MBeans, not the domains of MBeans in the name space + // we are narrowing to. Instead we're calling getDomains() on + // the JMXNamespace that handles the source name space. + // + // There is however one particular case when the sourceNs is empty. + // In that case, there's no handler - and the 'source' is the top + // level namespace. In that particular case, handlerName will be null, + // and we directly invoke the top level source(). + // This later complex case is only used when implementing ClientContexts. + // + @Override + public String[] getDomains() throws IOException { + try { + if (handlerName == null) return source().getDomains(); + return (String[]) getAttributeFromHandler("Domains"); + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + // We cannot call getDefaultDomain() on the underlying + // MBeanServerConnection, because it would return the default domain of + // 'top-level' namespace, not the default domain in the name space + // we are narrowing to. Instead we're calling getDefaultDomain() on + // the JMXNamespace that handles the source name space. + // + // There is however one particular case when the sourceNs is empty. + // In that case, there's no handler - and the 'source' is the top + // level namespace. In that particular case, handlerName will be null, + // and we directly invoke the top level source(). + // This later complex case is only used when implementing ClientContexts. + // + @Override + public String getDefaultDomain() throws IOException { + try { + if (handlerName == null) { + defaultDomain = source().getDefaultDomain(); + } else { + defaultDomain =(String) + getAttributeFromHandler("DefaultDomain"); + } + return defaultDomain; + } catch (RuntimeException ex) { + throw makeCompliantRuntimeException(ex); + } + } + + public String getSourceNamespace() { + return sourceNs; + } + + public String getTargetNamespace() { + return targetNs; + } + + @Override + public String toString() { + return super.toString()+", sourceNs="+ + sourceNs + (targetNs.equals("")?"": + (" mounted on targetNs="+targetNs)); + } + + // Creates an instance of a subclass 'R' of RoutingProxy + // RoutingServerProxy and RoutingConnectionProxy have their own factory + // instance. + static interface RoutingProxyFactory> { + R newInstance(T source, + String sourcePath, String targetPath, + boolean forwardsContext); + R newInstance(T source, + String sourcePath); + } + + // Performs a narrowDownToNamespace operation. + // This method will attempt to merge two RoutingProxies in a single + // one if they are of the same class. + // + // This method is never called directly - it should be called only by + // subclasses of RoutingProxy. + // + // As for now it is called by: + // RoutingServerProxy.cd and RoutingConnectionProxy.cd. + // + static > + R cd(Class routingProxyClass, + RoutingProxyFactory factory, + T source, String sourcePath) { + if (source == null) throw new IllegalArgumentException("null"); + if (source.getClass().equals(routingProxyClass)) { + // cast is OK here, but findbugs complains unless we use class.cast + final R other = routingProxyClass.cast(source); + final String target = other.getTargetNamespace(); + + // Avoid multiple layers of serialization. + // + // We construct a new proxy from the original source instead of + // stacking a new proxy on top of the old one. + // - that is we replace + // cd ( cd ( x, dir1), dir2); + // by + // cd (x, dir1//dir2); + // + // We can do this only when the source class is exactly + // RoutingServerProxy. + // + if (target == null || target.equals("")) { + final String path = + JMXNamespaces.concat(other.getSourceNamespace(), + sourcePath); + return factory.newInstance(other.source(),path,"", + other.forwardsContext); + } + // Note: we could do possibly something here - but it would involve + // removing part of targetDir, and possibly adding + // something to sourcePath. + // Too complex to bother! => simply default to stacking... + } + return factory.newInstance(source,sourcePath); + } +} diff --git a/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java b/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java new file mode 100644 index 0000000000000000000000000000000000000000..f58e39816d34d61acf4a83026b81bc3fda1f2296 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java @@ -0,0 +1,590 @@ +/* + * 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.mbeanserver.Util; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.Collections; +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.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; +import javax.management.namespace.JMXNamespaces; + +/** + * A RoutingServerProxy is an MBeanServer proxy that proxies a + * source name space in a source MBeanServer. + * It wraps a source MBeanServer, and rewrites routing ObjectNames. + * It is typically use for implementing 'cd' operations, and + * will add the source name space to routing ObjectNames at input, + * and remove it at output. + *

+ * This API is a Sun internal API and is subject to changes without notice. + *

+ * + * @since 1.7 + */ +// See class hierarchy and detailled explanations in RoutingProxy in this +// package. +// +public class RoutingServerProxy + extends RoutingProxy + implements MBeanServer { + + /** + * Creates a new instance of RoutingServerProxy + */ + public RoutingServerProxy(MBeanServer source, + String sourceNs) { + this(source,sourceNs,"",false); + } + + public RoutingServerProxy(MBeanServer source, + String sourceNs, + String targetNs, + boolean forwardsContext) { + super(source,sourceNs,targetNs,forwardsContext); + } + + /** + * 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. + * 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 an + * {@link UndeclaredThrowableException} wrapping x. + **/ + protected RuntimeException handleIOException(IOException x, + String method) { + return Util.newRuntimeIOException(x); + } + + + //-------------------------------------------- + //-------------------------------------------- + // + // Implementation of the MBeanServer interface + // + //-------------------------------------------- + //-------------------------------------------- + @Override + public void addNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + try { + super.addNotificationListener(name, listener, + filter, handback); + } catch (IOException x) { + throw handleIOException(x,"addNotificationListener"); + } + } + + @Override + public void addNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException { + try { + super.addNotificationListener(name, listener, + filter, handback); + } catch (IOException x) { + throw handleIOException(x,"addNotificationListener"); + } + } + + @Override + public ObjectInstance createMBean(String className, ObjectName name) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException { + try { + return super.createMBean(className, name); + } catch (IOException x) { + throw handleIOException(x,"createMBean"); + } + } + + @Override + public ObjectInstance createMBean(String className, ObjectName name, + Object params[], String signature[]) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException { + try { + return super.createMBean(className, name, + params, signature); + } catch (IOException x) { + throw handleIOException(x,"createMBean"); + } + } + + @Override + public ObjectInstance createMBean(String className, + ObjectName name, + ObjectName loaderName) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException, + InstanceNotFoundException { + try { + return super.createMBean(className, name, loaderName); + } catch (IOException x) { + throw handleIOException(x,"createMBean"); + } + } + + @Override + public ObjectInstance createMBean(String className, + ObjectName name, + ObjectName loaderName, + Object params[], + String signature[]) + throws + ReflectionException, + InstanceAlreadyExistsException, + MBeanRegistrationException, + MBeanException, + NotCompliantMBeanException, + InstanceNotFoundException { + try { + return super.createMBean(className, name, loaderName, + params, signature); + } catch (IOException x) { + throw handleIOException(x,"createMBean"); + } + } + + /** + * @deprecated see {@link MBeanServer#deserialize(ObjectName,byte[]) + * MBeanServer} + **/ + @Deprecated + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException { + final ObjectName sourceName = toSourceOrRuntime(name); + try { + return source().deserialize(sourceName,data); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + /** + * @deprecated see {@link MBeanServer#deserialize(String,byte[]) + * MBeanServer} + */ + @Deprecated + public ObjectInputStream deserialize(String className, byte[] data) + throws OperationsException, ReflectionException { + try { + return source().deserialize(className,data); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + /** + * @deprecated see {@link MBeanServer#deserialize(String,ObjectName,byte[]) + * MBeanServer} + */ + @Deprecated + public ObjectInputStream deserialize(String className, + ObjectName loaderName, + byte[] data) + throws + InstanceNotFoundException, + OperationsException, + ReflectionException { + try { + return source().deserialize(className,loaderName,data); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + @Override + public Object getAttribute(ObjectName name, String attribute) + throws + MBeanException, + AttributeNotFoundException, + InstanceNotFoundException, + ReflectionException { + try { + return super.getAttribute(name, attribute); + } catch (IOException x) { + throw handleIOException(x,"getAttribute"); + } + } + + @Override + public AttributeList getAttributes(ObjectName name, String[] attributes) + throws InstanceNotFoundException, ReflectionException { + try { + return super.getAttributes(name, attributes); + } catch (IOException x) { + throw handleIOException(x,"getAttributes"); + } + } + + public ClassLoader getClassLoader(ObjectName loaderName) + throws InstanceNotFoundException { + final ObjectName sourceName = toSourceOrRuntime(loaderName); + try { + return source().getClassLoader(sourceName); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + public ClassLoader getClassLoaderFor(ObjectName mbeanName) + throws InstanceNotFoundException { + final ObjectName sourceName = toSourceOrRuntime(mbeanName); + try { + return source().getClassLoaderFor(sourceName); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + public ClassLoaderRepository getClassLoaderRepository() { + try { + return source().getClassLoaderRepository(); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + @Override + public String getDefaultDomain() { + try { + return super.getDefaultDomain(); + } catch (IOException x) { + throw handleIOException(x,"getDefaultDomain"); + } + } + + @Override + public String[] getDomains() { + try { + return super.getDomains(); + } catch (IOException x) { + throw handleIOException(x,"getDomains"); + } + } + + @Override + public Integer getMBeanCount() { + try { + return super.getMBeanCount(); + } catch (IOException x) { + throw handleIOException(x,"getMBeanCount"); + } + } + + @Override + public MBeanInfo getMBeanInfo(ObjectName name) + throws + InstanceNotFoundException, + IntrospectionException, + ReflectionException { + try { + return super.getMBeanInfo(name); + } catch (IOException x) { + throw handleIOException(x,"getMBeanInfo"); + } + } + + @Override + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException { + try { + return super.getObjectInstance(name); + } catch (IOException x) { + throw handleIOException(x,"getObjectInstance"); + } + } + + public Object instantiate(String className) + throws ReflectionException, MBeanException { + try { + return source().instantiate(className); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + public Object instantiate(String className, + Object params[], + String signature[]) + throws ReflectionException, MBeanException { + try { + return source().instantiate(className, + params,signature); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + public Object instantiate(String className, ObjectName loaderName) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + final ObjectName srcLoaderName = toSourceOrRuntime(loaderName); + try { + return source().instantiate(className,srcLoaderName); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + public Object instantiate(String className, ObjectName loaderName, + Object params[], String signature[]) + throws ReflectionException, MBeanException, + InstanceNotFoundException { + final ObjectName srcLoaderName = toSourceOrRuntime(loaderName); + try { + return source().instantiate(className,srcLoaderName, + params,signature); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + @Override + public Object invoke(ObjectName name, String operationName, + Object params[], String signature[]) + throws + InstanceNotFoundException, + MBeanException, + ReflectionException { + try { + return super.invoke(name,operationName,params,signature); + } catch (IOException x) { + throw handleIOException(x,"invoke"); + } + } + + @Override + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException { + try { + return super.isInstanceOf(name, className); + } catch (IOException x) { + throw handleIOException(x,"isInstanceOf"); + } + } + + @Override + public boolean isRegistered(ObjectName name) { + try { + return super.isRegistered(name); + } catch (IOException x) { + throw handleIOException(x,"isRegistered"); + } + } + + @Override + public Set queryMBeans(ObjectName name, QueryExp query) { + try { + return super.queryMBeans(name, query); + } catch (IOException x) { + handleIOException(x,"queryMBeans"); + return Collections.emptySet(); + } + } + + @Override + public Set queryNames(ObjectName name, QueryExp query) { + try { + return super.queryNames(name, query); + } catch (IOException x) { + handleIOException(x,"queryNames"); + return Collections.emptySet(); + } + } + + public ObjectInstance registerMBean(Object object, ObjectName name) + throws + InstanceAlreadyExistsException, + MBeanRegistrationException, + NotCompliantMBeanException { + final ObjectName sourceName = newSourceMBeanName(name); + try { + return processOutputInstance( + source().registerMBean(object,sourceName)); + } catch (RuntimeException x) { + throw makeCompliantRuntimeException(x); + } + } + + @Override + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + super.removeNotificationListener(name, listener); + } catch (IOException x) { + throw handleIOException(x,"removeNotificationListener"); + } + } + + @Override + public void removeNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + super.removeNotificationListener(name, listener, + filter, handback); + } catch (IOException x) { + throw handleIOException(x,"removeNotificationListener"); + } + } + + @Override + public void removeNotificationListener(ObjectName name, + ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + super.removeNotificationListener(name, listener); + } catch (IOException x) { + throw handleIOException(x,"removeNotificationListener"); + } + } + + @Override + public void removeNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object handback) + throws InstanceNotFoundException, ListenerNotFoundException { + try { + super.removeNotificationListener(name, listener, + filter, handback); + } catch (IOException x) { + throw handleIOException(x,"removeNotificationListener"); + } + } + + @Override + public void setAttribute(ObjectName name, Attribute attribute) + throws + InstanceNotFoundException, + AttributeNotFoundException, + InvalidAttributeValueException, + MBeanException, + ReflectionException { + try { + super.setAttribute(name, attribute); + } catch (IOException x) { + throw handleIOException(x,"setAttribute"); + } + } + + @Override + public AttributeList setAttributes(ObjectName name, + AttributeList attributes) + throws InstanceNotFoundException, ReflectionException { + try { + return super.setAttributes(name, attributes); + } catch (IOException x) { + throw handleIOException(x,"setAttributes"); + } + } + + @Override + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException { + try { + super.unregisterMBean(name); + } catch (IOException x) { + throw handleIOException(x,"unregisterMBean"); + } + } + + static final RoutingProxyFactory + FACTORY = new RoutingProxyFactory() { + + public RoutingServerProxy newInstance(MBeanServer source, + String sourcePath, String targetPath, + boolean forwardsContext) { + return new RoutingServerProxy(source,sourcePath, + targetPath,forwardsContext); + } + + public RoutingServerProxy newInstance( + MBeanServer source, String sourcePath) { + return new RoutingServerProxy(source,sourcePath); + } + }; + + public static MBeanServer cd(MBeanServer source, String sourcePath) { + return RoutingProxy.cd(RoutingServerProxy.class, FACTORY, + source, sourcePath); + } +} diff --git a/src/share/classes/com/sun/jmx/namespace/package.html b/src/share/classes/com/sun/jmx/namespace/package.html new file mode 100644 index 0000000000000000000000000000000000000000..6677288ca8848f26169bea168ca08fa2a3564568 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/package.html @@ -0,0 +1,45 @@ + + + + + The <code>com.sun.jmx.namespace</code> package + + + +

The com.sun.jmx.namespace package contains + sun specific implementation classes used to implement the + JMX namespaces. +

+

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 javax.management.namespace + package. +

+ + diff --git a/src/share/classes/com/sun/jmx/namespace/serial/DefaultRewritingProcessor.java b/src/share/classes/com/sun/jmx/namespace/serial/DefaultRewritingProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..f458378cbccb188cc1c6a4febca9859c3a10c469 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/serial/DefaultRewritingProcessor.java @@ -0,0 +1,150 @@ +/* + * 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 javax.management.ObjectInstance; +import javax.management.ObjectName; + +/** + * Class DefaultRewritingProcessor. Rewrite ObjectName in input & output + * parameters. + *

+ * This API is a Sun internal API and is subject to changes without notice. + *

+ * @since 1.7 + */ +// We know that rewriting using serialization is costly. +// This object tries to determine whether an object needs rewriting prior +// to rewriting, and rewrites by creating a new object in those cases +// where we know how to recreate a new object (e.g. a Notification). +// Rewriting is however usually not used - so this object is just a +// skeleton that eventually uses serialization... +// +class DefaultRewritingProcessor extends RewritingProcessor { + + + private static enum RewriteMode { + INPUT, // Input from target to source (parameters) + OUTPUT // Output from source to target (results) + }; + + private final boolean identity; + + public DefaultRewritingProcessor(String targetDirName) { + this(targetDirName,null); + } + + /** Creates a new instance of SerialParamProcessor */ + public DefaultRewritingProcessor(final String remove, final String add) { + super(new SerialRewritingProcessor(remove, add)); + identity = remove.equals(add); + } + + private ObjectName rewriteObjectName(RewriteMode mode, + ObjectName name) { + return changeContext(mode, name); + } + + private ObjectInstance rewriteObjectInstance(RewriteMode mode, + ObjectInstance moi) { + final ObjectName srcName = moi.getObjectName(); + final ObjectName targetName = changeContext(mode,srcName); + if (targetName == srcName) return moi; + return new ObjectInstance(targetName,moi.getClassName()); + } + + + private Object processObject(RewriteMode mode, Object obj) { + if (obj == null) return null; + + // Some things which will always needs rewriting: + // ObjectName, ObjectInstance, and Notifications. + // Take care of those we can handle here... + // + if (obj instanceof ObjectName) + return rewriteObjectName(mode,(ObjectName) obj); + else if (obj instanceof ObjectInstance) + return rewriteObjectInstance(mode,(ObjectInstance) obj); + + // TODO: add other standard JMX classes - like e.g. MBeanInfo... + // + + // Well, the object may contain an ObjectName => pass it to + // our serial rewriting delegate... + // + return processAnyObject(mode,obj); + } + + + private Object processAnyObject(RewriteMode mode, Object obj) { + switch (mode) { + case INPUT: + return super.rewriteInput(obj); + case OUTPUT: + return super.rewriteOutput(obj); + default: // can't happen. + throw new AssertionError(); + } + } + + private ObjectName changeContext(RewriteMode mode, ObjectName name) { + switch (mode) { + case INPUT: + return toSourceContext(name); + case OUTPUT: + return toTargetContext(name); + default: // can't happen. + throw new AssertionError(); + } + } + + @Override + public ObjectName toTargetContext(ObjectName srcName) { + if (identity) return srcName; + return super.toTargetContext(srcName); + } + + @Override + public ObjectName toSourceContext(ObjectName targetName) { + if (identity) return targetName; + return super.toSourceContext(targetName); + } + + @SuppressWarnings("unchecked") + @Override + public T rewriteInput(T input) { + if (identity) return input; + return (T) processObject(RewriteMode.INPUT,input); + } + + @SuppressWarnings("unchecked") + @Override + public T rewriteOutput(T result) { + if (identity) return result; + return (T) processObject(RewriteMode.OUTPUT,result); + } +} diff --git a/src/share/classes/com/sun/jmx/namespace/serial/IdentityProcessor.java b/src/share/classes/com/sun/jmx/namespace/serial/IdentityProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..32cca2d2dc429c001118bba8f9ede81db06e5d5f --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/serial/IdentityProcessor.java @@ -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 javax.management.ObjectInstance; +import javax.management.ObjectName; + +/** + * Class RoutingOnlyProcessor. 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 IdentityProcessor extends RewritingProcessor { + + + /** Creates a new instance of SerialRewritingProcessor */ + public IdentityProcessor() { + } + + @Override + public T rewriteOutput(T result) { + return result; + } + + @Override + public T rewriteInput(T input) { + return input; + } + + @Override + public final ObjectName toTargetContext(ObjectName sourceName) { + return sourceName; + } + + @Override + public final ObjectInstance toTargetContext(ObjectInstance sourceMoi) { + return sourceMoi; + } + + @Override + public final ObjectName toSourceContext(ObjectName targetName) { + return targetName; + } + +} diff --git a/src/share/classes/com/sun/jmx/namespace/serial/JMXNamespaceContext.java b/src/share/classes/com/sun/jmx/namespace/serial/JMXNamespaceContext.java new file mode 100644 index 0000000000000000000000000000000000000000..6416bfb9644de69a7e30c2dd4b06116b3b398ddd --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/serial/JMXNamespaceContext.java @@ -0,0 +1,145 @@ +/* + * 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.defaults.JmxProperties; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * The JMXNamespaceContext class is used to implement a thread local + * serialization / deserialization context for namespaces. + *

+ * 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. + *

+ * @since 1.7 + */ +public class JMXNamespaceContext { + + private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; + + public final String prefixToRemove; + public final String prefixToAdd; + + private JMXNamespaceContext(String add, String remove) { + prefixToRemove = (remove==null?"":remove); + prefixToAdd = (add==null?"":add); + } + + private final static class SerialContext { + private JMXNamespaceContext serializationContext; + private JMXNamespaceContext deserializationContext; + public SerialContext(){ + serializationContext = new JMXNamespaceContext("",""); + deserializationContext = new JMXNamespaceContext("",""); + } + } + + private final static ThreadLocal prefix = + new ThreadLocal() { + @Override + protected SerialContext initialValue() { + return new SerialContext(); + } + }; + + public static JMXNamespaceContext getSerializationContext() { + return prefix.get().serializationContext; + } + + public static JMXNamespaceContext getDeserializationContext() { + return prefix.get().deserializationContext; + } + + private static String[] setSerializationContext(String oldPrefix, + String newPrefix) { + final SerialContext c = prefix.get(); + JMXNamespaceContext dc = c.serializationContext; + String[] old = {dc.prefixToRemove, dc.prefixToAdd}; + c.serializationContext = new JMXNamespaceContext(newPrefix,oldPrefix); + return old; + } + + private static String[] setDeserializationContext(String oldPrefix, + String newPrefix) { + final SerialContext c = prefix.get(); + JMXNamespaceContext dc = c.deserializationContext; + String[] old = {dc.prefixToRemove, dc.prefixToAdd}; + c.deserializationContext = new JMXNamespaceContext(newPrefix,oldPrefix); + return old; + } + + static void serialize(ObjectOutputStream stream, Object obj, + String prefixToRemove, String prefixToAdd) + throws IOException { + final String[] old = + setSerializationContext(prefixToRemove,prefixToAdd); + try { + stream.writeObject(obj); + } finally { + try { + setSerializationContext(old[0],old[1]); + } catch (Exception x) { + LOG.log(Level.FINEST, + "failed to restore serialization context",x); + } + } + } + + static Object deserialize(ObjectInputStream stream, + String prefixToRemove, + String prefixToAdd) + throws IOException, ClassNotFoundException { + final String[] old = + setDeserializationContext(prefixToRemove,prefixToAdd); + try { + return stream.readObject(); + } finally { + try { + setDeserializationContext(old[0],old[1]); + } catch (Exception x) { + LOG.log(Level.FINEST, + "failed to restore serialization context",x); + } + } + } + +} diff --git a/src/share/classes/com/sun/jmx/namespace/serial/RewritingProcessor.java b/src/share/classes/com/sun/jmx/namespace/serial/RewritingProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..2c81be934c5a719a28df121fcec06e2dcf8029d0 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/serial/RewritingProcessor.java @@ -0,0 +1,362 @@ +/* + * 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 javax.management.ObjectInstance; +import javax.management.ObjectName; + +/** + * An object that can rewrite ObjectNames contained in input/output + * parameters when entering/leaving a {@link javax.management.namespace + * namespace}. + *

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.
+ * 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}. + *

+ *

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: + *

+ * public class MyRewritingProcessor extends RewritingProcessor {
+ *      MyRewritingProcessor(String remove, String add) {
+ *          this(RewritingProcessor.newRewritingProcessor(remove,add));
+ *      }
+ *      MyRewritingProcessor(RewritingProcessor delegate) {
+ *          super(delegate);
+ *      }
+ *
+ *   T rewriteInput(T input) {
+ *          if (input == null) return null;
+ *          if (MyClass.equals(input.getClass())) {
+ *              // I know that MyClass doesn't contain any ObjectName
+ *              return (T) input;
+ *          }
+ *          return super.rewriteInput(input);
+ *      }
+ *   T rewriteOutput(T result) {
+ *          if (result == null) return null;
+ *          if (MyClass.equals(result.getClass())) {
+ *              // I know that MyClass doesn't contain any ObjectName
+ *              return (T) result;
+ *          }
+ *          return super.rewriteOutput(result);
+ *      }
+ * }
+ * 
+ *

+ *

Such a subclass may also provide an alternate way of rewriting + * custom subclasses for which rewriting is needed - for instance: + *

+ * public class MyRewritingProcessor extends RewritingProcessor {
+ *      MyRewritingProcessor(String remove, String add) {
+ *          this(RewritingProcessor.newRewritingProcessor(remove,add));
+ *      }
+ *      MyRewritingProcessor(RewritingProcessor delegate) {
+ *          super(delegate);
+ *      }
+ *
+ *   T rewriteInput(T input) {
+ *          if (input == null) return null;
+ *          if (MyClass.equals(input.getClass())) {
+ *              // I know that MyClass doesn't contain any ObjectName
+ *              return (T) input;
+ *          } else if (MyOtherClass.equals(input.getClass())) {
+ *              // Returns a new instance in which ObjectNames have been
+ *              // replaced.
+ *              final ObjectName aname = ((MyOtherClass)input).getName();
+ *              return (T) (new MyOtherClass(super.rewriteInput(aname)));
+ *          }
+ *          return super.rewriteInput(input,clp);
+ *      }
+ *   T rewriteOutput(T result) {
+ *          if (result == null) return null;
+ *          if (MyClass.equals(result.getClass())) {
+ *              // I know that MyClass doesn't contain any ObjectName
+ *              return (T) result;
+ *          } else if (MyOtherClass.equals(result.getClass())) {
+ *              // Returns a new instance in which ObjectNames have been
+ *              // replaced.
+ *              final ObjectName aname = ((MyOtherClass)result).getName();
+ *              return (T) (new MyOtherClass(super.rewriteOutput(aname)));
+ *          }
+ *          return super.rewriteOutput(result,clp);
+ *      }
+ * }
+ * 
+ *

+ *

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 T rewriteOutput(T obj) { + if (obj == null) return null; + if (delegate != null) + return delegate.rewriteOutput(obj); + throw new IllegalArgumentException("can't rewrite "+ + obj.getClass().getName()); + } + + /** + * Rewrites ObjectNames when {@link RewritingProcessor entering} 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.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 T rewriteInput(T obj) { + if (obj == null) return null; + if (delegate != null) + return delegate.rewriteInput(obj); + throw new IllegalArgumentException("can't rewrite "+ + obj.getClass().getName()); + } + + /** + * Translate a routing ObjectName from the target (calling) context to + * the source (called) context when {@link RewritingProcessor entering} 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.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 --git a/src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java b/src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..1df2e26a9c87201994db787ae1924fb5ff94f78e --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java @@ -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 --git a/src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java b/src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..d7e879822e379247c98122411432177df91d8fe1 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java @@ -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 { + Queue> classQueue = new LinkedList>(); + + CloneOutput(OutputStream out) throws IOException { + super(out); + } + + @Override + protected void annotateClass(Class c) { + classQueue.add(c); + } + + @Override + protected void annotateProxyClass(Class c) { + classQueue.add(c); + } + } + + private static class CloneInput extends ObjectInputStream { + private final CloneOutput output; + + CloneInput(InputStream in, CloneOutput output) throws IOException { + super(in); + this.output = output; + } + + @Override + protected Class resolveClass(ObjectStreamClass osc) + throws IOException, ClassNotFoundException { + Class c = output.classQueue.poll(); + String expected = osc.getName(); + String found = (c == null) ? null : c.getName(); + if (!expected.equals(found)) { + throw new InvalidClassException("Classes desynchronized: " + + "found " + found + " when expecting " + expected); + } + return c; + } + + @Override + protected Class resolveProxyClass(String[] interfaceNames) + throws IOException, ClassNotFoundException { + return output.classQueue.poll(); + } + } + + + final String targetPrefix; + final String sourcePrefix; + final boolean identity; + + + public SerialRewritingProcessor(String targetDirName) { + this(targetDirName,null); + } + + /** Creates a new instance of SerialRewritingProcessor */ + public SerialRewritingProcessor(final String remove, final String add) { + super(new RoutingOnlyProcessor(remove,add)); + this.targetPrefix = remove; + this.sourcePrefix = add; + identity = targetPrefix.equals(sourcePrefix); + } + + private T switchContext(T result, String from,String to) + throws IOException, ClassNotFoundException { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final CloneOutput ostream = new CloneOutput(baos); + + JMXNamespaceContext.serialize(ostream,result,from,null); + ostream.flush(); + + final byte[] bytes = baos.toByteArray(); + final ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + final CloneInput istream = new CloneInput(bais, ostream); + @SuppressWarnings("unchecked") + final T clone = (T) JMXNamespaceContext.deserialize(istream,null,to); + return clone; + } + + @Override + @SuppressWarnings("unchecked") + public T rewriteOutput(T result) { + if (identity) return result; + return (T) processOutput(result); + } + + private Object processOutput(Object result) { + try { + if (result instanceof ObjectName) + return toTargetContext((ObjectName) result); + return switchContext(result,sourcePrefix,targetPrefix); + } catch (ClassNotFoundException x) { + throw new IllegalArgumentException("Can't process result: "+x,x); + } catch (IOException x) { + throw new IllegalArgumentException("Can't process result: "+x,x); + } + } + + @Override + @SuppressWarnings("unchecked") + public T rewriteInput(T input) { + if (identity) return input; + return (T) processInput(input); + } + + private Object processInput(Object input) { + try { + if (input instanceof ObjectName) + return toSourceContext((ObjectName) input); + return switchContext(input,targetPrefix,sourcePrefix); + } catch (ClassNotFoundException x) { + throw new IllegalArgumentException("Can't process input: "+x,x); + } catch (IOException x) { + throw new IllegalArgumentException("Can't process input: "+x,x); + } + } + +} diff --git a/src/share/classes/com/sun/jmx/namespace/serial/package.html b/src/share/classes/com/sun/jmx/namespace/serial/package.html new file mode 100644 index 0000000000000000000000000000000000000000..fe2e8c64b9407d3eba97d0aa18c11c7cc9c9b174 --- /dev/null +++ b/src/share/classes/com/sun/jmx/namespace/serial/package.html @@ -0,0 +1,44 @@ + + + + + The <code>com.sun.jmx.namespace.serial</code> package + + + +

The 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 +

+ + diff --git a/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java b/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java index a6635aad8bd4f298bec3a4d2c2227caa8640a8c8..f90cbc4c50af710321c72d5109a7ed15a347dddd 100644 --- a/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java +++ b/src/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java @@ -32,13 +32,15 @@ import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; public abstract class ClientCommunicatorAdmin { + private static volatile long threadNo = 1; + public ClientCommunicatorAdmin(long period) { this.period = period; if (period > 0) { checker = new Checker(); - Thread t = new Thread(checker); + Thread t = new Thread(checker, "JMX client heartbeat " + ++threadNo); t.setDaemon(true); t.start(); } else diff --git a/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java b/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java index 2a140c2fecfa0c5b6e47c03035e5db6a5648dc33..c3542cc1d8a676448928f9661525389940f860ad 100644 --- a/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java +++ b/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java @@ -57,6 +57,7 @@ import javax.security.auth.Subject; public class ServerNotifForwarder { + public ServerNotifForwarder(MBeanServer mbeanServer, Map env, NotificationBuffer notifBuffer, @@ -85,7 +86,8 @@ public class ServerNotifForwarder { // Explicitly check MBeanPermission for addNotificationListener // - checkMBeanPermission(name, "addNotificationListener"); + checkMBeanPermission(getMBeanServerName(), + mbeanServer, name, "addNotificationListener"); if (notificationAccessController != null) { notificationAccessController.addNotificationListener( connectionId, name, getSubject()); @@ -155,7 +157,8 @@ public class ServerNotifForwarder { // Explicitly check MBeanPermission for removeNotificationListener // - checkMBeanPermission(name, "removeNotificationListener"); + checkMBeanPermission(getMBeanServerName(), + mbeanServer, name, "removeNotificationListener"); if (notificationAccessController != null) { notificationAccessController.removeNotificationListener( connectionId, name, getSubject()); @@ -330,13 +333,7 @@ public class ServerNotifForwarder { * Explicitly check the MBeanPermission for * the current access control context. */ - private void checkMBeanPermission(final ObjectName name, - final String actions) - throws InstanceNotFoundException, SecurityException { - checkMBeanPermission(mbeanServer, name, actions); - } - - public static void checkMBeanPermission( + public static void checkMBeanPermission(String serverName, final MBeanServer mbs, final ObjectName name, final String actions) throws InstanceNotFoundException, SecurityException { SecurityManager sm = System.getSecurityManager(); @@ -355,7 +352,9 @@ public class ServerNotifForwarder { throw (InstanceNotFoundException) extractException(e); } String classname = oi.getClassName(); - MBeanPermission perm = new MBeanPermission(classname, + MBeanPermission perm = new MBeanPermission( + serverName, + classname, null, name, actions); @@ -370,8 +369,8 @@ public class ServerNotifForwarder { TargetedNotification tn) { try { if (checkNotificationEmission) { - checkMBeanPermission( - name, "addNotificationListener"); + checkMBeanPermission(getMBeanServerName(), + mbeanServer, name, "addNotificationListener"); } if (notificationAccessController != null) { notificationAccessController.fetchNotification( @@ -433,11 +432,27 @@ public class ServerNotifForwarder { } } + private String getMBeanServerName() { + if (mbeanServerName != null) return mbeanServerName; + else return (mbeanServerName = getMBeanServerName(mbeanServer)); + } + + private static String getMBeanServerName(final MBeanServer server) { + final PrivilegedAction action = new PrivilegedAction() { + public String run() { + return Util.getMBeanServerSecurityName(server); + } + }; + return AccessController.doPrivileged(action); + } + + //------------------ // PRIVATE VARIABLES //------------------ private MBeanServer mbeanServer; + private volatile String mbeanServerName; private final String connectionId; diff --git a/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java b/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java index b3520a408d5a24a1f4f7199be5577851ba5a28bb..d0f81e1d243f9bf9f84b9fa0cc862a5e53a14457 100644 --- a/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java +++ b/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java @@ -25,6 +25,7 @@ package com.sun.jmx.remote.util; +import com.sun.jmx.defaults.JmxProperties; import com.sun.jmx.event.EventClientFactory; import java.lang.reflect.InvocationHandler; @@ -45,6 +46,7 @@ import javax.management.NotificationListener; import javax.management.ObjectName; import javax.management.event.EventClient; import javax.management.event.EventClientDelegate; +import javax.management.namespace.JMXNamespaces; /** * Class EventClientConnection - a {@link Proxy} that wraps an @@ -63,12 +65,10 @@ public class EventClientConnection implements InvocationHandler, /** * A logger for this class. **/ - private static final Logger LOG = - Logger.getLogger(EventClientConnection.class.getName()); + private static final Logger LOG = JmxProperties.NOTIFICATION_LOGGER; - private static final String NAMESPACE_SEPARATOR = "//"; private static final int NAMESPACE_SEPARATOR_LENGTH = - NAMESPACE_SEPARATOR.length(); + JMXNamespaces.NAMESPACE_SEPARATOR.length(); /** * Creates a new {@code EventClientConnection}. @@ -212,9 +212,9 @@ public class EventClientConnection implements InvocationHandler, } final ObjectName mbean = (ObjectName) args[0]; - final EventClient client = getEventClient(); + final EventClient evtClient = getEventClient(); - // Fails if client is null AND the MBean we try to listen to is + // Fails if evtClient is null AND the MBean we try to listen to is // in a subnamespace. We fail here because we know this will not // work. // @@ -222,15 +222,15 @@ public class EventClientConnection implements InvocationHandler, // earlier agent (JDK 1.6 or earlier), then the EventClient will // be null (we can't use the event service with earlier JDKs). // - // In principle a null client indicates that the remote VM is of + // In principle a null evtClient indicates that the remote VM is of // an earlier version, in which case it shouldn't contain any namespace. // - // So having a null client AND an MBean contained in a namespace is + // So having a null evtClient AND an MBean contained in a namespace is // clearly an error case. // - if (client == null) { + if (evtClient == null) { final String domain = mbean.getDomain(); - final int index = domain.indexOf(NAMESPACE_SEPARATOR); + final int index = domain.indexOf(JMXNamespaces.NAMESPACE_SEPARATOR); if (index > -1 && index < (domain.length()-NAMESPACE_SEPARATOR_LENGTH)) { throw new UnsupportedOperationException(method.getName()+ @@ -256,9 +256,9 @@ public class EventClientConnection implements InvocationHandler, final NotificationFilter filter = (NotificationFilter) args[2]; final Object handback = args[3]; - if (client != null) { + if (evtClient != null) { // general case - client.addNotificationListener(mbean,listener,filter,handback); + evtClient.addNotificationListener(mbean,listener,filter,handback); } else { // deprecated case. Only works for mbean in local namespace. connection.addNotificationListener(mbean,listener,filter, @@ -274,9 +274,9 @@ public class EventClientConnection implements InvocationHandler, switch (nargs) { case 2: - if (client != null) { + if (evtClient != null) { // general case - client.removeNotificationListener(mbean,listener); + evtClient.removeNotificationListener(mbean,listener); } else { // deprecated case. Only works for mbean in local namespace. connection.removeNotificationListener(mbean, listener); @@ -286,8 +286,8 @@ public class EventClientConnection implements InvocationHandler, case 4: NotificationFilter filter = (NotificationFilter) args[2]; Object handback = args[3]; - if (client != null) { - client.removeNotificationListener(mbean, + if (evtClient != null) { + evtClient.removeNotificationListener(mbean, listener, filter, handback); diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/Init.java b/src/share/classes/com/sun/org/apache/xml/internal/security/Init.java index 845c36a5f4471c29781786aa6c979e4ebb2bfbb3..5b1acfd6aa23dfc7c8f65db3480fe851c38b74c9 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/Init.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/Init.java @@ -20,12 +20,9 @@ */ package com.sun.org.apache.xml.internal.security; - - import java.io.InputStream; import java.security.AccessController; import java.security.PrivilegedAction; - import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -51,7 +48,7 @@ import org.w3c.dom.Node; * done by calling {@link Init#init} which should be done in any static block * of the files of this library. We ensure that this call is only executed once. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public final class Init { @@ -113,20 +110,19 @@ public final class Init { dbf.setValidating(false); DocumentBuilder db = dbf.newDocumentBuilder(); - // We don't allow users to override the Apache XML Security // configuration in the JRE. Users should use the standard security // provider mechanism instead if implementing their own // transform or canonicalization algorithms. - // String cfile = System.getProperty("com.sun.org.apache.xml.internal.security.resource.config"); - // InputStream is = - // Class.forName("com.sun.org.apache.xml.internal.security.Init") - // .getResourceAsStream(cfile != null ? cfile : "resource/config.xml"); + // InputStream is = Class.forName("com.sun.org.apache.xml.internal.security.Init").getResourceAsStream("resource/config.xml"); InputStream is = (InputStream) AccessController.doPrivileged( new PrivilegedAction() { public Object run() { +// String cfile = System.getProperty +// ("com.sun.org.apache.xml.internal.security.resource.config"); return getClass().getResourceAsStream - ("resource/config.xml"); +// (cfile != null ? cfile : "resource/config.xml"); + ("resource/config.xml"); } }); @@ -167,7 +163,7 @@ public final class Init { // // if (tag.equals("ResourceBundles")){ // XX_configure_i18n_start = System.currentTimeMillis(); -// Element resource=(Element)el; +// Element resource=(Element)el; // /* configure internationalization */ // Attr langAttr = resource.getAttributeNode("defaultLanguageCode"); // Attr countryAttr = resource.getAttributeNode("defaultCountryCode"); @@ -202,11 +198,11 @@ public final class Init { if (currMeth.getDeclaringClass().getName() .equals(JAVACLASS)) { - log.log(java.util.logging.Level.FINE, currMeth.getDeclaringClass().toString()); + log.log(java.util.logging.Level.FINE, currMeth.getDe claringClass().toString()); } }*/ - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Canonicalizer.register(" + URI + ", " + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Canonicalizer.register(" + URI + ", " + JAVACLASS + ")"); Canonicalizer.register(URI, JAVACLASS); } catch (ClassNotFoundException e) { @@ -233,9 +229,8 @@ public final class Init { "JAVACLASS"); try { Class.forName(JAVACLASS); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Transform.register(" + URI + ", " + JAVACLASS - + ")"); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Transform.register(" + URI + ", " + JAVACLASS + ")"); Transform.register(URI, JAVACLASS); } catch (ClassNotFoundException e) { Object exArgs[] = { URI, JAVACLASS }; @@ -284,12 +279,11 @@ public final class Init { // // if (currMeth.getDeclaringClass().getName() // .equals(JAVACLASS)) { -// log.log(java.util.logging.Level.FINE, currMeth.getDeclaringClass().toString()); +// log.log(java.util.logging.Level.FINE, currMeth.getDe claringClass().toString()); // } // } - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "SignatureAlgorithm.register(" + URI + ", " - + JAVACLASS + ")"); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "SignatureAlgorithm.register(" + URI + ", " + JAVACLASS + ")"); SignatureAlgorithm.register(URI, JAVACLASS); } catch (ClassNotFoundException e) { Object exArgs[] = { URI, JAVACLASS }; @@ -320,13 +314,11 @@ public final class Init { "DESCRIPTION"); if ((Description != null) && (Description.length() > 0)) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS + ": " - + Description); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS + ": " + Description); } else { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS - + ": For unknown purposes"); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS + ": For unknown purposes"); } try { ResourceResolver.register(JAVACLASS); @@ -359,13 +351,11 @@ public final class Init { "DESCRIPTION"); if ((Description != null) && (Description.length() > 0)) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS + ": " - + Description); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS + ": " + Description); } else { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS - + ": For unknown purposes"); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Register Resolver: " + JAVACLASS + ": For unknown purposes"); } KeyResolver.register(JAVACLASS); @@ -376,8 +366,8 @@ public final class Init { if (tag.equals("PrefixMappings")){ XX_configure_reg_prefixes_start = System.currentTimeMillis(); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Now I try to bind prefixes:"); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Now I try to bind prefixes:"); Element[] nl = XMLUtils.selectNodes(el.getFirstChild(), CONF_NS,"PrefixMapping"); @@ -386,8 +376,8 @@ public final class Init { "namespace"); String prefix = nl[i].getAttributeNS(null, "prefix"); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Now I try to bind " + prefix + " to " + namespace); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Now I try to bind " + prefix + " to " + namespace); com.sun.org.apache.xml.internal.security.utils.ElementProxy .setDefaultPrefix(namespace, prefix); } @@ -398,19 +388,19 @@ public final class Init { long XX_init_end = System.currentTimeMillis(); //J- - if (true) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "XX_init " + ((int)(XX_init_end - XX_init_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_prng " + ((int)(XX_prng_end - XX_prng_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_parsing " + ((int)(XX_parsing_end - XX_parsing_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_i18n " + ((int)(XX_configure_i18n_end- XX_configure_i18n_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_c14n " + ((int)(XX_configure_reg_c14n_end- XX_configure_reg_c14n_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_jcemapper " + ((int)(XX_configure_reg_jcemapper_end- XX_configure_reg_jcemapper_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_keyInfo " + ((int)(XX_configure_reg_keyInfo_end- XX_configure_reg_keyInfo_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_keyResolver " + ((int)(XX_configure_reg_keyResolver_end- XX_configure_reg_keyResolver_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_prefixes " + ((int)(XX_configure_reg_prefixes_end- XX_configure_reg_prefixes_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_resourceresolver " + ((int)(XX_configure_reg_resourceresolver_end- XX_configure_reg_resourceresolver_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_sigalgos " + ((int)(XX_configure_reg_sigalgos_end- XX_configure_reg_sigalgos_start)) + " ms"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, " XX_configure_reg_transforms " + ((int)(XX_configure_reg_transforms_end- XX_configure_reg_transforms_start)) + " ms"); + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "XX_init " + ((int)(XX_init_end - XX_init_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_prng " + ((int)(XX_prng_end - XX_prng_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_parsing " + ((int)(XX_parsing_end - XX_parsing_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_i18n " + ((int)(XX_configure_i18n_end- XX_configure_i18n_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_c14n " + ((int)(XX_configure_reg_c14n_end- XX_configure_reg_c14n_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_jcemapper " + ((int)(XX_configure_reg_jcemapper_end- XX_configure_reg_jcemapper_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_keyInfo " + ((int)(XX_configure_reg_keyInfo_end- XX_configure_reg_keyInfo_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_keyResolver " + ((int)(XX_configure_reg_keyResolver_end- XX_configure_reg_keyResolver_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_prefixes " + ((int)(XX_configure_reg_prefixes_end- XX_configure_reg_prefixes_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_resourceresolver " + ((int)(XX_configure_reg_resourceresolver_end- XX_configure_reg_resourceresolver_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_sigalgos " + ((int)(XX_configure_reg_sigalgos_end- XX_configure_reg_sigalgos_start)) + " ms"); + log.log(java.util.logging.Level.FINE, " XX_configure_reg_transforms " + ((int)(XX_configure_reg_transforms_end- XX_configure_reg_transforms_start)) + " ms"); } } catch (Exception e) { log.log(java.util.logging.Level.SEVERE, "Bad: ", e); diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/Algorithm.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/Algorithm.java index 2f326f0a7a44dd38d18301cde2622e46d8f90e16..62fd0fe4964cf16b2a33fbde643867e95edb03b0 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/Algorithm.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/Algorithm.java @@ -24,7 +24,7 @@ package com.sun.org.apache.xml.internal.security.algorithms; import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.utils.Constants; -import com.sun.org.apache.xml.internal.security.utils.ElementProxy; +import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -33,11 +33,7 @@ import org.w3c.dom.Element; * The Algorithm class which stores the Algorithm URI as a string. * */ -public abstract class Algorithm extends ElementProxy { - - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(Algorithm.class.getName()); +public abstract class Algorithm extends SignatureElementProxy { /** * @@ -79,7 +75,7 @@ public abstract class Algorithm extends ElementProxy { */ protected void setAlgorithmURI(String algorithmURI) { - if ((this._state == MODE_CREATE) && (algorithmURI != null)) { + if ( (algorithmURI != null)) { this._constructionElement.setAttributeNS(null, Constants._ATT_ALGORITHM, algorithmURI); } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/JCEMapper.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/JCEMapper.java index 475d4591bcdd95c0b3f7c16c0e37562b7e242300..7a239135920e75b4ee92eef2dad536d653e2b009 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/JCEMapper.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/JCEMapper.java @@ -35,7 +35,7 @@ import org.w3c.dom.Element; /** * This class maps algorithm identifier URIs to JAVA JCE class names. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class JCEMapper { @@ -45,9 +45,9 @@ public class JCEMapper { - private static Map uriToJCEName = new HashMap(); + private static Map uriToJCEName; - private static Map algorithmsMap = new HashMap(); + private static Map algorithmsMap; private static String providerName = null; /** @@ -63,6 +63,8 @@ public class JCEMapper { static void loadAlgorithms( Element algorithmsEl) { Element[] algorithms = XMLUtils.selectNodes(algorithmsEl.getFirstChild(),Init.CONF_NS,"Algorithm"); + uriToJCEName = new HashMap( algorithms.length * 2); + algorithmsMap = new HashMap( algorithms.length * 2); for (int i = 0 ;i < algorithms.length ;i ++) { Element el = algorithms[i]; String id = el.getAttribute("URI"); @@ -70,6 +72,7 @@ public class JCEMapper { uriToJCEName.put(id, jceName); algorithmsMap.put(id, new Algorithm(el)); } + } static Algorithm getAlgorithmMapping(String algoURI) { @@ -84,8 +87,8 @@ public class JCEMapper { * */ public static String translateURItoJCEID(String AlgorithmURI) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Request for URI " + AlgorithmURI); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Request for URI " + AlgorithmURI); String jceName = (String) uriToJCEName.get(AlgorithmURI); return jceName; @@ -100,8 +103,8 @@ public class JCEMapper { * */ public static String getAlgorithmClassFromURI(String AlgorithmURI) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Request for URI " + AlgorithmURI); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Request for URI " + AlgorithmURI); return ((Algorithm) algorithmsMap.get(AlgorithmURI)).algorithmClass; } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/MessageDigestAlgorithm.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/MessageDigestAlgorithm.java index 805d061a2e6dd5b6cfa37a67f2b5d517a059f1a5..fa62ef3518f750316b7bb817335a8c5d49b3d3f4 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/MessageDigestAlgorithm.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/MessageDigestAlgorithm.java @@ -20,10 +20,10 @@ */ package com.sun.org.apache.xml.internal.security.algorithms; - - import java.security.MessageDigest; import java.security.NoSuchProviderException; +import java.util.HashMap; +import java.util.Map; import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; import com.sun.org.apache.xml.internal.security.utils.Constants; @@ -41,11 +41,6 @@ import org.w3c.dom.Document; */ public class MessageDigestAlgorithm extends Algorithm { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger( - MessageDigestAlgorithm.class.getName()); - /** Message Digest - NOT RECOMMENDED MD5*/ public static final String ALGO_ID_DIGEST_NOT_RECOMMENDED_MD5 = Constants.MoreAlgorithmsSpecNS + "md5"; /** Digest - Required SHA1*/ @@ -76,6 +71,12 @@ public class MessageDigestAlgorithm extends Algorithm { this.algorithm = messageDigest; } + static ThreadLocal instances=new ThreadLocal() { + protected Object initialValue() { + return new HashMap(); + }; + }; + /** * Factory method for constructing a message digest algorithm by name. * @@ -86,8 +87,15 @@ public class MessageDigestAlgorithm extends Algorithm { */ public static MessageDigestAlgorithm getInstance( Document doc, String algorithmURI) throws XMLSignatureException { + MessageDigest md = getDigestInstance(algorithmURI); + return new MessageDigestAlgorithm(doc, md, algorithmURI); + } - String algorithmID = JCEMapper.translateURItoJCEID(algorithmURI); +private static MessageDigest getDigestInstance(String algorithmURI) throws XMLSignatureException { + MessageDigest result=(MessageDigest) ((Map)instances.get()).get(algorithmURI); + if (result!=null) + return result; + String algorithmID = JCEMapper.translateURItoJCEID(algorithmURI); if (algorithmID == null) { Object[] exArgs = { algorithmURI }; @@ -113,8 +121,9 @@ public class MessageDigestAlgorithm extends Algorithm { throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); } - return new MessageDigestAlgorithm(doc, md, algorithmURI); - } + ((Map)instances.get()).put(algorithmURI, md); + return md; +} /** * Returns the actual {@link java.security.MessageDigest} algorithm object diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithm.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithm.java index 3ebb782a3d22d70933d8155829a3c95486008264..567df3cbbd12c6fd17f8a944ec23e8c410e349ec 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithm.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithm.java @@ -25,6 +25,7 @@ import java.security.Key; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.util.HashMap; +import java.util.Map; import com.sun.org.apache.xml.internal.security.algorithms.implementations.IntegrityHmac; import com.sun.org.apache.xml.internal.security.exceptions.AlgorithmAlreadyRegisteredException; @@ -52,9 +53,35 @@ public class SignatureAlgorithm extends Algorithm { /** All available algorithm classes are registered here */ static HashMap _algorithmHash = null; + static ThreadLocal instancesSigning=new ThreadLocal() { + protected Object initialValue() { + return new HashMap(); + }; + }; + + static ThreadLocal instancesVerify=new ThreadLocal() { + protected Object initialValue() { + return new HashMap(); + }; + }; + + static ThreadLocal keysSigning=new ThreadLocal() { + protected Object initialValue() { + return new HashMap(); + }; + }; + static ThreadLocal keysVerify=new ThreadLocal() { + protected Object initialValue() { + return new HashMap(); + }; + }; +// boolean isForSigning=false; + /** Field _signatureAlgorithm */ protected SignatureAlgorithmSpi _signatureAlgorithm = null; + private String algorithmURI; + /** * Constructor SignatureAlgorithm * @@ -64,18 +91,49 @@ public class SignatureAlgorithm extends Algorithm { */ public SignatureAlgorithm(Document doc, String algorithmURI) throws XMLSecurityException { - super(doc, algorithmURI); + this.algorithmURI = algorithmURI; + } - try { + + private void initializeAlgorithm(boolean isForSigning) throws XMLSignatureException { + if (_signatureAlgorithm!=null) { + return; + } + _signatureAlgorithm=isForSigning ? getInstanceForSigning(algorithmURI) : getInstanceForVerify(algorithmURI); + this._signatureAlgorithm + .engineGetContextFromElement(this._constructionElement); + } + private static SignatureAlgorithmSpi getInstanceForSigning(String algorithmURI) throws XMLSignatureException { + SignatureAlgorithmSpi result=(SignatureAlgorithmSpi) ((Map)instancesSigning.get()).get(algorithmURI); + if (result!=null) { + result.reset(); + return result; + } + result=buildSigner(algorithmURI, result); + ((Map)instancesSigning.get()).put(algorithmURI,result); + return result; + } + private static SignatureAlgorithmSpi getInstanceForVerify(String algorithmURI) throws XMLSignatureException { + SignatureAlgorithmSpi result=(SignatureAlgorithmSpi) ((Map)instancesVerify.get()).get(algorithmURI); + if (result!=null) { + result.reset(); + return result; + } + result=buildSigner(algorithmURI, result); + ((Map)instancesVerify.get()).put(algorithmURI,result); + return result; + } + + private static SignatureAlgorithmSpi buildSigner(String algorithmURI, SignatureAlgorithmSpi result) throws XMLSignatureException { + try { Class implementingClass = SignatureAlgorithm.getImplementingClass(algorithmURI); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Create URI \"" + algorithmURI + "\" class \"" + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Create URI \"" + algorithmURI + "\" class \"" + implementingClass + "\""); - - this._signatureAlgorithm = - (SignatureAlgorithmSpi) implementingClass.newInstance(); + result=(SignatureAlgorithmSpi) implementingClass.newInstance(); + return result; } catch (IllegalAccessException ex) { Object exArgs[] = { algorithmURI, ex.getMessage() }; @@ -92,7 +150,7 @@ public class SignatureAlgorithm extends Algorithm { throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, ex); } - } +} /** * Constructor SignatureAlgorithm @@ -107,7 +165,8 @@ public class SignatureAlgorithm extends Algorithm { throws XMLSecurityException { this(doc, algorithmURI); - + this.algorithmURI=algorithmURI; + initializeAlgorithm(true); this._signatureAlgorithm.engineSetHMACOutputLength(HMACOutputLength); ((IntegrityHmac)this._signatureAlgorithm) .engineAddContextToElement(this._constructionElement); @@ -124,37 +183,7 @@ public class SignatureAlgorithm extends Algorithm { throws XMLSecurityException { super(element, BaseURI); - - String algorithmURI = this.getURI(); - - try { - Class implementingClass = - SignatureAlgorithm.getImplementingClass(algorithmURI); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Create URI \"" + algorithmURI + "\" class \"" - + implementingClass + "\""); - - this._signatureAlgorithm = - (SignatureAlgorithmSpi) implementingClass.newInstance(); - - this._signatureAlgorithm - .engineGetContextFromElement(this._constructionElement); - } catch (IllegalAccessException ex) { - Object exArgs[] = { algorithmURI, ex.getMessage() }; - - throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, - ex); - } catch (InstantiationException ex) { - Object exArgs[] = { algorithmURI, ex.getMessage() }; - - throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, - ex); - } catch (NullPointerException ex) { - Object exArgs[] = { algorithmURI, ex.getMessage() }; - - throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, - ex); - } + algorithmURI = this.getURI(); } /** @@ -175,7 +204,12 @@ public class SignatureAlgorithm extends Algorithm { * @return the result of the {@link java.security.Signature#getAlgorithm} method */ public String getJCEAlgorithmString() { - return this._signatureAlgorithm.engineGetJCEAlgorithmString(); + try { + return getInstanceForVerify(algorithmURI).engineGetJCEAlgorithmString(); + } catch (XMLSignatureException e) { + //Ignore. + return null; + } } /** @@ -184,7 +218,11 @@ public class SignatureAlgorithm extends Algorithm { * @return The Provider of this Signature Alogrithm */ public String getJCEProviderName() { - return this._signatureAlgorithm.engineGetJCEProviderName(); + try { + return getInstanceForVerify(algorithmURI).engineGetJCEProviderName(); + } catch (XMLSignatureException e) { + return null; + } } /** @@ -231,7 +269,13 @@ public class SignatureAlgorithm extends Algorithm { * @throws XMLSignatureException */ public void initSign(Key signingKey) throws XMLSignatureException { - this._signatureAlgorithm.engineInitSign(signingKey); + initializeAlgorithm(true); + Map map=(Map)keysSigning.get(); + if (map.get(this.algorithmURI)==signingKey) { + return; + } + map.put(this.algorithmURI,signingKey); + this._signatureAlgorithm.engineInitSign(signingKey); } /** @@ -244,6 +288,7 @@ public class SignatureAlgorithm extends Algorithm { */ public void initSign(Key signingKey, SecureRandom secureRandom) throws XMLSignatureException { + initializeAlgorithm(true); this._signatureAlgorithm.engineInitSign(signingKey, secureRandom); } @@ -258,6 +303,7 @@ public class SignatureAlgorithm extends Algorithm { public void initSign( Key signingKey, AlgorithmParameterSpec algorithmParameterSpec) throws XMLSignatureException { + initializeAlgorithm(true); this._signatureAlgorithm.engineInitSign(signingKey, algorithmParameterSpec); } @@ -282,7 +328,13 @@ public class SignatureAlgorithm extends Algorithm { * @throws XMLSignatureException */ public void initVerify(Key verificationKey) throws XMLSignatureException { - this._signatureAlgorithm.engineInitVerify(verificationKey); + initializeAlgorithm(false); + Map map=(Map)keysVerify.get(); + if (map.get(this.algorithmURI)==verificationKey) { + return; + } + map.put(this.algorithmURI,verificationKey); + this._signatureAlgorithm.engineInitVerify(verificationKey); } /** @@ -320,7 +372,7 @@ public class SignatureAlgorithm extends Algorithm { .getLogger(SignatureAlgorithm.class.getName()); } - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Init() called"); + log.log(java.util.logging.Level.FINE, "Init() called"); if (!SignatureAlgorithm._alreadyInitialized) { SignatureAlgorithm._algorithmHash = new HashMap(10); @@ -340,8 +392,8 @@ public class SignatureAlgorithm extends Algorithm { throws AlgorithmAlreadyRegisteredException,XMLSignatureException { { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Try to register " + algorithmURI + " " + implementingClass); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Try to register " + algorithmURI + " " + implementingClass); // are we already registered? Class registeredClassClass = diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithmSpi.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithmSpi.java index 1ae46db4bb35d5aa54d8487e7774b97a4ee0ae54..c47be7e2c0dd0a437476a65501b93746fd5245a2 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithmSpi.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithmSpi.java @@ -20,27 +20,20 @@ */ package com.sun.org.apache.xml.internal.security.algorithms; - - import java.security.Key; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; -import org.w3c.dom.Document; import org.w3c.dom.Element; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public abstract class SignatureAlgorithmSpi { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(SignatureAlgorithmSpi.class.getName()); - /** * Returns the URI representation of Transformation algorithm * @@ -167,20 +160,6 @@ public abstract class SignatureAlgorithmSpi { protected abstract void engineSetParameter(AlgorithmParameterSpec params) throws XMLSignatureException; - /** Field _doc */ - Document _doc = null; - - /** - * Method engineSetDocument - * - * @param doc - */ - protected void engineSetDocument(Document doc) { - this._doc = doc; - } - - /** Field _constructionElement */ - Element _constructionElement = null; /** * Method engineGetContextFromElement @@ -188,7 +167,6 @@ public abstract class SignatureAlgorithmSpi { * @param element */ protected void engineGetContextFromElement(Element element) { - this._constructionElement = element; } /** @@ -199,4 +177,7 @@ public abstract class SignatureAlgorithmSpi { */ protected abstract void engineSetHMACOutputLength(int HMACOutputLength) throws XMLSignatureException; + + public void reset() { + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/IntegrityHmac.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/IntegrityHmac.java index 0e89024bf265d7c1e302af34ef0777edc41cf88f..d3495bb567f4ed2402a7876e0ee91b4a22e12f2d 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/IntegrityHmac.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/IntegrityHmac.java @@ -45,7 +45,7 @@ import org.w3c.dom.Text; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { @@ -74,8 +74,8 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { public IntegrityHmac() throws XMLSignatureException { String algorithmID = JCEMapper.translateURItoJCEID(this.engineGetURI()); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Created IntegrityHmacSHA1 using " + algorithmID); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Created IntegrityHmacSHA1 using " + algorithmID); try { this._macAlgorithm = Mac.getInstance(algorithmID); @@ -99,6 +99,10 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { throw new XMLSignatureException("empty"); } + public void reset() { + _HMACOutputLength=0; + } + /** * Proxy method for {@link java.security.Signature#verify(byte[])} * which is executed on the internal {@link java.security.Signature} object. @@ -145,7 +149,20 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { try { this._macAlgorithm.init(secretKey); } catch (InvalidKeyException ex) { - throw new XMLSignatureException("empty", ex); + // reinstantiate Mac object to work around bug in JDK + // see: http://bugs.sun.com/view_bug.do?bug_id=4953555 + Mac mac = this._macAlgorithm; + try { + this._macAlgorithm = Mac.getInstance + (_macAlgorithm.getAlgorithm()); + } catch (Exception e) { + // this shouldn't occur, but if it does, restore previous Mac + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "Exception when reinstantiating Mac:" + e); + } + this._macAlgorithm = mac; + } + throw new XMLSignatureException("empty", ex); } } @@ -323,7 +340,7 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { */ protected String engineGetJCEAlgorithmString() { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "engineGetJCEAlgorithmString()"); + log.log(java.util.logging.Level.FINE, "engineGetJCEAlgorithmString()"); return this._macAlgorithm.getAlgorithm(); } @@ -397,7 +414,8 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { /** * Class IntegrityHmacSHA1 * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ public static class IntegrityHmacSHA1 extends IntegrityHmac { @@ -423,7 +441,8 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { /** * Class IntegrityHmacSHA256 * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ public static class IntegrityHmacSHA256 extends IntegrityHmac { @@ -449,7 +468,8 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { /** * Class IntegrityHmacSHA384 * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ public static class IntegrityHmacSHA384 extends IntegrityHmac { @@ -475,7 +495,8 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { /** * Class IntegrityHmacSHA512 * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ public static class IntegrityHmacSHA512 extends IntegrityHmac { @@ -501,7 +522,8 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { /** * Class IntegrityHmacRIPEMD160 * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ public static class IntegrityHmacRIPEMD160 extends IntegrityHmac { @@ -527,7 +549,8 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi { /** * Class IntegrityHmacMD5 * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ public static class IntegrityHmacMD5 extends IntegrityHmac { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureBaseRSA.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureBaseRSA.java index fde23e8fc880ea4014abcc069c4e7304a3962005..ccc01b01c58e644461f42d9b69c2878de613f417 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureBaseRSA.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureBaseRSA.java @@ -3,7 +3,7 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2007 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.algorithms.implementations; - - import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; @@ -38,329 +36,344 @@ import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithmSpi import com.sun.org.apache.xml.internal.security.signature.XMLSignature; import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public abstract class SignatureBaseRSA extends SignatureAlgorithmSpi { - /** {@link java.util.logging} logging facility */ + /** {@link java.util.logging} logging facility */ static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(SignatureBaseRSA.class.getName()); + java.util.logging.Logger.getLogger + (SignatureBaseRSA.class.getName()); /** @inheritDoc */ - public abstract String engineGetURI(); + public abstract String engineGetURI(); - /** Field algorithm */ - private java.security.Signature _signatureAlgorithm = null; + /** Field algorithm */ + private java.security.Signature _signatureAlgorithm = null; - /** - * Constructor SignatureRSA - * - * @throws XMLSignatureException - */ - public SignatureBaseRSA() throws XMLSignatureException { + /** + * Constructor SignatureRSA + * + * @throws XMLSignatureException + */ + public SignatureBaseRSA() throws XMLSignatureException { - String algorithmID = JCEMapper.translateURItoJCEID(this.engineGetURI()); + String algorithmID = JCEMapper.translateURItoJCEID(this.engineGetURI()); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Created SignatureDSA using " + algorithmID); - String provider=JCEMapper.getProviderId(); - try { - if (provider==null) { + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Created SignatureRSA using " + algorithmID); + String provider=JCEMapper.getProviderId(); + try { + if (provider==null) { this._signatureAlgorithm = Signature.getInstance(algorithmID); - } else { + } else { this._signatureAlgorithm = Signature.getInstance(algorithmID,provider); - } - } catch (java.security.NoSuchAlgorithmException ex) { - Object[] exArgs = { algorithmID, - ex.getLocalizedMessage() }; + } + } catch (java.security.NoSuchAlgorithmException ex) { + Object[] exArgs = { algorithmID, ex.getLocalizedMessage() }; + + throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); + } catch (NoSuchProviderException ex) { + Object[] exArgs = { algorithmID, ex.getLocalizedMessage() }; + + throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); + } + } + + /** @inheritDoc */ + protected void engineSetParameter(AlgorithmParameterSpec params) + throws XMLSignatureException { + + try { + this._signatureAlgorithm.setParameter(params); + } catch (InvalidAlgorithmParameterException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected boolean engineVerify(byte[] signature) + throws XMLSignatureException { + + try { + return this._signatureAlgorithm.verify(signature); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineInitVerify(Key publicKey) throws XMLSignatureException { + + if (!(publicKey instanceof PublicKey)) { + String supplied = publicKey.getClass().getName(); + String needed = PublicKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException + ("algorithms.WrongKeyForThisOperation", exArgs); + } + + try { + this._signatureAlgorithm.initVerify((PublicKey) publicKey); + } catch (InvalidKeyException ex) { + // reinstantiate Signature object to work around bug in JDK + // see: http://bugs.sun.com/view_bug.do?bug_id=4953555 + Signature sig = this._signatureAlgorithm; + try { + this._signatureAlgorithm = Signature.getInstance + (_signatureAlgorithm.getAlgorithm()); + } catch (Exception e) { + // this shouldn't occur, but if it does, restore previous + // Signature + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "Exception when reinstantiating Signature:" + e); + } + this._signatureAlgorithm = sig; + } + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected byte[] engineSign() throws XMLSignatureException { + try { + return this._signatureAlgorithm.sign(); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineInitSign(Key privateKey, SecureRandom secureRandom) + throws XMLSignatureException { + + if (!(privateKey instanceof PrivateKey)) { + String supplied = privateKey.getClass().getName(); + String needed = PrivateKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException + ("algorithms.WrongKeyForThisOperation", exArgs); + } + + try { + this._signatureAlgorithm.initSign + ((PrivateKey) privateKey, secureRandom); + } catch (InvalidKeyException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineInitSign(Key privateKey) throws XMLSignatureException { + + if (!(privateKey instanceof PrivateKey)) { + String supplied = privateKey.getClass().getName(); + String needed = PrivateKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException + ("algorithms.WrongKeyForThisOperation", exArgs); + } + + try { + this._signatureAlgorithm.initSign((PrivateKey) privateKey); + } catch (InvalidKeyException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineUpdate(byte[] input) throws XMLSignatureException { + try { + this._signatureAlgorithm.update(input); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineUpdate(byte input) throws XMLSignatureException { + try { + this._signatureAlgorithm.update(input); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineUpdate(byte buf[], int offset, int len) + throws XMLSignatureException { + try { + this._signatureAlgorithm.update(buf, offset, len); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected String engineGetJCEAlgorithmString() { + return this._signatureAlgorithm.getAlgorithm(); + } + + /** @inheritDoc */ + protected String engineGetJCEProviderName() { + return this._signatureAlgorithm.getProvider().getName(); + } + + /** @inheritDoc */ + protected void engineSetHMACOutputLength(int HMACOutputLength) + throws XMLSignatureException { + throw new XMLSignatureException + ("algorithms.HMACOutputLengthOnlyForHMAC"); + } - throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); - } catch (NoSuchProviderException ex) { - Object[] exArgs = { algorithmID, - ex.getLocalizedMessage() }; + /** @inheritDoc */ + protected void engineInitSign( + Key signingKey, AlgorithmParameterSpec algorithmParameterSpec) + throws XMLSignatureException { + throw new XMLSignatureException( + "algorithms.CannotUseAlgorithmParameterSpecOnRSA"); + } + + /** + * Class SignatureRSASHA1 + * + * @author $Author: mullan $ + * @version $Revision: 1.5 $ + */ + public static class SignatureRSASHA1 extends SignatureBaseRSA { + + /** + * Constructor SignatureRSASHA1 + * + * @throws XMLSignatureException + */ + public SignatureRSASHA1() throws XMLSignatureException { + super(); + } + + /** @inheritDoc */ + public String engineGetURI() { + return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1; + } + } + + /** + * Class SignatureRSASHA256 + * + * @author $Author: mullan $ + * @version $Revision: 1.5 $ + */ + public static class SignatureRSASHA256 extends SignatureBaseRSA { + + /** + * Constructor SignatureRSASHA256 + * + * @throws XMLSignatureException + */ + public SignatureRSASHA256() throws XMLSignatureException { + super(); + } + + /** @inheritDoc */ + public String engineGetURI() { + return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256; + } + } + + /** + * Class SignatureRSASHA384 + * + * @author $Author: mullan $ + * @version $Revision: 1.5 $ + */ + public static class SignatureRSASHA384 extends SignatureBaseRSA { + + /** + * Constructor SignatureRSASHA384 + * + * @throws XMLSignatureException + */ + public SignatureRSASHA384() throws XMLSignatureException { + super(); + } + + /** @inheritDoc */ + public String engineGetURI() { + return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384; + } + } + + /** + * Class SignatureRSASHA512 + * + * @author $Author: mullan $ + * @version $Revision: 1.5 $ + */ + public static class SignatureRSASHA512 extends SignatureBaseRSA { + + /** + * Constructor SignatureRSASHA512 + * + * @throws XMLSignatureException + */ + public SignatureRSASHA512() throws XMLSignatureException { + super(); + } + + /** @inheritDoc */ + public String engineGetURI() { + return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512; + } + } + + /** + * Class SignatureRSARIPEMD160 + * + * @author $Author: mullan $ + * @version $Revision: 1.5 $ + */ + public static class SignatureRSARIPEMD160 extends SignatureBaseRSA { + + /** + * Constructor SignatureRSARIPEMD160 + * + * @throws XMLSignatureException + */ + public SignatureRSARIPEMD160() throws XMLSignatureException { + super(); + } + + /** @inheritDoc */ + public String engineGetURI() { + return XMLSignature.ALGO_ID_SIGNATURE_RSA_RIPEMD160; + } + } + + /** + * Class SignatureRSAMD5 + * + * @author $Author: mullan $ + * @version $Revision: 1.5 $ + */ + public static class SignatureRSAMD5 extends SignatureBaseRSA { + + /** + * Constructor SignatureRSAMD5 + * + * @throws XMLSignatureException + */ + public SignatureRSAMD5() throws XMLSignatureException { + super(); + } - throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); + /** @inheritDoc */ + public String engineGetURI() { + return XMLSignature.ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5; } - } - - /** @inheritDoc */ - protected void engineSetParameter(AlgorithmParameterSpec params) - throws XMLSignatureException { - - try { - this._signatureAlgorithm.setParameter(params); - } catch (InvalidAlgorithmParameterException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected boolean engineVerify(byte[] signature) - throws XMLSignatureException { - - try { - return this._signatureAlgorithm.verify(signature); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected void engineInitVerify(Key publicKey) throws XMLSignatureException { - - if (!(publicKey instanceof PublicKey)) { - String supplied = publicKey.getClass().getName(); - String needed = PublicKey.class.getName(); - Object exArgs[] = { supplied, needed }; - - throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", - exArgs); - } - - try { - this._signatureAlgorithm.initVerify((PublicKey) publicKey); - } catch (InvalidKeyException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected byte[] engineSign() throws XMLSignatureException { - - try { - return this._signatureAlgorithm.sign(); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected void engineInitSign(Key privateKey, SecureRandom secureRandom) - throws XMLSignatureException { - - if (!(privateKey instanceof PrivateKey)) { - String supplied = privateKey.getClass().getName(); - String needed = PrivateKey.class.getName(); - Object exArgs[] = { supplied, needed }; - - throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", - exArgs); - } - - try { - this._signatureAlgorithm.initSign((PrivateKey) privateKey, - secureRandom); - } catch (InvalidKeyException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected void engineInitSign(Key privateKey) throws XMLSignatureException { - - if (!(privateKey instanceof PrivateKey)) { - String supplied = privateKey.getClass().getName(); - String needed = PrivateKey.class.getName(); - Object exArgs[] = { supplied, needed }; - - throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", - exArgs); - } - - try { - this._signatureAlgorithm.initSign((PrivateKey) privateKey); - } catch (InvalidKeyException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected void engineUpdate(byte[] input) throws XMLSignatureException { - - try { - this._signatureAlgorithm.update(input); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected void engineUpdate(byte input) throws XMLSignatureException { - - try { - this._signatureAlgorithm.update(input); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected void engineUpdate(byte buf[], int offset, int len) - throws XMLSignatureException { - - try { - this._signatureAlgorithm.update(buf, offset, len); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** @inheritDoc */ - protected String engineGetJCEAlgorithmString() { - return this._signatureAlgorithm.getAlgorithm(); - } - - /** @inheritDoc */ - protected String engineGetJCEProviderName() { - return this._signatureAlgorithm.getProvider().getName(); - } - - /** @inheritDoc */ - protected void engineSetHMACOutputLength(int HMACOutputLength) - throws XMLSignatureException { - throw new XMLSignatureException("algorithms.HMACOutputLengthOnlyForHMAC"); - } - - /** @inheritDoc */ - protected void engineInitSign( - Key signingKey, AlgorithmParameterSpec algorithmParameterSpec) - throws XMLSignatureException { - throw new XMLSignatureException( - "algorithms.CannotUseAlgorithmParameterSpecOnRSA"); - } - - /** - * Class SignatureRSASHA1 - * - * @author $Author: raul $ - */ - public static class SignatureRSASHA1 extends SignatureBaseRSA { - - /** - * Constructor SignatureRSASHA1 - * - * @throws XMLSignatureException - */ - public SignatureRSASHA1() throws XMLSignatureException { - super(); - } - - /** @inheritDoc */ - public String engineGetURI() { - return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1; - } - } - - /** - * Class SignatureRSASHA256 - * - * @author $Author: raul $ - */ - public static class SignatureRSASHA256 extends SignatureBaseRSA { - - /** - * Constructor SignatureRSASHA256 - * - * @throws XMLSignatureException - */ - public SignatureRSASHA256() throws XMLSignatureException { - super(); - } - - /** @inheritDoc */ - public String engineGetURI() { - return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256; - } - } - - /** - * Class SignatureRSASHA384 - * - * @author $Author: raul $ - */ - public static class SignatureRSASHA384 extends SignatureBaseRSA { - - /** - * Constructor SignatureRSASHA384 - * - * @throws XMLSignatureException - */ - public SignatureRSASHA384() throws XMLSignatureException { - super(); - } - - /** @inheritDoc */ - public String engineGetURI() { - return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384; - } - } - - /** - * Class SignatureRSASHA512 - * - * @author $Author: raul $ - */ - public static class SignatureRSASHA512 extends SignatureBaseRSA { - - /** - * Constructor SignatureRSASHA512 - * - * @throws XMLSignatureException - */ - public SignatureRSASHA512() throws XMLSignatureException { - super(); - } - - /** @inheritDoc */ - public String engineGetURI() { - return XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512; - } - } - - /** - * Class SignatureRSARIPEMD160 - * - * @author $Author: raul $ - */ - public static class SignatureRSARIPEMD160 extends SignatureBaseRSA { - - /** - * Constructor SignatureRSARIPEMD160 - * - * @throws XMLSignatureException - */ - public SignatureRSARIPEMD160() throws XMLSignatureException { - super(); - } - - /** @inheritDoc */ - public String engineGetURI() { - return XMLSignature.ALGO_ID_SIGNATURE_RSA_RIPEMD160; - } - } - - /** - * Class SignatureRSAMD5 - * - * @author $Author: raul $ - */ - public static class SignatureRSAMD5 extends SignatureBaseRSA { - - /** - * Constructor SignatureRSAMD5 - * - * @throws XMLSignatureException - */ - public SignatureRSAMD5() throws XMLSignatureException { - super(); - } - - /** @inheritDoc */ - public String engineGetURI() { - return XMLSignature.ALGO_ID_SIGNATURE_NOT_RECOMMENDED_RSA_MD5; - } - } + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureDSA.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureDSA.java index 355579b7e5385ee4a97f324d0a8d1436436a4987..615aa436e462358b457b5d002ba8e52f8b4aa096 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureDSA.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureDSA.java @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.algorithms.implementations; - - import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -39,342 +37,359 @@ import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; import com.sun.org.apache.xml.internal.security.utils.Base64; import com.sun.org.apache.xml.internal.security.utils.Constants; - /** * - * @author $Author: vishal $ + * @author $Author: mullan $ */ public class SignatureDSA extends SignatureAlgorithmSpi { - /** {@link java.util.logging} logging facility */ + /** {@link java.util.logging} logging facility */ static java.util.logging.Logger log = java.util.logging.Logger.getLogger(SignatureDSA.class.getName()); - /** Field _URI */ - public static final String _URI = Constants.SignatureSpecNS + "dsa-sha1"; - - /** Field algorithm */ - private java.security.Signature _signatureAlgorithm = null; - - /** - * Method engineGetURI - * - * @inheritDoc - */ - protected String engineGetURI() { - return SignatureDSA._URI; - } - - /** - * Constructor SignatureDSA - * - * @throws XMLSignatureException - */ - public SignatureDSA() throws XMLSignatureException { - - String algorithmID = JCEMapper.translateURItoJCEID(SignatureDSA._URI); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Created SignatureDSA using " + algorithmID); - - try { - this._signatureAlgorithm = Signature.getInstance(algorithmID); - } catch (java.security.NoSuchAlgorithmException ex) { - Object[] exArgs = { algorithmID, - ex.getLocalizedMessage() }; - - throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); - } - } - - /** - * @inheritDoc - */ - protected void engineSetParameter(AlgorithmParameterSpec params) - throws XMLSignatureException { - - try { - this._signatureAlgorithm.setParameter(params); - } catch (InvalidAlgorithmParameterException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected boolean engineVerify(byte[] signature) + /** Field _URI */ + public static final String _URI = Constants.SignatureSpecNS + "dsa-sha1"; + + /** Field algorithm */ + private java.security.Signature _signatureAlgorithm = null; + + /** + * Method engineGetURI + * + * @inheritDoc + */ + protected String engineGetURI() { + return SignatureDSA._URI; + } + + /** + * Constructor SignatureDSA + * + * @throws XMLSignatureException + */ + public SignatureDSA() throws XMLSignatureException { + + String algorithmID = JCEMapper.translateURItoJCEID(SignatureDSA._URI); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Created SignatureDSA using " + algorithmID); + + String provider = JCEMapper.getProviderId(); + try { + if (provider == null) { + this._signatureAlgorithm = Signature.getInstance(algorithmID); + } else { + this._signatureAlgorithm = + Signature.getInstance(algorithmID, provider); + } + } catch (java.security.NoSuchAlgorithmException ex) { + Object[] exArgs = { algorithmID, ex.getLocalizedMessage() }; + throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); + } catch (java.security.NoSuchProviderException ex) { + Object[] exArgs = { algorithmID, ex.getLocalizedMessage() }; + throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); + } + } + + /** + * @inheritDoc + */ + protected void engineSetParameter(AlgorithmParameterSpec params) + throws XMLSignatureException { + + try { + this._signatureAlgorithm.setParameter(params); + } catch (InvalidAlgorithmParameterException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected boolean engineVerify(byte[] signature) throws XMLSignatureException { - try { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Called DSA.verify() on " + Base64.encode(signature)); - - byte[] jcebytes = SignatureDSA.convertXMLDSIGtoASN1(signature); - - return this._signatureAlgorithm.verify(jcebytes); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } catch (IOException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected void engineInitVerify(Key publicKey) throws XMLSignatureException { - - if (!(publicKey instanceof PublicKey)) { - String supplied = publicKey.getClass().getName(); - String needed = PublicKey.class.getName(); - Object exArgs[] = { supplied, needed }; - - throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", - exArgs); - } - - try { - this._signatureAlgorithm.initVerify((PublicKey) publicKey); - } catch (InvalidKeyException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected byte[] engineSign() throws XMLSignatureException { - - try { - byte jcebytes[] = this._signatureAlgorithm.sign(); - - return SignatureDSA.convertASN1toXMLDSIG(jcebytes); - } catch (IOException ex) { - throw new XMLSignatureException("empty", ex); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected void engineInitSign(Key privateKey, SecureRandom secureRandom) + try { + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Called DSA.verify() on " + Base64.encode(signature)); + + byte[] jcebytes = SignatureDSA.convertXMLDSIGtoASN1(signature); + + return this._signatureAlgorithm.verify(jcebytes); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } catch (IOException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected void engineInitVerify(Key publicKey) throws XMLSignatureException { + + if (!(publicKey instanceof PublicKey)) { + String supplied = publicKey.getClass().getName(); + String needed = PublicKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException + ("algorithms.WrongKeyForThisOperation", exArgs); + } + + try { + this._signatureAlgorithm.initVerify((PublicKey) publicKey); + } catch (InvalidKeyException ex) { + // reinstantiate Signature object to work around bug in JDK + // see: http://bugs.sun.com/view_bug.do?bug_id=4953555 + Signature sig = this._signatureAlgorithm; + try { + this._signatureAlgorithm = Signature.getInstance + (_signatureAlgorithm.getAlgorithm()); + } catch (Exception e) { + // this shouldn't occur, but if it does, restore previous + // Signature + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "Exception when reinstantiating Signature:" + e); + } + this._signatureAlgorithm = sig; + } + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected byte[] engineSign() throws XMLSignatureException { + + try { + byte jcebytes[] = this._signatureAlgorithm.sign(); + + return SignatureDSA.convertASN1toXMLDSIG(jcebytes); + } catch (IOException ex) { + throw new XMLSignatureException("empty", ex); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected void engineInitSign(Key privateKey, SecureRandom secureRandom) throws XMLSignatureException { - if (!(privateKey instanceof PrivateKey)) { - String supplied = privateKey.getClass().getName(); - String needed = PrivateKey.class.getName(); - Object exArgs[] = { supplied, needed }; + if (!(privateKey instanceof PrivateKey)) { + String supplied = privateKey.getClass().getName(); + String needed = PrivateKey.class.getName(); + Object exArgs[] = { supplied, needed }; - throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", - exArgs); - } + throw new XMLSignatureException + ("algorithms.WrongKeyForThisOperation", exArgs); + } - try { - this._signatureAlgorithm.initSign((PrivateKey) privateKey, + try { + this._signatureAlgorithm.initSign((PrivateKey) privateKey, secureRandom); - } catch (InvalidKeyException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected void engineInitSign(Key privateKey) throws XMLSignatureException { - - if (!(privateKey instanceof PrivateKey)) { - String supplied = privateKey.getClass().getName(); - String needed = PrivateKey.class.getName(); - Object exArgs[] = { supplied, needed }; - - throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", - exArgs); - } - - try { - this._signatureAlgorithm.initSign((PrivateKey) privateKey); - } catch (InvalidKeyException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected void engineUpdate(byte[] input) throws XMLSignatureException { - - try { - this._signatureAlgorithm.update(input); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected void engineUpdate(byte input) throws XMLSignatureException { - - try { - this._signatureAlgorithm.update(input); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * @inheritDoc - */ - protected void engineUpdate(byte buf[], int offset, int len) - throws XMLSignatureException { - - try { - this._signatureAlgorithm.update(buf, offset, len); - } catch (SignatureException ex) { - throw new XMLSignatureException("empty", ex); - } - } - - /** - * Method engineGetJCEAlgorithmString - * - * @inheritDoc - */ - protected String engineGetJCEAlgorithmString() { - return this._signatureAlgorithm.getAlgorithm(); - } - - /** - * Method engineGetJCEProviderName - * - * @inheritDoc - */ - protected String engineGetJCEProviderName() { - return this._signatureAlgorithm.getProvider().getName(); - } - - - /** - * Converts an ASN.1 DSA value to a XML Signature DSA Value. - * - * The JAVA JCE DSA Signature algorithm creates ASN.1 encoded (r,s) value - * pairs; the XML Signature requires the core BigInteger values. - * - * @param asn1Bytes - * @return the decode bytes - * - * @throws IOException - * @see 6.4.1 DSA - */ - private static byte[] convertASN1toXMLDSIG(byte asn1Bytes[]) + } catch (InvalidKeyException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected void engineInitSign(Key privateKey) throws XMLSignatureException { + + if (!(privateKey instanceof PrivateKey)) { + String supplied = privateKey.getClass().getName(); + String needed = PrivateKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException + ("algorithms.WrongKeyForThisOperation", exArgs); + } + + try { + this._signatureAlgorithm.initSign((PrivateKey) privateKey); + } catch (InvalidKeyException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected void engineUpdate(byte[] input) throws XMLSignatureException { + try { + this._signatureAlgorithm.update(input); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected void engineUpdate(byte input) throws XMLSignatureException { + try { + this._signatureAlgorithm.update(input); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * @inheritDoc + */ + protected void engineUpdate(byte buf[], int offset, int len) + throws XMLSignatureException { + try { + this._signatureAlgorithm.update(buf, offset, len); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** + * Method engineGetJCEAlgorithmString + * + * @inheritDoc + */ + protected String engineGetJCEAlgorithmString() { + return this._signatureAlgorithm.getAlgorithm(); + } + + /** + * Method engineGetJCEProviderName + * + * @inheritDoc + */ + protected String engineGetJCEProviderName() { + return this._signatureAlgorithm.getProvider().getName(); + } + + /** + * Converts an ASN.1 DSA value to a XML Signature DSA Value. + * + * The JAVA JCE DSA Signature algorithm creates ASN.1 encoded (r,s) value + * pairs; the XML Signature requires the core BigInteger values. + * + * @param asn1Bytes + * @return the decode bytes + * + * @throws IOException + * @see 6.4.1 DSA + */ + private static byte[] convertASN1toXMLDSIG(byte asn1Bytes[]) throws IOException { - byte rLength = asn1Bytes[3]; - int i; + byte rLength = asn1Bytes[3]; + int i; - for (i = rLength; (i > 0) && (asn1Bytes[(4 + rLength) - i] == 0); i--); + for (i = rLength; (i > 0) && (asn1Bytes[(4 + rLength) - i] == 0); i--); - byte sLength = asn1Bytes[5 + rLength]; - int j; + byte sLength = asn1Bytes[5 + rLength]; + int j; - for (j = sLength; + for (j = sLength; (j > 0) && (asn1Bytes[(6 + rLength + sLength) - j] == 0); j--); - if ((asn1Bytes[0] != 48) || (asn1Bytes[1] != asn1Bytes.length - 2) + if ((asn1Bytes[0] != 48) || (asn1Bytes[1] != asn1Bytes.length - 2) || (asn1Bytes[2] != 2) || (i > 20) || (asn1Bytes[4 + rLength] != 2) || (j > 20)) { - throw new IOException("Invalid ASN.1 format of DSA signature"); - } - byte xmldsigBytes[] = new byte[40]; + throw new IOException("Invalid ASN.1 format of DSA signature"); + } + byte xmldsigBytes[] = new byte[40]; - System.arraycopy(asn1Bytes, (4 + rLength) - i, xmldsigBytes, 20 - i, + System.arraycopy(asn1Bytes, (4 + rLength) - i, xmldsigBytes, 20 - i, i); - System.arraycopy(asn1Bytes, (6 + rLength + sLength) - j, xmldsigBytes, + System.arraycopy(asn1Bytes, (6 + rLength + sLength) - j, xmldsigBytes, 40 - j, j); - return xmldsigBytes; - } - - /** - * Converts a XML Signature DSA Value to an ASN.1 DSA value. - * - * The JAVA JCE DSA Signature algorithm creates ASN.1 encoded (r,s) value - * pairs; the XML Signature requires the core BigInteger values. - * - * @param xmldsigBytes - * @return the encoded ASN.1 bytes - * - * @throws IOException - * @see 6.4.1 DSA - */ - private static byte[] convertXMLDSIGtoASN1(byte xmldsigBytes[]) + return xmldsigBytes; + } + + /** + * Converts a XML Signature DSA Value to an ASN.1 DSA value. + * + * The JAVA JCE DSA Signature algorithm creates ASN.1 encoded (r,s) value + * pairs; the XML Signature requires the core BigInteger values. + * + * @param xmldsigBytes + * @return the encoded ASN.1 bytes + * + * @throws IOException + * @see 6.4.1 DSA + */ + private static byte[] convertXMLDSIGtoASN1(byte xmldsigBytes[]) throws IOException { - if (xmldsigBytes.length != 40) { - throw new IOException("Invalid XMLDSIG format of DSA signature"); - } + if (xmldsigBytes.length != 40) { + throw new IOException("Invalid XMLDSIG format of DSA signature"); + } - int i; + int i; - for (i = 20; (i > 0) && (xmldsigBytes[20 - i] == 0); i--); + for (i = 20; (i > 0) && (xmldsigBytes[20 - i] == 0); i--); - int j = i; + int j = i; - if (xmldsigBytes[20 - i] < 0) { + if (xmldsigBytes[20 - i] < 0) { j += 1; - } - - int k; - - for (k = 20; (k > 0) && (xmldsigBytes[40 - k] == 0); k--); - - int l = k; - - if (xmldsigBytes[40 - k] < 0) { - l += 1; - } - - byte asn1Bytes[] = new byte[6 + j + l]; - - asn1Bytes[0] = 48; - asn1Bytes[1] = (byte) (4 + j + l); - asn1Bytes[2] = 2; - asn1Bytes[3] = (byte) j; - - System.arraycopy(xmldsigBytes, 20 - i, asn1Bytes, (4 + j) - i, i); - - asn1Bytes[4 + j] = 2; - asn1Bytes[5 + j] = (byte) l; - - System.arraycopy(xmldsigBytes, 40 - k, asn1Bytes, (6 + j + l) - k, k); - - return asn1Bytes; - } - - /** - * Method engineSetHMACOutputLength - * - * @param HMACOutputLength - * @throws XMLSignatureException - */ - protected void engineSetHMACOutputLength(int HMACOutputLength) - throws XMLSignatureException { - throw new XMLSignatureException("algorithms.HMACOutputLengthOnlyForHMAC"); - } - - /** - * Method engineInitSign - * - * @param signingKey - * @param algorithmParameterSpec - * @throws XMLSignatureException - */ - protected void engineInitSign( - Key signingKey, AlgorithmParameterSpec algorithmParameterSpec) - throws XMLSignatureException { - throw new XMLSignatureException( - "algorithms.CannotUseAlgorithmParameterSpecOnDSA"); - } + } + + int k; + + for (k = 20; (k > 0) && (xmldsigBytes[40 - k] == 0); k--); + + int l = k; + + if (xmldsigBytes[40 - k] < 0) { + l += 1; + } + + byte asn1Bytes[] = new byte[6 + j + l]; + + asn1Bytes[0] = 48; + asn1Bytes[1] = (byte) (4 + j + l); + asn1Bytes[2] = 2; + asn1Bytes[3] = (byte) j; + + System.arraycopy(xmldsigBytes, 20 - i, asn1Bytes, (4 + j) - i, i); + + asn1Bytes[4 + j] = 2; + asn1Bytes[5 + j] = (byte) l; + + System.arraycopy(xmldsigBytes, 40 - k, asn1Bytes, (6 + j + l) - k, k); + + return asn1Bytes; + } + + /** + * Method engineSetHMACOutputLength + * + * @param HMACOutputLength + * @throws XMLSignatureException + */ + protected void engineSetHMACOutputLength(int HMACOutputLength) + throws XMLSignatureException { + throw new XMLSignatureException( + "algorithms.HMACOutputLengthOnlyForHMAC"); + } + + /** + * Method engineInitSign + * + * @param signingKey + * @param algorithmParameterSpec + * @throws XMLSignatureException + */ + protected void engineInitSign( + Key signingKey, AlgorithmParameterSpec algorithmParameterSpec) + throws XMLSignatureException { + throw new XMLSignatureException( + "algorithms.CannotUseAlgorithmParameterSpecOnDSA"); + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureECDSA.java b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureECDSA.java new file mode 100644 index 0000000000000000000000000000000000000000..18fdffe28fb5533db2fbef538505501d98983141 --- /dev/null +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/algorithms/implementations/SignatureECDSA.java @@ -0,0 +1,384 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.sun.org.apache.xml.internal.security.algorithms.implementations; + + + +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.AlgorithmParameterSpec; + +import com.sun.org.apache.xml.internal.security.algorithms.JCEMapper; +import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithmSpi; +import com.sun.org.apache.xml.internal.security.signature.XMLSignature; +import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; +import com.sun.org.apache.xml.internal.security.utils.Base64; + + +/** + * + * @author $Author: mullan $ + */ +public abstract class SignatureECDSA extends SignatureAlgorithmSpi { + + /** {@link java.util.logging} logging facility */ + static java.util.logging.Logger log = + java.util.logging.Logger.getLogger(SignatureECDSA.class.getName()); + + /** @inheritDoc */ + public abstract String engineGetURI(); + + /** Field algorithm */ + private java.security.Signature _signatureAlgorithm = null; + + /** + * Converts an ASN.1 ECDSA value to a XML Signature ECDSA Value. + * + * The JAVA JCE ECDSA Signature algorithm creates ASN.1 encoded (r,s) value + * pairs; the XML Signature requires the core BigInteger values. + * + * @param asn1Bytes + * @return the decode bytes + * + * @throws IOException + * @see 6.4.1 DSA + * @see 3.3. ECDSA Signatures + */ + private static byte[] convertASN1toXMLDSIG(byte asn1Bytes[]) + throws IOException { + + byte rLength = asn1Bytes[3]; + int i; + + for (i = rLength; (i > 0) && (asn1Bytes[(4 + rLength) - i] == 0); i--); + + byte sLength = asn1Bytes[5 + rLength]; + int j; + + for (j = sLength; + (j > 0) && (asn1Bytes[(6 + rLength + sLength) - j] == 0); j--); + + if ((asn1Bytes[0] != 48) || (asn1Bytes[1] != asn1Bytes.length - 2) + || (asn1Bytes[2] != 2) || (i > 24) + || (asn1Bytes[4 + rLength] != 2) || (j > 24)) { + throw new IOException("Invalid ASN.1 format of ECDSA signature"); + } + byte xmldsigBytes[] = new byte[48]; + + System.arraycopy(asn1Bytes, (4 + rLength) - i, xmldsigBytes, 24 - i, + i); + System.arraycopy(asn1Bytes, (6 + rLength + sLength) - j, xmldsigBytes, + 48 - j, j); + + return xmldsigBytes; + } + + /** + * Converts a XML Signature ECDSA Value to an ASN.1 DSA value. + * + * The JAVA JCE ECDSA Signature algorithm creates ASN.1 encoded (r,s) value + * pairs; the XML Signature requires the core BigInteger values. + * + * @param xmldsigBytes + * @return the encoded ASN.1 bytes + * + * @throws IOException + * @see 6.4.1 DSA + * @see 3.3. ECDSA Signatures + */ + private static byte[] convertXMLDSIGtoASN1(byte xmldsigBytes[]) + throws IOException { + + if (xmldsigBytes.length != 48) { + throw new IOException("Invalid XMLDSIG format of ECDSA signature"); + } + + int i; + + for (i = 24; (i > 0) && (xmldsigBytes[24 - i] == 0); i--); + + int j = i; + + if (xmldsigBytes[24 - i] < 0) { + j += 1; + } + + int k; + + for (k = 24; (k > 0) && (xmldsigBytes[48 - k] == 0); k--); + + int l = k; + + if (xmldsigBytes[48 - k] < 0) { + l += 1; + } + + byte asn1Bytes[] = new byte[6 + j + l]; + + asn1Bytes[0] = 48; + asn1Bytes[1] = (byte) (4 + j + l); + asn1Bytes[2] = 2; + asn1Bytes[3] = (byte) j; + + System.arraycopy(xmldsigBytes, 24 - i, asn1Bytes, (4 + j) - i, i); + + asn1Bytes[4 + j] = 2; + asn1Bytes[5 + j] = (byte) l; + + System.arraycopy(xmldsigBytes, 48 - k, asn1Bytes, (6 + j + l) - k, k); + + return asn1Bytes; + } + + /** + * Constructor SignatureRSA + * + * @throws XMLSignatureException + */ + public SignatureECDSA() throws XMLSignatureException { + + String algorithmID = JCEMapper.translateURItoJCEID(this.engineGetURI()); + + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Created SignatureECDSA using " + algorithmID); + String provider=JCEMapper.getProviderId(); + try { + if (provider==null) { + this._signatureAlgorithm = Signature.getInstance(algorithmID); + } else { + this._signatureAlgorithm = Signature.getInstance(algorithmID,provider); + } + } catch (java.security.NoSuchAlgorithmException ex) { + Object[] exArgs = { algorithmID, + ex.getLocalizedMessage() }; + + throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); + } catch (NoSuchProviderException ex) { + Object[] exArgs = { algorithmID, + ex.getLocalizedMessage() }; + + throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs); + } + } + + /** @inheritDoc */ + protected void engineSetParameter(AlgorithmParameterSpec params) + throws XMLSignatureException { + + try { + this._signatureAlgorithm.setParameter(params); + } catch (InvalidAlgorithmParameterException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected boolean engineVerify(byte[] signature) + throws XMLSignatureException { + + try { + byte[] jcebytes = SignatureECDSA.convertXMLDSIGtoASN1(signature); + + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Called ECDSA.verify() on " + Base64.encode(signature)); + + return this._signatureAlgorithm.verify(jcebytes); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } catch (IOException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineInitVerify(Key publicKey) throws XMLSignatureException { + + if (!(publicKey instanceof PublicKey)) { + String supplied = publicKey.getClass().getName(); + String needed = PublicKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", + exArgs); + } + + try { + this._signatureAlgorithm.initVerify((PublicKey) publicKey); + } catch (InvalidKeyException ex) { + // reinstantiate Signature object to work around bug in JDK + // see: http://bugs.sun.com/view_bug.do?bug_id=4953555 + Signature sig = this._signatureAlgorithm; + try { + this._signatureAlgorithm = Signature.getInstance + (_signatureAlgorithm.getAlgorithm()); + } catch (Exception e) { + // this shouldn't occur, but if it does, restore previous + // Signature + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "Exception when reinstantiating Signature:" + e); + } + this._signatureAlgorithm = sig; + } + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected byte[] engineSign() throws XMLSignatureException { + + try { + byte jcebytes[] = this._signatureAlgorithm.sign(); + + return SignatureECDSA.convertASN1toXMLDSIG(jcebytes); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } catch (IOException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineInitSign(Key privateKey, SecureRandom secureRandom) + throws XMLSignatureException { + + if (!(privateKey instanceof PrivateKey)) { + String supplied = privateKey.getClass().getName(); + String needed = PrivateKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", + exArgs); + } + + try { + this._signatureAlgorithm.initSign((PrivateKey) privateKey, + secureRandom); + } catch (InvalidKeyException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineInitSign(Key privateKey) throws XMLSignatureException { + + if (!(privateKey instanceof PrivateKey)) { + String supplied = privateKey.getClass().getName(); + String needed = PrivateKey.class.getName(); + Object exArgs[] = { supplied, needed }; + + throw new XMLSignatureException("algorithms.WrongKeyForThisOperation", + exArgs); + } + + try { + this._signatureAlgorithm.initSign((PrivateKey) privateKey); + } catch (InvalidKeyException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineUpdate(byte[] input) throws XMLSignatureException { + + try { + this._signatureAlgorithm.update(input); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineUpdate(byte input) throws XMLSignatureException { + + try { + this._signatureAlgorithm.update(input); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected void engineUpdate(byte buf[], int offset, int len) + throws XMLSignatureException { + + try { + this._signatureAlgorithm.update(buf, offset, len); + } catch (SignatureException ex) { + throw new XMLSignatureException("empty", ex); + } + } + + /** @inheritDoc */ + protected String engineGetJCEAlgorithmString() { + return this._signatureAlgorithm.getAlgorithm(); + } + + /** @inheritDoc */ + protected String engineGetJCEProviderName() { + return this._signatureAlgorithm.getProvider().getName(); + } + + /** @inheritDoc */ + protected void engineSetHMACOutputLength(int HMACOutputLength) + throws XMLSignatureException { + throw new XMLSignatureException("algorithms.HMACOutputLengthOnlyForHMAC"); + } + + /** @inheritDoc */ + protected void engineInitSign( + Key signingKey, AlgorithmParameterSpec algorithmParameterSpec) + throws XMLSignatureException { + throw new XMLSignatureException( + "algorithms.CannotUseAlgorithmParameterSpecOnRSA"); + } + + /** + * Class SignatureRSASHA1 + * + * @author $Author: mullan $ + * @version $Revision: 1.2 $ + */ + public static class SignatureECDSASHA1 extends SignatureECDSA { + + /** + * Constructor SignatureRSASHA1 + * + * @throws XMLSignatureException + */ + public SignatureECDSASHA1() throws XMLSignatureException { + super(); + } + + /** @inheritDoc */ + public String engineGetURI() { + return XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA1; + } + } + +} diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/CanonicalizationException.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/CanonicalizationException.java index 732334c36562e12bd133eb2c1ed50e972a1f8e8e..36c98cfe7900fa70a430ac01ca123e17f6962610 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/CanonicalizationException.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/CanonicalizationException.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/Canonicalizer.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/Canonicalizer.java index eb7cb6cad0103150cfa2382588a2ffc6da1f556b..a4181233d6029ceaa3fb52b84574be5d5535b274 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/Canonicalizer.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/Canonicalizer.java @@ -3,7 +3,7 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2008 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.c14n; - - import java.io.ByteArrayInputStream; import java.io.OutputStream; import java.util.HashMap; @@ -37,318 +35,326 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; - /** - * * * @author Christian Geuer-Pollmann */ public class Canonicalizer { - //J- - /** The output encoding of canonicalized data */ - public static final String ENCODING = "UTF8"; + /** The output encoding of canonicalized data */ + public static final String ENCODING = "UTF8"; + + /** + * XPath Expresion for selecting every node and continuous comments joined + * in only one node + */ + public static final String XPATH_C14N_WITH_COMMENTS_SINGLE_NODE = + "(.//. | .//@* | .//namespace::*)"; + + /** + * The URL defined in XML-SEC Rec for inclusive c14n without comments. + */ + public static final String ALGO_ID_C14N_OMIT_COMMENTS = + "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"; + /** + * The URL defined in XML-SEC Rec for inclusive c14n with comments. + */ + public static final String ALGO_ID_C14N_WITH_COMMENTS = + ALGO_ID_C14N_OMIT_COMMENTS + "#WithComments"; + /** + * The URL defined in XML-SEC Rec for exclusive c14n without comments. + */ + public static final String ALGO_ID_C14N_EXCL_OMIT_COMMENTS = + "http://www.w3.org/2001/10/xml-exc-c14n#"; + /** + * The URL defined in XML-SEC Rec for exclusive c14n with comments. + */ + public static final String ALGO_ID_C14N_EXCL_WITH_COMMENTS = + ALGO_ID_C14N_EXCL_OMIT_COMMENTS + "WithComments"; + /** + * The URI for inclusive c14n 1.1 without comments. + */ + public static final String ALGO_ID_C14N11_OMIT_COMMENTS = + "http://www.w3.org/2006/12/xml-c14n11"; + /** + * The URI for inclusive c14n 1.1 with comments. + */ + public static final String ALGO_ID_C14N11_WITH_COMMENTS = + ALGO_ID_C14N11_OMIT_COMMENTS + "#WithComments"; + + static boolean _alreadyInitialized = false; + static Map _canonicalizerHash = null; + protected CanonicalizerSpi canonicalizerSpi = null; - /** - * XPath Expresion for selecting every node and continuos comments joined in only one node + /** + * Method init + * */ - public static final String XPATH_C14N_WITH_COMMENTS_SINGLE_NODE = "(.//. | .//@* | .//namespace::*)"; + public static void init() { + if (!Canonicalizer._alreadyInitialized) { + Canonicalizer._canonicalizerHash = new HashMap(10); + Canonicalizer._alreadyInitialized = true; + } + } - /** - * The URL defined in XML-SEC Rec for inclusive c14n without comments. + /** + * Constructor Canonicalizer + * + * @param algorithmURI + * @throws InvalidCanonicalizerException */ - public static final String ALGO_ID_C14N_OMIT_COMMENTS = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"; - /** - * The URL defined in XML-SEC Rec for inclusive c14n with comments. - */ - public static final String ALGO_ID_C14N_WITH_COMMENTS = ALGO_ID_C14N_OMIT_COMMENTS + "#WithComments"; - /** - * The URL defined in XML-SEC Rec for exclusive c14n without comments. - */ - public static final String ALGO_ID_C14N_EXCL_OMIT_COMMENTS = "http://www.w3.org/2001/10/xml-exc-c14n#"; - /** - * The URL defined in XML-SEC Rec for exclusive c14n with comments. - */ - public static final String ALGO_ID_C14N_EXCL_WITH_COMMENTS = ALGO_ID_C14N_EXCL_OMIT_COMMENTS + "WithComments"; - - static boolean _alreadyInitialized = false; - static Map _canonicalizerHash = null; - - protected CanonicalizerSpi canonicalizerSpi = null; - //J+ - - /** - * Method init - * - */ - public static void init() { - - if (!Canonicalizer._alreadyInitialized) { - Canonicalizer._canonicalizerHash = new HashMap(10); - Canonicalizer._alreadyInitialized = true; - } - } - - /** - * Constructor Canonicalizer - * - * @param algorithmURI - * @throws InvalidCanonicalizerException - */ - private Canonicalizer(String algorithmURI) + private Canonicalizer(String algorithmURI) throws InvalidCanonicalizerException { - try { - Class implementingClass = getImplementingClass(algorithmURI); - - this.canonicalizerSpi = - (CanonicalizerSpi) implementingClass.newInstance(); - this.canonicalizerSpi.reset=true; - } catch (Exception e) { - Object exArgs[] = { algorithmURI }; - - throw new InvalidCanonicalizerException( - "signature.Canonicalizer.UnknownCanonicalizer", exArgs); - } - } - - /** - * Method getInstance - * - * @param algorithmURI - * @return a Conicicalizer instance ready for the job - * @throws InvalidCanonicalizerException - */ - public static final Canonicalizer getInstance(String algorithmURI) + try { + Class implementingClass = getImplementingClass(algorithmURI); + + this.canonicalizerSpi = + (CanonicalizerSpi) implementingClass.newInstance(); + this.canonicalizerSpi.reset=true; + } catch (Exception e) { + Object exArgs[] = { algorithmURI }; + + throw new InvalidCanonicalizerException( + "signature.Canonicalizer.UnknownCanonicalizer", exArgs); + } + } + + /** + * Method getInstance + * + * @param algorithmURI + * @return a Conicicalizer instance ready for the job + * @throws InvalidCanonicalizerException + */ + public static final Canonicalizer getInstance(String algorithmURI) throws InvalidCanonicalizerException { - Canonicalizer c14nizer = new Canonicalizer(algorithmURI); + Canonicalizer c14nizer = new Canonicalizer(algorithmURI); - return c14nizer; - } + return c14nizer; + } - /** - * Method register - * - * @param algorithmURI - * @param implementingClass - * @throws AlgorithmAlreadyRegisteredException - */ - public static void register(String algorithmURI, String implementingClass) + /** + * Method register + * + * @param algorithmURI + * @param implementingClass + * @throws AlgorithmAlreadyRegisteredException + */ + public static void register(String algorithmURI, String implementingClass) throws AlgorithmAlreadyRegisteredException { - // check whether URI is already registered - Class registeredClass = getImplementingClass(algorithmURI); + // check whether URI is already registered + Class registeredClass = getImplementingClass(algorithmURI); - if (registeredClass != null) { - Object exArgs[] = { algorithmURI, registeredClass }; + if (registeredClass != null) { + Object exArgs[] = { algorithmURI, registeredClass }; - throw new AlgorithmAlreadyRegisteredException( - "algorithm.alreadyRegistered", exArgs); - } + throw new AlgorithmAlreadyRegisteredException( + "algorithm.alreadyRegistered", exArgs); + } - try { - _canonicalizerHash.put(algorithmURI, Class.forName(implementingClass)); + try { + _canonicalizerHash.put(algorithmURI, Class.forName(implementingClass)); } catch (ClassNotFoundException e) { - throw new RuntimeException("c14n class not found"); + throw new RuntimeException("c14n class not found"); } - } - - /** - * Method getURI - * - * @return the URI defined for this c14n instance. - */ - public final String getURI() { - return this.canonicalizerSpi.engineGetURI(); - } - - /** - * Method getIncludeComments - * - * @return true if the c14n respect the comments. - */ - public boolean getIncludeComments() { - return this.canonicalizerSpi.engineGetIncludeComments(); - } - - /** - * This method tries to canonicalize the given bytes. It's possible to even - * canonicalize non-wellformed sequences if they are well-formed after being - * wrapped with a >a<...>/a<. - * - * @param inputBytes - * @return the result of the conicalization. - * @throws CanonicalizationException - * @throws java.io.IOException - * @throws javax.xml.parsers.ParserConfigurationException - * @throws org.xml.sax.SAXException - */ - public byte[] canonicalize(byte[] inputBytes) + } + + /** + * Method getURI + * + * @return the URI defined for this c14n instance. + */ + public final String getURI() { + return this.canonicalizerSpi.engineGetURI(); + } + + /** + * Method getIncludeComments + * + * @return true if the c14n respect the comments. + */ + public boolean getIncludeComments() { + return this.canonicalizerSpi.engineGetIncludeComments(); + } + + /** + * This method tries to canonicalize the given bytes. It's possible to even + * canonicalize non-wellformed sequences if they are well-formed after being + * wrapped with a >a<...>/a<. + * + * @param inputBytes + * @return the result of the conicalization. + * @throws CanonicalizationException + * @throws java.io.IOException + * @throws javax.xml.parsers.ParserConfigurationException + * @throws org.xml.sax.SAXException + */ + public byte[] canonicalize(byte[] inputBytes) throws javax.xml.parsers.ParserConfigurationException, java.io.IOException, org.xml.sax.SAXException, CanonicalizationException { - ByteArrayInputStream bais = new ByteArrayInputStream(inputBytes); - InputSource in = new InputSource(bais); - DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); - - dfactory.setNamespaceAware(true); - - // needs to validate for ID attribute nomalization - dfactory.setValidating(true); - - DocumentBuilder db = dfactory.newDocumentBuilder(); - - /* - * for some of the test vectors from the specification, - * there has to be a validatin parser for ID attributes, default - * attribute values, NMTOKENS, etc. - * Unfortunaltely, the test vectors do use different DTDs or - * even no DTD. So Xerces 1.3.1 fires many warnings about using - * ErrorHandlers. - * - * Text from the spec: - * - * The input octet stream MUST contain a well-formed XML document, - * but the input need not be validated. However, the attribute - * value normalization and entity reference resolution MUST be - * performed in accordance with the behaviors of a validating - * XML processor. As well, nodes for default attributes (declared - * in the ATTLIST with an AttValue but not specified) are created - * in each element. Thus, the declarations in the document type - * declaration are used to help create the canonical form, even - * though the document type declaration is not retained in the - * canonical form. - * - */ - db.setErrorHandler(new com.sun.org.apache.xml.internal.security.utils - .IgnoreAllErrorHandler()); - - Document document = db.parse(in); - byte result[] = this.canonicalizeSubtree(document); - - return result; - } - - /** - * Canonicalizes the subtree rooted by node. - * - * @param node The node to canicalize - * @return the result of the c14n. - * - * @throws CanonicalizationException - */ - public byte[] canonicalizeSubtree(Node node) + ByteArrayInputStream bais = new ByteArrayInputStream(inputBytes); + InputSource in = new InputSource(bais); + DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); + + dfactory.setNamespaceAware(true); + + // needs to validate for ID attribute nomalization + dfactory.setValidating(true); + + DocumentBuilder db = dfactory.newDocumentBuilder(); + + /* + * for some of the test vectors from the specification, + * there has to be a validatin parser for ID attributes, default + * attribute values, NMTOKENS, etc. + * Unfortunaltely, the test vectors do use different DTDs or + * even no DTD. So Xerces 1.3.1 fires many warnings about using + * ErrorHandlers. + * + * Text from the spec: + * + * The input octet stream MUST contain a well-formed XML document, + * but the input need not be validated. However, the attribute + * value normalization and entity reference resolution MUST be + * performed in accordance with the behaviors of a validating + * XML processor. As well, nodes for default attributes (declared + * in the ATTLIST with an AttValue but not specified) are created + * in each element. Thus, the declarations in the document type + * declaration are used to help create the canonical form, even + * though the document type declaration is not retained in the + * canonical form. + * + */ + db.setErrorHandler(new com.sun.org.apache.xml.internal.security.utils + .IgnoreAllErrorHandler()); + + Document document = db.parse(in); + byte result[] = this.canonicalizeSubtree(document); + + return result; + } + + /** + * Canonicalizes the subtree rooted by node. + * + * @param node The node to canicalize + * @return the result of the c14n. + * + * @throws CanonicalizationException + */ + public byte[] canonicalizeSubtree(Node node) throws CanonicalizationException { - return this.canonicalizerSpi.engineCanonicalizeSubTree(node); - } - - /** - * Canonicalizes the subtree rooted by node. - * - * @param node - * @param inclusiveNamespaces - * @return the result of the c14n. - * @throws CanonicalizationException - */ - public byte[] canonicalizeSubtree(Node node, String inclusiveNamespaces) + return this.canonicalizerSpi.engineCanonicalizeSubTree(node); + } + + /** + * Canonicalizes the subtree rooted by node. + * + * @param node + * @param inclusiveNamespaces + * @return the result of the c14n. + * @throws CanonicalizationException + */ + public byte[] canonicalizeSubtree(Node node, String inclusiveNamespaces) throws CanonicalizationException { - return this.canonicalizerSpi.engineCanonicalizeSubTree(node, + return this.canonicalizerSpi.engineCanonicalizeSubTree(node, inclusiveNamespaces); - } - - /** - * Canonicalizes an XPath node set. The xpathNodeSet is treated - * as a list of XPath nodes, not as a list of subtrees. - * - * @param xpathNodeSet - * @return the result of the c14n. - * @throws CanonicalizationException - */ - public byte[] canonicalizeXPathNodeSet(NodeList xpathNodeSet) + } + + /** + * Canonicalizes an XPath node set. The xpathNodeSet is treated + * as a list of XPath nodes, not as a list of subtrees. + * + * @param xpathNodeSet + * @return the result of the c14n. + * @throws CanonicalizationException + */ + public byte[] canonicalizeXPathNodeSet(NodeList xpathNodeSet) throws CanonicalizationException { - return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet); - } - - /** - * Canonicalizes an XPath node set. The xpathNodeSet is treated - * as a list of XPath nodes, not as a list of subtrees. - * - * @param xpathNodeSet - * @param inclusiveNamespaces - * @return the result of the c14n. - * @throws CanonicalizationException - */ - public byte[] canonicalizeXPathNodeSet( + return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet); + } + + /** + * Canonicalizes an XPath node set. The xpathNodeSet is treated + * as a list of XPath nodes, not as a list of subtrees. + * + * @param xpathNodeSet + * @param inclusiveNamespaces + * @return the result of the c14n. + * @throws CanonicalizationException + */ + public byte[] canonicalizeXPathNodeSet( NodeList xpathNodeSet, String inclusiveNamespaces) throws CanonicalizationException { - return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet, + return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet, inclusiveNamespaces); - } - - /** - * Canonicalizes an XPath node set. - * - * @param xpathNodeSet - * @return the result of the c14n. - * @throws CanonicalizationException - */ - public byte[] canonicalizeXPathNodeSet(Set xpathNodeSet) + } + + /** + * Canonicalizes an XPath node set. + * + * @param xpathNodeSet + * @return the result of the c14n. + * @throws CanonicalizationException + */ + public byte[] canonicalizeXPathNodeSet(Set xpathNodeSet) throws CanonicalizationException { - return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet); - } - - /** - * Canonicalizes an XPath node set. - * - * @param xpathNodeSet - * @param inclusiveNamespaces - * @return the result of the c14n. - * @throws CanonicalizationException - */ - public byte[] canonicalizeXPathNodeSet( - Set xpathNodeSet, String inclusiveNamespaces) - throws CanonicalizationException { - return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet, - inclusiveNamespaces); - } - - /** - * Sets the writter where the cannocalization ends. ByteArrayOutputStream if - * none is setted. - * @param os - */ - public void setWriter(OutputStream os) { - this.canonicalizerSpi.setWriter(os); - } - - /** - * Returns the name of the implementing {@link CanonicalizerSpi} class - * - * @return the name of the implementing {@link CanonicalizerSpi} class - */ - public String getImplementingCanonicalizerClass() { - return this.canonicalizerSpi.getClass().getName(); - } - - /** - * Method getImplementingClass - * - * @param URI - * @return the name of the class that implements the give URI - */ - private static Class getImplementingClass(String URI) { - return (Class) _canonicalizerHash.get(URI); - } - - /** - * Set the canonicalizator behaviour to not reset. - * - */ - public void notReset() { - this.canonicalizerSpi.reset=false; - } + return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet); + } + + /** + * Canonicalizes an XPath node set. + * + * @param xpathNodeSet + * @param inclusiveNamespaces + * @return the result of the c14n. + * @throws CanonicalizationException + */ + public byte[] canonicalizeXPathNodeSet(Set xpathNodeSet, + String inclusiveNamespaces) throws CanonicalizationException { + return this.canonicalizerSpi.engineCanonicalizeXPathNodeSet(xpathNodeSet, + inclusiveNamespaces); + } + + /** + * Sets the writer where the canonicalization ends. ByteArrayOutputStream + * if none is set. + * @param os + */ + public void setWriter(OutputStream os) { + this.canonicalizerSpi.setWriter(os); + } + + /** + * Returns the name of the implementing {@link CanonicalizerSpi} class + * + * @return the name of the implementing {@link CanonicalizerSpi} class + */ + public String getImplementingCanonicalizerClass() { + return this.canonicalizerSpi.getClass().getName(); + } + + /** + * Method getImplementingClass + * + * @param URI + * @return the name of the class that implements the given URI + */ + private static Class getImplementingClass(String URI) { + return (Class) _canonicalizerHash.get(URI); + } + + /** + * Set the canonicalizer behaviour to not reset. + */ + public void notReset() { + this.canonicalizerSpi.reset = false; + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/InvalidCanonicalizerException.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/InvalidCanonicalizerException.java index 8af3ed88050382964bdf23e08cb4b091549a9d8f..9fb1531b7e910fa002e3373c8aec289c38d4df35 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/InvalidCanonicalizerException.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/InvalidCanonicalizerException.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/helper/AttrCompare.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/helper/AttrCompare.java index 46fdc660338e01752ad1fbe93dbe5b147298e0e7..802abda2862d10a033e43d2541c4f123ad623693 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/helper/AttrCompare.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/helper/AttrCompare.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -21,17 +20,17 @@ */ package com.sun.org.apache.xml.internal.security.c14n.helper; - - import com.sun.org.apache.xml.internal.security.utils.Constants; import org.w3c.dom.Attr; - +import java.io.Serializable; +import java.util.Comparator; /** * Compares two attributes based on the C14n specification. * *
    - *
  • Namespace nodes have a lesser document order position than attribute nodes. + *
  • Namespace nodes have a lesser document order position than attribute + * nodes. *
  • An element's namespace nodes are sorted lexicographically by * local name (the default namespace node, if one exists, has no * local name and is therefore lexicographically least). @@ -40,104 +39,89 @@ import org.w3c.dom.Attr; * key (an empty namespace URI is lexicographically least). *
* - * $todo$ Should we implement java.util.Comparator and import java.util.Arrays to use Arrays.sort(intarray); * @author Christian Geuer-Pollmann */ -public class AttrCompare implements java.util.Comparator { - - private final int ATTR0_BEFORE_ATTR1 = -1; - private final int ATTR1_BEFORE_ATTR0 = 1; - - private final static String XMLNS=Constants.NamespaceSpecNS; - /** - * Compares two attributes based on the C14n specification. - * - *
    - *
  • Namespace nodes have a lesser document order position than attribute nodes. - *
  • An element's namespace nodes are sorted lexicographically by - * local name (the default namespace node, if one exists, has no - * local name and is therefore lexicographically least). - *
  • An element's attribute nodes are sorted lexicographically with - * namespace URI as the primary key and local name as the secondary - * key (an empty namespace URI is lexicographically least). - *
- * - * @param obj0 casted Attr - * @param obj1 casted Attr - * @return returns a negative integer, zero, or a positive integer as obj0 is less than, equal to, or greater than obj1 - * - */ - public int compare(Object obj0, Object obj1) { - - Attr attr0 = (Attr) obj0; - Attr attr1 = (Attr) obj1; - String namespaceURI0 = attr0.getNamespaceURI(); - String namespaceURI1 = attr1.getNamespaceURI(); - - boolean isNamespaceAttr0 = - XMLNS.equals(namespaceURI0); - boolean isNamespaceAttr1 = - XMLNS.equals(namespaceURI1); - - if (isNamespaceAttr0) { - if (isNamespaceAttr1) { - - // both are namespaces - String localname0 = attr0.getLocalName(); - String localname1 = attr1.getLocalName(); - - if (localname0.equals("xmlns")) { - localname0 = ""; +public class AttrCompare implements Comparator, Serializable { + + private final static long serialVersionUID = -7113259629930576230L; + private final static int ATTR0_BEFORE_ATTR1 = -1; + private final static int ATTR1_BEFORE_ATTR0 = 1; + private final static String XMLNS=Constants.NamespaceSpecNS; + + /** + * Compares two attributes based on the C14n specification. + * + *
    + *
  • Namespace nodes have a lesser document order position than + * attribute nodes. + *
  • An element's namespace nodes are sorted lexicographically by + * local name (the default namespace node, if one exists, has no + * local name and is therefore lexicographically least). + *
  • An element's attribute nodes are sorted lexicographically with + * namespace URI as the primary key and local name as the secondary + * key (an empty namespace URI is lexicographically least). + *
+ * + * @param obj0 casted Attr + * @param obj1 casted Attr + * @return returns a negative integer, zero, or a positive integer as + * obj0 is less than, equal to, or greater than obj1 + * + */ + public int compare(Object obj0, Object obj1) { + + Attr attr0 = (Attr) obj0; + Attr attr1 = (Attr) obj1; + String namespaceURI0 = attr0.getNamespaceURI(); + String namespaceURI1 = attr1.getNamespaceURI(); + + boolean isNamespaceAttr0 = XMLNS==namespaceURI0; + boolean isNamespaceAttr1 = XMLNS==namespaceURI1; + + if (isNamespaceAttr0) { + if (isNamespaceAttr1) { + // both are namespaces + String localname0 = attr0.getLocalName(); + String localname1 = attr1.getLocalName(); + + if (localname0.equals("xmlns")) { + localname0 = ""; + } + + if (localname1.equals("xmlns")) { + localname1 = ""; + } + + return localname0.compareTo(localname1); } + // attr0 is a namespace, attr1 is not + return ATTR0_BEFORE_ATTR1; + } - if (localname1.equals("xmlns")) { - localname1 = ""; - } - - return localname0.compareTo(localname1); - } - // attr0 is a namespace, attr1 is not - return ATTR0_BEFORE_ATTR1; - - } - if (isNamespaceAttr1) { - + if (isNamespaceAttr1) { // attr1 is a namespace, attr0 is not return ATTR1_BEFORE_ATTR0; - } - - // none is a namespae - - if (namespaceURI0 == null) { - if (namespaceURI1 == null) { - /* - String localName0 = attr0.getLocalName(); - String localName1 = attr1.getLocalName(); - return localName0.compareTo(localName1); - */ + } + // none is a namespace + if (namespaceURI0 == null) { + if (namespaceURI1 == null) { String name0 = attr0.getName(); String name1 = attr1.getName(); return name0.compareTo(name1); + } + return ATTR0_BEFORE_ATTR1; } - return ATTR0_BEFORE_ATTR1; - } - if (namespaceURI1 == null) { - return ATTR1_BEFORE_ATTR0; - } - int a = namespaceURI0.compareTo(namespaceURI1); - - if (a != 0) { - return a; - } - /* - String localName0 = ; - String localName1 =;*/ - - return (attr0.getLocalName()) - .compareTo( attr1.getLocalName()); + if (namespaceURI1 == null) { + return ATTR1_BEFORE_ATTR0; + } - } + int a = namespaceURI0.compareTo(namespaceURI1); + if (a != 0) { + return a; + } + return (attr0.getLocalName()).compareTo(attr1.getLocalName()); + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11.java new file mode 100644 index 0000000000000000000000000000000000000000..4790fd890432a907e8c04e470b6aa4106f986cf9 --- /dev/null +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11.java @@ -0,0 +1,684 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2008 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.sun.org.apache.xml.internal.security.c14n.implementations; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import javax.xml.parsers.ParserConfigurationException; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + +import java.util.logging.Logger; +import java.util.logging.Logger; +import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; +import com.sun.org.apache.xml.internal.security.c14n.helper.C14nHelper; +import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput; +import com.sun.org.apache.xml.internal.security.utils.Constants; +import com.sun.org.apache.xml.internal.security.utils.XMLUtils; + +/** + * Implements + * Canonical XML Version 1.1, a W3C Proposed Recommendation from 29 + * January 2008. + * + * @author Sean Mullan + * @author Raul Benito + * @version $Revision: 1.2 $ + */ +public abstract class Canonicalizer11 extends CanonicalizerBase { + boolean firstCall = true; + final SortedSet result = new TreeSet(COMPARE); + static final String XMLNS_URI = Constants.NamespaceSpecNS; + static final String XML_LANG_URI = Constants.XML_LANG_SPACE_SpecNS; + + static Logger log = Logger.getLogger(Canonicalizer11.class.getName()); + + static class XmlAttrStack { + int currentLevel = 0; + int lastlevel = 0; + XmlsStackElement cur; + static class XmlsStackElement { + int level; + boolean rendered = false; + List nodes = new ArrayList(); + }; + List levels = new ArrayList(); + void push(int level) { + currentLevel = level; + if (currentLevel == -1) + return; + cur = null; + while (lastlevel >= currentLevel) { + levels.remove(levels.size() - 1); + if (levels.size() == 0) { + lastlevel = 0; + return; + } + lastlevel=((XmlsStackElement)levels.get(levels.size()-1)).level; + } + } + void addXmlnsAttr(Attr n) { + if (cur == null) { + cur = new XmlsStackElement(); + cur.level = currentLevel; + levels.add(cur); + lastlevel = currentLevel; + } + cur.nodes.add(n); + } + void getXmlnsAttr(Collection col) { + if (cur == null) { + cur = new XmlsStackElement(); + cur.level = currentLevel; + lastlevel = currentLevel; + levels.add(cur); + } + int size = levels.size() - 2; + boolean parentRendered = false; + XmlsStackElement e = null; + if (size == -1) { + parentRendered = true; + } else { + e = (XmlsStackElement) levels.get(size); + if (e.rendered && e.level+1 == currentLevel) + parentRendered = true; + } + if (parentRendered) { + col.addAll(cur.nodes); + cur.rendered = true; + return; + } + + Map loa = new HashMap(); + List baseAttrs = new ArrayList(); + boolean successiveOmitted = true; + for (;size>=0;size--) { + e = (XmlsStackElement) levels.get(size); + if (e.rendered) { + successiveOmitted = false; + } + Iterator it = e.nodes.iterator(); + while (it.hasNext() && successiveOmitted) { + Attr n = (Attr) it.next(); + if (n.getLocalName().equals("base")) { + if (!e.rendered) { + baseAttrs.add(n); + } + } else if (!loa.containsKey(n.getName())) + loa.put(n.getName(), n); + } + } + if (!baseAttrs.isEmpty()) { + Iterator it = cur.nodes.iterator(); + String base = null; + Attr baseAttr = null; + while (it.hasNext()) { + Attr n = (Attr) it.next(); + if (n.getLocalName().equals("base")) { + base = n.getValue(); + baseAttr = n; + break; + } + } + it = baseAttrs.iterator(); + while (it.hasNext()) { + Attr n = (Attr) it.next(); + if (base == null) { + base = n.getValue(); + baseAttr = n; + } else { + try { + base = joinURI(n.getValue(), base); + } catch (URISyntaxException ue) { + ue.printStackTrace(); + } + } + } + if (base != null && base.length() != 0) { + baseAttr.setValue(base); + col.add(baseAttr); + } + } + + cur.rendered = true; + col.addAll(loa.values()); + } + }; + XmlAttrStack xmlattrStack = new XmlAttrStack(); + + /** + * Constructor Canonicalizer11 + * + * @param includeComments + */ + public Canonicalizer11(boolean includeComments) { + super(includeComments); + } + + /** + * Returns the Attr[]s to be outputted for the given element. + *
+ * The code of this method is a copy of {@link #handleAttributes(Element, + * NameSpaceSymbTable)}, + * whereas it takes into account that subtree-c14n is -- well -- + * subtree-based. + * So if the element in question isRoot of c14n, it's parent is not in the + * node set, as well as all other ancestors. + * + * @param E + * @param ns + * @return the Attr[]s to be outputted + * @throws CanonicalizationException + */ + Iterator handleAttributesSubtree(Element E, NameSpaceSymbTable ns) + throws CanonicalizationException { + if (!E.hasAttributes() && !firstCall) { + return null; + } + // result will contain the attrs which have to be outputted + final SortedSet result = this.result; + result.clear(); + NamedNodeMap attrs = E.getAttributes(); + int attrsLength = attrs.getLength(); + + for (int i = 0; i < attrsLength; i++) { + Attr N = (Attr) attrs.item(i); + String NUri = N.getNamespaceURI(); + + if (XMLNS_URI != NUri) { + // It's not a namespace attr node. Add to the result and + // continue. + result.add(N); + continue; + } + + String NName = N.getLocalName(); + String NValue = N.getValue(); + if (XML.equals(NName) + && XML_LANG_URI.equals(NValue)) { + // The default mapping for xml must not be output. + continue; + } + + Node n = ns.addMappingAndRender(NName, NValue, N); + + if (n != null) { + // Render the ns definition + result.add(n); + if (C14nHelper.namespaceIsRelative(N)) { + Object exArgs[] = {E.getTagName(), NName, N.getNodeValue()}; + throw new CanonicalizationException( + "c14n.Canonicalizer.RelativeNamespace", exArgs); + } + } + } + + if (firstCall) { + // It is the first node of the subtree + // Obtain all the namespaces defined in the parents, and added + // to the output. + ns.getUnrenderedNodes(result); + // output the attributes in the xml namespace. + xmlattrStack.getXmlnsAttr(result); + firstCall = false; + } + + return result.iterator(); + } + + /** + * Returns the Attr[]s to be outputted for the given element. + *
+ * IMPORTANT: This method expects to work on a modified DOM tree, i.e. a + * DOM which has been prepared using + * {@link com.sun.org.apache.xml.internal.security.utils.XMLUtils#circumventBug2650( + * org.w3c.dom.Document)}. + * + * @param E + * @param ns + * @return the Attr[]s to be outputted + * @throws CanonicalizationException + */ + Iterator handleAttributes(Element E, NameSpaceSymbTable ns) + throws CanonicalizationException { + // result will contain the attrs which have to be output + xmlattrStack.push(ns.getLevel()); + boolean isRealVisible = isVisibleDO(E, ns.getLevel()) == 1; + NamedNodeMap attrs = null; + int attrsLength = 0; + if (E.hasAttributes()) { + attrs = E.getAttributes(); + attrsLength = attrs.getLength(); + } + + SortedSet result = this.result; + result.clear(); + + for (int i = 0; i < attrsLength; i++) { + Attr N = (Attr) attrs.item(i); + String NUri = N.getNamespaceURI(); + + if (XMLNS_URI != NUri) { + // A non namespace definition node. + if (XML_LANG_URI == NUri) { + if (N.getLocalName().equals("id")) { + if (isRealVisible) { + // treat xml:id like any other attribute + // (emit it, but don't inherit it) + result.add(N); + } + } else { + xmlattrStack.addXmlnsAttr(N); + } + } else if (isRealVisible) { + // The node is visible add the attribute to the list of + // output attributes. + result.add(N); + } + // keep working + continue; + } + + String NName = N.getLocalName(); + String NValue = N.getValue(); + if ("xml".equals(NName) + && XML_LANG_URI.equals(NValue)) { + /* except omit namespace node with local name xml, which defines + * the xml prefix, if its string value is + * http://www.w3.org/XML/1998/namespace. + */ + continue; + } + // add the prefix binding to the ns symb table. + // ns.addInclusiveMapping(NName,NValue,N,isRealVisible); + if (isVisible(N)) { + if (!isRealVisible && ns.removeMappingIfRender(NName)) { + continue; + } + // The xpath select this node output it if needed. + // Node n = ns.addMappingAndRenderXNodeSet + // (NName, NValue, N, isRealVisible); + Node n = ns.addMappingAndRender(NName, NValue, N); + if (n != null) { + result.add(n); + if (C14nHelper.namespaceIsRelative(N)) { + Object exArgs[] = + { E.getTagName(), NName, N.getNodeValue() }; + throw new CanonicalizationException( + "c14n.Canonicalizer.RelativeNamespace", exArgs); + } + } + } else { + if (isRealVisible && NName != XMLNS) { + ns.removeMapping(NName); + } else { + ns.addMapping(NName, NValue, N); + } + } + } + if (isRealVisible) { + // The element is visible, handle the xmlns definition + Attr xmlns = E.getAttributeNodeNS(XMLNS_URI, XMLNS); + Node n = null; + if (xmlns == null) { + // No xmlns def just get the already defined. + n = ns.getMapping(XMLNS); + } else if (!isVisible(xmlns)) { + // There is a defn but the xmlns is not selected by the xpath. + // then xmlns="" + n = ns.addMappingAndRender(XMLNS, "", nullNode); + } + // output the xmlns def if needed. + if (n != null) { + result.add(n); + } + // Float all xml:* attributes of the unselected parent elements to + // this one. addXmlAttributes(E,result); + xmlattrStack.getXmlnsAttr(result); + ns.getUnrenderedNodes(result); + } + + return result.iterator(); + } + + /** + * Always throws a CanonicalizationException because this is inclusive c14n. + * + * @param xpathNodeSet + * @param inclusiveNamespaces + * @return none it always fails + * @throws CanonicalizationException always + */ + public byte[] engineCanonicalizeXPathNodeSet(Set xpathNodeSet, + String inclusiveNamespaces) throws CanonicalizationException { + throw new CanonicalizationException( + "c14n.Canonicalizer.UnsupportedOperation"); + } + + /** + * Always throws a CanonicalizationException because this is inclusive c14n. + * + * @param rootNode + * @param inclusiveNamespaces + * @return none it always fails + * @throws CanonicalizationException + */ + public byte[] engineCanonicalizeSubTree(Node rootNode, + String inclusiveNamespaces) throws CanonicalizationException { + throw new CanonicalizationException( + "c14n.Canonicalizer.UnsupportedOperation"); + } + + void circumventBugIfNeeded(XMLSignatureInput input) + throws CanonicalizationException, ParserConfigurationException, + IOException, SAXException { + if (!input.isNeedsToBeExpanded()) + return; + Document doc = null; + if (input.getSubNode() != null) { + doc = XMLUtils.getOwnerDocument(input.getSubNode()); + } else { + doc = XMLUtils.getOwnerDocument(input.getNodeSet()); + } + XMLUtils.circumventBug2650(doc); + } + + void handleParent(Element e, NameSpaceSymbTable ns) { + if (!e.hasAttributes()) { + return; + } + xmlattrStack.push(-1); + NamedNodeMap attrs = e.getAttributes(); + int attrsLength = attrs.getLength(); + for (int i = 0; i < attrsLength; i++) { + Attr N = (Attr) attrs.item(i); + if (Constants.NamespaceSpecNS != N.getNamespaceURI()) { + // Not a namespace definition, ignore. + if (XML_LANG_URI == N.getNamespaceURI()) { + xmlattrStack.addXmlnsAttr(N); + } + continue; + } + + String NName = N.getLocalName(); + String NValue = N.getNodeValue(); + if (XML.equals(NName) + && Constants.XML_LANG_SPACE_SpecNS.equals(NValue)) { + continue; + } + ns.addMapping(NName,NValue,N); + } + } + + private static String joinURI(String baseURI, String relativeURI) + throws URISyntaxException { + String bscheme = null; + String bauthority = null; + String bpath = ""; + String bquery = null; + String bfragment = null; // Is this correct? + + // pre-parse the baseURI + if (baseURI != null) { + if (baseURI.endsWith("..")) { + baseURI = baseURI + "/"; + } + URI base = new URI(baseURI); + bscheme = base.getScheme(); + bauthority = base.getAuthority(); + bpath = base.getPath(); + bquery = base.getQuery(); + bfragment = base.getFragment(); + } + + URI r = new URI(relativeURI); + String rscheme = r.getScheme(); + String rauthority = r.getAuthority(); + String rpath = r.getPath(); + String rquery = r.getQuery(); + String rfragment = null; + + String tscheme, tauthority, tpath, tquery, tfragment; + if (rscheme != null && rscheme.equals(bscheme)) { + rscheme = null; + } + if (rscheme != null) { + tscheme = rscheme; + tauthority = rauthority; + tpath = removeDotSegments(rpath); + tquery = rquery; + } else { + if (rauthority != null) { + tauthority = rauthority; + tpath = removeDotSegments(rpath); + tquery = rquery; + } else { + if (rpath.length() == 0) { + tpath = bpath; + if (rquery != null) { + tquery = rquery; + } else { + tquery = bquery; + } + } else { + if (rpath.startsWith("/")) { + tpath = removeDotSegments(rpath); + } else { + if (bauthority != null && bpath.length() == 0) { + tpath = "/" + rpath; + } else { + int last = bpath.lastIndexOf('/'); + if (last == -1) { + tpath = rpath; + } else { + tpath = bpath.substring(0, last+1) + rpath; + } + } + tpath = removeDotSegments(tpath); + } + tquery = rquery; + } + tauthority = bauthority; + } + tscheme = bscheme; + } + tfragment = rfragment; + return new URI(tscheme, tauthority, tpath, tquery, tfragment).toString(); + } + + private static String removeDotSegments(String path) { + + log.log(java.util.logging.Level.FINE, "STEP OUTPUT BUFFER\t\tINPUT BUFFER"); + + // 1. The input buffer is initialized with the now-appended path + // components then replace occurrences of "//" in the input buffer + // with "/" until no more occurrences of "//" are in the input buffer. + String input = path; + while (input.indexOf("//") > -1) { + input = input.replaceAll("//", "/"); + } + + // Initialize the output buffer with the empty string. + StringBuffer output = new StringBuffer(); + + // If the input buffer starts with a root slash "/" then move this + // character to the output buffer. + if (input.charAt(0) == '/') { + output.append("/"); + input = input.substring(1); + } + + printStep("1 ", output.toString(), input); + + // While the input buffer is not empty, loop as follows + while (input.length() != 0) { + // 2A. If the input buffer begins with a prefix of "./", + // then remove that prefix from the input buffer + // else if the input buffer begins with a prefix of "../", then + // if also the output does not contain the root slash "/" only, + // then move this prefix to the end of the output buffer else + // remove that prefix + if (input.startsWith("./")) { + input = input.substring(2); + printStep("2A", output.toString(), input); + } else if (input.startsWith("../")) { + input = input.substring(3); + if (!output.toString().equals("/")) { + output.append("../"); + } + printStep("2A", output.toString(), input); + // 2B. if the input buffer begins with a prefix of "/./" or "/.", + // where "." is a complete path segment, then replace that prefix + // with "/" in the input buffer; otherwise, + } else if (input.startsWith("/./")) { + input = input.substring(2); + printStep("2B", output.toString(), input); + } else if (input.equals("/.")) { + // FIXME: what is complete path segment? + input = input.replaceFirst("/.", "/"); + printStep("2B", output.toString(), input); + // 2C. if the input buffer begins with a prefix of "/../" or "/..", + // where ".." is a complete path segment, then replace that prefix + // with "/" in the input buffer and if also the output buffer is + // empty, last segment in the output buffer equals "../" or "..", + // where ".." is a complete path segment, then append ".." or "/.." + // for the latter case respectively to the output buffer else + // remove the last segment and its preceding "/" (if any) from the + // output buffer and if hereby the first character in the output + // buffer was removed and it was not the root slash then delete a + // leading slash from the input buffer; otherwise, + } else if (input.startsWith("/../")) { + input = input.substring(3); + if (output.length() == 0) { + output.append("/"); + } else if (output.toString().endsWith("../")) { + output.append(".."); + } else if (output.toString().endsWith("..")) { + output.append("/.."); + } else { + int index = output.lastIndexOf("/"); + if (index == -1) { + output = new StringBuffer(); + if (input.charAt(0) == '/') { + input = input.substring(1); + } + } else { + output = output.delete(index, output.length()); + } + } + printStep("2C", output.toString(), input); + } else if (input.equals("/..")) { + // FIXME: what is complete path segment? + input = input.replaceFirst("/..", "/"); + if (output.length() == 0) { + output.append("/"); + } else if (output.toString().endsWith("../")) { + output.append(".."); + } else if (output.toString().endsWith("..")) { + output.append("/.."); + } else { + int index = output.lastIndexOf("/"); + if (index == -1) { + output = new StringBuffer(); + if (input.charAt(0) == '/') { + input = input.substring(1); + } + } else { + output = output.delete(index, output.length()); + } + } + printStep("2C", output.toString(), input); + // 2D. if the input buffer consists only of ".", then remove + // that from the input buffer else if the input buffer consists + // only of ".." and if the output buffer does not contain only + // the root slash "/", then move the ".." to the output buffer + // else delte it.; otherwise, + } else if (input.equals(".")) { + input = ""; + printStep("2D", output.toString(), input); + } else if (input.equals("..")) { + if (!output.toString().equals("/")) + output.append(".."); + input = ""; + printStep("2D", output.toString(), input); + // 2E. move the first path segment (if any) in the input buffer + // to the end of the output buffer, including the initial "/" + // character (if any) and any subsequent characters up to, but not + // including, the next "/" character or the end of the input buffer. + } else { + int end = -1; + int begin = input.indexOf('/'); + if (begin == 0) { + end = input.indexOf('/', 1); + } else { + end = begin; + begin = 0; + } + String segment; + if (end == -1) { + segment = input.substring(begin); + input = ""; + } else { + segment = input.substring(begin, end); + input = input.substring(end); + } + output.append(segment); + printStep("2E", output.toString(), input); + } + } + + // 3. Finally, if the only or last segment of the output buffer is + // "..", where ".." is a complete path segment not followed by a slash + // then append a slash "/". The output buffer is returned as the result + // of remove_dot_segments + if (output.toString().endsWith("..")) { + output.append("/"); + printStep("3 ", output.toString(), input); + } + + return output.toString(); + } + + private static void printStep(String step, String output, String input) { + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, " " + step + ": " + output); + if (output.length() == 0) { + log.log(java.util.logging.Level.FINE, "\t\t\t\t" + input); + } else { + log.log(java.util.logging.Level.FINE, "\t\t\t" + input); + } + } + } +} diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11_OmitComments.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11_OmitComments.java new file mode 100644 index 0000000000000000000000000000000000000000..31903667f606de63a33954c907ba9a7b7fc42fbe --- /dev/null +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11_OmitComments.java @@ -0,0 +1,41 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2008 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.sun.org.apache.xml.internal.security.c14n.implementations; + +import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer; + +/** + * @author Sean Mullan + */ +public class Canonicalizer11_OmitComments extends Canonicalizer11 { + + public Canonicalizer11_OmitComments() { + super(false); + } + + public final String engineGetURI() { + return Canonicalizer.ALGO_ID_C14N11_OMIT_COMMENTS; + } + + public final boolean engineGetIncludeComments() { + return false; + } +} diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11_WithComments.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11_WithComments.java new file mode 100644 index 0000000000000000000000000000000000000000..ba650c10872ca6b9dbe609e411da98bb5b5cc44c --- /dev/null +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer11_WithComments.java @@ -0,0 +1,41 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2008 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.sun.org.apache.xml.internal.security.c14n.implementations; + +import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer; + +/** + * @author Sean Mullan + */ +public class Canonicalizer11_WithComments extends Canonicalizer11 { + + public Canonicalizer11_WithComments() { + super(true); + } + + public final String engineGetURI() { + return Canonicalizer.ALGO_ID_C14N11_WITH_COMMENTS; + } + + public final boolean engineGetIncludeComments() { + return true; + } +} diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315.java index 5dbeb60f98519e7f083052696214278f0a8faffa..541c2d63c99574da4cd210b2d61d7d4479f3a57f 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -23,20 +22,30 @@ package com.sun.org.apache.xml.internal.security.c14n.implementations; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import javax.xml.parsers.ParserConfigurationException; + import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; import com.sun.org.apache.xml.internal.security.c14n.helper.C14nHelper; +import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput; import com.sun.org.apache.xml.internal.security.utils.Constants; +import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import org.w3c.dom.Attr; +import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; +import org.xml.sax.SAXException; /** @@ -44,13 +53,92 @@ import org.w3c.dom.Node; * XML Version 1.0, a W3C Recommendation from 15 March 2001. * * @author Christian Geuer-Pollmann + * @version $Revision: 1.5 $ */ public abstract class Canonicalizer20010315 extends CanonicalizerBase { boolean firstCall=true; final SortedSet result= new TreeSet(COMPARE); static final String XMLNS_URI=Constants.NamespaceSpecNS; static final String XML_LANG_URI=Constants.XML_LANG_SPACE_SpecNS; - /** + static class XmlAttrStack { + int currentLevel=0; + int lastlevel=0; + XmlsStackElement cur; + static class XmlsStackElement { + int level; + boolean rendered=false; + List nodes=new ArrayList(); + }; + List levels=new ArrayList(); + void push(int level) { + currentLevel=level; + if (currentLevel==-1) + return; + cur=null; + while (lastlevel>=currentLevel) { + levels.remove(levels.size()-1); + if (levels.size()==0) { + lastlevel=0; + return; + } + lastlevel=((XmlsStackElement)levels.get(levels.size()-1)).level; + } + } + void addXmlnsAttr(Attr n) { + if (cur==null) { + cur=new XmlsStackElement(); + cur.level=currentLevel; + levels.add(cur); + lastlevel=currentLevel; + } + cur.nodes.add(n); + } + void getXmlnsAttr(Collection col) { + int size=levels.size()-1; + if (cur==null) { + cur=new XmlsStackElement(); + cur.level=currentLevel; + lastlevel=currentLevel; + levels.add(cur); + } + boolean parentRendered=false; + XmlsStackElement e=null; + if (size==-1) { + parentRendered=true; + } else { + e=(XmlsStackElement)levels.get(size); + if (e.rendered && e.level+1==currentLevel) + parentRendered=true; + + } + if (parentRendered) { + col.addAll(cur.nodes); + cur.rendered=true; + return; + } + + Map loa = new HashMap(); + for (;size>=0;size--) { + e=(XmlsStackElement)levels.get(size); + Iterator it=e.nodes.iterator(); + while (it.hasNext()) { + Attr n=(Attr)it.next(); + if (!loa.containsKey(n.getName())) + loa.put(n.getName(),n); + } + //if (e.rendered) + //break; + + }; + //cur.nodes.clear(); + //cur.nodes.addAll(loa.values()); + cur.rendered=true; + col.addAll(loa.values()); + } + + } + XmlAttrStack xmlattrStack=new XmlAttrStack(); + /** * Constructor Canonicalizer20010315 * * @param includeComments @@ -86,16 +174,16 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { for (int i = 0; i < attrsLength; i++) { Attr N = (Attr) attrs.item(i); - String NName=N.getLocalName(); - String NValue=N.getValue(); String NUri =N.getNamespaceURI(); - if (!XMLNS_URI.equals(NUri)) { + if (XMLNS_URI!=NUri) { //It's not a namespace attr node. Add to the result and continue. result.add(N); continue; } + String NName=N.getLocalName(); + String NValue=N.getValue(); if (XML.equals(NName) && XML_LANG_URI.equals(NValue)) { //The default mapping for xml must not be output. @@ -120,64 +208,13 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { //Obtain all the namespaces defined in the parents, and added to the output. ns.getUnrenderedNodes(result); //output the attributes in the xml namespace. - addXmlAttributesSubtree(E, result); - firstCall=false; + xmlattrStack.getXmlnsAttr(result); + firstCall=false; } return result.iterator(); } - /** - * Float the xml:* attributes of the parent nodes to the root node of c14n - * @param E the root node. - * @param result the xml:* attributes to output. - */ - private void addXmlAttributesSubtree(Element E, SortedSet result) { - // E is in the node-set - Node parent = E.getParentNode(); - Map loa = new HashMap(); - - if ((parent != null) && (parent.getNodeType() == Node.ELEMENT_NODE)) { - - // parent element is not in node set - for (Node ancestor = parent; - (ancestor != null) - && (ancestor.getNodeType() == Node.ELEMENT_NODE); - ancestor = ancestor.getParentNode()) { - Element el=((Element) ancestor); - if (!el.hasAttributes()) { - continue; - } - // for all ancestor elements - NamedNodeMap ancestorAttrs = el.getAttributes(); - - for (int i = 0; i < ancestorAttrs.getLength(); i++) { - // for all attributes in the ancestor element - Attr currentAncestorAttr = (Attr) ancestorAttrs.item(i); - - if (XML_LANG_URI.equals( - currentAncestorAttr.getNamespaceURI())) { - - // do we have an xml:* ? - if (!E.hasAttributeNS( - XML_LANG_URI, - currentAncestorAttr.getLocalName())) { - - // the xml:* attr is not in E - if (!loa.containsKey(currentAncestorAttr.getName())) { - loa.put(currentAncestorAttr.getName(), - currentAncestorAttr); - } - } - } - } - } - } - - result.addAll( loa.values()); - - } - /** * Returns the Attr[]s to be outputted for the given element. *
@@ -192,7 +229,8 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { */ Iterator handleAttributes(Element E, NameSpaceSymbTable ns ) throws CanonicalizationException { // result will contain the attrs which have to be outputted - boolean isRealVisible=isVisible(E); + xmlattrStack.push(ns.getLevel()); + boolean isRealVisible=isVisibleDO(E,ns.getLevel())==1; NamedNodeMap attrs = null; int attrsLength = 0; if (E.hasAttributes()) { @@ -204,16 +242,15 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { SortedSet result = this.result; result.clear(); - for (int i = 0; i < attrsLength; i++) { Attr N = (Attr) attrs.item(i); - String NName=N.getLocalName(); - String NValue=N.getValue(); String NUri =N.getNamespaceURI(); - if (!XMLNS_URI.equals(NUri)) { + if (XMLNS_URI!=NUri) { //A non namespace definition node. - if (isRealVisible){ + if (XML_LANG_URI==NUri) { + xmlattrStack.addXmlnsAttr(N); + } else if (isRealVisible){ //The node is visible add the attribute to the list of output attributes. result.add(N); } @@ -221,7 +258,8 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { continue; } - + String NName=N.getLocalName(); + String NValue=N.getValue(); if ("xml".equals(NName) && XML_LANG_URI.equals(NValue)) { /* except omit namespace node with local name xml, which defines @@ -232,16 +270,26 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { //add the prefix binding to the ns symb table. //ns.addInclusiveMapping(NName,NValue,N,isRealVisible); if (isVisible(N)) { - //The xpath select this node output it if needed. - Node n=ns.addMappingAndRenderXNodeSet(NName,NValue,N,isRealVisible); - if (n!=null) { + if (!isRealVisible && ns.removeMappingIfRender(NName)) { + continue; + } + //The xpath select this node output it if needed. + //Node n=ns.addMappingAndRenderXNodeSet(NName,NValue,N,isRealVisible); + Node n=ns.addMappingAndRender(NName,NValue,N); + if (n!=null) { result.add(n); if (C14nHelper.namespaceIsRelative(N)) { Object exArgs[] = { E.getTagName(), NName, N.getNodeValue() }; throw new CanonicalizationException( "c14n.Canonicalizer.RelativeNamespace", exArgs); - } - } + } + } + } else { + if (isRealVisible && NName!=XMLNS) { + ns.removeMapping(NName); + } else { + ns.addMapping(NName,NValue,N); + } } } if (isRealVisible) { @@ -254,84 +302,21 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { } else if ( !isVisible(xmlns)) { //There is a definition but the xmlns is not selected by the xpath. //then xmlns="" - n=ns.addMappingAndRenderXNodeSet(XMLNS,"",nullNode,true); + n=ns.addMappingAndRender(XMLNS,"",nullNode); } //output the xmlns def if needed. if (n!=null) { result.add(n); } //Float all xml:* attributes of the unselected parent elements to this one. - addXmlAttributes(E,result); + //addXmlAttributes(E,result); + xmlattrStack.getXmlnsAttr(result); + ns.getUnrenderedNodes(result); + } return result.iterator(); } - /** - * Float the xml:* attributes of the unselected parent nodes to the ciurrent node. - * @param E - * @param result - */ - private void addXmlAttributes(Element E, SortedSet result) { - /* The processing of an element node E MUST be modified slightly when an - * XPath node-set is given as input and the element's parent is omitted - * from the node-set. The method for processing the attribute axis of an - * element E in the node-set is enhanced. All element nodes along E's - * ancestor axis are examined for nearest occurrences of attributes in - * the xml namespace, such as xml:lang and xml:space (whether or not they - * are in the node-set). From this list of attributes, remove any that are - * in E's attribute axis (whether or not they are in the node-set). Then, - * lexicographically merge this attribute list with the nodes of E's - * attribute axis that are in the node-set. The result of visiting the - * attribute axis is computed by processing the attribute nodes in this - * merged attribute list. - */ - - // E is in the node-set - Node parent = E.getParentNode(); - Map loa = new HashMap(); - - if ((parent != null) && (parent.getNodeType() == Node.ELEMENT_NODE) - &&!isVisible(parent)) { - - // parent element is not in node set - for (Node ancestor = parent; - (ancestor != null) - && (ancestor.getNodeType() == Node.ELEMENT_NODE); - ancestor = ancestor.getParentNode()) { - Element el=((Element) ancestor); - if (!el.hasAttributes()) { - continue; - } - // for all ancestor elements - NamedNodeMap ancestorAttrs =el.getAttributes(); - - for (int i = 0; i < ancestorAttrs.getLength(); i++) { - - // for all attributes in the ancestor element - Attr currentAncestorAttr = (Attr) ancestorAttrs.item(i); - - if (XML_LANG_URI.equals( - currentAncestorAttr.getNamespaceURI())) { - - // do we have an xml:* ? - if (!E.hasAttributeNS( - XML_LANG_URI, - currentAncestorAttr.getLocalName())) { - - // the xml:* attr is not in E - if (!loa.containsKey(currentAncestorAttr.getName())) { - loa.put(currentAncestorAttr.getName(), - currentAncestorAttr); - } - } - } - } - } - } - result.addAll(loa.values()); - -} - /** * Always throws a CanonicalizationException because this is inclusive c14n. * @@ -363,4 +348,43 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase { throw new CanonicalizationException( "c14n.Canonicalizer.UnsupportedOperation"); } + void circumventBugIfNeeded(XMLSignatureInput input) throws CanonicalizationException, ParserConfigurationException, IOException, SAXException { + if (!input.isNeedsToBeExpanded()) + return; + Document doc = null; + if (input.getSubNode() != null) { + doc=XMLUtils.getOwnerDocument(input.getSubNode()); + } else { + doc=XMLUtils.getOwnerDocument(input.getNodeSet()); + } + XMLUtils.circumventBug2650(doc); + + } + + void handleParent(Element e, NameSpaceSymbTable ns) { + if (!e.hasAttributes()) { + return; + } + xmlattrStack.push(-1); + NamedNodeMap attrs = e.getAttributes(); + int attrsLength = attrs.getLength(); + for (int i = 0; i < attrsLength; i++) { + Attr N = (Attr) attrs.item(i); + if (Constants.NamespaceSpecNS!=N.getNamespaceURI()) { + //Not a namespace definition, ignore. + if (XML_LANG_URI==N.getNamespaceURI()) { + xmlattrStack.addXmlnsAttr(N); + } + continue; + } + + String NName=N.getLocalName(); + String NValue=N.getNodeValue(); + if (XML.equals(NName) + && Constants.XML_LANG_SPACE_SpecNS.equals(NValue)) { + continue; + } + ns.addMapping(NName,NValue,N); + } + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315Excl.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315Excl.java index 18f697366cf51c12194970fda695aba978cda1bd..679c7b5088b7ca62547ca329e33a354d0f5f9015 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315Excl.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315Excl.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -21,20 +20,26 @@ */ package com.sun.org.apache.xml.internal.security.c14n.implementations; +import java.io.IOException; import java.util.Iterator; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import javax.xml.parsers.ParserConfigurationException; + import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; import com.sun.org.apache.xml.internal.security.c14n.helper.C14nHelper; import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput; import com.sun.org.apache.xml.internal.security.transforms.params.InclusiveNamespaces; import com.sun.org.apache.xml.internal.security.utils.Constants; +import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import org.w3c.dom.Attr; +import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; +import org.xml.sax.SAXException; /** * Implements " Exclusive XML @@ -47,6 +52,7 @@ import org.w3c.dom.Node; * THIS implementation is a complete rewrite of the algorithm. * * @author Christian Geuer-Pollmann + * @version $Revision: 1.5 $ * @see * XML Canonicalization, Version 1.0 */ @@ -55,7 +61,7 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { * This Set contains the names (Strings like "xmlns" or "xmlns:foo") of * the inclusive namespaces. */ - TreeSet _inclusiveNSSet = null; + TreeSet _inclusiveNSSet = new TreeSet(); static final String XMLNS_URI=Constants.NamespaceSpecNS; final SortedSet result = new TreeSet(COMPARE); /** @@ -143,10 +149,8 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { for (int i = 0; i < attrsLength; i++) { Attr N = (Attr) attrs.item(i); - String NName=N.getLocalName(); - String NNodeValue=N.getNodeValue(); - if (!XMLNS_URI.equals(N.getNamespaceURI())) { + if (XMLNS_URI!=N.getNamespaceURI()) { //Not a namespace definition. //The Element is output element, add his prefix(if used) to visibyUtilized String prefix = N.getPrefix(); @@ -157,6 +161,8 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { result.add(N); continue; } + String NName=N.getLocalName(); + String NNodeValue=N.getNodeValue(); if (ns.addMapping(NName, NNodeValue,N)) { //New definition check if it is relative. @@ -168,17 +174,17 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { } } } - + String prefix; if (E.getNamespaceURI() != null) { - String prefix = E.getPrefix(); + prefix = E.getPrefix(); if ((prefix == null) || (prefix.length() == 0)) { - visiblyUtilized.add(XMLNS); - } else { - visiblyUtilized.add(prefix); + prefix=XMLNS; } + } else { - visiblyUtilized.add(XMLNS); + prefix=XMLNS; } + visiblyUtilized.add(prefix); //This can be optimezed by I don't have time Iterator it=visiblyUtilized.iterator(); @@ -211,12 +217,6 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { } - /** @inheritDoc */ - public byte[] engineCanonicalizeXPathNodeSet(Set xpathNodeSet - ) throws CanonicalizationException { - return engineCanonicalizeXPathNodeSet(xpathNodeSet,""); - } - /** * @inheritDoc * @param E @@ -236,21 +236,20 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { //The prefix visibly utilized(in the attribute or in the name) in the element Set visiblyUtilized =null; //It's the output selected. - boolean isOutputElement = isVisible(E); + boolean isOutputElement=isVisibleDO(E,ns.getLevel())==1; if (isOutputElement) { visiblyUtilized = (Set) this._inclusiveNSSet.clone(); } for (int i = 0; i < attrsLength; i++) { Attr N = (Attr) attrs.item(i); - String NName=N.getLocalName(); - String NNodeValue=N.getNodeValue(); - if ( !isVisible(N) ) { - //The node is not in the nodeset(if there is a nodeset) - continue; - } - if (!XMLNS_URI.equals(N.getNamespaceURI())) { + + if (XMLNS_URI!=N.getNamespaceURI()) { + if ( !isVisible(N) ) { + //The node is not in the nodeset(if there is a nodeset) + continue; + } //Not a namespace definition. if (isOutputElement) { //The Element is output element, add his prefix(if used) to visibyUtilized @@ -263,6 +262,25 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { } continue; } + String NName=N.getLocalName(); + if (isOutputElement && !isVisible(N) && NName!=XMLNS) { + ns.removeMappingIfNotRender(NName); + continue; + } + String NNodeValue=N.getNodeValue(); + + if (!isOutputElement && isVisible(N) && _inclusiveNSSet.contains(NName) && !ns.removeMappingIfRender(NName)) { + Node n=ns.addMappingAndRender(NName,NNodeValue,N); + if (n!=null) { + result.add(n); + if (C14nHelper.namespaceIsRelative(N)) { + Object exArgs[] = { E.getTagName(), NName, N.getNodeValue() }; + throw new CanonicalizationException( + "c14n.Canonicalizer.RelativeNamespace", exArgs); + } + } + } + if (ns.addMapping(NName, NNodeValue,N)) { @@ -306,18 +324,20 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { } result.add(key); } - } else /*if (_circunvented)*/ { - Iterator it=this._inclusiveNSSet.iterator(); - while (it.hasNext()) { - String s=(String)it.next(); - Attr key=ns.getMappingWithoutRendered(s); - if (key==null) { - continue; - } - result.add(key); - } } return result.iterator(); } + void circumventBugIfNeeded(XMLSignatureInput input) throws CanonicalizationException, ParserConfigurationException, IOException, SAXException { + if (!input.isNeedsToBeExpanded() || _inclusiveNSSet.isEmpty()) + return; + Document doc = null; + if (input.getSubNode() != null) { + doc=XMLUtils.getOwnerDocument(input.getSubNode()); + } else { + doc=XMLUtils.getOwnerDocument(input.getNodeSet()); + } + + XMLUtils.circumventBug2650(doc); + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315ExclWithComments.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315ExclWithComments.java index 025502bd5feff48f2fa166ff835b8b7d9776f839..375501248793936249faa0ca3743c32470c1b4b0 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315ExclWithComments.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315ExclWithComments.java @@ -28,6 +28,7 @@ import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer; /** * Class Canonicalizer20010315ExclWithComments * + * @version $Revision: 1.5 $ */ public class Canonicalizer20010315ExclWithComments extends Canonicalizer20010315Excl { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315WithComments.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315WithComments.java index 539bb3a3957fbd315eff3d674c79d66876e1eb56..4714e165bba6500b9d58913063f5eb274db242e0 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315WithComments.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315WithComments.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/CanonicalizerBase.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/CanonicalizerBase.java index 8108763750f95abde0d5df456fc143468435ec9a..05f22d8c1e8cc6573a74fb3c6b204c49bcd6413e 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/CanonicalizerBase.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/CanonicalizerBase.java @@ -27,9 +27,11 @@ import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; +import java.util.Map; import java.util.Set; import javax.xml.parsers.DocumentBuilderFactory; @@ -45,7 +47,6 @@ import com.sun.org.apache.xml.internal.security.utils.UnsyncByteArrayOutputStrea import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import org.w3c.dom.Attr; import org.w3c.dom.Comment; -import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -57,6 +58,7 @@ import org.xml.sax.SAXException; * Abstract base class for canonicalization algorithms. * * @author Christian Geuer-Pollmann + * @version $Revision: 1.5 $ */ public abstract class CanonicalizerBase extends CanonicalizerSpi { //Constants to be outputed, In char array form, so @@ -122,6 +124,18 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { throws CanonicalizationException { return engineCanonicalizeSubTree(rootNode,(Node)null); } + /** + * Method engineCanonicalizeXPathNodeSet + * @inheritDoc + * @param xpathNodeSet + * @throws CanonicalizationException + */ + public byte[] engineCanonicalizeXPathNodeSet(Set xpathNodeSet) + throws CanonicalizationException { + this._xpathNodeSet = xpathNodeSet; + return engineCanonicalizeXPathNodeSetInternal(XMLUtils.getOwnerDocument(this._xpathNodeSet)); + } + /** * Canonicalizes a Subtree node. * @param input the root of the subtree to canicalize @@ -143,15 +157,8 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { return bytes; } else if (input.isNodeSet()) { nodeFilter=input.getNodeFilters(); - Document doc = null; - if (input.getSubNode() != null) { - doc=XMLUtils.getOwnerDocument(input.getSubNode()); - } else { - doc=XMLUtils.getOwnerDocument(input.getNodeSet()); - } - if (input.isNeedsToBeExpanded()) { - XMLUtils.circumventBug2650(doc); - } + + circumventBugIfNeeded(input); if (input.getSubNode() != null) { bytes = engineCanonicalizeXPathNodeSetInternal(input.getSubNode()); @@ -173,6 +180,13 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { } } /** + * @param _writer The _writer to set. + */ + public void setWriter(OutputStream _writer) { + this._writer = _writer; + } + + /** * Canonicalizes a Subtree node. * * @param rootNode @@ -187,11 +201,13 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { this._excludeNode = excludeNode; try { NameSpaceSymbTable ns=new NameSpaceSymbTable(); + int nodeLevel=NODE_BEFORE_DOCUMENT_ELEMENT; if (rootNode instanceof Element) { //Fills the nssymbtable with the definitions of the parent of the root subnode getParentNameSpaces((Element)rootNode,ns); + nodeLevel=NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; } - this.canonicalizeSubTree(rootNode,ns,rootNode); + this.canonicalizeSubTree(rootNode,ns,rootNode,nodeLevel); this._writer.close(); if (this._writer instanceof ByteArrayOutputStream) { byte []result=((ByteArrayOutputStream)this._writer).toByteArray(); @@ -199,6 +215,12 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { ((ByteArrayOutputStream)this._writer).reset(); } return result; + } else if (this._writer instanceof UnsyncByteArrayOutputStream) { + byte []result=((UnsyncByteArrayOutputStream)this._writer).toByteArray(); + if (reset) { + ((UnsyncByteArrayOutputStream)this._writer).reset(); + } + return result; } return null; @@ -219,13 +241,17 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { * @throws CanonicalizationException * @throws IOException */ - final void canonicalizeSubTree(Node currentNode, NameSpaceSymbTable ns,Node endnode) + final void canonicalizeSubTree(Node currentNode, NameSpaceSymbTable ns,Node endnode, + int documentLevel) throws CanonicalizationException, IOException { + if (isVisibleInt(currentNode)==-1) + return; Node sibling=null; Node parentNode=null; final OutputStream writer=this._writer; final Node excludeNode=this._excludeNode; final boolean includeComments=this._includeComments; + Map cache=new HashMap(); do { switch (currentNode.getNodeType()) { @@ -242,18 +268,17 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { case Node.DOCUMENT_FRAGMENT_NODE : case Node.DOCUMENT_NODE : ns.outputNodePush(); - //currentNode = currentNode.getFirstChild(); sibling= currentNode.getFirstChild(); break; case Node.COMMENT_NODE : if (includeComments) { - outputCommentToWriter((Comment) currentNode, writer); + outputCommentToWriter((Comment) currentNode, writer, documentLevel); } break; case Node.PROCESSING_INSTRUCTION_NODE : - outputPItoWriter((ProcessingInstruction) currentNode, writer); + outputPItoWriter((ProcessingInstruction) currentNode, writer, documentLevel); break; case Node.TEXT_NODE : @@ -262,6 +287,7 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { break; case Node.ELEMENT_NODE : + documentLevel=NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; if (currentNode==excludeNode) { break; } @@ -270,27 +296,27 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { ns.outputNodePush(); writer.write('<'); String name=currentElement.getTagName(); - writeStringToUtf8(name,writer); + UtfHelpper.writeByte(name,writer,cache); Iterator attrs = this.handleAttributesSubtree(currentElement,ns); if (attrs!=null) { //we output all Attrs which are available while (attrs.hasNext()) { Attr attr = (Attr) attrs.next(); - outputAttrToWriter(attr.getNodeName(),attr.getNodeValue(), writer); + outputAttrToWriter(attr.getNodeName(),attr.getNodeValue(), writer,cache); } } writer.write('>'); sibling= currentNode.getFirstChild(); if (sibling==null) { writer.write(_END_TAG); - writeStringToUtf8(name,writer); + UtfHelpper.writeStringToUtf8(name,writer); writer.write('>'); //We fineshed with this level, pop to the previous definitions. ns.outputNodePop(); - if (parentNode != null) { + if (parentNode != null) { sibling= currentNode.getNextSibling(); - } + } } else { parentNode=currentElement; } @@ -298,7 +324,7 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { } while (sibling==null && parentNode!=null) { writer.write(_END_TAG); - writeStringToUtf8(((Element)parentNode).getTagName(),writer); + UtfHelpper.writeByte(((Element)parentNode).getTagName(),writer,cache); writer.write('>'); //We fineshed with this level, pop to the previous definitions. ns.outputNodePop(); @@ -307,6 +333,7 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { sibling=parentNode.getNextSibling(); parentNode=parentNode.getParentNode(); if (!(parentNode instanceof Element)) { + documentLevel=NODE_AFTER_DOCUMENT_ELEMENT; parentNode=null; } } @@ -317,47 +344,8 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { } while(true); } - /** - * Checks whether a Comment or ProcessingInstruction is before or after the - * document element. This is needed for prepending or appending "\n"s. - * - * @param currentNode comment or pi to check - * @return NODE_BEFORE_DOCUMENT_ELEMENT, NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT or NODE_AFTER_DOCUMENT_ELEMENT - * @see #NODE_BEFORE_DOCUMENT_ELEMENT - * @see #NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT - * @see #NODE_AFTER_DOCUMENT_ELEMENT - */ - final static int getPositionRelativeToDocumentElement(Node currentNode) { - if ((currentNode == null) || - (currentNode.getParentNode().getNodeType() != Node.DOCUMENT_NODE) ) { - return CanonicalizerBase.NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; - } - Element documentElement = currentNode.getOwnerDocument().getDocumentElement(); - if ( (documentElement == null) || (documentElement == currentNode) ){ - return CanonicalizerBase.NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; - } - for (Node x = currentNode; x != null; x = x.getNextSibling()) { - if (x == documentElement) { - return CanonicalizerBase.NODE_BEFORE_DOCUMENT_ELEMENT; - } - } - - return CanonicalizerBase.NODE_AFTER_DOCUMENT_ELEMENT; - } - - /** - * Method engineCanonicalizeXPathNodeSet - * @inheritDoc - * @param xpathNodeSet - * @throws CanonicalizationException - */ - public byte[] engineCanonicalizeXPathNodeSet(Set xpathNodeSet) - throws CanonicalizationException { - this._xpathNodeSet = xpathNodeSet; - return engineCanonicalizeXPathNodeSetInternal(XMLUtils.getOwnerDocument(this._xpathNodeSet)); - } private byte[] engineCanonicalizeXPathNodeSetInternal(Node doc) throws CanonicalizationException { @@ -370,6 +358,12 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { ((ByteArrayOutputStream)this._writer).reset(); } return sol; + } else if (this._writer instanceof UnsyncByteArrayOutputStream) { + byte []result=((UnsyncByteArrayOutputStream)this._writer).toByteArray(); + if (reset) { + ((UnsyncByteArrayOutputStream)this._writer).reset(); + } + return result; } return null; } catch (UnsupportedEncodingException ex) { @@ -390,11 +384,17 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { */ final void canonicalizeXPathNodeSet(Node currentNode,Node endnode ) throws CanonicalizationException, IOException { - boolean currentNodeIsVisible = false; - NameSpaceSymbTable ns=new NameSpaceSymbTable(); + if (isVisibleInt(currentNode)==-1) + return; + boolean currentNodeIsVisible = false; + NameSpaceSymbTable ns=new NameSpaceSymbTable(); + if (currentNode instanceof Element) + getParentNameSpaces((Element)currentNode,ns); Node sibling=null; Node parentNode=null; OutputStream writer=this._writer; + int documentLevel=NODE_BEFORE_DOCUMENT_ELEMENT; + Map cache=new HashMap(); do { switch (currentNode.getNodeType()) { @@ -416,14 +416,14 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { break; case Node.COMMENT_NODE : - if (this._includeComments && isVisible(currentNode)) { - outputCommentToWriter((Comment) currentNode, writer); + if (this._includeComments && (isVisibleDO(currentNode,ns.getLevel())==1)) { + outputCommentToWriter((Comment) currentNode, writer, documentLevel); } break; case Node.PROCESSING_INSTRUCTION_NODE : if (isVisible(currentNode)) - outputPItoWriter((ProcessingInstruction) currentNode, writer); + outputPItoWriter((ProcessingInstruction) currentNode, writer, documentLevel); break; case Node.TEXT_NODE : @@ -436,12 +436,6 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { || (nextSibling.getNodeType() == Node.CDATA_SECTION_NODE)); nextSibling = nextSibling.getNextSibling()) { - /* The XPath data model allows to select only the first of a - * sequence of mixed text and CDATA nodes. But we must output - * them all, so we must search: - * - * @see http://nagoya.apache.org/bugzilla/show_bug.cgi?id=6329 - */ outputTextToWriter(nextSibling.getNodeValue(), writer); currentNode=nextSibling; sibling=currentNode.getNextSibling(); @@ -451,15 +445,21 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { break; case Node.ELEMENT_NODE : + documentLevel=NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT; Element currentElement = (Element) currentNode; //Add a level to the nssymbtable. So latter can be pop-back. String name=null; - currentNodeIsVisible=isVisible(currentNode); + int i=isVisibleDO(currentNode,ns.getLevel()); + if (i==-1) { + sibling= currentNode.getNextSibling(); + break; + } + currentNodeIsVisible=(i==1); if (currentNodeIsVisible) { ns.outputNodePush(); writer.write('<'); name=currentElement.getTagName(); - writeStringToUtf8(name,writer); + UtfHelpper.writeByte(name,writer,cache); } else { ns.push(); } @@ -469,7 +469,7 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { //we output all Attrs which are available while (attrs.hasNext()) { Attr attr = (Attr) attrs.next(); - outputAttrToWriter(attr.getNodeName(),attr.getNodeValue(), writer); + outputAttrToWriter(attr.getNodeName(),attr.getNodeValue(), writer,cache); } } if (currentNodeIsVisible) { @@ -480,7 +480,7 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { if (sibling==null) { if (currentNodeIsVisible) { writer.write(_END_TAG); - writeStringToUtf8(name,writer); + UtfHelpper.writeByte(name,writer,cache); writer.write('>'); //We fineshed with this level, pop to the previous definitions. ns.outputNodePop(); @@ -498,7 +498,7 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { while (sibling==null && parentNode!=null) { if (isVisible(parentNode)) { writer.write(_END_TAG); - writeStringToUtf8(((Element)parentNode).getTagName(),writer); + UtfHelpper.writeByte(((Element)parentNode).getTagName(),writer,cache); writer.write('>'); //We fineshed with this level, pop to the previous definitions. ns.outputNodePop(); @@ -511,6 +511,7 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { parentNode=parentNode.getParentNode(); if (!(parentNode instanceof Element)) { parentNode=null; + documentLevel=NODE_AFTER_DOCUMENT_ELEMENT; } } if (sibling==null) @@ -519,12 +520,38 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { sibling=currentNode.getNextSibling(); } while(true); } + int isVisibleDO(Node currentNode,int level) { + if (nodeFilter!=null) { + Iterator it=nodeFilter.iterator(); + while (it.hasNext()) { + int i=((NodeFilter)it.next()).isNodeIncludeDO(currentNode,level); + if (i!=1) + return i; + } + } + if ((this._xpathNodeSet!=null) && !this._xpathNodeSet.contains(currentNode)) + return 0; + return 1; + } + int isVisibleInt(Node currentNode) { + if (nodeFilter!=null) { + Iterator it=nodeFilter.iterator(); + while (it.hasNext()) { + int i=((NodeFilter)it.next()).isNodeInclude(currentNode); + if (i!=1) + return i; + } + } + if ((this._xpathNodeSet!=null) && !this._xpathNodeSet.contains(currentNode)) + return 0; + return 1; + } boolean isVisible(Node currentNode) { if (nodeFilter!=null) { Iterator it=nodeFilter.iterator(); while (it.hasNext()) { - if (!((NodeFilter)it.next()).isNodeInclude(currentNode)) + if (((NodeFilter)it.next()).isNodeInclude(currentNode)!=1) return false; } } @@ -533,19 +560,42 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { return true; } + void handleParent(Element e,NameSpaceSymbTable ns) { + if (!e.hasAttributes()) { + return; + } + NamedNodeMap attrs = e.getAttributes(); + int attrsLength = attrs.getLength(); + for (int i = 0; i < attrsLength; i++) { + Attr N = (Attr) attrs.item(i); + if (Constants.NamespaceSpecNS!=N.getNamespaceURI()) { + //Not a namespace definition, ignore. + continue; + } + + String NName=N.getLocalName(); + String NValue=N.getNodeValue(); + if (XML.equals(NName) + && Constants.XML_LANG_SPACE_SpecNS.equals(NValue)) { + continue; + } + ns.addMapping(NName,NValue,N); + } + } + /** * Adds to ns the definitons from the parent elements of el * @param el * @param ns */ - final static void getParentNameSpaces(Element el,NameSpaceSymbTable ns) { - List parents=new ArrayList(); + final void getParentNameSpaces(Element el,NameSpaceSymbTable ns) { + List parents=new ArrayList(10); Node n1=el.getParentNode(); if (!(n1 instanceof Element)) { return; } //Obtain all the parents of the elemnt - Element parent=(Element) el.getParentNode(); + Element parent=(Element) n1; while (parent!=null) { parents.add(parent); Node n=parent.getParentNode(); @@ -557,297 +607,15 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { //Visit them in reverse order. ListIterator it=parents.listIterator(parents.size()); while (it.hasPrevious()) { - Element ele=(Element)it.previous(); - if (!ele.hasAttributes()) { - continue; + Element ele=(Element)it.previous(); + handleParent(ele, ns); } - NamedNodeMap attrs = ele.getAttributes(); - int attrsLength = attrs.getLength(); - for (int i = 0; i < attrsLength; i++) { - Attr N = (Attr) attrs.item(i); - if (!Constants.NamespaceSpecNS.equals(N.getNamespaceURI())) { - //Not a namespace definition, ignore. - continue; - } - - String NName=N.getLocalName(); - String NValue=N.getNodeValue(); - if (XML.equals(NName) - && Constants.XML_LANG_SPACE_SpecNS.equals(NValue)) { - continue; - } - ns.addMapping(NName,NValue,N); - } - } Attr nsprefix; if (((nsprefix=ns.getMappingWithoutRendered("xmlns"))!=null) && "".equals(nsprefix.getValue())) { ns.addMappingAndRender("xmlns","",nullNode); } } - /** - * Outputs an Attribute to the internal Writer. - * - * The string value of the node is modified by replacing - *
    - *
  • all ampersands (&) with &amp;
  • - *
  • all open angle brackets (<) with &lt;
  • - *
  • all quotation mark characters with &quot;
  • - *
  • and the whitespace characters #x9, #xA, and #xD, with character - * references. The character references are written in uppercase - * hexadecimal with no leading zeroes (for example, #xD is represented - * by the character reference &#xD;)
  • - *
- * - * @param name - * @param value - * @param writer - * @throws IOException - */ - static final void outputAttrToWriter(final String name, final String value, final OutputStream writer) throws IOException { - writer.write(' '); - writeStringToUtf8(name,writer); - writer.write(equalsStr); - byte []toWrite; - final int length = value.length(); - for (int i=0;i < length; i++) { - char c = value.charAt(i); - - switch (c) { - - case '&' : - toWrite=_AMP_; - //writer.write(_AMP_); - break; - - case '<' : - toWrite=_LT_; - //writer.write(_LT_); - break; - - case '"' : - toWrite=_QUOT_; - //writer.write(_QUOT_); - break; - - case 0x09 : // '\t' - toWrite=__X9_; - //writer.write(__X9_); - break; - - case 0x0A : // '\n' - toWrite=__XA_; - //writer.write(__XA_); - break; - - case 0x0D : // '\r' - toWrite=__XD_; - //writer.write(__XD_); - break; - - default : - writeCharToUtf8(c,writer); - //this._writer.write(c); - continue; - } - writer.write(toWrite); - } - - writer.write('\"'); - } - - final static void writeCharToUtf8(final char c,final OutputStream out) throws IOException{ - char ch; - if (/*(c >= 0x0001) &&*/ (c <= 0x007F)) { - out.write(c); - return; - } - int bias; - int write; - if (c > 0x07FF) { - ch=(char)(c>>>12); - write=0xE0; - if (ch>0) { - write |= ( ch & 0x0F); - } - out.write(write); - write=0x80; - bias=0x3F; - } else { - write=0xC0; - bias=0x1F; - } - ch=(char)(c>>>6); - if (ch>0) { - write|= (ch & bias); - } - out.write(write); - out.write(0x80 | ((c) & 0x3F)); - - } - - final static void writeStringToUtf8(final String str,final OutputStream out) throws IOException{ - final int length=str.length(); - int i=0; - char c; - while (i= 0x0001) &&*/ (c <= 0x007F)) { - out.write(c); - continue; - } - char ch; - int bias; - int write; - if (c > 0x07FF) { - ch=(char)(c>>>12); - write=0xE0; - if (ch>0) { - write |= ( ch & 0x0F); - } - out.write(write); - write=0x80; - bias=0x3F; - } else { - write=0xC0; - bias=0x1F; - } - ch=(char)(c>>>6); - if (ch>0) { - write|= (ch & bias); - } - out.write(write); - out.write(0x80 | ((c) & 0x3F)); - continue; - - } - - } - /** - * Outputs a PI to the internal Writer. - * - * @param currentPI - * @param writer where to write the things - * @throws IOException - */ - static final void outputPItoWriter(ProcessingInstruction currentPI, OutputStream writer) throws IOException { - final int position = getPositionRelativeToDocumentElement(currentPI); - - if (position == NODE_AFTER_DOCUMENT_ELEMENT) { - writer.write('\n'); - } - writer.write(_BEGIN_PI); - - final String target = currentPI.getTarget(); - int length = target.length(); - - for (int i = 0; i < length; i++) { - char c=target.charAt(i); - if (c==0x0D) { - writer.write(__XD_); - } else { - writeCharToUtf8(c,writer); - } - } - - final String data = currentPI.getData(); - - length = data.length(); - - if (length > 0) { - writer.write(' '); - - for (int i = 0; i < length; i++) { - char c=data.charAt(i); - if (c==0x0D) { - writer.write(__XD_); - } else { - writeCharToUtf8(c,writer); - } - } - } - - writer.write(_END_PI); - if (position == NODE_BEFORE_DOCUMENT_ELEMENT) { - writer.write('\n'); - } - } - - /** - * Method outputCommentToWriter - * - * @param currentComment - * @param writer writer where to write the things - * @throws IOException - */ - static final void outputCommentToWriter(Comment currentComment, OutputStream writer) throws IOException { - final int position = getPositionRelativeToDocumentElement(currentComment); - if (position == NODE_AFTER_DOCUMENT_ELEMENT) { - writer.write('\n'); - } - writer.write(_BEGIN_COMM); - - final String data = currentComment.getData(); - final int length = data.length(); - - for (int i = 0; i < length; i++) { - char c=data.charAt(i); - if (c==0x0D) { - writer.write(__XD_); - } else { - writeCharToUtf8(c,writer); - } - } - - writer.write(_END_COMM); - if (position == NODE_BEFORE_DOCUMENT_ELEMENT) { - writer.write('\n'); - } - } - - /** - * Outputs a Text of CDATA section to the internal Writer. - * - * @param text - * @param writer writer where to write the things - * @throws IOException - */ - static final void outputTextToWriter(final String text, final OutputStream writer) throws IOException { - final int length = text.length(); - byte []toWrite; - for (int i = 0; i < length; i++) { - char c = text.charAt(i); - - switch (c) { - - case '&' : - toWrite=_AMP_; - //writer.write(_AMP_); - break; - - case '<' : - toWrite=_LT_; - //writer.write(_LT_); - break; - - case '>' : - toWrite=_GT_; - //writer.write(_GT_); - break; - - case 0xD : - toWrite=__XD_; - //writer.write(__XD_); - break; - - default : - writeCharToUtf8(c,writer); - continue; - } - writer.write(toWrite); - } - } - /** * Obtain the attributes to output for this node in XPathNodeSet c14n. * @@ -870,13 +638,207 @@ public abstract class CanonicalizerBase extends CanonicalizerSpi { abstract Iterator handleAttributesSubtree(Element E, NameSpaceSymbTable ns) throws CanonicalizationException; + abstract void circumventBugIfNeeded(XMLSignatureInput input) throws CanonicalizationException, ParserConfigurationException, IOException, SAXException; + /** + * Outputs an Attribute to the internal Writer. + * + * The string value of the node is modified by replacing + *
    + *
  • all ampersands (&) with &amp;
  • + *
  • all open angle brackets (<) with &lt;
  • + *
  • all quotation mark characters with &quot;
  • + *
  • and the whitespace characters #x9, #xA, and #xD, with character + * references. The character references are written in uppercase + * hexadecimal with no leading zeroes (for example, #xD is represented + * by the character reference &#xD;)
  • + *
+ * + * @param name + * @param value + * @param writer + * @throws IOException + */ + static final void outputAttrToWriter(final String name, final String value, final OutputStream writer, + final Map cache) throws IOException { + writer.write(' '); + UtfHelpper.writeByte(name,writer,cache); + writer.write(equalsStr); + byte []toWrite; + final int length = value.length(); + int i=0; + while (i < length) { + char c = value.charAt(i++); + + switch (c) { + + case '&' : + toWrite=_AMP_; + break; + + case '<' : + toWrite=_LT_; + break; + + case '"' : + toWrite=_QUOT_; + break; + + case 0x09 : // '\t' + toWrite=__X9_; + break; + + case 0x0A : // '\n' + toWrite=__XA_; + break; + + case 0x0D : // '\r' + toWrite=__XD_; + break; + + default : + if (c < 0x80 ) { + writer.write(c); + } else { + UtfHelpper.writeCharToUtf8(c,writer); + }; + continue; + } + writer.write(toWrite); + } - /** - * @param _writer The _writer to set. - */ - public void setWriter(OutputStream _writer) { - this._writer = _writer; - } + writer.write('\"'); + } + + /** + * Outputs a PI to the internal Writer. + * + * @param currentPI + * @param writer where to write the things + * @throws IOException + */ + static final void outputPItoWriter(ProcessingInstruction currentPI, OutputStream writer,int position) throws IOException { + + if (position == NODE_AFTER_DOCUMENT_ELEMENT) { + writer.write('\n'); + } + writer.write(_BEGIN_PI); + + final String target = currentPI.getTarget(); + int length = target.length(); + + for (int i = 0; i < length; i++) { + char c=target.charAt(i); + if (c==0x0D) { + writer.write(__XD_); + } else { + if (c < 0x80) { + writer.write(c); + } else { + UtfHelpper.writeCharToUtf8(c,writer); + }; + } + } + + final String data = currentPI.getData(); + + length = data.length(); + + if (length > 0) { + writer.write(' '); + + for (int i = 0; i < length; i++) { + char c=data.charAt(i); + if (c==0x0D) { + writer.write(__XD_); + } else { + UtfHelpper.writeCharToUtf8(c,writer); + } + } + } + + writer.write(_END_PI); + if (position == NODE_BEFORE_DOCUMENT_ELEMENT) { + writer.write('\n'); + } + } + + /** + * Method outputCommentToWriter + * + * @param currentComment + * @param writer writer where to write the things + * @throws IOException + */ + static final void outputCommentToWriter(Comment currentComment, OutputStream writer,int position) throws IOException { + if (position == NODE_AFTER_DOCUMENT_ELEMENT) { + writer.write('\n'); + } + writer.write(_BEGIN_COMM); + + final String data = currentComment.getData(); + final int length = data.length(); + + for (int i = 0; i < length; i++) { + char c=data.charAt(i); + if (c==0x0D) { + writer.write(__XD_); + } else { + if (c < 0x80) { + writer.write(c); + } else { + UtfHelpper.writeCharToUtf8(c,writer); + }; + } + } + + writer.write(_END_COMM); + if (position == NODE_BEFORE_DOCUMENT_ELEMENT) { + writer.write('\n'); + } + } + + /** + * Outputs a Text of CDATA section to the internal Writer. + * + * @param text + * @param writer writer where to write the things + * @throws IOException + */ + static final void outputTextToWriter(final String text, final OutputStream writer) throws IOException { + final int length = text.length(); + byte []toWrite; + for (int i = 0; i < length; i++) { + char c = text.charAt(i); + + switch (c) { + + case '&' : + toWrite=_AMP_; + break; + + case '<' : + toWrite=_LT_; + break; + + case '>' : + toWrite=_GT_; + break; + + case 0xD : + toWrite=__XD_; + break; + + default : + if (c < 0x80) { + writer.write(c); + } else { + UtfHelpper.writeCharToUtf8(c,writer); + }; + continue; + } + writer.write(toWrite); + } + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/NameSpaceSymbTable.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/NameSpaceSymbTable.java index bad23010f11c02eeacc16bc6abe61f0d631c4049..538d369748c0da7e07d1d7d8bc97ec2b17d177b6 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/NameSpaceSymbTable.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/NameSpaceSymbTable.java @@ -20,16 +20,10 @@ */ package com.sun.org.apache.xml.internal.security.c14n.implementations; -import java.lang.reflect.Array; -import java.util.AbstractList; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; - import org.w3c.dom.Attr; @@ -46,21 +40,26 @@ import org.w3c.dom.Node; public class NameSpaceSymbTable { /**The map betwen prefix-> entry table. */ - SymbMap symb = new SymbMap(); + SymbMap symb; /**The level of nameSpaces (for Inclusive visibility).*/ int nameSpaces=0; /**The stacks for removing the definitions when doing pop.*/ - List level = new ArrayList(); + List level; boolean cloned=true; static final String XMLNS="xmlns"; + final static SymbMap initialMap=new SymbMap(); + static { + NameSpaceSymbEntry ne=new NameSpaceSymbEntry("",null,true,XMLNS); + ne.lastrendered=""; + initialMap.put(XMLNS,ne); + } /** * Default constractor **/ public NameSpaceSymbTable() { + level = new ArrayList(10); //Insert the default binding for xmlns. - NameSpaceSymbEntry ne=new NameSpaceSymbEntry("",null,true); - ne.lastrendered=""; - symb.put(XMLNS,ne); + symb=(SymbMap) initialMap.clone(); } /** @@ -75,8 +74,14 @@ public class NameSpaceSymbTable { NameSpaceSymbEntry n=(NameSpaceSymbEntry)(it.next()); //put them rendered? if ((!n.rendered) && (n.n!=null)) { + n=(NameSpaceSymbEntry) n.clone(); + needsClone(); + symb.put(n.prefix,n); + n.lastrendered=n.uri; + n.rendered=true; + result.add(n.n); - n.rendered=true; + } } } @@ -104,10 +109,6 @@ public class NameSpaceSymbTable { **/ public void push() { //Put the number of namespace definitions in the stack. - /**if (cloned) { - Object ob[]= {symb,cloned ? symb : null}; - level.add(ob); - } **/ level.add(null); cloned=false; } @@ -124,7 +125,7 @@ public class NameSpaceSymbTable { if (size==0) { cloned=false; } else - cloned=(level.get(size-1)!=symb); + cloned=(level.get(size-1)!=symb); } else { cloned=false; } @@ -134,8 +135,7 @@ public class NameSpaceSymbTable { final void needsClone() { if (!cloned) { - level.remove(level.size()-1); - level.add(symb); + level.set(level.size()-1,symb); symb=(SymbMap) symb.clone(); cloned=true; } @@ -200,7 +200,7 @@ public class NameSpaceSymbTable { return false; } //Creates and entry in the table for this new definition. - NameSpaceSymbEntry ne=new NameSpaceSymbEntry(uri,n,false); + NameSpaceSymbEntry ne=new NameSpaceSymbEntry(uri,n,false,prefix); needsClone(); symb.put(prefix, ne); if (ob != null) { @@ -238,7 +238,7 @@ public class NameSpaceSymbTable { return null; } - NameSpaceSymbEntry ne=new NameSpaceSymbEntry(uri,n,true); + NameSpaceSymbEntry ne=new NameSpaceSymbEntry(uri,n,true,prefix); ne.lastrendered=uri; needsClone(); symb.put(prefix, ne); @@ -251,53 +251,38 @@ public class NameSpaceSymbTable { } return ne.n; } - /** - * Adds & gets(if needed) the attribute node that defines the binding for the prefix. - * Take on account if the rules of rendering in the inclusive c14n. - * For inclusive c14n. - * @param prefix the prefix to obtain the attribute. - * @param outputNode the container element is an output element. - * @param uri the Uri of the definition - * @param n the attribute that have the definition - * @return null if there is no need to render the prefix. Otherwise the node of - * definition. - **/ - public Node addMappingAndRenderXNodeSet(String prefix, String uri,Attr n,boolean outputNode) { + + public int getLevel() { + // TODO Auto-generated method stub + return level.size(); + } + + public void removeMapping(String prefix) { NameSpaceSymbEntry ob = symb.get(prefix); - int visibleNameSpaces=nameSpaces; - if ((ob!=null) && uri.equals(ob.uri)) { - if (!ob.rendered) { - ob=(NameSpaceSymbEntry)ob.clone(); - needsClone(); - symb.put(prefix,ob); - ob.rendered=true; - ob.level=visibleNameSpaces; - return ob.n; - } - ob=(NameSpaceSymbEntry)ob.clone(); + + if (ob!=null) { needsClone(); - symb.put(prefix,ob); - if (outputNode && (((visibleNameSpaces-ob.level)<2) || XMLNS.equals(prefix)) ) { - ob.level=visibleNameSpaces; - return null; //Already rendered, just return nulll - } - ob.level=visibleNameSpaces; - return ob.n; - } + symb.put(prefix,null); + } + } - NameSpaceSymbEntry ne=new NameSpaceSymbEntry(uri,n,true); - ne.level=nameSpaces; - ne.rendered=true; - needsClone(); - symb.put(prefix, ne); - if (ob != null) { - ne.lastrendered=ob.lastrendered; + public void removeMappingIfNotRender(String prefix) { + NameSpaceSymbEntry ob = symb.get(prefix); - if ((ob.lastrendered!=null)&& (ob.lastrendered.equals(uri))) { - ne.rendered=true; - } - } - return ne.n; + if (ob!=null && !ob.rendered) { + needsClone(); + symb.put(prefix,null); + } + } + + public boolean removeMappingIfRender(String prefix) { + NameSpaceSymbEntry ob = symb.get(prefix); + + if (ob!=null && ob.rendered) { + needsClone(); + symb.put(prefix,null); + } + return false; } } @@ -305,10 +290,11 @@ public class NameSpaceSymbTable { * The internal structure of NameSpaceSymbTable. **/ class NameSpaceSymbEntry implements Cloneable { - NameSpaceSymbEntry(String name,Attr n,boolean rendered) { + NameSpaceSymbEntry(String name,Attr n,boolean rendered,String prefix) { this.uri=name; this.rendered=rendered; this.n=n; + this.prefix=prefix; } /** @inheritDoc */ public Object clone() { @@ -320,6 +306,7 @@ class NameSpaceSymbEntry implements Cloneable { } /** The level where the definition was rendered(Only for inclusive) */ int level=0; + String prefix; /**The URI that the prefix defines */ String uri; /**The last output in the URI for this prefix (This for speed reason).*/ @@ -330,53 +317,57 @@ class NameSpaceSymbEntry implements Cloneable { Attr n; }; -class SymbMap implements Cloneable{ - int free=23; - NameSpaceSymbEntry[] entries=new NameSpaceSymbEntry[free]; - String[] keys=new String[free]; - - void put(String key, NameSpaceSymbEntry value) { +class SymbMap implements Cloneable { + int free=23; + NameSpaceSymbEntry[] entries; + String[] keys; + SymbMap() { + entries=new NameSpaceSymbEntry[free]; + keys=new String[free]; + } + void put(String key, NameSpaceSymbEntry value) { int index = index(key); - Object oldKey = keys[index]; - keys[index] = key; - entries[index] = value; + Object oldKey = keys[index]; + keys[index] = key; + entries[index] = value; if (oldKey==null || !oldKey.equals(key)) { - if (--free == 0) { - free=entries.length; - int newCapacity = free<<2; - rehash(newCapacity); - } + if (--free == 0) { + free=entries.length; + int newCapacity = free<<2; + rehash(newCapacity); + } } } List entrySet() { - List a=new ArrayList(); - for (int i=0;iint value @@ -384,37 +375,38 @@ class SymbMap implements Cloneable{ protected void rehash(int newCapacity) { int oldCapacity = keys.length; String oldKeys[] = keys; - NameSpaceSymbEntry oldVals[] = entries; + NameSpaceSymbEntry oldVals[] = entries; - keys = new String[newCapacity]; - entries = new NameSpaceSymbEntry[newCapacity]; + keys = new String[newCapacity]; + entries = new NameSpaceSymbEntry[newCapacity]; for (int i = oldCapacity; i-- > 0;) { if(oldKeys[i] != null) { String o = oldKeys[i]; int index = index(o); - keys[index] = o; - entries[index] = oldVals[i]; + keys[index] = o; + entries[index] = oldVals[i]; } } } - NameSpaceSymbEntry get(String key) { - return entries[index(key)]; - } - protected Object clone() { - // TODO Auto-generated method stub - try { - SymbMap copy=(SymbMap) super.clone(); - copy.entries=new NameSpaceSymbEntry[entries.length]; - System.arraycopy(entries,0,copy.entries,0,entries.length); - copy.keys=new String[keys.length]; - System.arraycopy(keys,0,copy.keys,0,keys.length); - - return copy; - } catch (CloneNotSupportedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return null; + + NameSpaceSymbEntry get(String key) { + return entries[index(key)]; + } + + protected Object clone() { + try { + SymbMap copy=(SymbMap) super.clone(); + copy.entries=new NameSpaceSymbEntry[entries.length]; + System.arraycopy(entries,0,copy.entries,0,entries.length); + copy.keys=new String[keys.length]; + System.arraycopy(keys,0,copy.keys,0,keys.length); + + return copy; + } catch (CloneNotSupportedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } + return null; + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/UtfHelpper.java b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/UtfHelpper.java new file mode 100644 index 0000000000000000000000000000000000000000..cfcc06dd2c41c640c57398c16a256fd151c4b187 --- /dev/null +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/UtfHelpper.java @@ -0,0 +1,155 @@ +package com.sun.org.apache.xml.internal.security.c14n.implementations; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Map; + +public class UtfHelpper { + + final static void writeByte(final String str,final OutputStream out,Map cache) throws IOException { + byte []result=(byte[]) cache.get(str); + if (result==null) { + result=getStringInUtf8(str); + cache.put(str,result); + } + + out.write(result); + + } + + final static void writeCharToUtf8(final char c,final OutputStream out) throws IOException{ + if (c < 0x80) { + out.write(c); + return; + } + if ((c >= 0xD800 && c <= 0xDBFF) || (c >= 0xDC00 && c <= 0xDFFF) ){ + //No Surrogates in sun java + out.write(0x3f); + return; + } + int bias; + int write; + char ch; + if (c > 0x07FF) { + ch=(char)(c>>>12); + write=0xE0; + if (ch>0) { + write |= ( ch & 0x0F); + } + out.write(write); + write=0x80; + bias=0x3F; + } else { + write=0xC0; + bias=0x1F; + } + ch=(char)(c>>>6); + if (ch>0) { + write|= (ch & bias); + } + out.write(write); + out.write(0x80 | ((c) & 0x3F)); + + } + + final static void writeStringToUtf8(final String str,final OutputStream out) throws IOException{ + final int length=str.length(); + int i=0; + char c; + while (i= 0xD800 && c <= 0xDBFF) || (c >= 0xDC00 && c <= 0xDFFF) ){ + //No Surrogates in sun java + out.write(0x3f); + continue; + } + char ch; + int bias; + int write; + if (c > 0x07FF) { + ch=(char)(c>>>12); + write=0xE0; + if (ch>0) { + write |= ( ch & 0x0F); + } + out.write(write); + write=0x80; + bias=0x3F; + } else { + write=0xC0; + bias=0x1F; + } + ch=(char)(c>>>6); + if (ch>0) { + write|= (ch & bias); + } + out.write(write); + out.write(0x80 | ((c) & 0x3F)); + + } + + } + public final static byte[] getStringInUtf8(final String str) { + final int length=str.length(); + boolean expanded=false; + byte []result=new byte[length]; + int i=0; + int out=0; + char c; + while (i= 0xD800 && c <= 0xDBFF) || (c >= 0xDC00 && c <= 0xDFFF) ){ + //No Surrogates in sun java + result[out++]=0x3f; + + continue; + } + if (!expanded) { + byte newResult[]=new byte[3*length]; + System.arraycopy(result, 0, newResult, 0, out); + result=newResult; + expanded=true; + } + char ch; + int bias; + byte write; + if (c > 0x07FF) { + ch=(char)(c>>>12); + write=(byte)0xE0; + if (ch>0) { + write |= ( ch & 0x0F); + } + result[out++]=write; + write=(byte)0x80; + bias=0x3F; + } else { + write=(byte)0xC0; + bias=0x1F; + } + ch=(char)(c>>>6); + if (ch>0) { + write|= (ch & bias); + } + result[out++]=write; + result[out++]=(byte)(0x80 | ((c) & 0x3F));/**/ + + } + if (expanded) { + byte newResult[]=new byte[out]; + System.arraycopy(result, 0, newResult, 0, out); + result=newResult; + } + return result; + } + + + +} diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipher.java b/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipher.java index 7814216496dfa7dd9bd35ce8787e039efdca3d71..683acdbf003dc9a85579b3ff4a4576c37efec9f9 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipher.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipher.java @@ -22,6 +22,7 @@ package com.sun.org.apache.xml.internal.security.encryption; import java.io.ByteArrayOutputStream; +import java.io.InputStream; import java.io.IOException; import java.io.StringReader; import java.io.UnsupportedEncodingException; @@ -30,6 +31,7 @@ import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -204,7 +206,7 @@ public class XMLCipher { * @since 1.0. */ private XMLCipher() { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Constructing XMLCipher..."); + logger.log(java.util.logging.Level.FINE, "Constructing XMLCipher..."); _factory = new Factory(); _serializer = new Serializer(); @@ -266,7 +268,7 @@ public class XMLCipher { public static XMLCipher getInstance(String transformation) throws XMLEncryptionException { // sanity checks - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher..."); + logger.log(java.util.logging.Level.FINE, "Getting XMLCipher..."); if (null == transformation) logger.log(java.util.logging.Level.SEVERE, "Transformation unexpectedly null..."); if(!isValidEncryptionAlgorithm(transformation)) @@ -294,7 +296,7 @@ public class XMLCipher { try { instance._contextCipher = Cipher.getInstance(jceAlgorithm); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "cihper.algoritm = " + + logger.log(java.util.logging.Level.FINE, "cihper.algoritm = " + instance._contextCipher.getAlgorithm()); } catch (NoSuchAlgorithmException nsae) { throw new XMLEncryptionException("empty", nsae); @@ -305,8 +307,39 @@ public class XMLCipher { return (instance); } - public static XMLCipher getInstance(String transformation,Cipher cipher) throws - XMLEncryptionException { + /** + * Returns an XMLCipher that implements the specified + * transformation, operates on the specified context document and serializes + * the document with the specified canonicalization algorithm before it + * encrypts the document. + *

+ * + * @param transformation the name of the transformation, e.g., + * XMLCipher.TRIPLEDES which is + * shorthand for + * "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" + * @param canon the name of the c14n algorithm, if + * null use standard serializer + * @return + * @throws XMLEncryptionException + */ + + public static XMLCipher getInstance(String transformation, String canon) + throws XMLEncryptionException { + XMLCipher instance = XMLCipher.getInstance(transformation); + + if (canon != null) { + try { + instance._canon = Canonicalizer.getInstance(canon); + } catch (InvalidCanonicalizerException ice) { + throw new XMLEncryptionException("empty", ice); + } + } + + return instance; + } + + public static XMLCipher getInstance(String transformation,Cipher cipher) throws XMLEncryptionException { // sanity checks logger.log(java.util.logging.Level.FINE, "Getting XMLCipher..."); if (null == transformation) @@ -321,8 +354,8 @@ public class XMLCipher { instance._kek = null; - /* Create a canonicaliser - used when serialising DOM to octets - * prior to encryption (and for the reverse) */ + /* Create a canonicaliser - used when serialising DOM to octets + * prior to encryption (and for the reverse) */ try { instance._canon = Canonicalizer.getInstance @@ -346,41 +379,6 @@ public class XMLCipher { return (instance); } - - - /** - * Returns an XMLCipher that implements the specified - * transformation, operates on the specified context document and serializes - * the document with the specified canonicalization algorithm before it - * encrypts the document. - *

- * - * @param transformation the name of the transformation, e.g., - * XMLCipher.TRIPLEDES which is - * shorthand for - * "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" - * @param canon the name of the c14n algorithm, if - * null use standard serializer - * @return - * @throws XMLEncryptionException - */ - - public static XMLCipher getInstance(String transformation, String canon) - throws XMLEncryptionException { - XMLCipher instance = XMLCipher.getInstance(transformation); - - if (canon != null) { - try { - instance._canon = Canonicalizer.getInstance(canon); - } catch (InvalidCanonicalizerException ice) { - throw new XMLEncryptionException("empty", ice); - } - } - - return instance; - } - - /** * Returns an XMLCipher that implements the specified * transformation and operates on the specified context document. @@ -396,7 +394,7 @@ public class XMLCipher { public static XMLCipher getProviderInstance(String transformation, String provider) throws XMLEncryptionException { // sanity checks - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher..."); + logger.log(java.util.logging.Level.FINE, "Getting XMLCipher..."); if (null == transformation) logger.log(java.util.logging.Level.SEVERE, "Transformation unexpectedly null..."); if(null == provider) @@ -429,9 +427,9 @@ public class XMLCipher { instance._contextCipher = Cipher.getInstance(jceAlgorithm, provider); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "cipher._algorithm = " + + logger.log(java.util.logging.Level.FINE, "cipher._algorithm = " + instance._contextCipher.getAlgorithm()); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "provider.name = " + provider); + logger.log(java.util.logging.Level.FINE, "provider.name = " + provider); } catch (NoSuchAlgorithmException nsae) { throw new XMLEncryptionException("empty", nsae); } catch (NoSuchProviderException nspre) { @@ -490,7 +488,7 @@ public class XMLCipher { public static XMLCipher getInstance() throws XMLEncryptionException { // sanity checks - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher for no transformation..."); + logger.log(java.util.logging.Level.FINE, "Getting XMLCipher for no transformation..."); XMLCipher instance = new XMLCipher(); @@ -532,7 +530,7 @@ public class XMLCipher { throws XMLEncryptionException { // sanity checks - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Getting XMLCipher, provider but no transformation"); + logger.log(java.util.logging.Level.FINE, "Getting XMLCipher, provider but no transformation"); if(null == provider) logger.log(java.util.logging.Level.SEVERE, "Provider unexpectedly null.."); if("" == provider) @@ -578,7 +576,7 @@ public class XMLCipher { */ public void init(int opmode, Key key) throws XMLEncryptionException { // sanity checks - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Initializing XMLCipher..."); + logger.log(java.util.logging.Level.FINE, "Initializing XMLCipher..."); _ek = null; _ed = null; @@ -586,18 +584,18 @@ public class XMLCipher { switch (opmode) { case ENCRYPT_MODE : - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = ENCRYPT_MODE"); + logger.log(java.util.logging.Level.FINE, "opmode = ENCRYPT_MODE"); _ed = createEncryptedData(CipherData.VALUE_TYPE, "NO VALUE YET"); break; case DECRYPT_MODE : - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = DECRYPT_MODE"); + logger.log(java.util.logging.Level.FINE, "opmode = DECRYPT_MODE"); break; case WRAP_MODE : - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = WRAP_MODE"); + logger.log(java.util.logging.Level.FINE, "opmode = WRAP_MODE"); _ek = createEncryptedKey(CipherData.VALUE_TYPE, "NO VALUE YET"); break; case UNWRAP_MODE : - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "opmode = UNWRAP_MODE"); + logger.log(java.util.logging.Level.FINE, "opmode = UNWRAP_MODE"); break; default : logger.log(java.util.logging.Level.SEVERE, "Mode unexpectedly invalid"); @@ -622,7 +620,7 @@ public class XMLCipher { public EncryptedData getEncryptedData() { // Sanity checks - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Returning EncryptedData"); + logger.log(java.util.logging.Level.FINE, "Returning EncryptedData"); return _ed; } @@ -640,7 +638,7 @@ public class XMLCipher { public EncryptedKey getEncryptedKey() { // Sanity checks - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Returning EncryptedKey"); + logger.log(java.util.logging.Level.FINE, "Returning EncryptedKey"); return _ek; } @@ -750,11 +748,11 @@ public class XMLCipher { */ private Document encryptElement(Element element) throws Exception{ - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypting element..."); + logger.log(java.util.logging.Level.FINE, "Encrypting element..."); if(null == element) logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null..."); if(_cipherMode != ENCRYPT_MODE) - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); + logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); if (_algorithm == null) { throw new XMLEncryptionException("XMLCipher instance without transformation specified"); @@ -785,11 +783,11 @@ public class XMLCipher { */ private Document encryptElementContent(Element element) throws /* XMLEncryption */Exception { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypting element content..."); + logger.log(java.util.logging.Level.FINE, "Encrypting element content..."); if(null == element) logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null..."); if(_cipherMode != ENCRYPT_MODE) - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); + logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); if (_algorithm == null) { throw new XMLEncryptionException("XMLCipher instance without transformation specified"); @@ -815,7 +813,7 @@ public class XMLCipher { */ public Document doFinal(Document context, Document source) throws /* XMLEncryption */Exception { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Processing source document..."); + logger.log(java.util.logging.Level.FINE, "Processing source document..."); if(null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if(null == source) @@ -855,7 +853,7 @@ public class XMLCipher { */ public Document doFinal(Document context, Element element) throws /* XMLEncryption */Exception { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Processing source element..."); + logger.log(java.util.logging.Level.FINE, "Processing source element..."); if(null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if(null == element) @@ -898,7 +896,7 @@ public class XMLCipher { */ public Document doFinal(Document context, Element element, boolean content) throws /* XMLEncryption*/ Exception { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Processing source element..."); + logger.log(java.util.logging.Level.FINE, "Processing source element..."); if(null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if(null == element) @@ -952,6 +950,34 @@ public class XMLCipher { return encryptData(context, element, false); } + /** + * Returns an EncryptedData interface. Use this operation if + * you want to have full control over the serialization of the element + * or element content. + * + * This does not change the source document in any way. + * + * @param context the context Document. + * @param type a URI identifying type information about the plaintext form + * of the encrypted content (may be null) + * @param serializedData the serialized data + * @return the EncryptedData + * @throws Exception + */ + public EncryptedData encryptData(Document context, String type, + InputStream serializedData) throws Exception { + + logger.log(java.util.logging.Level.FINE, "Encrypting element..."); + if (null == context) + logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); + if (null == serializedData) + logger.log(java.util.logging.Level.SEVERE, "Serialized data unexpectedly null..."); + if (_cipherMode != ENCRYPT_MODE) + logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); + + return encryptData(context, null, type, serializedData); + } + /** * Returns an EncryptedData interface. Use this operation if * you want to have full control over the contents of the @@ -966,160 +992,60 @@ public class XMLCipher { * @return the EncryptedData * @throws Exception */ - public EncryptedData encryptData(Document context, Element element, boolean contentMode) throws - /* XMLEncryption */ Exception { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypting element..."); - if (null == context) - logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); - if (null == element) - logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null..."); - if (_cipherMode != ENCRYPT_MODE) - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); + public EncryptedData encryptData( + Document context, Element element, boolean contentMode) + throws /* XMLEncryption */ Exception { - _contextDocument = context; - - if (_algorithm == null) { - throw new XMLEncryptionException("XMLCipher instance without transformation specified"); - } - - String serializedOctets = null; - if (contentMode) { - NodeList children = element.getChildNodes(); - if ((null != children)) { - serializedOctets = _serializer.serialize(children); - } else { - Object exArgs[] = { "Element has no content." }; - throw new XMLEncryptionException("empty", exArgs); - } - } else { - serializedOctets = _serializer.serialize(element); - } - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Serialized octets:\n" + serializedOctets); - - byte[] encryptedBytes = null; - - // Now create the working cipher if none was created already - Cipher c; - if (_contextCipher == null) { - String jceAlgorithm = - JCEMapper.translateURItoJCEID(_algorithm); - - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "alg = " + jceAlgorithm); - - try { - if (_requestedJCEProvider == null) - c = Cipher.getInstance(jceAlgorithm); - else - c = Cipher.getInstance(jceAlgorithm, _requestedJCEProvider); - } catch (NoSuchAlgorithmException nsae) { - throw new XMLEncryptionException("empty", nsae); - } catch (NoSuchProviderException nspre) { - throw new XMLEncryptionException("empty", nspre); - } catch (NoSuchPaddingException nspae) { - throw new XMLEncryptionException("empty", nspae); - } - } - else { - c = _contextCipher; - } - // Now perform the encryption - - try { - // Should internally generate an IV - // todo - allow user to set an IV - c.init(_cipherMode, _key); - } catch (InvalidKeyException ike) { - throw new XMLEncryptionException("empty", ike); - } - - try { - encryptedBytes = - c.doFinal(serializedOctets.getBytes("UTF-8")); - - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Expected cipher.outputSize = " + - Integer.toString(c.getOutputSize( - serializedOctets.getBytes().length))); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Actual cipher.outputSize = " + - Integer.toString(encryptedBytes.length)); - } catch (IllegalStateException ise) { - throw new XMLEncryptionException("empty", ise); - } catch (IllegalBlockSizeException ibse) { - throw new XMLEncryptionException("empty", ibse); - } catch (BadPaddingException bpe) { - throw new XMLEncryptionException("empty", bpe); - } catch (UnsupportedEncodingException uee) { - throw new XMLEncryptionException("empty", uee); - } - - // Now build up to a properly XML Encryption encoded octet stream - // IvParameterSpec iv; - - byte[] iv = c.getIV(); - byte[] finalEncryptedBytes = - new byte[iv.length + encryptedBytes.length]; - System.arraycopy(iv, 0, finalEncryptedBytes, 0, - iv.length); - System.arraycopy(encryptedBytes, 0, finalEncryptedBytes, - iv.length, - encryptedBytes.length); - - String base64EncodedEncryptedOctets = Base64.encode(finalEncryptedBytes); - - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypted octets:\n" + base64EncodedEncryptedOctets); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypted octets length = " + - base64EncodedEncryptedOctets.length()); - - try { - CipherData cd = _ed.getCipherData(); - CipherValue cv = cd.getCipherValue(); - // cv.setValue(base64EncodedEncryptedOctets.getBytes()); - cv.setValue(base64EncodedEncryptedOctets); - - if (contentMode) { - _ed.setType( - new URI(EncryptionConstants.TYPE_CONTENT).toString()); - } else { - _ed.setType( - new URI(EncryptionConstants.TYPE_ELEMENT).toString()); - } - EncryptionMethod method = - _factory.newEncryptionMethod(new URI(_algorithm).toString()); - _ed.setEncryptionMethod(method); - } catch (URI.MalformedURIException mfue) { - throw new XMLEncryptionException("empty", mfue); - } - return (_ed); - } - - - - public EncryptedData encryptData(Document context, byte [] serializedOctets, boolean contentMode) throws - /* XMLEncryption */ Exception { logger.log(java.util.logging.Level.FINE, "Encrypting element..."); if (null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); - if (null == serializedOctets) - logger.log(java.util.logging.Level.SEVERE, "Canonicalized Data is unexpectedly null..."); + if (null == element) + logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null..."); if (_cipherMode != ENCRYPT_MODE) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in ENCRYPT_MODE..."); + if (contentMode) { + return encryptData + (context, element, EncryptionConstants.TYPE_CONTENT, null); + } else { + return encryptData + (context, element, EncryptionConstants.TYPE_ELEMENT, null); + } + } + + private EncryptedData encryptData( + Document context, Element element, String type, + InputStream serializedData) throws /* XMLEncryption */ Exception { + _contextDocument = context; if (_algorithm == null) { - throw new XMLEncryptionException("XMLCipher instance without transformation specified"); + throw new XMLEncryptionException + ("XMLCipher instance without transformation specified"); } - - logger.log(java.util.logging.Level.FINE, "Serialized octets:\n" + serializedOctets); + String serializedOctets = null; + if (serializedData == null) { + if (type == EncryptionConstants.TYPE_CONTENT) { + NodeList children = element.getChildNodes(); + if (null != children) { + serializedOctets = _serializer.serialize(children); + } else { + Object exArgs[] = { "Element has no content." }; + throw new XMLEncryptionException("empty", exArgs); + } + } else { + serializedOctets = _serializer.serialize(element); + } + logger.log(java.util.logging.Level.FINE, "Serialized octets:\n" + serializedOctets); + } byte[] encryptedBytes = null; // Now create the working cipher if none was created already Cipher c; if (_contextCipher == null) { - String jceAlgorithm = - JCEMapper.translateURItoJCEID(_algorithm); - + String jceAlgorithm = JCEMapper.translateURItoJCEID(_algorithm); logger.log(java.util.logging.Level.FINE, "alg = " + jceAlgorithm); try { @@ -1148,41 +1074,47 @@ public class XMLCipher { } try { - encryptedBytes = - c.doFinal(serializedOctets); - - logger.log(java.util.logging.Level.FINE, "Expected cipher.outputSize = " + + if (serializedData != null) { + int numBytes; + byte[] buf = new byte[8192]; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + while ((numBytes = serializedData.read(buf)) != -1) { + byte[] data = c.update(buf, 0, numBytes); + baos.write(data); + } + baos.write(c.doFinal()); + encryptedBytes = baos.toByteArray(); + } else { + encryptedBytes = c.doFinal(serializedOctets.getBytes("UTF-8")); + logger.log(java.util.logging.Level.FINE, "Expected cipher.outputSize = " + Integer.toString(c.getOutputSize( - serializedOctets.length))); + serializedOctets.getBytes().length))); + } logger.log(java.util.logging.Level.FINE, "Actual cipher.outputSize = " + - Integer.toString(encryptedBytes.length)); + Integer.toString(encryptedBytes.length)); } catch (IllegalStateException ise) { throw new XMLEncryptionException("empty", ise); } catch (IllegalBlockSizeException ibse) { throw new XMLEncryptionException("empty", ibse); } catch (BadPaddingException bpe) { throw new XMLEncryptionException("empty", bpe); - } catch (Exception uee) { + } catch (UnsupportedEncodingException uee) { throw new XMLEncryptionException("empty", uee); } // Now build up to a properly XML Encryption encoded octet stream // IvParameterSpec iv; - byte[] iv = c.getIV(); byte[] finalEncryptedBytes = new byte[iv.length + encryptedBytes.length]; - System.arraycopy(iv, 0, finalEncryptedBytes, 0, - iv.length); - System.arraycopy(encryptedBytes, 0, finalEncryptedBytes, - iv.length, - encryptedBytes.length); - + System.arraycopy(iv, 0, finalEncryptedBytes, 0, iv.length); + System.arraycopy(encryptedBytes, 0, finalEncryptedBytes, iv.length, + encryptedBytes.length); String base64EncodedEncryptedOctets = Base64.encode(finalEncryptedBytes); logger.log(java.util.logging.Level.FINE, "Encrypted octets:\n" + base64EncodedEncryptedOctets); logger.log(java.util.logging.Level.FINE, "Encrypted octets length = " + - base64EncodedEncryptedOctets.length()); + base64EncodedEncryptedOctets.length()); try { CipherData cd = _ed.getCipherData(); @@ -1190,15 +1122,11 @@ public class XMLCipher { // cv.setValue(base64EncodedEncryptedOctets.getBytes()); cv.setValue(base64EncodedEncryptedOctets); - if (contentMode) { - _ed.setType( - new URI(EncryptionConstants.TYPE_CONTENT).toString()); - } else { - _ed.setType( - new URI(EncryptionConstants.TYPE_ELEMENT).toString()); + if (type != null) { + _ed.setType(new URI(type).toString()); } EncryptionMethod method = - _factory.newEncryptionMethod(new URI(_algorithm).toString()); + _factory.newEncryptionMethod(new URI(_algorithm).toString()); _ed.setEncryptionMethod(method); } catch (URI.MalformedURIException mfue) { throw new XMLEncryptionException("empty", mfue); @@ -1206,7 +1134,6 @@ public class XMLCipher { return (_ed); } - /** * Returns an EncryptedData interface. Use this operation if * you want to load an EncryptedData structure from a DOM @@ -1219,7 +1146,7 @@ public class XMLCipher { */ public EncryptedData loadEncryptedData(Document context, Element element) throws XMLEncryptionException { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Loading encrypted element..."); + logger.log(java.util.logging.Level.FINE, "Loading encrypted element..."); if(null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if(null == element) @@ -1246,13 +1173,13 @@ public class XMLCipher { public EncryptedKey loadEncryptedKey(Document context, Element element) throws XMLEncryptionException { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Loading encrypted key..."); + logger.log(java.util.logging.Level.FINE, "Loading encrypted key..."); if(null == context) logger.log(java.util.logging.Level.SEVERE, "Context document unexpectedly null..."); if(null == element) logger.log(java.util.logging.Level.SEVERE, "Element unexpectedly null..."); if(_cipherMode != UNWRAP_MODE && _cipherMode != DECRYPT_MODE) - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in UNWRAP_MODE or DECRYPT_MODE..."); + logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in UNWRAP_MODE or DECRYPT_MODE..."); _contextDocument = context; _ek = _factory.newEncryptedKey(element); @@ -1290,12 +1217,12 @@ public class XMLCipher { public EncryptedKey encryptKey(Document doc, Key key) throws XMLEncryptionException { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypting key ..."); + logger.log(java.util.logging.Level.FINE, "Encrypting key ..."); if(null == key) logger.log(java.util.logging.Level.SEVERE, "Key unexpectedly null..."); if(_cipherMode != WRAP_MODE) - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in WRAP_MODE..."); + logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in WRAP_MODE..."); if (_algorithm == null) { @@ -1313,7 +1240,7 @@ public class XMLCipher { String jceAlgorithm = JCEMapper.translateURItoJCEID(_algorithm); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "alg = " + jceAlgorithm); + logger.log(java.util.logging.Level.FINE, "alg = " + jceAlgorithm); try { if (_requestedJCEProvider == null) @@ -1345,8 +1272,8 @@ public class XMLCipher { String base64EncodedEncryptedOctets = Base64.encode(encryptedBytes); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypted key octets:\n" + base64EncodedEncryptedOctets); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypted key octets length = " + + logger.log(java.util.logging.Level.FINE, "Encrypted key octets:\n" + base64EncodedEncryptedOctets); + logger.log(java.util.logging.Level.FINE, "Encrypted key octets length = " + base64EncodedEncryptedOctets.length()); CipherValue cv = _ek.getCipherData().getCipherValue(); @@ -1376,10 +1303,10 @@ public class XMLCipher { public Key decryptKey(EncryptedKey encryptedKey, String algorithm) throws XMLEncryptionException { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Decrypting key from previously loaded EncryptedKey..."); + logger.log(java.util.logging.Level.FINE, "Decrypting key from previously loaded EncryptedKey..."); if(_cipherMode != UNWRAP_MODE) - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in UNWRAP_MODE..."); + logger.log(java.util.logging.Level.FINE, "XMLCipher unexpectedly not in UNWRAP_MODE..."); if (algorithm == null) { throw new XMLEncryptionException("Cannot decrypt a key without knowing the algorithm"); @@ -1387,7 +1314,7 @@ public class XMLCipher { if (_key == null) { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Trying to find a KEK via key resolvers"); + logger.log(java.util.logging.Level.FINE, "Trying to find a KEK via key resolvers"); KeyInfo ki = encryptedKey.getKeyInfo(); if (ki != null) { @@ -1418,7 +1345,7 @@ public class XMLCipher { JCEMapper.translateURItoJCEID( encryptedKey.getEncryptionMethod().getAlgorithm()); - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "JCE Algorithm = " + jceAlgorithm); + logger.log(java.util.logging.Level.FINE, "JCE Algorithm = " + jceAlgorithm); try { if (_requestedJCEProvider == null) @@ -1448,7 +1375,7 @@ public class XMLCipher { throw new XMLEncryptionException("empty", nsae); } - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Decryption of key type " + algorithm + " OK"); + logger.log(java.util.logging.Level.FINE, "Decryption of key type " + algorithm + " OK"); return ret; @@ -1478,14 +1405,9 @@ public class XMLCipher { * * @param node the Node to clear. */ - private void removeContent(Node node) { - NodeList list = node.getChildNodes(); - if (list.getLength() > 0) { - Node n = list.item(0); - if (null != n) { - n.getParentNode().removeChild(n); - } - removeContent(node); + private static void removeContent(Node node) { + while (node.hasChildNodes()) { + node.removeChild(node.getFirstChild()); } } @@ -1499,7 +1421,7 @@ public class XMLCipher { private Document decryptElement(Element element) throws XMLEncryptionException { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Decrypting element..."); + logger.log(java.util.logging.Level.FINE, "Decrypting element..."); if(_cipherMode != DECRYPT_MODE) logger.log(java.util.logging.Level.SEVERE, "XMLCipher unexpectedly not in DECRYPT_MODE..."); @@ -1512,7 +1434,7 @@ public class XMLCipher { } - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Decrypted octets:\n" + octets); + logger.log(java.util.logging.Level.FINE, "Decrypted octets:\n" + octets); Node sourceParent = element.getParentNode(); @@ -1573,7 +1495,7 @@ public class XMLCipher { public byte[] decryptToByteArray(Element element) throws XMLEncryptionException { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Decrypting to ByteArray..."); + logger.log(java.util.logging.Level.FINE, "Decrypting to ByteArray..."); if(_cipherMode != DECRYPT_MODE) logger.log(java.util.logging.Level.SEVERE, "XMLCipher unexpectedly not in DECRYPT_MODE..."); @@ -2226,7 +2148,7 @@ public class XMLCipher { AgreementMethod newAgreementMethod(Element element) throws XMLEncryptionException { if (null == element) { - //complain + throw new NullPointerException("element is null"); } String algorithm = element.getAttributeNS(null, @@ -2292,7 +2214,7 @@ public class XMLCipher { CipherData newCipherData(Element element) throws XMLEncryptionException { if (null == element) { - // complain + throw new NullPointerException("element is null"); } int type = 0; @@ -2352,7 +2274,7 @@ public class XMLCipher { (Element) transformsElements.item(0); if (transformsElement != null) { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Creating a DSIG based Transforms element"); + logger.log(java.util.logging.Level.FINE, "Creating a DSIG based Transforms element"); try { result.setTransforms(new TransformsImpl(transformsElement)); } @@ -2411,34 +2333,28 @@ public class XMLCipher { XMLEncryptionException { EncryptedData result = null; - NodeList dataElements = element.getElementsByTagNameNS( - EncryptionConstants.EncryptionSpecNS, - EncryptionConstants._TAG_CIPHERDATA); + NodeList dataElements = element.getElementsByTagNameNS( + EncryptionConstants.EncryptionSpecNS, + EncryptionConstants._TAG_CIPHERDATA); - // Need to get the last CipherData found, as earlier ones will - // be for elements in the KeyInfo lists + // Need to get the last CipherData found, as earlier ones will + // be for elements in the KeyInfo lists Element dataElement = - (Element) dataElements.item(dataElements.getLength() - 1); + (Element) dataElements.item(dataElements.getLength() - 1); CipherData data = newCipherData(dataElement); result = newEncryptedData(data); - try { - result.setId(element.getAttributeNS( - null, EncryptionConstants._ATT_ID)); - result.setType(new URI( - element.getAttributeNS( - null, EncryptionConstants._ATT_TYPE)).toString()); - result.setMimeType(element.getAttributeNS( - null, EncryptionConstants._ATT_MIMETYPE)); - result.setEncoding(new URI( - element.getAttributeNS( - null, Constants._ATT_ENCODING)).toString()); - } catch (URI.MalformedURIException mfue) { - // do nothing - } + result.setId(element.getAttributeNS( + null, EncryptionConstants._ATT_ID)); + result.setType( + element.getAttributeNS(null, EncryptionConstants._ATT_TYPE)); + result.setMimeType(element.getAttributeNS( + null, EncryptionConstants._ATT_MIMETYPE)); + result.setEncoding( + element.getAttributeNS(null, Constants._ATT_ENCODING)); Element encryptionMethodElement = (Element) element.getElementsByTagNameNS( @@ -2450,18 +2366,18 @@ public class XMLCipher { } // BFL 16/7/03 - simple implementation - // TODO: Work out how to handle relative URI + // TODO: Work out how to handle relative URI Element keyInfoElement = (Element) element.getElementsByTagNameNS( Constants.SignatureSpecNS, Constants._TAG_KEYINFO).item(0); if (null != keyInfoElement) { - try { - result.setKeyInfo(new KeyInfo(keyInfoElement, null)); - } catch (XMLSecurityException xse) { - throw new XMLEncryptionException("Error loading Key Info", - xse); - } + try { + result.setKeyInfo(new KeyInfo(keyInfoElement, null)); + } catch (XMLSecurityException xse) { + throw new XMLEncryptionException("Error loading Key Info", + xse); + } } // TODO: Implement @@ -2511,31 +2427,25 @@ public class XMLCipher { EncryptedKey newEncryptedKey(Element element) throws XMLEncryptionException { EncryptedKey result = null; - NodeList dataElements = element.getElementsByTagNameNS( - EncryptionConstants.EncryptionSpecNS, - EncryptionConstants._TAG_CIPHERDATA); + NodeList dataElements = element.getElementsByTagNameNS( + EncryptionConstants.EncryptionSpecNS, + EncryptionConstants._TAG_CIPHERDATA); Element dataElement = - (Element) dataElements.item(dataElements.getLength() - 1); + (Element) dataElements.item(dataElements.getLength() - 1); CipherData data = newCipherData(dataElement); result = newEncryptedKey(data); - try { - result.setId(element.getAttributeNS( - null, EncryptionConstants._ATT_ID)); - result.setType(new URI( - element.getAttributeNS( - null, EncryptionConstants._ATT_TYPE)).toString()); - result.setMimeType(element.getAttributeNS( - null, EncryptionConstants._ATT_MIMETYPE)); - result.setEncoding(new URI( - element.getAttributeNS( - null, Constants._ATT_ENCODING)).toString()); - result.setRecipient(element.getAttributeNS( - null, EncryptionConstants._ATT_RECIPIENT)); - } catch (URI.MalformedURIException mfue) { - // do nothing - } + result.setId(element.getAttributeNS( + null, EncryptionConstants._ATT_ID)); + result.setType( + element.getAttributeNS(null, EncryptionConstants._ATT_TYPE)); + result.setMimeType(element.getAttributeNS( + null, EncryptionConstants._ATT_MIMETYPE)); + result.setEncoding( + element.getAttributeNS(null, Constants._ATT_ENCODING)); + result.setRecipient(element.getAttributeNS( + null, EncryptionConstants._ATT_RECIPIENT)); Element encryptionMethodElement = (Element) element.getElementsByTagNameNS( @@ -2550,12 +2460,12 @@ public class XMLCipher { (Element) element.getElementsByTagNameNS( Constants.SignatureSpecNS, Constants._TAG_KEYINFO).item(0); if (null != keyInfoElement) { - try { - result.setKeyInfo(new KeyInfo(keyInfoElement, null)); - } catch (XMLSecurityException xse) { - throw new XMLEncryptionException("Error loading Key Info", - xse); - } + try { + result.setKeyInfo(new KeyInfo(keyInfoElement, null)); + } catch (XMLSecurityException xse) { + throw new XMLEncryptionException + ("Error loading Key Info", xse); + } } // TODO: Implement @@ -2581,7 +2491,8 @@ public class XMLCipher { EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CARRIEDKEYNAME).item(0); if (null != carriedNameElement) { - result.setCarriedName(carriedNameElement.getNodeValue()); + result.setCarriedName + (carriedNameElement.getFirstChild().getNodeValue()); } return (result); @@ -2680,13 +2591,8 @@ public class XMLCipher { EncryptionProperty newEncryptionProperty(Element element) { EncryptionProperty result = newEncryptionProperty(); - try { - result.setTarget(new URI( - element.getAttributeNS( - null, EncryptionConstants._ATT_TARGET)).toString()); - } catch (URI.MalformedURIException mfue) { - // do nothing - } + result.setTarget( + element.getAttributeNS(null, EncryptionConstants._ATT_TARGET)); result.setId(element.getAttributeNS( null, EncryptionConstants._ATT_ID)); // TODO: Make this lot work... @@ -2943,7 +2849,7 @@ public class XMLCipher { } catch (URI.MalformedURIException mfue) { //complain } - algorithm = tmpAlgorithm.toString(); + algorithmURI = tmpAlgorithm.toString(); } // @@ -3183,7 +3089,7 @@ public class XMLCipher { _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_CIPHERVALUE); result.appendChild(_contextDocument.createTextNode( - new String(cipherValue))); + cipherValue)); return (result); } @@ -3247,8 +3153,7 @@ public class XMLCipher { } if (null != super.getType()) { result.setAttributeNS( - null, EncryptionConstants._ATT_TYPE, - super.getType().toString()); + null, EncryptionConstants._ATT_TYPE, super.getType()); } if (null != super.getMimeType()) { result.setAttributeNS( @@ -3258,7 +3163,7 @@ public class XMLCipher { if (null != super.getEncoding()) { result.setAttributeNS( null, EncryptionConstants._ATT_ENCODING, - super.getEncoding().toString()); + super.getEncoding()); } if (null != super.getEncryptionMethod()) { result.appendChild(((EncryptionMethodImpl) @@ -3383,8 +3288,7 @@ public class XMLCipher { } if (null != super.getType()) { result.setAttributeNS( - null, EncryptionConstants._ATT_TYPE, - super.getType().toString()); + null, EncryptionConstants._ATT_TYPE, super.getType()); } if (null != super.getMimeType()) { result.setAttributeNS(null, @@ -3392,7 +3296,7 @@ public class XMLCipher { } if (null != super.getEncoding()) { result.setAttributeNS(null, Constants._ATT_ENCODING, - super.getEncoding().toString()); + super.getEncoding()); } if (null != getRecipient()) { result.setAttributeNS(null, @@ -3468,13 +3372,17 @@ public class XMLCipher { * @param type */ public void setType(String type) { - URI tmpType = null; - try { - tmpType = new URI(type); - } catch (URI.MalformedURIException mfue) { - // complain + if (type == null || type.length() == 0) { + this.type = null; + } else { + URI tmpType = null; + try { + tmpType = new URI(type); + } catch (URI.MalformedURIException mfue) { + // complain + } + this.type = tmpType.toString(); } - this.type = tmpType.toString(); } /** * @@ -3502,13 +3410,17 @@ public class XMLCipher { * @param encoding */ public void setEncoding(String encoding) { - URI tmpEncoding = null; - try { - tmpEncoding = new URI(encoding); - } catch (URI.MalformedURIException mfue) { - // complain + if (encoding == null || encoding.length() == 0) { + this.encoding = null; + } else { + URI tmpEncoding = null; + try { + tmpEncoding = new URI(encoding); + } catch (URI.MalformedURIException mfue) { + // complain + } + this.encoding = tmpEncoding.toString(); } - this.encoding = tmpEncoding.toString(); } /** * @@ -3635,7 +3547,7 @@ public class XMLCipher { _contextDocument, EncryptionConstants.EncryptionSpecNS, EncryptionConstants._TAG_ENCRYPTIONMETHOD); result.setAttributeNS(null, EncryptionConstants._ATT_ALGORITHM, - algorithm.toString()); + algorithm); if (keySize > 0) { result.appendChild( ElementProxy.createElementForFamily(_contextDocument, @@ -3735,8 +3647,7 @@ public class XMLCipher { private class EncryptionPropertyImpl implements EncryptionProperty { private String target = null; private String id = null; - private String attributeName = null; - private String attributeValue = null; + private HashMap attributeMap = new HashMap(); private List encryptionInformation = null; /** @@ -3752,13 +3663,24 @@ public class XMLCipher { } /** @inheritDoc */ public void setTarget(String target) { - URI tmpTarget = null; - try { - tmpTarget = new URI(target); - } catch (URI.MalformedURIException mfue) { - // complain + if (target == null || target.length() == 0) { + this.target = null; + } else if (target.startsWith("#")) { + /* + * This is a same document URI reference. Do not parse, + * because com.sun.org.apache.xml.internal.utils.URI considers this an + * illegal URI because it has no scheme. + */ + this.target = target; + } else { + URI tmpTarget = null; + try { + tmpTarget = new URI(target); + } catch (URI.MalformedURIException mfue) { + // complain + } + this.target = tmpTarget.toString(); } - this.target = tmpTarget.toString(); } /** @inheritDoc */ public String getId() { @@ -3770,12 +3692,11 @@ public class XMLCipher { } /** @inheritDoc */ public String getAttribute(String attribute) { - return (attributeValue); + return (String) attributeMap.get(attribute); } /** @inheritDoc */ public void setAttribute(String attribute, String value) { - attributeName = attribute; - attributeValue = value; + attributeMap.put(attribute, value); } /** @inheritDoc */ public Iterator getEncryptionInformation() { @@ -3805,7 +3726,7 @@ public class XMLCipher { EncryptionConstants._TAG_ENCRYPTIONPROPERTY); if (null != target) { result.setAttributeNS(null, EncryptionConstants._ATT_TARGET, - target.toString()); + target); } if (null != id) { result.setAttributeNS(null, EncryptionConstants._ATT_ID, @@ -3839,7 +3760,13 @@ public class XMLCipher { * @param doc */ public TransformsImpl(Document doc) { - super(doc); + if (doc == null) { + throw new RuntimeException("Document is null"); + } + + this._doc = doc; + this._constructionElement = createElementForFamilyLocal(this._doc, + this.getBaseNamespace(), this.getBaseLocalName()); } /** * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipherInput.java b/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipherInput.java index 9d1db588eb6d25d52d7abd05a31d211e744248e3..65b9a604b661bc08063b161ce47ee8c84cb0a955 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipherInput.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/encryption/XMLCipherInput.java @@ -108,84 +108,78 @@ public class XMLCipherInput { return null; } - /** - * Internal method to get bytes in decryption mode + /** + * Internal method to get bytes in decryption mode * @return the decripted bytes * @throws XMLEncryptionException - */ - - private byte[] getDecryptBytes() throws XMLEncryptionException { + */ + private byte[] getDecryptBytes() throws XMLEncryptionException { - String base64EncodedEncryptedOctets = null; + String base64EncodedEncryptedOctets = null; if (_cipherData.getDataType() == CipherData.REFERENCE_TYPE) { - // Fun time! - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Found a reference type CipherData"); - CipherReference cr = _cipherData.getCipherReference(); - - // Need to wrap the uri in an Attribute node so that we can - // Pass to the resource resolvers - - Attr uriAttr = cr.getURIAsAttr(); - XMLSignatureInput input = null; - - try { - ResourceResolver resolver = - ResourceResolver.getInstance(uriAttr, null); - input = resolver.resolve(uriAttr, null); - } catch (ResourceResolverException ex) { - throw new XMLEncryptionException("empty", ex); - } - - if (input != null) { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Managed to resolve URI \"" + cr.getURI() + "\""); - } - else { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Failed to resolve URI \"" + cr.getURI() + "\""); - } - - // Lets see if there are any transforms - Transforms transforms = cr.getTransforms(); - if (transforms != null) { - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Have transforms in cipher reference"); - try { - com.sun.org.apache.xml.internal.security.transforms.Transforms dsTransforms = - transforms.getDSTransforms(); - input = dsTransforms.performTransforms(input); - } catch (TransformationException ex) { - throw new XMLEncryptionException("empty", ex); - } - } - - try { - return input.getBytes(); - } - catch (IOException ex) { - throw new XMLEncryptionException("empty", ex); - } catch (CanonicalizationException ex) { - throw new XMLEncryptionException("empty", ex); - } - - // retrieve the cipher text + // Fun time! + logger.log(java.util.logging.Level.FINE, "Found a reference type CipherData"); + CipherReference cr = _cipherData.getCipherReference(); + + // Need to wrap the uri in an Attribute node so that we can + // Pass to the resource resolvers + + Attr uriAttr = cr.getURIAsAttr(); + XMLSignatureInput input = null; + + try { + ResourceResolver resolver = + ResourceResolver.getInstance(uriAttr, null); + input = resolver.resolve(uriAttr, null); + } catch (ResourceResolverException ex) { + throw new XMLEncryptionException("empty", ex); + } + + if (input != null) { + logger.log(java.util.logging.Level.FINE, "Managed to resolve URI \"" + cr.getURI() + "\""); + } else { + logger.log(java.util.logging.Level.FINE, "Failed to resolve URI \"" + cr.getURI() + "\""); + } + + // Lets see if there are any transforms + Transforms transforms = cr.getTransforms(); + if (transforms != null) { + logger.log(java.util.logging.Level.FINE, "Have transforms in cipher reference"); + try { + com.sun.org.apache.xml.internal.security.transforms.Transforms dsTransforms = + transforms.getDSTransforms(); + input = dsTransforms.performTransforms(input); + } catch (TransformationException ex) { + throw new XMLEncryptionException("empty", ex); + } + } + + try { + return input.getBytes(); + } catch (IOException ex) { + throw new XMLEncryptionException("empty", ex); + } catch (CanonicalizationException ex) { + throw new XMLEncryptionException("empty", ex); + } + + // retrieve the cipher text } else if (_cipherData.getDataType() == CipherData.VALUE_TYPE) { - CipherValue cv = _cipherData.getCipherValue(); - base64EncodedEncryptedOctets = new String(cv.getValue()); + base64EncodedEncryptedOctets = + _cipherData.getCipherValue().getValue(); } else { - throw new XMLEncryptionException("CipherData.getDataType() returned unexpected value"); - } + throw new XMLEncryptionException("CipherData.getDataType() returned unexpected value"); + } - if (logger.isLoggable(java.util.logging.Level.FINE)) logger.log(java.util.logging.Level.FINE, "Encrypted octets:\n" + base64EncodedEncryptedOctets); + logger.log(java.util.logging.Level.FINE, "Encrypted octets:\n" + base64EncodedEncryptedOctets); byte[] encryptedBytes = null; - try { - encryptedBytes = Base64.decode(base64EncodedEncryptedOctets); + encryptedBytes = Base64.decode(base64EncodedEncryptedOctets); } catch (Base64DecodingException bde) { throw new XMLEncryptionException("empty", bde); } - return (encryptedBytes); - - } - + return (encryptedBytes); + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/ContentHandlerAlreadyRegisteredException.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/ContentHandlerAlreadyRegisteredException.java index e071b1474c62dd13a6a77bb535c2b5d35420c213..6477d9bba2c24a1bd37ecb7f80677976e8529527 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/ContentHandlerAlreadyRegisteredException.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/ContentHandlerAlreadyRegisteredException.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -28,7 +27,7 @@ import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class ContentHandlerAlreadyRegisteredException extends XMLSecurityException { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/KeyInfo.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/KeyInfo.java index 1750257f625d0937cf4daa87e815250ce7f455e7..cf588b8d488fa6eac65c5b7ad333ee226961b13e 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/KeyInfo.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/KeyInfo.java @@ -25,6 +25,8 @@ package com.sun.org.apache.xml.internal.security.keys; import java.security.PublicKey; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; import java.util.List; import javax.crypto.SecretKey; @@ -88,15 +90,22 @@ import org.w3c.dom.NodeList; * The containsXXX() methods return whether the KeyInfo * contains the corresponding type. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class KeyInfo extends SignatureElementProxy { /** {@link java.util.logging} logging facility */ static java.util.logging.Logger log = java.util.logging.Logger.getLogger(KeyInfo.class.getName()); + List x509Datas=null; + List encryptedKeys=null; - + static final List nullList; + static { + List list = new ArrayList(); + list.add(null); + nullList = Collections.unmodifiableList(list); + } /** * Constructor KeyInfo @@ -108,7 +117,6 @@ public class KeyInfo extends SignatureElementProxy { XMLUtils.addReturnToElement(this._constructionElement); - } /** @@ -119,8 +127,8 @@ public class KeyInfo extends SignatureElementProxy { * @throws XMLSecurityException */ public KeyInfo(Element element, String BaseURI) throws XMLSecurityException { - super(element, BaseURI); + // _storageResolvers.add(null); } @@ -131,7 +139,7 @@ public class KeyInfo extends SignatureElementProxy { */ public void setId(String Id) { - if ((this._state == MODE_SIGN) && (Id != null)) { + if ((Id != null)) { this._constructionElement.setAttributeNS(null, Constants._ATT_ID, Id); IdResolver.registerElementById(this._constructionElement, Id); } @@ -162,10 +170,8 @@ public class KeyInfo extends SignatureElementProxy { */ public void add(KeyName keyname) { - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(keyname.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -219,11 +225,8 @@ public class KeyInfo extends SignatureElementProxy { * @param keyvalue */ public void add(KeyValue keyvalue) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(keyvalue.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -241,11 +244,8 @@ public class KeyInfo extends SignatureElementProxy { * @param mgmtdata */ public void add(MgmtData mgmtdata) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(mgmtdata.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -254,11 +254,8 @@ public class KeyInfo extends SignatureElementProxy { * @param pgpdata */ public void add(PGPData pgpdata) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(pgpdata.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -279,11 +276,8 @@ public class KeyInfo extends SignatureElementProxy { * @param retrievalmethod */ public void add(RetrievalMethod retrievalmethod) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(retrievalmethod.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -292,11 +286,8 @@ public class KeyInfo extends SignatureElementProxy { * @param spkidata */ public void add(SPKIData spkidata) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(spkidata.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -305,11 +296,11 @@ public class KeyInfo extends SignatureElementProxy { * @param x509data */ public void add(X509Data x509data) { - - if (this._state == MODE_SIGN) { + if (x509Datas==null) + x509Datas=new ArrayList(); + x509Datas.add(x509data); this._constructionElement.appendChild(x509data.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -321,12 +312,11 @@ public class KeyInfo extends SignatureElementProxy { public void add(EncryptedKey encryptedKey) throws XMLEncryptionException { - - if (this._state == MODE_SIGN) { + if (encryptedKeys==null) + encryptedKeys=new ArrayList(); + encryptedKeys.add(encryptedKey); XMLCipher cipher = XMLCipher.getInstance(); this._constructionElement.appendChild(cipher.martial(encryptedKey)); - } - } /** @@ -335,11 +325,8 @@ public class KeyInfo extends SignatureElementProxy { * @param element */ public void addUnknownElement(Element element) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(element); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -403,6 +390,9 @@ public class KeyInfo extends SignatureElementProxy { *@return the number of the X509Data tags */ public int lengthX509Data() { + if (x509Datas!=null) { + return x509Datas.size(); + } return this.length(Constants.SignatureSpecNS, Constants._TAG_X509DATA); } @@ -550,7 +540,9 @@ public class KeyInfo extends SignatureElementProxy { * @throws XMLSecurityException */ public X509Data itemX509Data(int i) throws XMLSecurityException { - + if (x509Datas!=null) { + return (X509Data) x509Datas.get(i); + } Element e = XMLUtils.selectDsNode(this._constructionElement.getFirstChild(), Constants._TAG_X509DATA,i); @@ -569,7 +561,9 @@ public class KeyInfo extends SignatureElementProxy { */ public EncryptedKey itemEncryptedKey(int i) throws XMLSecurityException { - + if (encryptedKeys!=null) { + return (EncryptedKey) encryptedKeys.get(i); + } Element e = XMLUtils.selectXencNode(this._constructionElement.getFirstChild(), EncryptionConstants._TAG_ENCRYPTEDKEY,i); @@ -707,20 +701,20 @@ public class KeyInfo extends SignatureElementProxy { PublicKey pk = this.getPublicKeyFromInternalResolvers(); if (pk != null) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I could find a key using the per-KeyInfo key resolvers"); + log.log(java.util.logging.Level.FINE, "I could find a key using the per-KeyInfo key resolvers"); return pk; } - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I couldn't find a key using the per-KeyInfo key resolvers"); + log.log(java.util.logging.Level.FINE, "I couldn't find a key using the per-KeyInfo key resolvers"); pk = this.getPublicKeyFromStaticResolvers(); if (pk != null) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I could find a key using the system-wide key resolvers"); + log.log(java.util.logging.Level.FINE, "I could find a key using the system-wide key resolvers"); return pk; } - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I couldn't find a key using the system-wide key resolvers"); + log.log(java.util.logging.Level.FINE, "I couldn't find a key using the system-wide key resolvers"); return null; } @@ -732,46 +726,29 @@ public class KeyInfo extends SignatureElementProxy { * @throws KeyResolverException */ PublicKey getPublicKeyFromStaticResolvers() throws KeyResolverException { - - for (int i = 0; i < KeyResolver.length(); i++) { - KeyResolver keyResolver = KeyResolver.item(i); + int length=KeyResolver.length(); + int storageLength=this._storageResolvers.size(); + Iterator it= KeyResolver.iterator(); + for (int i = 0; i < length; i++) { + KeyResolverSpi keyResolver = (KeyResolverSpi) it.next(); Node currentChild=this._constructionElement.getFirstChild(); + String uri= this.getBaseURI(); while (currentChild!=null) { if (currentChild.getNodeType() == Node.ELEMENT_NODE) { - if (this._storageResolvers.size() == 0) { - - // if we do not have storage resolvers, we verify with null - StorageResolver storage = null; - - if (keyResolver.canResolve((Element) currentChild, - this.getBaseURI(), storage)) { - PublicKey pk = - keyResolver.resolvePublicKey((Element) currentChild, - this.getBaseURI(), - storage); - - if (pk != null) { - return pk; - } - } - } else { - for (int k = 0; k < this._storageResolvers.size(); k++) { + for (int k = 0; k < storageLength; k++) { StorageResolver storage = (StorageResolver) this._storageResolvers.get(k); - if (keyResolver.canResolve((Element) currentChild, - this.getBaseURI(), storage)) { - PublicKey pk = - keyResolver.resolvePublicKey((Element) currentChild, - this.getBaseURI(), + PublicKey pk = + keyResolver.engineLookupAndResolvePublicKey((Element) currentChild, + uri, storage); - if (pk != null) { - return pk; - } + if (pk != null) { + KeyResolver.hit(it); + return pk; } } - } } currentChild=currentChild.getNextSibling(); } @@ -786,50 +763,27 @@ public class KeyInfo extends SignatureElementProxy { * @throws KeyResolverException */ PublicKey getPublicKeyFromInternalResolvers() throws KeyResolverException { - - for (int i = 0; i < this.lengthInternalKeyResolver(); i++) { + int length=lengthInternalKeyResolver(); + int storageLength=this._storageResolvers.size(); + for (int i = 0; i < length; i++) { KeyResolverSpi keyResolver = this.itemInternalKeyResolver(i); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Try " + keyResolver.getClass().getName()); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Try " + keyResolver.getClass().getName()); Node currentChild=this._constructionElement.getFirstChild(); + String uri=this.getBaseURI(); while (currentChild!=null) { if (currentChild.getNodeType() == Node.ELEMENT_NODE) { - if (this._storageResolvers.size() == 0) { - - // if we do not have storage resolvers, we verify with null - StorageResolver storage = null; - - if (keyResolver.engineCanResolve((Element) currentChild, - this.getBaseURI(), - storage)) { - PublicKey pk = - keyResolver - .engineResolvePublicKey((Element) currentChild, this - .getBaseURI(), storage); + for (int k = 0; k < storageLength; k++) { + StorageResolver storage = + (StorageResolver) this._storageResolvers.get(k); + PublicKey pk = keyResolver + .engineLookupAndResolvePublicKey((Element) currentChild, uri, storage); if (pk != null) { - return pk; + return pk; } } - } else { - for (int k = 0; k < this._storageResolvers.size(); k++) { - StorageResolver storage = - (StorageResolver) this._storageResolvers.get(k); - - if (keyResolver.engineCanResolve((Element) currentChild, - this.getBaseURI(), - storage)) { - PublicKey pk = keyResolver - .engineResolvePublicKey((Element) currentChild, this - .getBaseURI(), storage); - - if (pk != null) { - return pk; - } - } - } - } } currentChild=currentChild.getNextSibling(); } @@ -850,12 +804,12 @@ public class KeyInfo extends SignatureElementProxy { X509Certificate cert = this.getX509CertificateFromInternalResolvers(); if (cert != null) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, + log.log(java.util.logging.Level.FINE, "I could find a X509Certificate using the per-KeyInfo key resolvers"); return cert; } - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, + log.log(java.util.logging.Level.FINE, "I couldn't find a X509Certificate using the per-KeyInfo key resolvers"); @@ -863,12 +817,12 @@ public class KeyInfo extends SignatureElementProxy { cert = this.getX509CertificateFromStaticResolvers(); if (cert != null) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, + log.log(java.util.logging.Level.FINE, "I could find a X509Certificate using the system-wide key resolvers"); return cert; } - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, + log.log(java.util.logging.Level.FINE, "I couldn't find a X509Certificate using the system-wide key resolvers"); @@ -885,53 +839,44 @@ public class KeyInfo extends SignatureElementProxy { */ X509Certificate getX509CertificateFromStaticResolvers() throws KeyResolverException { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Start getX509CertificateFromStaticResolvers() with " + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Start getX509CertificateFromStaticResolvers() with " + KeyResolver.length() + " resolvers"); + String uri=this.getBaseURI(); + int length= KeyResolver.length(); + int storageLength=this._storageResolvers.size(); + Iterator it = KeyResolver.iterator(); + for (int i = 0; i com.sun.org.apache.xml.internal.security.keys package. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class KeyUtils { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyInfoContent.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyInfoContent.java index ba9769043a39e229a21f4b918adc9cf86adc7d3f..4d5a7a6b975f6f30b490cdaa0248d0707f6eae9b 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyInfoContent.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyInfoContent.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -28,7 +27,7 @@ package com.sun.org.apache.xml.internal.security.keys.content; /** * Empty interface just to identify Elements that can be cildren of ds:KeyInfo. * - * @author $Author: blautenb $ + * @author $Author: mullan $ */ public interface KeyInfoContent { } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyName.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyName.java index dfff3c322111375895fbe66e5827b109180384b0..6794ea675866713ffab8f54bf33f15d8a7446c07 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyName.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyName.java @@ -20,25 +20,18 @@ */ package com.sun.org.apache.xml.internal.security.keys.content; - - import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.utils.Constants; import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class KeyName extends SignatureElementProxy implements KeyInfoContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(KeyName.class.getName()); - /** * Constructor KeyName * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyValue.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyValue.java index ab8b959f75cbe757c5e178c05000f793e9169532..0d3ee810d2392a2a30f885e66d94cf52f705f303 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyValue.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/KeyValue.java @@ -20,11 +20,8 @@ */ package com.sun.org.apache.xml.internal.security.keys.content; - - import java.security.PublicKey; - import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.keys.content.keyvalues.DSAKeyValue; import com.sun.org.apache.xml.internal.security.keys.content.keyvalues.RSAKeyValue; @@ -34,140 +31,131 @@ import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * The KeyValue element contains a single public key that may be useful in * validating the signature. Structured formats for defining DSA (REQUIRED) * and RSA (RECOMMENDED) public keys are defined in Signature Algorithms * (section 6.4). The KeyValue element may include externally defined public - * keys values represented as PCDATA or element types from an external namespace. + * keys values represented as PCDATA or element types from an external + * namespace. * - * @author $Author: vishal $ + * @author $Author: mullan $ */ public class KeyValue extends SignatureElementProxy implements KeyInfoContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(KeyValue.class.getName()); - - /** - * Constructor KeyValue - * - * @param doc - * @param dsaKeyValue - */ - public KeyValue(Document doc, DSAKeyValue dsaKeyValue) { - - super(doc); - - XMLUtils.addReturnToElement(this._constructionElement); - this._constructionElement.appendChild(dsaKeyValue.getElement()); - XMLUtils.addReturnToElement(this._constructionElement); - } - - /** - * Constructor KeyValue - * - * @param doc - * @param rsaKeyValue - */ - public KeyValue(Document doc, RSAKeyValue rsaKeyValue) { - - super(doc); - - XMLUtils.addReturnToElement(this._constructionElement); - this._constructionElement.appendChild(rsaKeyValue.getElement()); - XMLUtils.addReturnToElement(this._constructionElement); - } - - /** - * Constructor KeyValue - * - * @param doc - * @param unknownKeyValue - */ - public KeyValue(Document doc, Element unknownKeyValue) { - - super(doc); - - XMLUtils.addReturnToElement(this._constructionElement); - this._constructionElement.appendChild(unknownKeyValue); - XMLUtils.addReturnToElement(this._constructionElement); - } - - /** - * Constructor KeyValue - * - * @param doc - * @param pk - */ - public KeyValue(Document doc, PublicKey pk) { - - super(doc); - - XMLUtils.addReturnToElement(this._constructionElement); - - if (pk instanceof java.security.interfaces.DSAPublicKey) { - DSAKeyValue dsa = new DSAKeyValue(this._doc, pk); - - this._constructionElement.appendChild(dsa.getElement()); - XMLUtils.addReturnToElement(this._constructionElement); - } else if (pk instanceof java.security.interfaces.RSAPublicKey) { - RSAKeyValue rsa = new RSAKeyValue(this._doc, pk); - - this._constructionElement.appendChild(rsa.getElement()); - XMLUtils.addReturnToElement(this._constructionElement); - } - } - - /** - * Constructor KeyValue - * - * @param element - * @param BaseURI - * @throws XMLSecurityException - */ - public KeyValue(Element element, String BaseURI) + /** + * Constructor KeyValue + * + * @param doc + * @param dsaKeyValue + */ + public KeyValue(Document doc, DSAKeyValue dsaKeyValue) { + + super(doc); + + XMLUtils.addReturnToElement(this._constructionElement); + this._constructionElement.appendChild(dsaKeyValue.getElement()); + XMLUtils.addReturnToElement(this._constructionElement); + } + + /** + * Constructor KeyValue + * + * @param doc + * @param rsaKeyValue + */ + public KeyValue(Document doc, RSAKeyValue rsaKeyValue) { + + super(doc); + + XMLUtils.addReturnToElement(this._constructionElement); + this._constructionElement.appendChild(rsaKeyValue.getElement()); + XMLUtils.addReturnToElement(this._constructionElement); + } + + /** + * Constructor KeyValue + * + * @param doc + * @param unknownKeyValue + */ + public KeyValue(Document doc, Element unknownKeyValue) { + + super(doc); + + XMLUtils.addReturnToElement(this._constructionElement); + this._constructionElement.appendChild(unknownKeyValue); + XMLUtils.addReturnToElement(this._constructionElement); + } + + /** + * Constructor KeyValue + * + * @param doc + * @param pk + */ + public KeyValue(Document doc, PublicKey pk) { + + super(doc); + + XMLUtils.addReturnToElement(this._constructionElement); + + if (pk instanceof java.security.interfaces.DSAPublicKey) { + DSAKeyValue dsa = new DSAKeyValue(this._doc, pk); + + this._constructionElement.appendChild(dsa.getElement()); + XMLUtils.addReturnToElement(this._constructionElement); + } else if (pk instanceof java.security.interfaces.RSAPublicKey) { + RSAKeyValue rsa = new RSAKeyValue(this._doc, pk); + + this._constructionElement.appendChild(rsa.getElement()); + XMLUtils.addReturnToElement(this._constructionElement); + } + } + + /** + * Constructor KeyValue + * + * @param element + * @param BaseURI + * @throws XMLSecurityException + */ + public KeyValue(Element element, String BaseURI) throws XMLSecurityException { - super(element, BaseURI); - } - - /** - * Method getPublicKey - * - * @return the public key - * @throws XMLSecurityException - */ - public PublicKey getPublicKey() throws XMLSecurityException { - - - Element rsa = XMLUtils.selectDsNode(this._constructionElement.getFirstChild(), - Constants._TAG_RSAKEYVALUE,0); - - if (rsa != null) { - RSAKeyValue kv = new RSAKeyValue(rsa, - this._baseURI); - + super(element, BaseURI); + } + + /** + * Method getPublicKey + * + * @return the public key + * @throws XMLSecurityException + */ + public PublicKey getPublicKey() throws XMLSecurityException { + + Element rsa = XMLUtils.selectDsNode + (this._constructionElement.getFirstChild(), + Constants._TAG_RSAKEYVALUE,0); + + if (rsa != null) { + RSAKeyValue kv = new RSAKeyValue(rsa, this._baseURI); return kv.getPublicKey(); - } + } - Element dsa = XMLUtils.selectDsNode(this._constructionElement, - Constants._TAG_DSAKEYVALUE,0); - - - if (dsa != null) { - DSAKeyValue kv = new DSAKeyValue(dsa, - this._baseURI); + Element dsa = XMLUtils.selectDsNode + (this._constructionElement.getFirstChild(), + Constants._TAG_DSAKEYVALUE,0); + if (dsa != null) { + DSAKeyValue kv = new DSAKeyValue(dsa, this._baseURI); return kv.getPublicKey(); - } - + } - return null; - } + return null; + } - /** @inheritDoc */ - public String getBaseLocalName() { - return Constants._TAG_KEYVALUE; - } + /** @inheritDoc */ + public String getBaseLocalName() { + return Constants._TAG_KEYVALUE; + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/MgmtData.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/MgmtData.java index 52662d9129b65387e3fc839585464be240c9ca93..185e3557170973109d4fa2629b354f523c530866 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/MgmtData.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/MgmtData.java @@ -20,25 +20,18 @@ */ package com.sun.org.apache.xml.internal.security.keys.content; - - import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.utils.Constants; import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class MgmtData extends SignatureElementProxy implements KeyInfoContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(MgmtData.class.getName()); - /** * Constructor MgmtData * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/PGPData.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/PGPData.java index 7829c36527f14e55be2834b213639ee7c115fc47..010c907a8d9bb4e37e9968f5b297482a873c4f1a 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/PGPData.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/PGPData.java @@ -20,25 +20,18 @@ */ package com.sun.org.apache.xml.internal.security.keys.content; - - import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.utils.Constants; import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ * $todo$ Implement */ public class PGPData extends SignatureElementProxy implements KeyInfoContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(PGPData.class.getName()); - /** * Constructor PGPData * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/RetrievalMethod.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/RetrievalMethod.java index feb8b26d3b587924f010567a29ee398e89bef2bf..3c4956b7787c3a86e1882b3d5a4a4032800a5175 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/RetrievalMethod.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/RetrievalMethod.java @@ -20,9 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.content; - - - import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; import com.sun.org.apache.xml.internal.security.transforms.Transforms; @@ -33,17 +30,13 @@ import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class RetrievalMethod extends SignatureElementProxy implements KeyInfoContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(RetrievalMethod.class.getName()); //J- /** DSA retrieval */ public static final String TYPE_DSA = Constants.SignatureSpecNS + "DSAKeyValue"; @@ -133,7 +126,7 @@ public class RetrievalMethod extends SignatureElementProxy try { Element transformsElem = - XMLUtils.selectDsNode(this._constructionElement, + XMLUtils.selectDsNode(this._constructionElement.getFirstChild(), Constants ._TAG_TRANSFORMS, 0); diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/SPKIData.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/SPKIData.java index 64bb23c62310aa1ceb27370cab985a3a9a78a760..95cef8d5491d88b7bc27619c4e845845e675f4de 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/SPKIData.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/SPKIData.java @@ -20,25 +20,18 @@ */ package com.sun.org.apache.xml.internal.security.keys.content; - - import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.utils.Constants; import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ * $todo$ implement */ public class SPKIData extends SignatureElementProxy implements KeyInfoContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(SPKIData.class.getName()); - /** * Constructor SPKIData * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/X509Data.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/X509Data.java index d60f3ad6518751a19bbaa7f7b39400db793aef5b..199b1dcb020dd507faf245a0c41ab085329bff92 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/X509Data.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/X509Data.java @@ -41,7 +41,7 @@ import org.w3c.dom.Node; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class X509Data extends SignatureElementProxy implements KeyInfoContent { @@ -72,60 +72,17 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { throws XMLSecurityException { super(element, BaseURI); - - boolean noElements=true; Node sibling=this._constructionElement.getFirstChild(); while (sibling!=null) { if (sibling.getNodeType()!=Node.ELEMENT_NODE) { sibling=sibling.getNextSibling(); continue; } - noElements=false; - Element currentElem = (Element) sibling; - sibling=sibling.getNextSibling(); - String localname = currentElem.getLocalName(); - - if (currentElem.getNamespaceURI().equals(Constants.SignatureSpecNS)) { - if (localname.equals(Constants._TAG_X509ISSUERSERIAL)) { - XMLX509IssuerSerial is = new XMLX509IssuerSerial(currentElem, - BaseURI); - - this.add(is); - } else if (localname.equals(Constants._TAG_X509SKI)) { - XMLX509SKI ski = new XMLX509SKI(currentElem, BaseURI); - - this.add(ski); - } else if (localname.equals(Constants._TAG_X509SUBJECTNAME)) { - XMLX509SubjectName sn = new XMLX509SubjectName(currentElem, - BaseURI); - - this.add(sn); - } else if (localname.equals(Constants._TAG_X509CERTIFICATE)) { - XMLX509Certificate cert = new XMLX509Certificate(currentElem, - BaseURI); - - this.add(cert); - } else if (localname.equals(Constants._TAG_X509CRL)) { - XMLX509CRL crl = new XMLX509CRL(currentElem, BaseURI); - - this.add(crl); - } else { - log.log(java.util.logging.Level.WARNING, "Found a " + currentElem.getTagName() + " element in " - + Constants._TAG_X509DATA); - this.addUnknownElement(currentElem); - } - } else { - log.log(java.util.logging.Level.WARNING, "Found a " + currentElem.getTagName() + " element in " - + Constants._TAG_X509DATA); - this.addUnknownElement(currentElem); - } + return; } - if (noElements) { - Object exArgs[] = { "Elements", Constants._TAG_X509DATA }; - - throw new XMLSecurityException("xml.WrongContent", exArgs); - } - + /* No Elements found */ + Object exArgs[] = { "Elements", Constants._TAG_X509DATA }; + throw new XMLSecurityException("xml.WrongContent", exArgs); } /** @@ -169,11 +126,9 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { */ public void add(XMLX509IssuerSerial xmlX509IssuerSerial) { - if (this._state == MODE_SIGN) { this._constructionElement .appendChild(xmlX509IssuerSerial.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -202,11 +157,8 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { * @param xmlX509SKI */ public void add(XMLX509SKI xmlX509SKI) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(xmlX509SKI.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -233,11 +185,8 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { * @param xmlX509SubjectName */ public void add(XMLX509SubjectName xmlX509SubjectName) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(xmlX509SubjectName.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -266,11 +215,8 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { * @param xmlX509Certificate */ public void add(XMLX509Certificate xmlX509Certificate) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(xmlX509Certificate.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -288,11 +234,8 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { * @param xmlX509CRL */ public void add(XMLX509CRL xmlX509CRL) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(xmlX509CRL.getElement()); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -301,11 +244,8 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { * @param element */ public void addUnknownElement(Element element) { - - if (this._state == MODE_SIGN) { this._constructionElement.appendChild(element); XMLUtils.addReturnToElement(this._constructionElement); - } } /** @@ -479,7 +419,7 @@ public class X509Data extends SignatureElementProxy implements KeyInfoContent { * TODO implement **/ public Element itemUnknownElement(int i) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "itemUnknownElement not implemented:"+i); + log.log(java.util.logging.Level.FINE, "itemUnknownElement not implemented:"+i); return null; } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/DSAKeyValue.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/DSAKeyValue.java index 19fb7758f6299e7611970611184d9997805a935a..ef735c3dad6eb6c3398393b3b46bfec02f2eaf39 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/DSAKeyValue.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/DSAKeyValue.java @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.content.keyvalues; - - import java.math.BigInteger; import java.security.Key; import java.security.KeyFactory; @@ -39,18 +37,13 @@ import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class DSAKeyValue extends SignatureElementProxy implements KeyValueContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(DSAKeyValue.class.getName()); - /** * Constructor DSAKeyValue * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/KeyValueContent.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/KeyValueContent.java index 608758e16ce8c958b6ca2d886bb76b0410ffe8be..31e761443c57008433c6b28557a8219930d9605c 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/KeyValueContent.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/KeyValueContent.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -32,7 +31,7 @@ import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; * * * - * @author $Author: raul $ + * @author $Author: mullan $ * */ public interface KeyValueContent { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/RSAKeyValue.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/RSAKeyValue.java index 6fc33aded203f25c290fc92041818dfc0642f2b7..71b23cda593a477f71890181c886a7e437a028aa 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/RSAKeyValue.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/keyvalues/RSAKeyValue.java @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.content.keyvalues; - - import java.math.BigInteger; import java.security.Key; import java.security.KeyFactory; @@ -39,19 +37,13 @@ import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class RSAKeyValue extends SignatureElementProxy implements KeyValueContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger( - RSAKeyValue.class.getName()); - /** * Constructor RSAKeyValue * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509CRL.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509CRL.java index 7c9f5be1f69a2b7550e110cadb59d058e026c1db..b68c444dc08c15daabce2c5a8259da80f5b067e1 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509CRL.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509CRL.java @@ -20,30 +20,20 @@ */ package com.sun.org.apache.xml.internal.security.keys.content.x509; - - import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.utils.Constants; import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * - * - * - * @author $Author: raul $ + * @author $Author: mullan $ * */ public class XMLX509CRL extends SignatureElementProxy implements XMLX509DataContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(XMLX509CRL.class.getName()); - /** * Constructor XMLX509CRL * diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509Certificate.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509Certificate.java index 51f81e529015f5e7855502cce097970d067c36a7..630d9ccc279f3849c12d4e236c9d9fc7d0c69068 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509Certificate.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509Certificate.java @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.content.x509; - - import java.io.ByteArrayInputStream; import java.security.PublicKey; import java.security.cert.CertificateException; @@ -34,18 +32,13 @@ import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class XMLX509Certificate extends SignatureElementProxy implements XMLX509DataContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(XMLX509Certificate.class.getName()); - /** Field JCA_CERT_ID */ public static final String JCA_CERT_ID = "X.509"; @@ -146,23 +139,25 @@ public class XMLX509Certificate extends SignatureElementProxy return null; } - /** @inheritDoc */ - public boolean equals(Object obj) { + /** @inheritDoc */ + public boolean equals(Object obj) { - try { - if (!obj.getClass().getName().equals(this.getClass().getName())) { + if (obj == null) { return false; - } - - XMLX509Certificate other = (XMLX509Certificate) obj; - - /** $todo$ or should be create X509Certificates and use the equals() from the Certs */ - return java.security.MessageDigest.isEqual(other.getCertificateBytes(), - this.getCertificateBytes()); - } catch (XMLSecurityException ex) { - return false; - } - } + } + if (!this.getClass().getName().equals(obj.getClass().getName())) { + return false; + } + XMLX509Certificate other = (XMLX509Certificate) obj; + try { + + /** $todo$ or should be create X509Certificates and use the equals() from the Certs */ + return java.security.MessageDigest.isEqual + (other.getCertificateBytes(), this.getCertificateBytes()); + } catch (XMLSecurityException ex) { + return false; + } + } /** @inheritDoc */ public String getBaseLocalName() { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509DataContent.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509DataContent.java index adbf4978fec7b364de896f7a73993509fb996ff5..02bf9f82d3962210b4e85c15a69ac3b6806c2e7d 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509DataContent.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509DataContent.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -28,7 +27,7 @@ package com.sun.org.apache.xml.internal.security.keys.content.x509; /** * Just used for tagging contents that are allowed inside a ds:X509Data Element. * - * @author $Author: blautenb $ + * @author $Author: mullan $ */ public interface XMLX509DataContent { } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509IssuerSerial.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509IssuerSerial.java index d0701592d5464a53cb5c4dabeadc3421eca93f33..1d16b2b622f5a4e12376923221e8ae996446c0f2 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509IssuerSerial.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509IssuerSerial.java @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.content.x509; - - import java.math.BigInteger; import java.security.cert.X509Certificate; @@ -33,148 +31,139 @@ import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; - /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class XMLX509IssuerSerial extends SignatureElementProxy implements XMLX509DataContent { - /** {@link java.util.logging} logging facility */ + /** {@link java.util.logging} logging facility */ static java.util.logging.Logger log = java.util.logging.Logger.getLogger( XMLX509IssuerSerial.class.getName()); - /** - * Constructor XMLX509IssuerSerial - * - * @param element - * @param BaseURI - * @throws XMLSecurityException - */ - public XMLX509IssuerSerial(Element element, String BaseURI) + /** + * Constructor XMLX509IssuerSerial + * + * @param element + * @param baseURI + * @throws XMLSecurityException + */ + public XMLX509IssuerSerial(Element element, String baseURI) throws XMLSecurityException { - super(element, BaseURI); - } - - /** - * Constructor XMLX509IssuerSerial - * - * @param doc - * @param X509IssuerName - * @param X509SerialNumber - */ - public XMLX509IssuerSerial(Document doc, String X509IssuerName, - BigInteger X509SerialNumber) { - - super(doc); - - XMLUtils.addReturnToElement(this._constructionElement); - this.addTextElement(X509IssuerName, Constants._TAG_X509ISSUERNAME); - XMLUtils.addReturnToElement(this._constructionElement); - this.addTextElement(X509SerialNumber.toString(), Constants._TAG_X509SERIALNUMBER); - } - - /** - * Constructor XMLX509IssuerSerial - * - * @param doc - * @param X509IssuerName - * @param X509SerialNumber - */ - public XMLX509IssuerSerial(Document doc, String X509IssuerName, - String X509SerialNumber) { - this(doc, X509IssuerName, new BigInteger(X509SerialNumber)); - } - - /** - * Constructor XMLX509IssuerSerial - * - * @param doc - * @param X509IssuerName - * @param X509SerialNumber - */ - public XMLX509IssuerSerial(Document doc, String X509IssuerName, - int X509SerialNumber) { - this(doc, X509IssuerName, - new BigInteger(Integer.toString(X509SerialNumber))); - } - - /** - * Constructor XMLX509IssuerSerial - * - * @param doc - * @param x509certificate - */ - public XMLX509IssuerSerial(Document doc, X509Certificate x509certificate) { - - this(doc, - RFC2253Parser.normalize(x509certificate.getIssuerDN().getName()), - x509certificate.getSerialNumber()); - } - - /** - * Method getSerialNumber - * - * - * @return the serial number - */ - public BigInteger getSerialNumber() { - - String text = - this.getTextFromChildElement(Constants._TAG_X509SERIALNUMBER, - Constants.SignatureSpecNS); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "In dem X509SerialNumber wurde gefunden: " + text); - - return new BigInteger(text); - } - - /** - * Method getSerialNumberInteger - * - * - * @return the serial number as plain int - */ - public int getSerialNumberInteger() { - return this.getSerialNumber().intValue(); - } - - /** - * Method getIssuerName - * - * - * @return the issuer name - */ - public String getIssuerName() { - - return RFC2253Parser - .normalize(this - .getTextFromChildElement(Constants._TAG_X509ISSUERNAME, - Constants.SignatureSpecNS)); - } - - /** @inheritDoc */ - public boolean equals(Object obj) { - - if (!obj.getClass().getName().equals(this.getClass().getName())) { - return false; - } - - XMLX509IssuerSerial other = (XMLX509IssuerSerial) obj; - - - if (other.getSerialNumber().equals(this.getSerialNumber()) - && other.getIssuerName().equals(this.getIssuerName())) { - return true; - } - - return false; - } - - /** @inheritDoc */ - public String getBaseLocalName() { - return Constants._TAG_X509ISSUERSERIAL; - } + super(element, baseURI); + } + + /** + * Constructor XMLX509IssuerSerial + * + * @param doc + * @param x509IssuerName + * @param x509SerialNumber + */ + public XMLX509IssuerSerial(Document doc, String x509IssuerName, + BigInteger x509SerialNumber) { + + super(doc); + XMLUtils.addReturnToElement(this._constructionElement); + addTextElement(x509IssuerName, Constants._TAG_X509ISSUERNAME); + addTextElement(x509SerialNumber.toString(), Constants._TAG_X509SERIALNUMBER); + } + + /** + * Constructor XMLX509IssuerSerial + * + * @param doc + * @param x509IssuerName + * @param x509SerialNumber + */ + public XMLX509IssuerSerial(Document doc, String x509IssuerName, + String x509SerialNumber) { + this(doc, x509IssuerName, new BigInteger(x509SerialNumber)); + } + + /** + * Constructor XMLX509IssuerSerial + * + * @param doc + * @param x509IssuerName + * @param x509SerialNumber + */ + public XMLX509IssuerSerial(Document doc, String x509IssuerName, + int x509SerialNumber) { + this(doc, x509IssuerName, + new BigInteger(Integer.toString(x509SerialNumber))); + } + + /** + * Constructor XMLX509IssuerSerial + * + * @param doc + * @param x509certificate + */ + public XMLX509IssuerSerial(Document doc, X509Certificate x509certificate) { + + this(doc, + RFC2253Parser.normalize(x509certificate.getIssuerDN().getName()), + x509certificate.getSerialNumber()); + } + + /** + * Method getSerialNumber + * + * @return the serial number + */ + public BigInteger getSerialNumber() { + + String text = this.getTextFromChildElement + (Constants._TAG_X509SERIALNUMBER, Constants.SignatureSpecNS); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "X509SerialNumber text: " + text); + + return new BigInteger(text); + } + + /** + * Method getSerialNumberInteger + * + * @return the serial number as plain int + */ + public int getSerialNumberInteger() { + return this.getSerialNumber().intValue(); + } + + /** + * Method getIssuerName + * + * @return the issuer name + */ + public String getIssuerName() { + + return RFC2253Parser + .normalize(this + .getTextFromChildElement(Constants._TAG_X509ISSUERNAME, + Constants.SignatureSpecNS)); + } + + /** @inheritDoc */ + public boolean equals(Object obj) { + + if (obj == null) { + return false; + } + if (!this.getClass().getName().equals(obj.getClass().getName())) { + return false; + } + + XMLX509IssuerSerial other = (XMLX509IssuerSerial) obj; + + return this.getSerialNumber().equals(other.getSerialNumber()) + && this.getIssuerName().equals(other.getIssuerName()); + } + + /** @inheritDoc */ + public String getBaseLocalName() { + return Constants._TAG_X509ISSUERSERIAL; + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SKI.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SKI.java index fcbb19e245ac88670610010e36d2c480f89c3d66..fbbb17e6a5400278fdf4dd273b6b8964ce5e5e7e 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SKI.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SKI.java @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.content.x509; - - import java.io.IOException; import java.io.ByteArrayInputStream; import java.io.InputStream; @@ -36,192 +34,143 @@ import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; import org.w3c.dom.Document; import org.w3c.dom.Element; -import sun.security.util.DerValue; - - /** * Handles SubjectKeyIdentifier (SKI) for X.509v3. * - * @author $Author: raul $ - * @see Interface X509Extension + * @author $Author: mullan $ + * @see Interface X509Extension */ public class XMLX509SKI extends SignatureElementProxy implements XMLX509DataContent { - /** {@link java.util.logging} logging facility */ + /** {@link java.util.logging} logging facility */ static java.util.logging.Logger log = java.util.logging.Logger.getLogger(XMLX509SKI.class.getName()); - /** - * SubjectKeyIdentifier (id-ce-subjectKeyIdentifier) (2.5.29.14): - * This extension identifies the public key being certified. It enables - * distinct keys used by the same subject to be differentiated - * (e.g., as key updating occurs). - *
- * A key identifer shall be unique with respect to all key identifiers - * for the subject with which it is used. This extension is always non-critical. - */ - public static final String SKI_OID = "2.5.29.14"; - - /** - * Constructor X509SKI - * - * @param doc - * @param skiBytes - */ - public XMLX509SKI(Document doc, byte[] skiBytes) { - - super(doc); - - this.addBase64Text(skiBytes); - } - - /** - * Constructor XMLX509SKI - * - * @param doc - * @param x509certificate - * @throws XMLSecurityException - */ - public XMLX509SKI(Document doc, X509Certificate x509certificate) - throws XMLSecurityException { - - super(doc); - - this.addBase64Text(XMLX509SKI.getSKIBytesFromCert(x509certificate)); - } - - /** - * Constructor XMLX509SKI - * - * @param element - * @param BaseURI - * @throws XMLSecurityException - */ - public XMLX509SKI(Element element, String BaseURI) + /** + * SubjectKeyIdentifier (id-ce-subjectKeyIdentifier) (2.5.29.14): + * This extension identifies the public key being certified. It enables + * distinct keys used by the same subject to be differentiated + * (e.g., as key updating occurs). + *
+ * A key identifer shall be unique with respect to all key identifiers + * for the subject with which it is used. This extension is always non-critical. + */ + public static final String SKI_OID = "2.5.29.14"; + + /** + * Constructor X509SKI + * + * @param doc + * @param skiBytes + */ + public XMLX509SKI(Document doc, byte[] skiBytes) { + super(doc); + this.addBase64Text(skiBytes); + } + + /** + * Constructor XMLX509SKI + * + * @param doc + * @param x509certificate + * @throws XMLSecurityException + */ + public XMLX509SKI(Document doc, X509Certificate x509certificate) throws XMLSecurityException { - super(element, BaseURI); - } - - /** - * Method getSKIBytes - * - * @return the skibytes - * @throws XMLSecurityException - */ - public byte[] getSKIBytes() throws XMLSecurityException { - return this.getBytesFromTextChild(); - } - - /** - * Method getSKIBytesFromCert - * - * @param cert - * @return sky bytes from the given certificate - * - * @throws XMLSecurityException - * @see java.security.cert.X509Extension#getExtensionValue(java.lang.String) - */ - public static byte[] getSKIBytesFromCert(X509Certificate cert) + super(doc); + this.addBase64Text(XMLX509SKI.getSKIBytesFromCert(x509certificate)); + } + + /** + * Constructor XMLX509SKI + * + * @param element + * @param BaseURI + * @throws XMLSecurityException + */ + public XMLX509SKI(Element element, String BaseURI) throws XMLSecurityException { - - try { - - /* - * Gets the DER-encoded OCTET string for the extension value (extnValue) - * identified by the passed-in oid String. The oid string is - * represented by a set of positive whole numbers separated by periods. - */ - byte[] derEncodedValue = cert.getExtensionValue(XMLX509SKI.SKI_OID); - - if (cert.getVersion() < 3) { + super(element, BaseURI); + } + + /** + * Method getSKIBytes + * + * @return the skibytes + * @throws XMLSecurityException + */ + public byte[] getSKIBytes() throws XMLSecurityException { + return this.getBytesFromTextChild(); + } + + /** + * Method getSKIBytesFromCert + * + * @param cert + * @return ski bytes from the given certificate + * + * @throws XMLSecurityException + * @see java.security.cert.X509Extension#getExtensionValue(java.lang.String) + */ + public static byte[] getSKIBytesFromCert(X509Certificate cert) + throws XMLSecurityException { + + if (cert.getVersion() < 3) { Object exArgs[] = { new Integer(cert.getVersion()) }; - throw new XMLSecurityException("certificate.noSki.lowVersion", exArgs); - } - - byte[] extensionValue = null; - - /** - * Use sun.security.util.DerValue if it is present. - */ - try { - DerValue dervalue = new DerValue(derEncodedValue); - if (dervalue == null) { - throw new XMLSecurityException("certificate.noSki.null"); - } - if (dervalue.tag != DerValue.tag_OctetString) { - throw new XMLSecurityException("certificate.noSki.notOctetString"); - } - extensionValue = dervalue.getOctetString(); - } catch (NoClassDefFoundError e) { - } - - /** - * Fall back to org.bouncycastle.asn1.DERInputStream - */ - if (extensionValue == null) { - try { - Class clazz = Class.forName("org.bouncycastle.asn1.DERInputStream"); - if (clazz != null) { - Constructor constructor = clazz.getConstructor(new Class[]{InputStream.class}); - InputStream is = (InputStream) constructor.newInstance(new Object[]{new ByteArrayInputStream(derEncodedValue)}); - Method method = clazz.getMethod("readObject", new Class[]{}); - Object obj = method.invoke(is, new Object[]{}); - if (obj == null) { - throw new XMLSecurityException("certificate.noSki.null"); - } - Class clazz2 = Class.forName("org.bouncycastle.asn1.ASN1OctetString"); - if (!clazz2.isInstance(obj)) { - throw new XMLSecurityException("certificate.noSki.notOctetString"); - } - Method method2 = clazz2.getMethod("getOctets", new Class[]{}); - extensionValue = (byte[]) method2.invoke(obj, new Object[]{}); - } - } catch (Throwable t) { - } - } - - /** - * Strip away first two bytes from the DerValue (tag and length) - */ - byte abyte0[] = new byte[extensionValue.length - 2]; - - System.arraycopy(extensionValue, 2, abyte0, 0, abyte0.length); - - /* - byte abyte0[] = new byte[derEncodedValue.length - 4]; - System.arraycopy(derEncodedValue, 4, abyte0, 0, abyte0.length); + } + + /* + * Gets the DER-encoded OCTET string for the extension value + * (extnValue) identified by the passed-in oid String. The oid + * string is represented by a set of positive whole numbers + * separated by periods. + */ + byte[] extensionValue = cert.getExtensionValue(XMLX509SKI.SKI_OID); + if (extensionValue == null) { + throw new XMLSecurityException("certificate.noSki.null"); + } + + /** + * Strip away first four bytes from the extensionValue + * The first two bytes are the tag and length of the extensionValue + * OCTET STRING, and the next two bytes are the tag and length of + * the skid OCTET STRING. */ - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Base64 of SKI is " + Base64.encode(abyte0)); + byte skidValue[] = new byte[extensionValue.length - 4]; + + System.arraycopy(extensionValue, 4, skidValue, 0, skidValue.length); - return abyte0; - } catch (IOException ex) { - throw new XMLSecurityException("generic.EmptyMessage", ex); - } - } + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "Base64 of SKI is " + Base64.encode(skidValue)); + } - /** @inheritDoc */ - public boolean equals(Object obj) { + return skidValue; + } - if (!obj.getClass().getName().equals(this.getClass().getName())) { - return false; - } + /** @inheritDoc */ + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!this.getClass().getName().equals(obj.getClass().getName())) { + return false; + } - XMLX509SKI other = (XMLX509SKI) obj; + XMLX509SKI other = (XMLX509SKI) obj; - try { - return java.security.MessageDigest.isEqual(other.getSKIBytes(), + try { + return java.security.MessageDigest.isEqual(other.getSKIBytes(), this.getSKIBytes()); - } catch (XMLSecurityException ex) { - return false; - } - } - - /** @inheritDoc */ - public String getBaseLocalName() { - return Constants._TAG_X509SKI; - } + } catch (XMLSecurityException ex) { + return false; + } + } + + /** @inheritDoc */ + public String getBaseLocalName() { + return Constants._TAG_X509SKI; + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SubjectName.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SubjectName.java index 548ec7ba57d1bad16553ffe908677a3e0ffc4603..8d51da2e2fdd29b4a604f9c3bd9a77249a8e5c34 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SubjectName.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/content/x509/XMLX509SubjectName.java @@ -20,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.content.x509; - - import java.security.cert.X509Certificate; import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; @@ -33,15 +31,11 @@ import org.w3c.dom.Element; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class XMLX509SubjectName extends SignatureElementProxy implements XMLX509DataContent { - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(XMLX509SubjectName.class.getName()); - /** * Constructor X509SubjectName * @@ -88,23 +82,21 @@ public class XMLX509SubjectName extends SignatureElementProxy return RFC2253Parser.normalize(this.getTextFromTextChild()); } - /** @inheritDoc */ - public boolean equals(Object obj) { - - if (!obj.getClass().getName().equals(this.getClass().getName())) { - return false; - } - - XMLX509SubjectName other = (XMLX509SubjectName) obj; - String otherSubject = other.getSubjectName(); - String thisSubject = this.getSubjectName(); + /** @inheritDoc */ + public boolean equals(Object obj) { + if (obj == null) { + return false; + } - if (otherSubject.equals(thisSubject)) { - return true; - } + if (!this.getClass().getName().equals(obj.getClass().getName())) { + return false; + } - return false; + XMLX509SubjectName other = (XMLX509SubjectName) obj; + String otherSubject = other.getSubjectName(); + String thisSubject = this.getSubjectName(); + return thisSubject.equals(otherSubject); } /** @inheritDoc */ diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/InvalidKeyResolverException.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/InvalidKeyResolverException.java index 6e3d408d43de05c4011dc37349b59c18b3763302..3b3508005cbdbb23661f0fb7e31c5a6f76be7fc0 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/InvalidKeyResolverException.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/InvalidKeyResolverException.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -29,7 +28,7 @@ import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; /** * * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class InvalidKeyResolverException extends XMLSecurityException { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolver.java index 488a59731c424cc0d37fff21f0f5dfe2c311c136..1da9dbb362f6926468faa00cc42ccc529d7cfa97 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -26,6 +25,7 @@ package com.sun.org.apache.xml.internal.security.keys.keyresolver; import java.security.PublicKey; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import javax.crypto.SecretKey; @@ -39,7 +39,8 @@ import org.w3c.dom.Node; * KeyResolver is factory class for subclass of KeyResolverSpi that * represent child element of KeyInfo. * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version %I%, %G% */ public class KeyResolver { @@ -72,6 +73,7 @@ public class KeyResolver { InstantiationException { this._resolverSpi = (KeyResolverSpi) Class.forName(className).newInstance(); + this._resolverSpi.setGlobalResolver(true); } /** @@ -83,40 +85,82 @@ public class KeyResolver { return KeyResolver._resolverVector.size(); } + public static void hit(Iterator hintI) { + ResolverIterator hint = (ResolverIterator) hintI; + int i = hint.i; + if (i!=1 && hint.res ==_resolverVector) { + List resolverVector=(List)((ArrayList)_resolverVector).clone(); + Object ob=resolverVector.remove(i-1); + resolverVector.add(0,ob); + _resolverVector=resolverVector; + } else { + //System.out.println("KeyResolver hitting"); + } + } + /** - * Method item + * Method getInstance + * + * @param element + * @param BaseURI + * @param storage + * @return The certificate represented by the element. * - * @param i - * @return the number i resolver registerd * @throws KeyResolverException */ - public static KeyResolver item(int i) throws KeyResolverException { + public static final X509Certificate getX509Certificate( + Element element, String BaseURI, StorageResolver storage) + throws KeyResolverException { + + // use the old vector to not be hit by updates + List resolverVector = KeyResolver._resolverVector; + for (int i = 0; i < resolverVector.size(); i++) { + KeyResolver resolver= + (KeyResolver) resolverVector.get(i); - KeyResolver resolver = (KeyResolver) KeyResolver._resolverVector.get(i); - if (resolver==null) { - throw new KeyResolverException("utils.resolver.noClass"); + if (resolver==null) { + Object exArgs[] = { + (((element != null) + && (element.getNodeType() == Node.ELEMENT_NODE)) + ? element.getTagName() + : "null") }; + + throw new KeyResolverException("utils.resolver.noClass", exArgs); + } + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "check resolvability by class " + resolver.getClass()); + + X509Certificate cert=resolver.resolveX509Certificate(element, BaseURI, storage); + if (cert!=null) { + return cert; + } } - return resolver; - } + Object exArgs[] = { + (((element != null) && (element.getNodeType() == Node.ELEMENT_NODE)) + ? element.getTagName() + : "null") }; + throw new KeyResolverException("utils.resolver.noClass", exArgs); + } /** * Method getInstance * * @param element * @param BaseURI * @param storage - * @return the instance that happends to implement the thing. + * @return the public key contained in the element * * @throws KeyResolverException */ - public static final KeyResolver getInstance( + public static final PublicKey getPublicKey( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - for (int i = 0; i < KeyResolver._resolverVector.size(); i++) { + List resolverVector = KeyResolver._resolverVector; + for (int i = 0; i < resolverVector.size(); i++) { KeyResolver resolver= - (KeyResolver) KeyResolver._resolverVector.get(i); + (KeyResolver) resolverVector.get(i); if (resolver==null) { Object exArgs[] = { @@ -127,11 +171,19 @@ public class KeyResolver { throw new KeyResolverException("utils.resolver.noClass", exArgs); } - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "check resolvability by class " + resolver.getClass()); - - if (resolver.canResolve(element, BaseURI, storage)) { - return resolver; + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "check resolvability by class " + resolver.getClass()); + + PublicKey cert=resolver.resolvePublicKey(element, BaseURI, storage); + if (cert!=null) { + if (i!=0 && resolverVector==_resolverVector) { + //update resolver. + resolverVector=(List)((ArrayList)_resolverVector).clone(); + Object ob=resolverVector.remove(i); + resolverVector.add(0,ob); + _resolverVector=resolverVector; + } + return cert; } } @@ -182,34 +234,6 @@ public class KeyResolver { KeyResolver._resolverVector.add(0, className); } - /* - * Method resolve - * - * @param element - * - * @throws KeyResolverException - */ - - /** - * Method resolveStatic - * - * @param element - * @param BaseURI - * @param storage - * @return resolve from the static register an element - * - * @throws KeyResolverException - */ - public static PublicKey resolveStatic( - Element element, String BaseURI, StorageResolver storage) - throws KeyResolverException { - - KeyResolver myResolver = KeyResolver.getInstance(element, BaseURI, - storage); - - return myResolver.resolvePublicKey(element, BaseURI, storage); - } - /** * Method resolve * @@ -223,7 +247,7 @@ public class KeyResolver { public PublicKey resolvePublicKey( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - return this._resolverSpi.engineResolvePublicKey(element, BaseURI, storage); + return this._resolverSpi.engineLookupAndResolvePublicKey(element, BaseURI, storage); } /** @@ -239,7 +263,7 @@ public class KeyResolver { public X509Certificate resolveX509Certificate( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - return this._resolverSpi.engineResolveX509Certificate(element, BaseURI, + return this._resolverSpi.engineLookupResolveX509Certificate(element, BaseURI, storage); } @@ -253,7 +277,7 @@ public class KeyResolver { public SecretKey resolveSecretKey( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - return this._resolverSpi.engineResolveSecretKey(element, BaseURI, + return this._resolverSpi.engineLookupAndResolveSecretKey(element, BaseURI, storage); } @@ -277,14 +301,6 @@ public class KeyResolver { return this._resolverSpi.engineGetProperty(key); } - /** - * Method getPropertyKeys - * - * @return the properties key registerd in this resolver - */ - public String[] getPropertyKeys() { - return this._resolverSpi.engineGetPropertyKeys(); - } /** * Method understandsProperty @@ -296,18 +312,6 @@ public class KeyResolver { return this._resolverSpi.understandsProperty(propertyToTest); } - /** - * Method canResolve - * - * @param element - * @param BaseURI - * @param storage - * @return true if can resolve the key in the element - */ - public boolean canResolve(Element element, String BaseURI, - StorageResolver storage) { - return this._resolverSpi.engineCanResolve(element, BaseURI, storage); - } /** * Method resolverClassName @@ -317,4 +321,37 @@ public class KeyResolver { public String resolverClassName() { return this._resolverSpi.getClass().getName(); } + + static class ResolverIterator implements Iterator { + List res; + Iterator it; + int i; + public ResolverIterator(List list) { + res = list; + it = res.iterator(); + } + public boolean hasNext() { + // TODO Auto-generated method stub + return it.hasNext(); + } + + public Object next() { + i++; + KeyResolver resolver = (KeyResolver) it.next(); + if (resolver==null) { + throw new RuntimeException("utils.resolver.noClass"); + } + + return resolver._resolverSpi; + } + + public void remove() { + // TODO Auto-generated method stub + + } + + }; + public static Iterator iterator() { + return new ResolverIterator(_resolverVector); + } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverException.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverException.java index 4248c8dfa6b280119a59b98acd6ac82c7261cf78..f0069949b2f804ec02fe458b4179c80ca023a059 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverException.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverException.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -31,7 +30,7 @@ import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; * * * - * @author $Author: raul $ + * @author $Author: mullan $ * */ public class KeyResolverException extends XMLSecurityException { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverSpi.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverSpi.java index a6b99825ebc5294f67fe34e55e7c8fac7d7f1bad..dc2865bcfc4d67632320bda1a65d2b22e05e18a4 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverSpi.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverSpi.java @@ -20,17 +20,15 @@ */ package com.sun.org.apache.xml.internal.security.keys.keyresolver; - - import java.security.PublicKey; import java.security.cert.X509Certificate; +import java.util.HashMap; import javax.crypto.SecretKey; import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver; import org.w3c.dom.Element; - /** * This class is abstract class for a child KeyInfo Elemnet. * @@ -41,14 +39,10 @@ import org.w3c.dom.Element; * JAVACLASS="MyPackage.MyKeyValueImpl"//gt; * * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ public abstract class KeyResolverSpi { - - /** {@link java.util.logging} logging facility */ - static java.util.logging.Logger log = - java.util.logging.Logger.getLogger(KeyResolverSpi.class.getName()); - /** * This method helps the {@link com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver} to decide whether a * {@link com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverSpi} is able to perform the requested action. @@ -56,10 +50,12 @@ public abstract class KeyResolverSpi { * @param element * @param BaseURI * @param storage - * @return true if can resolve the key in the element + * @return */ - abstract public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage); + public boolean engineCanResolve(Element element, String BaseURI, + StorageResolver storage) { + throw new UnsupportedOperationException(); + } /** * Method engineResolvePublicKey @@ -71,9 +67,60 @@ public abstract class KeyResolverSpi { * * @throws KeyResolverException */ - abstract public PublicKey engineResolvePublicKey( + public PublicKey engineResolvePublicKey( Element element, String BaseURI, StorageResolver storage) - throws KeyResolverException; + throws KeyResolverException { + throw new UnsupportedOperationException(); + }; + + /** + * Method engineResolvePublicKey + * + * @param element + * @param BaseURI + * @param storage + * @return resolved public key from the registered from the element. + * + * @throws KeyResolverException + */ + public PublicKey engineLookupAndResolvePublicKey( + Element element, String BaseURI, StorageResolver storage) + throws KeyResolverException { + KeyResolverSpi tmp = cloneIfNeeded(); + if (!tmp.engineCanResolve(element, BaseURI, storage)) + return null; + return tmp.engineResolvePublicKey(element, BaseURI, storage); + } + + private KeyResolverSpi cloneIfNeeded() throws KeyResolverException { + KeyResolverSpi tmp=this; + if (globalResolver) { + try { + tmp = (KeyResolverSpi) getClass().newInstance(); + } catch (InstantiationException e) { + throw new KeyResolverException("",e); + } catch (IllegalAccessException e) { + throw new KeyResolverException("",e); + } + } + return tmp; + } + + /** + * Method engineResolveCertificate + * + * @param element + * @param BaseURI + * @param storage + * @return resolved X509Certificate key from the registered from the elements + * + * @throws KeyResolverException + */ + public X509Certificate engineResolveX509Certificate( + Element element, String BaseURI, StorageResolver storage) + throws KeyResolverException{ + throw new UnsupportedOperationException(); + }; /** * Method engineResolveCertificate @@ -85,9 +132,30 @@ public abstract class KeyResolverSpi { * * @throws KeyResolverException */ - abstract public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) - throws KeyResolverException; + throws KeyResolverException { + KeyResolverSpi tmp = cloneIfNeeded(); + if (!tmp.engineCanResolve(element, BaseURI, storage)) + return null; + return tmp.engineResolveX509Certificate(element, BaseURI, storage); + + } + /** + * Method engineResolveSecretKey + * + * @param element + * @param BaseURI + * @param storage + * @return resolved SecretKey key from the registered from the elements + * + * @throws KeyResolverException + */ + public SecretKey engineResolveSecretKey( + Element element, String BaseURI, StorageResolver storage) + throws KeyResolverException{ + throw new UnsupportedOperationException(); + }; /** * Method engineResolveSecretKey @@ -99,12 +167,19 @@ public abstract class KeyResolverSpi { * * @throws KeyResolverException */ - abstract public SecretKey engineResolveSecretKey( + public SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage) - throws KeyResolverException; + throws KeyResolverException { + KeyResolverSpi tmp = cloneIfNeeded(); + if (!tmp.engineCanResolve(element, BaseURI, storage)) + return null; + return tmp.engineResolveSecretKey(element, BaseURI, storage); + } /** Field _properties */ - protected java.util.Map _properties = new java.util.HashMap(10); + protected java.util.Map _properties = null; + + protected boolean globalResolver=false; /** * Method engineSetProperty @@ -113,19 +188,8 @@ public abstract class KeyResolverSpi { * @param value */ public void engineSetProperty(String key, String value) { - - java.util.Iterator i = this._properties.keySet().iterator(); - - while (i.hasNext()) { - String c = (String) i.next(); - - if (c.equals(key)) { - key = c; - - break; - } - } - + if (_properties==null) + _properties=new HashMap(); this._properties.put(key, value); } @@ -136,31 +200,12 @@ public abstract class KeyResolverSpi { * @return obtain the property appointed by key */ public String engineGetProperty(String key) { - - java.util.Iterator i = this._properties.keySet().iterator(); - - while (i.hasNext()) { - String c = (String) i.next(); - - if (c.equals(key)) { - key = c; - - break; - } - } + if (_properties==null) + return null; return (String) this._properties.get(key); } - /** - * Method engineGetPropertyKeys - * - * @return the keys of properties known by this resolver - */ - public String[] engineGetPropertyKeys() { - return new String[0]; - } - /** * Method understandsProperty * @@ -168,17 +213,13 @@ public abstract class KeyResolverSpi { * @return true if understood the property */ public boolean understandsProperty(String propertyToTest) { + if (_properties==null) + return false; - String[] understood = this.engineGetPropertyKeys(); - - if (understood != null) { - for (int i = 0; i < understood.length; i++) { - if (understood[i].equals(propertyToTest)) { - return true; - } - } - } - - return false; + return this._properties.get(propertyToTest)!=null; } + public void setGlobalResolver(boolean globalResolver) { + this.globalResolver = globalResolver; + } + } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/DSAKeyValueResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/DSAKeyValueResolver.java index efda14c1a4a0066417e062dae7100c9e908f5539..20bf7bad777fa08e94f5f79fddb9fcd45646a18e 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/DSAKeyValueResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/DSAKeyValueResolver.java @@ -37,46 +37,10 @@ import org.w3c.dom.Element; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class DSAKeyValueResolver extends KeyResolverSpi { - /** Field _dsaKeyElement */ - private Element _dsaKeyElement = null; - - /** @inheritDoc */ - public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage) { - - if (element == null) { - return false; - } - - boolean isKeyValue = XMLUtils.elementIsInSignatureSpace(element, - Constants._TAG_KEYVALUE); - boolean isDSAKeyValue = XMLUtils.elementIsInSignatureSpace(element, - Constants._TAG_DSAKEYVALUE); - - if (isKeyValue) { - - this._dsaKeyElement = - XMLUtils.selectDsNode(element.getFirstChild(),Constants._TAG_DSAKEYVALUE,0); - - if (this._dsaKeyElement != null) { - return true; - } - } else if (isDSAKeyValue) { - - // this trick is needed to allow the RetrievalMethodResolver to eat a - // ds:DSAKeyValue directly (without KeyValue) - this._dsaKeyElement = element; - - return true; - } - - return false; - } - /** * Method engineResolvePublicKey * @@ -85,20 +49,30 @@ public class DSAKeyValueResolver extends KeyResolverSpi { * @param storage * @return null if no {@link PublicKey} could be obtained */ - public PublicKey engineResolvePublicKey( + public PublicKey engineLookupAndResolvePublicKey( Element element, String BaseURI, StorageResolver storage) { + if (element == null) { + return null; + } + Element dsaKeyElement=null; + boolean isKeyValue = XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_KEYVALUE); + if (isKeyValue) { + dsaKeyElement = + XMLUtils.selectDsNode(element.getFirstChild(),Constants._TAG_DSAKEYVALUE,0); + } else if (XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_DSAKEYVALUE)) { + // this trick is needed to allow the RetrievalMethodResolver to eat a + // ds:DSAKeyValue directly (without KeyValue) + dsaKeyElement = element; + } - if (this._dsaKeyElement == null) { - boolean weCanResolve = this.engineCanResolve(element, BaseURI, - storage); - - if (!weCanResolve || (this._dsaKeyElement == null)) { - return null; - } + if (dsaKeyElement == null) { + return null; } try { - DSAKeyValue dsaKeyValue = new DSAKeyValue(this._dsaKeyElement, + DSAKeyValue dsaKeyValue = new DSAKeyValue(dsaKeyElement, BaseURI); PublicKey pk = dsaKeyValue.getPublicKey(); @@ -112,13 +86,13 @@ public class DSAKeyValueResolver extends KeyResolverSpi { /** @inheritDoc */ - public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) { return null; } /** @inheritDoc */ - public javax.crypto.SecretKey engineResolveSecretKey( + public javax.crypto.SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage){ return null; } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/EncryptedKeyResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/EncryptedKeyResolver.java index 4b44f1c50d15434bf71c3bf98cf349f4921422bd..6adc050e8935b37d90faa61fe67d373d72353a33 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/EncryptedKeyResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/EncryptedKeyResolver.java @@ -56,7 +56,6 @@ public class EncryptedKeyResolver extends KeyResolverSpi { RSAKeyValueResolver.class.getName()); - Key _key; Key _kek; String _algorithm; @@ -66,7 +65,6 @@ public class EncryptedKeyResolver extends KeyResolverSpi { * @param algorithm */ public EncryptedKeyResolver(String algorithm) { - _key = null; _kek = null; _algorithm=algorithm; } @@ -78,64 +76,49 @@ public class EncryptedKeyResolver extends KeyResolverSpi { */ public EncryptedKeyResolver(String algorithm, Key kek) { - _key = null; _algorithm = algorithm; _kek = kek; } - /** - * Method engineCanResolve - * - * @param element - * @param BaseURI - * @param storage - * @return true if can resolve the key in the element - * - */ - - public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "EncryptedKeyResolver - Can I resolve " + element.getTagName()); - - if (element == null) { - return false; - } - - boolean isEncryptedKey = XMLUtils.elementIsInEncryptionSpace(element, - EncryptionConstants._TAG_ENCRYPTEDKEY); - - if (isEncryptedKey) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Passed an Encrypted Key"); - try { - XMLCipher cipher = XMLCipher.getInstance(); - cipher.init(XMLCipher.UNWRAP_MODE, _kek); - EncryptedKey ek = cipher.loadEncryptedKey(element); - _key = cipher.decryptKey(ek, _algorithm); - } - catch (Exception e) {} - } - - return (_key != null); - } - /** @inheritDoc */ - public PublicKey engineResolvePublicKey( + public PublicKey engineLookupAndResolvePublicKey( Element element, String BaseURI, StorageResolver storage) { return null; } /** @inheritDoc */ - public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) { return null; } /** @inheritDoc */ - public javax.crypto.SecretKey engineResolveSecretKey( + public javax.crypto.SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage) { - return (SecretKey) _key; + SecretKey key=null; + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "EncryptedKeyResolver - Can I resolve " + element.getTagName()); + + if (element == null) { + return null; + } + + boolean isEncryptedKey = XMLUtils.elementIsInEncryptionSpace(element, + EncryptionConstants._TAG_ENCRYPTEDKEY); + + if (isEncryptedKey) { + log.log(java.util.logging.Level.FINE, "Passed an Encrypted Key"); + try { + XMLCipher cipher = XMLCipher.getInstance(); + cipher.init(XMLCipher.UNWRAP_MODE, _kek); + EncryptedKey ek = cipher.loadEncryptedKey(element); + key = (SecretKey) cipher.decryptKey(ek, _algorithm); + } + catch (Exception e) {} + } + + return key; } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RSAKeyValueResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RSAKeyValueResolver.java index 541de7307f458702c775dffb48f4e5e648db3fc6..fb38e8725908901a545533d178af3b79ad3ca120 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RSAKeyValueResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RSAKeyValueResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -38,7 +37,7 @@ import org.w3c.dom.Element; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class RSAKeyValueResolver extends KeyResolverSpi { @@ -48,75 +47,55 @@ public class RSAKeyValueResolver extends KeyResolverSpi { RSAKeyValueResolver.class.getName()); /** Field _rsaKeyElement */ - private Element _rsaKeyElement = null; - /** @inheritDoc */ - public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName()); + /** @inheritDoc */ + public PublicKey engineLookupAndResolvePublicKey( + Element element, String BaseURI, StorageResolver storage) { + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName()); if (element == null) { - return false; + return null; } - boolean isKeyValue = XMLUtils.elementIsInSignatureSpace(element, - Constants._TAG_KEYVALUE); - boolean isRSAKeyValue = XMLUtils.elementIsInSignatureSpace(element, - Constants._TAG_RSAKEYVALUE); - - if (isKeyValue) { - this._rsaKeyElement = XMLUtils.selectDsNode(element.getFirstChild(), - Constants._TAG_RSAKEYVALUE, 0); - - if (this._rsaKeyElement != null) { - return true; - } - } else if (isRSAKeyValue) { - + boolean isKeyValue = XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_KEYVALUE); + Element rsaKeyElement=null; + if (isKeyValue) { + rsaKeyElement = XMLUtils.selectDsNode(element.getFirstChild(), + Constants._TAG_RSAKEYVALUE, 0); + } else if (XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_RSAKEYVALUE)) { // this trick is needed to allow the RetrievalMethodResolver to eat a // ds:RSAKeyValue directly (without KeyValue) - this._rsaKeyElement = element; - - return true; - } - - return false; - } - - /** @inheritDoc */ - public PublicKey engineResolvePublicKey( - Element element, String BaseURI, StorageResolver storage) { + rsaKeyElement = element; + } - if (this._rsaKeyElement == null) { - boolean weCanResolve = this.engineCanResolve(element, BaseURI, - storage); - if (!weCanResolve || (this._rsaKeyElement == null)) { - return null; - } + if (rsaKeyElement == null) { + return null; } try { - RSAKeyValue rsaKeyValue = new RSAKeyValue(this._rsaKeyElement, + RSAKeyValue rsaKeyValue = new RSAKeyValue(rsaKeyElement, BaseURI); return rsaKeyValue.getPublicKey(); } catch (XMLSecurityException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); + log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); } return null; } /** @inheritDoc */ - public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) { return null; } /** @inheritDoc */ - public javax.crypto.SecretKey engineResolveSecretKey( + public javax.crypto.SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage) { return null; } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RetrievalMethodResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RetrievalMethodResolver.java index d8d98bdb9e9651f47049990b377e4a6f7267c344..3dff21824457cf144b05888576feecc1ec74bd4b 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RetrievalMethodResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/RetrievalMethodResolver.java @@ -28,7 +28,15 @@ import java.security.PublicKey; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; +import javax.xml.parsers.ParserConfigurationException; + +import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; import com.sun.org.apache.xml.internal.security.keys.content.RetrievalMethod; import com.sun.org.apache.xml.internal.security.keys.content.x509.XMLX509Certificate; @@ -44,6 +52,7 @@ import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.Node; +import org.xml.sax.SAXException; /** @@ -55,7 +64,7 @@ import org.w3c.dom.Node; * RetrievalMethodResolver cannot handle itself, resolving of the extracted * element is delegated back to the KeyResolver mechanism. * - * @author $Author: raul $ + * @author $Author: mullan $ modified by Dave Garcia */ public class RetrievalMethodResolver extends KeyResolverSpi { @@ -65,198 +74,170 @@ public class RetrievalMethodResolver extends KeyResolverSpi { RetrievalMethodResolver.class.getName()); /** - * Method engineCanResolve + * Method engineResolvePublicKey * @inheritDoc * @param element * @param BaseURI * @param storage * */ - public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage) { + public PublicKey engineLookupAndResolvePublicKey( + Element element, String BaseURI, StorageResolver storage) + { + if (!XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_RETRIEVALMETHOD)) { + return null; + } - if - (!XMLUtils.elementIsInSignatureSpace(element, - Constants._TAG_RETRIEVALMETHOD)) { - return false; - } + try { + //Create a retrieval method over the given element + RetrievalMethod rm = new RetrievalMethod(element, BaseURI); + String type = rm.getType(); + XMLSignatureInput resource=resolveInput(rm,BaseURI); + if (RetrievalMethod.TYPE_RAWX509.equals(type)) { + //a raw certificate, direct parsing is done! + X509Certificate cert=getRawCertificate(resource); + if (cert != null) { + return cert.getPublicKey(); + } + return null; + }; + Element e = obtainRefrenceElement(resource); + return resolveKey(e,BaseURI,storage); + } catch (XMLSecurityException ex) { + log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); + } catch (CertificateException ex) { + log.log(java.util.logging.Level.FINE, "CertificateException", ex); + } catch (IOException ex) { + log.log(java.util.logging.Level.FINE, "IOException", ex); + } catch (ParserConfigurationException e) { + log.log(java.util.logging.Level.FINE, "ParserConfigurationException", e); + } catch (SAXException e) { + log.log(java.util.logging.Level.FINE, "SAXException", e); + } + return null; + } - return true; + static private Element obtainRefrenceElement(XMLSignatureInput resource) throws CanonicalizationException, ParserConfigurationException, IOException, SAXException, KeyResolverException { + Element e; + if (resource.isElement()){ + e=(Element) resource.getSubNode(); + } else if (resource.isNodeSet()) { + //Retrieved resource is a nodeSet + e=getDocumentElement(resource.getNodeSet()); + } else { + //Retrieved resource is an inputStream + byte inputBytes[] = resource.getBytes(); + e = getDocFromBytes(inputBytes); + //otherwise, we parse the resource, create an Element and delegate + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "we have to parse " + inputBytes.length + " bytes"); + } + return e; } /** - * Method engineResolvePublicKey + * Method engineResolveX509Certificate * @inheritDoc * @param element * @param BaseURI * @param storage * */ - public PublicKey engineResolvePublicKey( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) { + if (!XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_RETRIEVALMETHOD)) { + return null; + } - try { + try { RetrievalMethod rm = new RetrievalMethod(element, BaseURI); - Attr uri = rm.getURIAttr(); - - // type can be null because it's optional - String type = rm.getType(); - Transforms transforms = rm.getTransforms(); - ResourceResolver resRes = ResourceResolver.getInstance(uri, BaseURI); - - if (resRes != null) { - XMLSignatureInput resource = resRes.resolve(uri, BaseURI); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Before applying Transforms, resource has " - + resource.getBytes().length + "bytes"); - - if (transforms != null) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "We have Transforms"); - - resource = transforms.performTransforms(resource); - } - if (true) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "After applying Transforms, resource has " - + resource.getBytes().length + "bytes"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Resolved to resource " + resource.getSourceURI()); - } - - byte inputBytes[] = resource.getBytes(); - - if ((type != null) && type.equals(RetrievalMethod.TYPE_RAWX509)) { - - // if the resource stores a raw certificate, we have to handle it - CertificateFactory certFact = - CertificateFactory - .getInstance(XMLX509Certificate.JCA_CERT_ID); - X509Certificate cert = - (X509Certificate) certFact - .generateCertificate(new ByteArrayInputStream(inputBytes)); - - if (cert != null) { - return cert.getPublicKey(); - } - } else { - - // otherwise, we parse the resource, create an Element and delegate - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "we have to parse " + inputBytes.length + " bytes"); - - Element e = this.getDocFromBytes(inputBytes); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Now we have a {" + e.getNamespaceURI() + "}" - + e.getLocalName() + " Element"); - - if (e != null) { - KeyResolver newKeyResolver = KeyResolver.getInstance(getFirstElementChild(e), - BaseURI, storage); - - if (newKeyResolver != null) { - return newKeyResolver.resolvePublicKey(getFirstElementChild(e), BaseURI, - storage); - } - } - } - } + String type = rm.getType(); + XMLSignatureInput resource=resolveInput(rm,BaseURI); + if (RetrievalMethod.TYPE_RAWX509.equals(type)) { + X509Certificate cert=getRawCertificate(resource); + return cert; + } + Element e = obtainRefrenceElement(resource); + return resolveCertificate(e,BaseURI,storage); } catch (XMLSecurityException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); + log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); } catch (CertificateException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "CertificateException", ex); + log.log(java.util.logging.Level.FINE, "CertificateException", ex); } catch (IOException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "IOException", ex); - } - + log.log(java.util.logging.Level.FINE, "IOException", ex); + } catch (ParserConfigurationException e) { + log.log(java.util.logging.Level.FINE, "ParserConfigurationException", e); + } catch (SAXException e) { + log.log(java.util.logging.Level.FINE, "SAXException", e); + } return null; } /** - * Method engineResolveX509Certificate - * @inheritDoc - * @param element + * Retrieves a x509Certificate from the given information + * @param e * @param BaseURI * @param storage - * + * @return + * @throws KeyResolverException */ - public X509Certificate engineResolveX509Certificate( - Element element, String BaseURI, StorageResolver storage) - { - - try { - RetrievalMethod rm = new RetrievalMethod(element, BaseURI); - Attr uri = rm.getURIAttr(); - Transforms transforms = rm.getTransforms(); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Asked to resolve URI " + uri); - - ResourceResolver resRes = ResourceResolver.getInstance(uri, BaseURI); - - if (resRes != null) { - XMLSignatureInput resource = resRes.resolve(uri, BaseURI); - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Before applying Transforms, resource has " - + resource.getBytes().length + "bytes"); - - if (transforms != null) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "We have Transforms"); - - resource = transforms.performTransforms(resource); - } - - if (true) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "After applying Transforms, resource has " - + resource.getBytes().length + "bytes"); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Resolved to resource " + resource.getSourceURI()); - } - - byte inputBytes[] = resource.getBytes(); - - if ((rm.getType() != null) - && rm.getType().equals(RetrievalMethod.TYPE_RAWX509)) { - - // if the resource stores a raw certificate, we have to handle it - CertificateFactory certFact = - CertificateFactory - .getInstance(XMLX509Certificate.JCA_CERT_ID); - X509Certificate cert = - (X509Certificate) certFact - .generateCertificate(new ByteArrayInputStream(inputBytes)); - - if (cert != null) { - return cert; - } - } else { - - // otherwise, we parse the resource, create an Element and delegate - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "we have to parse " + inputBytes.length + " bytes"); - - Element e = this.getDocFromBytes(inputBytes); - - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Now we have a {" + e.getNamespaceURI() + "}" - + e.getLocalName() + " Element"); - - if (e != null) { - KeyResolver newKeyResolver = KeyResolver.getInstance(getFirstElementChild(e), - BaseURI, storage); + static private X509Certificate resolveCertificate(Element e,String BaseURI,StorageResolver storage) throws KeyResolverException{ + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Now we have a {" + e.getNamespaceURI() + "}"+ e.getLocalName() + " Element"); + //An element has been provided + if (e != null) { + return KeyResolver.getX509Certificate(e,BaseURI, storage); + } + return null; + } - if (newKeyResolver != null) { - return newKeyResolver.resolveX509Certificate(getFirstElementChild(e), BaseURI, - storage); + /** + * Retrieves a x509Certificate from the given information + * @param e + * @param BaseURI + * @param storage + * @return + * @throws KeyResolverException + */ + static private PublicKey resolveKey(Element e,String BaseURI,StorageResolver storage) throws KeyResolverException{ + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Now we have a {" + e.getNamespaceURI() + "}"+ e.getLocalName() + " Element"); + //An element has been provided + if (e != null) { + return KeyResolver.getPublicKey(e,BaseURI, storage); } - } - } - } - } catch (XMLSecurityException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); - } catch (CertificateException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "CertificateException", ex); - } catch (IOException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "IOException", ex); - } + return null; + } - return null; + static private X509Certificate getRawCertificate(XMLSignatureInput resource) throws CanonicalizationException, IOException, CertificateException{ + byte inputBytes[] = resource.getBytes(); + // if the resource stores a raw certificate, we have to handle it + CertificateFactory certFact =CertificateFactory.getInstance(XMLX509Certificate.JCA_CERT_ID); + X509Certificate cert =(X509Certificate) certFact.generateCertificate(new ByteArrayInputStream(inputBytes)); + return cert; + } + /** + * Resolves the input from the given retrieval method + * @return + * @throws XMLSecurityException + */ + static private XMLSignatureInput resolveInput(RetrievalMethod rm,String BaseURI) throws XMLSecurityException{ + Attr uri = rm.getURIAttr(); + //Apply the trnasforms + Transforms transforms = rm.getTransforms(); + ResourceResolver resRes = ResourceResolver.getInstance(uri, BaseURI); + if (resRes != null) { + XMLSignatureInput resource = resRes.resolve(uri, BaseURI); + if (transforms != null) { + log.log(java.util.logging.Level.FINE, "We have Transforms"); + resource = transforms.performTransforms(resource); + } + return resource; + } + return null; } /** @@ -266,18 +247,13 @@ public class RetrievalMethodResolver extends KeyResolverSpi { * @return the Document Element after parsing bytes * @throws KeyResolverException if something goes wrong */ - Element getDocFromBytes(byte[] bytes) throws KeyResolverException { - + static Element getDocFromBytes(byte[] bytes) throws KeyResolverException { try { - javax.xml.parsers.DocumentBuilderFactory dbf = - javax.xml.parsers.DocumentBuilderFactory.newInstance(); - + javax.xml.parsers.DocumentBuilderFactory dbf =javax.xml.parsers.DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); - javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder(); org.w3c.dom.Document doc = db.parse(new java.io.ByteArrayInputStream(bytes)); - return doc.getDocumentElement(); } catch (org.xml.sax.SAXException ex) { throw new KeyResolverException("empty", ex); @@ -296,16 +272,43 @@ public class RetrievalMethodResolver extends KeyResolverSpi { * @param storage * */ - public javax.crypto.SecretKey engineResolveSecretKey( + public javax.crypto.SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage) { return null; } - static Element getFirstElementChild(Element e){ - Node n=e.getFirstChild(); - while (n!=null && n.getNodeType()!=Node.ELEMENT_NODE) { - n=n.getNextSibling(); - } - return (Element)n; + + static Element getDocumentElement(Set set) { + Iterator it=set.iterator(); + Element e=null; + while (it.hasNext()) { + Node currentNode=(Node)it.next(); + if (currentNode instanceof Element) { + e=(Element)currentNode; + break; + } + + } + List parents=new ArrayList(10); + + //Obtain all the parents of the elemnt + do { + parents.add(e); + Node n=e.getParentNode(); + if (!(n instanceof Element )) { + break; + } + e=(Element)n; + } while (e!=null); + //Visit them in reverse order. + ListIterator it2=parents.listIterator(parents.size()-1); + Element ele=null; + while (it2.hasPrevious()) { + ele=(Element)it2.previous(); + if (set.contains(ele)) { + return ele; + } + } + return null; } } diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509CertificateResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509CertificateResolver.java index 16264c998687fce2ae6c3c52c10211462561e0fb..06a49c6708e7c70dfb639bb2d0dffa0bbae7092a 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509CertificateResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509CertificateResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -41,7 +40,7 @@ import org.w3c.dom.Element; * Resolves Certificates which are directly contained inside a * ds:X509Certificate Element. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class X509CertificateResolver extends KeyResolverSpi { @@ -49,47 +48,7 @@ public class X509CertificateResolver extends KeyResolverSpi { static java.util.logging.Logger log = java.util.logging.Logger.getLogger(X509CertificateResolver.class.getName()); - /** Field _dsaKeyElement */ - Element[] _x509CertKeyElements = null; - - /** - * Method engineCanResolve - * @inheritDoc - * @param element - * @param BaseURI - * @param storage - * - */ - public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName() + "?"); - - if (!XMLUtils.elementIsInSignatureSpace(element, - Constants._TAG_X509DATA)) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - - return false; - } - - this._x509CertKeyElements = XMLUtils.selectDsNodes(element.getFirstChild(), - Constants._TAG_X509CERTIFICATE); - - if ((this._x509CertKeyElements != null) - && (this._x509CertKeyElements.length > 0)) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Yes Sir, I can"); - - return true; - } - - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - - return false; - } - - /** Field _x509certObject[] */ - XMLX509Certificate _x509certObject[] = null; /** * Method engineResolvePublicKey @@ -100,11 +59,11 @@ public class X509CertificateResolver extends KeyResolverSpi { * * @throws KeyResolverException */ - public PublicKey engineResolvePublicKey( + public PublicKey engineLookupAndResolvePublicKey( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - X509Certificate cert = this.engineResolveX509Certificate(element, + X509Certificate cert = this.engineLookupResolveX509Certificate(element, BaseURI, storage); if (cert != null) { @@ -123,43 +82,33 @@ public class X509CertificateResolver extends KeyResolverSpi { * * @throws KeyResolverException */ - public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { try { - if ((this._x509CertKeyElements == null) - || (this._x509CertKeyElements.length == 0)) { - boolean weCanResolve = this.engineCanResolve(element, BaseURI, - storage); - - if (!weCanResolve || (this._x509CertKeyElements == null) - || (this._x509CertKeyElements.length == 0)) { - return null; - } + Element[] els=XMLUtils.selectDsNodes(element.getFirstChild(), + Constants._TAG_X509CERTIFICATE); + if ((els == null) || (els.length == 0)) { + Element el=XMLUtils.selectDsNode(element.getFirstChild(), + Constants._TAG_X509DATA,0); + if (el!=null) { + return engineLookupResolveX509Certificate(el, BaseURI, storage); + } + return null; } - this._x509certObject = - new XMLX509Certificate[this._x509CertKeyElements.length]; - // populate Object array - for (int i = 0; i < this._x509CertKeyElements.length; i++) { - this._x509certObject[i] = - new XMLX509Certificate(this._x509CertKeyElements[i] - , BaseURI); - } - - for (int i = 0; i < this._x509certObject.length; i++) { - X509Certificate cert = this._x509certObject[i].getX509Certificate(); - - if (cert != null) { - return cert; + for (int i = 0; i < els.length; i++) { + XMLX509Certificate xmlCert=new XMLX509Certificate(els[i], BaseURI); + X509Certificate cert = xmlCert.getX509Certificate(); + if (cert!=null) { + return cert; } } - return null; } catch (XMLSecurityException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); + log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); throw new KeyResolverException("generic.EmptyMessage", ex); } @@ -173,7 +122,7 @@ public class X509CertificateResolver extends KeyResolverSpi { * @param storage * */ - public javax.crypto.SecretKey engineResolveSecretKey( + public javax.crypto.SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage) { return null; diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509IssuerSerialResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509IssuerSerialResolver.java index c4e824747ba198707875933156e282f6cbb0aa77..8f717e716897187aaaa2828bb5d6bca6d0ba76de 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509IssuerSerialResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509IssuerSerialResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -39,7 +38,7 @@ import org.w3c.dom.Element; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class X509IssuerSerialResolver extends KeyResolverSpi { @@ -48,44 +47,13 @@ public class X509IssuerSerialResolver extends KeyResolverSpi { java.util.logging.Logger.getLogger( X509IssuerSerialResolver.class.getName()); - /** @inheritDoc */ - public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName() + "?"); - - X509Data x509data = null; - try { - x509data = new X509Data(element, BaseURI); - } catch (XMLSignatureException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - - return false; - } catch (XMLSecurityException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - - return false; - } - - if (x509data == null) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - return false; - } - - if (x509data.containsIssuerSerial()) { - return true; - } - - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - return false; - } /** @inheritDoc */ - public PublicKey engineResolvePublicKey( + public PublicKey engineLookupAndResolvePublicKey( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - X509Certificate cert = this.engineResolveX509Certificate(element, + X509Certificate cert = this.engineLookupResolveX509Certificate(element, BaseURI, storage); if (cert != null) { @@ -96,10 +64,31 @@ public class X509IssuerSerialResolver extends KeyResolverSpi { } /** @inheritDoc */ - public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName() + "?"); + + X509Data x509data = null; + try { + x509data = new X509Data(element, BaseURI); + } catch (XMLSignatureException ex) { + log.log(java.util.logging.Level.FINE, "I can't"); + return null; + } catch (XMLSecurityException ex) { + log.log(java.util.logging.Level.FINE, "I can't"); + return null; + } + + if (x509data == null) { + log.log(java.util.logging.Level.FINE, "I can't"); + return null; + } + + if (!x509data.containsIssuerSerial()) { + return null; + } try { if (storage == null) { Object exArgs[] = { Constants._TAG_X509ISSUERSERIAL }; @@ -107,53 +96,52 @@ public class X509IssuerSerialResolver extends KeyResolverSpi { new KeyResolverException("KeyResolver.needStorageResolver", exArgs); - if (log.isLoggable(java.util.logging.Level.INFO)) log.log(java.util.logging.Level.INFO, "", ex); + log.log(java.util.logging.Level.INFO, "", ex); throw ex; } - X509Data x509data = new X509Data(element, BaseURI); int noOfISS = x509data.lengthIssuerSerial(); while (storage.hasNext()) { X509Certificate cert = storage.next(); XMLX509IssuerSerial certSerial = new XMLX509IssuerSerial(element.getOwnerDocument(), cert); - if (true) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Found Certificate Issuer: " + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "Found Certificate Issuer: " + certSerial.getIssuerName()); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Found Certificate Serial: " + log.log(java.util.logging.Level.FINE, "Found Certificate Serial: " + certSerial.getSerialNumber().toString()); } for (int i=0; i 0)) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Yes Sir, I can"); - - return true; - } - - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - - return false; - } /** * Method engineResolvePublicKey @@ -102,11 +57,11 @@ public class X509SKIResolver extends KeyResolverSpi { * @return null if no {@link PublicKey} could be obtained * @throws KeyResolverException */ - public PublicKey engineResolvePublicKey( + public PublicKey engineLookupAndResolvePublicKey( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - X509Certificate cert = this.engineResolveX509Certificate(element, + X509Certificate cert = this.engineLookupResolveX509Certificate(element, BaseURI, storage); if (cert != null) { @@ -125,46 +80,55 @@ public class X509SKIResolver extends KeyResolverSpi { * * @throws KeyResolverException */ - public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - - try { - if (this._x509childNodes == null) { - boolean weCanResolve = this.engineCanResolve(element, BaseURI, - storage); - - if (!weCanResolve || (this._x509childNodes == null)) { - return null; - } - } - + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName() + "?"); + } + if (!XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_X509DATA)) { + log.log(java.util.logging.Level.FINE, "I can't"); + return null; + } + /** Field _x509childObject[] */ + XMLX509SKI x509childObject[] = null; + + Element x509childNodes[] = null; + x509childNodes = XMLUtils.selectDsNodes(element.getFirstChild(), + Constants._TAG_X509SKI); + + if (!((x509childNodes != null) + && (x509childNodes.length > 0))) { + log.log(java.util.logging.Level.FINE, "I can't"); + return null; + } + try { if (storage == null) { Object exArgs[] = { Constants._TAG_X509SKI }; KeyResolverException ex = new KeyResolverException("KeyResolver.needStorageResolver", exArgs); - if (log.isLoggable(java.util.logging.Level.INFO)) log.log(java.util.logging.Level.INFO, "", ex); + log.log(java.util.logging.Level.INFO, "", ex); throw ex; } - this._x509childObject = - new XMLX509SKI[this._x509childNodes.length]; + x509childObject = new XMLX509SKI[x509childNodes.length]; - for (int i = 0; i < this._x509childNodes.length; i++) { - this._x509childObject[i] = - new XMLX509SKI(this._x509childNodes[i], BaseURI); + for (int i = 0; i < x509childNodes.length; i++) { + x509childObject[i] = + new XMLX509SKI(x509childNodes[i], BaseURI); } while (storage.hasNext()) { X509Certificate cert = storage.next(); XMLX509SKI certSKI = new XMLX509SKI(element.getOwnerDocument(), cert); - for (int i = 0; i < this._x509childObject.length; i++) { - if (certSKI.equals(this._x509childObject[i])) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Return PublicKey from " + for (int i = 0; i < x509childObject.length; i++) { + if (certSKI.equals(x509childObject[i])) { + log.log(java.util.logging.Level.FINE, "Return PublicKey from " + cert.getSubjectDN().getName()); return cert; @@ -186,7 +150,7 @@ public class X509SKIResolver extends KeyResolverSpi { * @param storage * */ - public javax.crypto.SecretKey engineResolveSecretKey( + public javax.crypto.SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage) { return null; diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509SubjectNameResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509SubjectNameResolver.java index 5da6a7d8fd75d5288c62fe171d7ef9a647ce9305..05e82226c4c3a377304a0a1a8311f2a56ff42ee6 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509SubjectNameResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/implementations/X509SubjectNameResolver.java @@ -38,7 +38,7 @@ import org.w3c.dom.Element; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class X509SubjectNameResolver extends KeyResolverSpi { @@ -47,50 +47,6 @@ public class X509SubjectNameResolver extends KeyResolverSpi { java.util.logging.Logger.getLogger( X509SubjectNameResolver.class.getName()); - /** Field _x509childNodes */ - private Element[] _x509childNodes = null; - - /** Field _x509childObject[] */ - private XMLX509SubjectName _x509childObject[] = null; - - /** - * Method engineCanResolve - * @inheritDoc - * @param element - * @param BaseURI - * @param storage - * - */ - public boolean engineCanResolve(Element element, String BaseURI, - StorageResolver storage) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName() + "?"); - - - if (!XMLUtils.elementIsInSignatureSpace(element, - Constants._TAG_X509DATA) ) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - - return false; - } - - - - this._x509childNodes = XMLUtils.selectDsNodes(element, - Constants._TAG_X509SUBJECTNAME); - - if ((this._x509childNodes != null) - && (this._x509childNodes.length > 0)) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Yes Sir, I can"); - - return true; - } - - - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "I can't"); - - return false; - } /** * Method engineResolvePublicKey @@ -101,11 +57,11 @@ public class X509SubjectNameResolver extends KeyResolverSpi { * @return null if no {@link PublicKey} could be obtained * @throws KeyResolverException */ - public PublicKey engineResolvePublicKey( + public PublicKey engineLookupAndResolvePublicKey( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { - X509Certificate cert = this.engineResolveX509Certificate(element, + X509Certificate cert = this.engineLookupResolveX509Certificate(element, BaseURI, storage); if (cert != null) { @@ -124,37 +80,46 @@ public class X509SubjectNameResolver extends KeyResolverSpi { * * @throws KeyResolverException */ - public X509Certificate engineResolveX509Certificate( + public X509Certificate engineLookupResolveX509Certificate( Element element, String BaseURI, StorageResolver storage) throws KeyResolverException { + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Can I resolve " + element.getTagName() + "?"); + Element[] x509childNodes = null; + XMLX509SubjectName x509childObject[] = null; + + if (!XMLUtils.elementIsInSignatureSpace(element, + Constants._TAG_X509DATA) ) { + log.log(java.util.logging.Level.FINE, "I can't"); + return null; + } + x509childNodes = XMLUtils.selectDsNodes(element.getFirstChild(), + Constants._TAG_X509SUBJECTNAME); - try { - if (this._x509childNodes == null) { - boolean weCanResolve = this.engineCanResolve(element, BaseURI, - storage); - - if (!weCanResolve || (this._x509childNodes == null)) { - return null; + if (!((x509childNodes != null) + && (x509childNodes.length > 0))) { + log.log(java.util.logging.Level.FINE, "I can't"); + return null; } - } + try { if (storage == null) { Object exArgs[] = { Constants._TAG_X509SUBJECTNAME }; KeyResolverException ex = new KeyResolverException("KeyResolver.needStorageResolver", exArgs); - if (log.isLoggable(java.util.logging.Level.INFO)) log.log(java.util.logging.Level.INFO, "", ex); + log.log(java.util.logging.Level.INFO, "", ex); throw ex; } - this._x509childObject = - new XMLX509SubjectName[this._x509childNodes.length]; + x509childObject = + new XMLX509SubjectName[x509childNodes.length]; - for (int i = 0; i < this._x509childNodes.length; i++) { - this._x509childObject[i] = - new XMLX509SubjectName(this._x509childNodes[i], + for (int i = 0; i < x509childNodes.length; i++) { + x509childObject[i] = + new XMLX509SubjectName(x509childNodes[i], BaseURI); } @@ -163,24 +128,24 @@ public class X509SubjectNameResolver extends KeyResolverSpi { XMLX509SubjectName certSN = new XMLX509SubjectName(element.getOwnerDocument(), cert); - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Found Certificate SN: " + certSN.getSubjectName()); + log.log(java.util.logging.Level.FINE, "Found Certificate SN: " + certSN.getSubjectName()); - for (int i = 0; i < this._x509childObject.length; i++) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Found Element SN: " - + this._x509childObject[i].getSubjectName()); + for (int i = 0; i < x509childObject.length; i++) { + log.log(java.util.logging.Level.FINE, "Found Element SN: " + + x509childObject[i].getSubjectName()); - if (certSN.equals(this._x509childObject[i])) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "match !!! "); + if (certSN.equals(x509childObject[i])) { + log.log(java.util.logging.Level.FINE, "match !!! "); return cert; } - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "no match..."); + log.log(java.util.logging.Level.FINE, "no match..."); } } return null; } catch (XMLSecurityException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); + log.log(java.util.logging.Level.FINE, "XMLSecurityException", ex); throw new KeyResolverException("generic.EmptyMessage", ex); } @@ -194,7 +159,7 @@ public class X509SubjectNameResolver extends KeyResolverSpi { * @param storage * */ - public javax.crypto.SecretKey engineResolveSecretKey( + public javax.crypto.SecretKey engineLookupAndResolveSecretKey( Element element, String BaseURI, StorageResolver storage) { return null; diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolver.java index 46fee3d4240467ab6fbac1bc4240439a15464426..f1a8dd3400d090235e1d1dfe9ea5c621a75c9bde 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -21,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.storage; - - import java.security.KeyStore; import java.security.cert.X509Certificate; import java.util.ArrayList; @@ -36,7 +33,7 @@ import com.sun.org.apache.xml.internal.security.keys.storage.implementations.Sin /** * This class collects customized resolvers for Certificates. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class StorageResolver { @@ -45,7 +42,7 @@ public class StorageResolver { java.util.logging.Logger.getLogger(StorageResolver.class.getName()); /** Field _storageResolvers */ - List _storageResolvers = new ArrayList(); + List _storageResolvers = null; /** Field _iterator */ Iterator _iterator = null; @@ -71,7 +68,8 @@ public class StorageResolver { * @param resolver */ public void add(StorageResolverSpi resolver) { - + if (_storageResolvers==null) + _storageResolvers=new ArrayList(); this._storageResolvers.add(resolver); this._iterator = null; @@ -126,6 +124,8 @@ public class StorageResolver { public Iterator getIterator() { if (this._iterator == null) { + if (_storageResolvers==null) + _storageResolvers=new ArrayList(); this._iterator = new StorageResolverIterator(this._storageResolvers.iterator()); } @@ -140,6 +140,8 @@ public class StorageResolver { public boolean hasNext() { if (this._iterator == null) { + if (_storageResolvers==null) + _storageResolvers=new ArrayList(); this._iterator = new StorageResolverIterator(this._storageResolvers.iterator()); } @@ -158,15 +160,13 @@ public class StorageResolver { /** * Class StorageResolverIterator * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ - class StorageResolverIterator implements Iterator { + static class StorageResolverIterator implements Iterator { /** Field _resolvers */ - Iterator _resolvers = null; - - /** Field _currentResolver */ - int _currentResolver = 0; + Iterator _resolvers = null; /** * Constructor FilesystemIterator @@ -179,17 +179,16 @@ public class StorageResolver { /** @inheritDoc */ public boolean hasNext() { - return _resolvers.hasNext(); + return _resolvers.hasNext(); } /** @inheritDoc */ public Object next() { - return _resolvers.next(); + return _resolvers.next(); } /** * Method remove - * */ public void remove() { throw new UnsupportedOperationException( diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverException.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverException.java index 2388ef19bc8244437c8f3d3163cfdc254ef48435..29dff030f78b03f346028a1361f50ecf26724838 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverException.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverException.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -28,7 +27,7 @@ import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class StorageResolverException extends XMLSecurityException { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverSpi.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverSpi.java index dc95e60407f2b4346a5a8bbbbfef917a689f6b7d..25f3e2828d2e8441ff81b32ebd5ee8f511410994 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverSpi.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolverSpi.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -28,7 +27,7 @@ import java.util.Iterator; /** * - * @author $Author: raul $ + * @author $Author: mullan $ */ public abstract class StorageResolverSpi { diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/CertsInFilesystemDirectoryResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/CertsInFilesystemDirectoryResolver.java index 6c6909665c30cbdd5250ce898b8d44cfdb2415d5..06fb5694befe6849bc27c6f9729d567f38e71d37 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/CertsInFilesystemDirectoryResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/CertsInFilesystemDirectoryResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -21,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.storage.implementations; - - import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -40,12 +37,11 @@ import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolverExce import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolverSpi; import com.sun.org.apache.xml.internal.security.utils.Base64; - /** * This {@link StorageResolverSpi} makes all raw (binary) {@link X509Certificate}s * which reside as files in a single directory available to the {@link com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver}. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class CertsInFilesystemDirectoryResolver extends StorageResolverSpi { @@ -131,20 +127,20 @@ public class CertsInFilesystemDirectoryResolver extends StorageResolverSpi { dn = cert.getSubjectDN().getName(); added = true; } catch (FileNotFoundException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); + log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); } catch (IOException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); + log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); } catch (CertificateNotYetValidException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); + log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); } catch (CertificateExpiredException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); + log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); } catch (CertificateException ex) { - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); + log.log(java.util.logging.Level.FINE, "Could not add certificate from file " + filename, ex); } if (added) { - if (true) - if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "Added certificate: " + dn); + if (log.isLoggable(java.util.logging.Level.FINE)) + log.log(java.util.logging.Level.FINE, "Added certificate: " + dn); } } } @@ -157,9 +153,10 @@ public class CertsInFilesystemDirectoryResolver extends StorageResolverSpi { /** * Class FilesystemIterator * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ - class FilesystemIterator implements Iterator { + private static class FilesystemIterator implements Iterator { /** Field _certs */ List _certs = null; diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/KeyStoreResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/KeyStoreResolver.java index ad1eb6b149465880ca5e61b14ab42b4b67a19b96..18632433ca515217153e33b1368751603006489b 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/KeyStoreResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/KeyStoreResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -21,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.storage.implementations; - - import java.security.KeyStore; import java.security.KeyStoreException; import java.security.cert.X509Certificate; @@ -37,7 +34,7 @@ import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolverSpi; * Makes the Certificates from a JAVA {@link KeyStore} object available to the * {@link com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver}. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class KeyStoreResolver extends StorageResolverSpi { @@ -66,9 +63,10 @@ public class KeyStoreResolver extends StorageResolverSpi { /** * Class KeyStoreIterator * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ - class KeyStoreIterator implements Iterator { + static class KeyStoreIterator implements Iterator { /** Field _keyStore */ KeyStore _keyStore = null; diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/SingleCertificateResolver.java b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/SingleCertificateResolver.java index 6c4f260b9d1b51c5ee44b53e7f9421b0539b6cb6..7e61b2a244d23ed955dec16b304ad5221e6894d0 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/SingleCertificateResolver.java +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/SingleCertificateResolver.java @@ -2,7 +2,6 @@ * reserved comment block * DO NOT REMOVE OR ALTER! */ - /* * Copyright 1999-2004 The Apache Software Foundation. * @@ -21,8 +20,6 @@ */ package com.sun.org.apache.xml.internal.security.keys.storage.implementations; - - import java.security.cert.X509Certificate; import java.util.Iterator; @@ -33,7 +30,7 @@ import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolverSpi; * This {@link StorageResolverSpi} makes a single {@link X509Certificate} * available to the {@link com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver}. * - * @author $Author: raul $ + * @author $Author: mullan $ */ public class SingleCertificateResolver extends StorageResolverSpi { @@ -61,9 +58,10 @@ public class SingleCertificateResolver extends StorageResolverSpi { /** * Class InternalIterator * - * @author $Author: raul $ + * @author $Author: mullan $ + * @version $Revision: 1.5 $ */ - class InternalIterator implements Iterator { + static class InternalIterator implements Iterator { /** Field _alreadyReturned */ boolean _alreadyReturned = false; diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.dtd b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.dtd index 1e886bf17760aad26920c92726ae1c9554deb86a..f57b9fabe4d3aa59de28f6c0c3930a8251a2a916 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.dtd +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.dtd @@ -1,73 +1,73 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.xml b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.xml index d0d6edcee6956942553a2055b1362f08fa2f8e60..aea1595741b81fcf21298cc510e3cbb496acf636 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.xml +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/config.xml @@ -1,380 +1,399 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/etsi.xsd b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/etsi.xsd index 3a08c64f4b6a93c30b83468c3827df0fe0231c9c..d69852ff8421c3400819831b6c16b56ce3f8d0af 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/etsi.xsd +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/etsi.xsd @@ -1,347 +1,347 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.dtd b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.dtd index 969dbb18c21e32ae80080095121f3c4939e08710..b2cc19f63a1f6958529002476d12ce11c39061ef 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.dtd +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.dtd @@ -3,7 +3,7 @@ Joseph Reagle $last changed 20001215$ http://www.w3.org/2000/09/xmldsig# - $Revision: 1.1 $ on $Date: 2002/02/08 20:32:26 $ by $Author: reagle $ + $Revision: 1.6 $ on $Date: 2008/07/24 16:15:03 $ by $Author: mullan $ Copyright 2001 The Internet Society and W3C (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en diff --git a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.xsd b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.xsd index df126b30e684091b32a748cd2e408f5fb9d651a9..e8288a526c3995e0737456793c25660ebe25ab2b 100644 --- a/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.xsd +++ b/src/share/classes/com/sun/org/apache/xml/internal/security/resource/schema/xmldsig-core-schema.xsd @@ -11,7 +11,7 @@ - - - - - -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

{@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
- -

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

{@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
- -

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

{@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
- -

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 - - - diff --git a/src/share/classes/java/nio/channels/spi/SelectorProvider.java b/src/share/classes/java/nio/channels/spi/SelectorProvider.java index 9a8a3cc707c87a4854fc3a27eb125d9c03d0075f..dc61c9c270abc391044eb95504b3c80d5db517a6 100644 --- a/src/share/classes/java/nio/channels/spi/SelectorProvider.java +++ b/src/share/classes/java/nio/channels/spi/SelectorProvider.java @@ -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 @@ public abstract class SelectorProvider { throws IOException; /** - * Opens a pipe.

+ * Opens a datagram channel. + * + * @param family + * The protocol family + * + * @return A new datagram channel + * + * @throws UnsupportedOperationException + * If the specified protocol family is not supported + * @throws IOException + * If an I/O error occurs + * + * @since 1.7 + */ + public abstract DatagramChannel openDatagramChannel(ProtocolFamily family) + throws IOException; + + /** + * Opens a pipe.

* * @return The new pipe */ diff --git a/src/share/classes/java/nio/charset/Charset.java b/src/share/classes/java/nio/charset/Charset.java index 4908c77d1dbda8a59f7357469e43f9332a184f49..804d0091c483129568e1b727575ddb9ed634ca63 100644 --- a/src/share/classes/java/nio/charset/Charset.java +++ b/src/share/classes/java/nio/charset/Charset.java @@ -85,6 +85,9 @@ import sun.security.action.GetPropertyAction; *
  • The dash character '-' * ('\u002d'HYPHEN-MINUS), * + *
  • The plus character '+' + * ('\u002b'PLUS SIGN), + * *
  • The period character '.' * ('\u002e'FULL STOP), * @@ -307,6 +310,7 @@ public abstract class Charset if (c >= 'a' && c <= 'z') continue; if (c >= '0' && c <= '9') continue; if (c == '-' && i != 0) continue; + if (c == '+' && i != 0) continue; if (c == ':' && i != 0) continue; if (c == '_' && i != 0) continue; if (c == '.' && i != 0) continue; diff --git a/src/share/classes/java/util/EnumSet.java b/src/share/classes/java/util/EnumSet.java index d5c8d23dfa3cb22332fb716fa1addbb815a0f493..5b92a972b8c73f863c262f6c44264c1685478347 100644 --- a/src/share/classes/java/util/EnumSet.java +++ b/src/share/classes/java/util/EnumSet.java @@ -432,4 +432,11 @@ public abstract class EnumSet> extends AbstractSet Object writeReplace() { return new SerializationProxy(this); } + + // readObject method for the serialization proxy pattern + // See Effective Java, Second Ed., Item 78. + private void readObject(java.io.ObjectInputStream stream) + throws java.io.InvalidObjectException { + throw new java.io.InvalidObjectException("Proxy required"); + } } diff --git a/src/share/classes/java/util/logging/Logging.java b/src/share/classes/java/util/logging/Logging.java index 72468699ead06d487d58f33903f52d4dbe3d45c7..d99782407a56a934be487c92d19b139b5f2c8cbe 100644 --- a/src/share/classes/java/util/logging/Logging.java +++ b/src/share/classes/java/util/logging/Logging.java @@ -118,6 +118,6 @@ class Logging implements LoggingMXBean { } public ObjectName getObjectName() { - return com.sun.jmx.mbeanserver.Util.newObjectName(LogManager.LOGGING_MXBEAN_NAME); + return ObjectName.valueOf(LogManager.LOGGING_MXBEAN_NAME); } } diff --git a/src/share/classes/java/util/zip/Inflater.java b/src/share/classes/java/util/zip/Inflater.java index bc0bdf55f3ec830db4f2c35366b36ebd4d8f4d7c..68c8d62339702138338abeda1420f67a70127279 100644 --- a/src/share/classes/java/util/zip/Inflater.java +++ b/src/share/classes/java/util/zip/Inflater.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-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 @@ -73,11 +73,13 @@ package java.util.zip; public class Inflater { private long strm; - private byte[] buf = new byte[0]; + private byte[] buf = defaultBuf; private int off, len; private boolean finished; private boolean needDict; + private static final byte[] defaultBuf = new byte[0]; + static { /* Zip library is loaded from System.initializeSystemClass */ initIDs(); @@ -318,6 +320,7 @@ class Inflater { public synchronized void reset() { ensureOpen(); reset(strm); + buf = defaultBuf; finished = false; needDict = false; off = len = 0; diff --git a/src/share/classes/java/util/zip/ZipFile.java b/src/share/classes/java/util/zip/ZipFile.java index 8ad177fdc92999514a8e013e7b37fb350991ac1f..37e92ddecb77084c3bb64d75b70f184f403a0e4c 100644 --- a/src/share/classes/java/util/zip/ZipFile.java +++ b/src/share/classes/java/util/zip/ZipFile.java @@ -1,5 +1,5 @@ /* - * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-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 @@ -278,7 +278,6 @@ class ZipFile implements ZipConstants { int size = inflaters.size(); if (size > 0) { Inflater inf = (Inflater)inflaters.remove(size - 1); - inf.reset(); return inf; } else { return new Inflater(true); @@ -291,6 +290,7 @@ class ZipFile implements ZipConstants { */ private void releaseInflater(Inflater inf) { synchronized (inflaters) { + inf.reset(); inflaters.add(inf); } } diff --git a/src/share/classes/java/util/zip/ZipOutputStream.java b/src/share/classes/java/util/zip/ZipOutputStream.java index 65394268297bec06604b818b07b4303db7dfe18d..797a37392fe4e73ac57a3d8ee14a8887ee11b6b7 100644 --- a/src/share/classes/java/util/zip/ZipOutputStream.java +++ b/src/share/classes/java/util/zip/ZipOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-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 @@ -317,9 +317,6 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { if (current != null) { closeEntry(); } - if (xentries.size() < 1) { - throw new ZipException("ZIP file must have at least one entry"); - } // write central directory long off = written; for (XEntry xentry : xentries) diff --git a/src/share/classes/javax/management/InstanceNotFoundException.java b/src/share/classes/javax/management/InstanceNotFoundException.java index f572d614d0030319fa9ae22f83387bb038a08f5e..3a8376f7baf6a8b3e32f83121afec319b5e04f56 100644 --- a/src/share/classes/javax/management/InstanceNotFoundException.java +++ b/src/share/classes/javax/management/InstanceNotFoundException.java @@ -51,4 +51,16 @@ public class InstanceNotFoundException extends OperationsException { public InstanceNotFoundException(String message) { super(message); } + + /** + * Constructor for the frequent case where the message is the ObjectName + * of the missing MBean. + * + * @param name the ObjectName of the missing MBean. + * + * @since 1.7 + */ + public InstanceNotFoundException(ObjectName name) { + this(String.valueOf(name)); + } } diff --git a/src/share/classes/javax/management/MBeanPermission.java b/src/share/classes/javax/management/MBeanPermission.java index 762f5defc7c1bbd53746f05b3cf87a7272e249a7..def34bed3ecfbbaaa7eba46a6fdc13a5cee6c11f 100644 --- a/src/share/classes/javax/management/MBeanPermission.java +++ b/src/share/classes/javax/management/MBeanPermission.java @@ -25,6 +25,7 @@ package javax.management; +import com.sun.jmx.mbeanserver.Util; import java.io.IOException; import java.io.ObjectInputStream; import java.security.Permission; @@ -42,10 +43,10 @@ import java.security.Permission; * permission that you need. When a sensitive operation is * being checked for permission, an MBeanPermission is constructed * representing the permission you need. The operation is only - * allowed if the permissions you have {@link #implies imply} the + * allowed if the permissions you have {@linkplain #implies imply} the * permission you need.

    * - *

    An MBeanPermission contains four items of information:

    + *

    An MBeanPermission contains five items of information:

    * *
      * @@ -57,6 +58,23 @@ import java.security.Permission; * *

      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.
      + * An {@code mbeanServerName} pattern can also be empty or the single + * character {@code "*"}, both of which will match any {@code MBeanServer} name. + *

      + * *
    • The class name.

      * *

      For a permission you need, this is the class name of an MBean @@ -88,7 +106,7 @@ import java.security.Permission; * or operation you can access, or it is empty or the single character * "*", both of which grant access to any member.

      * - *
    • 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 @@ import java.security.Permission; *

    * *

    If you have an MBeanPermission, it allows operations only if all - * four of the items match.

    + * five 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:

    * *
    - * className#member[objectName] + * mbeanServerName::className#member[objectName] *
    * *

    The object name is written using the usual syntax for {@link @@ -119,15 +137,18 @@ import java.security.Permission; * ]. It is terminated by a ] character * that is the last character in the string.

    * - *

    One or more of the className, member, - * or objectName may be omitted. If the - * member is omitted, the # may be too (but + *

    One or more of the 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.

    * - *

    One or more of the className, member, + *

    One or more of the 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 @@ -246,6 +267,13 @@ public class MBeanPermission extends Permission { */ 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. */ @@ -283,6 +311,13 @@ public class MBeanPermission extends Permission { 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 @@ public class MBeanPermission extends Permission { // 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 @@ public class MBeanPermission extends Permission { } 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 @@ public class MBeanPermission extends Permission { 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 @@ public class MBeanPermission extends Permission { * 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 @@ public class MBeanPermission extends Permission { 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; + } + } + + /** *

    Create a new MBeanPermission object with the specified target name * and actions.

    * *

    The target name is of the form - * "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.

    * *

    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 "className#member[objectName]". + * @param name the quadruplet "mbeanServerName::className#member[objectName]". * @param actions the action string. * * @exception IllegalArgumentException if the name or @@ -418,6 +468,12 @@ public class MBeanPermission extends Permission { * optional. This will be the result of {@link #getName()} on the * resultant MBeanPermission.

    * + *

    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.

    @@ -439,17 +495,67 @@ public class MBeanPermission extends Permission { String member, ObjectName objectName, String actions) { + this("*",className,member,objectName,actions); + } + + /** + *

    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 + * "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. + *

    + * + *

    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 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(className, member, objectName)); - initName(className, member, objectName); + 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 @@ public class MBeanPermission extends Permission { * *
  • p is an instance of MBeanPermission; and
  • * + *
  • p has a null mbeanServerName or p's mbeanServerName + * matches this object's mbeanServerName; and
  • + * *
  • p has a null className or p's className * matches this object's className; and
  • * @@ -1004,6 +1113,13 @@ public class MBeanPermission extends Permission { * * * + *

    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 className is "*", p's * className always matches it. If it is "a.*", p's * className matches it if it begins with "a.".

    @@ -1050,6 +1166,12 @@ public class MBeanPermission extends Permission { // 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 'className' check is true iff: // 1) the className in 'this' permission is omitted or "*", or // 2) the className in 'that' permission is omitted or "*", or @@ -1076,6 +1198,17 @@ public class MBeanPermission extends Permission { expect that "that" contains a wildcard, since it is a needed permission. So we assume that.classNameExactMatch. */ + 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 + } + if (that.classNamePrefix == null) { // bottom is implied } else if (this.classNamePrefix == null) { diff --git a/src/share/classes/javax/management/MBeanServer.java b/src/share/classes/javax/management/MBeanServer.java index a08f64011dfdfa7acf70df5a82c48c2c4b222127..90d42d2df6c2d2b2799b5a65c67e00685288d3f1 100644 --- a/src/share/classes/javax/management/MBeanServer.java +++ b/src/share/classes/javax/management/MBeanServer.java @@ -42,7 +42,7 @@ import javax.management.loading.ClassLoaderRepository; * *

    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.

    + * the methods in the {@link javax.management.MBeanServerFactory} class.

    * *

    Every MBean which is added to the MBean server becomes * manageable: its attributes and operations become remotely @@ -62,8 +62,12 @@ import javax.management.loading.ClassLoaderRepository; * JMImplementation:type=MBeanServerDelegate.

    * *

    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.

    * @@ -73,9 +77,26 @@ import javax.management.loading.ClassLoaderRepository; * *

    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, 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.

      + * MBean,
    • + *
    • {@code mbeanServerName} is the + * {@linkplain MBeanServerFactory#getMBeanServerName name of the + * MBean Server} in which the target MBean is registered. This is the + * value returned by {@link MBeanServerFactory#getMBeanServerName + * MBeanServerFactory.getMBeanServerName(MBeanServer)}, and + * is usually the {@code mbeanServerName} parameter that was supplied + * to the {@link + * MBeanServerFactory#createNamedMBeanServer(String,String) + * createNamedMBeanServer} or {@link + * MBeanServerFactory#newNamedMBeanServer(String,String) newNamedMBeanServer} + * methods of the {@link MBeanServerFactory} when the MBeanServer was created, + * or {@value javax.management.MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if + * no name was supplied. + *
    * *

    If a security check fails, the method throws {@link * SecurityException}.

    @@ -89,78 +110,86 @@ import javax.management.loading.ClassLoaderRepository; * *
  • For the {@link #invoke invoke} method, the caller's * permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, operationName, name, "invoke")}.

    + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, 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")}.

    + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, 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 * attrName is {@link Attribute#getName() * attribute.getName()}.

    * *
  • 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 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")}.

    * *
  • For the 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")}.

    * *
  • For the {@link #getMBeanInfo getMBeanInfo} method, the * caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "getMBeanInfo")}.

    + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, 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")}.

    + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, 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")}.

    + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, 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 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.

    * *

    Certain query elements perform operations on the MBean server. @@ -179,10 +208,10 @@ import javax.management.loading.ClassLoaderRepository; * *

  • 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 @@ import javax.management.loading.ClassLoaderRepository; * *

  • 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")}.

    + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, null, null, null, + * "getClassLoaderRepository")}.

    * *
  • For the deprecated deserialize methods, the * required permissions are the same as for the methods that replace @@ -213,15 +243,15 @@ import javax.management.loading.ClassLoaderRepository; * *

  • For the instantiate methods, the caller's * permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, null, "instantiate")}.

    + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, null, "instantiate")}, + * where {@code className} is the name of the class which is to + * be instantiated.

    * *
  • 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 - * 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")}. * *

    If the MBeanPermission check succeeds, the MBean's * class is validated by checking that its {@link @@ -241,8 +271,9 @@ import javax.management.loading.ClassLoaderRepository; * *

  • For the {@link #unregisterMBean unregisterMBean} method, * the caller's permissions must imply {@link - * MBeanPermission#MBeanPermission(String,String,ObjectName,String) - * MBeanPermission(className, null, name, "unregisterMBean")}.

    + * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String) + * MBeanPermission(mbeanServerName, className, null, name, "unregisterMBean")}. + *

    * * * @@ -264,6 +295,8 @@ public interface MBeanServer extends MBeanServerConnection { * is sent as described above.

    * * @throws RuntimeOperationsException {@inheritDoc} + * @throws RuntimeMBeanException {@inheritDoc} + * @throws RuntimeErrorException {@inheritDoc} */ public ObjectInstance createMBean(String className, ObjectName name) throws ReflectionException, InstanceAlreadyExistsException, @@ -276,6 +309,8 @@ public interface MBeanServer extends MBeanServerConnection { * is sent as described above.

    * * @throws RuntimeOperationsException {@inheritDoc} + * @throws RuntimeMBeanException {@inheritDoc} + * @throws RuntimeErrorException {@inheritDoc} */ public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName) @@ -289,6 +324,8 @@ public interface MBeanServer extends MBeanServerConnection { * is sent as described above.

    * * @throws RuntimeOperationsException {@inheritDoc} + * @throws RuntimeMBeanException {@inheritDoc} + * @throws RuntimeErrorException {@inheritDoc} */ public ObjectInstance createMBean(String className, ObjectName name, Object params[], String signature[]) @@ -302,6 +339,8 @@ public interface MBeanServer extends MBeanServerConnection { * is sent as described above.

    * * @throws RuntimeOperationsException {@inheritDoc} + * @throws RuntimeMBeanException {@inheritDoc} + * @throws RuntimeErrorException {@inheritDoc} */ public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName, Object params[], diff --git a/src/share/classes/javax/management/MBeanServerConnection.java b/src/share/classes/javax/management/MBeanServerConnection.java index 779301491542fe0818c77d2b76ee5c919f66b873..8b0dd6646ce157603eb6e8e98dd7ec2367d3093a 100644 --- a/src/share/classes/javax/management/MBeanServerConnection.java +++ b/src/share/classes/javax/management/MBeanServerConnection.java @@ -78,19 +78,19 @@ public interface MBeanServerConnection extends NotificationManager { * 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. @@ -150,19 +150,19 @@ public interface MBeanServerConnection extends NotificationManager { * 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 @@ public interface MBeanServerConnection extends NotificationManager { * 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 @@ public interface MBeanServerConnection extends NotificationManager { * 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 @@ public interface MBeanServerConnection extends NotificationManager { * 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 --git a/src/share/classes/javax/management/MBeanServerDelegate.java b/src/share/classes/javax/management/MBeanServerDelegate.java index 4ee9766306b4b0e2aa86f95e1999d3d19ddb8c00..00b82a92ff827575263abf885ce98b4cd175ba39 100644 --- a/src/share/classes/javax/management/MBeanServerDelegate.java +++ b/src/share/classes/javax/management/MBeanServerDelegate.java @@ -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 @@ public class MBeanServerDelegate implements MBeanServerDelegateMBean, /** The MBean server agent identification.*/ private String mbeanServerId ; + private String mbeanServerName; /** The NotificationBroadcasterSupport object that sends the notifications */ @@ -68,6 +71,7 @@ public class MBeanServerDelegate implements MBeanServerDelegateMBean, public MBeanServerDelegate () { stamp = getStamp(); broadcaster = new NotificationBroadcasterSupport() ; + mbeanServerName=null; } @@ -82,13 +86,102 @@ public class MBeanServerDelegate implements MBeanServerDelegateMBean, 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 @@ public class MBeanServerDelegate implements MBeanServerDelegateMBean, * * @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 = + ObjectName.valueOf("JMImplementation:type=MBeanServerDelegate"); /* Return a timestamp that is monotonically increasing even if System.currentTimeMillis() isn't (for example, if you call this diff --git a/src/share/classes/javax/management/MBeanServerFactory.java b/src/share/classes/javax/management/MBeanServerFactory.java index 743ca3a1827da1b86538cf166c960d85747990d2..7657af1080e6872f2d9d79125766754fb69a908e 100644 --- a/src/share/classes/javax/management/MBeanServerFactory.java +++ b/src/share/classes/javax/management/MBeanServerFactory.java @@ -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 @@ import javax.management.loading.ClassLoaderRepository; * 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 @@ public class MBeanServerFactory { * 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 @@ public class MBeanServerFactory { * 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 @@ public class MBeanServerFactory { 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,16 +586,107 @@ public class MBeanServerFactory { ArrayList result = new ArrayList(); for (MBeanServer mbs : mBeanServerList) { - String name = mBeanServerName(mbs); + String name = mBeanServerId(mbs); if (agentId.equals(name)) result.add(mbs); } return result; } + /** + *

    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 class MBeanServerFactory { * **/ 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 @@ public class MBeanServerFactory { } 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 @@ public class MBeanServerFactory { **/ 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 @@ public class MBeanServerFactory { 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 @@ public class MBeanServerFactory { 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 --git a/src/share/classes/javax/management/MXBean.java b/src/share/classes/javax/management/MXBean.java index 1773328ddc41241501e0331df64443a7bf42606a..f6691ccaeae6947d30cb34b9fa561f8be79a1368 100644 --- a/src/share/classes/javax/management/MXBean.java +++ b/src/share/classes/javax/management/MXBean.java @@ -469,8 +469,8 @@ public class MemoryPool 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 --git a/src/share/classes/javax/management/ObjectName.java b/src/share/classes/javax/management/ObjectName.java index d06cb35eeb3f115e143ed661e0dfe3ed9349a7db..8185edc274206b2e4e49edfae73f0e47c8ebe3e9 100644 --- a/src/share/classes/javax/management/ObjectName.java +++ b/src/share/classes/javax/management/ObjectName.java @@ -27,6 +27,8 @@ package javax.management; 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; @@ -222,6 +224,17 @@ import java.util.Map; @SuppressWarnings("serial") // don't complain serialVersionUID not constant 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 @@ public class ObjectName implements Comparable, QueryExp { /** * 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 @@ public class ObjectName implements Comparable, QueryExp { */ 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 { + + // 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 <======================================== @@ -414,7 +467,7 @@ public class ObjectName implements Comparable, QueryExp { * is null. */ private void construct(String name) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { // The name cannot be null if (name == null) @@ -435,10 +488,10 @@ public class ObjectName implements Comparable, QueryExp { } // 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 @@ public class ObjectName implements Comparable, QueryExp { // 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); @@ -674,7 +729,7 @@ public class ObjectName implements Comparable, QueryExp { * @exception NullPointerException One of the parameters is null. */ private void construct(String domain, Map props) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { // The domain cannot be null if (domain == null) @@ -725,12 +780,12 @@ public class ObjectName implements Comparable, QueryExp { 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 @@ public class ObjectName implements Comparable, QueryExp { 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] = ','; @@ -1016,7 +1071,7 @@ public class ObjectName implements Comparable, QueryExp { * Check if the supplied key is a valid key. */ private static void checkKey(String key) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { if (key == null) throw new NullPointerException("Invalid key (null)"); @@ -1031,33 +1086,6 @@ public class ObjectName implements Comparable, QueryExp { 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 @@ public class ObjectName implements Comparable, QueryExp { 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 @@ public class ObjectName implements Comparable, QueryExp { 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 @@ public class ObjectName implements Comparable, QueryExp { // Serializes this instance in the new serial form // out.defaultWriteObject(); - out.writeObject(getSerializedNameString()); + + out.writeObject(changeContext(ctxt,getSerializedNameString())); } } @@ -1295,9 +1359,10 @@ public class ObjectName implements Comparable, QueryExp { * @exception NullPointerException The name parameter * is null. * + * @see #valueOf(String) */ public static ObjectName getInstance(String name) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { return new ObjectName(name); } @@ -1322,10 +1387,11 @@ public class ObjectName implements Comparable, QueryExp { * follow the rules for quoting. * @exception NullPointerException One of the parameters is null. * + * @see #valueOf(String, String, String) */ public static ObjectName getInstance(String domain, String key, String value) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { return new ObjectName(domain, key, value); } @@ -1353,10 +1419,11 @@ public class ObjectName implements Comparable, QueryExp { * quoting. * @exception NullPointerException One of the parameters is null. * + * @see #valueOf(String, Hashtable) */ public static ObjectName getInstance(String domain, Hashtable table) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { return new ObjectName(domain, table); } @@ -1389,11 +1456,141 @@ public class ObjectName implements Comparable, QueryExp { * @exception NullPointerException The name is null. * */ - public static ObjectName getInstance(ObjectName name) - throws NullPointerException { + public static ObjectName getInstance(ObjectName name) { if (name.getClass().equals(ObjectName.class)) return name; - return Util.newObjectName(name.getSerializedNameString()); + return valueOf(name.getSerializedNameString()); + } + + /** + *

    Return an instance of ObjectName that can be used anywhere + * an object obtained with {@link #ObjectName(String) new + * ObjectName(name)} can be used. The returned object may be of + * a subclass of ObjectName. Calling this method twice with the + * same parameters may return the same object or two equal but + * not identical objects.

    + * + *

    This method is equivalent to {@link #getInstance(String)} except that + * it does not throw any checked exceptions.

    + * + * @param name A string representation of the object name. + * + * @return an ObjectName corresponding to the given String. + * + * @exception IllegalArgumentException The string passed as a + * parameter does not have the right format. The {@linkplain + * Throwable#getCause() cause} of this exception will be a + * {@link MalformedObjectNameException}. + * @exception NullPointerException The name parameter + * is null. + * + * @since 1.7 + */ + public static ObjectName valueOf(String name) { + try { + return getInstance(name); + } catch (MalformedObjectNameException e) { + throw new IllegalArgumentException(e.getMessage(), e); + // Just plain IllegalArgumentException(e) produces an exception + // message "javax.management.MalformedObjectNameException: ..." + // which is distracting. + } + } + + /** + *

    Return an instance of ObjectName that can be used anywhere + * an object obtained with {@link #ObjectName(String, String, + * String) new ObjectName(domain, key, value)} can be used. The + * returned object may be of a subclass of ObjectName. Calling + * this method twice with the same parameters may return the same + * object or two equal but not identical objects.

    + * + *

    This method is equivalent to {@link #getInstance(String, String, + * String)} except that it does not throw any checked exceptions.

    + * + * @param domain The domain part of the object name. + * @param key The attribute in the key property of the object name. + * @param value The value in the key property of the object name. + * + * @return an ObjectName corresponding to the given domain, + * key, and value. + * + * @exception IllegalArgumentException The + * domain, key, or value + * contains an illegal character, or value does not + * follow the rules for quoting. The {@linkplain + * Throwable#getCause() cause} of this exception will be a + * {@link MalformedObjectNameException}. + * @exception NullPointerException One of the parameters is null. + * + * @since 1.7 + */ + public static ObjectName valueOf(String domain, String key, String value) { + try { + return getInstance(domain, key, value); + } catch (MalformedObjectNameException e) { + throw new IllegalArgumentException(e.getMessage(), e); + } + } + + /** + *

    Return an instance of ObjectName that can be used anywhere + * an object obtained with {@link #ObjectName(String, Hashtable) + * new ObjectName(domain, table)} can be used. The returned + * object may be of a subclass of ObjectName. Calling this method + * twice with the same parameters may return the same object or + * two equal but not identical objects.

    + * + *

    This method is equivalent to {@link #getInstance(String, Hashtable)} + * except that it does not throw any checked exceptions.

    + * + * @param domain The domain part of the object name. + * @param table A hash table containing one or more key + * properties. The key of each entry in the table is the key of a + * key property in the object name. The associated value in the + * table is the associated value in the object name. + * + * @return an ObjectName corresponding to the given domain and + * key mappings. + * + * @exception IllegalArgumentException The domain + * contains an illegal character, or one of the keys or values in + * table contains an illegal character, or one of the + * values in table does not follow the rules for + * quoting. The {@linkplain Throwable#getCause() cause} of this exception + * will be a {@link MalformedObjectNameException}. + * @exception NullPointerException One of the parameters is null. + * + * @since 1.7 + */ + public static ObjectName valueOf(String domain, + Hashtable table) { + try { + return new ObjectName(domain, table); + } catch (MalformedObjectNameException e) { + throw new IllegalArgumentException(e.getMessage(), e); + } + } + + /** + * 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 MalformedObjectNameException { + return new ObjectName(newDomain, this); } /** @@ -1405,9 +1602,11 @@ public class ObjectName implements Comparable, QueryExp { * parameter does not have the right format. * @exception NullPointerException The name parameter * is null. + * + * @see #valueOf(String) */ public ObjectName(String name) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { construct(name); } @@ -1423,9 +1622,11 @@ public class ObjectName implements Comparable, QueryExp { * contains an illegal character, or value does not * follow the rules for quoting. * @exception NullPointerException One of the parameters is null. + * + * @see #valueOf(String, String, String) */ public ObjectName(String domain, String key, String value) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { // If key or value are null a NullPointerException // will be thrown by the put method in Hashtable. // @@ -1448,9 +1649,11 @@ public class ObjectName implements Comparable, QueryExp { * values in table does not follow the rules for * quoting. * @exception NullPointerException One of the parameters is null. + * + * @see #valueOf(String, Hashtable) */ public ObjectName(String domain, Hashtable table) - throws MalformedObjectNameException, NullPointerException { + throws MalformedObjectNameException { construct(domain, table); /* The exception for when a key or value in the table is not a String is now ClassCastException rather than @@ -1544,13 +1747,12 @@ public class ObjectName implements Comparable, QueryExp { * * @since 1.6 */ - public boolean isPropertyValuePattern(String property) - throws NullPointerException, IllegalArgumentException { + public boolean isPropertyValuePattern(String property) { if (property == null) 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); } @@ -1606,7 +1808,7 @@ public class ObjectName implements Comparable, QueryExp { * * @exception NullPointerException If property is null. */ - public String getKeyProperty(String property) throws NullPointerException { + public String getKeyProperty(String property) { return _getKeyPropertyList().get(property); } @@ -1630,8 +1832,10 @@ public class ObjectName implements Comparable, QueryExp { 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 +1920,8 @@ public class ObjectName implements Comparable, QueryExp { } } - return new String(dest_chars); + final String name = new String(dest_chars); + return name; } /** @@ -1734,7 +1939,7 @@ public class ObjectName implements Comparable, QueryExp { 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 +1947,7 @@ public class ObjectName implements Comparable, QueryExp { 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 +2021,7 @@ public class ObjectName implements Comparable, QueryExp { // (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 @@ -1862,8 +2067,7 @@ public class ObjectName implements Comparable, QueryExp { * @exception NullPointerException if s is null. * */ - public static String quote(String s) - throws NullPointerException { + public static String quote(String s) { final StringBuilder buf = new StringBuilder("\""); final int len = s.length(); for (int i = 0; i < len; i++) { @@ -1907,8 +2111,7 @@ public class ObjectName implements Comparable, QueryExp { * @exception NullPointerException if q is null. * */ - public static String unquote(String q) - throws IllegalArgumentException, NullPointerException { + public static String unquote(String q) { final StringBuilder buf = new StringBuilder(); final int len = q.length(); if (len < 2 || q.charAt(0) != '"' || q.charAt(len - 1) != '"') @@ -1953,7 +2156,7 @@ public class ObjectName implements Comparable, QueryExp { * * @since 1.6 */ - public static final ObjectName WILDCARD = Util.newObjectName("*:*"); + public static final ObjectName WILDCARD = valueOf("*:*"); // Category : Utilities <=================================== @@ -1976,7 +2179,7 @@ public class ObjectName implements Comparable, QueryExp { * @exception NullPointerException if name is null. * */ - public boolean apply(ObjectName name) throws NullPointerException { + public boolean apply(ObjectName name) { if (name == null) throw new NullPointerException(); @@ -1997,9 +2200,9 @@ public class ObjectName implements Comparable, QueryExp { 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 +2228,7 @@ public class ObjectName implements Comparable, QueryExp { // 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 +2237,13 @@ public class ObjectName implements Comparable, QueryExp { // 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 +2310,10 @@ public class ObjectName implements Comparable, QueryExp { * @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 --git a/src/share/classes/javax/management/QueryNotificationFilter.java b/src/share/classes/javax/management/QueryNotificationFilter.java index 42451088f2ede0a0ad8bc72c99472ae0e18ab0fa..7d1990fa2b9e1d703f57428aad47d37cd91fdb11 100644 --- a/src/share/classes/javax/management/QueryNotificationFilter.java +++ b/src/share/classes/javax/management/QueryNotificationFilter.java @@ -170,7 +170,7 @@ public class QueryNotificationFilter implements NotificationFilter { private static final long serialVersionUID = -8408613922660635231L; private static final ObjectName DEFAULT_NAME = - Util.newObjectName(":type=Notification"); + ObjectName.valueOf(":type=Notification"); private static final QueryExp trueQuery; static { ValueExp zero = Query.value(0); diff --git a/src/share/classes/javax/management/event/EventClient.java b/src/share/classes/javax/management/event/EventClient.java index 923ef90cd2f87cc6ccc351cf3fc5532e50b392ee..10a4df5004bcbbf7e09b0b96f7dd6035cb307be5 100644 --- a/src/share/classes/javax/management/event/EventClient.java +++ b/src/share/classes/javax/management/event/EventClient.java @@ -29,6 +29,7 @@ import com.sun.jmx.event.DaemonThreadFactory; 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; @@ -263,11 +264,12 @@ public class EventClient implements EventConsumer, NotificationManager { new PerThreadGroupPool.Create() { public ScheduledThreadPoolExecutor createThreadPool(ThreadGroup group) { ThreadFactory daemonThreadFactory = new DaemonThreadFactory( - "EventClient lease renewer %d"); + "JMX EventClient lease renewer %d"); ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor( 20, daemonThreadFactory); - exec.setKeepAliveTime(3, TimeUnit.SECONDS); + exec.setKeepAliveTime(1, TimeUnit.SECONDS); exec.allowCoreThreadTimeOut(true); + exec.setRemoveOnCancelPolicy(true); return exec; } }; @@ -1063,6 +1065,24 @@ public class EventClient implements EventConsumer, NotificationManager { 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 --git a/src/share/classes/javax/management/event/EventClientDelegate.java b/src/share/classes/javax/management/event/EventClientDelegate.java index e5ce1f7be74b123c54b39c645574d53e12d1452c..cab3ff49238d5a4feeec540ec127f29a045a2bac 100644 --- a/src/share/classes/javax/management/event/EventClientDelegate.java +++ b/src/share/classes/javax/management/event/EventClientDelegate.java @@ -721,7 +721,10 @@ public class EventClientDelegate implements EventClientDelegateMBean { SecurityManager sm = System.getSecurityManager(); if (sm != null) { try { - ObjectInstance oi = (ObjectInstance) AccessController.doPrivileged( + final String serverName = getMBeanServerName(); + + ObjectInstance oi = (ObjectInstance) + AccessController.doPrivileged( new PrivilegedExceptionAction() { public Object run() throws InstanceNotFoundException { @@ -731,6 +734,7 @@ public class EventClientDelegate implements EventClientDelegateMBean { String classname = oi.getClassName(); MBeanPermission perm = new MBeanPermission( + serverName, classname, null, name, @@ -746,6 +750,20 @@ public class EventClientDelegate implements EventClientDelegateMBean { return true; } + private String getMBeanServerName() { + if (mbeanServerName != null) return mbeanServerName; + else return (mbeanServerName = getMBeanServerName(mbeanServer)); + } + + private static String getMBeanServerName(final MBeanServer server) { + final PrivilegedAction action = new PrivilegedAction() { + public String run() { + return Util.getMBeanServerSecurityName(server); + } + }; + return AccessController.doPrivileged(action); + } + // ------------------------------------ // private variables // ------------------------------------ diff --git a/src/share/classes/javax/management/event/EventClientDelegateMBean.java b/src/share/classes/javax/management/event/EventClientDelegateMBean.java index ba57cce9cb28521e0507f6b4965cc56837fc021c..7c0b3107cc4a64fa564cf6e0c606e7ae5833d60c 100644 --- a/src/share/classes/javax/management/event/EventClientDelegateMBean.java +++ b/src/share/classes/javax/management/event/EventClientDelegateMBean.java @@ -96,7 +96,7 @@ public interface EventClientDelegateMBean { * {@value #OBJECT_NAME_STRING}. */ public final static ObjectName OBJECT_NAME = - Util.newObjectName(OBJECT_NAME_STRING); + ObjectName.valueOf(OBJECT_NAME_STRING); /** * A unique listener identifier specified for an EventClient. diff --git a/src/share/classes/javax/management/event/EventSubscriber.java b/src/share/classes/javax/management/event/EventSubscriber.java index 2426345550f34a29dd98dea2ead9f716bbecafca..9948810bfeb52e03fcb40b8c06005014c19d7b53 100644 --- a/src/share/classes/javax/management/event/EventSubscriber.java +++ b/src/share/classes/javax/management/event/EventSubscriber.java @@ -149,10 +149,10 @@ public class EventSubscriber implements EventConsumer { if (listener == null) throw new IllegalArgumentException("Null listener"); - final ListenerInfo li = new ListenerInfo(listener, filter, handback); - List list; + final MyListenerInfo li = new MyListenerInfo(listener, filter, handback); + List list; - Map> map; + Map> map; Set names; if (name.isPattern()) { map = patternSubscriptionMap; @@ -165,7 +165,7 @@ public class EventSubscriber implements EventConsumer { synchronized (map) { list = map.get(name); if (list == null) { - list = new ArrayList(); + list = new ArrayList(); map.put(name, list); } list.add(li); @@ -186,7 +186,6 @@ public class EventSubscriber implements EventConsumer { public void unsubscribe(ObjectName name, NotificationListener listener) throws ListenerNotFoundException, IOException { - if (logger.traceOn()) logger.trace("unsubscribe", "" + name); @@ -196,7 +195,7 @@ public class EventSubscriber implements EventConsumer { if (listener == null) throw new ListenerNotFoundException(); - Map> map; + Map> map; Set names; if (name.isPattern()) { @@ -207,22 +206,39 @@ public class EventSubscriber implements EventConsumer { names = Collections.singleton(name); } - final ListenerInfo li = new ListenerInfo(listener, null, null); - List list; + List toRemove = new ArrayList(); synchronized (map) { - list = map.get(name); - if (list == null || !list.remove(li)) + List list = map.get(name); + if (list == null) { + throw new ListenerNotFoundException(); + } + + for (MyListenerInfo info : list) { + if (info.listener == listener) { + toRemove.add(info); + } + } + + if (toRemove.isEmpty()) { throw new ListenerNotFoundException(); + } + + for (MyListenerInfo info : toRemove) { + list.remove(info); + } if (list.isEmpty()) map.remove(name); } for (ObjectName mbeanName : names) { - try { - mbeanServer.removeNotificationListener(mbeanName, li.listener); - } catch (Exception e) { - logger.fine("unsubscribe", "removeNotificationListener", e); + for (MyListenerInfo i : toRemove) { + try { + mbeanServer.removeNotificationListener(mbeanName, + i.listener, i.filter, i.handback); + } catch (Exception e) { + logger.fine("unsubscribe", "removeNotificationListener", e); + } } } } @@ -256,12 +272,12 @@ public class EventSubscriber implements EventConsumer { return; } - final List listeners = new ArrayList(); + final List listeners = new ArrayList(); // If there are subscribers for the exact name that has just arrived // then add their listeners to the list. synchronized (exactSubscriptionMap) { - List exactListeners = exactSubscriptionMap.get(name); + List exactListeners = exactSubscriptionMap.get(name); if (exactListeners != null) listeners.addAll(exactListeners); } @@ -277,7 +293,7 @@ public class EventSubscriber implements EventConsumer { } // Add all the listeners just found to the new MBean. - for (ListenerInfo li : listeners) { + for (MyListenerInfo li : listeners) { try { mbeanServer.addNotificationListener( name, @@ -292,12 +308,12 @@ public class EventSubscriber implements EventConsumer { } }; - private static class ListenerInfo { + private static class MyListenerInfo { public final NotificationListener listener; public final NotificationFilter filter; public final Object handback; - public ListenerInfo(NotificationListener listener, + public MyListenerInfo(NotificationListener listener, NotificationFilter filter, Object handback) { @@ -308,26 +324,6 @@ public class EventSubscriber implements EventConsumer { 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); - } - - @Override - public int hashCode() { - return listener.hashCode(); - } } // --------------------------------- @@ -338,10 +334,10 @@ public class EventSubscriber implements EventConsumer { // --------------------------------- private final MBeanServer mbeanServer; - private final Map> exactSubscriptionMap = - new HashMap>(); - private final Map> patternSubscriptionMap = - new HashMap>(); + private final Map> exactSubscriptionMap = + new HashMap>(); + private final Map> patternSubscriptionMap = + new HashMap>(); diff --git a/src/share/classes/javax/management/event/FetchingEventRelay.java b/src/share/classes/javax/management/event/FetchingEventRelay.java index 2b65f9b12d6b8f14d7dae1847c44816c502240b8..9aa68df0fe188dbbea0649483e30834ae2140469 100644 --- a/src/share/classes/javax/management/event/FetchingEventRelay.java +++ b/src/share/classes/javax/management/event/FetchingEventRelay.java @@ -31,10 +31,8 @@ import com.sun.jmx.remote.util.ClassLogger; import java.io.IOException; import java.io.NotSerializableException; import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import javax.management.MBeanException; @@ -215,50 +213,47 @@ public class FetchingEventRelay implements EventRelay { this.maxNotifs = maxNotifs; if (executor == null) { - executor = Executors.newSingleThreadScheduledExecutor( + ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor(1, daemonThreadFactory); - } + stpe.setKeepAliveTime(1, TimeUnit.SECONDS); + stpe.allowCoreThreadTimeOut(true); + executor = stpe; + this.defaultExecutor = stpe; + } else + this.defaultExecutor = null; this.executor = executor; - if (executor instanceof ScheduledExecutorService) - leaseScheduler = (ScheduledExecutorService) executor; - else { - leaseScheduler = Executors.newSingleThreadScheduledExecutor( - daemonThreadFactory); - } startSequenceNumber = 0; fetchingJob = new MyJob(); } - public void setEventReceiver(EventReceiver eventReceiver) { + public synchronized void setEventReceiver(EventReceiver eventReceiver) { if (logger.traceOn()) { logger.trace("setEventReceiver", ""+eventReceiver); } EventReceiver old = this.eventReceiver; - synchronized(fetchingJob) { - this.eventReceiver = eventReceiver; - if (old == null && eventReceiver != null) - fetchingJob.resume(); - } + this.eventReceiver = eventReceiver; + if (old == null && eventReceiver != null) + fetchingJob.resume(); } public String getClientId() { return clientId; } - public void stop() { + public synchronized void stop() { if (logger.traceOn()) { logger.trace("stop", ""); } - synchronized(fetchingJob) { - if (stopped) { - return; - } - - stopped = true; - clientId = null; + if (stopped) { + return; } + + stopped = true; + clientId = null; + if (defaultExecutor != null) + defaultExecutor.shutdown(); } private class MyJob extends RepeatedSingletonJob { @@ -372,10 +367,9 @@ public class FetchingEventRelay implements EventRelay { private final EventClientDelegateMBean delegate; private String clientId; private boolean stopped = false; - private volatile ScheduledFuture leaseRenewalFuture; private final Executor executor; - private final ScheduledExecutorService leaseScheduler; + private final ExecutorService defaultExecutor; private final MyJob fetchingJob; private final long timeout; @@ -385,5 +379,5 @@ public class FetchingEventRelay implements EventRelay { new ClassLogger("javax.management.event", "FetchingEventRelay"); private static final ThreadFactory daemonThreadFactory = - new DaemonThreadFactory("FetchingEventRelay-executor"); + new DaemonThreadFactory("JMX FetchingEventRelay executor %d"); } diff --git a/src/share/classes/javax/management/event/RMIPushEventForwarder.java b/src/share/classes/javax/management/event/RMIPushEventForwarder.java index 2018f98adfce657ef4607ee1c526727abb608972..751300d5443f5a03163db6b98dd53bded1b73f2b 100644 --- a/src/share/classes/javax/management/event/RMIPushEventForwarder.java +++ b/src/share/classes/javax/management/event/RMIPushEventForwarder.java @@ -185,7 +185,7 @@ public class RMIPushEventForwarder implements EventForwarder { private static final ExecutorService executor = Executors.newCachedThreadPool( - new DaemonThreadFactory("RMIEventForwarder Executor")); + new DaemonThreadFactory("JMX RMIEventForwarder Executor")); private final SendingJob sendingJob = new SendingJob(); private final BlockingQueue buffer; diff --git a/src/share/classes/javax/management/namespace/JMXDomain.java b/src/share/classes/javax/management/namespace/JMXDomain.java new file mode 100644 index 0000000000000000000000000000000000000000..bff3c1370624db19ab97825f470253407c1d00c2 --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXDomain.java @@ -0,0 +1,382 @@ +/* + * 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.ListenerNotFoundException; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR; + + +import javax.management.InstanceNotFoundException; +import javax.management.MBeanServer; +import javax.management.MBeanServerDelegate; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +/** + * A special {@link JMXNamespace} that can handle part of + * the MBeanServer local name space. + *

    + * A {@code JMXDomain} makes a domain X of a + * {@linkplain #getSourceServer() source MBean server} appear in the same domain + * X of a containing {@code MBeanServer} in which the + * {@code JMXDomain} MBean {@linkplain #getMBeanServer() is registered}. + *

    + *

    + * The JMX infrastructure of the containing {@code MBeanServer} takes care of + * routing all calls to MBeans whose names have domain X to the + * {@linkplain #getSourceServer() source MBean server} exported by the + * {@code JMXDomain} MBean in charge of domain X. + *

    + *

    + * The {@linkplain #getSourceServer() source MBean server} of a {@code JMXDomain} + * can, but need not be a regular {@code MBeanServer} created through + * the {@link javax.management.MBeanServerFactory}. It could also be, + * for instance, an instance of a subclass of {@link MBeanServerSupport}, + * or a custom object implementing the {@link MBeanServer} interface. + *

    + * + *

    Differences between {@code JMXNamespace} and {@code JMXDomain}

    + * + *

    + * A {@code JMXDomain} is a special kind of {@code JMXNamespace}. + * A {@code JMXNamespace} such as {@code foo//} is triggered by an + * {@code ObjectName} that begins with the string {@code foo//}, for example + * {@code foo//bar:type=Baz}. A {@code JMXDomain} such as {@code foo} is + * triggered by an {@code ObjectName} with that exact domain, for example + * {@code foo:type=Baz}. A client can immediately see that an MBean is + * handled by a {@code JMXNamespace} because of the {@code //} in the name. + * A client cannot see whether a name such as {@code foo:type=Baz} is an + * ordinary MBean or is handled by a {@code JMXDomain}. + *

    + * + *

    + * A {@linkplain MBeanServer#queryNames query} on the containing {@code + * MBeanserver} will return all MBeans from the {@code JMXDomain} that match + * the query. In particular, {@code queryNames(null, null)} will return all + * MBeans including those from {@code JMXDomain} domains. On the other hand, + * a query will not include MBeans from a {@code JMXNamespace} unless the + * {@code ObjectName} pattern in the query starts with the name of that + * namespace. + *

    + * + *

    Permission checks

    + * + *

    + * When a JMXDomain MBean is registered in a containing + * MBean server created through the default {@link + * javax.management.MBeanServerBuilder}, and if a {@link + * SecurityManager SecurityManager} is + * {@linkplain System#getSecurityManager() present}, the containing MBeanServer will + * check an {@link javax.management.MBeanPermission} before invoking + * any method on the {@linkplain #getSourceServer() source MBeanServer} of the + * JMXDomain. + *

    + * + *

    First, if there is no security manager ({@link + * System#getSecurityManager()} is null), that containing + * {@code MBeanServer} is free not to make any checks. + *

    + * + *

    + * Assuming that there is a security manager, or that the + * implementation chooses to make checks anyway, the containing + * {@code MBeanServer} will perform + * {@link javax.management.MBeanPermission MBeanPermission} checks + * for access to the MBeans in domain X handled by a {@code JMXDomain} + * in the same way that it would do for MBeans registered in its own local + * repository, and as described in + * the MBeanServer interface, with the following exceptions: + *

    + * + *

    + * For those permissions that require a {@code className}, the + * className is the + * string returned by {@link #getSourceServer() getSourceServer()}. + * {@link MBeanServer#getObjectInstance(ObjectName) + * getObjectInstance(mbeanName)}. + * {@link javax.management.ObjectInstance#getClassName() getClassName()}, + * except for {@code createMBean} and {@code registerMBean} operations, + * for which the permission checks are performed as follows: + *

    + *
      + *
    • For {@code createMBean} operations, the {@code className} of the + * permission you need is the {@code className} passed as first parameter + * to {@code createMBean}.

      + * + *
    • For {@code registerMBean} operations, the {@code className} of the + * permission you need is the name of the class of the mbean object, as + * returned by {@code mbean.getClass().getClassName()}, where + * {@code mbean} is the mbean reference passed as first parameter + * to {@code registerMBean}.

      + * + *
    • In addition, for {@code createMBean} and {@code registerMBean}, the + * permission you need is checked with the {@linkplain ObjectName object name} of + * the mbean that is passed as second parameter to the {@code createMBean} or + * {@code registerMBean} operation. + *

      + * + *
    • Contrarily to what is done for regular MBeans registered in the + * MBeanServer local repository, the containing MBeanServer will not + * check the {@link javax.management.MBeanTrustPermission#MBeanTrustPermission(String) + * MBeanTrustPermission("register")} against the protection domain + * of the MBean's class. This check can be performed by the + * {@linkplain #getSourceServer source MBean server} implementation, + * if necessary. + *

      + *
    + * + *

    If a security check fails, the method throws {@link + * SecurityException}.

    + * + *

    For methods that can throw {@link InstanceNotFoundException}, + * this exception is thrown for a non-existent MBean, regardless of + * permissions. This is because a non-existent MBean has no + * className.

    + * + * All these checks are performed by the containing {@code MBeanServer}, + * before accessing the JMXDomain {@linkplain #getSourceServer source MBean server}. + * The implementation of the JMXDomain {@linkplain #getSourceServer source MBean + * server} is free to make any additional checks. In fact, if the JMXDomain + * {@linkplain #getSourceServer source MBean server} is an {@code MBeanServer} + * obtained through the {@link javax.management.MBeanServerFactory}, it will + * again make permission checks as described in the + * MBeanServer interface. + * + *

    See the MBeanServer interface + * for more details on permission checks.

    + * + * @since 1.7 + */ +public class JMXDomain extends JMXNamespace { + + + /** + * This constant contains the value of the {@code type} + * key used in defining a standard JMXDomain MBean object name. + * By definition, a standard JMXDomain MBean object name must be of + * the form: + *
    +     * {@code ":"}+{@value javax.management.namespace.JMXDomain#TYPE_ASSIGNMENT}
    +     * 
    + */ + public static final String TYPE = "JMXDomain"; + + /** + * This constant contains the value of the standard + * {@linkplain javax.management.ObjectName#getKeyPropertyListString() key + * property list string} for JMXDomain MBean object names. + * By definition, a standard JMXDomain MBean object name must be of + * the form: + *
    +     * {@code }+":"+{@value javax.management.namespace.JMXDomain#TYPE_ASSIGNMENT}
    +     * 
    + */ + public static final String TYPE_ASSIGNMENT = "type="+TYPE; + + + + /** + * Creates a new instance of JMXDomain. The MBeans contained in this + * domain are handled by the {@code virtualServer} object given to + * this constructor. Frequently, this will be an instance of + * {@link MBeanServerSupport}. + * @param virtualServer The virtual server that acts as a container for + * the MBeans handled by this JMXDomain object. Frequently, this will + * be an instance of {@link MBeanServerSupport} + * @see JMXNamespace#JMXNamespace(MBeanServer) + */ + public JMXDomain(MBeanServer virtualServer) { + super(virtualServer); + } + + /** + * Return the name of domain handled by this JMXDomain. + * @return the domain handled by this JMXDomain. + * @throws IOException - if the domain cannot be determined, + * for instance, if the MBean is not registered yet. + */ + @Override + public final String getDefaultDomain() { + final ObjectName name = getObjectName(); + if (name == null) + throw new IllegalStateException("DefaultDomain is not yet known"); + final String dom = name.getDomain(); + return dom; + } + + /** + * Returns a singleton array, containing the only domain handled by + * this JMXDomain object. This is + * {@code new String[] {getDefaultDomain()}}. + * @return the only domain handled by this JMXDomain. + * @throws IOException if the domain cannot be determined, + * for instance, if the MBean is not registered yet. + * @see #getDefaultDomain() + */ + @Override + public final String[] getDomains() { + return new String[] {getDefaultDomain()}; + } + + /** + * This method returns the number of MBeans in the domain handled + * by this JMXDomain object. The default implementation is: + *
    +     *    getSourceServer().queryNames(
    +     *        new ObjectName(getObjectName().getDomain()+":*"), null).size();
    +     * 
    + * If this JMXDomain is not yet registered, this method returns 0. + * Subclasses can override the above behavior and provide a better + * implementation. + *

    + * The getMBeanCount() method is called when computing the number + * of MBeans in the {@linkplain #getMBeanServer() containing MBeanServer}. + * @return the number of MBeans in this domain, or 0. + */ + @Override + public Integer getMBeanCount() { + final ObjectName name = getObjectName(); + if (name == null) return 0; + try { + return getSourceServer(). + queryNames(ObjectName.WILDCARD.withDomain(name.getDomain()), + null).size(); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException("Unexpected exception: "+x,x); + } + } + + + + /** + * Return a canonical handler name for the provided local + * domain name, or null if the provided domain name is + * {@code null}. + * If not null, the handler name returned will be + * {@code domain+":type="+}{@link #TYPE TYPE}, for example + * {@code foo:type=JMXDomain}. + * @param domain A domain name + * @return a canonical ObjectName for a domain handler. + * @throws IllegalArgumentException if the provided + * domain is not valid - e.g it contains "//". + */ + public static ObjectName getDomainObjectName(String domain) { + if (domain == null) return null; + if (domain.contains(NAMESPACE_SEPARATOR)) + throw new IllegalArgumentException(domain); + try { + return ObjectName.getInstance(domain, "type", TYPE); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(domain,x); + } + } + + + /** + * 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. + **/ + @Override + ObjectName validateHandlerName(ObjectName suppliedName) { + if (suppliedName == null) + throw new IllegalArgumentException("Must supply a valid name"); + final String dirName = JMXNamespaces. + normalizeNamespaceName(suppliedName.getDomain()); + final ObjectName handlerName = getDomainObjectName(dirName); + if (!suppliedName.equals(handlerName)) + throw new IllegalArgumentException("invalid name space name: "+ + suppliedName); + + return suppliedName; + } + + /** + * This method is called by the JMX framework to register a + * NotificationListener that will forward {@linkplain + * javax.management.MBeanServerNotification mbean server notifications} + * through the delegate of the {@linkplain #getMBeanServer() + * containing MBeanServer}. + * The default implementation of this method is to call + *

    +     *    getSourceServer().addNotificationListener(
    +     *           MBeanServerDelegate.DELEGATE_NAME, listener, filter, null);
    +     * 
    + * Subclasses can redefine this behavior if needed. In particular, + * subclasses can send their own instances of {@link + * javax.management.MBeanServerNotification} by calling + * {@code listener.handleNotification()}. + * + * @param listener The MBeanServerNotification listener for this domain. + * @param filter A notification filter. + */ + public void addMBeanServerNotificationListener( + NotificationListener listener, NotificationFilter filter) { + try { + getSourceServer().addNotificationListener( + MBeanServerDelegate.DELEGATE_NAME, listener, filter, null); + } catch(InstanceNotFoundException x) { + throw new UnsupportedOperationException( + "Unexpected exception: " + + "Emission of MBeanServerNotification disabled.", x); + } + } + + /** + * This method is called by the JMX framework to remove the + * NotificationListener that was added with {@link + * #addMBeanServerNotificationListener addMBeanServerNotificationListener}. + * The default implementation of this method is to call + *
    +     *    getSourceServer().removeNotificationListener(
    +     *           MBeanServerDelegate.DELEGATE_NAME, listener);
    +     * 
    + * Subclasses can redefine this behavior if needed. + * + * @param listener The MBeanServerNotification listener for this domain. + * @throws ListenerNotFoundException if the listener is not found. + */ + public void removeMBeanServerNotificationListener( + NotificationListener listener) + throws ListenerNotFoundException { + try { + getSourceServer().removeNotificationListener( + MBeanServerDelegate.DELEGATE_NAME, listener); + } catch(InstanceNotFoundException x) { + throw new UnsupportedOperationException( + "Unexpected exception: " + + "Emission of MBeanServerNotification disabled.", x); + } + } + +} diff --git a/src/share/classes/javax/management/namespace/JMXNamespace.java b/src/share/classes/javax/management/namespace/JMXNamespace.java new file mode 100644 index 0000000000000000000000000000000000000000..23f3004ebe5dce2d0619c28dbb0d5d281d4b83a2 --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXNamespace.java @@ -0,0 +1,666 @@ +/* + * 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; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +/** + * MBean Servers can be federated into a single hierarchical name space: + * A JMXNamespace is an MBean that handles a sub name space in that + * hierarchical name space. + *

    + * A name space is created simply by registering a {@code JMXNamespace} + * MBean in the MBean Server. The name of the created name space is defined + * by the {@linkplain JMXNamespaces#getNamespaceObjectName name of the JMXNamespace} + * that handles it. A name space is equivalent to + * an MBean Server within an MBean Server. When creating a {@code JMXNamespace}, + * the MBean Server within is passed to the constructor. + *

    + *

    + * The {@code JMXNamespace} class is the base class for implementing + * all name space handlers. All name space handlers must be instances of + * {@code JMXNamespace} or a subclass of it. + *

    + *

    + * A concrete example of a {@code JMXNamespace} MBean subclass + * is the {@link JMXRemoteNamespace JMXRemoteNamespace} MBean which + * is able to mirror all MBeans contained in a remote MBean server known by its + * {@link javax.management.remote.JMXServiceURL}. + *

    + *

    + * You can create a local namespace by supplying a newly created MBean Server + * to an instance of {@code JMXNamespace}. For instance: + *

    + * final String namespace = "foo";
    + * final ObjectName namespaceName = {@link JMXNamespaces#getNamespaceObjectName
    + *       JMXNamespaces.getNamespaceObjectName(namespace)};
    + * server.registerMBean(new JMXNamespace(MBeanServerFactory.newMBeanServer()),
    + *                      namespaceName);
    + * 
    + *

    + *

    + * 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: + *

    + *
      + *
    1. + * 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"}) + *
    2. + *
    3. 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"}), + *
    4. + *
    5. 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"}), + *
    6. + *
    7. 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))}). + *
    8. + *
    + *

    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 reference to the MBean server in which it is + * registered. It also checks 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 { + // need to synchronize to protect against multiple registration. + synchronized(this) { + 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 suppliedName) { + if (suppliedName == null) + throw new IllegalArgumentException("Must supply a valid name"); + final String dirName = JMXNamespaces. + normalizeNamespaceName(suppliedName.getDomain()); + final ObjectName handlerName = + JMXNamespaces.getNamespaceObjectName(dirName); + if (!suppliedName.equals(handlerName)) + throw new IllegalArgumentException("invalid name space name: "+ + suppliedName); + return suppliedName; + } + + /** + * This method is part of the {@link MBeanRegistration} interface. + * The {@link JMXNamespace} class uses the {@link MBeanRegistration} + * interface in order to get a reference 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 reference 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() { + // need to synchronize to protect against multiple registration. + synchronized(this) { + 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 --git a/src/share/classes/javax/management/namespace/JMXNamespaceMBean.java b/src/share/classes/javax/management/namespace/JMXNamespaceMBean.java new file mode 100644 index 0000000000000000000000000000000000000000..4632b410ae756b7d7e3206a4eb42ed1c028af034 --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXNamespaceMBean.java @@ -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 --git a/src/share/classes/javax/management/namespace/JMXNamespacePermission.java b/src/share/classes/javax/management/namespace/JMXNamespacePermission.java new file mode 100644 index 0000000000000000000000000000000000000000..5dd012672b3ba2afe86057ea36c68f3fe9b8bcb0 --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXNamespacePermission.java @@ -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."}. + *

    + *

    Depending on how your namespace hierarchy + * is defined some of these wildcard permission names can be useful:

    + *
    + *    // 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:

    + *
      + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
      patternmatchesdoesn't match
      **//D:k=va//D:k=v
      + * a//b//D:k=v
      + * a//b//c//D:k=v
      D:k=v
      a//**//D:k=va//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=va//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=va//b//e//D:k=va//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 --git a/src/share/classes/javax/management/namespace/JMXNamespaceView.java b/src/share/classes/javax/management/namespace/JMXNamespaceView.java new file mode 100644 index 0000000000000000000000000000000000000000..eacc0f4bce76a16992211a9794822a0271c5fba2 --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXNamespaceView.java @@ -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 --git a/src/share/classes/javax/management/namespace/JMXNamespaces.java b/src/share/classes/javax/management/namespace/JMXNamespaces.java new file mode 100644 index 0000000000000000000000000000000000000000..429a9d466d6175a2f56e0f5b4d7c74d2b7fb8211 --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXNamespaces.java @@ -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.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 { + // We could use Util.newObjectName here - but throwing an + // IllegalArgumentException that contains just the supplied + // namespace instead of the whole ObjectName seems preferable. + return ObjectName.getInstance(sourcePath+ + NAMESPACE_SEPARATOR+":"+ + JMXNamespace.TYPE_ASSIGNMENT); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException("Invalid namespace: " + + 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 --git a/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java b/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java new file mode 100644 index 0000000000000000000000000000000000000000..6958f57f2d72db7a17c99e2acb93fb058c33b1f3 --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java @@ -0,0 +1,734 @@ +/* + * 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.remote.util.EnvHelp; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; +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.MBeanServerConnection; +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; + + + // 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 class ConnectionListener implements NotificationListener { + private ConnectionListener() { + } + public void handleNotification(Notification notification, + Object handback) { + if (!(notification instanceof JMXConnectionNotification)) + return; + final JMXConnectionNotification cn = + (JMXConnectionNotification)notification; + final String type = cn.getType(); + if (JMXConnectionNotification.CLOSED.equals(type) + || JMXConnectionNotification.FAILED.equals(type)) { + 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 { + 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; + + } + + } + + private static final MBeanNotificationInfo connectNotification = + new MBeanNotificationInfo(new String[] { + AttributeChangeNotification.ATTRIBUTE_CHANGE}, + "Connected", + "Emitted when the Connected state of this object changes"); + + private static AtomicLong seqNumber = new AtomicLong(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; + + /** + * 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(); + } + + /** + * 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; + } + + 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 long getNextSeqNumber() { + return seqNumber.getAndIncrement(); + } + + + /** + * 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. The 'emittingConnector' is the connector from which the + // notification originated. This could be an 'old' connector - as + // closed() and connect() could already have been called before the + // notification arrived. So what we do is to compare the + // 'emittingConnector' with the current connector, to see if the + // notification actually comes from the curent connector. + // + 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 close(JMXConnector c) { + 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 { + LOG.fine("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) { + close(aconn); + throw io; + } catch (RuntimeException x) { + close(aconn); + throw x; + } + + switchConnection(conn,aconn,msc); + + LOG.fine("connected."); + } + + 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 --git a/src/share/classes/javax/management/namespace/JMXRemoteNamespaceMBean.java b/src/share/classes/javax/management/namespace/JMXRemoteNamespaceMBean.java new file mode 100644 index 0000000000000000000000000000000000000000..18b0fb86dfeeb4ecda2e8e69d24eb88f2887446e --- /dev/null +++ b/src/share/classes/javax/management/namespace/JMXRemoteNamespaceMBean.java @@ -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 --git a/src/share/classes/javax/management/namespace/MBeanServerConnectionWrapper.java b/src/share/classes/javax/management/namespace/MBeanServerConnectionWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..7eeda961e31756773b635df5aa45fb44c2fc3207 --- /dev/null +++ b/src/share/classes/javax/management/namespace/MBeanServerConnectionWrapper.java @@ -0,0 +1,702 @@ +/* + * 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.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 --git a/src/share/classes/com/sun/jmx/interceptor/MBeanServerSupport.java b/src/share/classes/javax/management/namespace/MBeanServerSupport.java similarity index 98% rename from src/share/classes/com/sun/jmx/interceptor/MBeanServerSupport.java rename to src/share/classes/javax/management/namespace/MBeanServerSupport.java index e7144cf36e19da7cf16adf628e8c7dd7f3434a32..903be3c308f1029a76777a1cbb18efa7a0de2a92 100644 --- a/src/share/classes/com/sun/jmx/interceptor/MBeanServerSupport.java +++ b/src/share/classes/javax/management/namespace/MBeanServerSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * 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 @@ -22,8 +22,9 @@ * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ -package com.sun.jmx.interceptor; +package javax.management.namespace; +import com.sun.jmx.defaults.JmxProperties; import com.sun.jmx.mbeanserver.Util; import java.io.ObjectInputStream; import java.util.Collections; @@ -47,7 +48,6 @@ import javax.management.MBeanException; import javax.management.MBeanInfo; import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.management.NotificationBroadcaster; import javax.management.NotificationEmitter; @@ -193,14 +193,6 @@ import javax.management.loading.ClassLoaderRepository; * } * * 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; * @@ -219,7 +211,7 @@ import javax.management.loading.ClassLoaderRepository; * throws InstanceNotFoundException { * * // Check that the name is a legal one for a Property MBean - * ObjectName namePattern = newObjectName( + * ObjectName namePattern = ObjectName.valueOf( * "com.example:type=Property,name=\"*\""); * if (!namePattern.apply(name)) * throw new InstanceNotFoundException(name); @@ -239,7 +231,7 @@ import javax.management.loading.ClassLoaderRepository; * {@code Set names = new TreeSet();} * Properties props = System.getProperties(); * for (String propName : props.stringPropertyNames()) { - * ObjectName objectName = newObjectName( + * ObjectName objectName = ObjectName.valueOf( * "com.example:type=Property,name=" + * ObjectName.quote(propName)); * names.add(objectName); @@ -278,7 +270,7 @@ import javax.management.loading.ClassLoaderRepository; * } * * public void propertyChanged(String name, String newValue) { - * ObjectName objectName = newObjectName( + * ObjectName objectName = ObjectName.valueOf( * "com.example:type=Property,name=" + ObjectName.quote(name)); * Notification n = new Notification( * "com.example.property.changed", objectName, 0L, @@ -343,7 +335,7 @@ import javax.management.loading.ClassLoaderRepository; * vem.publish}(name, n). See the example * above.

    * - * @since Java SE 7 + * @since 1.7 */ public abstract class MBeanServerSupport implements MBeanServer { @@ -351,7 +343,7 @@ public abstract class MBeanServerSupport implements MBeanServer { * A logger for this class. */ private static final Logger LOG = - Logger.getLogger(MBeanServerSupport.class.getName()); + JmxProperties.NAMESPACE_LOGGER; /** *

    Make a new {@code MBeanServerSupport} instance.

    @@ -1314,9 +1306,7 @@ public abstract class MBeanServerSupport implements MBeanServer { 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()); + name = name.withDomain(getDefaultDomain()); } catch (Exception e) { throw newIllegalArgumentException( "Illegal default domain: " + defaultDomain); diff --git a/src/share/classes/javax/management/namespace/VirtualEventManager.java b/src/share/classes/javax/management/namespace/VirtualEventManager.java new file mode 100644 index 0000000000000000000000000000000000000000..336f37565cba35728219ba18a5b53edda1415845 --- /dev/null +++ b/src/share/classes/javax/management/namespace/VirtualEventManager.java @@ -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 --git a/src/share/classes/javax/management/namespace/package-info.java b/src/share/classes/javax/management/namespace/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..df8354bab635379c29f3340676192c2c1b0a5238 --- /dev/null +++ b/src/share/classes/javax/management/namespace/package-info.java @@ -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: + *

    + *
      + *
    1. + * You can use the {@link javax.management.namespace.JMXNamespaceView} + * class shown above, + *
    2. + *
    3. + * or you can directly look for MBeans + * whose names match + * {@code "foo//*:*"}, + *
    4. + *
    5. + * 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}. + *
    6. + *
    + * + *

    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 --git a/src/share/classes/javax/management/openmbean/CompositeType.java b/src/share/classes/javax/management/openmbean/CompositeType.java index b513b0faa9af1aaae461d123ab53c81d9b122388..b4c662ec9bce8a7f0e91a112c990fa6f3dc666fb 100644 --- a/src/share/classes/javax/management/openmbean/CompositeType.java +++ b/src/share/classes/javax/management/openmbean/CompositeType.java @@ -89,7 +89,7 @@ public class CompositeType extends OpenType { *
      * @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 @@ public class CompositeType extends OpenType { * @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 @@ public class CompositeType extends OpenType { // 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 --git a/src/share/classes/javax/management/remote/JMXConnectorFactory.java b/src/share/classes/javax/management/remote/JMXConnectorFactory.java index 23003f007c596acd6bec82154846f7bb4ce30c23..219865b603c9dc1e07d5b8fb5aaaceb841c65b11 100644 --- a/src/share/classes/javax/management/remote/JMXConnectorFactory.java +++ b/src/share/classes/javax/management/remote/JMXConnectorFactory.java @@ -268,6 +268,14 @@ public class JMXConnectorFactory { 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 class JMXConnectorFactory { 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 @@ public class JMXConnectorFactory { } } - 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 @@ public class JMXConnectorFactory { if (pkgsObject == null) pkgsObject = - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { + AccessController.doPrivileged(new PrivilegedAction() { + public String run() { return System.getProperty(PROTOCOL_PROVIDER_PACKAGES); } }); @@ -423,8 +434,7 @@ public class JMXConnectorFactory { static Iterator getProviderIterator(final Class providerClass, final ClassLoader loader) { ServiceLoader serviceLoader = - ServiceLoader.load(providerClass, - loader); + ServiceLoader.load(providerClass, loader); return serviceLoader.iterator(); } @@ -528,8 +538,8 @@ public class JMXConnectorFactory { } if (loader == null) - loader = - AccessController.doPrivileged(new PrivilegedAction() { + loader = AccessController.doPrivileged( + new PrivilegedAction() { public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); diff --git a/src/share/classes/javax/management/remote/JMXServiceURL.java b/src/share/classes/javax/management/remote/JMXServiceURL.java index f2b19c5ef0befd50e78ba73bc037f9a9d189b81e..06b3b92f91a69fcd4615a7b74a3105f1dc7e3f9d 100644 --- a/src/share/classes/javax/management/remote/JMXServiceURL.java +++ b/src/share/classes/javax/management/remote/JMXServiceURL.java @@ -30,13 +30,14 @@ package javax.management.remote; import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; -import java.beans.ConstructorProperties; import java.io.Serializable; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.UnknownHostException; import java.util.BitSet; import java.util.StringTokenizer; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.InvalidKeyException; /** *

    The address of a JMX API connector server. Instances of this class @@ -273,7 +274,6 @@ public class JMXServiceURL implements Serializable { * is not possible to find the local host name, or if * port is negative. */ - @ConstructorProperties({"protocol", "host", "port", "URLPath"}) public JMXServiceURL(String protocol, String host, int port, String urlPath) throws MalformedURLException { @@ -338,6 +338,50 @@ public class JMXServiceURL implements Serializable { validate(); } + /** + *

    Construct a {@code JMXServiceURL} instance from the given + * {@code CompositeData}. The presence of this method means that + * {@code JMXServiceURL} is + * reconstructible in MXBeans.

    + * + *

    (The effect of this method could have been obtained more simply + * with a @{@link java.beans.ConstructorProperties ConstructorProperties} + * annotation on the four-parameter {@linkplain #JMXServiceURL( + * String, String, int, String) constructor}, but that would have meant + * that this API could not be implemented on versions of the Java platform + * that predated the introduction of that annotation.)

    + * + * @param cd a {@code CompositeData} object that must contain items called + * {@code protocol}, {@code host}, and {@code URLPath} of type {@code String} + * and {@code port} of type {@code Integer}. Such an object will be produced + * by the MXBean framework when mapping a {@code JMXServiceURL} + * instance to an Open Data value. + * + * @return a {@code JMXServiceURL} constructed with the protocol, host, + * port, and URL path extracted from the given {@code CompositeData}. + * + * @throws MalformedURLException if the given {@code CompositeData} does + * not contain all the required items with the required types or if the + * resultant URL is syntactically incorrect. + */ + public static JMXServiceURL from(CompositeData cd) + throws MalformedURLException { + try { + String proto = (String) cd.get("protocol"); + String host = (String) cd.get("host"); + int port = (Integer) cd.get("port"); + String urlPath = (String) cd.get("URLPath"); + return new JMXServiceURL(proto, host, port, urlPath); + } catch (RuntimeException e) { + // Could be InvalidKeyException if the item is missing, + // or ClassCastException if it is present but with the wrong type. + MalformedURLException x = new MalformedURLException(e.getMessage()); + x.initCause(e); + throw x; + } + } + private void validate() throws MalformedURLException { // Check protocol diff --git a/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java b/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java index 8f5119242618591bb21ab7ac0101c451028241ab..31964ebaaa32294199c34318594a5e14243b96e9 100644 --- a/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java +++ b/src/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java @@ -77,6 +77,7 @@ import javax.management.event.EventClientDelegate; import javax.management.event.EventClientDelegateMBean; import javax.management.event.EventClientNotFoundException; import javax.management.event.FetchingEventForwarder; +import javax.management.namespace.JMXNamespaces; import javax.management.remote.JMXServerErrorException; import javax.management.remote.NotificationResult; import javax.management.remote.TargetedNotification; @@ -1292,11 +1293,27 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { public void removeNotificationListener(ObjectName name, Integer id) throws InstanceNotFoundException, ListenerNotFoundException, IOException { + if (!JMXNamespaces.getContainingNamespace(name).equals("")) { + logger.debug("removeNotificationListener", + "This connector server is not configured to support " + + "forwarding of notification subscriptions to name spaces"); + throw new RuntimeOperationsException( + new UnsupportedOperationException( + "removeNotificationListener on name space MBeans. ")); + } forwarder.removeNotificationListener(name,id); } public void removeNotificationListener(ObjectName name, Integer[] ids) throws Exception { + if (!JMXNamespaces.getContainingNamespace(name).equals("")) { + logger.debug("removeNotificationListener", + "This connector server is not configured to support " + + "forwarding of notification subscriptions to name spaces"); + throw new RuntimeOperationsException( + new UnsupportedOperationException( + "removeNotificationListener on name space MBeans. ")); + } forwarder.removeNotificationListener(name,ids); } @@ -1307,6 +1324,14 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { public Integer addNotificationListener(ObjectName name, NotificationFilter filter) throws InstanceNotFoundException, IOException { + if (!JMXNamespaces.getContainingNamespace(name).equals("")) { + logger.debug("addNotificationListener", + "This connector server is not configured to support " + + "forwarding of notification subscriptions to name spaces"); + throw new RuntimeOperationsException( + new UnsupportedOperationException( + "addNotificationListener on name space MBeans. ")); + } return forwarder.addNotificationListener(name,filter); } @@ -1326,6 +1351,7 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { private final boolean checkNotificationEmission; private final String clientId; private final String connectionId; + private volatile String mbeanServerName; EventSubscriptionManager( MBeanServer mbeanServer, @@ -1343,6 +1369,11 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { this.connectionId = connectionId; } + private String mbeanServerName() { + if (mbeanServerName != null) return mbeanServerName; + else return (mbeanServerName = getMBeanServerName(mbeanServer)); + } + @SuppressWarnings("serial") // no serialVersionUID private class AccessControlFilter implements NotificationFilter { private final NotificationFilter wrapped; @@ -1357,7 +1388,8 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { try { if (checkNotificationEmission) { ServerNotifForwarder.checkMBeanPermission( - mbeanServer, name, "addNotificationListener"); + mbeanServerName(), mbeanServer, name, + "addNotificationListener"); } notifAC.fetchNotification( connectionId, name, notification, getSubject()); @@ -1392,7 +1424,7 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { if (notifAC != null) notifAC.removeNotificationListener(connectionId, name, getSubject()); try { - delegate.removeListenerOrSubscriber(clientId,id); + delegate.removeListenerOrSubscriber(clientId, id); } catch (EventClientNotFoundException x) { throw new IOException("Unknown clientId: "+clientId,x); } @@ -1405,7 +1437,7 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { notifAC.removeNotificationListener(connectionId, name, getSubject()); try { for (Integer id : ids) - delegate.removeListenerOrSubscriber(clientId,id); + delegate.removeListenerOrSubscriber(clientId, id); } catch (EventClientNotFoundException x) { throw new IOException("Unknown clientId: "+clientId,x); } @@ -1867,6 +1899,15 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced { return e; } + private static String getMBeanServerName(final MBeanServer server) { + final PrivilegedAction action = new PrivilegedAction() { + public String run() { + return Util.getMBeanServerSecurityName(server); + } + }; + return AccessController.doPrivileged(action); + } + private static final Object[] NO_OBJECTS = new Object[0]; private static final String[] NO_STRINGS = new String[0]; diff --git a/src/share/classes/javax/management/remote/rmi/RMIConnector.java b/src/share/classes/javax/management/remote/rmi/RMIConnector.java index bdcbb15685b52e5b1fef2f6f97c3aaf9035679b9..a620235ac139f8302732a3d30b41d2d5dfa1b7ae 100644 --- a/src/share/classes/javax/management/remote/rmi/RMIConnector.java +++ b/src/share/classes/javax/management/remote/rmi/RMIConnector.java @@ -420,7 +420,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable new PerThreadGroupPool.Create() { public ThreadPoolExecutor createThreadPool(ThreadGroup group) { ThreadFactory daemonThreadFactory = new DaemonThreadFactory( - "RMIConnector listener dispatch %d"); + "JMX RMIConnector listener dispatch %d"); ThreadPoolExecutor exec = new ThreadPoolExecutor( 1, 10, 1, TimeUnit.SECONDS, new LinkedBlockingDeque(), diff --git a/src/share/classes/org/jcp/xml/dsig/internal/DigesterOutputStream.java b/src/share/classes/org/jcp/xml/dsig/internal/DigesterOutputStream.java index e346a049a28f519a57fde4826f7ffe4ba29b79ea..025f4fd7f403a0e638b115e3b7d2df60ac2f2071 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/DigesterOutputStream.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/DigesterOutputStream.java @@ -19,7 +19,10 @@ * */ /* - * $Id: DigesterOutputStream.java,v 1.1.2.2 2005/08/12 18:15:35 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DigesterOutputStream.java,v 1.2 2008/07/24 15:20:31 mullan Exp $ */ package org.jcp.xml.dsig.internal; @@ -35,10 +38,11 @@ import com.sun.org.apache.xml.internal.security.utils.UnsyncByteArrayOutputStrea /** * This class has been modified slightly to use java.security.MessageDigest * objects as input, rather than - * org.apache.xml.security.algorithms.MessageDigestAlgorithm objects. + * com.sun.org.apache.xml.internal.security.algorithms.MessageDigestAlgorithm objects. * It also optionally caches the input bytes. * * @author raul + * @author Sean Mullan */ public class DigesterOutputStream extends OutputStream { private boolean buffer = false; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/MacOutputStream.java b/src/share/classes/org/jcp/xml/dsig/internal/MacOutputStream.java index 4161f4c1d3e06a47306079657dde85c76418ed12..3309215bb961de637d8a219cbee739d10840fe2e 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/MacOutputStream.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/MacOutputStream.java @@ -24,38 +24,35 @@ import java.io.ByteArrayOutputStream; import javax.crypto.Mac; /** - * Derived from Apache sources and changed to use Mac objects - * objects instead of org.apache.xml.security.algorithms.SignatureAlgorithm - * objects. + * Derived from Apache sources and changed to use Mac objects instead of + * com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithm objects. * * @author raul + * @author Sean Mullan * */ public class MacOutputStream extends ByteArrayOutputStream { - private final static byte none[]="error".getBytes(); private final Mac mac; public MacOutputStream(Mac mac) { this.mac = mac; } - /** @inheritDoc */ - public byte[] toByteArray() { - return none; - } - /** @inheritDoc */ public void write(byte[] arg0) { + super.write(arg0, 0, arg0.length); mac.update(arg0); } /** @inheritDoc */ public void write(int arg0) { - mac.update((byte)arg0); + super.write(arg0); + mac.update((byte) arg0); } /** @inheritDoc */ public void write(byte[] arg0, int arg1, int arg2) { - mac.update(arg0,arg1,arg2); + super.write(arg0, arg1, arg2); + mac.update(arg0, arg1, arg2); } } diff --git a/src/share/classes/org/jcp/xml/dsig/internal/SignerOutputStream.java b/src/share/classes/org/jcp/xml/dsig/internal/SignerOutputStream.java index fe3d46a18c27f2a7b8e64e4bc40c178600616b7d..41ae1f2d38730701b3f2d27c39bf4e19945e96f1 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/SignerOutputStream.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/SignerOutputStream.java @@ -19,7 +19,10 @@ * */ /* - * $Id: SignerOutputStream.java,v 1.1.2.2 2005/08/12 18:01:58 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: SignerOutputStream.java,v 1.2 2008/07/24 15:20:31 mullan Exp $ */ package org.jcp.xml.dsig.internal; @@ -29,10 +32,11 @@ import java.security.SignatureException; /** * Derived from Apache sources and changed to use java.security.Signature - * objects as input instead of org.apache.xml.security.algorithms.SignatureAlgorithm + * objects as input instead of com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithm * objects. * * @author raul + * @author Sean Mullan */ public class SignerOutputStream extends ByteArrayOutputStream { private final Signature sig; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheCanonicalizer.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheCanonicalizer.java index f48a5d276b96772ffe26e71f5c61f8b2886035e1..66a4c07182044a157d8ffeb00d2ee32508ef8bb3 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheCanonicalizer.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheCanonicalizer.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: ApacheCanonicalizer.java,v 1.17 2005/09/19 18:20:04 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: ApacheCanonicalizer.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -53,6 +52,10 @@ import org.w3c.dom.NodeList; public abstract class ApacheCanonicalizer extends TransformService { + static { + com.sun.org.apache.xml.internal.security.Init.init(); + } + private static Logger log = Logger.getLogger("org.jcp.xml.dsig.internal.dom"); protected Canonicalizer apacheCanonicalizer; private Transform apacheTransform; @@ -235,13 +238,9 @@ public abstract class ApacheCanonicalizer extends TransformService { } try { - if (os != null) { - in = apacheTransform.performTransform(in, os); - if (!in.isNodeSet() && !in.isElement()) { - return null; - } - } else { - in = apacheTransform.performTransform(in); + in = apacheTransform.performTransform(in, os); + if (!in.isNodeSet() && !in.isElement()) { + return null; } if (in.isOctetStream()) { return new ApacheOctetStreamData(in); diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheData.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheData.java index 4eb887df62cc4eecd1a3a79bd75abf6a379d019b..7aa6be7e52de990d95d8edda357d5dbe273d3ae2 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheData.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheData.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: ApacheData.java,v 1.4 2005/05/10 18:15:31 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: ApacheData.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheNodeSetData.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheNodeSetData.java index 916cb1771db779fbcccace6a0aa7a01a280bbef4..abf90588c62b2deca9e9db00c381d2a0d8193f3c 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheNodeSetData.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheNodeSetData.java @@ -1,29 +1,28 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: ApacheNodeSetData.java,v 1.4 2005/05/10 18:15:31 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: ApacheNodeSetData.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -83,7 +82,7 @@ public class ApacheNodeSetData implements ApacheData, NodeSetData { boolean skipNode = false; while (it.hasNext() && !skipNode) { NodeFilter nf = (NodeFilter) it.next(); - if (!nf.isNodeInclude(currentNode)) { + if (nf.isNodeInclude(currentNode)!=1) { skipNode = true; } } diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheOctetStreamData.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheOctetStreamData.java index 7d729ae7c139463342ea459e5cca8e7b1c7bb937..5f1dc4b54a0e7f7f6fc1a4ad6c8303c7218a3120 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheOctetStreamData.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheOctetStreamData.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: ApacheOctetStreamData.java,v 1.4 2005/05/10 18:15:31 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: ApacheOctetStreamData.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheTransform.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheTransform.java index 6d1b01ec8529348bd6d79e1037b3f0c4b65a6e90..4b4f141397e32d5ae997917a52b7603d1af5a24c 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheTransform.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/ApacheTransform.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: ApacheTransform.java,v 1.23 2005/09/15 14:29:03 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: ApacheTransform.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -54,6 +53,10 @@ import javax.xml.crypto.dsig.spec.TransformParameterSpec; */ public abstract class ApacheTransform extends TransformService { + static { + com.sun.org.apache.xml.internal.security.Init.init(); + } + private static Logger log = Logger.getLogger("org.jcp.xml.dsig.internal.dom"); private Transform apacheTransform; protected Document ownerDoc; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMBase64Transform.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMBase64Transform.java index 753bd374215545dc0a25d682ea4676fad29f4405..5646bf9417601993b9efd0dd8820642daacc38bb 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMBase64Transform.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMBase64Transform.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMBase64Transform.java,v 1.14 2005/05/10 18:15:31 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMBase64Transform.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMCanonicalXMLC14N11Method.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMCanonicalXMLC14N11Method.java new file mode 100644 index 0000000000000000000000000000000000000000..7ae0e1da8ea73b6f4a98c395d171ee8f25d6cc3c --- /dev/null +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMCanonicalXMLC14N11Method.java @@ -0,0 +1,79 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2008 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMCanonicalXMLC14N11Method.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ + */ +package org.jcp.xml.dsig.internal.dom; + +import javax.xml.crypto.*; +import javax.xml.crypto.dsig.*; +import javax.xml.crypto.dsig.spec.TransformParameterSpec; + +import java.security.InvalidAlgorithmParameterException; + +import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer; +import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException; + +/** + * DOM-based implementation of CanonicalizationMethod for Canonical XML 1.1 + * (with or without comments). Uses Apache XML-Sec Canonicalizer. + * + * @author Sean Mullan + */ +public final class DOMCanonicalXMLC14N11Method extends ApacheCanonicalizer { + + public static final String C14N_11 = "http://www.w3.org/2006/12/xml-c14n11"; + public static final String C14N_11_WITH_COMMENTS + = "http://www.w3.org/2006/12/xml-c14n11#WithComments"; + + public void init(TransformParameterSpec params) + throws InvalidAlgorithmParameterException { + if (params != null) { + throw new InvalidAlgorithmParameterException("no parameters " + + "should be specified for Canonical XML 1.1 algorithm"); + } + } + + public Data transform(Data data, XMLCryptoContext xc) + throws TransformException { + + // ignore comments if dereferencing same-document URI that requires + // you to omit comments, even if the Transform says otherwise - + // this is to be compliant with section 4.3.3.3 of W3C Rec. + if (data instanceof DOMSubTreeData) { + DOMSubTreeData subTree = (DOMSubTreeData) data; + if (subTree.excludeComments()) { + try { + apacheCanonicalizer = Canonicalizer.getInstance(C14N_11); + } catch (InvalidCanonicalizerException ice) { + throw new TransformException + ("Couldn't find Canonicalizer for: " + + C14N_11 + ": " + ice.getMessage(), ice); + } + } + } + + return canonicalize(data, xc); + } +} diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMCanonicalXMLC14NMethod.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMCanonicalXMLC14NMethod.java index e8feb7266d40f033d5a13416d07bdf6c82f70d52..7443dbad53db7380c07d4094e373c6cf1c5f3dd6 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMCanonicalXMLC14NMethod.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMCanonicalXMLC14NMethod.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMCanonicalXMLC14NMethod.java,v 1.24.4.1 2005/08/12 15:27:49 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMCanonicalXMLC14NMethod.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMCanonicalizationMethod.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMCanonicalizationMethod.java index 3e4a1f81473fdcd7cfec506df36c2395be8b8ae0..2b2469f36868699c792e58c0c604624ff5a313f7 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMCanonicalizationMethod.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMCanonicalizationMethod.java @@ -1,34 +1,34 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMCanonicalizationMethod.java,v 1.25 2005/05/10 18:15:31 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMCanonicalizationMethod.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; import java.io.OutputStream; import java.security.InvalidAlgorithmParameterException; +import java.security.Provider; import org.w3c.dom.Element; @@ -60,9 +60,9 @@ public class DOMCanonicalizationMethod extends DOMTransform * * @param cmElem a CanonicalizationMethod element */ - public DOMCanonicalizationMethod(Element cmElem, XMLCryptoContext context) - throws MarshalException{ - super(cmElem, context); + public DOMCanonicalizationMethod(Element cmElem, XMLCryptoContext context, + Provider provider) throws MarshalException { + super(cmElem, context, provider); } /** @@ -75,7 +75,7 @@ public class DOMCanonicalizationMethod extends DOMTransform * additional context (may be null if not applicable) * @return the canonicalized data * @throws NullPointerException if data is null - * @throws XMLSignatureException if an unexpected error occurs while + * @throws TransformException if an unexpected error occurs while * canonicalizing the data */ public Data canonicalize(Data data, XMLCryptoContext xc) diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMCryptoBinary.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMCryptoBinary.java index d5ef5b80b426e25430f228738306b9d79b037819..bd6e30bc6589b84ea812a5037509403b85e926d0 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMCryptoBinary.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMCryptoBinary.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMCryptoBinary.java,v 1.14 2005/05/12 19:28:29 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMCryptoBinary.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMDigestMethod.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMDigestMethod.java index c77ba559cd9cc829cca96252559ec391a21d1962..620c9a77ea1eb30418c8431bf065151c7e0420b8 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMDigestMethod.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMDigestMethod.java @@ -1,29 +1,28 @@ /* - * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMDigestMethod.java,v 1.17 2005/05/10 18:15:32 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMDigestMethod.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -127,7 +126,7 @@ public abstract class DOMDigestMethod extends DOMStructure /** * Unmarshals DigestMethodParameterSpec from the specified - * Element. By default, this method throws an exception since + * Element. By default, this method throws an exception since * most DigestMethod algorithms do not have parameters. Subclasses should * override it if they have parameters. * diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMEnvelopedTransform.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMEnvelopedTransform.java index 8a0e532ba98f1bc3c9ba459ae8b31f42857aeca8..0d8b8e6b577a92ef0ee5824193a36b44fbbab816 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMEnvelopedTransform.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMEnvelopedTransform.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMEnvelopedTransform.java,v 1.16 2005/05/10 18:15:32 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMEnvelopedTransform.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMExcC14NMethod.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMExcC14NMethod.java index 7a2f2330d9ae2ef3693eb4d208a4a87f24a7c1c0..5dd5a85115fe6978c5fe6596b73d0e690d3f3299 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMExcC14NMethod.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMExcC14NMethod.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMExcC14NMethod.java,v 1.28 2005/09/23 20:20:41 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMExcC14NMethod.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -104,7 +103,7 @@ public final class DOMExcC14NMethod extends ApacheCanonicalizer { Element excElem = DOMUtils.createElement (ownerDoc, "InclusiveNamespaces", CanonicalizationMethod.EXCLUSIVE, prefix); - if (prefix == null) { + if (prefix == null || prefix.length() == 0) { excElem.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", CanonicalizationMethod.EXCLUSIVE); } else { diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMHMACSignatureMethod.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMHMACSignatureMethod.java index d095360f866a4725e297ce7c31bdc136820d0de2..66ce33f5db205f389fa11c1cf393d2eaad5c3609 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMHMACSignatureMethod.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMHMACSignatureMethod.java @@ -1,29 +1,28 @@ /* - * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMHMACSignatureMethod.java,v 1.17 2005/09/15 14:29:04 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMHMACSignatureMethod.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyInfo.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyInfo.java index d246198ef1de32b311186924d6ba43ab1c3913b8..9c89f200028cfa9e41f43b4bb60d8d77d5057a53 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyInfo.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyInfo.java @@ -1,29 +1,28 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMKeyInfo.java,v 1.19 2005/05/12 19:28:30 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMKeyInfo.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -33,6 +32,7 @@ import javax.xml.crypto.dsig.dom.DOMSignContext; import javax.xml.crypto.dsig.keyinfo.KeyInfo; import javax.xml.crypto.dom.*; +import java.security.Provider; import java.util.*; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -82,10 +82,10 @@ public final class DOMKeyInfo extends DOMStructure implements KeyInfo { /** * Creates a DOMKeyInfo from XML. * - * @param input XML input + * @param kiElem KeyInfo element */ - public DOMKeyInfo(Element kiElem, XMLCryptoContext context) - throws MarshalException { + public DOMKeyInfo(Element kiElem, XMLCryptoContext context, + Provider provider) throws MarshalException { // get Id attribute, if specified id = DOMUtils.getAttributeValue(kiElem, "Id"); @@ -112,7 +112,10 @@ public final class DOMKeyInfo extends DOMStructure implements KeyInfo { } else if (localName.equals("KeyValue")) { content.add(new DOMKeyValue(childElem)); } else if (localName.equals("RetrievalMethod")) { - content.add(new DOMRetrievalMethod(childElem, context)); + content.add + (new DOMRetrievalMethod(childElem, context, provider)); + } else if (localName.equals("PGPData")) { + content.add(new DOMPGPData(childElem)); } else { //may be MgmtData, SPKIData or element from other namespace content.add(new javax.xml.crypto.dom.DOMStructure((childElem))); } @@ -139,7 +142,7 @@ public final class DOMKeyInfo extends DOMStructure implements KeyInfo { Element kiElem = DOMUtils.createElement (DOMUtils.getOwnerDocument(pNode), "KeyInfo", XMLSignature.XMLNS, dsPrefix); - if (dsPrefix == null) { + if (dsPrefix == null || dsPrefix.length() == 0) { kiElem.setAttributeNS ("http://www.w3.org/2000/xmlns/", "xmlns", XMLSignature.XMLNS); } else { diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyInfoFactory.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyInfoFactory.java index 61d2389453167a855b736eb809e1dc48b3bae1f6..58b227670cf00c309c41a1bd455ff5fb64c0e76f 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyInfoFactory.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyInfoFactory.java @@ -1,34 +1,34 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMKeyInfoFactory.java,v 1.24 2005/09/23 20:18:50 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMKeyInfoFactory.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; import java.math.BigInteger; -import java.security.*; +import java.security.KeyException; +import java.security.PublicKey; import java.util.List; import javax.xml.crypto.*; import javax.xml.crypto.dsig.*; @@ -45,7 +45,6 @@ import org.w3c.dom.Node; */ public final class DOMKeyInfoFactory extends KeyInfoFactory { - public DOMKeyInfoFactory() { } public KeyInfo newKeyInfo(List content) { @@ -135,7 +134,7 @@ public final class DOMKeyInfoFactory extends KeyInfoFactory { "support DOM Level 2 and be namespace aware"); } if (tag.equals("KeyInfo")) { - return new DOMKeyInfo(element, null); + return new DOMKeyInfo(element, null, getProvider()); } else { throw new MarshalException("invalid KeyInfo tag: " + tag); } diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyName.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyName.java index 0c352c23af7d26c2c8ea01444de4d08123330728..5403ebe7b8716430ad02177a9ca80384de06a72f 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyName.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyName.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMKeyName.java,v 1.12 2005/05/10 18:15:32 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMKeyName.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyValue.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyValue.java index 9bd888206778edeecc2752afecdee899d8d293e1..c23f54200a061683dcd54e5af1ccbaca3288a7f2 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyValue.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyValue.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMKeyValue.java,v 1.18 2005/05/10 18:15:33 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMKeyValue.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMManifest.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMManifest.java index 8da0f7480ae342c97f1a48fdb73e96b71178a788..e2bb4da03bbc7018a8210c969afc9a54bbaf288b 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMManifest.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMManifest.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMManifest.java,v 1.16 2005/05/12 19:28:31 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMManifest.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -31,6 +30,7 @@ import javax.xml.crypto.*; import javax.xml.crypto.dom.DOMCryptoContext; import javax.xml.crypto.dsig.*; +import java.security.Provider; import java.util.*; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -83,13 +83,13 @@ public final class DOMManifest extends DOMStructure implements Manifest { * * @param manElem a Manifest element */ - public DOMManifest(Element manElem, XMLCryptoContext context) - throws MarshalException { + public DOMManifest(Element manElem, XMLCryptoContext context, + Provider provider) throws MarshalException { this.id = DOMUtils.getAttributeValue(manElem, "Id"); Element refElem = DOMUtils.getFirstChildElement(manElem); List refs = new ArrayList(); while (refElem != null) { - refs.add(new DOMReference(refElem, context)); + refs.add(new DOMReference(refElem, context, provider)); refElem = DOMUtils.getNextSiblingElement(refElem); } this.references = Collections.unmodifiableList(refs); diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMPGPData.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMPGPData.java index e2dc505ffd1216f550cbce0dcd4f3b0c2726fc5a..1593a570b6248ab6245bb9905ee6cea7461b0c8d 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMPGPData.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMPGPData.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMPGPData.java,v 1.18 2005/05/12 19:28:31 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMPGPData.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMReference.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMReference.java index 54271620414a6fd36b68bf2a7c579816692cf2a0..cd77ad462d20097a378f9bb3f3f1b96a9f115bc9 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMReference.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMReference.java @@ -1,28 +1,26 @@ /* - * Portions Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ - +/* + * Portions copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ /* * =========================================================================== * @@ -31,7 +29,7 @@ * =========================================================================== */ /* - * $Id: DOMReference.java,v 1.40 2005/09/19 18:27:04 mullan Exp $ + * $Id: DOMReference.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -67,13 +65,27 @@ import com.sun.org.apache.xml.internal.security.utils.UnsyncBufferedOutputStream public final class DOMReference extends DOMStructure implements Reference, DOMURIReference { + /** + * Look up useC14N11 system property. If true, an explicit C14N11 transform + * will be added if necessary when generating the signature. See section + * 3.1.1 of http://www.w3.org/2007/xmlsec/Drafts/xmldsig-core/ for more info. + * + * If true, overrides the same property if set in the XMLSignContext. + */ + private static boolean useC14N11 = + AccessController.doPrivileged(new PrivilegedAction() { + public Boolean run() { + return Boolean.getBoolean + ("com.sun.org.apache.xml.internal.security.useC14N11"); + } + }); + private static Logger log = Logger.getLogger("org.jcp.xml.dsig.internal.dom"); private final DigestMethod digestMethod; private final String id; - private final List appliedTransforms; private final List transforms; - private final List allTransforms; + private List allTransforms; private final Data appliedTransformData; private Attr here; private final String uri; @@ -87,6 +99,7 @@ public final class DOMReference extends DOMStructure private Data derefData; private InputStream dis; private MessageDigest md; + private Provider provider; /** * Creates a Reference from the specified parameters. @@ -104,24 +117,25 @@ public final class DOMReference extends DOMStructure * not of type Transform */ public DOMReference(String uri, String type, DigestMethod dm, - List transforms, String id) { - this(uri, type, dm, null, null, transforms, id, null); + List transforms, String id, Provider provider) { + this(uri, type, dm, null, null, transforms, id, null, provider); } public DOMReference(String uri, String type, DigestMethod dm, - List appliedTransforms, Data result, List transforms, String id) { - this(uri, type, dm, appliedTransforms, result, transforms, id, null); + List appliedTransforms, Data result, List transforms, String id, + Provider provider) { + this(uri, type, dm, appliedTransforms, + result, transforms, id, null, provider); } public DOMReference(String uri, String type, DigestMethod dm, List appliedTransforms, Data result, List transforms, String id, - byte[] digestValue){ + byte[] digestValue, Provider provider) { if (dm == null) { throw new NullPointerException("DigestMethod must be non-null"); } - if (appliedTransforms == null || appliedTransforms.isEmpty()) { - this.appliedTransforms = Collections.EMPTY_LIST; - } else { + this.allTransforms = new ArrayList(); + if (appliedTransforms != null) { List transformsCopy = new ArrayList(appliedTransforms); for (int i = 0, size = transformsCopy.size(); i < size; i++) { if (!(transformsCopy.get(i) instanceof Transform)) { @@ -129,10 +143,9 @@ public final class DOMReference extends DOMStructure ("appliedTransforms["+i+"] is not a valid type"); } } - this.appliedTransforms = - Collections.unmodifiableList(transformsCopy); + this.allTransforms = transformsCopy; } - if (transforms == null || transforms.isEmpty()) { + if (transforms == null) { this.transforms = Collections.EMPTY_LIST; } else { List transformsCopy = new ArrayList(transforms); @@ -142,11 +155,9 @@ public final class DOMReference extends DOMStructure ("transforms["+i+"] is not a valid type"); } } - this.transforms = Collections.unmodifiableList(transformsCopy); + this.transforms = transformsCopy; + this.allTransforms.addAll(transformsCopy); } - List all = new ArrayList(this.appliedTransforms); - all.addAll(this.transforms); - this.allTransforms = Collections.unmodifiableList(all); this.digestMethod = dm; this.uri = uri; if ((uri != null) && (!uri.equals(""))) { @@ -163,6 +174,7 @@ public final class DOMReference extends DOMStructure this.digested = true; } this.appliedTransformData = result; + this.provider = provider; } /** @@ -170,15 +182,16 @@ public final class DOMReference extends DOMStructure * * @param refElem a Reference element */ - public DOMReference(Element refElem, XMLCryptoContext context) - throws MarshalException { + public DOMReference(Element refElem, XMLCryptoContext context, + Provider provider) throws MarshalException { // unmarshal Transforms, if specified Element nextSibling = DOMUtils.getFirstChildElement(refElem); List transforms = new ArrayList(5); if (nextSibling.getLocalName().equals("Transforms")) { Element transformElem = DOMUtils.getFirstChildElement(nextSibling); while (transformElem != null) { - transforms.add(new DOMTransform(transformElem, context)); + transforms.add + (new DOMTransform(transformElem, context, provider)); transformElem = DOMUtils.getNextSiblingElement(transformElem); } nextSibling = DOMUtils.getNextSiblingElement(nextSibling); @@ -203,15 +216,10 @@ public final class DOMReference extends DOMStructure this.type = DOMUtils.getAttributeValue(refElem, "Type"); this.here = refElem.getAttributeNodeNS(null, "URI"); this.refElem = refElem; - - if (transforms.isEmpty()) { - this.transforms = Collections.EMPTY_LIST; - } else { - this.transforms = Collections.unmodifiableList(transforms); - } - this.appliedTransforms = Collections.EMPTY_LIST; + this.transforms = transforms; this.allTransforms = transforms; this.appliedTransformData = null; + this.provider = provider; } public DigestMethod getDigestMethod() { @@ -231,7 +239,7 @@ public final class DOMReference extends DOMStructure } public List getTransforms() { - return allTransforms; + return Collections.unmodifiableList(allTransforms); } public byte[] getDigestValue() { @@ -259,17 +267,13 @@ public final class DOMReference extends DOMStructure DOMUtils.setAttribute(refElem, "Type", type); // create and append Transforms element - if (!transforms.isEmpty() || !appliedTransforms.isEmpty()) { + if (!allTransforms.isEmpty()) { Element transformsElem = DOMUtils.createElement (ownerDoc, "Transforms", XMLSignature.XMLNS, dsPrefix); refElem.appendChild(transformsElem); - for (int i = 0, size = appliedTransforms.size(); i < size; i++) { + for (int i = 0, size = allTransforms.size(); i < size; i++) { DOMStructure transform = - (DOMStructure) appliedTransforms.get(i); - transform.marshal(transformsElem, dsPrefix, context); - } - for (int i = 0, size = transforms.size(); i < size; i++) { - DOMStructure transform = (DOMStructure) transforms.get(i); + (DOMStructure) allTransforms.get(i); transform.marshal(transformsElem, dsPrefix, context); } } @@ -416,21 +420,62 @@ public final class DOMReference extends DOMStructure try { if (data != null) { XMLSignatureInput xi; + // explicitly use C14N 1.1 when generating signature + // first check system property, then context property + boolean c14n11 = useC14N11; + String c14nalg = CanonicalizationMethod.INCLUSIVE; + if (context instanceof XMLSignContext) { + if (!c14n11) { + Boolean prop = (Boolean) context.getProperty + ("com.sun.org.apache.xml.internal.security.useC14N11"); + c14n11 = (prop != null && prop.booleanValue() == true); + if (c14n11) { + c14nalg = "http://www.w3.org/2006/12/xml-c14n11"; + } + } else { + c14nalg = "http://www.w3.org/2006/12/xml-c14n11"; + } + } if (data instanceof ApacheData) { xi = ((ApacheData) data).getXMLSignatureInput(); } else if (data instanceof OctetStreamData) { xi = new XMLSignatureInput (((OctetStreamData)data).getOctetStream()); } else if (data instanceof NodeSetData) { - TransformService spi = TransformService.getInstance - (CanonicalizationMethod.INCLUSIVE, "DOM"); + TransformService spi = null; + try { + spi = TransformService.getInstance(c14nalg, "DOM"); + } catch (NoSuchAlgorithmException nsae) { + spi = TransformService.getInstance + (c14nalg, "DOM", provider); + } data = spi.transform(data, context); xi = new XMLSignatureInput (((OctetStreamData)data).getOctetStream()); } else { throw new XMLSignatureException("unrecognized Data type"); } - xi.updateOutputStream(os); + if (context instanceof XMLSignContext && c14n11 + && !xi.isOctetStream() && !xi.isOutputStreamSet()) { + DOMTransform t = new DOMTransform + (TransformService.getInstance(c14nalg, "DOM")); + Element transformsElem = null; + String dsPrefix = DOMUtils.getSignaturePrefix(context); + if (allTransforms.isEmpty()) { + transformsElem = DOMUtils.createElement( + refElem.getOwnerDocument(), + "Transforms", XMLSignature.XMLNS, dsPrefix); + refElem.insertBefore(transformsElem, + DOMUtils.getFirstChildElement(refElem)); + } else { + transformsElem = DOMUtils.getFirstChildElement(refElem); + } + t.marshal(transformsElem, dsPrefix, (DOMCryptoContext) context); + allTransforms.add(t); + xi.updateOutputStream(os, true); + } else { + xi.updateOutputStream(os); + } } os.flush(); if (cache != null && cache.booleanValue() == true) { @@ -466,7 +511,7 @@ public final class DOMReference extends DOMStructure Arrays.equals(digestValue, oref.getDigestValue()); return (digestMethod.equals(oref.getDigestMethod()) && idsEqual && - urisEqual && typesEqual && transforms.equals(oref.getTransforms())); + urisEqual && typesEqual && allTransforms.equals(oref.getTransforms())); } boolean isDigested() { @@ -486,7 +531,7 @@ public final class DOMReference extends DOMStructure }; } catch (Exception e) { // log a warning - log.log(Level.WARNING, + log.log(Level.WARNING, "cannot cache dereferenced data: " + e); return null; } @@ -499,7 +544,7 @@ public final class DOMReference extends DOMStructure (xsi.getOctetStream(), xsi.getSourceURI(), xsi.getMIMEType()); } catch (IOException ioe) { // log a warning - log.log(Level.WARNING, + log.log(Level.WARNING, "cannot cache dereferenced data: " + ioe); return null; } diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMRetrievalMethod.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMRetrievalMethod.java index 8a3af2b8818d3d98ab9107f849d285091ce5c2ec..0d0f6a58153652b051561a15fc1c99836fb65999 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMRetrievalMethod.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMRetrievalMethod.java @@ -1,28 +1,26 @@ /* - * Portions Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ - +/* + * Portions copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ /* * =========================================================================== * @@ -31,13 +29,14 @@ * =========================================================================== */ /* - * $Id: DOMRetrievalMethod.java,v 1.24 2005/05/12 19:28:32 mullan Exp $ + * $Id: DOMRetrievalMethod.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; import java.io.ByteArrayInputStream; import java.net.URI; import java.net.URISyntaxException; +import java.security.Provider; import java.util.*; import javax.xml.crypto.*; import javax.xml.crypto.dsig.*; @@ -116,8 +115,8 @@ public final class DOMRetrievalMethod extends DOMStructure * * @param rmElem a RetrievalMethod element */ - public DOMRetrievalMethod(Element rmElem, XMLCryptoContext context) - throws MarshalException { + public DOMRetrievalMethod(Element rmElem, XMLCryptoContext context, + Provider provider) throws MarshalException { // get URI and Type attributes uri = DOMUtils.getAttributeValue(rmElem, "URI"); type = DOMUtils.getAttributeValue(rmElem, "Type"); @@ -132,7 +131,8 @@ public final class DOMRetrievalMethod extends DOMStructure Element transformElem = DOMUtils.getFirstChildElement(transformsElem); while (transformElem != null) { - transforms.add(new DOMTransform(transformElem, context)); + transforms.add + (new DOMTransform(transformElem, context, provider)); transformElem = DOMUtils.getNextSiblingElement(transformElem); } } diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java index 09747274d12d2e5cb400d2ea76bf50ade0611247..67a4fa55f2e8c33081f37000d5825919d68239e0 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java @@ -1,32 +1,28 @@ /* - * Portions Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. */ /* - * $Id: DOMSignatureMethod.java,v 1.20.4.1 2005/08/12 14:23:49 mullan Exp $ + * $Id: DOMSignatureMethod.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -226,7 +222,11 @@ public abstract class DOMSignatureMethod extends DOMStructure } if (signature == null) { try { - signature = Signature.getInstance(getSignatureAlgorithm()); + Provider p = (Provider) context.getProperty + ("org.jcp.xml.dsig.internal.dom.SignatureProvider"); + signature = (p == null) + ? Signature.getInstance(getSignatureAlgorithm()) + : Signature.getInstance(getSignatureAlgorithm(), p); } catch (NoSuchAlgorithmException nsae) { throw new XMLSignatureException(nsae); } @@ -274,7 +274,11 @@ public abstract class DOMSignatureMethod extends DOMStructure } if (signature == null) { try { - signature = Signature.getInstance(getSignatureAlgorithm()); + Provider p = (Provider) context.getProperty + ("org.jcp.xml.dsig.internal.dom.SignatureProvider"); + signature = (p == null) + ? Signature.getInstance(getSignatureAlgorithm()) + : Signature.getInstance(getSignatureAlgorithm(), p); } catch (NoSuchAlgorithmException nsae) { throw new XMLSignatureException(nsae); } @@ -302,7 +306,7 @@ public abstract class DOMSignatureMethod extends DOMStructure /** * Marshals the algorithm-specific parameters to an Element and - * appends it to the specified parent element. By default, this method + * appends it to the specified parent element. By default, this method * throws an exception since most SignatureMethod algorithms do not have * parameters. Subclasses should override it if they have parameters. * @@ -360,7 +364,6 @@ public abstract class DOMSignatureMethod extends DOMStructure private static byte[] convertASN1toXMLDSIG(byte asn1Bytes[]) throws IOException { - // THIS CODE IS COPIED FROM APACHE (see copyright at top of file) byte rLength = asn1Bytes[3]; int i; @@ -401,7 +404,6 @@ public abstract class DOMSignatureMethod extends DOMStructure private static byte[] convertXMLDSIGtoASN1(byte xmldsigBytes[]) throws IOException { - // THIS CODE IS COPIED FROM APACHE (see copyright at top of file) if (xmldsigBytes.length != 40) { throw new IOException("Invalid XMLDSIG format of DSA signature"); } diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureProperties.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureProperties.java index 4413578c687afad0ca13a49f2684105142a4134b..07f3b89ed38314476530cd49131ba4079a28bb81 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureProperties.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureProperties.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMSignatureProperties.java,v 1.12 2005/05/12 19:28:32 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMSignatureProperties.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureProperty.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureProperty.java index eda8ad362f59d414bd1cb05a20f957844a310297..d868558289daad323c2c466da4e7ede6d6674e4a 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureProperty.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureProperty.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMSignatureProperty.java,v 1.14 2005/05/12 19:28:32 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMSignatureProperty.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignedInfo.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignedInfo.java index 782ab984386a71082fa672df776426c2fc4b258d..3597c5f0c3543e4feb9049f5863104d3f4efdc0c 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignedInfo.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignedInfo.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMSignedInfo.java,v 1.30 2005/09/23 20:14:07 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMSignedInfo.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -37,6 +36,7 @@ import java.io.InputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; +import java.security.Provider; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; @@ -126,8 +126,8 @@ public final class DOMSignedInfo extends DOMStructure implements SignedInfo { * * @param siElem a SignedInfo element */ - public DOMSignedInfo(Element siElem, XMLCryptoContext context) - throws MarshalException { + public DOMSignedInfo(Element siElem, XMLCryptoContext context, + Provider provider) throws MarshalException { localSiElem = siElem; ownerDoc = siElem.getOwnerDocument(); @@ -136,7 +136,8 @@ public final class DOMSignedInfo extends DOMStructure implements SignedInfo { // unmarshal CanonicalizationMethod Element cmElem = DOMUtils.getFirstChildElement(siElem); - canonicalizationMethod = new DOMCanonicalizationMethod(cmElem, context); + canonicalizationMethod = new DOMCanonicalizationMethod + (cmElem, context, provider); // unmarshal SignatureMethod Element smElem = DOMUtils.getNextSiblingElement(cmElem); @@ -146,7 +147,7 @@ public final class DOMSignedInfo extends DOMStructure implements SignedInfo { ArrayList refList = new ArrayList(5); Element refElem = DOMUtils.getNextSiblingElement(smElem); while (refElem != null) { - refList.add(new DOMReference(refElem, context)); + refList.add(new DOMReference(refElem, context, provider)); refElem = DOMUtils.getNextSiblingElement(refElem); } references = Collections.unmodifiableList(refList); @@ -188,9 +189,8 @@ public final class DOMSignedInfo extends DOMStructure implements SignedInfo { DOMSubTreeData subTree = new DOMSubTreeData(localSiElem, true); - OctetStreamData data = null; try { - data = (OctetStreamData) ((DOMCanonicalizationMethod) + Data data = ((DOMCanonicalizationMethod) canonicalizationMethod).canonicalize(subTree, context, os); } catch (TransformException te) { throw new XMLSignatureException(te); @@ -205,9 +205,11 @@ public final class DOMSignedInfo extends DOMStructure implements SignedInfo { char[] siBytes = new char[signedInfoBytes.length]; try { isr.read(siBytes); - } catch (IOException ioex) {} //ignore since this is logging code - log.log(Level.FINE, "Canonicalized SignedInfo:\n" - + new String(siBytes)); + log.log(Level.FINE, "Canonicalized SignedInfo:\n" + + new String(siBytes)); + } catch (IOException ioex) { + log.log(Level.FINE, "IOException reading SignedInfo bytes"); + } log.log(Level.FINE, "Data to be signed/verified:" + Base64.encode(signedInfoBytes)); } diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMStructure.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMStructure.java index 57040db89644bae0617d6514367fb2ab4836f9b1..19b5359be83d7d38332168fcf9e15a7fdd9b241e 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMStructure.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMStructure.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMStructure.java,v 1.11 2005/05/10 18:15:34 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMStructure.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSubTreeData.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSubTreeData.java index 79698de555c0cac6421b5773d225502665f03ff6..fc88ae6436cd1baba5f2daa2922b454e20f194f8 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSubTreeData.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMSubTreeData.java @@ -1,29 +1,28 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2006 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMSubTreeData.java,v 1.2 2005/09/15 14:29:04 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMSubTreeData.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMTransform.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMTransform.java index 1e499a72b4645c8ba70514cd113a636d41b9196b..4425a00d3683959e5197a36feb5be9fe37827771 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMTransform.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMTransform.java @@ -1,35 +1,35 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMTransform.java,v 1.25 2005/05/10 18:15:34 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMTransform.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; import java.io.OutputStream; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; +import java.security.Provider; import java.security.spec.AlgorithmParameterSpec; import org.w3c.dom.Document; @@ -68,14 +68,17 @@ public class DOMTransform extends DOMStructure implements Transform { * * @param transElem a Transform element */ - public DOMTransform(Element transElem, XMLCryptoContext context) - throws MarshalException { - Document ownerDoc = transElem.getOwnerDocument(); + public DOMTransform(Element transElem, XMLCryptoContext context, + Provider provider) throws MarshalException { String algorithm = DOMUtils.getAttributeValue(transElem, "Algorithm"); try { spi = TransformService.getInstance(algorithm, "DOM"); - } catch (NoSuchAlgorithmException e) { - throw new MarshalException(e); + } catch (NoSuchAlgorithmException e1) { + try { + spi = TransformService.getInstance(algorithm, "DOM", provider); + } catch (NoSuchAlgorithmException e2) { + throw new MarshalException(e2); + } } try { spi.init(new javax.xml.crypto.dom.DOMStructure(transElem), context); diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java index 3abe615a400c689fb7cebce36b732848b13cd894..b6c23c25cde7f81ef50c3c0201a7f53c1008b2aa 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMURIDereferencer.java,v 1.19 2005/09/23 20:09:34 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMURIDereferencer.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -83,11 +82,9 @@ public class DOMURIDereferencer implements URIDereferencer { // this is a bit of a hack to check for registered // IDRefs and manually register them with Apache's IdResolver // map which includes builtin schema knowledge of DSig/Enc IDs - if (context instanceof XMLSignContext) { - Node referencedElem = dcc.getElementById(id); - if (referencedElem != null) { - IdResolver.registerElementById((Element) referencedElem, id); - } + Node referencedElem = dcc.getElementById(id); + if (referencedElem != null) { + IdResolver.registerElementById((Element) referencedElem, id); } } diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMUtils.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMUtils.java index 5956bae886628fb0966157f12862851d6ea8615e..ccd3e1957815e06bc1e51799c7439b6a6faaa4cd 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMUtils.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMUtils.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMUtils.java,v 1.18 2005/05/12 19:28:34 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMUtils.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -77,7 +76,8 @@ public class DOMUtils { */ public static Element createElement(Document doc, String tag, String nsURI, String prefix) { - String qName = prefix == null ? tag : prefix + ":" + tag; + String qName = (prefix == null || prefix.length() == 0) + ? tag : prefix + ":" + tag; return doc.createElementNS(nsURI, qName); } @@ -327,6 +327,7 @@ public class DOMUtils { XPathType type = (XPathType) types.get(i); XPathType otype = (XPathType) otypes.get(i); if (!type.getExpression().equals(otype.getExpression()) || + !type.getNamespaceMap().equals(otype.getNamespaceMap()) || type.getFilter() != otype.getFilter()) { return false; } @@ -341,8 +342,8 @@ public class DOMUtils { private static boolean paramsEqual(XPathFilterParameterSpec spec1, XPathFilterParameterSpec spec2) { - - return spec1.getXPath().equals(spec2.getXPath()); + return (spec1.getXPath().equals(spec2.getXPath()) && + spec1.getNamespaceMap().equals(spec2.getNamespaceMap())); } private static boolean paramsEqual(XSLTTransformParameterSpec spec1, diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMX509Data.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMX509Data.java index d095cbef68e7625a4cc59da6081a4d3471601264..8ee3db600a50e99c26b74137bbd9272c496b7c28 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMX509Data.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMX509Data.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMX509Data.java,v 1.20 2005/05/12 19:28:34 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMX509Data.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -53,7 +52,7 @@ import com.sun.org.apache.xml.internal.security.utils.Base64; public final class DOMX509Data extends DOMStructure implements X509Data { private final List content; - private CertificateFactory cf; //FIX - make this static? + private CertificateFactory cf; /** * Creates a DOMX509Data. diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMX509IssuerSerial.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMX509IssuerSerial.java index 8f3d909582203a49edb9cc7196d68113346def23..ecfe5851fd9349471d2e3b49512d981e265a2024 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMX509IssuerSerial.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMX509IssuerSerial.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMX509IssuerSerial.java,v 1.13 2005/05/10 18:15:35 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMX509IssuerSerial.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLObject.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLObject.java index eb279752577bad8fb619c9ef04fb70cdf6d11b9f..45f9984bc2ecc3865fd23f720b8c58dcc256482b 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLObject.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLObject.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMXMLObject.java,v 1.16 2005/05/12 19:28:35 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMXMLObject.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -31,6 +30,7 @@ import javax.xml.crypto.*; import javax.xml.crypto.dom.DOMCryptoContext; import javax.xml.crypto.dsig.*; +import java.security.Provider; import java.util.*; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -87,8 +87,8 @@ public final class DOMXMLObject extends DOMStructure implements XMLObject { * @param objElem an Object element * @throws MarshalException if there is an error when unmarshalling */ - public DOMXMLObject(Element objElem, XMLCryptoContext context) - throws MarshalException { + public DOMXMLObject(Element objElem, XMLCryptoContext context, + Provider provider) throws MarshalException { // unmarshal attributes this.encoding = DOMUtils.getAttributeValue(objElem, "Encoding"); this.id = DOMUtils.getAttributeValue(objElem, "Id"); @@ -103,7 +103,7 @@ public final class DOMXMLObject extends DOMStructure implements XMLObject { Element childElem = (Element) child; String tag = childElem.getLocalName(); if (tag.equals("Manifest")) { - content.add(new DOMManifest(childElem, context)); + content.add(new DOMManifest(childElem, context, provider)); continue; } else if (tag.equals("SignatureProperties")) { content.add(new DOMSignatureProperties(childElem)); diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignature.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignature.java index 1e31d60a0821b6203a3afab652a7ba140a4edc0c..a758486e0cbdaaf81d3e80e71bc80fa0d68eed96 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignature.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignature.java @@ -1,28 +1,26 @@ /* - * Portions Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ - +/* + * Portions copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ /* * =========================================================================== * @@ -31,7 +29,7 @@ * =========================================================================== */ /* - * $Id: DOMXMLSignature.java,v 1.42 2005/09/23 20:29:04 mullan Exp $ + * $Id: DOMXMLSignature.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -45,6 +43,7 @@ import javax.xml.crypto.dsig.keyinfo.KeyInfo; import java.io.*; import java.security.InvalidKeyException; import java.security.Key; +import java.security.Provider; import java.util.Collections; import java.util.ArrayList; import java.util.HashMap; @@ -128,8 +127,8 @@ public final class DOMXMLSignature extends DOMStructure * @param sigElem Signature element * @throws MarshalException if XMLSignature cannot be unmarshalled */ - public DOMXMLSignature(Element sigElem, XMLCryptoContext context) - throws MarshalException { + public DOMXMLSignature(Element sigElem, XMLCryptoContext context, + Provider provider) throws MarshalException { localSigElem = sigElem; ownerDoc = localSigElem.getOwnerDocument(); @@ -138,7 +137,7 @@ public final class DOMXMLSignature extends DOMStructure // unmarshal SignedInfo Element siElem = DOMUtils.getFirstChildElement(localSigElem); - si = new DOMSignedInfo(siElem, context); + si = new DOMSignedInfo(siElem, context, provider); // unmarshal SignatureValue Element sigValElem = DOMUtils.getNextSiblingElement(siElem); @@ -147,7 +146,7 @@ public final class DOMXMLSignature extends DOMStructure // unmarshal KeyInfo, if specified Element nextSibling = DOMUtils.getNextSiblingElement(sigValElem); if (nextSibling != null && nextSibling.getLocalName().equals("KeyInfo")) { - ki = new DOMKeyInfo(nextSibling, context); + ki = new DOMKeyInfo(nextSibling, context, provider); nextSibling = DOMUtils.getNextSiblingElement(nextSibling); } @@ -157,7 +156,8 @@ public final class DOMXMLSignature extends DOMStructure } else { List tempObjects = new ArrayList(); while (nextSibling != null) { - tempObjects.add(new DOMXMLObject(nextSibling, context)); + tempObjects.add + (new DOMXMLObject(nextSibling, context, provider)); nextSibling = DOMUtils.getNextSiblingElement(nextSibling); } objects = Collections.unmodifiableList(tempObjects); @@ -201,9 +201,7 @@ public final class DOMXMLSignature extends DOMStructure (ownerDoc, "Signature", XMLSignature.XMLNS, dsPrefix); // append xmlns attribute - //XXX I think this is supposed to be automatically inserted when - //XXX serializing a DOM2 tree, but doesn't seem to work with JAXP/Xalan - if (dsPrefix == null) { + if (dsPrefix == null || dsPrefix.length() == 0) { sigElem.setAttributeNS ("http://www.w3.org/2000/xmlns/", "xmlns", XMLSignature.XMLNS); } else { @@ -301,7 +299,7 @@ public final class DOMXMLSignature extends DOMStructure Reference ref = (Reference) manRefs.get(k); boolean refValid = ref.validate(vc); if (log.isLoggable(Level.FINE)) { - log.log(Level.FINE, "Manifest ref[" + log.log(Level.FINE, "Manifest ref[" + ref.getURI() + "] is valid: " + refValid); } validateMans &= refValid; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignatureFactory.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignatureFactory.java index ab29819a100ae28215bca70299184b6038c4a892..59e0ebe3946e11792f7b20caa435628d1559f650 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignatureFactory.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignatureFactory.java @@ -1,29 +1,28 @@ /* - * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMXMLSignatureFactory.java,v 1.21 2005/09/23 19:59:11 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMXMLSignatureFactory.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -33,7 +32,8 @@ import javax.xml.crypto.dsig.dom.DOMValidateContext; import javax.xml.crypto.dsig.keyinfo.*; import javax.xml.crypto.dsig.spec.*; -import java.security.*; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; import java.security.spec.AlgorithmParameterSpec; import java.util.List; import org.w3c.dom.Document; @@ -67,7 +67,7 @@ public final class DOMXMLSignatureFactory extends XMLSignatureFactory { public Reference newReference(String uri, DigestMethod dm, List transforms, String type, String id) { - return new DOMReference(uri, type, dm, transforms, id); + return new DOMReference(uri, type, dm, transforms, id, getProvider()); } public Reference newReference(String uri, DigestMethod dm, @@ -83,7 +83,7 @@ public final class DOMXMLSignatureFactory extends XMLSignatureFactory { throw new NullPointerException("result cannot be null"); } return new DOMReference - (uri, type, dm, appliedTransforms, result, transforms, id); + (uri, type, dm, appliedTransforms, result, transforms, id, getProvider()); } public Reference newReference(String uri, DigestMethod dm, List transforms, @@ -92,7 +92,7 @@ public final class DOMXMLSignatureFactory extends XMLSignatureFactory { throw new NullPointerException("digestValue cannot be null"); } return new DOMReference - (uri, type, dm, null, null, transforms, id, digestValue); + (uri, type, dm, null, null, transforms, id, digestValue, getProvider()); } public SignedInfo newSignedInfo(CanonicalizationMethod cm, @@ -170,7 +170,7 @@ public final class DOMXMLSignatureFactory extends XMLSignatureFactory { "support DOM Level 2 and be namespace aware"); } if (tag.equals("Signature")) { - return new DOMXMLSignature(element, context); + return new DOMXMLSignature(element, context, getProvider()); } else { throw new MarshalException("invalid Signature tag: " + tag); } @@ -235,7 +235,12 @@ public final class DOMXMLSignatureFactory extends XMLSignatureFactory { public Transform newTransform(String algorithm, TransformParameterSpec params) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { - TransformService spi = TransformService.getInstance(algorithm, "DOM"); + TransformService spi; + try { + spi = TransformService.getInstance(algorithm, "DOM"); + } catch (NoSuchAlgorithmException nsae) { + spi = TransformService.getInstance(algorithm, "DOM", getProvider()); + } spi.init(params); return new DOMTransform(spi); } @@ -243,7 +248,12 @@ public final class DOMXMLSignatureFactory extends XMLSignatureFactory { public Transform newTransform(String algorithm, XMLStructure params) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { - TransformService spi = TransformService.getInstance(algorithm, "DOM"); + TransformService spi; + try { + spi = TransformService.getInstance(algorithm, "DOM"); + } catch (NoSuchAlgorithmException nsae) { + spi = TransformService.getInstance(algorithm, "DOM", getProvider()); + } if (params == null) { spi.init(null); } else { @@ -255,7 +265,12 @@ public final class DOMXMLSignatureFactory extends XMLSignatureFactory { public CanonicalizationMethod newCanonicalizationMethod(String algorithm, C14NMethodParameterSpec params) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { - TransformService spi = TransformService.getInstance(algorithm, "DOM"); + TransformService spi; + try { + spi = TransformService.getInstance(algorithm, "DOM"); + } catch (NoSuchAlgorithmException nsae) { + spi = TransformService.getInstance(algorithm, "DOM", getProvider()); + } spi.init(params); return new DOMCanonicalizationMethod(spi); } @@ -263,7 +278,12 @@ public final class DOMXMLSignatureFactory extends XMLSignatureFactory { public CanonicalizationMethod newCanonicalizationMethod(String algorithm, XMLStructure params) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { - TransformService spi = TransformService.getInstance(algorithm, "DOM"); + TransformService spi; + try { + spi = TransformService.getInstance(algorithm, "DOM"); + } catch (NoSuchAlgorithmException nsae) { + spi = TransformService.getInstance(algorithm, "DOM", getProvider()); + } if (params == null) { spi.init(null); } else { diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXPathFilter2Transform.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXPathFilter2Transform.java index c616cf8a35db9290f9f25b06d7de628c8b01cc10..8814b7b70be0b97a73a23819df79eabca99343f8 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXPathFilter2Transform.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXPathFilter2Transform.java @@ -1,28 +1,23 @@ /* - * Portions Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ - /* * =========================================================================== * @@ -31,7 +26,10 @@ * =========================================================================== */ /* - * $Id: DOMXPathFilter2Transform.java,v 1.18 2005/09/19 18:30:30 mullan Exp $ + * Portions copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMXPathFilter2Transform.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -129,7 +127,8 @@ public final class DOMXPathFilter2Transform extends ApacheTransform { XPathFilter2ParameterSpec xp = (XPathFilter2ParameterSpec) getParameterSpec(); String prefix = DOMUtils.getNSPrefix(context, Transform.XPATH2); - String qname = (prefix == null) ? "xmlns" : "xmlns:" + prefix; + String qname = (prefix == null || prefix.length() == 0) + ? "xmlns" : "xmlns:" + prefix; List list = xp.getXPathList(); for (int i = 0, size = list.size(); i < size; i++) { XPathType xpathType = (XPathType) list.get(i); diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXPathTransform.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXPathTransform.java index d4cdfd38b50b67da38f5016991e997a81c9d353f..3272f76c888244cdb3efcbf3ab49bbb9d1682bed 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXPathTransform.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXPathTransform.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMXPathTransform.java,v 1.16 2005/05/12 19:28:35 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMXPathTransform.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXSLTTransform.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXSLTTransform.java index 96a0a9a21d38fbacd67cf5b90116ea7243951c71..2ee51105638f5ad65416fb6d30dca0982986d5d5 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXSLTTransform.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/DOMXSLTTransform.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: DOMXSLTTransform.java,v 1.15 2005/05/10 18:15:36 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: DOMXSLTTransform.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/Utils.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/Utils.java index 0236909f38c02c8d64d968fc4963bf6cc985d426..1bbd7b20477f120d694a12ca20e1b34d8c00c4c1 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/Utils.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/Utils.java @@ -1,29 +1,28 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ /* - * $Id: Utils.java,v 1.14 2005/09/23 19:49:20 mullan Exp $ + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: Utils.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; diff --git a/src/share/classes/org/jcp/xml/dsig/internal/dom/XMLDSigRI.java b/src/share/classes/org/jcp/xml/dsig/internal/dom/XMLDSigRI.java index fbf4d9c4da77a52c8df5529cd2a57fd7bcb1d768..20958bc72784b25f557a3e114d9183a780bb2b76 100644 --- a/src/share/classes/org/jcp/xml/dsig/internal/dom/XMLDSigRI.java +++ b/src/share/classes/org/jcp/xml/dsig/internal/dom/XMLDSigRI.java @@ -1,28 +1,23 @@ /* - * Portions Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2005 The Apache Software Foundation. * - * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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). + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * - * 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. */ - /* * =========================================================================== * @@ -31,7 +26,10 @@ * =========================================================================== */ /* - * $Id: XMLDSigRI.java,v 1.7 2005/05/12 19:28:36 mullan Exp $ + * Portions copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * $Id: XMLDSigRI.java,v 1.2 2008/07/24 15:20:32 mullan Exp $ */ package org.jcp.xml.dsig.internal.dom; @@ -86,6 +84,22 @@ public final class XMLDSigRI extends Provider { CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS + " MechanismType", "DOM"); + // Inclusive C14N 1.1 + map.put((String)"TransformService." + + "http://www.w3.org/2006/12/xml-c14n11", + "org.jcp.xml.dsig.internal.dom.DOMCanonicalXMLC14N11Method"); + map.put((String)"TransformService." + + "http://www.w3.org/2006/12/xml-c14n11" + + " MechanismType", "DOM"); + + // InclusiveWithComments C14N 1.1 + map.put((String)"TransformService." + + "http://www.w3.org/2006/12/xml-c14n11#WithComments", + "org.jcp.xml.dsig.internal.dom.DOMCanonicalXMLC14N11Method"); + map.put((String)"TransformService." + + "http://www.w3.org/2006/12/xml-c14n11#WithComments" + + " MechanismType", "DOM"); + // Exclusive C14N map.put((String) "TransformService." + CanonicalizationMethod.EXCLUSIVE, "org.jcp.xml.dsig.internal.dom.DOMExcC14NMethod"); diff --git a/src/share/classes/org/jcp/xml/dsig/internal/package.html b/src/share/classes/org/jcp/xml/dsig/internal/package.html deleted file mode 100644 index d0e56dbf10423c7dc293a749948a6888d9d85fb0..0000000000000000000000000000000000000000 --- a/src/share/classes/org/jcp/xml/dsig/internal/package.html +++ /dev/null @@ -1,5 +0,0 @@ - - -Contains the classes of the Reference Implementation of JSR 105. - - diff --git a/src/share/classes/sun/management/ClassLoadingImpl.java b/src/share/classes/sun/management/ClassLoadingImpl.java index 2f4b6ed07317e147a589f6d9093c741f1cd8949a..9eda58380879e1fca7c42314866e1d79a078b901 100644 --- a/src/share/classes/sun/management/ClassLoadingImpl.java +++ b/src/share/classes/sun/management/ClassLoadingImpl.java @@ -71,6 +71,6 @@ class ClassLoadingImpl implements ClassLoadingMXBean { native static void setVerboseClass(boolean value); public ObjectName getObjectName() { - return Util.newObjectName(ManagementFactory.CLASS_LOADING_MXBEAN_NAME); + return ObjectName.valueOf(ManagementFactory.CLASS_LOADING_MXBEAN_NAME); } } diff --git a/src/share/classes/sun/management/CompilationImpl.java b/src/share/classes/sun/management/CompilationImpl.java index d69d9cc641e8508b8f44923d184096e373443547..9c13e67ebd71d24c8c90bbac2b63f6070c2eecf9 100644 --- a/src/share/classes/sun/management/CompilationImpl.java +++ b/src/share/classes/sun/management/CompilationImpl.java @@ -70,7 +70,7 @@ class CompilationImpl implements CompilationMXBean { } public ObjectName getObjectName() { - return Util.newObjectName(ManagementFactory.COMPILATION_MXBEAN_NAME); + return ObjectName.valueOf(ManagementFactory.COMPILATION_MXBEAN_NAME); } diff --git a/src/share/classes/sun/management/HotSpotDiagnostic.java b/src/share/classes/sun/management/HotSpotDiagnostic.java index f42188ff135532c94bec8601d454e11f7e410a87..d33337fcf9fee530664c99a8aa942f50d16ec4fe 100644 --- a/src/share/classes/sun/management/HotSpotDiagnostic.java +++ b/src/share/classes/sun/management/HotSpotDiagnostic.java @@ -117,6 +117,6 @@ public class HotSpotDiagnostic implements HotSpotDiagnosticMXBean { } public ObjectName getObjectName() { - return Util.newObjectName("com.sun.management:type=HotSpotDiagnostic"); + return ObjectName.valueOf("com.sun.management:type=HotSpotDiagnostic"); } } diff --git a/src/share/classes/sun/management/HotspotInternal.java b/src/share/classes/sun/management/HotspotInternal.java index 7006699a4d9a37bd73e7f21db0db229d14652183..88f9a82680cbd55fd838b5a29c0e6baaa93b2926 100644 --- a/src/share/classes/sun/management/HotspotInternal.java +++ b/src/share/classes/sun/management/HotspotInternal.java @@ -41,7 +41,7 @@ public class HotspotInternal private final static String HOTSPOT_INTERNAL_MBEAN_NAME = "sun.management:type=HotspotInternal"; - private static ObjectName objName = Util.newObjectName(HOTSPOT_INTERNAL_MBEAN_NAME); + private static ObjectName objName = ObjectName.valueOf(HOTSPOT_INTERNAL_MBEAN_NAME); private MBeanServer server = null; /** diff --git a/src/share/classes/sun/management/ManagementFactoryHelper.java b/src/share/classes/sun/management/ManagementFactoryHelper.java index 9bb4785d7ee1209a505274bcd5480cc8fe71f122..c07acfdbc61706e1114a354e863c8b86839a1be7 100644 --- a/src/share/classes/sun/management/ManagementFactoryHelper.java +++ b/src/share/classes/sun/management/ManagementFactoryHelper.java @@ -220,7 +220,7 @@ public class ManagementFactoryHelper { */ private static void addMBean(MBeanServer mbs, Object mbean, String mbeanName) { try { - final ObjectName objName = Util.newObjectName(mbeanName); + final ObjectName objName = ObjectName.valueOf(mbeanName); // inner class requires these fields to be final final MBeanServer mbs0 = mbs; @@ -280,7 +280,7 @@ public class ManagementFactoryHelper { private static void unregisterMBean(MBeanServer mbs, String mbeanName) { try { - final ObjectName objName = Util.newObjectName(mbeanName); + final ObjectName objName = ObjectName.valueOf(mbeanName); // inner class requires these fields to be final final MBeanServer mbs0 = mbs; diff --git a/src/share/classes/sun/management/MemoryImpl.java b/src/share/classes/sun/management/MemoryImpl.java index 29da467ce0b8ebae7b33b4d3c0e0ab97cdbecd44..aa56186ae5959ec35cfc9cd5c0f527bf60d8e642 100644 --- a/src/share/classes/sun/management/MemoryImpl.java +++ b/src/share/classes/sun/management/MemoryImpl.java @@ -177,7 +177,7 @@ class MemoryImpl extends NotificationEmitterSupport } public ObjectName getObjectName() { - return Util.newObjectName(ManagementFactory.MEMORY_MXBEAN_NAME); + return ObjectName.valueOf(ManagementFactory.MEMORY_MXBEAN_NAME); } } diff --git a/src/share/classes/sun/management/OperatingSystemImpl.java b/src/share/classes/sun/management/OperatingSystemImpl.java index cfe729688a7d45f19f7bd82011f0494902e02320..9ab8b5695ceff1e52a42d57bc6b4d2badfdce590 100644 --- a/src/share/classes/sun/management/OperatingSystemImpl.java +++ b/src/share/classes/sun/management/OperatingSystemImpl.java @@ -74,7 +74,7 @@ public class OperatingSystemImpl implements OperatingSystemMXBean { } } public ObjectName getObjectName() { - return Util.newObjectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME); + return ObjectName.valueOf(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME); } } diff --git a/src/share/classes/sun/management/RuntimeImpl.java b/src/share/classes/sun/management/RuntimeImpl.java index e58040e838802e648b8d53afc9bfd19ccad6123d..55bcbdc85f415d0c7ac6cb7513f656162a781770 100644 --- a/src/share/classes/sun/management/RuntimeImpl.java +++ b/src/share/classes/sun/management/RuntimeImpl.java @@ -149,7 +149,7 @@ class RuntimeImpl implements RuntimeMXBean { } public ObjectName getObjectName() { - return Util.newObjectName(ManagementFactory.RUNTIME_MXBEAN_NAME); + return ObjectName.valueOf(ManagementFactory.RUNTIME_MXBEAN_NAME); } } diff --git a/src/share/classes/sun/management/ThreadImpl.java b/src/share/classes/sun/management/ThreadImpl.java index d12258b9ea581c484c76f782a71e0e328c1550b3..565966e9ddd8fb91083a90fff8fa621a32660f2b 100644 --- a/src/share/classes/sun/management/ThreadImpl.java +++ b/src/share/classes/sun/management/ThreadImpl.java @@ -415,7 +415,7 @@ class ThreadImpl implements ThreadMXBean { private static native void resetContentionTimes0(long tid); public ObjectName getObjectName() { - return Util.newObjectName(ManagementFactory.THREAD_MXBEAN_NAME); + return ObjectName.valueOf(ManagementFactory.THREAD_MXBEAN_NAME); } } diff --git a/src/share/classes/sun/management/Util.java b/src/share/classes/sun/management/Util.java index 3c0997531c4261dc1e0cf1aa1d594b9b510a0e1c..1da8083005863a293ec7b4021bc73587a2fe735e 100644 --- a/src/share/classes/sun/management/Util.java +++ b/src/share/classes/sun/management/Util.java @@ -43,12 +43,8 @@ class Util { return (String[]) list.toArray(EMPTY_STRING_ARRAY); } - static ObjectName newObjectName(String name) { - return com.sun.jmx.mbeanserver.Util.newObjectName(name); - } - public static ObjectName newObjectName(String domainAndType, String name) { - return newObjectName(domainAndType + ",name=" + name); + return ObjectName.valueOf(domainAndType + ",name=" + name); } private static ManagementPermission monitorPermission = diff --git a/src/share/classes/sun/misc/JavaNioAccess.java b/src/share/classes/sun/misc/JavaNioAccess.java new file mode 100644 index 0000000000000000000000000000000000000000..4781cb7b4438a17d925da95a410ef710b61f73c0 --- /dev/null +++ b/src/share/classes/sun/misc/JavaNioAccess.java @@ -0,0 +1,32 @@ +/* + * 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 sun.misc; + +import java.nio.BufferPoolMXBean; + +public interface JavaNioAccess { + BufferPoolMXBean getDirectBufferPoolMXBean(); +} diff --git a/src/share/classes/sun/misc/SharedSecrets.java b/src/share/classes/sun/misc/SharedSecrets.java index 3a9db2364fcefbc985724fb637e7c9332b1b1cb7..b9de220bb20f3a2cec29d4f52d888bd69274e8f5 100644 --- a/src/share/classes/sun/misc/SharedSecrets.java +++ b/src/share/classes/sun/misc/SharedSecrets.java @@ -46,6 +46,7 @@ public class SharedSecrets { private static JavaIOAccess javaIOAccess; private static JavaIODeleteOnExitAccess javaIODeleteOnExitAccess; private static JavaNetAccess javaNetAccess; + private static JavaNioAccess javaNioAccess; private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess; public static JavaUtilJarAccess javaUtilJarAccess() { @@ -77,6 +78,20 @@ public class SharedSecrets { return javaNetAccess; } + public static void setJavaNioAccess(JavaNioAccess jna) { + javaNioAccess = jna; + } + + public static JavaNioAccess getJavaNioAccess() { + if (javaNioAccess == null) { + // Ensure java.nio.ByteOrder is initialized; we know that + // this class initializes java.nio.Bits that provides the + // shared secret. + unsafe.ensureClassInitialized(java.nio.ByteOrder.class); + } + return javaNioAccess; + } + public static void setJavaIOAccess(JavaIOAccess jia) { javaIOAccess = jia; } diff --git a/src/share/classes/sun/net/ConnectionResetException.java b/src/share/classes/sun/net/ConnectionResetException.java index 095ba913398ccf4ac67377566854890bb564bfba..69202945d4dd416d6bbb280e981b6855c781eade 100644 --- a/src/share/classes/sun/net/ConnectionResetException.java +++ b/src/share/classes/sun/net/ConnectionResetException.java @@ -1,5 +1,5 @@ /* - * Copyright 2002 Sun Microsystems, Inc. All Rights Reserved. + * 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 @@ -30,10 +30,11 @@ import java.net.SocketException; /** * Thrown to indicate a connection reset. * - * @since 1.4 + * @since 1.4.1 */ public class ConnectionResetException extends SocketException { + private static final long serialVersionUID = -7633185991801851556L; public ConnectionResetException(String msg) { super(msg); diff --git a/src/share/classes/sun/net/ProgressEvent.java b/src/share/classes/sun/net/ProgressEvent.java index ee4ec018d2273a303163786bdb783a882c58ae73..cba1007e32e43dfa0ae9503f2c8482785cebd7fc 100644 --- a/src/share/classes/sun/net/ProgressEvent.java +++ b/src/share/classes/sun/net/ProgressEvent.java @@ -32,6 +32,7 @@ import java.net.URL; * * @author Stanley Man-Kit Ho */ +@SuppressWarnings("serial") // never serialized public class ProgressEvent extends EventObject { // URL of the stream private URL url; diff --git a/src/share/classes/sun/net/TelnetProtocolException.java b/src/share/classes/sun/net/TelnetProtocolException.java index 4cf4e72db69335cca945f862a401a8698b032241..8400d13ba993009022292b48f0d8eb5605dd21a6 100644 --- a/src/share/classes/sun/net/TelnetProtocolException.java +++ b/src/share/classes/sun/net/TelnetProtocolException.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1995 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1994-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 @@ -35,6 +35,8 @@ import java.io.*; */ public class TelnetProtocolException extends IOException { + private static final long serialVersionUID = 8509127047257111343L; + public TelnetProtocolException(String s) { super(s); } diff --git a/src/share/classes/sun/net/ftp/FtpLoginException.java b/src/share/classes/sun/net/ftp/FtpLoginException.java index 55cf34ffe100ebf84c282698b43d9f595b0b3ef6..0d37a8706ce100e7b4c08f4a261c37c365321e14 100644 --- a/src/share/classes/sun/net/ftp/FtpLoginException.java +++ b/src/share/classes/sun/net/ftp/FtpLoginException.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1995 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1994-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 @@ -34,6 +34,8 @@ import java.io.*; * @author Jonathan Payne */ public class FtpLoginException extends FtpProtocolException { + private static final long serialVersionUID = 2218162403237941536L; + FtpLoginException(String s) { super(s); } diff --git a/src/share/classes/sun/net/ftp/FtpProtocolException.java b/src/share/classes/sun/net/ftp/FtpProtocolException.java index 9745f9eb999fe1d499444a6f8928550b11567181..6afbe215e0f659c68aaa72750614be5285281331 100644 --- a/src/share/classes/sun/net/ftp/FtpProtocolException.java +++ b/src/share/classes/sun/net/ftp/FtpProtocolException.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-1995 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1994-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 @@ -34,6 +34,8 @@ import java.io.*; * @author Jonathan Payne */ public class FtpProtocolException extends IOException { + private static final long serialVersionUID = 5978077070276545054L; + FtpProtocolException(String s) { super(s); } diff --git a/src/share/classes/sun/net/httpserver/ChunkedOutputStream.java b/src/share/classes/sun/net/httpserver/ChunkedOutputStream.java index f53d40e5ee619da1b767bda3b19314f0b4124a6e..bbef17c64e2cac62301c0dfd36dbb67c83b248e7 100644 --- a/src/share/classes/sun/net/httpserver/ChunkedOutputStream.java +++ b/src/share/classes/sun/net/httpserver/ChunkedOutputStream.java @@ -73,6 +73,7 @@ class ChunkedOutputStream extends FilterOutputStream if (count == CHUNK_SIZE) { writeChunk(); } + assert count < CHUNK_SIZE; } public void write (byte[]b, int off, int len) throws IOException { @@ -86,20 +87,22 @@ class ChunkedOutputStream extends FilterOutputStream writeChunk(); len -= remain; off += remain; - while (len > CHUNK_SIZE) { + while (len >= CHUNK_SIZE) { System.arraycopy (b,off,buf,OFFSET,CHUNK_SIZE); len -= CHUNK_SIZE; off += CHUNK_SIZE; count = CHUNK_SIZE; writeChunk(); } - pos = OFFSET; } if (len > 0) { System.arraycopy (b,off,buf,pos,len); count += len; pos += len; } + if (count == CHUNK_SIZE) { + writeChunk(); + } } /** diff --git a/src/share/classes/sun/net/httpserver/HttpError.java b/src/share/classes/sun/net/httpserver/HttpError.java index a6dd066aa886a2e4682c146b82d9a21ffdd4c695..77dca7ed57d5112114f3b061016656e5abd0dddc 100644 --- a/src/share/classes/sun/net/httpserver/HttpError.java +++ b/src/share/classes/sun/net/httpserver/HttpError.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-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 @@ -29,6 +29,8 @@ package sun.net.httpserver; * A Http error */ class HttpError extends RuntimeException { + private static final long serialVersionUID = 8769596371344178179L; + public HttpError (String msg) { super (msg); } diff --git a/src/share/classes/sun/net/httpserver/StreamClosedException.java b/src/share/classes/sun/net/httpserver/StreamClosedException.java index 0fc2c6d5039bf922040e329de809ffc3e891e094..09295fdc1f993e2fd1ab93c5f3b41867e7488e2b 100644 --- a/src/share/classes/sun/net/httpserver/StreamClosedException.java +++ b/src/share/classes/sun/net/httpserver/StreamClosedException.java @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-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 @@ -28,4 +28,5 @@ package sun.net.httpserver; import java.io.*; class StreamClosedException extends IOException { + private static final long serialVersionUID = -4485921499356327937L; } diff --git a/src/share/classes/sun/net/smtp/SmtpProtocolException.java b/src/share/classes/sun/net/smtp/SmtpProtocolException.java index 0550eea738eb47e8cd2a190308d0d990d3c699e5..e52563dbdce8d55f4b58ccca8d2077256870fd06 100644 --- a/src/share/classes/sun/net/smtp/SmtpProtocolException.java +++ b/src/share/classes/sun/net/smtp/SmtpProtocolException.java @@ -1,5 +1,5 @@ /* - * Copyright 1995 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-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 @@ -32,6 +32,8 @@ import java.io.IOException; * an SMTP session. */ public class SmtpProtocolException extends IOException { + private static final long serialVersionUID = -7547136771133814908L; + SmtpProtocolException(String s) { super(s); } diff --git a/src/share/classes/sun/net/www/ApplicationLaunchException.java b/src/share/classes/sun/net/www/ApplicationLaunchException.java index 3b346d5bea58a1c4d6c1979f8b465adf5f2e9f87..fe4370690a14ee5b0ff2ccf4216d373ecf4d2eb6 100644 --- a/src/share/classes/sun/net/www/ApplicationLaunchException.java +++ b/src/share/classes/sun/net/www/ApplicationLaunchException.java @@ -1,5 +1,5 @@ /* - * Copyright 1996 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-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 @@ -33,6 +33,8 @@ package sun.net.www; */ public class ApplicationLaunchException extends Exception { + private static final long serialVersionUID = -4782286141289536883L; + public ApplicationLaunchException(String reason) { super(reason); } diff --git a/src/share/classes/sun/net/www/http/KeepAliveStreamCleaner.java b/src/share/classes/sun/net/www/http/KeepAliveStreamCleaner.java index 7eea3194cc14ab7429b068d34c77ec71c3325ee4..ec149197f0cea5235862a4fff7dc3f2ee8d7c61e 100644 --- a/src/share/classes/sun/net/www/http/KeepAliveStreamCleaner.java +++ b/src/share/classes/sun/net/www/http/KeepAliveStreamCleaner.java @@ -43,6 +43,7 @@ import java.security.PrivilegedAction; * @author Chris Hegarty */ +@SuppressWarnings("serial") // never serialized public class KeepAliveStreamCleaner extends LinkedBlockingQueue implements Runnable { // maximum amount of remaining data that we will try to cleanup diff --git a/src/share/classes/sun/net/www/protocol/http/DigestAuthentication.java b/src/share/classes/sun/net/www/protocol/http/DigestAuthentication.java index 7720640a04b9f4875eb2e0aa37081554822136e0..8ddaa4d87d3b83f79445527c54e1cd85c6bccf66 100644 --- a/src/share/classes/sun/net/www/protocol/http/DigestAuthentication.java +++ b/src/share/classes/sun/net/www/protocol/http/DigestAuthentication.java @@ -59,6 +59,8 @@ class DigestAuthentication extends AuthenticationInfo { // instances as a result of a single authorization (for multiple domains) static class Parameters implements java.io.Serializable { + private static final long serialVersionUID = -3584543755194526252L; + private boolean serverQop; // server proposed qop=auth private String opaque; private String cnonce; diff --git a/src/share/classes/sun/nio/ch/DatagramChannelImpl.java b/src/share/classes/sun/nio/ch/DatagramChannelImpl.java index 029ab3e11689daa132450eed713045590015cf88..a7939c0ce6e70700f4e8b14f81e0b6f5a07aa5f0 100644 --- a/src/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/src/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -31,7 +31,7 @@ import java.net.*; import java.nio.ByteBuffer; import java.nio.channels.*; import java.nio.channels.spi.*; -import java.lang.ref.SoftReference; +import java.util.*; /** @@ -47,11 +47,14 @@ class DatagramChannelImpl private static NativeDispatcher nd = new DatagramDispatcher(); // Our file descriptor - FileDescriptor fd = null; + private final FileDescriptor fd; // fd value needed for dev/poll. This value will remain valid // even after the value in the file descriptor object has been set to -1 - int fdVal; + private final int fdVal; + + // The protocol family of the socket + private final ProtocolFamily family; // IDs of native threads doing reads and writes, for signalling private volatile long readerThread = 0; @@ -59,8 +62,8 @@ class DatagramChannelImpl // Cached InetAddress and port for unconnected DatagramChannels // used by receive0 - private InetAddress cachedSenderInetAddress = null; - private int cachedSenderPort = 0; + private InetAddress cachedSenderInetAddress; + private int cachedSenderPort; // Lock held by current reading or connecting thread private final Object readLock = new Object(); @@ -76,20 +79,20 @@ class DatagramChannelImpl // State (does not necessarily increase monotonically) private static final int ST_UNINITIALIZED = -1; - private static int ST_UNCONNECTED = 0; - private static int ST_CONNECTED = 1; + private static final int ST_UNCONNECTED = 0; + private static final int ST_CONNECTED = 1; private static final int ST_KILLED = 2; private int state = ST_UNINITIALIZED; // Binding - private SocketAddress localAddress = null; - SocketAddress remoteAddress = null; - - // Options - private SocketOpts.IP options = null; + private SocketAddress localAddress; + private SocketAddress remoteAddress; // Our socket adaptor, if any - private DatagramSocket socket = null; + private DatagramSocket socket; + + // Multicast support + private MembershipRegistry registry; // -- End of fields protected by stateLock @@ -98,7 +101,26 @@ class DatagramChannelImpl throws IOException { super(sp); - this.fd = Net.socket(false); + this.family = Net.isIPv6Available() ? + StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; + this.fd = Net.socket(family, false); + this.fdVal = IOUtil.fdVal(fd); + this.state = ST_UNCONNECTED; + } + + public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family) { + super(sp); + if ((family != StandardProtocolFamily.INET) && + (family != StandardProtocolFamily.INET6)) { + throw new UnsupportedOperationException("Protocol family not supported"); + } + if (family == StandardProtocolFamily.INET6) { + if (!Net.isIPv6Available()) { + throw new UnsupportedOperationException("IPv6 not available"); + } + } + this.family = family; + this.fd = Net.socket(family, false); this.fdVal = IOUtil.fdVal(fd); this.state = ST_UNCONNECTED; } @@ -107,9 +129,12 @@ class DatagramChannelImpl throws IOException { super(sp); + this.family = Net.isIPv6Available() ? + StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; this.fd = fd; this.fdVal = IOUtil.fdVal(fd); this.state = ST_UNCONNECTED; + this.localAddress = Net.localAddress(fd); } public DatagramSocket socket() { @@ -120,6 +145,156 @@ class DatagramChannelImpl } } + @Override + public SocketAddress getLocalAddress() throws IOException { + synchronized (stateLock) { + if (!isOpen()) + return null; + return localAddress; + } + } + + @Override + public SocketAddress getConnectedAddress() throws IOException { + synchronized (stateLock) { + if (!isOpen()) + return null; + return remoteAddress; + } + } + + @Override + public DatagramChannel setOption(SocketOption name, Object value) + throws IOException + { + if (name == null) + throw new NullPointerException(); + if (!options().contains(name)) + throw new IllegalArgumentException("Invalid option name"); + + synchronized (stateLock) { + ensureOpen(); + + if (name == StandardSocketOption.IP_TOS) { + // IPv4 only; no-op for IPv6 + if (family == StandardProtocolFamily.INET) { + Net.setSocketOption(fd, family, name, value); + } + return this; + } + + if (name == StandardSocketOption.IP_MULTICAST_TTL || + name == StandardSocketOption.IP_MULTICAST_LOOP) + { + // options are protocol dependent + Net.setSocketOption(fd, family, name, value); + return this; + } + + if (name == StandardSocketOption.IP_MULTICAST_IF) { + if (value == null) + throw new IllegalArgumentException("Cannot set IP_MULTICAST_IF to 'null'"); + NetworkInterface interf = (NetworkInterface)value; + if (family == StandardProtocolFamily.INET6) { + int index = interf.getIndex(); + if (index == -1) + throw new IOException("Network interface cannot be identified"); + Net.setInterface6(fd, index); + } else { + // need IPv4 address to identify interface + Inet4Address target = Net.anyInet4Address(interf); + if (target == null) + throw new IOException("Network interface not configured for IPv4"); + int targetAddress = Net.inet4AsInt(target); + Net.setInterface4(fd, targetAddress); + } + return this; + } + + // remaining options don't need any special handling + Net.setSocketOption(fd, Net.UNSPEC, name, value); + return this; + } + } + + @Override + @SuppressWarnings("unchecked") + public T getOption(SocketOption name) + throws IOException + { + if (name == null) + throw new NullPointerException(); + if (!options().contains(name)) + throw new IllegalArgumentException("Invalid option name"); + + synchronized (stateLock) { + ensureOpen(); + + if (name == StandardSocketOption.IP_TOS) { + // IPv4 only; always return 0 on IPv6 + if (family == StandardProtocolFamily.INET) { + return (T) Net.getSocketOption(fd, family, name); + } else { + return (T) Integer.valueOf(0); + } + } + + if (name == StandardSocketOption.IP_MULTICAST_TTL || + name == StandardSocketOption.IP_MULTICAST_LOOP) + { + return (T) Net.getSocketOption(fd, family, name); + } + + if (name == StandardSocketOption.IP_MULTICAST_IF) { + if (family == StandardProtocolFamily.INET) { + int address = Net.getInterface4(fd); + if (address == 0) + return null; // default interface + + InetAddress ia = Net.inet4FromInt(address); + NetworkInterface ni = NetworkInterface.getByInetAddress(ia); + if (ni == null) + throw new IOException("Unable to map address to interface"); + return (T) ni; + } else { + int index = Net.getInterface6(fd); + if (index == 0) + return null; // default interface + + NetworkInterface ni = NetworkInterface.getByIndex(index); + if (ni == null) + throw new IOException("Unable to map index to interface"); + return (T) ni; + } + } + + // no special handling + return (T) Net.getSocketOption(fd, Net.UNSPEC, name); + } + } + + private static class LazyInitialization { + static final Set> defaultOptions = defaultOptions(); + + private static Set> defaultOptions() { + HashSet> set = new HashSet>(8); + set.add(StandardSocketOption.SO_SNDBUF); + set.add(StandardSocketOption.SO_RCVBUF); + set.add(StandardSocketOption.SO_REUSEADDR); + set.add(StandardSocketOption.SO_BROADCAST); + set.add(StandardSocketOption.IP_TOS); + set.add(StandardSocketOption.IP_MULTICAST_IF); + set.add(StandardSocketOption.IP_MULTICAST_TTL); + set.add(StandardSocketOption.IP_MULTICAST_LOOP); + return Collections.unmodifiableSet(set); + } + } + + @Override + public final Set> options() { + return LazyInitialization.defaultOptions; + } + private void ensureOpen() throws ClosedChannelException { if (!isOpen()) throw new ClosedChannelException(); @@ -135,8 +310,10 @@ class DatagramChannelImpl synchronized (readLock) { ensureOpen(); // If socket is not bound then behave as if nothing received - if (!isBound()) // ## NotYetBoundException ?? + // Will be fixed by 6621699 + if (localAddress() == null) { return null; + } int n = 0; ByteBuffer bb = null; try { @@ -267,6 +444,12 @@ class DatagramChannelImpl do { n = send(fd, src, target); } while ((n == IOStatus.INTERRUPTED) && isOpen()); + + synchronized (stateLock) { + if (isOpen() && (localAddress == null)) { + localAddress = Net.localAddress(fd); + } + } return IOStatus.normalize(n); } finally { writerThread = 0; @@ -316,7 +499,8 @@ class DatagramChannelImpl assert (pos <= lim); int rem = (pos <= lim ? lim - pos : 0); - int written = send0(fd, ((DirectBuffer)bb).address() + pos, + boolean preferIPv6 = (family != StandardProtocolFamily.INET); + int written = send0(preferIPv6, fd, ((DirectBuffer)bb).address() + pos, rem, target); if (written > 0) bb.position(pos + written); @@ -453,42 +637,8 @@ class DatagramChannelImpl IOUtil.configureBlocking(fd, block); } - public SocketOpts options() { - synchronized (stateLock) { - if (options == null) { - SocketOptsImpl.Dispatcher d - = new SocketOptsImpl.Dispatcher() { - int getInt(int opt) throws IOException { - return Net.getIntOption(fd, opt); - } - void setInt(int opt, int arg) - throws IOException - { - Net.setIntOption(fd, opt, arg); - } - }; - options = new SocketOptsImpl.IP(d); - } - return options; - } - } - - public boolean isBound() { - return Net.localPortNumber(fd) != 0; - } - public SocketAddress localAddress() { synchronized (stateLock) { - if (isConnected() && (localAddress == null)) { - // Socket was not bound before connecting, - // so ask what the address turned out to be - localAddress = Net.localAddress(fd); - } - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - InetSocketAddress isa = (InetSocketAddress)localAddress; - sm.checkConnect(isa.getAddress().getHostAddress(), -1); - } return localAddress; } } @@ -499,22 +649,37 @@ class DatagramChannelImpl } } - public void bind(SocketAddress local) throws IOException { + @Override + public DatagramChannel bind(SocketAddress local) throws IOException { synchronized (readLock) { synchronized (writeLock) { synchronized (stateLock) { ensureOpen(); - if (isBound()) + if (localAddress != null) throw new AlreadyBoundException(); - InetSocketAddress isa = Net.checkAddress(local); + InetSocketAddress isa; + if (local == null) { + isa = new InetSocketAddress(0); + } else { + isa = Net.checkAddress(local); + + // only Inet4Address allowed with IPv4 socket + if (family == StandardProtocolFamily.INET) { + InetAddress addr = isa.getAddress(); + if (!(addr instanceof Inet4Address)) + throw new UnsupportedAddressTypeException(); + } + } SecurityManager sm = System.getSecurityManager(); - if (sm != null) + if (sm != null) { sm.checkListen(isa.getPort()); - Net.bind(fd, isa.getAddress(), isa.getPort()); + } + Net.bind(family, fd, isa.getAddress(), isa.getPort()); localAddress = Net.localAddress(fd); } } } + return this; } public boolean isConnected() { @@ -533,7 +698,6 @@ class DatagramChannelImpl } public DatagramChannel connect(SocketAddress sa) throws IOException { - int trafficClass = 0; int localPort = 0; synchronized(readLock) { @@ -545,10 +709,10 @@ class DatagramChannelImpl if (sm != null) sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort()); - int n = Net.connect(fd, + int n = Net.connect(family, + fd, isa.getAddress(), - isa.getPort(), - trafficClass); + isa.getPort()); if (n <= 0) throw new Error(); // Can't happen @@ -558,6 +722,11 @@ class DatagramChannelImpl sender = isa; cachedSenderInetAddress = isa.getAddress(); cachedSenderPort = isa.getPort(); + + // Socket was not bound before connecting, + if (localAddress == null) { + localAddress = Net.localAddress(fd); + } } } } @@ -584,9 +753,215 @@ class DatagramChannelImpl return this; } + /** + * Joins channel's socket to the given group/interface and + * optional source address. + */ + private MembershipKey innerJoin(InetAddress group, + NetworkInterface interf, + InetAddress source) + throws IOException + { + if (!group.isMulticastAddress()) + throw new IllegalArgumentException("Group not a multicast address"); + + // check multicast address is compatible with this socket + if (!(group instanceof Inet4Address)) { + if (family == StandardProtocolFamily.INET) + throw new IllegalArgumentException("Group is not IPv4 address"); + if (!(group instanceof Inet6Address)) + throw new IllegalArgumentException("Address type not supported"); + } + + // check source address + if (source != null) { + if (source.isAnyLocalAddress()) + throw new IllegalArgumentException("Source address is a wildcard address"); + if (source.isMulticastAddress()) + throw new IllegalArgumentException("Source address is multicast address"); + if (source.getClass() != group.getClass()) + throw new IllegalArgumentException("Source address is different type to group"); + } + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkMulticast(group); + + synchronized (stateLock) { + if (!isOpen()) + throw new ClosedChannelException(); + + // check the registry to see if we are already a member of the group + if (registry == null) { + registry = new MembershipRegistry(); + } else { + // return existing membership key + MembershipKey key = registry.checkMembership(group, interf, source); + if (key != null) + return key; + } + + MembershipKeyImpl key; + if (family == StandardProtocolFamily.INET6) { + int index = interf.getIndex(); + if (index == -1) + throw new IOException("Network interface cannot be identified"); + + // need multicast and source address as byte arrays + byte[] groupAddress = Net.inet6AsByteArray(group); + byte[] sourceAddress = (source == null) ? null : + Net.inet6AsByteArray(source); + + // join the group + int n = Net.join6(fd, groupAddress, index, sourceAddress); + if (n == IOStatus.UNAVAILABLE) + throw new UnsupportedOperationException(); + + key = new MembershipKeyImpl.Type6(this, group, interf, source, + groupAddress, index, sourceAddress); + + } else { + // need IPv4 address to identify interface + Inet4Address target = Net.anyInet4Address(interf); + if (target == null) + throw new IOException("Network interface not configured for IPv4"); + + int groupAddress = Net.inet4AsInt(group); + int targetAddress = Net.inet4AsInt(target); + int sourceAddress = (source == null) ? 0 : Net.inet4AsInt(source); + + // join the group + int n = Net.join4(fd, groupAddress, targetAddress, sourceAddress); + if (n == IOStatus.UNAVAILABLE) + throw new UnsupportedOperationException(); + + key = new MembershipKeyImpl.Type4(this, group, interf, source, + groupAddress, targetAddress, sourceAddress); + } + + registry.add(key); + return key; + } + } + + @Override + public MembershipKey join(InetAddress group, + NetworkInterface interf) + throws IOException + { + return innerJoin(group, interf, null); + } + + @Override + public MembershipKey join(InetAddress group, + NetworkInterface interf, + InetAddress source) + throws IOException + { + if (source == null) + throw new NullPointerException("source address is null"); + return innerJoin(group, interf, source); + } + + // package-private + void drop(MembershipKeyImpl key) + throws IOException + { + assert key.getChannel() == this; + + synchronized (stateLock) { + if (!key.isValid()) + return; + + if (family == StandardProtocolFamily.INET6) { + MembershipKeyImpl.Type6 key6 = + (MembershipKeyImpl.Type6)key; + Net.drop6(fd, key6.group(), key6.index(), key6.source()); + } else { + MembershipKeyImpl.Type4 key4 = + (MembershipKeyImpl.Type4)key; + Net.drop4(fd, key4.group(), key4.interfaceAddress(), key4.source()); + } + + key.invalidate(); + registry.remove(key); + } + } + + /** + * Block datagrams from given source if a memory to receive all + * datagrams. + */ + void block(MembershipKeyImpl key, InetAddress source) + throws IOException + { + assert key.getChannel() == this; + assert key.getSourceAddress() == null; + + synchronized (stateLock) { + if (!key.isValid()) + throw new IllegalStateException("key is no longer valid"); + if (source.isAnyLocalAddress()) + throw new IllegalArgumentException("Source address is a wildcard address"); + if (source.isMulticastAddress()) + throw new IllegalArgumentException("Source address is multicast address"); + if (source.getClass() != key.getGroup().getClass()) + throw new IllegalArgumentException("Source address is different type to group"); + + int n; + if (family == StandardProtocolFamily.INET6) { + MembershipKeyImpl.Type6 key6 = + (MembershipKeyImpl.Type6)key; + n = Net.block6(fd, key6.group(), key6.index(), + Net.inet6AsByteArray(source)); + } else { + MembershipKeyImpl.Type4 key4 = + (MembershipKeyImpl.Type4)key; + n = Net.block4(fd, key4.group(), key4.interfaceAddress(), + Net.inet4AsInt(source)); + } + if (n == IOStatus.UNAVAILABLE) { + // ancient kernel + throw new UnsupportedOperationException(); + } + } + } + + /** + * Unblock given source. + */ + void unblock(MembershipKeyImpl key, InetAddress source) + throws IOException + { + assert key.getChannel() == this; + assert key.getSourceAddress() == null; + + synchronized (stateLock) { + if (!key.isValid()) + throw new IllegalStateException("key is no longer valid"); + + if (family == StandardProtocolFamily.INET6) { + MembershipKeyImpl.Type6 key6 = + (MembershipKeyImpl.Type6)key; + Net.unblock6(fd, key6.group(), key6.index(), + Net.inet6AsByteArray(source)); + } else { + MembershipKeyImpl.Type4 key4 = + (MembershipKeyImpl.Type4)key; + Net.unblock4(fd, key4.group(), key4.interfaceAddress(), + Net.inet4AsInt(source)); + } + } + } + protected void implCloseSelectableChannel() throws IOException { synchronized (stateLock) { nd.preClose(fd); + + // if member of mulitcast group then invalidate all keys + if (registry != null) + registry.invalidateAll(); + long th; if ((th = readerThread) != 0) NativeThread.signal(th); @@ -695,8 +1070,8 @@ class DatagramChannelImpl boolean connected) throws IOException; - private native int send0(FileDescriptor fd, long address, int len, - SocketAddress sa) + private native int send0(boolean preferIPv6, FileDescriptor fd, long address, int len, + SocketAddress sa) throws IOException; static { diff --git a/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java b/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java index 79a0d41b469b3a5b1d47c9d0e5c34e586c3da893..34b24225a5f4ee91a889bf13ce66cef3d16f9963 100644 --- a/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java +++ b/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java @@ -45,16 +45,9 @@ public class DatagramSocketAdaptor // The channel being adapted private final DatagramChannelImpl dc; - // Option adaptor object, created on demand - private volatile OptionAdaptor opts = null; - // Timeout "option" value for receives private volatile int timeout = 0; - // Traffic-class/Type-of-service - private volatile int trafficClass = 0; - - // ## super will create a useless impl private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException { // Invoke the DatagramSocketAdaptor(SocketAddress) constructor, @@ -82,7 +75,7 @@ public class DatagramSocketAdaptor throw new IllegalArgumentException("connect: " + port); if (remote == null) throw new IllegalArgumentException("connect: null address"); - if (!isClosed()) + if (isClosed()) return; try { dc.connect(remote); @@ -124,11 +117,11 @@ public class DatagramSocketAdaptor } public boolean isBound() { - return dc.isBound(); + return dc.localAddress() != null; } public boolean isConnected() { - return dc.isConnected(); + return dc.remoteAddress() != null; } public InetAddress getInetAddress() { @@ -157,7 +150,7 @@ public class DatagramSocketAdaptor // Legacy DatagramSocket will send in this case // and set address and port of the packet InetSocketAddress isa = (InetSocketAddress) - dc.remoteAddress; + dc.remoteAddress(); p.setPort(isa.getPort()); p.setAddress(isa.getAddress()); dc.write(bb); @@ -241,21 +234,32 @@ public class DatagramSocketAdaptor public InetAddress getLocalAddress() { if (isClosed()) return null; - try { - return Net.asInetSocketAddress(dc.localAddress()).getAddress(); - } catch (Exception x) { - return new InetSocketAddress(0).getAddress(); + SocketAddress local = dc.localAddress(); + if (local == null) + local = new InetSocketAddress(0); + InetAddress result = ((InetSocketAddress)local).getAddress(); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + try { + sm.checkConnect(result.getHostAddress(), -1); + } catch (SecurityException x) { + return new InetSocketAddress(0).getAddress(); + } } + return result; } public int getLocalPort() { if (isClosed()) return -1; try { - return Net.asInetSocketAddress(dc.localAddress()).getPort(); + SocketAddress local = dc.getLocalAddress(); + if (local != null) { + return ((InetSocketAddress)local).getPort(); + } } catch (Exception x) { - return 0; } + return 0; } public void setSoTimeout(int timeout) throws SocketException { @@ -266,55 +270,87 @@ public class DatagramSocketAdaptor return timeout; } - private OptionAdaptor opts() { - if (opts == null) - opts = new OptionAdaptor(dc); - return opts; + private void setBooleanOption(SocketOption name, boolean value) + throws SocketException + { + try { + dc.setOption(name, value); + } catch (IOException x) { + Net.translateToSocketException(x); + } + } + + private void setIntOption(SocketOption name, int value) + throws SocketException + { + try { + dc.setOption(name, value); + } catch (IOException x) { + Net.translateToSocketException(x); + } + } + + private boolean getBooleanOption(SocketOption name) throws SocketException { + try { + return dc.getOption(name).booleanValue(); + } catch (IOException x) { + Net.translateToSocketException(x); + return false; // keep compiler happy + } + } + + private int getIntOption(SocketOption name) throws SocketException { + try { + return dc.getOption(name).intValue(); + } catch (IOException x) { + Net.translateToSocketException(x); + return -1; // keep compiler happy + } } public void setSendBufferSize(int size) throws SocketException { - opts().setSendBufferSize(size); + if (size <= 0) + throw new IllegalArgumentException("Invalid send size"); + setIntOption(StandardSocketOption.SO_SNDBUF, size); } public int getSendBufferSize() throws SocketException { - return opts().getSendBufferSize(); + return getIntOption(StandardSocketOption.SO_SNDBUF); } public void setReceiveBufferSize(int size) throws SocketException { - opts().setReceiveBufferSize(size); + if (size <= 0) + throw new IllegalArgumentException("Invalid receive size"); + setIntOption(StandardSocketOption.SO_RCVBUF, size); } public int getReceiveBufferSize() throws SocketException { - return opts().getReceiveBufferSize(); + return getIntOption(StandardSocketOption.SO_RCVBUF); } public void setReuseAddress(boolean on) throws SocketException { - opts().setReuseAddress(on); + setBooleanOption(StandardSocketOption.SO_REUSEADDR, on); } public boolean getReuseAddress() throws SocketException { - return opts().getReuseAddress(); + return getBooleanOption(StandardSocketOption.SO_REUSEADDR); + } public void setBroadcast(boolean on) throws SocketException { - opts().setBroadcast(on); + setBooleanOption(StandardSocketOption.SO_BROADCAST, on); } public boolean getBroadcast() throws SocketException { - return opts().getBroadcast(); + return getBooleanOption(StandardSocketOption.SO_BROADCAST); } public void setTrafficClass(int tc) throws SocketException { - opts().setTrafficClass(tc); - trafficClass = tc; + setIntOption(StandardSocketOption.IP_TOS, tc); } public int getTrafficClass() throws SocketException { - int tc = opts().getTrafficClass(); - if (tc < 0) { - tc = trafficClass; - } - return tc; + return getIntOption(StandardSocketOption.IP_TOS); } public void close() { diff --git a/src/share/classes/sun/nio/ch/ExtendedSocketOption.java b/src/share/classes/sun/nio/ch/ExtendedSocketOption.java new file mode 100644 index 0000000000000000000000000000000000000000..86e787ef80558f1a45deaa55f983fdd219f23464 --- /dev/null +++ b/src/share/classes/sun/nio/ch/ExtendedSocketOption.java @@ -0,0 +1,44 @@ +/* + * 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 sun.nio.ch; + +import java.net.SocketOption; + +/** + * Defines socket options that are supported by the implementation + * but not defined in StandardSocketOption. + */ + +class ExtendedSocketOption { + private ExtendedSocketOption() { } + + static final SocketOption SO_OOBINLINE = + new SocketOption() { + public String name() { return "SO_OOBINLINE"; } + public Class type() { return Boolean.class; } + public String toString() { return name(); } + }; +} diff --git a/src/share/classes/sun/nio/ch/FileChannelImpl.java b/src/share/classes/sun/nio/ch/FileChannelImpl.java index c4ac22c04a2adad652658a3b87ce4b588706083a..894c489cd85bef90a03857b0690e203c008ed5c2 100644 --- a/src/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/src/share/classes/sun/nio/ch/FileChannelImpl.java @@ -32,6 +32,7 @@ import java.io.RandomAccessFile; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; +import java.nio.BufferPoolMXBean; import java.nio.channels.*; import java.nio.channels.spi.*; import java.util.ArrayList; @@ -43,10 +44,12 @@ import java.lang.ref.ReferenceQueue; import java.lang.reflect.Field; import java.security.AccessController; import java.security.PrivilegedAction; +import javax.management.ObjectName; +import javax.management.MalformedObjectNameException; + import sun.misc.Cleaner; import sun.security.action.GetPropertyAction; - public class FileChannelImpl extends FileChannel { @@ -681,14 +684,26 @@ public class FileChannelImpl private static class Unmapper implements Runnable { + // keep track of mapped buffer usage + static volatile int count; + static volatile long totalSize; + static volatile long totalCapacity; private long address; private long size; + private int cap; - private Unmapper(long address, long size) { + private Unmapper(long address, long size, int cap) { assert (address != 0); this.address = address; this.size = size; + this.cap = cap; + + synchronized (Unmapper.class) { + count++; + totalSize += size; + totalCapacity += cap; + } } public void run() { @@ -696,8 +711,13 @@ public class FileChannelImpl return; unmap0(address, size); address = 0; - } + synchronized (Unmapper.class) { + count--; + totalSize -= size; + totalCapacity -= cap; + } + } } private static void unmap(MappedByteBuffer bb) { @@ -786,7 +806,7 @@ public class FileChannelImpl assert (IOStatus.checkAll(addr)); assert (addr % allocationGranularity == 0); int isize = (int)size; - Unmapper um = new Unmapper(addr, size + pagePosition); + Unmapper um = new Unmapper(addr, size + pagePosition, isize); if ((!writable) || (imode == MAP_RO)) return Util.newMappedByteBufferR(isize, addr + pagePosition, um); else @@ -797,6 +817,49 @@ public class FileChannelImpl } } + /** + * Returns the management interface for mapped buffers + */ + public static BufferPoolMXBean getMappedBufferPoolMXBean() { + return LazyInitialization.mappedBufferPoolMXBean; + } + + // Lazy initialization of management interface + private static class LazyInitialization { + static final BufferPoolMXBean mappedBufferPoolMXBean = mappedBufferPoolMXBean(); + + private static BufferPoolMXBean mappedBufferPoolMXBean() { + final String pool = "mapped"; + final ObjectName obj; + try { + obj = new ObjectName("java.nio:type=BufferPool,name=" + pool); + } catch (MalformedObjectNameException x) { + throw new AssertionError(x); + } + return new BufferPoolMXBean() { + @Override + public ObjectName getObjectName() { + return obj; + } + @Override + public String getName() { + return pool; + } + @Override + public long getCount() { + return Unmapper.count; + } + @Override + public long getTotalCapacity() { + return Unmapper.totalCapacity; + } + @Override + public long getMemoryUsed() { + return Unmapper.totalSize; + } + }; + } + } // -- Locks -- diff --git a/src/share/classes/sun/nio/ch/MembershipKeyImpl.java b/src/share/classes/sun/nio/ch/MembershipKeyImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..687f79c009509e41acdbce3d53472987ba7ebb74 --- /dev/null +++ b/src/share/classes/sun/nio/ch/MembershipKeyImpl.java @@ -0,0 +1,222 @@ +/* + * 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 sun.nio.ch; + +import java.nio.channels.*; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.io.IOException; +import java.util.HashSet; + +/** + * MembershipKey implementation. + */ + +class MembershipKeyImpl + extends MembershipKey +{ + private final MulticastChannel ch; + private final InetAddress group; + private final NetworkInterface interf; + private final InetAddress source; + + // true when key is valid + private volatile boolean valid = true; + + // lock used when creating or accessing blockedSet + private Object stateLock = new Object(); + + // set of source addresses that are blocked + private HashSet blockedSet; + + private MembershipKeyImpl(MulticastChannel ch, + InetAddress group, + NetworkInterface interf, + InetAddress source) + { + this.ch = ch; + this.group = group; + this.interf = interf; + this.source = source; + } + + /** + * MembershipKey will additional context for IPv4 membership + */ + static class Type4 extends MembershipKeyImpl { + private final int groupAddress; + private final int interfAddress; + private final int sourceAddress; + + Type4(MulticastChannel ch, + InetAddress group, + NetworkInterface interf, + InetAddress source, + int groupAddress, + int interfAddress, + int sourceAddress) + { + super(ch, group, interf, source); + this.groupAddress = groupAddress; + this.interfAddress = interfAddress; + this.sourceAddress = sourceAddress; + } + + int group() { + return groupAddress; + } + + int interfaceAddress() { + return interfAddress; + } + + int source() { + return sourceAddress; + } + } + + /** + * MembershipKey will additional context for IPv6 membership + */ + static class Type6 extends MembershipKeyImpl { + private final byte[] groupAddress; + private final int index; + private final byte[] sourceAddress; + + Type6(MulticastChannel ch, + InetAddress group, + NetworkInterface interf, + InetAddress source, + byte[] groupAddress, + int index, + byte[] sourceAddress) + { + super(ch, group, interf, source); + this.groupAddress = groupAddress; + this.index = index; + this.sourceAddress = sourceAddress; + } + + byte[] group() { + return groupAddress; + } + + int index() { + return index; + } + + byte[] source() { + return sourceAddress; + } + } + + public boolean isValid() { + return valid; + } + + // package-private + void invalidate() { + valid = false; + } + + public void drop() throws IOException { + // delegate to channel + ((DatagramChannelImpl)ch).drop(this); + } + + @Override + public MulticastChannel getChannel() { + return ch; + } + + @Override + public InetAddress getGroup() { + return group; + } + + @Override + public NetworkInterface getNetworkInterface() { + return interf; + } + + @Override + public InetAddress getSourceAddress() { + return source; + } + + @Override + public MembershipKey block(InetAddress toBlock) + throws IOException + { + if (source != null) + throw new IllegalStateException("key is source-specific"); + + synchronized (stateLock) { + if ((blockedSet != null) && blockedSet.contains(toBlock)) { + // already blocked, nothing to do + return this; + } + + ((DatagramChannelImpl)ch).block(this, toBlock); + + // created blocked set if required and add source address + if (blockedSet == null) + blockedSet = new HashSet(); + blockedSet.add(toBlock); + } + return this; + } + + @Override + public MembershipKey unblock(InetAddress toUnblock) + throws IOException + { + synchronized (stateLock) { + if ((blockedSet == null) || !blockedSet.contains(toUnblock)) + throw new IllegalStateException("not blocked"); + + ((DatagramChannelImpl)ch).unblock(this, toUnblock); + + blockedSet.remove(toUnblock); + } + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(64); + sb.append('<'); + sb.append(group.getHostAddress()); + sb.append(','); + sb.append(interf.getName()); + if (source != null) { + sb.append(','); + sb.append(source.getHostAddress()); + } + sb.append('>'); + return sb.toString(); + } +} diff --git a/src/share/classes/sun/nio/ch/MembershipRegistry.java b/src/share/classes/sun/nio/ch/MembershipRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..5a2a8ef7447e6f970f062037a7aa69b714906432 --- /dev/null +++ b/src/share/classes/sun/nio/ch/MembershipRegistry.java @@ -0,0 +1,129 @@ +/* + * 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 sun.nio.ch; + +import java.nio.channels.*; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.*; + +/** + * Simple registry of membership keys for a MulticastChannel. + * + * Instances of this object are not safe by multiple concurrent threads. + */ + +class MembershipRegistry { + + // map multicast group to keys + private Map> groups = null; + + MembershipRegistry() { + } + + /** + * Checks registry for membership of the group on the given + * network interface. + */ + MembershipKey checkMembership(InetAddress group, NetworkInterface interf, + InetAddress source) + { + if (groups != null) { + List keys = groups.get(group); + if (keys != null) { + for (MembershipKeyImpl key: keys) { + if (key.getNetworkInterface().equals(interf)) { + // already a member to receive all packets so return + // existing key or detect conflict + if (source == null) { + if (key.getSourceAddress() == null) + return key; + throw new IllegalStateException("Already a member to receive all packets"); + } + + // already have source-specific membership so return key + // or detect conflict + if (key.getSourceAddress() == null) + throw new IllegalStateException("Already have source-specific membership"); + if (source.equals(key.getSourceAddress())) + return key; + } + } + } + } + return null; + } + + /** + * Add membership to the registry, returning a new membership key. + */ + void add(MembershipKeyImpl key) { + InetAddress group = key.getGroup(); + List keys; + if (groups == null) { + groups = new HashMap>(); + keys = null; + } else { + keys = groups.get(group); + } + if (keys == null) { + keys = new LinkedList(); + groups.put(group, keys); + } + keys.add(key); + } + + /** + * Remove a key from the registry + */ + void remove(MembershipKeyImpl key) { + InetAddress group = key.getGroup(); + List keys = groups.get(group); + if (keys != null) { + Iterator i = keys.iterator(); + while (i.hasNext()) { + if (i.next() == key) { + i.remove(); + break; + } + } + if (keys.isEmpty()) { + groups.remove(group); + } + } + } + + /** + * Invalidate all keys in the registry + */ + void invalidateAll() { + for (InetAddress group: groups.keySet()) { + for (MembershipKeyImpl key: groups.get(group)) { + key.invalidate(); + } + } + } +} diff --git a/src/share/classes/sun/nio/ch/Net.java b/src/share/classes/sun/nio/ch/Net.java index 295e4f5c49e4acfbdf4ad3b1ed64c19b59e5ed8a..98b4615ab427802d36fbc059a982ab6f5bab1e01 100644 --- a/src/share/classes/sun/nio/ch/Net.java +++ b/src/share/classes/sun/nio/ch/Net.java @@ -26,21 +26,43 @@ package sun.nio.ch; import java.io.*; -import java.lang.reflect.*; import java.net.*; import java.nio.channels.*; +import java.util.*; +import java.security.AccessController; +import java.security.PrivilegedAction; class Net { // package-private private Net() { } + // unspecified protocol family + static final ProtocolFamily UNSPEC = new ProtocolFamily() { + public String name() { + return "UNSPEC"; + } + }; // -- Miscellaneous utilities -- + private static volatile boolean checkedIPv6 = false; + private static volatile boolean isIPv6Available; + + /** + * Tells whether dual-IPv4/IPv6 sockets should be used. + */ + static boolean isIPv6Available() { + if (!checkedIPv6) { + isIPv6Available = isIPv6Available0(); + checkedIPv6 = true; + } + return isIPv6Available; + } + static InetSocketAddress checkAddress(SocketAddress sa) { if (sa == null) - throw new IllegalArgumentException(); + throw new NullPointerException(); if (!(sa instanceof InetSocketAddress)) throw new UnsupportedAddressTypeException(); // ## needs arg InetSocketAddress isa = (InetSocketAddress)sa; @@ -63,6 +85,8 @@ class Net { // package-private Exception nx = x; if (x instanceof ClosedChannelException) nx = new SocketException("Socket is closed"); + else if (x instanceof NotYetConnectedException) + nx = new SocketException("Socket is not connected"); else if (x instanceof AlreadyBoundException) nx = new SocketException("Already bound"); else if (x instanceof NotYetBoundException) @@ -105,73 +129,359 @@ class Net { // package-private translateException(x, false); } + /** + * Returns any IPv4 address of the given network interface, or + * null if the interface does not have any IPv4 addresses. + */ + static Inet4Address anyInet4Address(final NetworkInterface interf) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Inet4Address run() { + Enumeration addrs = interf.getInetAddresses(); + while (addrs.hasMoreElements()) { + InetAddress addr = addrs.nextElement(); + if (addr instanceof Inet4Address) { + return (Inet4Address)addr; + } + } + return null; + } + }); + } + + /** + * Returns an IPv4 address as an int. + */ + static int inet4AsInt(InetAddress ia) { + if (ia instanceof Inet4Address) { + byte[] addr = ia.getAddress(); + int address = addr[3] & 0xFF; + address |= ((addr[2] << 8) & 0xFF00); + address |= ((addr[1] << 16) & 0xFF0000); + address |= ((addr[0] << 24) & 0xFF000000); + return address; + } + throw new AssertionError("Should not reach here"); + } + + /** + * Returns an InetAddress from the given IPv4 address + * represented as an int. + */ + static InetAddress inet4FromInt(int address) { + byte[] addr = new byte[4]; + addr[0] = (byte) ((address >>> 24) & 0xFF); + addr[1] = (byte) ((address >>> 16) & 0xFF); + addr[2] = (byte) ((address >>> 8) & 0xFF); + addr[3] = (byte) (address & 0xFF); + try { + return InetAddress.getByAddress(addr); + } catch (UnknownHostException uhe) { + throw new AssertionError("Should not reach here"); + } + } + + /** + * Returns an IPv6 address as a byte array + */ + static byte[] inet6AsByteArray(InetAddress ia) { + if (ia instanceof Inet6Address) { + return ia.getAddress(); + } + + // need to construct IPv4-mapped address + if (ia instanceof Inet4Address) { + byte[] ip4address = ia.getAddress(); + byte[] address = new byte[16]; + address[10] = (byte)0xff; + address[11] = (byte)0xff; + address[12] = ip4address[0]; + address[13] = ip4address[1]; + address[14] = ip4address[2]; + address[15] = ip4address[3]; + return address; + } + + throw new AssertionError("Should not reach here"); + } + + // -- Socket options + + static void setSocketOption(FileDescriptor fd, ProtocolFamily family, + SocketOption name, Object value) + throws IOException + { + if (value == null) + throw new IllegalArgumentException("Invalid option value"); + + // only simple values supported by this method + Class type = name.type(); + if (type != Integer.class && type != Boolean.class) + throw new AssertionError("Should not reach here"); + + // special handling + if (name == StandardSocketOption.SO_RCVBUF || + name == StandardSocketOption.SO_SNDBUF) + { + int i = ((Integer)value).intValue(); + if (i < 0) + throw new IllegalArgumentException("Invalid send/receive buffer size"); + } + if (name == StandardSocketOption.SO_LINGER) { + int i = ((Integer)value).intValue(); + if (i < 0) + value = Integer.valueOf(-1); + if (i > 65535) + value = Integer.valueOf(65535); + } + if (name == StandardSocketOption.IP_TOS) { + int i = ((Integer)value).intValue(); + if (i < 0 || i > 255) + throw new IllegalArgumentException("Invalid IP_TOS value"); + } + if (name == StandardSocketOption.IP_MULTICAST_TTL) { + int i = ((Integer)value).intValue(); + if (i < 0 || i > 255) + throw new IllegalArgumentException("Invalid TTL/hop value"); + } + + // map option name to platform level/name + OptionKey key = SocketOptionRegistry.findOption(name, family); + if (key == null) + throw new AssertionError("Option not found"); + + int arg; + if (type == Integer.class) { + arg = ((Integer)value).intValue(); + } else { + boolean b = ((Boolean)value).booleanValue(); + arg = (b) ? 1 : 0; + } + + boolean mayNeedConversion = (family == UNSPEC); + setIntOption0(fd, mayNeedConversion, key.level(), key.name(), arg); + } + + static Object getSocketOption(FileDescriptor fd, ProtocolFamily family, + SocketOption name) + throws IOException + { + Class type = name.type(); + + // only simple values supported by this method + if (type != Integer.class && type != Boolean.class) + throw new AssertionError("Should not reach here"); + + // map option name to platform level/name + OptionKey key = SocketOptionRegistry.findOption(name, family); + if (key == null) + throw new AssertionError("Option not found"); + + boolean mayNeedConversion = (family == UNSPEC); + int value = getIntOption0(fd, mayNeedConversion, key.level(), key.name()); + + if (type == Integer.class) { + return Integer.valueOf(value); + } else { + return (value == 0) ? Boolean.FALSE : Boolean.TRUE; + } + } // -- Socket operations -- + static native boolean isIPv6Available0(); + static FileDescriptor socket(boolean stream) { - return IOUtil.newFD(socket0(stream, false)); + return socket(UNSPEC, stream); + } + + static FileDescriptor socket(ProtocolFamily family, boolean stream) { + boolean preferIPv6 = isIPv6Available() && + (family != StandardProtocolFamily.INET); + return IOUtil.newFD(socket0(preferIPv6, stream, false)); } static FileDescriptor serverSocket(boolean stream) { - return IOUtil.newFD(socket0(stream, true)); + return IOUtil.newFD(socket0(isIPv6Available(), stream, true)); } // Due to oddities SO_REUSEADDR on windows reuse is ignored - private static native int socket0(boolean stream, boolean reuse); + private static native int socket0(boolean preferIPv6, boolean stream, boolean reuse); + + static void bind(FileDescriptor fd, InetAddress addr, int port) + throws IOException + { + bind(UNSPEC, fd, addr, port); + } - static native void bind(FileDescriptor fd, InetAddress addr, int port) + static void bind(ProtocolFamily family, FileDescriptor fd, + InetAddress addr, int port) throws IOException + { + boolean preferIPv6 = isIPv6Available() && + (family != StandardProtocolFamily.INET); + bind0(preferIPv6, fd, addr, port); + } + + private static native void bind0(boolean preferIPv6, FileDescriptor fd, + InetAddress addr, int port) throws IOException; - static native int connect(FileDescriptor fd, - InetAddress remote, - int remotePort, - int trafficClass) + static native void listen(FileDescriptor fd, int backlog) throws IOException; + + static int connect(FileDescriptor fd, InetAddress remote, int remotePort) + throws IOException + { + return connect(UNSPEC, fd, remote, remotePort); + } + + static int connect(ProtocolFamily family, FileDescriptor fd, InetAddress remote, int remotePort) + throws IOException + { + boolean preferIPv6 = isIPv6Available() && + (family != StandardProtocolFamily.INET); + return connect0(preferIPv6, fd, remote, remotePort); + } + + private static native int connect0(boolean preferIPv6, + FileDescriptor fd, + InetAddress remote, + int remotePort) throws IOException; + public final static int SHUT_RD = 0; + public final static int SHUT_WR = 1; + public final static int SHUT_RDWR = 2; + + static native void shutdown(FileDescriptor fd, int how) throws IOException; + private static native int localPort(FileDescriptor fd) throws IOException; private static native InetAddress localInetAddress(FileDescriptor fd) throws IOException; - static InetSocketAddress localAddress(FileDescriptor fd) { - try { - return new InetSocketAddress(localInetAddress(fd), - localPort(fd)); - } catch (IOException x) { - throw new Error(x); // Can't happen - } + static InetSocketAddress localAddress(FileDescriptor fd) + throws IOException + { + return new InetSocketAddress(localInetAddress(fd), localPort(fd)); } - static int localPortNumber(FileDescriptor fd) { - try { - return localPort(fd); - } catch (IOException x) { - throw new Error(x); // Can't happen - } + private static native int remotePort(FileDescriptor fd) + throws IOException; + + private static native InetAddress remoteInetAddress(FileDescriptor fd) + throws IOException; + + static InetSocketAddress remoteAddress(FileDescriptor fd) + throws IOException + { + return new InetSocketAddress(remoteInetAddress(fd), remotePort(fd)); + } + + private static native int getIntOption0(FileDescriptor fd, boolean mayNeedConversion, + int level, int opt) + throws IOException; + + private static native void setIntOption0(FileDescriptor fd, boolean mayNeedConversion, + int level, int opt, int arg) + throws IOException; + + // -- Multicast support -- + + + /** + * Join IPv4 multicast group + */ + static int join4(FileDescriptor fd, int group, int interf, int source) + throws IOException + { + return joinOrDrop4(true, fd, group, interf, source); + } + + /** + * Drop membership of IPv4 multicast group + */ + static void drop4(FileDescriptor fd, int group, int interf, int source) + throws IOException + { + joinOrDrop4(false, fd, group, interf, source); + } + + private static native int joinOrDrop4(boolean join, FileDescriptor fd, int group, int interf, int source) + throws IOException; + + /** + * Block IPv4 source + */ + static int block4(FileDescriptor fd, int group, int interf, int source) + throws IOException + { + return blockOrUnblock4(true, fd, group, interf, source); + } + + /** + * Unblock IPv6 source + */ + static void unblock4(FileDescriptor fd, int group, int interf, int source) + throws IOException + { + blockOrUnblock4(false, fd, group, interf, source); } - private static native int getIntOption0(FileDescriptor fd, int opt) + private static native int blockOrUnblock4(boolean block, FileDescriptor fd, int group, + int interf, int source) throws IOException; - static int getIntOption(FileDescriptor fd, int opt) + /** + * Join IPv6 multicast group + */ + static int join6(FileDescriptor fd, byte[] group, int index, byte[] source) throws IOException { - return getIntOption0(fd, opt); + return joinOrDrop6(true, fd, group, index, source); } + /** + * Drop membership of IPv6 multicast group + */ + static void drop6(FileDescriptor fd, byte[] group, int index, byte[] source) + throws IOException + { + joinOrDrop6(false, fd, group, index, source); + } - private static native void setIntOption0(FileDescriptor fd, - int opt, int arg) + private static native int joinOrDrop6(boolean join, FileDescriptor fd, byte[] group, int index, byte[] source) throws IOException; - static void setIntOption(FileDescriptor fd, int opt, int arg) + /** + * Block IPv6 source + */ + static int block6(FileDescriptor fd, byte[] group, int index, byte[] source) + throws IOException + { + return blockOrUnblock6(true, fd, group, index, source); + } + + /** + * Unblock IPv6 source + */ + static void unblock6(FileDescriptor fd, byte[] group, int index, byte[] source) throws IOException { - setIntOption0(fd, opt, arg); + blockOrUnblock6(false, fd, group, index, source); } + static native int blockOrUnblock6(boolean block, FileDescriptor fd, byte[] group, int index, byte[] source) + throws IOException; + + static native void setInterface4(FileDescriptor fd, int interf) throws IOException; + + static native int getInterface4(FileDescriptor fd) throws IOException; + + static native void setInterface6(FileDescriptor fd, int index) throws IOException; + + static native int getInterface6(FileDescriptor fd) throws IOException; + private static native void initIDs(); static { diff --git a/src/share/classes/sun/nio/ch/OptionAdaptor.java b/src/share/classes/sun/nio/ch/OptionAdaptor.java deleted file mode 100644 index 95a2711764ffa0ca09cce52b5fe4b426f73ff44d..0000000000000000000000000000000000000000 --- a/src/share/classes/sun/nio/ch/OptionAdaptor.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2001 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 sun.nio.ch; - -import java.io.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.*; - - -// Adaptor class for java.net-style options -// -// The option get/set methods in the socket, server-socket, and datagram-socket -// adaptors delegate to an instance of this class. -// - -class OptionAdaptor { // package-private - - private final SocketOpts.IP opts; - - OptionAdaptor(SocketChannelImpl sc) { - opts = (SocketOpts.IP)sc.options(); - } - - OptionAdaptor(ServerSocketChannelImpl ssc) { - opts = (SocketOpts.IP)ssc.options(); - } - - OptionAdaptor(DatagramChannelImpl dc) { - opts = (SocketOpts.IP)dc.options(); - } - - private SocketOpts.IP opts() { - return opts; - } - - private SocketOpts.IP.TCP tcpOpts() { - return (SocketOpts.IP.TCP)opts; - } - - public void setTcpNoDelay(boolean on) throws SocketException { - try { - tcpOpts().noDelay(on); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public boolean getTcpNoDelay() throws SocketException { - try { - return tcpOpts().noDelay(); - } catch (Exception x) { - Net.translateToSocketException(x); - return false; // Never happens - } - } - - public void setSoLinger(boolean on, int linger) throws SocketException { - try { - if (linger > 65535) - linger = 65535; - opts().linger(on ? linger : -1); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public int getSoLinger() throws SocketException { - try { - return opts().linger(); - } catch (Exception x) { - Net.translateToSocketException(x); - return 0; // Never happens - } - } - - public void setOOBInline(boolean on) throws SocketException { - try { - opts().outOfBandInline(on); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public boolean getOOBInline() throws SocketException { - try { - return opts().outOfBandInline(); - } catch (Exception x) { - Net.translateToSocketException(x); - return false; // Never happens - } - } - - public void setSendBufferSize(int size) - throws SocketException - { - try { - opts().sendBufferSize(size); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public int getSendBufferSize() throws SocketException { - try { - return opts().sendBufferSize(); - } catch (Exception x) { - Net.translateToSocketException(x); - return 0; // Never happens - } - } - - public void setReceiveBufferSize(int size) - throws SocketException - { - try { - opts().receiveBufferSize(size); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public int getReceiveBufferSize() throws SocketException { - try { - return opts().receiveBufferSize(); - } catch (Exception x) { - Net.translateToSocketException(x); - return 0; // Never happens - } - } - - public void setKeepAlive(boolean on) throws SocketException { - try { - opts().keepAlive(on); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public boolean getKeepAlive() throws SocketException { - try { - return opts().keepAlive(); - } catch (Exception x) { - Net.translateToSocketException(x); - return false; // Never happens - } - } - - public void setTrafficClass(int tc) throws SocketException { - if (tc < 0 || tc > 255) - throw new IllegalArgumentException("tc is not in range 0 -- 255"); - try { - opts().typeOfService(tc); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public int getTrafficClass() throws SocketException { - try { - return opts().typeOfService(); - } catch (Exception x) { - Net.translateToSocketException(x); - return 0; // Never happens - } - } - - public void setReuseAddress(boolean on) - throws SocketException - { - try { - opts().reuseAddress(on); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public boolean getReuseAddress() throws SocketException { - try { - return opts().reuseAddress(); - } catch (Exception x) { - Net.translateToSocketException(x); - return false; // Never happens - } - } - - public void setBroadcast(boolean on) - throws SocketException - { - try { - opts().broadcast(on); - } catch (Exception x) { - Net.translateToSocketException(x); - } - } - - public boolean getBroadcast() throws SocketException { - try { - return opts().broadcast(); - } catch (Exception x) { - Net.translateToSocketException(x); - return false; // Never happens - } - } - -} diff --git a/src/share/classes/sun/nio/ch/OptionKey.java b/src/share/classes/sun/nio/ch/OptionKey.java new file mode 100644 index 0000000000000000000000000000000000000000..70ba8a6fa7144e6463348e95104c06dce3589607 --- /dev/null +++ b/src/share/classes/sun/nio/ch/OptionKey.java @@ -0,0 +1,48 @@ +/* + * 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 sun.nio.ch; + +/** + * Represents the level/name of a socket option + */ + +class OptionKey { + private int level; + private int name; + + OptionKey(int level, int name) { + this.level = level; + this.name = name; + } + + int level() { + return level; + } + + int name() { + return name; + } +} diff --git a/src/share/classes/sun/nio/ch/SelectorProviderImpl.java b/src/share/classes/sun/nio/ch/SelectorProviderImpl.java index 367785564addd703edf1a0df08e2fe70bc4f45f2..7a8771361b4d15cb59926b5a46f19561e9867f56 100644 --- a/src/share/classes/sun/nio/ch/SelectorProviderImpl.java +++ b/src/share/classes/sun/nio/ch/SelectorProviderImpl.java @@ -29,6 +29,7 @@ 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.nio.channels.spi.*; @@ -41,6 +42,10 @@ public abstract class SelectorProviderImpl return new DatagramChannelImpl(this); } + public DatagramChannel openDatagramChannel(ProtocolFamily family) throws IOException { + return new DatagramChannelImpl(this, family); + } + public Pipe openPipe() throws IOException { return new PipeImpl(this); } @@ -54,5 +59,4 @@ public abstract class SelectorProviderImpl public SocketChannel openSocketChannel() throws IOException { return new SocketChannelImpl(this); } - } diff --git a/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java b/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java index 1077ae4bdad14f4b9c33f3ca1929e68549227351..ccf8e03d5782f102639248b5ef2752aa78fcd6d7 100644 --- a/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java +++ b/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java @@ -44,9 +44,6 @@ public class ServerSocketAdaptor // package-private // The channel being adapted private final ServerSocketChannelImpl ssc; - // Option adaptor object, created on demand - private volatile OptionAdaptor opts = null; - // Timeout "option" value for accepts private volatile int timeout = 0; @@ -174,18 +171,21 @@ public class ServerSocketAdaptor // package-private return timeout; } - private OptionAdaptor opts() { - if (opts == null) - opts = new OptionAdaptor(ssc); - return opts; - } - public void setReuseAddress(boolean on) throws SocketException { - opts().setReuseAddress(on); + try { + ssc.setOption(StandardSocketOption.SO_REUSEADDR, on); + } catch (IOException x) { + Net.translateToSocketException(x); + } } public boolean getReuseAddress() throws SocketException { - return opts().getReuseAddress(); + try { + return ssc.getOption(StandardSocketOption.SO_REUSEADDR).booleanValue(); + } catch (IOException x) { + Net.translateToSocketException(x); + return false; // Never happens + } } public String toString() { @@ -197,11 +197,23 @@ public class ServerSocketAdaptor // package-private } public void setReceiveBufferSize(int size) throws SocketException { - opts().setReceiveBufferSize(size); + // size 0 valid for ServerSocketChannel, invalid for ServerSocket + if (size <= 0) + throw new IllegalArgumentException("size cannot be 0 or negative"); + try { + ssc.setOption(StandardSocketOption.SO_RCVBUF, size); + } catch (IOException x) { + Net.translateToSocketException(x); + } } public int getReceiveBufferSize() throws SocketException { - return opts().getReceiveBufferSize(); + try { + return ssc.getOption(StandardSocketOption.SO_RCVBUF).intValue(); + } catch (IOException x) { + Net.translateToSocketException(x); + return -1; // Never happens + } } } diff --git a/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java index 7f91cf3b89743209f360a29c175db2ce87586063..cf4e11ddebcf7d5524724cc2817529eca9b61c0b 100644 --- a/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java +++ b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java @@ -33,8 +33,7 @@ import java.nio.channels.*; import java.nio.channels.spi.*; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.HashSet; -import java.util.Iterator; +import java.util.*; /** @@ -75,10 +74,7 @@ class ServerSocketChannelImpl private int state = ST_UNINITIALIZED; // Binding - private SocketAddress localAddress = null; // null => unbound - - // Options, created on demand - private SocketOpts.IP.TCP options = null; + private SocketAddress localAddress; // null => unbound // Our socket adaptor, if any ServerSocket socket; @@ -103,7 +99,6 @@ class ServerSocketChannelImpl localAddress = Net.localAddress(fd); } - public ServerSocket socket() { synchronized (stateLock) { if (socket == null) @@ -112,6 +107,69 @@ class ServerSocketChannelImpl } } + @Override + public SocketAddress getLocalAddress() throws IOException { + synchronized (stateLock) { + if (!isOpen()) + return null; + return localAddress; + } + } + + @Override + public ServerSocketChannel setOption(SocketOption name, Object value) + throws IOException + { + if (name == null) + throw new NullPointerException(); + if (!options().contains(name)) + throw new IllegalArgumentException("invalid option name"); + + synchronized (stateLock) { + if (!isOpen()) + throw new ClosedChannelException(); + + // no options that require special handling + Net.setSocketOption(fd, Net.UNSPEC, name, value); + return this; + } + } + + @Override + @SuppressWarnings("unchecked") + public T getOption(SocketOption name) + throws IOException + { + if (name == null) + throw new NullPointerException(); + if (!options().contains(name)) + throw new IllegalArgumentException("invalid option name"); + + synchronized (stateLock) { + if (!isOpen()) + throw new ClosedChannelException(); + + // no options that require special handling + return (T) Net.getSocketOption(fd, Net.UNSPEC, name); + } + } + + private static class LazyInitialization { + static final Set> defaultOptions = defaultOptions(); + + private static Set> defaultOptions() { + HashSet> set = new HashSet>(2); + set.add(StandardSocketOption.SO_RCVBUF); + set.add(StandardSocketOption.SO_REUSEADDR); + return Collections.unmodifiableSet(set); + } + } + + @Override + public final Set> options() { + return LazyInitialization.defaultOptions; + } + public boolean isBound() { synchronized (stateLock) { return localAddress != null; @@ -124,22 +182,25 @@ class ServerSocketChannelImpl } } - public void bind(SocketAddress local, int backlog) throws IOException { + @Override + public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { synchronized (lock) { if (!isOpen()) throw new ClosedChannelException(); if (isBound()) throw new AlreadyBoundException(); - InetSocketAddress isa = Net.checkAddress(local); + InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) : + Net.checkAddress(local); SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkListen(isa.getPort()); Net.bind(fd, isa.getAddress(), isa.getPort()); - listen(fd, backlog < 1 ? 50 : backlog); + Net.listen(fd, backlog < 1 ? 50 : backlog); synchronized (stateLock) { localAddress = Net.localAddress(fd); } } + return this; } public SocketChannel accept() throws IOException { @@ -196,24 +257,6 @@ class ServerSocketChannelImpl IOUtil.configureBlocking(fd, block); } - public SocketOpts options() { - synchronized (stateLock) { - if (options == null) { - SocketOptsImpl.Dispatcher d - = new SocketOptsImpl.Dispatcher() { - int getInt(int opt) throws IOException { - return Net.getIntOption(fd, opt); - } - void setInt(int opt, int arg) throws IOException { - Net.setIntOption(fd, opt, arg); - } - }; - options = new SocketOptsImpl.IP.TCP(d); - } - return options; - } - } - protected void implCloseSelectableChannel() throws IOException { synchronized (stateLock) { nd.preClose(fd); @@ -320,9 +363,6 @@ class ServerSocketChannelImpl // -- Native methods -- - private static native void listen(FileDescriptor fd, int backlog) - throws IOException; - // Accepts a new connection, setting the given file descriptor to refer to // the new socket and setting isaa[0] to the socket's remote address. // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no diff --git a/src/share/classes/sun/nio/ch/SocketAdaptor.java b/src/share/classes/sun/nio/ch/SocketAdaptor.java index dbf79620303c9587b600a45cbfa91ca564128dc0..8d74663bf8b7c8af1351a97c0bb9cf028b0de72c 100644 --- a/src/share/classes/sun/nio/ch/SocketAdaptor.java +++ b/src/share/classes/sun/nio/ch/SocketAdaptor.java @@ -54,16 +54,9 @@ public class SocketAdaptor // The channel being adapted private final SocketChannelImpl sc; - // Option adaptor object, created on demand - private volatile OptionAdaptor opts = null; - // Timeout "option" value for reads private volatile int timeout = 0; - // Traffic-class/Type-of-service - private volatile int trafficClass = 0; - - // ## super will create a useless impl private SocketAdaptor(SocketChannelImpl sc) { this.sc = sc; @@ -145,8 +138,6 @@ public class SocketAdaptor public void bind(SocketAddress local) throws IOException { try { - if (local == null) - local = new InetSocketAddress(0); sc.bind(local); } catch (Exception x) { Net.translateException(x); @@ -154,27 +145,39 @@ public class SocketAdaptor } public InetAddress getInetAddress() { - if (!sc.isConnected()) + SocketAddress remote = sc.remoteAddress(); + if (remote == null) { return null; - return Net.asInetSocketAddress(sc.remoteAddress()).getAddress(); + } else { + return ((InetSocketAddress)remote).getAddress(); + } } public InetAddress getLocalAddress() { - if (!sc.isBound()) - return new InetSocketAddress(0).getAddress(); - return Net.asInetSocketAddress(sc.localAddress()).getAddress(); + if (sc.isOpen()) { + SocketAddress local = sc.localAddress(); + if (local != null) + return ((InetSocketAddress)local).getAddress(); + } + return new InetSocketAddress(0).getAddress(); } public int getPort() { - if (!sc.isConnected()) + SocketAddress remote = sc.remoteAddress(); + if (remote == null) { return 0; - return Net.asInetSocketAddress(sc.remoteAddress()).getPort(); + } else { + return ((InetSocketAddress)remote).getPort(); + } } public int getLocalPort() { - if (!sc.isBound()) + SocketAddress local = sc.localAddress(); + if (local == null) { return -1; - return Net.asInetSocketAddress(sc.localAddress()).getPort(); + } else { + return ((InetSocketAddress)local).getPort(); + } } private class SocketInputStream @@ -276,26 +279,60 @@ public class SocketAdaptor return os; } - private OptionAdaptor opts() { - if (opts == null) - opts = new OptionAdaptor(sc); - return opts; + private void setBooleanOption(SocketOption name, boolean value) + throws SocketException + { + try { + sc.setOption(name, value); + } catch (IOException x) { + Net.translateToSocketException(x); + } + } + + private void setIntOption(SocketOption name, int value) + throws SocketException + { + try { + sc.setOption(name, value); + } catch (IOException x) { + Net.translateToSocketException(x); + } + } + + private boolean getBooleanOption(SocketOption name) throws SocketException { + try { + return sc.getOption(name).booleanValue(); + } catch (IOException x) { + Net.translateToSocketException(x); + return false; // keep compiler happy + } + } + + private int getIntOption(SocketOption name) throws SocketException { + try { + return sc.getOption(name).intValue(); + } catch (IOException x) { + Net.translateToSocketException(x); + return -1; // keep compiler happy + } } public void setTcpNoDelay(boolean on) throws SocketException { - opts().setTcpNoDelay(on); + setBooleanOption(StandardSocketOption.TCP_NODELAY, on); } public boolean getTcpNoDelay() throws SocketException { - return opts().getTcpNoDelay(); + return getBooleanOption(StandardSocketOption.TCP_NODELAY); } public void setSoLinger(boolean on, int linger) throws SocketException { - opts().setSoLinger(on, linger); + if (!on) + linger = -1; + setIntOption(StandardSocketOption.SO_LINGER, linger); } public int getSoLinger() throws SocketException { - return opts().getSoLinger(); + return getIntOption(StandardSocketOption.SO_LINGER); } public void sendUrgentData(int data) throws IOException { @@ -303,11 +340,11 @@ public class SocketAdaptor } public void setOOBInline(boolean on) throws SocketException { - opts().setOOBInline(on); + setBooleanOption(ExtendedSocketOption.SO_OOBINLINE, on); } public boolean getOOBInline() throws SocketException { - return opts().getOOBInline(); + return getBooleanOption(ExtendedSocketOption.SO_OOBINLINE); } public void setSoTimeout(int timeout) throws SocketException { @@ -321,48 +358,49 @@ public class SocketAdaptor } public void setSendBufferSize(int size) throws SocketException { - opts().setSendBufferSize(size); + // size 0 valid for SocketChannel, invalid for Socket + if (size <= 0) + throw new IllegalArgumentException("Invalid send size"); + setIntOption(StandardSocketOption.SO_SNDBUF, size); } public int getSendBufferSize() throws SocketException { - return opts().getSendBufferSize(); + return getIntOption(StandardSocketOption.SO_SNDBUF); } public void setReceiveBufferSize(int size) throws SocketException { - opts().setReceiveBufferSize(size); + // size 0 valid for SocketChannel, invalid for Socket + if (size <= 0) + throw new IllegalArgumentException("Invalid receive size"); + setIntOption(StandardSocketOption.SO_RCVBUF, size); } public int getReceiveBufferSize() throws SocketException { - return opts().getReceiveBufferSize(); + return getIntOption(StandardSocketOption.SO_RCVBUF); } public void setKeepAlive(boolean on) throws SocketException { - opts().setKeepAlive(on); + setBooleanOption(StandardSocketOption.SO_KEEPALIVE, on); } public boolean getKeepAlive() throws SocketException { - return opts().getKeepAlive(); + return getBooleanOption(StandardSocketOption.SO_KEEPALIVE); } public void setTrafficClass(int tc) throws SocketException { - opts().setTrafficClass(tc); - trafficClass = tc; + setIntOption(StandardSocketOption.IP_TOS, tc); } public int getTrafficClass() throws SocketException { - int tc = opts().getTrafficClass(); - if (tc < 0) { - tc = trafficClass; - } - return tc; + return getIntOption(StandardSocketOption.IP_TOS); } public void setReuseAddress(boolean on) throws SocketException { - opts().setReuseAddress(on); + setBooleanOption(StandardSocketOption.SO_REUSEADDR, on); } public boolean getReuseAddress() throws SocketException { - return opts().getReuseAddress(); + return getBooleanOption(StandardSocketOption.SO_REUSEADDR); } public void close() throws IOException { @@ -402,7 +440,7 @@ public class SocketAdaptor } public boolean isBound() { - return sc.isBound(); + return sc.localAddress() != null; } public boolean isClosed() { diff --git a/src/share/classes/sun/nio/ch/SocketChannelImpl.java b/src/share/classes/sun/nio/ch/SocketChannelImpl.java index 2c67270aa2fa2a76d476f630b37f496193d28c69..4549eacfd90bf5683a27952ca1a87fda0809e1a3 100644 --- a/src/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/src/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -31,6 +31,7 @@ import java.net.*; import java.nio.ByteBuffer; import java.nio.channels.*; import java.nio.channels.spi.*; +import java.util.*; /** @@ -78,19 +79,16 @@ class SocketChannelImpl private int state = ST_UNINITIALIZED; // Binding - private SocketAddress localAddress = null; - private SocketAddress remoteAddress = null; + private SocketAddress localAddress; + private SocketAddress remoteAddress; // Input/Output open private boolean isInputOpen = true; private boolean isOutputOpen = true; private boolean readyToConnect = false; - // Options, created on demand - private SocketOpts.IP.TCP options = null; - // Socket adaptor, created on demand - private Socket socket = null; + private Socket socket; // -- End of fields protected by stateLock @@ -114,6 +112,7 @@ class SocketChannelImpl this.fd = fd; this.fdVal = IOUtil.fdVal(fd); this.state = ST_CONNECTED; + this.localAddress = Net.localAddress(fd); this.remoteAddress = remote; } @@ -125,6 +124,98 @@ class SocketChannelImpl } } + @Override + public SocketAddress getLocalAddress() throws IOException { + synchronized (stateLock) { + if (!isOpen()) + return null; + return localAddress; + } + } + + @Override + public SocketAddress getConnectedAddress() throws IOException { + synchronized (stateLock) { + if (!isOpen()) + return null; + return remoteAddress; + } + } + + @Override + public SocketChannel setOption(SocketOption name, Object value) + throws IOException + { + if (name == null) + throw new NullPointerException(); + if (!options().contains(name)) + throw new IllegalArgumentException("Invalid option name"); + + synchronized (stateLock) { + if (!isOpen()) + throw new ClosedChannelException(); + + // special handling for IP_TOS: no-op when IPv6 + if (name == StandardSocketOption.IP_TOS) { + if (!Net.isIPv6Available()) + Net.setSocketOption(fd, StandardProtocolFamily.INET, name, value); + return this; + } + + // no options that require special handling + Net.setSocketOption(fd, Net.UNSPEC, name, value); + return this; + } + } + + @Override + @SuppressWarnings("unchecked") + public T getOption(SocketOption name) + throws IOException + { + if (name == null) + throw new NullPointerException(); + if (!options().contains(name)) + throw new IllegalArgumentException("Invalid option name"); + + synchronized (stateLock) { + if (!isOpen()) + throw new ClosedChannelException(); + + // special handling for IP_TOS: always return 0 when IPv6 + if (name == StandardSocketOption.IP_TOS) { + return (Net.isIPv6Available()) ? (T) Integer.valueOf(0) : + (T) Net.getSocketOption(fd, StandardProtocolFamily.INET, name); + } + + // no options that require special handling + return (T) Net.getSocketOption(fd, Net.UNSPEC, name); + } + } + + private static class LazyInitialization { + static final Set> defaultOptions = defaultOptions(); + + private static Set> defaultOptions() { + HashSet> set = new HashSet>(8); + set.add(StandardSocketOption.SO_SNDBUF); + set.add(StandardSocketOption.SO_RCVBUF); + set.add(StandardSocketOption.SO_KEEPALIVE); + set.add(StandardSocketOption.SO_REUSEADDR); + set.add(StandardSocketOption.SO_LINGER); + set.add(StandardSocketOption.TCP_NODELAY); + // additional options required by socket adaptor + set.add(StandardSocketOption.IP_TOS); + set.add(ExtendedSocketOption.SO_OOBINLINE); + return Collections.unmodifiableSet(set); + } + } + + @Override + public final Set> options() { + return LazyInitialization.defaultOptions; + } + private boolean ensureReadOpen() throws ClosedChannelException { synchronized (stateLock) { if (!isOpen()) @@ -410,43 +501,8 @@ class SocketChannelImpl IOUtil.configureBlocking(fd, block); } - public SocketOpts options() { - synchronized (stateLock) { - if (options == null) { - SocketOptsImpl.Dispatcher d - = new SocketOptsImpl.Dispatcher() { - int getInt(int opt) throws IOException { - return Net.getIntOption(fd, opt); - } - void setInt(int opt, int arg) - throws IOException - { - Net.setIntOption(fd, opt, arg); - } - }; - options = new SocketOptsImpl.IP.TCP(d); - } - return options; - } - } - - public boolean isBound() { - synchronized (stateLock) { - if (state == ST_CONNECTED) - return true; - return localAddress != null; - } - } - public SocketAddress localAddress() { synchronized (stateLock) { - if (state == ST_CONNECTED && - (localAddress == null || - ((InetSocketAddress)localAddress).getAddress().isAnyLocalAddress())) { - // Socket was not bound before connecting or - // Socket was bound with an "anyLocalAddress" - localAddress = Net.localAddress(fd); - } return localAddress; } } @@ -457,19 +513,25 @@ class SocketChannelImpl } } - public void bind(SocketAddress local) throws IOException { + @Override + public SocketChannel bind(SocketAddress local) throws IOException { synchronized (readLock) { synchronized (writeLock) { synchronized (stateLock) { - ensureOpenAndUnconnected(); + if (!isOpen()) + throw new ClosedChannelException(); + if (state == ST_PENDING) + throw new ConnectionPendingException(); if (localAddress != null) throw new AlreadyBoundException(); - InetSocketAddress isa = Net.checkAddress(local); + InetSocketAddress isa = (local == null) ? + new InetSocketAddress(0) : Net.checkAddress(local); Net.bind(fd, isa.getAddress(), isa.getPort()); localAddress = Net.localAddress(fd); } } } + return this; } public boolean isConnected() { @@ -496,7 +558,6 @@ class SocketChannelImpl } public boolean connect(SocketAddress sa) throws IOException { - int trafficClass = 0; // ## Pick up from options int localPort = 0; synchronized (readLock) { @@ -524,13 +585,24 @@ class SocketChannelImpl ia = InetAddress.getLocalHost(); n = Net.connect(fd, ia, - isa.getPort(), - trafficClass); + isa.getPort()); if ( (n == IOStatus.INTERRUPTED) && isOpen()) continue; break; } + + synchronized (stateLock) { + if (isOpen() && (localAddress == null) || + ((InetSocketAddress)localAddress) + .getAddress().isAnyLocalAddress()) + { + // Socket was not bound before connecting or + // Socket was bound with an "anyLocalAddress" + localAddress = Net.localAddress(fd); + } + } + } finally { readerCleanup(); end((n > 0) || (n == IOStatus.UNAVAILABLE)); @@ -646,29 +718,37 @@ class SocketChannelImpl } } - public final static int SHUT_RD = 0; - public final static int SHUT_WR = 1; - public final static int SHUT_RDWR = 2; - - public void shutdownInput() throws IOException { + @Override + public SocketChannel shutdownInput() throws IOException { synchronized (stateLock) { if (!isOpen()) throw new ClosedChannelException(); - isInputOpen = false; - shutdown(fd, SHUT_RD); - if (readerThread != 0) - NativeThread.signal(readerThread); + if (!isConnected()) + throw new NotYetConnectedException(); + if (isInputOpen) { + Net.shutdown(fd, Net.SHUT_RD); + if (readerThread != 0) + NativeThread.signal(readerThread); + isInputOpen = false; + } + return this; } } - public void shutdownOutput() throws IOException { + @Override + public SocketChannel shutdownOutput() throws IOException { synchronized (stateLock) { if (!isOpen()) throw new ClosedChannelException(); - isOutputOpen = false; - shutdown(fd, SHUT_WR); - if (writerThread != 0) - NativeThread.signal(writerThread); + if (!isConnected()) + throw new NotYetConnectedException(); + if (isOutputOpen) { + Net.shutdown(fd, Net.SHUT_WR); + if (writerThread != 0) + NativeThread.signal(writerThread); + isOutputOpen = false; + } + return this; } } @@ -869,9 +949,6 @@ class SocketChannelImpl boolean block, boolean ready) throws IOException; - private static native void shutdown(FileDescriptor fd, int how) - throws IOException; - static { Util.load(); nd = new SocketDispatcher(); diff --git a/src/share/classes/sun/nio/ch/SocketOpts.java b/src/share/classes/sun/nio/ch/SocketOpts.java deleted file mode 100644 index 52ef58d8dc79b1aa81822988923060c7fad489d0..0000000000000000000000000000000000000000 --- a/src/share/classes/sun/nio/ch/SocketOpts.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2001 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 sun.nio.ch; - -import java.io.IOException; -import java.nio.*; -import java.net.NetworkInterface; - - -// Typical use: -// -// sc.options() -// .noDelay(true) -// .typeOfService(SocketOpts.IP.TOS_RELIABILITY) -// .sendBufferSize(1024) -// .receiveBufferSize(1024) -// .keepAlive(true); -// - - -public interface SocketOpts { // SocketOptions already used in java.net - - // Options that apply to all kinds of sockets - - // SO_BROADCAST - public abstract boolean broadcast() throws IOException; - public abstract SocketOpts broadcast(boolean b) throws IOException; - - // SO_KEEPALIVE - public abstract boolean keepAlive() throws IOException; - public abstract SocketOpts keepAlive(boolean b) throws IOException; - - // SO_LINGER - public abstract int linger() throws IOException; - public abstract SocketOpts linger(int n) throws IOException; - - // SO_OOBINLINE - public abstract boolean outOfBandInline() throws IOException; - public abstract SocketOpts outOfBandInline(boolean b) throws IOException; - - // SO_RCVBUF - public abstract int receiveBufferSize() throws IOException; - public abstract SocketOpts receiveBufferSize(int n) throws IOException; - - // SO_SNDBUF - public abstract int sendBufferSize() throws IOException; - public abstract SocketOpts sendBufferSize(int n) throws IOException; - - // SO_REUSEADDR - public abstract boolean reuseAddress() throws IOException; - public abstract SocketOpts reuseAddress(boolean b) throws IOException; - - - // IP-specific options - - public static interface IP - extends SocketOpts - { - - // IP_MULTICAST_IF2 - public abstract NetworkInterface multicastInterface() - throws IOException; - public abstract IP multicastInterface(NetworkInterface ni) - throws IOException; - - // IP_MULTICAST_LOOP - public abstract boolean multicastLoop() throws IOException; - public abstract IP multicastLoop(boolean b) throws IOException; - - // IP_TOS - public static final int TOS_LOWDELAY = 0x10; - public static final int TOS_THROUGHPUT = 0x08; - public static final int TOS_RELIABILITY = 0x04; - public static final int TOS_MINCOST = 0x02; - public abstract int typeOfService() throws IOException; - public abstract IP typeOfService(int tos) throws IOException; - - - // TCP-specific options - - public static interface TCP - extends IP - { - // TCP_NODELAY - public abstract boolean noDelay() throws IOException; - public abstract TCP noDelay(boolean b) throws IOException; - - } - - } - -} diff --git a/src/share/classes/sun/nio/ch/SocketOptsImpl.java b/src/share/classes/sun/nio/ch/SocketOptsImpl.java deleted file mode 100644 index 183747de16d25c9a398cca448aac8d496696df6a..0000000000000000000000000000000000000000 --- a/src/share/classes/sun/nio/ch/SocketOptsImpl.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright 2001 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 sun.nio.ch; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.net.NetworkInterface; -import java.net.SocketOptions; -import java.nio.channels.*; - - -class SocketOptsImpl - implements SocketOpts -{ - - static abstract class Dispatcher { - abstract int getInt(int opt) throws IOException; - abstract void setInt(int opt, int arg) throws IOException; - // Others that pass addresses, etc., will come later - } - - private final Dispatcher d; - - SocketOptsImpl(Dispatcher d) { - this.d = d; - } - - protected boolean getBoolean(int opt) throws IOException { - return d.getInt(opt) > 0; - } - - protected void setBoolean(int opt, boolean b) throws IOException { - d.setInt(opt, b ? 1 : 0); - } - - protected int getInt(int opt) throws IOException { - return d.getInt(opt); - } - - protected void setInt(int opt, int n) throws IOException { - d.setInt(opt, n); - } - - protected NetworkInterface getNetworkInterface(int opt) - throws IOException - { - throw new UnsupportedOperationException("NYI"); - } - - protected void setNetworkInterface(int opt, NetworkInterface ni) - throws IOException - { - throw new UnsupportedOperationException("NYI"); - } - - protected void addToString(StringBuffer sb, String s) { - char c = sb.charAt(sb.length() - 1); - if ((c != '[') && (c != '=')) - sb.append(' '); - sb.append(s); - } - - protected void addToString(StringBuffer sb, int n) { - addToString(sb, Integer.toString(n)); - } - - - // SO_BROADCAST - - public boolean broadcast() throws IOException { - return getBoolean(SocketOptions.SO_BROADCAST); - } - - public SocketOpts broadcast(boolean b) throws IOException { - setBoolean(SocketOptions.SO_BROADCAST, b); - return this; - } - - - // SO_KEEPALIVE - - public boolean keepAlive() throws IOException { - return getBoolean(SocketOptions.SO_KEEPALIVE); - } - - public SocketOpts keepAlive(boolean b) throws IOException { - setBoolean(SocketOptions.SO_KEEPALIVE, b); - return this; - } - - - // SO_LINGER - - public int linger() throws IOException { - return getInt(SocketOptions.SO_LINGER); - } - - public SocketOpts linger(int n) throws IOException { - setInt(SocketOptions.SO_LINGER, n); - return this; - } - - - // SO_OOBINLINE - - public boolean outOfBandInline() throws IOException { - return getBoolean(SocketOptions.SO_OOBINLINE); - } - - public SocketOpts outOfBandInline(boolean b) throws IOException { - setBoolean(SocketOptions.SO_OOBINLINE, b); - return this; - } - - - // SO_RCVBUF - - public int receiveBufferSize() throws IOException { - return getInt(SocketOptions.SO_RCVBUF); - } - - public SocketOpts receiveBufferSize(int n) throws IOException { - if (n <= 0) - throw new IllegalArgumentException("Invalid receive size"); - setInt(SocketOptions.SO_RCVBUF, n); - return this; - } - - - // SO_SNDBUF - - public int sendBufferSize() throws IOException { - return getInt(SocketOptions.SO_SNDBUF); - } - - public SocketOpts sendBufferSize(int n) throws IOException { - if (n <= 0) - throw new IllegalArgumentException("Invalid send size"); - setInt(SocketOptions.SO_SNDBUF, n); - return this; - } - - - // SO_REUSEADDR - - public boolean reuseAddress() throws IOException { - return getBoolean(SocketOptions.SO_REUSEADDR); - } - - public SocketOpts reuseAddress(boolean b) throws IOException { - setBoolean(SocketOptions.SO_REUSEADDR, b); - return this; - } - - - // toString - - protected void toString(StringBuffer sb) throws IOException { - int n; - if (broadcast()) - addToString(sb, "broadcast"); - if (keepAlive()) - addToString(sb, "keepalive"); - if ((n = linger()) > 0) { - addToString(sb, "linger="); - addToString(sb, n); - } - if (outOfBandInline()) - addToString(sb, "oobinline"); - if ((n = receiveBufferSize()) > 0) { - addToString(sb, "rcvbuf="); - addToString(sb, n); - } - if ((n = sendBufferSize()) > 0) { - addToString(sb, "sndbuf="); - addToString(sb, n); - } - if (reuseAddress()) - addToString(sb, "reuseaddr"); - } - - public String toString() { - StringBuffer sb = new StringBuffer(); - sb.append(this.getClass().getInterfaces()[0].getName()); - sb.append('['); - int i = sb.length(); - try { - toString(sb); - } catch (IOException x) { - sb.setLength(i); - sb.append("closed"); - } - sb.append(']'); - return sb.toString(); - } - - - // IP-specific socket options - - static class IP - extends SocketOptsImpl - implements SocketOpts.IP - { - - IP(Dispatcher d) { - super(d); - } - - - // IP_MULTICAST_IF2 - // ## Do we need IP_MULTICAST_IF also? - - public NetworkInterface multicastInterface() throws IOException { - return getNetworkInterface(SocketOptions.IP_MULTICAST_IF2); - } - - public SocketOpts.IP multicastInterface(NetworkInterface ni) - throws IOException - { - setNetworkInterface(SocketOptions.IP_MULTICAST_IF2, ni); - return this; - } - - - // IP_MULTICAST_LOOP - - public boolean multicastLoop() throws IOException { - return getBoolean(SocketOptions.IP_MULTICAST_LOOP); - } - - public SocketOpts.IP multicastLoop(boolean b) throws IOException { - setBoolean(SocketOptions.IP_MULTICAST_LOOP, b); - return this; - } - - - // IP_TOS - - public int typeOfService() throws IOException { - return getInt(SocketOptions.IP_TOS); - } - - public SocketOpts.IP typeOfService(int tos) throws IOException { - setInt(SocketOptions.IP_TOS, tos); - return this; - } - - - // toString - - protected void toString(StringBuffer sb) throws IOException { - super.toString(sb); - int n; - if ((n = typeOfService()) > 0) { - addToString(sb, "tos="); - addToString(sb, n); - } - } - - - // TCP-specific IP options - - public static class TCP - extends SocketOptsImpl.IP - implements SocketOpts.IP.TCP - { - - TCP(Dispatcher d) { - super(d); - } - - // TCP_NODELAY - - public boolean noDelay() throws IOException { - return getBoolean(SocketOptions.TCP_NODELAY); - } - - public SocketOpts.IP.TCP noDelay(boolean b) throws IOException { - setBoolean(SocketOptions.TCP_NODELAY, b); - return this; - } - - - // toString - - protected void toString(StringBuffer sb) throws IOException { - super.toString(sb); - if (noDelay()) - addToString(sb, "nodelay"); - } - - } - } - -} diff --git a/src/share/classes/sun/nio/cs/UTF_8.java b/src/share/classes/sun/nio/cs/UTF_8.java index b665b4f56a5b029f3658955f15fd813a7dd12d2f..589e3679511d6a270033d5843b861584889dbe3e 100644 --- a/src/share/classes/sun/nio/cs/UTF_8.java +++ b/src/share/classes/sun/nio/cs/UTF_8.java @@ -25,34 +25,36 @@ package sun.nio.cs; +import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.CharBuffer; -import java.nio.BufferOverflowException; -import java.nio.BufferUnderflowException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.MalformedInputException; -import java.nio.charset.UnmappableCharacterException; - -/* - * # Bits Bit pattern - * 1 7 0xxxxxxx - * 2 11 110xxxxx 10xxxxxx - * 3 16 1110xxxx 10xxxxxx 10xxxxxx - * 4 21 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - * 5 26 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - * 6 31 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx +/* Legal UTF-8 Byte Sequences + * + * # Code Points Bits Bit/Byte pattern + * 1 7 0xxxxxxx + * U+0000..U+007F 00..7F + * + * 2 11 110xxxxx 10xxxxxx + * U+0080..U+07FF C2..DF 80..BF + * + * 3 16 1110xxxx 10xxxxxx 10xxxxxx + * U+0800..U+0FFF E0 A0..BF 80..BF + * U+1000..U+FFFF E1..EF 80..BF 80..BF + * + * 4 21 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + * U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + * U+100000..U10FFFF F4 80..8F 80..BF 80..BF * - * UCS-2 uses 1-3, UTF-16 uses 1-4, UCS-4 uses 1-6 */ class UTF_8 extends Unicode { - public UTF_8() { super("UTF-8", StandardCharsets.aliases_UTF_8); } @@ -69,304 +71,250 @@ class UTF_8 extends Unicode return new Encoder(this); } + static final void updatePositions(Buffer src, int sp, + Buffer dst, int dp) { + src.position(sp - src.arrayOffset()); + dst.position(dp - dst.arrayOffset()); + } private static class Decoder extends CharsetDecoder { private Decoder(Charset cs) { super(cs, 1.0f, 1.0f); } - private boolean isContinuation(int b) { - return ((b & 0xc0) == 0x80); + private static boolean isNotContinuation(int b) { + return (b & 0xc0) != 0x80; + } + + // [C2..DF] [80..BF] + private static boolean isMalformed2(int b1, int b2) { + return (b1 & 0x1e) == 0x0 || (b2 & 0xc0) != 0x80; + } + + // [E0] [A0..BF] [80..BF] + // [E1..EF] [80..BF] [80..BF] + private static boolean isMalformed3(int b1, int b2, int b3) { + return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) || + (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80; + } + + // [F0] [90..BF] [80..BF] [80..BF] + // [F1..F3] [80..BF] [80..BF] [80..BF] + // [F4] [80..8F] [80..BF] [80..BF] + // only check 80-be range here, the [0xf0,0x80...] and [0xf4,0x90-...] + // will be checked by Surrogate.neededFor(uc) + private static boolean isMalformed4(int b2, int b3, int b4) { + return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 || + (b4 & 0xc0) != 0x80; + } + + private static CoderResult lookupN(ByteBuffer src, int n) + { + for (int i = 1; i < n; i++) { + if (isNotContinuation(src.get())) + return CoderResult.malformedForLength(i); + } + return CoderResult.malformedForLength(n); + } + + private static CoderResult malformedN(ByteBuffer src, int nb) { + switch (nb) { + case 1: + int b1 = src.get(); + if ((b1 >> 2) == -2) { + // 5 bytes 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + if (src.remaining() < 4) + return CoderResult.UNDERFLOW; + return lookupN(src, 5); + } + if ((b1 >> 1) == -2) { + // 6 bytes 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + if (src.remaining() < 5) + return CoderResult.UNDERFLOW; + return lookupN(src, 6); + } + return CoderResult.malformedForLength(1); + case 2: // always 1 + return CoderResult.malformedForLength(1); + case 3: + b1 = src.get(); + int b2 = src.get(); // no need to lookup b3 + return CoderResult.malformedForLength( + ((b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) || + isNotContinuation(b2))?1:2); + case 4: // we don't care the speed here + b1 = src.get() & 0xff; + b2 = src.get() & 0xff; + if (b1 > 0xf4 || + (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) || + (b1 == 0xf4 && (b2 & 0xf0) != 0x80) || + isNotContinuation(b2)) + return CoderResult.malformedForLength(1); + if (isNotContinuation(src.get())) + return CoderResult.malformedForLength(2); + return CoderResult.malformedForLength(3); + default: + assert false; + return null; + } } - private final Surrogate.Generator sgg = new Surrogate.Generator(); + private static CoderResult malformed(ByteBuffer src, int sp, + CharBuffer dst, int dp, + int nb) + { + src.position(sp - src.arrayOffset()); + CoderResult cr = malformedN(src, nb); + updatePositions(src, sp, dst, dp); + return cr; + } + + private static CoderResult malformed(ByteBuffer src, + int mark, int nb) + { + src.position(mark); + CoderResult cr = malformedN(src, nb); + src.position(mark); + return cr; + } + + private static CoderResult xflow(Buffer src, int sp, int sl, + Buffer dst, int dp, int nb) { + updatePositions(src, sp, dst, dp); + return (nb == 0 || sl - sp < nb) + ?CoderResult.UNDERFLOW:CoderResult.OVERFLOW; + } + + private static CoderResult xflow(Buffer src, int mark, int nb) { + CoderResult cr = (nb == 0 || src.remaining() < (nb - 1)) + ?CoderResult.UNDERFLOW:CoderResult.OVERFLOW; + src.position(mark); + return cr; + } private CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) { + // This method is optimized for ASCII input. byte[] sa = src.array(); int sp = src.arrayOffset() + src.position(); int sl = src.arrayOffset() + src.limit(); - assert (sp <= sl); - sp = (sp <= sl ? sp : sl); + char[] da = dst.array(); int dp = dst.arrayOffset() + dst.position(); int dl = dst.arrayOffset() + dst.limit(); - assert (dp <= dl); - dp = (dp <= dl ? dp : dl); - - try { - while (sp < sl) { - int b1 = sa[sp]; - int b2, b3; - switch ((b1 >> 4) & 0x0f) { - - case 0: case 1: case 2: case 3: - case 4: case 5: case 6: case 7: - // 1 byte, 7 bits: 0xxxxxxx - if (dl - dp < 1) - return CoderResult.OVERFLOW; - da[dp++] = (char)(b1 & 0x7f); - sp++; - continue; - - case 12: case 13: - // 2 bytes, 11 bits: 110xxxxx 10xxxxxx - if (sl - sp < 2) - return CoderResult.UNDERFLOW; - if (dl - dp < 1) - return CoderResult.OVERFLOW; - if (!isContinuation(b2 = sa[sp + 1])) - return CoderResult.malformedForLength(1); - da[dp++] = ((char)(((b1 & 0x1f) << 6) | - ((b2 & 0x3f) << 0))); - sp += 2; - continue; - - case 14: - // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx - if (sl - sp < 3) - return CoderResult.UNDERFLOW; - if (dl - dp < 1) - return CoderResult.OVERFLOW; - if (!isContinuation(b2 = sa[sp + 1])) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = sa[sp + 2])) - return CoderResult.malformedForLength(2); - da[dp++] = ((char)(((b1 & 0x0f) << 12) | - ((b2 & 0x3f) << 06) | - ((b3 & 0x3f) << 0))); - sp += 3; - continue; - - case 15: - // 4, 5, or 6 bytes - - int b4, b5, b6, uc, n; - switch (b1 & 0x0f) { - - case 0: case 1: case 2: case 3: - case 4: case 5: case 6: case 7: - // 4 bytes, 21 bits - if (sl - sp < 4) - return CoderResult.UNDERFLOW; - if (!isContinuation(b2 = sa[sp + 1])) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = sa[sp + 2])) - return CoderResult.malformedForLength(2); - if (!isContinuation(b4 = sa[sp + 3])) - return CoderResult.malformedForLength(3); - uc = (((b1 & 0x07) << 18) | - ((b2 & 0x3f) << 12) | - ((b3 & 0x3f) << 06) | - ((b4 & 0x3f) << 00)); - n = 4; - break; - - case 8: case 9: case 10: case 11: - // 5 bytes, 26 bits - if (sl - sp < 5) - return CoderResult.UNDERFLOW; - if (!isContinuation(b2 = sa[sp + 1])) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = sa[sp + 2])) - return CoderResult.malformedForLength(2); - if (!isContinuation(b4 = sa[sp + 3])) - return CoderResult.malformedForLength(3); - if (!isContinuation(b5 = sa[sp + 4])) - return CoderResult.malformedForLength(4); - uc = (((b1 & 0x03) << 24) | - ((b2 & 0x3f) << 18) | - ((b3 & 0x3f) << 12) | - ((b4 & 0x3f) << 06) | - ((b5 & 0x3f) << 00)); - n = 5; - break; - - case 12: case 13: - // 6 bytes, 31 bits - if (sl - sp < 6) - return CoderResult.UNDERFLOW; - if (!isContinuation(b2 = sa[sp + 1])) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = sa[sp + 2])) - return CoderResult.malformedForLength(2); - if (!isContinuation(b4 = sa[sp + 3])) - return CoderResult.malformedForLength(3); - if (!isContinuation(b5 = sa[sp + 4])) - return CoderResult.malformedForLength(4); - if (!isContinuation(b6 = sa[sp + 5])) - return CoderResult.malformedForLength(5); - uc = (((b1 & 0x01) << 30) | - ((b2 & 0x3f) << 24) | - ((b3 & 0x3f) << 18) | - ((b4 & 0x3f) << 12) | - ((b5 & 0x3f) << 06) | - ((b6 & 0x3f))); - n = 6; - break; - - default: - return CoderResult.malformedForLength(1); - - } - - int gn = sgg.generate(uc, n, da, dp, dl); - if (gn < 0) - return sgg.error(); - dp += gn; - sp += n; - continue; - - default: - return CoderResult.malformedForLength(1); - + int dlASCII = dp + Math.min(sl - sp, dl - dp); + + // ASCII only loop + while (dp < dlASCII && sa[sp] >= 0) + da[dp++] = (char)sa[sp++]; + + while (sp < sl) { + int b1 = sa[sp]; + if (b1 >= 0) { + // 1 byte, 7 bits: 0xxxxxxx + if (dp >= dl) + return xflow(src, sp, sl, dst, dp, 1); + da[dp++] = (char)b1; + sp++; + } else if ((b1 >> 5) == -2) { + // 2 bytes, 11 bits: 110xxxxx 10xxxxxx + if (sl - sp < 2 || dp >= dl) + return xflow(src, sp, sl, dst, dp, 2); + int b2 = sa[sp + 1]; + if (isMalformed2(b1, b2)) + return malformed(src, sp, dst, dp, 2); + da[dp++] = (char) (((b1 << 6) ^ b2) ^ 0x0f80); + sp += 2; + } else if ((b1 >> 4) == -2) { + // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx + if (sl - sp < 3 || dp >= dl) + return xflow(src, sp, sl, dst, dp, 3); + int b2 = sa[sp + 1]; + int b3 = sa[sp + 2]; + if (isMalformed3(b1, b2, b3)) + return malformed(src, sp, dst, dp, 3); + da[dp++] = (char) (((b1 << 12) ^ (b2 << 6) ^ b3) ^ 0x1f80); + sp += 3; + } else if ((b1 >> 3) == -2) { + // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + if (sl - sp < 4 || dl - dp < 2) + return xflow(src, sp, sl, dst, dp, 4); + int b2 = sa[sp + 1]; + int b3 = sa[sp + 2]; + int b4 = sa[sp + 3]; + int uc = ((b1 & 0x07) << 18) | + ((b2 & 0x3f) << 12) | + ((b3 & 0x3f) << 06) | + (b4 & 0x3f); + if (isMalformed4(b2, b3, b4) || + !Surrogate.neededFor(uc)) { + return malformed(src, sp, dst, dp, 4); } - - } - - return CoderResult.UNDERFLOW; - } finally { - src.position(sp - src.arrayOffset()); - dst.position(dp - dst.arrayOffset()); + da[dp++] = Surrogate.high(uc); + da[dp++] = Surrogate.low(uc); + sp += 4; + } else + return malformed(src, sp, dst, dp, 1); } + return xflow(src, sp, sl, dst, dp, 0); } private CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) { int mark = src.position(); - try { - while (src.hasRemaining()) { - int b1 = src.get(); - int b2, b3; - switch ((b1 >> 4) & 0x0f) { - - case 0: case 1: case 2: case 3: - case 4: case 5: case 6: case 7: - // 1 byte, 7 bits: 0xxxxxxx - if (dst.remaining() < 1) - return CoderResult.OVERFLOW; - dst.put((char)b1); - mark++; - continue; - - case 12: case 13: - // 2 bytes, 11 bits: 110xxxxx 10xxxxxx - if (src.remaining() < 1) - return CoderResult.UNDERFLOW; - if (dst.remaining() < 1) - return CoderResult.OVERFLOW; - if (!isContinuation(b2 = src.get())) - return CoderResult.malformedForLength(1); - dst.put((char)(((b1 & 0x1f) << 6) | - ((b2 & 0x3f) << 0))); - mark += 2; - continue; - - case 14: - // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx - if (src.remaining() < 2) - return CoderResult.UNDERFLOW; - if (dst.remaining() < 1) - return CoderResult.OVERFLOW; - if (!isContinuation(b2 = src.get())) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = src.get())) - return CoderResult.malformedForLength(2); - dst.put((char)(((b1 & 0x0f) << 12) | - ((b2 & 0x3f) << 06) | - ((b3 & 0x3f) << 0))); - mark += 3; - continue; - - case 15: - // 4, 5, or 6 bytes - - int b4, b5, b6, uc, n; - switch (b1 & 0x0f) { - - case 0: case 1: case 2: case 3: - case 4: case 5: case 6: case 7: - // 4 bytes, 21 bits - if (src.remaining() < 3) - return CoderResult.UNDERFLOW; - if (!isContinuation(b2 = src.get())) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = src.get())) - return CoderResult.malformedForLength(2); - if (!isContinuation(b4 = src.get())) - return CoderResult.malformedForLength(3); - uc = (((b1 & 0x07) << 18) | - ((b2 & 0x3f) << 12) | - ((b3 & 0x3f) << 06) | - ((b4 & 0x3f) << 00)); - n = 4; - break; - - case 8: case 9: case 10: case 11: - // 5 bytes, 26 bits - if (src.remaining() < 4) - return CoderResult.UNDERFLOW; - if (!isContinuation(b2 = src.get())) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = src.get())) - return CoderResult.malformedForLength(2); - if (!isContinuation(b4 = src.get())) - return CoderResult.malformedForLength(3); - if (!isContinuation(b5 = src.get())) - return CoderResult.malformedForLength(4); - uc = (((b1 & 0x03) << 24) | - ((b2 & 0x3f) << 18) | - ((b3 & 0x3f) << 12) | - ((b4 & 0x3f) << 06) | - ((b5 & 0x3f) << 00)); - n = 5; - break; - - case 12: case 13: - // 6 bytes, 31 bits - if (src.remaining() < 5) - return CoderResult.UNDERFLOW; - if (!isContinuation(b2 = src.get())) - return CoderResult.malformedForLength(1); - if (!isContinuation(b3 = src.get())) - return CoderResult.malformedForLength(2); - if (!isContinuation(b4 = src.get())) - return CoderResult.malformedForLength(3); - if (!isContinuation(b5 = src.get())) - return CoderResult.malformedForLength(4); - if (!isContinuation(b6 = src.get())) - return CoderResult.malformedForLength(5); - uc = (((b1 & 0x01) << 30) | - ((b2 & 0x3f) << 24) | - ((b3 & 0x3f) << 18) | - ((b4 & 0x3f) << 12) | - ((b5 & 0x3f) << 06) | - ((b6 & 0x3f))); - n = 6; - break; - - default: - return CoderResult.malformedForLength(1); - - } - - if (sgg.generate(uc, n, dst) < 0) - return sgg.error(); - mark += n; - continue; - - default: - return CoderResult.malformedForLength(1); - + int limit = src.limit(); + while (mark < limit) { + int b1 = src.get(); + if (b1 >= 0) { + // 1 byte, 7 bits: 0xxxxxxx + if (dst.remaining() < 1) + return xflow(src, mark, 1); //overflow + dst.put((char)b1); + mark++; + } else if ((b1 >> 5) == -2) { + // 2 bytes, 11 bits: 110xxxxx 10xxxxxx + if (limit - mark < 2|| dst.remaining() < 1) + return xflow(src, mark, 2); + int b2 = src.get(); + if (isMalformed2(b1, b2)) + return malformed(src, mark, 2); + dst.put((char) (((b1 << 6) ^ b2) ^ 0x0f80)); + mark += 2; + } else if ((b1 >> 4) == -2) { + // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx + if (limit - mark < 3 || dst.remaining() < 1) + return xflow(src, mark, 3); + int b2 = src.get(); + int b3 = src.get(); + if (isMalformed3(b1, b2, b3)) + return malformed(src, mark, 3); + dst.put((char) (((b1 << 12) ^ (b2 << 6) ^ b3) ^ 0x1f80)); + mark += 3; + } else if ((b1 >> 3) == -2) { + // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + if (limit - mark < 4 || dst.remaining() < 2) + return xflow(src, mark, 4); + int b2 = src.get(); + int b3 = src.get(); + int b4 = src.get(); + int uc = ((b1 & 0x07) << 18) | + ((b2 & 0x3f) << 12) | + ((b3 & 0x3f) << 06) | + (b4 & 0x3f); + if (isMalformed4(b2, b3, b4) || + !Surrogate.neededFor(uc)) { // shortest form check + return malformed(src, mark, 4); } - + dst.put(Surrogate.high(uc)); + dst.put(Surrogate.low(uc)); + mark += 4; + } else { + return malformed(src, mark, 1); } - return CoderResult.UNDERFLOW; - } finally { - src.position(mark); } + return xflow(src, mark, 0); } protected CoderResult decodeLoop(ByteBuffer src, @@ -377,10 +325,8 @@ class UTF_8 extends Unicode else return decodeBufferLoop(src, dst); } - } - private static class Encoder extends CharsetEncoder { private Encoder(Charset cs) { @@ -391,141 +337,126 @@ class UTF_8 extends Unicode return !Surrogate.is(c); } - private final Surrogate.Parser sgp = new Surrogate.Parser(); + public boolean isLegalReplacement(byte[] repl) { + return ((repl.length == 1 && repl[0] >= 0) || + super.isLegalReplacement(repl)); + } + private static CoderResult overflow(CharBuffer src, int sp, + ByteBuffer dst, int dp) { + updatePositions(src, sp, dst, dp); + return CoderResult.OVERFLOW; + } + + private static CoderResult overflow(CharBuffer src, int mark) { + src.position(mark); + return CoderResult.OVERFLOW; + } + + private Surrogate.Parser sgp; private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { char[] sa = src.array(); int sp = src.arrayOffset() + src.position(); int sl = src.arrayOffset() + src.limit(); - assert (sp <= sl); - sp = (sp <= sl ? sp : sl); + byte[] da = dst.array(); int dp = dst.arrayOffset() + dst.position(); int dl = dst.arrayOffset() + dst.limit(); - assert (dp <= dl); - dp = (dp <= dl ? dp : dl); - - try { - while (sp < sl) { - char c = sa[sp]; - - if (c < 0x80) { - // Have at most seven bits - if (dp >= dl) - return CoderResult.OVERFLOW; - da[dp++] = (byte)c; - sp++; - continue; - } - - if (!Surrogate.is(c)) { - // 2 bytes, 11 bits - if (c < 0x800) { - if (dl - dp < 2) - return CoderResult.OVERFLOW; - da[dp++] = (byte)(0xc0 | ((c >> 06))); - da[dp++] = (byte)(0x80 | ((c >> 00) & 0x3f)); - sp++; - continue; - } - if (c <= '\uFFFF') { - // 3 bytes, 16 bits - if (dl - dp < 3) - return CoderResult.OVERFLOW; - da[dp++] = (byte)(0xe0 | ((c >> 12))); - da[dp++] = (byte)(0x80 | ((c >> 06) & 0x3f)); - da[dp++] = (byte)(0x80 | ((c >> 00) & 0x3f)); - sp++; - continue; - } - } - + int dlASCII = dp + Math.min(sl - sp, dl - dp); + + //ASCII only loop + while (dp < dlASCII && sa[sp] < '\u0080') + da[dp++] = (byte) sa[sp++]; + while (sp < sl) { + int c = sa[sp]; + if (c < 0x80) { + // Have at most seven bits + if (dp >= dl) + return overflow(src, sp, dst, dp); + da[dp++] = (byte)c; + } else if (c < 0x800) { + // 2 bytes, 11 bits + if (dl - dp < 2) + return overflow(src, sp, dst, dp); + da[dp++] = (byte)(0xc0 | ((c >> 06))); + da[dp++] = (byte)(0x80 | (c & 0x3f)); + } else if (Surrogate.is(c)) { // Have a surrogate pair - int uc = sgp.parse(c, sa, sp, sl); - if (uc < 0) + if (sgp == null) + sgp = new Surrogate.Parser(); + int uc = sgp.parse((char)c, sa, sp, sl); + if (uc < 0) { + updatePositions(src, sp, dst, dp); return sgp.error(); - if (uc < 0x200000) { - if (dl - dp < 4) - return CoderResult.OVERFLOW; - da[dp++] = (byte)(0xf0 | ((uc >> 18))); - da[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f)); - da[dp++] = (byte)(0x80 | ((uc >> 06) & 0x3f)); - da[dp++] = (byte)(0x80 | ((uc >> 00) & 0x3f)); - sp += sgp.increment(); - continue; } - assert false; - + if (dl - dp < 4) + return overflow(src, sp, dst, dp); + da[dp++] = (byte)(0xf0 | ((uc >> 18))); + da[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f)); + da[dp++] = (byte)(0x80 | ((uc >> 06) & 0x3f)); + da[dp++] = (byte)(0x80 | (uc & 0x3f)); + sp++; // 2 chars + } else { + // 3 bytes, 16 bits + if (dl - dp < 3) + return overflow(src, sp, dst, dp); + da[dp++] = (byte)(0xe0 | ((c >> 12))); + da[dp++] = (byte)(0x80 | ((c >> 06) & 0x3f)); + da[dp++] = (byte)(0x80 | (c & 0x3f)); } - return CoderResult.UNDERFLOW; - } finally { - src.position(sp - src.arrayOffset()); - dst.position(dp - dst.arrayOffset()); + sp++; } + updatePositions(src, sp, dst, dp); + return CoderResult.UNDERFLOW; } private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) { int mark = src.position(); - try { - while (src.hasRemaining()) { - char c = src.get(); - - if (c < 0x80) { - // Have at most seven bits - if (!dst.hasRemaining()) - return CoderResult.OVERFLOW; - dst.put((byte)c); - mark++; - continue; - } - - if (!Surrogate.is(c)) { - if (c < 0x800) { - // 2 bytes, 11 bits - if (dst.remaining() < 2) - return CoderResult.OVERFLOW; - dst.put((byte)(0xc0 | ((c >> 06)))); - dst.put((byte)(0x80 | ((c >> 00) & 0x3f))); - mark++; - continue; - } - if (c <= '\uFFFF') { - // 3 bytes, 16 bits - if (dst.remaining() < 3) - return CoderResult.OVERFLOW; - dst.put((byte)(0xe0 | ((c >> 12)))); - dst.put((byte)(0x80 | ((c >> 06) & 0x3f))); - dst.put((byte)(0x80 | ((c >> 00) & 0x3f))); - mark++; - continue; - } - } - + while (src.hasRemaining()) { + int c = src.get(); + if (c < 0x80) { + // Have at most seven bits + if (!dst.hasRemaining()) + return overflow(src, mark); + dst.put((byte)c); + } else if (c < 0x800) { + // 2 bytes, 11 bits + if (dst.remaining() < 2) + return overflow(src, mark); + dst.put((byte)(0xc0 | ((c >> 06)))); + dst.put((byte)(0x80 | (c & 0x3f))); + } else if (Surrogate.is(c)) { // Have a surrogate pair - int uc = sgp.parse(c, src); - if (uc < 0) + if (sgp == null) + sgp = new Surrogate.Parser(); + int uc = sgp.parse((char)c, src); + if (uc < 0) { + src.position(mark); return sgp.error(); - if (uc < 0x200000) { - if (dst.remaining() < 4) - return CoderResult.OVERFLOW; - dst.put((byte)(0xf0 | ((uc >> 18)))); - dst.put((byte)(0x80 | ((uc >> 12) & 0x3f))); - dst.put((byte)(0x80 | ((uc >> 06) & 0x3f))); - dst.put((byte)(0x80 | ((uc >> 00) & 0x3f))); - mark += sgp.increment(); - continue; } - assert false; - + if (dst.remaining() < 4) + return overflow(src, mark); + dst.put((byte)(0xf0 | ((uc >> 18)))); + dst.put((byte)(0x80 | ((uc >> 12) & 0x3f))); + dst.put((byte)(0x80 | ((uc >> 06) & 0x3f))); + dst.put((byte)(0x80 | (uc & 0x3f))); + mark++; //2 chars + } else { + // 3 bytes, 16 bits + if (dst.remaining() < 3) + return overflow(src, mark); + dst.put((byte)(0xe0 | ((c >> 12)))); + dst.put((byte)(0x80 | ((c >> 06) & 0x3f))); + dst.put((byte)(0x80 | (c & 0x3f))); } - return CoderResult.UNDERFLOW; - } finally { - src.position(mark); + mark++; } + src.position(mark); + return CoderResult.UNDERFLOW; } protected final CoderResult encodeLoop(CharBuffer src, @@ -536,7 +467,5 @@ class UTF_8 extends Unicode else return encodeBufferLoop(src, dst); } - } - } diff --git a/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java b/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java index 9c7ae0910fed25a46bb368dce362d1c3d2e8d6af..04434f1f56354c9524f707e89ca896c4983bdf93 100644 --- a/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java +++ b/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java @@ -916,7 +916,7 @@ public class ExtendedCharsets "ccsid01140", "cp01140", "1140", - // "ebcdic-us-037+euro" + "ebcdic-us-037+euro" }); charset("IBM01141", "IBM1141", @@ -925,7 +925,7 @@ public class ExtendedCharsets "ccsid01141", "cp01141", "1141", - // "ebcdic-de-273+euro" + "ebcdic-de-273+euro" }); charset("IBM01142", "IBM1142", @@ -934,8 +934,8 @@ public class ExtendedCharsets "ccsid01142", "cp01142", "1142", - // "ebcdic-no-277+euro", - // "ebcdic-dk-277+euro" + "ebcdic-no-277+euro", + "ebcdic-dk-277+euro" }); charset("IBM01143", "IBM1143", @@ -944,8 +944,8 @@ public class ExtendedCharsets "ccsid01143", "cp01143", "1143", - // "ebcdic-fi-278+euro", - // "ebcdic-se-278+euro" + "ebcdic-fi-278+euro", + "ebcdic-se-278+euro" }); charset("IBM01144", "IBM1144", @@ -954,7 +954,7 @@ public class ExtendedCharsets "ccsid01144", "cp01144", "1144", - // "ebcdic-it-280+euro" + "ebcdic-it-280+euro" }); charset("IBM01145", "IBM1145", @@ -963,7 +963,7 @@ public class ExtendedCharsets "ccsid01145", "cp01145", "1145", - // "ebcdic-es-284+euro" + "ebcdic-es-284+euro" }); charset("IBM01146", "IBM1146", @@ -972,7 +972,7 @@ public class ExtendedCharsets "ccsid01146", "cp01146", "1146", - // "ebcdic-gb-285+euro" + "ebcdic-gb-285+euro" }); charset("IBM01147", "IBM1147", @@ -981,7 +981,7 @@ public class ExtendedCharsets "ccsid01147", "cp01147", "1147", - // "ebcdic-fr-277+euro" + "ebcdic-fr-277+euro" }); charset("IBM01148", "IBM1148", @@ -990,7 +990,7 @@ public class ExtendedCharsets "ccsid01148", "cp01148", "1148", - // "ebcdic-international-500+euro" + "ebcdic-international-500+euro" }); charset("IBM01149", "IBM1149", @@ -999,7 +999,7 @@ public class ExtendedCharsets "ccsid01149", "cp01149", "1149", - // "ebcdic-s-871+euro" + "ebcdic-s-871+euro" }); // Macintosh MacOS/Apple char encodingd diff --git a/src/share/classes/sun/nio/cs/standard-charsets b/src/share/classes/sun/nio/cs/standard-charsets index a3cad5fd941d36c458722b96b1f7699ca618463a..da0b26f55bf64523d2abab4eabb1a1e51551c6ad 100644 --- a/src/share/classes/sun/nio/cs/standard-charsets +++ b/src/share/classes/sun/nio/cs/standard-charsets @@ -314,6 +314,7 @@ charset IBM00858 IBM858 alias ccsid00858 alias cp00858 alias 858 + alias PC-Multilingual-850+euro charset IBM862 IBM862 alias cp862 #JDK historical diff --git a/src/share/classes/sun/reflect/generics/factory/CoreReflectionFactory.java b/src/share/classes/sun/reflect/generics/factory/CoreReflectionFactory.java index e3972325dbd5ff2f2a1c0c3ff3764e579f0a13ba..54c0908ca50ce22aceafa2ffdcd07c4a3b4ff43a 100644 --- a/src/share/classes/sun/reflect/generics/factory/CoreReflectionFactory.java +++ b/src/share/classes/sun/reflect/generics/factory/CoreReflectionFactory.java @@ -25,6 +25,7 @@ package sun.reflect.generics.factory; +import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.GenericDeclaration; import java.lang.reflect.Method; @@ -118,7 +119,10 @@ public class CoreReflectionFactory implements GenericsFactory { } public Type makeArrayType(Type componentType){ - return GenericArrayTypeImpl.make(componentType); + if (componentType instanceof Class) + return Array.newInstance((Class) componentType, 0).getClass(); + else + return GenericArrayTypeImpl.make(componentType); } public Type makeByte(){return byte.class;} diff --git a/src/share/classes/sun/security/krb5/Config.java b/src/share/classes/sun/security/krb5/Config.java index 56e5fb1d61e90c3b031843fd7742322a04dc9045..2a16b983f3319a628cb68f0c14f96f53400dca4d 100644 --- a/src/share/classes/sun/security/krb5/Config.java +++ b/src/share/classes/sun/security/krb5/Config.java @@ -803,7 +803,7 @@ public class Config { for (int j = 0; j < line.length(); j++) { if (line.charAt(j) == '=') { int index; - key = line.substring(0, j - 1).trim(); + key = line.substring(0, j).trim(); if (! exists(key, keyVector)) { keyVector.addElement(key); nameVector = new Vector (); diff --git a/src/share/classes/sun/tools/jconsole/Plotter.java b/src/share/classes/sun/tools/jconsole/Plotter.java index ea9d637ed7a4e779843c7ac23f9f0e24b66e102e..5c8305bac7a4fca37487b1e05223e67f3d3c7167 100644 --- a/src/share/classes/sun/tools/jconsole/Plotter.java +++ b/src/share/classes/sun/tools/jconsole/Plotter.java @@ -30,18 +30,15 @@ import java.awt.event.*; import java.beans.*; import java.io.*; import java.lang.reflect.Array; -import java.text.*; import java.util.*; import javax.accessibility.*; import javax.swing.*; import javax.swing.border.*; -import javax.swing.event.*; import javax.swing.filechooser.*; import javax.swing.filechooser.FileFilter; import com.sun.tools.jconsole.JConsoleContext; -import com.sun.tools.jconsole.JConsoleContext.ConnectionState; import static com.sun.tools.jconsole.JConsoleContext.ConnectionState.*; @@ -130,6 +127,7 @@ public class Plotter extends JComponent private int bottomMargin = 45; private int leftMargin = 65; private int rightMargin = 70; + private final boolean displayLegend; public Plotter() { this(Unit.NONE, 0); @@ -139,15 +137,21 @@ public class Plotter extends JComponent this(unit, 0); } + public Plotter(Unit unit, int decimals) { + this(unit,decimals,true); + } + // Note: If decimals > 0 then values must be decimally shifted left // that many places, i.e. multiplied by Math.pow(10.0, decimals). - public Plotter(Unit unit, int decimals) { + public Plotter(Unit unit, int decimals, boolean displayLegend) { + this.displayLegend = displayLegend; setUnit(unit); setDecimals(decimals); enableEvents(AWTEvent.MOUSE_EVENT_MASK); addMouseListener(new MouseAdapter() { + @Override public void mousePressed(MouseEvent e) { if (getParent() instanceof PlotterPanel) { getParent().requestFocusInWindow(); @@ -240,6 +244,7 @@ public class Plotter extends JComponent } } + @Override public JPopupMenu getComponentPopupMenu() { if (popupMenu == null) { popupMenu = new JPopupMenu(Resources.getText("Chart:")); @@ -330,6 +335,7 @@ public class Plotter extends JComponent } } + @Override public void paintComponent(Graphics g) { super.paintComponent(g); @@ -670,7 +676,7 @@ public class Plotter extends JComponent curValue += "%"; } int valWidth = fm.stringWidth(curValue); - String legend = seq.name; + String legend = (displayLegend?seq.name:""); int legendWidth = fm.stringWidth(legend); if (checkRightMargin(valWidth) || checkRightMargin(legendWidth)) { // Wait for next repaint @@ -986,10 +992,12 @@ public class Plotter extends JComponent } private static class SaveDataFileChooser extends JFileChooser { + private static final long serialVersionUID = -5182890922369369669L; SaveDataFileChooser() { setFileFilter(new FileNameExtensionFilter("CSV file", "csv")); } + @Override public void approveSelection() { File file = getSelectedFile(); if (file != null) { @@ -1034,6 +1042,7 @@ public class Plotter extends JComponent } } + @Override public AccessibleContext getAccessibleContext() { if (accessibleContext == null) { accessibleContext = new AccessiblePlotter(); @@ -1042,10 +1051,12 @@ public class Plotter extends JComponent } protected class AccessiblePlotter extends AccessibleJComponent { + private static final long serialVersionUID = -3847205410473510922L; protected AccessiblePlotter() { setAccessibleName(getText("Plotter.accessibleName")); } + @Override public String getAccessibleName() { String name = super.getAccessibleName(); @@ -1076,6 +1087,7 @@ public class Plotter extends JComponent return name; } + @Override public AccessibleRole getAccessibleRole() { return AccessibleRole.CANVAS; } diff --git a/src/share/classes/sun/tools/jconsole/inspector/XMBeanAttributes.java b/src/share/classes/sun/tools/jconsole/inspector/XMBeanAttributes.java index 5fca79d37776e6342fc21f12fe4f12f7b61e945d..4fe9e737fd1fd66ce08f5962e8ac2c6d4ca2e623 100644 --- a/src/share/classes/sun/tools/jconsole/inspector/XMBeanAttributes.java +++ b/src/share/classes/sun/tools/jconsole/inspector/XMBeanAttributes.java @@ -872,8 +872,8 @@ public class XMBeanAttributes extends XTable { MaximizedCellRenderer(Component comp) { this.comp = comp; Dimension d = comp.getPreferredSize(); - if (d.getHeight() > 200) { - comp.setPreferredSize(new Dimension((int) d.getWidth(), 200)); + if (d.getHeight() > 220) { + comp.setPreferredSize(new Dimension((int) d.getWidth(), 220)); } } @Override diff --git a/src/share/classes/sun/tools/jconsole/inspector/XPlotter.java b/src/share/classes/sun/tools/jconsole/inspector/XPlotter.java index 24b4104b7c5f75dc29a91635507be157dbcf486e..8be8c5ca898f7ed5c4e3c4e45a9bded36f4e388c 100644 --- a/src/share/classes/sun/tools/jconsole/inspector/XPlotter.java +++ b/src/share/classes/sun/tools/jconsole/inspector/XPlotter.java @@ -34,7 +34,7 @@ public class XPlotter extends Plotter { JTable table; public XPlotter(JTable table, Plotter.Unit unit) { - super(unit); + super(unit,0,false); this.table = table; } @Override diff --git a/src/share/classes/sun/tools/jconsole/inspector/XPlottingViewer.java b/src/share/classes/sun/tools/jconsole/inspector/XPlottingViewer.java index 7da7576b552393b2b6220bc99a6c78ecebf9a6c8..0c074a5599e6f558ed0379bd6a14ca11c3396209 100644 --- a/src/share/classes/sun/tools/jconsole/inspector/XPlottingViewer.java +++ b/src/share/classes/sun/tools/jconsole/inspector/XPlottingViewer.java @@ -27,14 +27,10 @@ package sun.tools.jconsole.inspector; import java.awt.*; import java.awt.event.*; -import java.io.*; import java.util.*; import java.util.Timer; -import javax.management.*; import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; import sun.tools.jconsole.*; @@ -127,6 +123,7 @@ public class XPlottingViewer extends PlotterPanel implements ActionListener { setBackground(g.getColor()); plotter.paintComponent(g); }*/ + @Override public void actionPerformed(ActionEvent evt) { plotterCache.remove(key); Timer t = timerCache.remove(key); @@ -141,9 +138,11 @@ public class XPlottingViewer extends PlotterPanel implements ActionListener { JTable table) { final Plotter plotter = new XPlotter(table, Plotter.Unit.NONE) { Dimension prefSize = new Dimension(400, 170); + @Override public Dimension getPreferredSize() { return prefSize; } + @Override public Dimension getMinimumSize() { return prefSize; } @@ -183,42 +182,40 @@ public class XPlottingViewer extends PlotterPanel implements ActionListener { return plotter; } - //Create Plotter display private void setupDisplay(Plotter plotter) { - //setLayout(new GridLayout(2,0)); - GridBagLayout gbl = new GridBagLayout(); - setLayout(gbl); + final JPanel buttonPanel = new JPanel(); + final GridBagLayout gbl = new GridBagLayout(); + buttonPanel.setLayout(gbl); + setLayout(new BorderLayout()); plotButton = new JButton(Resources.getText("Discard chart")); plotButton.addActionListener(this); plotButton.setEnabled(true); - // Add the display to the top four cells GridBagConstraints buttonConstraints = new GridBagConstraints(); buttonConstraints.gridx = 0; buttonConstraints.gridy = 0; buttonConstraints.fill = GridBagConstraints.VERTICAL; buttonConstraints.anchor = GridBagConstraints.CENTER; gbl.setConstraints(plotButton, buttonConstraints); - add(plotButton); - - GridBagConstraints plotterConstraints = new GridBagConstraints(); - plotterConstraints.gridx = 0; - plotterConstraints.gridy = 1; - plotterConstraints.weightx = 1; - //plotterConstraints.gridwidth = (int) plotter.getPreferredSize().getWidth(); - //plotterConstraints.gridheight = (int) plotter.getPreferredSize().getHeight(); - plotterConstraints.fill = GridBagConstraints.VERTICAL; - gbl.setConstraints(plotter, plotterConstraints); - - - //bordered = new JPanel(); - //bordered.setPreferredSize(new Dimension(400, 250)); - //bordered.add(plotButton); - //bordered.add(plotter); - - //add(bordered); - + buttonPanel.add(plotButton); + + if (attributeName != null && attributeName.length()!=0) { + final JPanel plotterLabelPanel = new JPanel(); + final JLabel label = new JLabel(attributeName); + final GridBagLayout gbl2 = new GridBagLayout(); + plotterLabelPanel.setLayout(gbl2); + final GridBagConstraints labelConstraints = new GridBagConstraints(); + labelConstraints.gridx = 0; + labelConstraints.gridy = 0; + labelConstraints.fill = GridBagConstraints.VERTICAL; + labelConstraints.anchor = GridBagConstraints.CENTER; + labelConstraints.ipady = 10; + gbl2.setConstraints(label, labelConstraints); + plotterLabelPanel.add(label); + add(plotterLabelPanel, BorderLayout.NORTH); + } setPlotter(plotter); + add(buttonPanel, BorderLayout.SOUTH); repaint(); } diff --git a/src/share/classes/sun/tools/jmap/JMap.java b/src/share/classes/sun/tools/jmap/JMap.java index b770c4cd8e6170150b311a87af56f4392bcd5bdf..39100523c3f5732ad6f4764d33b752d9509829f0 100644 --- a/src/share/classes/sun/tools/jmap/JMap.java +++ b/src/share/classes/sun/tools/jmap/JMap.java @@ -56,7 +56,7 @@ public class JMap { private static String FORCE_SA_OPTION = "-F"; // Default option (if nothing provided) - private static String DEFAULT_OPTION = "-heap"; + private static String DEFAULT_OPTION = "-pmap"; public static void main(String[] args) throws Exception { if (args.length == 0) { @@ -147,6 +147,7 @@ public class JMap { // Invoke SA tool with the given arguments private static void runTool(String option, String args[]) throws Exception { String[][] tools = { + { "-pmap", "sun.jvm.hotspot.tools.PMap" }, { "-heap", "sun.jvm.hotspot.tools.HeapSummary" }, { "-heap:format=b", "sun.jvm.hotspot.tools.HeapDumper" }, { "-histo", "sun.jvm.hotspot.tools.ObjectHistogram" }, diff --git a/src/share/instrument/InstrumentationImplNativeMethods.c b/src/share/instrument/InstrumentationImplNativeMethods.c index f4a1239699614a6fecc06e15f904dea02592c2e7..7acd7298bd39ec65951559eb9fb099437e59e41c 100644 --- a/src/share/instrument/InstrumentationImplNativeMethods.c +++ b/src/share/instrument/InstrumentationImplNativeMethods.c @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-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 @@ -23,15 +23,14 @@ * have any questions. */ - #include #include "JPLISAgent.h" #include "JPLISAssert.h" #include "Utilities.h" #include "JavaExceptions.h" +#include "FileSystemSupport.h" /* For uintptr_t */ #include "sun_instrument_InstrumentationImpl.h" -#include "typedefs.h" /* * Copyright 2003 Wily Technology, Inc. diff --git a/src/share/instrument/JPLISAgent.c b/src/share/instrument/JPLISAgent.c index 9e1a0b0983010a4452eba93f99c0353912ce6a6b..e34beac794b18ca824369de1e4d117db6577c4e5 100644 --- a/src/share/instrument/JPLISAgent.c +++ b/src/share/instrument/JPLISAgent.c @@ -38,10 +38,9 @@ #include "JavaExceptions.h" #include "EncodingSupport.h" -#include "FileSystemSupport.h" /* MAXPATHLEN */ +#include "FileSystemSupport.h" /* For MAXPATHLEN & uintptr_t */ #include "sun_instrument_InstrumentationImpl.h" -#include "typedefs.h" /* * The JPLISAgent manages the initialization all of the Java programming language Agents. diff --git a/src/share/javavm/export/jvm.h b/src/share/javavm/export/jvm.h index 3778d43093e13dbc00698d280680ccdcaf7f98e5..df8f27e6602eaf6d68f43018fcb3b15ce653fe6e 100644 --- a/src/share/javavm/export/jvm.h +++ b/src/share/javavm/export/jvm.h @@ -948,90 +948,8 @@ JVM_ReleaseUTF(const char *utf); JNIEXPORT jboolean JNICALL JVM_IsSameClassPackage(JNIEnv *env, jclass class1, jclass class2); -/* Constants in class files */ - -#define JVM_ACC_PUBLIC 0x0001 /* visible to everyone */ -#define JVM_ACC_PRIVATE 0x0002 /* visible only to the defining class */ -#define JVM_ACC_PROTECTED 0x0004 /* visible to subclasses */ -#define JVM_ACC_STATIC 0x0008 /* instance variable is static */ -#define JVM_ACC_FINAL 0x0010 /* no further subclassing, overriding */ -#define JVM_ACC_SYNCHRONIZED 0x0020 /* wrap method call in monitor lock */ -#define JVM_ACC_SUPER 0x0020 /* funky handling of invokespecial */ -#define JVM_ACC_VOLATILE 0x0040 /* can not cache in registers */ -#define JVM_ACC_BRIDGE 0x0040 /* bridge method generated by compiler */ -#define JVM_ACC_TRANSIENT 0x0080 /* not persistant */ -#define JVM_ACC_VARARGS 0x0080 /* method declared with variable number of args */ -#define JVM_ACC_NATIVE 0x0100 /* implemented in C */ -#define JVM_ACC_INTERFACE 0x0200 /* class is an interface */ -#define JVM_ACC_ABSTRACT 0x0400 /* no definition provided */ -#define JVM_ACC_STRICT 0x0800 /* strict floating point */ -#define JVM_ACC_SYNTHETIC 0x1000 /* compiler-generated class, method or field */ - -#define JVM_ACC_ANNOTATION 0x2000 /* annotation type */ -#define JVM_ACC_ENUM 0x4000 /* field is declared as element of enum */ - -#define JVM_ACC_PUBLIC_BIT 0 -#define JVM_ACC_PRIVATE_BIT 1 -#define JVM_ACC_PROTECTED_BIT 2 -#define JVM_ACC_STATIC_BIT 3 -#define JVM_ACC_FINAL_BIT 4 -#define JVM_ACC_SYNCHRONIZED_BIT 5 -#define JVM_ACC_SUPER_BIT 5 -#define JVM_ACC_VOLATILE_BIT 6 -#define JVM_ACC_BRIDGE_BIT 6 -#define JVM_ACC_TRANSIENT_BIT 7 -#define JVM_ACC_VARARGS_BIT 7 -#define JVM_ACC_NATIVE_BIT 8 -#define JVM_ACC_INTERFACE_BIT 9 -#define JVM_ACC_ABSTRACT_BIT 10 -#define JVM_ACC_STRICT_BIT 11 -#define JVM_ACC_SYNTHETIC_BIT 12 -#define JVM_ACC_ANNOTATION_BIT 13 -#define JVM_ACC_ENUM_BIT 14 - -enum { - JVM_CONSTANT_Utf8 = 1, - JVM_CONSTANT_Unicode, /* unused */ - JVM_CONSTANT_Integer, - JVM_CONSTANT_Float, - JVM_CONSTANT_Long, - JVM_CONSTANT_Double, - JVM_CONSTANT_Class, - JVM_CONSTANT_String, - JVM_CONSTANT_Fieldref, - JVM_CONSTANT_Methodref, - JVM_CONSTANT_InterfaceMethodref, - JVM_CONSTANT_NameAndType -}; - -/* Used in the newarray instruction. */ - -#define JVM_T_BOOLEAN 4 -#define JVM_T_CHAR 5 -#define JVM_T_FLOAT 6 -#define JVM_T_DOUBLE 7 -#define JVM_T_BYTE 8 -#define JVM_T_SHORT 9 -#define JVM_T_INT 10 -#define JVM_T_LONG 11 - -/* JVM method signatures */ - -#define JVM_SIGNATURE_ARRAY '[' -#define JVM_SIGNATURE_BYTE 'B' -#define JVM_SIGNATURE_CHAR 'C' -#define JVM_SIGNATURE_CLASS 'L' -#define JVM_SIGNATURE_ENDCLASS ';' -#define JVM_SIGNATURE_ENUM 'E' -#define JVM_SIGNATURE_FLOAT 'F' -#define JVM_SIGNATURE_DOUBLE 'D' -#define JVM_SIGNATURE_FUNC '(' -#define JVM_SIGNATURE_ENDFUNC ')' -#define JVM_SIGNATURE_INT 'I' -#define JVM_SIGNATURE_LONG 'J' -#define JVM_SIGNATURE_SHORT 'S' -#define JVM_SIGNATURE_VOID 'V' -#define JVM_SIGNATURE_BOOLEAN 'Z' +/* Get classfile constants */ +#include "classfile_constants.h" /* * A function defined by the byte-code verifier and called by the VM. @@ -1329,23 +1247,6 @@ JVM_GetSockOpt(jint fd, int level, int optname, char *optval, int *optlen); JNIEXPORT jint JNICALL JVM_SetSockOpt(jint fd, int level, int optname, const char *optval, int optlen); -/* - * These routines are only reentrant on Windows - */ - -#ifdef WIN32 - -JNIEXPORT struct protoent * JNICALL -JVM_GetProtoByName(char* name); - -JNIEXPORT struct hostent* JNICALL -JVM_GetHostByAddr(const char* name, int len, int type); - -JNIEXPORT struct hostent* JNICALL -JVM_GetHostByName(char* name); - -#endif /* _WINDOWS */ - JNIEXPORT int JNICALL JVM_GetHostName(char* name, int namelen); diff --git a/src/share/javavm/include/opcodes.h b/src/share/javavm/include/opcodes.h deleted file mode 100644 index e13a4b2030b7c51c6859a60512c2b67cb9807463..0000000000000000000000000000000000000000 --- a/src/share/javavm/include/opcodes.h +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright 1998-2003 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. - */ - -#ifndef _JAVASOFT_OPCODES_H_ -#define _JAVASOFT_OPCODES_H_ - -typedef enum { - opc_nop = 0, - opc_aconst_null = 1, - opc_iconst_m1 = 2, - opc_iconst_0 = 3, - opc_iconst_1 = 4, - opc_iconst_2 = 5, - opc_iconst_3 = 6, - opc_iconst_4 = 7, - opc_iconst_5 = 8, - opc_lconst_0 = 9, - opc_lconst_1 = 10, - opc_fconst_0 = 11, - opc_fconst_1 = 12, - opc_fconst_2 = 13, - opc_dconst_0 = 14, - opc_dconst_1 = 15, - opc_bipush = 16, - opc_sipush = 17, - opc_ldc = 18, - opc_ldc_w = 19, - opc_ldc2_w = 20, - opc_iload = 21, - opc_lload = 22, - opc_fload = 23, - opc_dload = 24, - opc_aload = 25, - opc_iload_0 = 26, - opc_iload_1 = 27, - opc_iload_2 = 28, - opc_iload_3 = 29, - opc_lload_0 = 30, - opc_lload_1 = 31, - opc_lload_2 = 32, - opc_lload_3 = 33, - opc_fload_0 = 34, - opc_fload_1 = 35, - opc_fload_2 = 36, - opc_fload_3 = 37, - opc_dload_0 = 38, - opc_dload_1 = 39, - opc_dload_2 = 40, - opc_dload_3 = 41, - opc_aload_0 = 42, - opc_aload_1 = 43, - opc_aload_2 = 44, - opc_aload_3 = 45, - opc_iaload = 46, - opc_laload = 47, - opc_faload = 48, - opc_daload = 49, - opc_aaload = 50, - opc_baload = 51, - opc_caload = 52, - opc_saload = 53, - opc_istore = 54, - opc_lstore = 55, - opc_fstore = 56, - opc_dstore = 57, - opc_astore = 58, - opc_istore_0 = 59, - opc_istore_1 = 60, - opc_istore_2 = 61, - opc_istore_3 = 62, - opc_lstore_0 = 63, - opc_lstore_1 = 64, - opc_lstore_2 = 65, - opc_lstore_3 = 66, - opc_fstore_0 = 67, - opc_fstore_1 = 68, - opc_fstore_2 = 69, - opc_fstore_3 = 70, - opc_dstore_0 = 71, - opc_dstore_1 = 72, - opc_dstore_2 = 73, - opc_dstore_3 = 74, - opc_astore_0 = 75, - opc_astore_1 = 76, - opc_astore_2 = 77, - opc_astore_3 = 78, - opc_iastore = 79, - opc_lastore = 80, - opc_fastore = 81, - opc_dastore = 82, - opc_aastore = 83, - opc_bastore = 84, - opc_castore = 85, - opc_sastore = 86, - opc_pop = 87, - opc_pop2 = 88, - opc_dup = 89, - opc_dup_x1 = 90, - opc_dup_x2 = 91, - opc_dup2 = 92, - opc_dup2_x1 = 93, - opc_dup2_x2 = 94, - opc_swap = 95, - opc_iadd = 96, - opc_ladd = 97, - opc_fadd = 98, - opc_dadd = 99, - opc_isub = 100, - opc_lsub = 101, - opc_fsub = 102, - opc_dsub = 103, - opc_imul = 104, - opc_lmul = 105, - opc_fmul = 106, - opc_dmul = 107, - opc_idiv = 108, - opc_ldiv = 109, - opc_fdiv = 110, - opc_ddiv = 111, - opc_irem = 112, - opc_lrem = 113, - opc_frem = 114, - opc_drem = 115, - opc_ineg = 116, - opc_lneg = 117, - opc_fneg = 118, - opc_dneg = 119, - opc_ishl = 120, - opc_lshl = 121, - opc_ishr = 122, - opc_lshr = 123, - opc_iushr = 124, - opc_lushr = 125, - opc_iand = 126, - opc_land = 127, - opc_ior = 128, - opc_lor = 129, - opc_ixor = 130, - opc_lxor = 131, - opc_iinc = 132, - opc_i2l = 133, - opc_i2f = 134, - opc_i2d = 135, - opc_l2i = 136, - opc_l2f = 137, - opc_l2d = 138, - opc_f2i = 139, - opc_f2l = 140, - opc_f2d = 141, - opc_d2i = 142, - opc_d2l = 143, - opc_d2f = 144, - opc_i2b = 145, - opc_i2c = 146, - opc_i2s = 147, - opc_lcmp = 148, - opc_fcmpl = 149, - opc_fcmpg = 150, - opc_dcmpl = 151, - opc_dcmpg = 152, - opc_ifeq = 153, - opc_ifne = 154, - opc_iflt = 155, - opc_ifge = 156, - opc_ifgt = 157, - opc_ifle = 158, - opc_if_icmpeq = 159, - opc_if_icmpne = 160, - opc_if_icmplt = 161, - opc_if_icmpge = 162, - opc_if_icmpgt = 163, - opc_if_icmple = 164, - opc_if_acmpeq = 165, - opc_if_acmpne = 166, - opc_goto = 167, - opc_jsr = 168, - opc_ret = 169, - opc_tableswitch = 170, - opc_lookupswitch = 171, - opc_ireturn = 172, - opc_lreturn = 173, - opc_freturn = 174, - opc_dreturn = 175, - opc_areturn = 176, - opc_return = 177, - opc_getstatic = 178, - opc_putstatic = 179, - opc_getfield = 180, - opc_putfield = 181, - opc_invokevirtual = 182, - opc_invokespecial = 183, - opc_invokestatic = 184, - opc_invokeinterface = 185, - opc_xxxunusedxxx = 186, - opc_new = 187, - opc_newarray = 188, - opc_anewarray = 189, - opc_arraylength = 190, - opc_athrow = 191, - opc_checkcast = 192, - opc_instanceof = 193, - opc_monitorenter = 194, - opc_monitorexit = 195, - opc_wide = 196, - opc_multianewarray = 197, - opc_ifnull = 198, - opc_ifnonnull = 199, - opc_goto_w = 200, - opc_jsr_w = 201, - opc_breakpoint = 202, - opc_ldc_quick = 203, - opc_ldc_w_quick = 204, - opc_ldc2_w_quick = 205, - opc_getfield_quick = 206, - opc_putfield_quick = 207, - opc_getfield2_quick = 208, - opc_putfield2_quick = 209, - opc_getstatic_quick = 210, - opc_putstatic_quick = 211, - opc_getstatic2_quick = 212, - opc_putstatic2_quick = 213, - opc_invokevirtual_quick = 214, - opc_invokenonvirtual_quick = 215, - opc_invokesuper_quick = 216, - opc_invokestatic_quick = 217, - opc_invokeinterface_quick = 218, - opc_invokevirtualobject_quick = 219, - opc_invokeignored_quick = 220, - opc_new_quick = 221, - opc_anewarray_quick = 222, - opc_multianewarray_quick = 223, - opc_checkcast_quick = 224, - opc_instanceof_quick = 225, - opc_invokevirtual_quick_w = 226, - opc_getfield_quick_w = 227, - opc_putfield_quick_w = 228, - opc_nonnull_quick = 229, - opc_first_unused_index = 230, - opc_software = 254, - opc_hardware = 255, - opc_dummy = (int)0xF0000000U /* portability change, opc_invokeinit in the - * verifier requires more than 8 bits. - */ -} opcode_type; - -#endif /* !_JAVASOFT_OPCODES_H_ */ diff --git a/src/share/javavm/include/opcodes.length b/src/share/javavm/include/opcodes.length deleted file mode 100644 index 6e93ec63828169ca6ce824e35261a20ff80a9360..0000000000000000000000000000000000000000 --- a/src/share/javavm/include/opcodes.length +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright 1998-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. - */ - -const short opcode_length[256] = { - 1, /* nop */ - 1, /* aconst_null */ - 1, /* iconst_m1 */ - 1, /* iconst_0 */ - 1, /* iconst_1 */ - 1, /* iconst_2 */ - 1, /* iconst_3 */ - 1, /* iconst_4 */ - 1, /* iconst_5 */ - 1, /* lconst_0 */ - 1, /* lconst_1 */ - 1, /* fconst_0 */ - 1, /* fconst_1 */ - 1, /* fconst_2 */ - 1, /* dconst_0 */ - 1, /* dconst_1 */ - 2, /* bipush */ - 3, /* sipush */ - 2, /* ldc */ - 3, /* ldc_w */ - 3, /* ldc2_w */ - 2, /* iload */ - 2, /* lload */ - 2, /* fload */ - 2, /* dload */ - 2, /* aload */ - 1, /* iload_0 */ - 1, /* iload_1 */ - 1, /* iload_2 */ - 1, /* iload_3 */ - 1, /* lload_0 */ - 1, /* lload_1 */ - 1, /* lload_2 */ - 1, /* lload_3 */ - 1, /* fload_0 */ - 1, /* fload_1 */ - 1, /* fload_2 */ - 1, /* fload_3 */ - 1, /* dload_0 */ - 1, /* dload_1 */ - 1, /* dload_2 */ - 1, /* dload_3 */ - 1, /* aload_0 */ - 1, /* aload_1 */ - 1, /* aload_2 */ - 1, /* aload_3 */ - 1, /* iaload */ - 1, /* laload */ - 1, /* faload */ - 1, /* daload */ - 1, /* aaload */ - 1, /* baload */ - 1, /* caload */ - 1, /* saload */ - 2, /* istore */ - 2, /* lstore */ - 2, /* fstore */ - 2, /* dstore */ - 2, /* astore */ - 1, /* istore_0 */ - 1, /* istore_1 */ - 1, /* istore_2 */ - 1, /* istore_3 */ - 1, /* lstore_0 */ - 1, /* lstore_1 */ - 1, /* lstore_2 */ - 1, /* lstore_3 */ - 1, /* fstore_0 */ - 1, /* fstore_1 */ - 1, /* fstore_2 */ - 1, /* fstore_3 */ - 1, /* dstore_0 */ - 1, /* dstore_1 */ - 1, /* dstore_2 */ - 1, /* dstore_3 */ - 1, /* astore_0 */ - 1, /* astore_1 */ - 1, /* astore_2 */ - 1, /* astore_3 */ - 1, /* iastore */ - 1, /* lastore */ - 1, /* fastore */ - 1, /* dastore */ - 1, /* aastore */ - 1, /* bastore */ - 1, /* castore */ - 1, /* sastore */ - 1, /* pop */ - 1, /* pop2 */ - 1, /* dup */ - 1, /* dup_x1 */ - 1, /* dup_x2 */ - 1, /* dup2 */ - 1, /* dup2_x1 */ - 1, /* dup2_x2 */ - 1, /* swap */ - 1, /* iadd */ - 1, /* ladd */ - 1, /* fadd */ - 1, /* dadd */ - 1, /* isub */ - 1, /* lsub */ - 1, /* fsub */ - 1, /* dsub */ - 1, /* imul */ - 1, /* lmul */ - 1, /* fmul */ - 1, /* dmul */ - 1, /* idiv */ - 1, /* ldiv */ - 1, /* fdiv */ - 1, /* ddiv */ - 1, /* irem */ - 1, /* lrem */ - 1, /* frem */ - 1, /* drem */ - 1, /* ineg */ - 1, /* lneg */ - 1, /* fneg */ - 1, /* dneg */ - 1, /* ishl */ - 1, /* lshl */ - 1, /* ishr */ - 1, /* lshr */ - 1, /* iushr */ - 1, /* lushr */ - 1, /* iand */ - 1, /* land */ - 1, /* ior */ - 1, /* lor */ - 1, /* ixor */ - 1, /* lxor */ - 3, /* iinc */ - 1, /* i2l */ - 1, /* i2f */ - 1, /* i2d */ - 1, /* l2i */ - 1, /* l2f */ - 1, /* l2d */ - 1, /* f2i */ - 1, /* f2l */ - 1, /* f2d */ - 1, /* d2i */ - 1, /* d2l */ - 1, /* d2f */ - 1, /* i2b */ - 1, /* i2c */ - 1, /* i2s */ - 1, /* lcmp */ - 1, /* fcmpl */ - 1, /* fcmpg */ - 1, /* dcmpl */ - 1, /* dcmpg */ - 3, /* ifeq */ - 3, /* ifne */ - 3, /* iflt */ - 3, /* ifge */ - 3, /* ifgt */ - 3, /* ifle */ - 3, /* if_icmpeq */ - 3, /* if_icmpne */ - 3, /* if_icmplt */ - 3, /* if_icmpge */ - 3, /* if_icmpgt */ - 3, /* if_icmple */ - 3, /* if_acmpeq */ - 3, /* if_acmpne */ - 3, /* goto */ - 3, /* jsr */ - 2, /* ret */ - 99, /* tableswitch */ - 99, /* lookupswitch */ - 1, /* ireturn */ - 1, /* lreturn */ - 1, /* freturn */ - 1, /* dreturn */ - 1, /* areturn */ - 1, /* return */ - 3, /* getstatic */ - 3, /* putstatic */ - 3, /* getfield */ - 3, /* putfield */ - 3, /* invokevirtual */ - 3, /* invokespecial */ - 3, /* invokestatic */ - 5, /* invokeinterface */ - 0, /* xxxunusedxxx */ - 3, /* new */ - 2, /* newarray */ - 3, /* anewarray */ - 1, /* arraylength */ - 1, /* athrow */ - 3, /* checkcast */ - 3, /* instanceof */ - 1, /* monitorenter */ - 1, /* monitorexit */ - 0, /* wide */ - 4, /* multianewarray */ - 3, /* ifnull */ - 3, /* ifnonnull */ - 5, /* goto_w */ - 5, /* jsr_w */ - 1, /* breakpoint */ - 2, /* ldc_quick */ - 3, /* ldc_w_quick */ - 3, /* ldc2_w_quick */ - 3, /* getfield_quick */ - 3, /* putfield_quick */ - 3, /* getfield2_quick */ - 3, /* putfield2_quick */ - 3, /* getstatic_quick */ - 3, /* putstatic_quick */ - 3, /* getstatic2_quick */ - 3, /* putstatic2_quick */ - 3, /* invokevirtual_quick */ - 3, /* invokenonvirtual_quick */ - 3, /* invokesuper_quick */ - 3, /* invokestatic_quick */ - 5, /* invokeinterface_quick */ - 3, /* invokevirtualobject_quick */ - 3, /* invokeignored_quick */ - 3, /* new_quick */ - 3, /* anewarray_quick */ - 4, /* multianewarray_quick */ - 3, /* checkcast_quick */ - 3, /* instanceof_quick */ - 3, /* invokevirtual_quick_w */ - 3, /* getfield_quick_w */ - 3, /* putfield_quick_w */ - 1, /* nonnull_quick */ - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, -}; diff --git a/src/share/javavm/include/opcodes.list b/src/share/javavm/include/opcodes.list deleted file mode 100644 index db546070ac66dc5538f98c302e459bc04554928c..0000000000000000000000000000000000000000 --- a/src/share/javavm/include/opcodes.list +++ /dev/null @@ -1,301 +0,0 @@ -# Copyright 1994-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. -# - -# Any line that doesn't have a-z in the 1st column is a comment. -# -# The first column is the name of the opcodes. The second column is the -# total length of the instruction. We use 99 for tableswitch and -# tablelookup, which must always be treated as special cases. -# -# The third and fourth colum give what the opcode pops off the stack, and -# what it then pushes back onto the stack -# - -# I integer -# L long integer -# F float -# D double float -# A address [array or object] -# O object only -# R return address (for jsr) -# a integer, array, or object -# ? unknown -# [I], [L], [F], [D], [A], [B], [C], [?] -# array of integer, long, float, double, address, bytes, -# chars, or anything -# 1,2,3,4,+ used by stack duplicating/popping routines. -# -# 1,2,3,4 represent >>any<< stack type except long or double. Two numbers -# separated by a + (in the third column) indicate that the two, together, can -# be used for a double or long. (Or they can represent two non-long items). -# -# The fifth column provides an *approximate* relative cost of executing the -# opcode. It is used by the instruction profiler. See profiler.h for -# blurb. - -nop 1 - - 1 /* nop */ -aconst_null 1 - A 1 /* push null object */ -iconst_m1 1 - I 1 /* push integer constant -1 */ -iconst_0 1 - I 1 /* push integer constant 0 */ -iconst_1 1 - I 1 /* push integer constant 1 */ -iconst_2 1 - I 1 /* push integer constant 2 */ -iconst_3 1 - I 1 /* push integer constant 3 */ -iconst_4 1 - I 1 /* push integer constant 4 */ -iconst_5 1 - I 1 /* push integer constant 5 */ -lconst_0 1 - L 1 /* push long 0L */ -lconst_1 1 - L 1 /* push long 1L */ -fconst_0 1 - F 1 /* push float constant 0.0 */ -fconst_1 1 - F 1 /* push float constant 1.0 */ -fconst_2 1 - F 1 /* push float constant 2.0 */ -dconst_0 1 - D 1 /* push double float constant 0.0d */ -dconst_1 1 - D 1 /* push double float constant 1.0d */ -bipush 2 - I 1 /* push byte-sized value */ -sipush 3 - I 1 /* push two-byte value */ -ldc 2 - ? 1 /* load a const from constant table */ -ldc_w 3 - ? 1 -ldc2_w 3 - ? 1 /* load a 2-word constant . . . */ -iload 2 - I 1 /* load local integer variable */ -lload 2 - L 1 /* load local long variable */ -fload 2 - F 1 /* load local floating variable */ -dload 2 - D 1 /* load local double variable */ -aload 2 - A 1 /* load local object variable */ -iload_0 1 - I 1 /* load local integer variable #0 */ -iload_1 1 - I 1 /* load local integer variable #1 */ -iload_2 1 - I 1 /* load local integer variable #2 */ -iload_3 1 - I 1 /* load local integer variable #3 */ -lload_0 1 - L 1 /* load local long variable #0 */ -lload_1 1 - L 1 /* load local long variable #1 */ -lload_2 1 - L 1 /* load local long variable #2 */ -lload_3 1 - L 1 /* load local long variable #3 */ -fload_0 1 - F 1 /* load local float variable #0 */ -fload_1 1 - F 1 /* load local float variable #1 */ -fload_2 1 - F 1 /* load local float variable #2 */ -fload_3 1 - F 1 /* load local float variable #3 */ -dload_0 1 - D 1 /* load lcl double float variable #0 */ -dload_1 1 - D 1 /* load lcl double float variable #1 */ -dload_2 1 - D 1 /* load lcl double float variable #2 */ -dload_3 1 - D 1 /* load lcl double float variable #3 */ -aload_0 1 - A 1 /* load local object variable #0 */ -aload_1 1 - A 1 /* load local object variable #1 */ -aload_2 1 - A 1 /* load local object variable #2 */ -aload_3 1 - A 1 /* load local object variable #3 */ -iaload 1 [I]I I 1 /* load from array of integer */ -laload 1 [L]I L 1 /* load from array of long */ -faload 1 [F]I F 1 /* load from array of float */ -daload 1 [D]I D 1 /* load from array of double */ -aaload 1 [A]I A 1 /* load from array of object */ -baload 1 [B]I I 1 /* load from array of (signed) bytes */ -caload 1 [C]I I 1 /* load from array of chars */ -saload 1 [S]I I 1 /* load from array of (signed) shorts */ -istore 2 I - 1 /* store local integer variable */ -lstore 2 L - 1 /* store local long variable */ -fstore 2 F - 1 /* store local float variable */ -dstore 2 D - 1 /* store local double variable */ -astore 2 A - 1 /* store local object variable */ -istore_0 1 I - 1 /* store local integer variable #0 */ -istore_1 1 I - 1 /* store local integer variable #1 */ -istore_2 1 I - 1 /* store local integer variable #2 */ -istore_3 1 I - 1 /* store local integer variable #3 */ -lstore_0 1 L - 1 /* store local long variable #0 */ -lstore_1 1 L - 1 /* store local long variable #1 */ -lstore_2 1 L - 1 /* store local long variable #2 */ -lstore_3 1 L - 1 /* store local long variable #3 */ -fstore_0 1 F - 1 /* store local float variable #0 */ -fstore_1 1 F - 1 /* store local float variable #1 */ -fstore_2 1 F - 1 /* store local float variable #2 */ -fstore_3 1 F - 1 /* store local float variable #3 */ -dstore_0 1 D - 1 /* store lcl double float variable #0 */ -dstore_1 1 D - 1 /* store lcl double float variable #1 */ -dstore_2 1 D - 1 /* store lcl double float variable #2 */ -dstore_3 1 D - 1 /* store lcl double float variable #3 */ -astore_0 1 A - 1 /* store local object variable #0 */ -astore_1 1 A - 1 /* store local object variable #1 */ -astore_2 1 A - 1 /* store local object variable #2 */ -astore_3 1 A - 1 /* store local object variable #3 */ -iastore 1 [I]II - 1 /* store into array of int */ -lastore 1 [L]IL - 1 /* store into array of long */ -fastore 1 [F]IF - 1 /* store into array of float */ -dastore 1 [D]ID - 1 /* store into array of double float */ -aastore 1 [A]IA - 1 /* store into array of object */ -bastore 1 [B]II - 1 /* store into array of (signed) bytes */ -castore 1 [C]II - 1 /* store into array of chars */ -sastore 1 [S]II - 1 /* store into array of (signed) shorts*/ -pop 1 1 - 1 /* pop top element */ -pop2 1 2+1 - 1 /* pop top two elements */ -dup 1 1 11 1 /* dup top element */ -dup_x1 1 21 121 1 /* dup top element. Skip one */ -dup_x2 1 3+21 1321 1 /* dup top element. Skip two */ -dup2 1 2+1 2121 1 /* dup top two elements. */ -dup2_x1 1 32+1 21321 1 /* dup top two elements. Skip one */ -dup2_x2 1 4+32+1 214321 1 /* dup top two elements. Skip two */ -swap 1 21 12 1 /* swap top two elements of stack. */ -iadd 1 II I 1 /* integer add */ -ladd 1 LL L 1 /* long add */ -fadd 1 FF F 1 /* floating add */ -dadd 1 DD D 1 /* double float add */ -isub 1 II I 1 /* integer subtract */ -lsub 1 LL L 1 /* long subtract */ -fsub 1 FF F 1 /* floating subtract */ -dsub 1 DD D 1 /* floating double subtract */ -imul 1 II I 1 /* integer multiply */ -lmul 1 LL L 1 /* long multiply */ -fmul 1 FF F 1 /* floating multiply */ -dmul 1 DD D 1 /* double float multiply */ -idiv 1 II I 1 /* integer divide */ -ldiv 1 LL L 1 /* long divide */ -fdiv 1 FF F 1 /* floating divide */ -ddiv 1 DD D 1 /* double float divide */ -irem 1 II I 1 /* integer mod */ -lrem 1 LL L 1 /* long mod */ -frem 1 FF F 1 /* floating mod */ -drem 1 DD D 1 /* double float mod */ -ineg 1 I I 1 /* integer negate */ -lneg 1 L L 1 /* long negate */ -fneg 1 F F 1 /* floating negate */ -dneg 1 D D 1 /* double float negate */ -ishl 1 II I 1 /* shift left */ -lshl 1 LI L 1 /* long shift left */ -ishr 1 II I 1 /* shift right */ -lshr 1 LI L 1 /* long shift right */ -iushr 1 II I 1 /* unsigned shift right */ -lushr 1 LI L 1 /* long unsigned shift right */ -iand 1 II I 1 /* boolean and */ -land 1 LL L 1 /* long boolean and */ -ior 1 II I 1 /* boolean or */ -lor 1 LL L 1 /* long boolean or */ -ixor 1 II I 1 /* boolean xor */ -lxor 1 LL L 1 /* long boolean xor */ -iinc 3 - - 1 /* increment lcl variable by constant */ -i2l 1 I L 1 /* integer to long */ -i2f 1 I F 1 /* integer to float */ -i2d 1 I D 1 /* integer to double */ -l2i 1 L I 1 /* long to integer */ -l2f 1 L F 1 /* long to float */ -l2d 1 L D 1 /* long to double */ -f2i 1 F I 1 /* float to integer */ -f2l 1 F L 1 /* float to long */ -f2d 1 F D 1 /* float to double */ -d2i 1 D I 1 /* double to integer */ -d2l 1 D L 1 /* double to long */ -d2f 1 D F 1 /* double to float */ -i2b 1 I I 1 /* integer to byte */ -i2c 1 I I 1 /* integer to character */ -i2s 1 I I 1 /* integer to signed short */ -lcmp 1 LL I 1 /* long compare */ -fcmpl 1 FF I 1 /* float compare. -1 on incomparable */ -fcmpg 1 FF I 1 /* float compare. 1 on incomparable */ -dcmpl 1 DD I 1 /* dbl floating cmp. -1 on incomp */ -dcmpg 1 DD I 1 /* dbl floating cmp. 1 on incomp */ -ifeq 3 I - 1 /* goto if equal */ -ifne 3 I - 1 /* goto if not equal */ -iflt 3 I - 1 /* goto if less than */ -ifge 3 I - 1 /* goto if greater than or equal */ -ifgt 3 I - 1 /* goto if greater than */ -ifle 3 I - 1 /* goto if less than or equal */ -if_icmpeq 3 II - 1 /* compare top two elements of stack */ -if_icmpne 3 II - 1 /* compare top two elements of stack */ -if_icmplt 3 II - 1 /* compare top two elements of stack */ -if_icmpge 3 II - 1 /* compare top two elements of stack */ -if_icmpgt 3 II - 1 /* compare top two elements of stack */ -if_icmple 3 II - 1 /* compare top two elements of stack */ -if_acmpeq 3 AA - 1 /* compare top two objects of stack */ -if_acmpne 3 AA - 1 /* compare top two objects of stack */ -goto 3 - - 1 /* unconditional goto */ -jsr 3 - R 1 /* jump subroutine */ -ret 2 - - 1 /* return from subroutine */ -tableswitch 99 I - 1 /* goto (case) */ -lookupswitch 99 I - 1 /* goto (case) */ -ireturn 1 I - 1 /* return integer from procedure */ -lreturn 1 L - 1 /* return long from procedure */ -freturn 1 F - 1 /* return float from procedure */ -dreturn 1 D - 1 /* return double from procedure */ -areturn 1 A - 1 /* return object from procedure */ -return 1 - - 1 /* return (void) from procedure */ -getstatic 3 - ? 1 /* get static field value. */ -putstatic 3 ? - 1 /* assign static field value */ -getfield 3 A ? 1 /* get field value from object. */ -putfield 3 ? - 1 /* assign field value to object. */ -invokevirtual 3 ? ? 1 /* call method, based on object. */ -invokespecial 3 ? ? 1 /* call method, not based on object. */ -invokestatic 3 ? ? 1 /* call a static method. */ -invokeinterface 5 ? ? 1 /* call an interface method */ -xxxunusedxxx 0 ? ? 1 /* was newfromname */ -new 3 - A 1 /* Create a new object */ -newarray 2 I A 1 /* Create a new array of non-objects*/ -anewarray 3 I A 1 /* Create a new array of objects */ -arraylength 1 [?] I 1 /* get length of array */ -athrow 1 O - 1 /* throw an exception */ -checkcast 3 A A 1 /* error if object not of given type */ -instanceof 3 A I 1 /* is object of given type? */ -monitorenter 1 A - 1 /* enter a monitored region of code */ -monitorexit 1 A - 1 /* exit a monitored region of code */ -wide 0 - - 1 /* prefix operation. */ -multianewarray 4 ? A 1 /* create multidimensional array */ -ifnull 3 A - 1 /* goto if null */ -ifnonnull 3 A - 1 /* goto if not null */ - -# The following instructions are "long" versions. They allow access to -# variables with index greater than 255. - -goto_w 5 - - 1 /* unconditional goto. 4byte offset */ -jsr_w 5 - R 1 /* jump subroutine. 4byte offset */ - -breakpoint 1 - - 1 /* call breakpoint handler */ - -# The compiler will not generate any of the following instructions. That -# are created by the interpreter from the non _quick versions of the -# instructions. - -ldc_quick 2 - ? 1 -ldc_w_quick 3 - ? 1 -ldc2_w_quick 3 - ? 1 -getfield_quick 3 A ? 1 -putfield_quick 3 ? - 1 -getfield2_quick 3 A ? 1 -putfield2_quick 3 ? - 1 -getstatic_quick 3 - ? 1 -putstatic_quick 3 ? - 1 -getstatic2_quick 3 - ? 1 -putstatic2_quick 3 ? _ 1 -invokevirtual_quick 3 ? ? 1 -invokenonvirtual_quick 3 ? ? 1 -invokesuper_quick 3 ? ? 1 -invokestatic_quick 3 ? ? 1 -invokeinterface_quick 5 ? ? 1 -invokevirtualobject_quick 3 ? ? 1 -invokeignored_quick 3 ? ? 1 -new_quick 3 - A 1 -anewarray_quick 3 I A 1 -multianewarray_quick 4 ? A 1 -checkcast_quick 3 A A 1 -instanceof_quick 3 A I 1 - -# The following are generated when the offset is bigger than 255 - -invokevirtual_quick_w 3 ? ? 1 -getfield_quick_w 3 A ? 1 -putfield_quick_w 3 ? - 1 - -# used for simplification - -nonnull_quick 1 A - 1 /* throw exception if stacktop null */ diff --git a/src/share/javavm/include/opcodes.weight b/src/share/javavm/include/opcodes.weight deleted file mode 100644 index e1a2d6d51dcb8fe2ebb7dbcd76e80480430c196a..0000000000000000000000000000000000000000 --- a/src/share/javavm/include/opcodes.weight +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright 1998-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. - */ - -char const opcode_weight[256] = { - 1, /* nop */ - 1, /* aconst_null */ - 1, /* iconst_m1 */ - 1, /* iconst_0 */ - 1, /* iconst_1 */ - 1, /* iconst_2 */ - 1, /* iconst_3 */ - 1, /* iconst_4 */ - 1, /* iconst_5 */ - 1, /* lconst_0 */ - 1, /* lconst_1 */ - 1, /* fconst_0 */ - 1, /* fconst_1 */ - 1, /* fconst_2 */ - 1, /* dconst_0 */ - 1, /* dconst_1 */ - 1, /* bipush */ - 1, /* sipush */ - 1, /* ldc */ - 1, /* ldc_w */ - 1, /* ldc2_w */ - 1, /* iload */ - 1, /* lload */ - 1, /* fload */ - 1, /* dload */ - 1, /* aload */ - 1, /* iload_0 */ - 1, /* iload_1 */ - 1, /* iload_2 */ - 1, /* iload_3 */ - 1, /* lload_0 */ - 1, /* lload_1 */ - 1, /* lload_2 */ - 1, /* lload_3 */ - 1, /* fload_0 */ - 1, /* fload_1 */ - 1, /* fload_2 */ - 1, /* fload_3 */ - 1, /* dload_0 */ - 1, /* dload_1 */ - 1, /* dload_2 */ - 1, /* dload_3 */ - 1, /* aload_0 */ - 1, /* aload_1 */ - 1, /* aload_2 */ - 1, /* aload_3 */ - 1, /* iaload */ - 1, /* laload */ - 1, /* faload */ - 1, /* daload */ - 1, /* aaload */ - 1, /* baload */ - 1, /* caload */ - 1, /* saload */ - 1, /* istore */ - 1, /* lstore */ - 1, /* fstore */ - 1, /* dstore */ - 1, /* astore */ - 1, /* istore_0 */ - 1, /* istore_1 */ - 1, /* istore_2 */ - 1, /* istore_3 */ - 1, /* lstore_0 */ - 1, /* lstore_1 */ - 1, /* lstore_2 */ - 1, /* lstore_3 */ - 1, /* fstore_0 */ - 1, /* fstore_1 */ - 1, /* fstore_2 */ - 1, /* fstore_3 */ - 1, /* dstore_0 */ - 1, /* dstore_1 */ - 1, /* dstore_2 */ - 1, /* dstore_3 */ - 1, /* astore_0 */ - 1, /* astore_1 */ - 1, /* astore_2 */ - 1, /* astore_3 */ - 1, /* iastore */ - 1, /* lastore */ - 1, /* fastore */ - 1, /* dastore */ - 1, /* aastore */ - 1, /* bastore */ - 1, /* castore */ - 1, /* sastore */ - 1, /* pop */ - 1, /* pop2 */ - 1, /* dup */ - 1, /* dup_x1 */ - 1, /* dup_x2 */ - 1, /* dup2 */ - 1, /* dup2_x1 */ - 1, /* dup2_x2 */ - 1, /* swap */ - 1, /* iadd */ - 1, /* ladd */ - 1, /* fadd */ - 1, /* dadd */ - 1, /* isub */ - 1, /* lsub */ - 1, /* fsub */ - 1, /* dsub */ - 1, /* imul */ - 1, /* lmul */ - 1, /* fmul */ - 1, /* dmul */ - 1, /* idiv */ - 1, /* ldiv */ - 1, /* fdiv */ - 1, /* ddiv */ - 1, /* irem */ - 1, /* lrem */ - 1, /* frem */ - 1, /* drem */ - 1, /* ineg */ - 1, /* lneg */ - 1, /* fneg */ - 1, /* dneg */ - 1, /* ishl */ - 1, /* lshl */ - 1, /* ishr */ - 1, /* lshr */ - 1, /* iushr */ - 1, /* lushr */ - 1, /* iand */ - 1, /* land */ - 1, /* ior */ - 1, /* lor */ - 1, /* ixor */ - 1, /* lxor */ - 1, /* iinc */ - 1, /* i2l */ - 1, /* i2f */ - 1, /* i2d */ - 1, /* l2i */ - 1, /* l2f */ - 1, /* l2d */ - 1, /* f2i */ - 1, /* f2l */ - 1, /* f2d */ - 1, /* d2i */ - 1, /* d2l */ - 1, /* d2f */ - 1, /* i2b */ - 1, /* i2c */ - 1, /* i2s */ - 1, /* lcmp */ - 1, /* fcmpl */ - 1, /* fcmpg */ - 1, /* dcmpl */ - 1, /* dcmpg */ - 1, /* ifeq */ - 1, /* ifne */ - 1, /* iflt */ - 1, /* ifge */ - 1, /* ifgt */ - 1, /* ifle */ - 1, /* if_icmpeq */ - 1, /* if_icmpne */ - 1, /* if_icmplt */ - 1, /* if_icmpge */ - 1, /* if_icmpgt */ - 1, /* if_icmple */ - 1, /* if_acmpeq */ - 1, /* if_acmpne */ - 1, /* goto */ - 1, /* jsr */ - 1, /* ret */ - 1, /* tableswitch */ - 1, /* lookupswitch */ - 1, /* ireturn */ - 1, /* lreturn */ - 1, /* freturn */ - 1, /* dreturn */ - 1, /* areturn */ - 1, /* return */ - 1, /* getstatic */ - 1, /* putstatic */ - 1, /* getfield */ - 1, /* putfield */ - 1, /* invokevirtual */ - 1, /* invokespecial */ - 1, /* invokestatic */ - 1, /* invokeinterface */ - 1, /* xxxunusedxxx */ - 1, /* new */ - 1, /* newarray */ - 1, /* anewarray */ - 1, /* arraylength */ - 1, /* athrow */ - 1, /* checkcast */ - 1, /* instanceof */ - 1, /* monitorenter */ - 1, /* monitorexit */ - 1, /* wide */ - 1, /* multianewarray */ - 1, /* ifnull */ - 1, /* ifnonnull */ - 1, /* goto_w */ - 1, /* jsr_w */ - 1, /* breakpoint */ - 1, /* ldc_quick */ - 1, /* ldc_w_quick */ - 1, /* ldc2_w_quick */ - 1, /* getfield_quick */ - 1, /* putfield_quick */ - 1, /* getfield2_quick */ - 1, /* putfield2_quick */ - 1, /* getstatic_quick */ - 1, /* putstatic_quick */ - 1, /* getstatic2_quick */ - 1, /* putstatic2_quick */ - 1, /* invokevirtual_quick */ - 1, /* invokenonvirtual_quick */ - 1, /* invokesuper_quick */ - 1, /* invokestatic_quick */ - 1, /* invokeinterface_quick */ - 1, /* invokevirtualobject_quick */ - 1, /* invokeignored_quick */ - 1, /* new_quick */ - 1, /* anewarray_quick */ - 1, /* multianewarray_quick */ - 1, /* checkcast_quick */ - 1, /* instanceof_quick */ - 1, /* invokevirtual_quick_w */ - 1, /* getfield_quick_w */ - 1, /* putfield_quick_w */ - 1, /* nonnull_quick */ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, -}; diff --git a/src/share/javavm/include/opcodes.wide b/src/share/javavm/include/opcodes.wide deleted file mode 100644 index ed33d819b441ef2bcfee3d1a06ed05d26a7ec2f8..0000000000000000000000000000000000000000 --- a/src/share/javavm/include/opcodes.wide +++ /dev/null @@ -1,256 +0,0 @@ -NoWideOpcode(nop) -NoWideOpcode(aconst_null) -NoWideOpcode(iconst_m1) -NoWideOpcode(iconst_0) -NoWideOpcode(iconst_1) -NoWideOpcode(iconst_2) -NoWideOpcode(iconst_3) -NoWideOpcode(iconst_4) -NoWideOpcode(iconst_5) -NoWideOpcode(lconst_0) -NoWideOpcode(lconst_1) -NoWideOpcode(fconst_0) -NoWideOpcode(fconst_1) -NoWideOpcode(fconst_2) -NoWideOpcode(dconst_0) -NoWideOpcode(dconst_1) -NoWideOpcode(bipush) -NoWideOpcode(sipush) -NoWideOpcode(ldc) -NoWideOpcode(ldc_w) -NoWideOpcode(ldc2_w) -WideOpcode(iload) -WideOpcode(lload) -WideOpcode(fload) -WideOpcode(dload) -WideOpcode(aload) -NoWideOpcode(iload_0) -NoWideOpcode(iload_1) -NoWideOpcode(iload_2) -NoWideOpcode(iload_3) -NoWideOpcode(lload_0) -NoWideOpcode(lload_1) -NoWideOpcode(lload_2) -NoWideOpcode(lload_3) -NoWideOpcode(fload_0) -NoWideOpcode(fload_1) -NoWideOpcode(fload_2) -NoWideOpcode(fload_3) -NoWideOpcode(dload_0) -NoWideOpcode(dload_1) -NoWideOpcode(dload_2) -NoWideOpcode(dload_3) -NoWideOpcode(aload_0) -NoWideOpcode(aload_1) -NoWideOpcode(aload_2) -NoWideOpcode(aload_3) -NoWideOpcode(iaload) -NoWideOpcode(laload) -NoWideOpcode(faload) -NoWideOpcode(daload) -NoWideOpcode(aaload) -NoWideOpcode(baload) -NoWideOpcode(caload) -NoWideOpcode(saload) -WideOpcode(istore) -WideOpcode(lstore) -WideOpcode(fstore) -WideOpcode(dstore) -WideOpcode(astore) -NoWideOpcode(istore_0) -NoWideOpcode(istore_1) -NoWideOpcode(istore_2) -NoWideOpcode(istore_3) -NoWideOpcode(lstore_0) -NoWideOpcode(lstore_1) -NoWideOpcode(lstore_2) -NoWideOpcode(lstore_3) -NoWideOpcode(fstore_0) -NoWideOpcode(fstore_1) -NoWideOpcode(fstore_2) -NoWideOpcode(fstore_3) -NoWideOpcode(dstore_0) -NoWideOpcode(dstore_1) -NoWideOpcode(dstore_2) -NoWideOpcode(dstore_3) -NoWideOpcode(astore_0) -NoWideOpcode(astore_1) -NoWideOpcode(astore_2) -NoWideOpcode(astore_3) -NoWideOpcode(iastore) -NoWideOpcode(lastore) -NoWideOpcode(fastore) -NoWideOpcode(dastore) -NoWideOpcode(aastore) -NoWideOpcode(bastore) -NoWideOpcode(castore) -NoWideOpcode(sastore) -NoWideOpcode(pop) -NoWideOpcode(pop2) -NoWideOpcode(dup) -NoWideOpcode(dup_x1) -NoWideOpcode(dup_x2) -NoWideOpcode(dup2) -NoWideOpcode(dup2_x1) -NoWideOpcode(dup2_x2) -NoWideOpcode(swap) -NoWideOpcode(iadd) -NoWideOpcode(ladd) -NoWideOpcode(fadd) -NoWideOpcode(dadd) -NoWideOpcode(isub) -NoWideOpcode(lsub) -NoWideOpcode(fsub) -NoWideOpcode(dsub) -NoWideOpcode(imul) -NoWideOpcode(lmul) -NoWideOpcode(fmul) -NoWideOpcode(dmul) -NoWideOpcode(idiv) -NoWideOpcode(ldiv) -NoWideOpcode(fdiv) -NoWideOpcode(ddiv) -NoWideOpcode(irem) -NoWideOpcode(lrem) -NoWideOpcode(frem) -NoWideOpcode(drem) -NoWideOpcode(ineg) -NoWideOpcode(lneg) -NoWideOpcode(fneg) -NoWideOpcode(dneg) -NoWideOpcode(ishl) -NoWideOpcode(lshl) -NoWideOpcode(ishr) -NoWideOpcode(lshr) -NoWideOpcode(iushr) -NoWideOpcode(lushr) -NoWideOpcode(iand) -NoWideOpcode(land) -NoWideOpcode(ior) -NoWideOpcode(lor) -NoWideOpcode(ixor) -NoWideOpcode(lxor) -WideOpcode(iinc) -NoWideOpcode(i2l) -NoWideOpcode(i2f) -NoWideOpcode(i2d) -NoWideOpcode(l2i) -NoWideOpcode(l2f) -NoWideOpcode(l2d) -NoWideOpcode(f2i) -NoWideOpcode(f2l) -NoWideOpcode(f2d) -NoWideOpcode(d2i) -NoWideOpcode(d2l) -NoWideOpcode(d2f) -NoWideOpcode(i2b) -NoWideOpcode(i2c) -NoWideOpcode(i2s) -NoWideOpcode(lcmp) -NoWideOpcode(fcmpl) -NoWideOpcode(fcmpg) -NoWideOpcode(dcmpl) -NoWideOpcode(dcmpg) -NoWideOpcode(ifeq) -NoWideOpcode(ifne) -NoWideOpcode(iflt) -NoWideOpcode(ifge) -NoWideOpcode(ifgt) -NoWideOpcode(ifle) -NoWideOpcode(if_icmpeq) -NoWideOpcode(if_icmpne) -NoWideOpcode(if_icmplt) -NoWideOpcode(if_icmpge) -NoWideOpcode(if_icmpgt) -NoWideOpcode(if_icmple) -NoWideOpcode(if_acmpeq) -NoWideOpcode(if_acmpne) -NoWideOpcode(goto) -NoWideOpcode(jsr) -WideOpcode(ret) -NoWideOpcode(tableswitch) -NoWideOpcode(lookupswitch) -NoWideOpcode(ireturn) -NoWideOpcode(lreturn) -NoWideOpcode(freturn) -NoWideOpcode(dreturn) -NoWideOpcode(areturn) -NoWideOpcode(return) -NoWideOpcode(getstatic) -NoWideOpcode(putstatic) -NoWideOpcode(getfield) -NoWideOpcode(putfield) -NoWideOpcode(invokevirtual) -NoWideOpcode(invokespecial) -NoWideOpcode(invokestatic) -NoWideOpcode(invokeinterface) -NoWideOpcode(xxxunusedxxx) -NoWideOpcode(new) -NoWideOpcode(newarray) -NoWideOpcode(anewarray) -NoWideOpcode(arraylength) -NoWideOpcode(athrow) -NoWideOpcode(checkcast) -NoWideOpcode(instanceof) -NoWideOpcode(monitorenter) -NoWideOpcode(monitorexit) -NoWideOpcode(wide) -NoWideOpcode(multianewarray) -NoWideOpcode(ifnull) -NoWideOpcode(ifnonnull) -NoWideOpcode(goto_w) -NoWideOpcode(jsr_w) -NoWideOpcode(breakpoint) -NoWideOpcode(ldc_quick) -NoWideOpcode(ldc_w_quick) -NoWideOpcode(ldc2_w_quick) -NoWideOpcode(getfield_quick) -NoWideOpcode(putfield_quick) -NoWideOpcode(getfield2_quick) -NoWideOpcode(putfield2_quick) -NoWideOpcode(getstatic_quick) -NoWideOpcode(putstatic_quick) -NoWideOpcode(getstatic2_quick) -NoWideOpcode(putstatic2_quick) -NoWideOpcode(invokevirtual_quick) -NoWideOpcode(invokenonvirtual_quick) -NoWideOpcode(invokesuper_quick) -NoWideOpcode(invokestatic_quick) -NoWideOpcode(invokeinterface_quick) -NoWideOpcode(invokevirtualobject_quick) -NoWideOpcode(invokeignored_quick) -NoWideOpcode(new_quick) -NoWideOpcode(anewarray_quick) -NoWideOpcode(multianewarray_quick) -NoWideOpcode(checkcast_quick) -NoWideOpcode(instanceof_quick) -NoWideOpcode(invokevirtual_quick_w) -NoWideOpcode(getfield_quick_w) -NoWideOpcode(putfield_quick_w) -NoWideOpcode(nonnull_quick) -NoWideOpcode(Illegal230) -NoWideOpcode(Illegal231) -NoWideOpcode(Illegal232) -NoWideOpcode(Illegal233) -NoWideOpcode(Illegal234) -NoWideOpcode(Illegal235) -NoWideOpcode(Illegal236) -NoWideOpcode(Illegal237) -NoWideOpcode(Illegal238) -NoWideOpcode(Illegal239) -NoWideOpcode(Illegal240) -NoWideOpcode(Illegal241) -NoWideOpcode(Illegal242) -NoWideOpcode(Illegal243) -NoWideOpcode(Illegal244) -NoWideOpcode(Illegal245) -NoWideOpcode(Illegal246) -NoWideOpcode(Illegal247) -NoWideOpcode(Illegal248) -NoWideOpcode(Illegal249) -NoWideOpcode(Illegal250) -NoWideOpcode(Illegal251) -NoWideOpcode(Illegal252) -NoWideOpcode(Illegal253) -NoWideOpcode(Illegal254) -NoWideOpcode(Illegal255) diff --git a/src/share/javavm/include/sys_api.h b/src/share/javavm/include/sys_api.h deleted file mode 100644 index d7856c3f658f2b0d96e394b18dcb49ff3e6473d8..0000000000000000000000000000000000000000 --- a/src/share/javavm/include/sys_api.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 1994-1999 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. - */ - -#ifndef _JAVASOFT_SYS_API_H_ -#define _JAVASOFT_SYS_API_H_ - -#include "hpi.h" - -extern HPI_MemoryInterface *hpi_memory_interface; -extern HPI_LibraryInterface *hpi_library_interface; -extern HPI_SystemInterface *hpi_system_interface; -extern HPI_ThreadInterface *hpi_thread_interface; -extern HPI_FileInterface *hpi_file_interface; -extern HPI_SocketInterface *hpi_socket_interface; - -#define sysMalloc(x) hpi_memory_interface->Malloc(x) -#define sysRealloc(x,y) hpi_memory_interface->Realloc(x,y) -#define sysFree(x) hpi_memory_interface->Free(x) -#define sysCalloc(x,y) hpi_memory_interface->Calloc(x,y) -#define sysStrdup(x) hpi_memory_interface->Strdup(x) -#define sysMapMem(x,y) hpi_memory_interface->MapMem(x,y) -#define sysUnmapMem(x,y,z) hpi_memory_interface->UnmapMem(x,y,z) -#define sysCommitMem(x,y,z) hpi_memory_interface->CommitMem(x,y,z) -#define sysDecommitMem(x,y,z) hpi_memory_interface->DecommitMem(x,y,z) -#define sysAllocBlock(x,y) hpi_memory_interface->AllocBlock(x,y) -#define sysFreeBlock(x) hpi_memory_interface->FreeBlock(x) - -#define sysBuildLibName(a,b,c,d) hpi_library_interface->BuildLibName(a,b,c,d) -#define sysBuildFunName(a,b,c,d) hpi_library_interface->BuildFunName(a,b,c,d) -#define sysLoadLibrary(a,b,c) hpi_library_interface->LoadLibrary(a,b,c) -#define sysUnloadLibrary(a) hpi_library_interface->UnloadLibrary(a) -#define sysFindLibraryEntry(a,b) hpi_library_interface->FindLibraryEntry(a,b) - -#define sysGetSysInfo() hpi_system_interface->GetSysInfo() -#define sysGetMilliTicks() hpi_system_interface->GetMilliTicks() -#define sysTimeMillis() hpi_system_interface->TimeMillis() - -#define sysSignal(a,b) hpi_system_interface->Signal(a,b) -#define sysRaise(a) hpi_system_interface->Raise(a) -#define sysSignalNotify(a) hpi_system_interface->SignalNotify(a) -#define sysSignalWait() hpi_system_interface->SignalWait() -#define sysShutdown() hpi_system_interface->Shutdown() -#define sysSetLoggingLevel(a) hpi_system_interface->SetLoggingLevel(a) -#define sysSetMonitoringOn(a) hpi_system_interface->SetMonitoringOn(a) -#define sysGetLastErrorString(a,b) hpi_system_interface->GetLastErrorString(a,b) - -#define sysThreadBootstrap(a,b,c) hpi_thread_interface->ThreadBootstrap(a,b,c) -#define sysThreadCreate(a,b,c,d) hpi_thread_interface->ThreadCreate(a,b,c,d) -#define sysThreadSelf() hpi_thread_interface->ThreadSelf() -#define sysThreadYield() hpi_thread_interface->ThreadYield() -#define sysThreadSuspend(a) hpi_thread_interface->ThreadSuspend(a) -#define sysThreadResume(a) hpi_thread_interface->ThreadResume(a) -#define sysThreadSetPriority(a,b) hpi_thread_interface->ThreadSetPriority(a,b) -#define sysThreadGetPriority(a,b) hpi_thread_interface->ThreadGetPriority(a,b) -#define sysThreadStackPointer(a) hpi_thread_interface->ThreadStackPointer(a) -#define sysThreadStackTop(a) hpi_thread_interface->ThreadStackTop(a) -#define sysThreadRegs(a,b) hpi_thread_interface->ThreadRegs(a,b) -#define sysThreadSingle() hpi_thread_interface->ThreadSingle() -#define sysThreadMulti() hpi_thread_interface->ThreadMulti() -#define sysThreadCheckStack() hpi_thread_interface->ThreadCheckStack() -#define sysThreadPostException(a,b) \ - hpi_thread_interface->ThreadPostException(a,b) -#define sysThreadInterrupt(a) hpi_thread_interface->ThreadInterrupt(a) -#define sysThreadIsInterrupted(a,b) \ - hpi_thread_interface->ThreadIsInterrupted(a,b) -#define sysThreadAlloc(a) hpi_thread_interface->ThreadAlloc(a) -#define sysThreadFree() hpi_thread_interface->ThreadFree() -#define sysThreadCPUTime() hpi_thread_interface->ThreadCPUTime() -#define sysThreadGetStatus(a,b) hpi_thread_interface->ThreadGetStatus(a,b) -#define sysThreadEnumerateOver(a,b) \ - hpi_thread_interface->ThreadEnumerateOver(a,b) -#define sysThreadIsRunning(a) hpi_thread_interface->ThreadIsRunning(a) -#define sysThreadProfSuspend(a) hpi_thread_interface->ThreadProfSuspend(a) -#define sysThreadProfResume(a) hpi_thread_interface->ThreadProfResume(a) -#define sysAdjustTimeSlice(a) hpi_thread_interface->AdjustTimeSlice(a) - -#define sysMonitorSizeof() hpi_thread_interface->MonitorSizeof() -#define sysMonitorInit(a) hpi_thread_interface->MonitorInit(a) -#define sysMonitorDestroy(a) hpi_thread_interface->MonitorDestroy(a) -#define sysMonitorEnter(a,b) hpi_thread_interface->MonitorEnter(a,b) -#define sysMonitorEntered(a,b) hpi_thread_interface->MonitorEntered(a,b) -#define sysMonitorExit(a,b) hpi_thread_interface->MonitorExit(a,b) -#define sysMonitorNotify(a,b) hpi_thread_interface->MonitorNotify(a,b) -#define sysMonitorNotifyAll(a,b) hpi_thread_interface->MonitorNotifyAll(a,b) -#define sysMonitorWait(a,b,c) hpi_thread_interface->MonitorWait(a,b,c) -#define sysMonitorInUse(a) hpi_thread_interface->MonitorInUse(a) -#define sysMonitorOwner(a) hpi_thread_interface->MonitorOwner(a) -#define sysMonitorGetInfo(a,b) hpi_thread_interface->MonitorGetInfo(a,b) - -#define sysThreadInterruptEvent() hpi_thread_interface->ThreadInterruptEvent() -#define sysThreadNativeID(a) hpi_thread_interface->ThreadNativeID(a) - -#define sysNativePath(a) hpi_file_interface->NativePath(a) -#define sysFileType(a) hpi_file_interface->FileType(a) -#define sysOpen(a,b,c) hpi_file_interface->Open(a,b,c) -#define sysClose(a) hpi_file_interface->Close(a) -#define sysSeek(a,b,c) hpi_file_interface->Seek(a,b,c) -#define sysSetLength(a,b) hpi_file_interface->SetLength(a,b) -#define sysSync(a) hpi_file_interface->Sync(a) -#define sysAvailable(a,b) hpi_file_interface->Available(a,b) -#define sysRead(a,b,c) hpi_file_interface->Read(a,b,c) -#define sysWrite(a,b,c) hpi_file_interface->Write(a,b,c) -#define sysFileSizeFD(a,b) hpi_file_interface->FileSizeFD(a,b) - -#define sysSocketClose(a) hpi_socket_interface->Close(a) -#define sysSocketShutdown(a,b) hpi_socket_interface->SocketShutdown(a,b) -#define sysSocketAvailable(a,b) hpi_socket_interface->Available(a,b) -#define sysConnect(a,b,c) hpi_socket_interface->Connect(a,b,c) -#define sysBind(a,b,c) hpi_socket_interface->Bind(a,b,c) -#define sysAccept(a,b,c) hpi_socket_interface->Accept(a,b,c) -#define sysGetSockName(a,b,c) hpi_socket_interface->GetSocketName(a,b,c) -#define sysSendTo(a,b,c,d,e,f) hpi_socket_interface->SendTo(a,b,c,d,e,f) -#define sysRecvFrom(a,b,c,d,e,f) hpi_socket_interface->RecvFrom(a,b,c,d,e,f) -#define sysListen(a,b) hpi_socket_interface->Listen(a,b) -#define sysRecv(a,b,c,d) hpi_socket_interface->Recv(a,b,c,d) -#define sysSend(a,b,c,d) hpi_socket_interface->Send(a,b,c,d) -#define sysTimeout(a,b) hpi_socket_interface->Timeout(a,b) -#define sysGetHostName(a, b) hpi_socket_interface->GetHostName(a, b) -#define sysGetHostByAddr(a, b, c) hpi_socket_interface->GetHostByAddr(a, b, c) -#define sysGetHostByName(a) hpi_socket_interface->GetHostByName(a) -#define sysSocket(a,b,c) hpi_socket_interface->Socket(a,b,c) -#define sysGetSockOpt(a, b, c, d, e) hpi_socket_interface->SocketGetOption(a, b, c, d, e) -#define sysSetSockOpt(a, b, c, d, e) hpi_socket_interface->SocketSetOption(a, b, c, d, e) -#define sysGetProtoByName(a) hpi_socket_interface->GetProtoByName(a) - -#define SYS_SIG_DFL HPI_SIG_DFL -#define SYS_SIG_ERR HPI_SIG_ERR -#define SYS_SIG_IGN HPI_SIG_IGN - -#define SYS_OK HPI_OK -#define SYS_ERR HPI_ERR -#define SYS_INTRPT HPI_INTRPT -#define SYS_TIMEOUT HPI_TIMEOUT -#define SYS_NOMEM HPI_NOMEM -#define SYS_NORESOURCE HPI_NORESOURCE - -#define SYS_THREAD_RUNNABLE HPI_THREAD_RUNNABLE -#define SYS_THREAD_MONITOR_WAIT HPI_THREAD_MONITOR_WAIT -#define SYS_THREAD_CONDVAR_WAIT HPI_THREAD_CONDVAR_WAIT - -#define MinimumPriority HPI_MINIMUM_PRIORITY -#define MaximumPriority HPI_MAXIMUM_PRIORITY -#define NormalPriority HPI_NORMAL_PRIORITY - -#define SYS_THREAD_SUSPENDED HPI_THREAD_SUSPENDED -#define SYS_THREAD_INTERRUPTED HPI_THREAD_INTERRUPTED - -#define PAGE_ALIGNMENT HPI_PAGE_ALIGNMENT - -#define SYS_TIMEOUT_INFINITY HPI_TIMEOUT_INFINITY - -#define SYS_FILETYPE_REGULAR HPI_FILETYPE_REGULAR -#define SYS_FILETYPE_DIRECTORY HPI_FILETYPE_DIRECTORY -#define SYS_FILETYPE_OTHER HPI_FILETYPE_OTHER - -#endif /* !_JAVASOFT_SYS_API_H_ */ diff --git a/src/share/javavm/include/typedefs.h b/src/share/javavm/include/typedefs.h deleted file mode 100644 index 6c35063bca7a2764a2ffdb8874120b382094f311..0000000000000000000000000000000000000000 --- a/src/share/javavm/include/typedefs.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 1994-2002 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. - */ - -#ifndef _JAVASOFT_TYPEDEFS_H_ -#define _JAVASOFT_TYPEDEFS_H_ - -#include "typedefs_md.h" /* for int64_t */ - -/* - * Macros to deal with the JavaVM's stack alignment. Many machines - * require doublewords to be double aligned. This union is used by - * code in math.h as a more portable way do alingnment on machines - * that require it. This union and the macros that use it came from - * Netscape. - */ - -#ifdef HAVE_ALIGNED_LONGLONGS -#define GET_INT64(_t,_addr) \ - ((((int32_t*) &(_t))[0] = ((int32_t*)(_addr))[0]), \ - (((int32_t*) &(_t))[1] = ((int32_t*)(_addr))[1]), \ - (_t).j ) -#define SET_INT64(_t, _addr, _v) \ - ( (_t).j = (_v), \ - ((int32_t*)(_addr))[0] = ((int32_t*) &(_t))[0], \ - ((int32_t*)(_addr))[1] = ((int32_t*) &(_t))[1] ) -#else -#define GET_INT64(_t,_addr) (*(int64_t*)(_addr)) -#define SET_INT64(_t, _addr, _v) (*(int64_t*)(_addr) = (_v)) -#endif - -/* If double's must be aligned on doubleword boundaries then define this */ -#ifdef HAVE_ALIGNED_DOUBLES -#define GET_DOUBLE(_t,_addr) \ - ((((int32_t*) &(_t))[0] = ((int32_t*)(_addr))[0]), \ - (((int32_t*) &(_t))[1] = ((int32_t*)(_addr))[1]), \ - (_t).d ) -#define SET_DOUBLE(_t, _addr, _v) \ - ( (_t).d = (_v), \ - ((int32_t*)(_addr))[0] = ((int32_t*) &(_t))[0], \ - ((int32_t*)(_addr))[1] = ((int32_t*) &(_t))[1] ) -#else -#define GET_DOUBLE(_t,_addr) (*(jdouble*)(_addr)) -#define SET_DOUBLE(_t, _addr, _v) (*(jdouble*)(_addr) = (_v)) -#endif - -/* If pointers are 64bits then define this */ -#ifdef HAVE_64BIT_POINTERS -#define GET_HANDLE(_t,_addr) \ - ( ((int32_t*) &(_t))[0] = ((int32_t*)(_addr))[0]), \ - ((int32_t*) &(_t))[1] = ((int32_t*)(_addr))[1]), \ - (void*) (_t).l ) -#define SET_HANDLE(_t, _addr, _v) \ - ( *(void**) &((_t).l) = (_v), \ - ((int32_t*)(_addr))[0] = ((int32_t*) &(_t))[0], \ - ((int32_t*)(_addr))[1] = ((int32_t*) &(_t))[1] ) -#else -#define GET_HANDLE(_t,_addr) (*(JHandle*)(_addr)) -#define SET_HANDLE(_t, _addr, _v) (*(JHandle*)(_addr) = (_v)) -#endif - - -/* - * Printf-style formatters for fixed- and variable-width types as pointers and - * integers. - * - * Each platform-specific definitions file "typedefs_md.h" - * must define the macro FORMAT64_MODIFIER, which is the modifier for '%x' or - * '%d' formats to indicate a 64-bit quantity; commonly "l" (in LP64) or "ll" - * (in ILP32). - */ - -/* Format 32-bit quantities. */ -#define INT32_FORMAT "%d" -#define UINT32_FORMAT "%u" -#define PTR32_FORMAT "0x%08x" - -/* Format 64-bit quantities. */ -#define INT64_FORMAT "%" FORMAT64_MODIFIER "d" -#define UINT64_FORMAT "%" FORMAT64_MODIFIER "u" -#define PTR64_FORMAT "0x%016" FORMAT64_MODIFIER "x" - -/* Format pointers and size_t (or size_t-like integer types) which change size - * between 32- and 64-bit. - */ -#if defined(_LP64) || defined(_WIN64) -#define PTR_FORMAT PTR64_FORMAT -#define SIZE_FORMAT UINT64_FORMAT -#define SSIZE_FORMAT INT64_FORMAT -#else -#define PTR_FORMAT PTR32_FORMAT -#define SIZE_FORMAT UINT32_FORMAT -#define SSIZE_FORMAT INT32_FORMAT -#endif - -#define INTPTR_FORMAT PTR_FORMAT - - -#endif /* !_JAVASOFT_TYPEDEFS_H_ */ diff --git a/src/share/native/common/check_code.c b/src/share/native/common/check_code.c index d06b2eddd6257fc58ceec55b7117a1942f4fcbd4..7e1613255dcf48924fd92b93447469ebcf049644 100644 --- a/src/share/native/common/check_code.c +++ b/src/share/native/common/check_code.c @@ -1,5 +1,5 @@ /* - * Copyright 1994-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1994-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 @@ -87,10 +87,7 @@ #include "jni.h" #include "jvm.h" -#include "typedefs.h" - -#include "opcodes.h" -#include "opcodes.length" +#include "classfile_constants.h" #include "opcodes.in_out" #define MAX_ARRAY_DIMENSIONS 255 @@ -161,8 +158,8 @@ typedef unsigned int *bitvector; #define NULL_FULLINFO MAKE_FULLINFO(ITEM_Object, 0, 0) -/* opc_invokespecial calls to need to be treated special */ -#define opc_invokeinit 0x100 +/* JVM_OPC_invokespecial calls to need to be treated special */ +#define JVM_OPC_invokeinit 0x100 /* A hash mechanism used by the verifier. * Maps class names to unique 16 bit integers. @@ -301,7 +298,7 @@ struct mask_type { typedef unsigned short flag_type; struct instruction_data_type { - opcode_type opcode; /* may turn into "canonical" opcode */ + int opcode; /* may turn into "canonical" opcode */ unsigned changed:1; /* has it changed */ unsigned protected:1; /* must accessor be a subclass of "this" */ union { @@ -345,7 +342,7 @@ static void free_all_code(int num_methods, int* lengths, unsigned char** code); static void verify_field(context_type *context, jclass cb, int index); static void verify_opcode_operands (context_type *, unsigned int inumber, int offset); -static void set_protected(context_type *, unsigned int inumber, int key, opcode_type); +static void set_protected(context_type *, unsigned int inumber, int key, int); static jboolean is_superclass(context_type *, fullinfo_type); static void initialize_exception_table(context_type *); @@ -1084,7 +1081,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) int *code_data = context->code_data; int mi = context->method_index; unsigned char *code = context->code; - opcode_type opcode = this_idata->opcode; + int opcode = this_idata->opcode; int var; /* @@ -1096,17 +1093,17 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) switch (opcode) { - case opc_jsr: + case JVM_OPC_jsr: /* instruction of ret statement */ this_idata->operand2.i = UNKNOWN_RET_INSTRUCTION; /* FALLTHROUGH */ - case opc_ifeq: case opc_ifne: case opc_iflt: - case opc_ifge: case opc_ifgt: case opc_ifle: - case opc_ifnull: case opc_ifnonnull: - case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt: - case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple: - case opc_if_acmpeq: case opc_if_acmpne: - case opc_goto: { + case JVM_OPC_ifeq: case JVM_OPC_ifne: case JVM_OPC_iflt: + case JVM_OPC_ifge: case JVM_OPC_ifgt: case JVM_OPC_ifle: + case JVM_OPC_ifnull: case JVM_OPC_ifnonnull: + case JVM_OPC_if_icmpeq: case JVM_OPC_if_icmpne: case JVM_OPC_if_icmplt: + case JVM_OPC_if_icmpge: case JVM_OPC_if_icmpgt: case JVM_OPC_if_icmple: + case JVM_OPC_if_acmpeq: case JVM_OPC_if_acmpne: + case JVM_OPC_goto: { /* Set the ->operand to be the instruction number of the target. */ int jump = (((signed char)(code[offset+1])) << 8) + code[offset+2]; int target = offset + jump; @@ -1116,11 +1113,11 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; } - case opc_jsr_w: + case JVM_OPC_jsr_w: /* instruction of ret statement */ this_idata->operand2.i = UNKNOWN_RET_INSTRUCTION; /* FALLTHROUGH */ - case opc_goto_w: { + case JVM_OPC_goto_w: { /* Set the ->operand to be the instruction number of the target. */ int jump = (((signed char)(code[offset+1])) << 24) + (code[offset+2] << 16) + (code[offset+3] << 8) + @@ -1132,8 +1129,8 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; } - case opc_tableswitch: - case opc_lookupswitch: { + case JVM_OPC_tableswitch: + case JVM_OPC_lookupswitch: { /* Set the ->operand to be a table of possible instruction targets. */ int *lpc = (int *) UCALIGN(code + offset + 1); int *lptr; @@ -1147,7 +1144,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) CCerror(context, "Non zero padding bytes in switch"); } } - if (opcode == opc_tableswitch) { + if (opcode == JVM_OPC_tableswitch) { keys = ntohl(lpc[2]) - ntohl(lpc[1]) + 1; delta = 1; } else { @@ -1169,7 +1166,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) for (k = keys, lptr = &lpc[3]; --k >= 0; lptr += delta) { int target = offset + ntohl(lptr[0]); if (!isLegalTarget(context, target)) - CCerror(context, "Illegal branch in opc_tableswitch"); + CCerror(context, "Illegal branch in tableswitch"); saved_operand[k + 1] = code_data[target]; } saved_operand[0] = keys + 1; /* number of successors */ @@ -1177,7 +1174,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; } - case opc_ldc: { + case JVM_OPC_ldc: { /* Make sure the constant pool item is the right type. */ int key = code[offset + 1]; int types = (1 << JVM_CONSTANT_Integer) | (1 << JVM_CONSTANT_Float) | @@ -1190,7 +1187,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; } - case opc_ldc_w: { + case JVM_OPC_ldc_w: { /* Make sure the constant pool item is the right type. */ int key = (code[offset + 1] << 8) + code[offset + 2]; int types = (1 << JVM_CONSTANT_Integer) | (1 << JVM_CONSTANT_Float) | @@ -1203,7 +1200,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; } - case opc_ldc2_w: { + case JVM_OPC_ldc2_w: { /* Make sure the constant pool item is the right type. */ int key = (code[offset + 1] << 8) + code[offset + 2]; int types = (1 << JVM_CONSTANT_Double) | (1 << JVM_CONSTANT_Long); @@ -1212,28 +1209,28 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; } - case opc_getfield: case opc_putfield: - case opc_getstatic: case opc_putstatic: { + case JVM_OPC_getfield: case JVM_OPC_putfield: + case JVM_OPC_getstatic: case JVM_OPC_putstatic: { /* Make sure the constant pool item is the right type. */ int key = (code[offset + 1] << 8) + code[offset + 2]; this_idata->operand.i = key; verify_constant_pool_type(context, key, 1 << JVM_CONSTANT_Fieldref); - if (opcode == opc_getfield || opcode == opc_putfield) + if (opcode == JVM_OPC_getfield || opcode == JVM_OPC_putfield) set_protected(context, inumber, key, opcode); break; } - case opc_invokevirtual: - case opc_invokespecial: - case opc_invokestatic: - case opc_invokeinterface: { + case JVM_OPC_invokevirtual: + case JVM_OPC_invokespecial: + case JVM_OPC_invokestatic: + case JVM_OPC_invokeinterface: { /* Make sure the constant pool item is the right type. */ int key = (code[offset + 1] << 8) + code[offset + 2]; const char *methodname; jclass cb = context->class; fullinfo_type clazz_info; int is_constructor, is_internal; - int kind = (opcode == opc_invokeinterface + int kind = (opcode == JVM_OPC_invokeinterface ? 1 << JVM_CONSTANT_InterfaceMethodref : 1 << JVM_CONSTANT_Methodref); /* Make sure the constant pool item is the right type. */ @@ -1249,16 +1246,16 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) this_idata->operand.i = key; this_idata->operand2.fi = clazz_info; if (is_constructor) { - if (opcode != opc_invokespecial) { + if (opcode != JVM_OPC_invokespecial) { CCerror(context, "Must call initializers using invokespecial"); } - this_idata->opcode = opc_invokeinit; + this_idata->opcode = JVM_OPC_invokeinit; } else { if (is_internal) { CCerror(context, "Illegal call to internal method"); } - if (opcode == opc_invokespecial + if (opcode == JVM_OPC_invokespecial && clazz_info != context->currentclass_info && clazz_info != context->superclass_info) { int not_found = 1; @@ -1290,7 +1287,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) } } } - if (opcode == opc_invokeinterface) { + if (opcode == JVM_OPC_invokeinterface) { unsigned int args1; unsigned int args2; const char *signature = @@ -1300,25 +1297,25 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) args2 = code[offset + 3]; if (args1 != args2) { CCerror(context, - "Inconsistent args_size for opc_invokeinterface"); + "Inconsistent args_size for invokeinterface"); } if (code[offset + 4] != 0) { CCerror(context, "Fourth operand byte of invokeinterface must be zero"); } pop_and_free(context); - } else if (opcode == opc_invokevirtual - || opcode == opc_invokespecial) + } else if (opcode == JVM_OPC_invokevirtual + || opcode == JVM_OPC_invokespecial) set_protected(context, inumber, key, opcode); break; } - case opc_instanceof: - case opc_checkcast: - case opc_new: - case opc_anewarray: - case opc_multianewarray: { + case JVM_OPC_instanceof: + case JVM_OPC_checkcast: + case JVM_OPC_new: + case JVM_OPC_anewarray: + case JVM_OPC_multianewarray: { /* Make sure the constant pool item is a class */ int key = (code[offset + 1] << 8) + code[offset + 2]; fullinfo_type target; @@ -1327,14 +1324,14 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) if (GET_ITEM_TYPE(target) == ITEM_Bogus) CCerror(context, "Illegal type"); switch(opcode) { - case opc_anewarray: + case JVM_OPC_anewarray: if ((GET_INDIRECTION(target)) >= MAX_ARRAY_DIMENSIONS) CCerror(context, "Array with too many dimensions"); this_idata->operand.fi = MAKE_FULLINFO(GET_ITEM_TYPE(target), GET_INDIRECTION(target) + 1, GET_EXTRA_INFO(target)); break; - case opc_new: + case JVM_OPC_new: if (WITH_ZERO_EXTRA_INFO(target) != MAKE_FULLINFO(ITEM_Object, 0, 0)) CCerror(context, "Illegal creation of multi-dimensional array"); @@ -1343,10 +1340,10 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) this_idata->operand.fi = MAKE_FULLINFO(ITEM_NewObject, 0, inumber); this_idata->operand2.fi = target; break; - case opc_multianewarray: + case JVM_OPC_multianewarray: this_idata->operand.fi = target; this_idata->operand2.i = code[offset + 3]; - if ( (this_idata->operand2.i > GET_INDIRECTION(target)) + if ( (this_idata->operand2.i > (int)GET_INDIRECTION(target)) || (this_idata->operand2.i == 0)) CCerror(context, "Illegal dimension argument"); break; @@ -1356,8 +1353,8 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; } - case opc_newarray: { - /* Cache the result of the opc_newarray into the operand slot */ + case JVM_OPC_newarray: { + /* Cache the result of the JVM_OPC_newarray into the operand slot */ fullinfo_type full_info; switch (code[offset + 1]) { case JVM_T_INT: @@ -1376,78 +1373,78 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) full_info = MAKE_FULLINFO(ITEM_Short, 1, 0); break; default: full_info = 0; /* Keep lint happy */ - CCerror(context, "Bad type passed to opc_newarray"); + CCerror(context, "Bad type passed to newarray"); } this_idata->operand.fi = full_info; break; } /* Fudge iload_x, aload_x, etc to look like their generic cousin. */ - case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3: - this_idata->opcode = opc_iload; - var = opcode - opc_iload_0; + case JVM_OPC_iload_0: case JVM_OPC_iload_1: case JVM_OPC_iload_2: case JVM_OPC_iload_3: + this_idata->opcode = JVM_OPC_iload; + var = opcode - JVM_OPC_iload_0; goto check_local_variable; - case opc_fload_0: case opc_fload_1: case opc_fload_2: case opc_fload_3: - this_idata->opcode = opc_fload; - var = opcode - opc_fload_0; + case JVM_OPC_fload_0: case JVM_OPC_fload_1: case JVM_OPC_fload_2: case JVM_OPC_fload_3: + this_idata->opcode = JVM_OPC_fload; + var = opcode - JVM_OPC_fload_0; goto check_local_variable; - case opc_aload_0: case opc_aload_1: case opc_aload_2: case opc_aload_3: - this_idata->opcode = opc_aload; - var = opcode - opc_aload_0; + case JVM_OPC_aload_0: case JVM_OPC_aload_1: case JVM_OPC_aload_2: case JVM_OPC_aload_3: + this_idata->opcode = JVM_OPC_aload; + var = opcode - JVM_OPC_aload_0; goto check_local_variable; - case opc_lload_0: case opc_lload_1: case opc_lload_2: case opc_lload_3: - this_idata->opcode = opc_lload; - var = opcode - opc_lload_0; + case JVM_OPC_lload_0: case JVM_OPC_lload_1: case JVM_OPC_lload_2: case JVM_OPC_lload_3: + this_idata->opcode = JVM_OPC_lload; + var = opcode - JVM_OPC_lload_0; goto check_local_variable2; - case opc_dload_0: case opc_dload_1: case opc_dload_2: case opc_dload_3: - this_idata->opcode = opc_dload; - var = opcode - opc_dload_0; + case JVM_OPC_dload_0: case JVM_OPC_dload_1: case JVM_OPC_dload_2: case JVM_OPC_dload_3: + this_idata->opcode = JVM_OPC_dload; + var = opcode - JVM_OPC_dload_0; goto check_local_variable2; - case opc_istore_0: case opc_istore_1: case opc_istore_2: case opc_istore_3: - this_idata->opcode = opc_istore; - var = opcode - opc_istore_0; + case JVM_OPC_istore_0: case JVM_OPC_istore_1: case JVM_OPC_istore_2: case JVM_OPC_istore_3: + this_idata->opcode = JVM_OPC_istore; + var = opcode - JVM_OPC_istore_0; goto check_local_variable; - case opc_fstore_0: case opc_fstore_1: case opc_fstore_2: case opc_fstore_3: - this_idata->opcode = opc_fstore; - var = opcode - opc_fstore_0; + case JVM_OPC_fstore_0: case JVM_OPC_fstore_1: case JVM_OPC_fstore_2: case JVM_OPC_fstore_3: + this_idata->opcode = JVM_OPC_fstore; + var = opcode - JVM_OPC_fstore_0; goto check_local_variable; - case opc_astore_0: case opc_astore_1: case opc_astore_2: case opc_astore_3: - this_idata->opcode = opc_astore; - var = opcode - opc_astore_0; + case JVM_OPC_astore_0: case JVM_OPC_astore_1: case JVM_OPC_astore_2: case JVM_OPC_astore_3: + this_idata->opcode = JVM_OPC_astore; + var = opcode - JVM_OPC_astore_0; goto check_local_variable; - case opc_lstore_0: case opc_lstore_1: case opc_lstore_2: case opc_lstore_3: - this_idata->opcode = opc_lstore; - var = opcode - opc_lstore_0; + case JVM_OPC_lstore_0: case JVM_OPC_lstore_1: case JVM_OPC_lstore_2: case JVM_OPC_lstore_3: + this_idata->opcode = JVM_OPC_lstore; + var = opcode - JVM_OPC_lstore_0; goto check_local_variable2; - case opc_dstore_0: case opc_dstore_1: case opc_dstore_2: case opc_dstore_3: - this_idata->opcode = opc_dstore; - var = opcode - opc_dstore_0; + case JVM_OPC_dstore_0: case JVM_OPC_dstore_1: case JVM_OPC_dstore_2: case JVM_OPC_dstore_3: + this_idata->opcode = JVM_OPC_dstore; + var = opcode - JVM_OPC_dstore_0; goto check_local_variable2; - case opc_wide: + case JVM_OPC_wide: this_idata->opcode = code[offset + 1]; var = (code[offset + 2] << 8) + code[offset + 3]; switch(this_idata->opcode) { - case opc_lload: case opc_dload: - case opc_lstore: case opc_dstore: + case JVM_OPC_lload: case JVM_OPC_dload: + case JVM_OPC_lstore: case JVM_OPC_dstore: goto check_local_variable2; default: goto check_local_variable; } - case opc_iinc: /* the increment amount doesn't matter */ - case opc_ret: - case opc_aload: case opc_iload: case opc_fload: - case opc_astore: case opc_istore: case opc_fstore: + case JVM_OPC_iinc: /* the increment amount doesn't matter */ + case JVM_OPC_ret: + case JVM_OPC_aload: case JVM_OPC_iload: case JVM_OPC_fload: + case JVM_OPC_astore: case JVM_OPC_istore: case JVM_OPC_fstore: var = code[offset + 1]; check_local_variable: /* Make sure that the variable number isn't illegal. */ @@ -1456,7 +1453,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) CCerror(context, "Illegal local variable number"); break; - case opc_lload: case opc_dload: case opc_lstore: case opc_dstore: + case JVM_OPC_lload: case JVM_OPC_dload: case JVM_OPC_lstore: case JVM_OPC_dstore: var = code[offset + 1]; check_local_variable2: /* Make sure that the variable number isn't illegal. */ @@ -1466,7 +1463,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) break; default: - if (opcode >= opc_breakpoint) + if (opcode > JVM_OPC_MAX) CCerror(context, "Quick instructions shouldn't appear yet."); break; } /* of switch */ @@ -1474,11 +1471,11 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) static void -set_protected(context_type *context, unsigned int inumber, int key, opcode_type opcode) +set_protected(context_type *context, unsigned int inumber, int key, int opcode) { JNIEnv *env = context->env; fullinfo_type clazz_info; - if (opcode != opc_invokevirtual && opcode != opc_invokespecial) { + if (opcode != JVM_OPC_invokevirtual && opcode != JVM_OPC_invokespecial) { clazz_info = cp_index_to_class_fullinfo(context, key, JVM_CONSTANT_Fieldref); } else { @@ -1497,7 +1494,7 @@ set_protected(context_type *context, unsigned int inumber, int key, opcode_type calledClass = (*env)->NewLocalRef(env, calledClass); do { jclass tmp_cb; - if (opcode != opc_invokevirtual && opcode != opc_invokespecial) { + if (opcode != JVM_OPC_invokevirtual && opcode != JVM_OPC_invokespecial) { access = JVM_GetCPFieldModifiers (env, context->class, key, calledClass); } else { @@ -1607,9 +1604,10 @@ initialize_exception_table(context_type *context) */ static int instruction_length(unsigned char *iptr, unsigned char *end) { + static unsigned char opcode_length[] = JVM_OPCODE_LENGTH_INITIALIZER; int instruction = *iptr; switch (instruction) { - case opc_tableswitch: { + case JVM_OPC_tableswitch: { int *lpc = (int *)UCALIGN(iptr + 1); int index; if (lpc + 2 >= (int *)end) { @@ -1623,7 +1621,7 @@ static int instruction_length(unsigned char *iptr, unsigned char *end) } } - case opc_lookupswitch: { + case JVM_OPC_lookupswitch: { int *lpc = (int *) UCALIGN(iptr + 1); int npairs; if (lpc + 1 >= (int *)end) @@ -1638,18 +1636,18 @@ static int instruction_length(unsigned char *iptr, unsigned char *end) return (unsigned char *)(&lpc[2 * (npairs + 1)]) - iptr; } - case opc_wide: + case JVM_OPC_wide: if (iptr + 1 >= end) return -1; /* do not read pass the end */ switch(iptr[1]) { - case opc_ret: - case opc_iload: case opc_istore: - case opc_fload: case opc_fstore: - case opc_aload: case opc_astore: - case opc_lload: case opc_lstore: - case opc_dload: case opc_dstore: + case JVM_OPC_ret: + case JVM_OPC_iload: case JVM_OPC_istore: + case JVM_OPC_fload: case JVM_OPC_fstore: + case JVM_OPC_aload: case JVM_OPC_astore: + case JVM_OPC_lload: case JVM_OPC_lstore: + case JVM_OPC_dload: case JVM_OPC_dstore: return 4; - case opc_iinc: + case JVM_OPC_iinc: return 6; default: return -1; @@ -1767,7 +1765,7 @@ run_dataflow(context_type *context) { jclass cb = context->class; int max_stack_size = JVM_GetMethodIxMaxStack(env, cb, mi); instruction_data_type *idata = context->instruction_data; - int icount = context->instruction_count; + unsigned int icount = context->instruction_count; jboolean work_to_do = JNI_TRUE; unsigned int inumber; @@ -1839,7 +1837,7 @@ check_register_values(context_type *context, unsigned int inumber) { instruction_data_type *idata = context->instruction_data; instruction_data_type *this_idata = &idata[inumber]; - opcode_type opcode = this_idata->opcode; + int opcode = this_idata->opcode; int operand = this_idata->operand.i; int register_count = this_idata->register_info.register_count; fullinfo_type *registers = this_idata->register_info.registers; @@ -1849,17 +1847,17 @@ check_register_values(context_type *context, unsigned int inumber) switch (opcode) { default: return; - case opc_iload: case opc_iinc: + case JVM_OPC_iload: case JVM_OPC_iinc: type = ITEM_Integer; break; - case opc_fload: + case JVM_OPC_fload: type = ITEM_Float; break; - case opc_aload: + case JVM_OPC_aload: type = ITEM_Object; break; - case opc_ret: + case JVM_OPC_ret: type = ITEM_ReturnAddress; break; - case opc_lload: + case JVM_OPC_lload: type = ITEM_Long; double_word = JNI_TRUE; break; - case opc_dload: + case JVM_OPC_dload: type = ITEM_Double; double_word = JNI_TRUE; break; } if (!double_word) { @@ -1871,7 +1869,7 @@ check_register_values(context_type *context, unsigned int inumber) } reg = registers[operand]; - if (WITH_ZERO_EXTRA_INFO(reg) == MAKE_FULLINFO(type, 0, 0)) { + if (WITH_ZERO_EXTRA_INFO(reg) == (unsigned)MAKE_FULLINFO(type, 0, 0)) { /* the register is obviously of the given type */ return; } else if (GET_INDIRECTION(reg) > 0 && type == ITEM_Object) { @@ -1882,7 +1880,7 @@ check_register_values(context_type *context, unsigned int inumber) operand); /* alternatively (GET_ITEM_TYPE(reg) == ITEM_ReturnAddress) - && (opcode == opc_iload) + && (opcode == JVM_OPC_iload) && (type == ITEM_Object || type == ITEM_Integer) but this never occurs */ @@ -1902,8 +1900,8 @@ check_register_values(context_type *context, unsigned int inumber) "Accessing value from uninitialized register pair %d/%d", operand, operand+1); } else { - if ((registers[operand] == MAKE_FULLINFO(type, 0, 0)) && - (registers[operand + 1] == MAKE_FULLINFO(type + 1, 0, 0))) { + if ((registers[operand] == (unsigned)MAKE_FULLINFO(type, 0, 0)) && + (registers[operand + 1] == (unsigned)MAKE_FULLINFO(type + 1, 0, 0))) { return; } else { CCerror(context, "Register pair %d/%d contains wrong type", @@ -1922,16 +1920,16 @@ check_flags(context_type *context, unsigned int inumber) { instruction_data_type *idata = context->instruction_data; instruction_data_type *this_idata = &idata[inumber]; - opcode_type opcode = this_idata->opcode; + int opcode = this_idata->opcode; switch (opcode) { - case opc_return: + case JVM_OPC_return: /* We need a constructor, but we aren't guaranteed it's called */ if ((this_idata->or_flags & FLAG_NEED_CONSTRUCTOR) && !(this_idata->and_flags & FLAG_CONSTRUCTED)) CCerror(context, "Constructor must call super() or this()"); /* fall through */ - case opc_ireturn: case opc_lreturn: - case opc_freturn: case opc_dreturn: case opc_areturn: + case JVM_OPC_ireturn: case JVM_OPC_lreturn: + case JVM_OPC_freturn: case JVM_OPC_dreturn: case JVM_OPC_areturn: if (this_idata->or_flags & FLAG_NO_RETURN) /* This method cannot exit normally */ CCerror(context, "Cannot return normally"); @@ -1950,7 +1948,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac { instruction_data_type *idata = context->instruction_data; instruction_data_type *this_idata = &idata[inumber]; - opcode_type opcode = this_idata->opcode; + int opcode = this_idata->opcode; stack_item_type *stack = this_idata->stack_info.stack; int stack_size = this_idata->stack_info.stack_size; char *stack_operands, *p; @@ -1958,7 +1956,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac fullinfo_type stack_extra_info_buffer[256]; /* save info popped off stack */ fullinfo_type *stack_extra_info = &stack_extra_info_buffer[256]; fullinfo_type full_info; /* only used in case of invoke instructions */ - fullinfo_type put_full_info; /* only used in case opc_putstatic and opc_putfield */ + fullinfo_type put_full_info; /* only used in case JVM_OPC_putstatic and JVM_OPC_putfield */ switch(opcode) { default: @@ -1966,7 +1964,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac stack_operands = opcode_in_out[opcode][0]; break; - case opc_putstatic: case opc_putfield: { + case JVM_OPC_putstatic: case JVM_OPC_putfield: { /* The top thing on the stack depends on the signature of * the object. */ int operand = this_idata->operand.i; @@ -1981,7 +1979,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac print_formatted_fieldname(context, operand); } #endif - if (opcode == opc_putfield) + if (opcode == JVM_OPC_putfield) *ip++ = 'A'; /* object for putfield */ *ip++ = signature_to_fieldtype(context, &signature, &put_full_info); *ip = '\0'; @@ -1990,9 +1988,9 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac break; } - case opc_invokevirtual: case opc_invokespecial: - case opc_invokeinit: /* invokespecial call to */ - case opc_invokestatic: case opc_invokeinterface: { + case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial: + case JVM_OPC_invokeinit: /* invokespecial call to */ + case JVM_OPC_invokestatic: case JVM_OPC_invokeinterface: { /* The top stuff on the stack depends on the method signature */ int operand = this_idata->operand.i; const char *signature = @@ -2007,9 +2005,9 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac print_formatted_methodname(context, operand); } #endif - if (opcode != opc_invokestatic) + if (opcode != JVM_OPC_invokestatic) /* First, push the object */ - *ip++ = (opcode == opc_invokeinit ? '@' : 'A'); + *ip++ = (opcode == JVM_OPC_invokeinit ? '@' : 'A'); for (p = signature + 1; *p != JVM_SIGNATURE_ENDFUNC; ) { *ip++ = signature_to_fieldtype(context, &p, &full_info); if (ip >= buffer + sizeof(buffer) - 1) @@ -2022,7 +2020,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac break; } - case opc_multianewarray: { + case JVM_OPC_multianewarray: { /* Count can't be larger than 255. So can't overflow buffer */ int count = this_idata->operand2.i; /* number of ints on stack */ memset(buffer, 'I', count); @@ -2062,19 +2060,19 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac * one of the special cases */ if ( (WITH_ZERO_EXTRA_INFO(top_type) == MAKE_FULLINFO(ITEM_ReturnAddress, 0, 0)) - && (opcode == opc_astore)) + && (opcode == JVM_OPC_astore)) break; if ( (GET_ITEM_TYPE(top_type) == ITEM_NewObject || (GET_ITEM_TYPE(top_type) == ITEM_InitObject)) - && ((opcode == opc_astore) || (opcode == opc_aload) - || (opcode == opc_ifnull) || (opcode == opc_ifnonnull))) + && ((opcode == JVM_OPC_astore) || (opcode == JVM_OPC_aload) + || (opcode == JVM_OPC_ifnull) || (opcode == JVM_OPC_ifnonnull))) break; /* The 2nd edition VM of the specification allows field * initializations before the superclass initializer, * if the field is defined within the current class. */ if ( (GET_ITEM_TYPE(top_type) == ITEM_InitObject) - && (opcode == opc_putfield)) { + && (opcode == JVM_OPC_putfield)) { int operand = this_idata->operand.i; int access_bits = JVM_GetCPFieldModifiers(context->env, context->class, @@ -2231,7 +2229,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac */ switch (opcode) { default: break; - case opc_aastore: { /* array index object */ + case JVM_OPC_aastore: { /* array index object */ fullinfo_type array_type = stack_extra_info[0]; fullinfo_type object_type = stack_extra_info[2]; fullinfo_type target_type = decrement_indirection(array_type); @@ -2246,12 +2244,12 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac break; } - case opc_putfield: - case opc_getfield: - case opc_putstatic: { + case JVM_OPC_putfield: + case JVM_OPC_getfield: + case JVM_OPC_putstatic: { int operand = this_idata->operand.i; fullinfo_type stack_object = stack_extra_info[0]; - if (opcode == opc_putfield || opcode == opc_getfield) { + if (opcode == JVM_OPC_putfield || opcode == JVM_OPC_getfield) { if (!isAssignableTo (context, stack_object, @@ -2266,8 +2264,8 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac CCerror(context, "Bad access to protected data"); } } - if (opcode == opc_putfield || opcode == opc_putstatic) { - int item = (opcode == opc_putfield ? 1 : 0); + if (opcode == JVM_OPC_putfield || opcode == JVM_OPC_putstatic) { + int item = (opcode == JVM_OPC_putfield ? 1 : 0); if (!isAssignableTo(context, stack_extra_info[item], put_full_info)) { CCerror(context, "Bad type in putfield/putstatic"); @@ -2276,23 +2274,23 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac break; } - case opc_athrow: + case JVM_OPC_athrow: if (!isAssignableTo(context, stack_extra_info[0], context->throwable_info)) { CCerror(context, "Can only throw Throwable objects"); } break; - case opc_aaload: { /* array index */ + case JVM_OPC_aaload: { /* array index */ /* We need to pass the information to the stack updater */ fullinfo_type array_type = stack_extra_info[0]; context->swap_table[0] = decrement_indirection(array_type); break; } - case opc_invokevirtual: case opc_invokespecial: - case opc_invokeinit: - case opc_invokeinterface: case opc_invokestatic: { + case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial: + case JVM_OPC_invokeinit: + case JVM_OPC_invokeinterface: case JVM_OPC_invokestatic: { int operand = this_idata->operand.i; const char *signature = JVM_GetCPMethodSignatureUTF(context->env, @@ -2301,15 +2299,15 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac int item; const char *p; check_and_push(context, signature, VM_STRING_UTF); - if (opcode == opc_invokestatic) { + if (opcode == JVM_OPC_invokestatic) { item = 0; - } else if (opcode == opc_invokeinit) { + } else if (opcode == JVM_OPC_invokeinit) { fullinfo_type init_type = this_idata->operand2.fi; fullinfo_type object_type = stack_extra_info[0]; context->swap_table[0] = object_type; /* save value */ if (GET_ITEM_TYPE(stack_extra_info[0]) == ITEM_NewObject) { /* We better be calling the appropriate init. Find the - * inumber of the "opc_new" instruction", and figure + * inumber of the "JVM_OPC_new" instruction", and figure * out what the type really is. */ unsigned int new_inumber = GET_EXTRA_INFO(stack_extra_info[0]); @@ -2341,7 +2339,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac CCerror(context, "Incompatible object argument for function call"); } - if (opcode == opc_invokespecial + if (opcode == JVM_OPC_invokespecial && !isAssignableTo(context, object_type, context->currentclass_info)) { /* Make sure object argument is assignment compatible to current class */ @@ -2381,13 +2379,13 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac break; } - case opc_return: + case JVM_OPC_return: if (context->return_type != MAKE_FULLINFO(ITEM_Void, 0, 0)) CCerror(context, "Wrong return type in function"); break; - case opc_ireturn: case opc_lreturn: case opc_freturn: - case opc_dreturn: case opc_areturn: { + case JVM_OPC_ireturn: case JVM_OPC_lreturn: case JVM_OPC_freturn: + case JVM_OPC_dreturn: case JVM_OPC_areturn: { fullinfo_type target_type = context->return_type; fullinfo_type object_type = stack_extra_info[0]; if (!isAssignableTo(context, object_type, target_type)) { @@ -2396,7 +2394,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac break; } - case opc_new: { + case JVM_OPC_new: { /* Make sure that nothing on the stack already looks like what * we want to create. I can't image how this could possibly happen * but we should test for it anyway, since if it could happen, the @@ -2433,7 +2431,7 @@ update_registers(context_type *context, unsigned int inumber, { instruction_data_type *idata = context->instruction_data; instruction_data_type *this_idata = &idata[inumber]; - opcode_type opcode = this_idata->opcode; + int opcode = this_idata->opcode; int operand = this_idata->operand.i; int register_count = this_idata->register_info.register_count; fullinfo_type *registers = this_idata->register_info.registers; @@ -2453,11 +2451,11 @@ update_registers(context_type *context, unsigned int inumber, /* Remember, we've already verified the type at the top of the stack. */ switch (opcode) { default: break; - case opc_istore: case opc_fstore: case opc_astore: + case JVM_OPC_istore: case JVM_OPC_fstore: case JVM_OPC_astore: access = ACCESS_SINGLE; goto continue_store; - case opc_lstore: case opc_dstore: + case JVM_OPC_lstore: case JVM_OPC_dstore: access = ACCESS_DOUBLE; goto continue_store; @@ -2484,16 +2482,16 @@ update_registers(context_type *context, unsigned int inumber, break; } - case opc_iload: case opc_fload: case opc_aload: - case opc_iinc: case opc_ret: + case JVM_OPC_iload: case JVM_OPC_fload: case JVM_OPC_aload: + case JVM_OPC_iinc: case JVM_OPC_ret: access = ACCESS_SINGLE; break; - case opc_lload: case opc_dload: + case JVM_OPC_lload: case JVM_OPC_dload: access = ACCESS_DOUBLE; break; - case opc_jsr: case opc_jsr_w: + case JVM_OPC_jsr: case JVM_OPC_jsr_w: for (i = 0; i < new_mask_count; i++) if (new_masks[i].entry == operand) CCerror(context, "Recursive call to jsr entry"); @@ -2501,8 +2499,8 @@ update_registers(context_type *context, unsigned int inumber, new_mask_count++; break; - case opc_invokeinit: - case opc_new: { + case JVM_OPC_invokeinit: + case JVM_OPC_new: { /* For invokeinit, an uninitialized object has been initialized. * For new, all previous occurrences of an uninitialized object * from the same instruction must be made bogus. @@ -2588,7 +2586,7 @@ update_flags(context_type *context, unsigned int inumber, flag_type or_flags = this_idata->or_flags; /* Set the "we've done a constructor" flag */ - if (this_idata->opcode == opc_invokeinit) { + if (this_idata->opcode == JVM_OPC_invokeinit) { fullinfo_type from = context->swap_table[0]; if (from == MAKE_FULLINFO(ITEM_InitObject, 0, 0)) and_flags |= FLAG_CONSTRUCTED; @@ -2611,7 +2609,7 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta { instruction_data_type *idata = context->instruction_data; instruction_data_type *this_idata = &idata[inumber]; - opcode_type opcode = this_idata->opcode; + int opcode = this_idata->opcode; int operand = this_idata->operand.i; int stack_size = new_stack_info->stack_size; @@ -2631,7 +2629,7 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta stack_results = opcode_in_out[opcode][1]; break; - case opc_ldc: case opc_ldc_w: case opc_ldc2_w: { + case JVM_OPC_ldc: case JVM_OPC_ldc_w: case JVM_OPC_ldc2_w: { /* Look to constant pool to determine correct result. */ unsigned char *type_table = context->constant_types; switch (type_table[operand]) { @@ -2661,7 +2659,7 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta break; } - case opc_getstatic: case opc_getfield: { + case JVM_OPC_getstatic: case JVM_OPC_getfield: { /* Look to signature to determine correct result. */ int operand = this_idata->operand.i; const char *signature = JVM_GetCPFieldSignatureUTF(context->env, @@ -2680,9 +2678,9 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta break; } - case opc_invokevirtual: case opc_invokespecial: - case opc_invokeinit: - case opc_invokestatic: case opc_invokeinterface: { + case JVM_OPC_invokevirtual: case JVM_OPC_invokespecial: + case JVM_OPC_invokeinit: + case JVM_OPC_invokestatic: case JVM_OPC_invokeinterface: { /* Look to signature to determine correct result. */ int operand = this_idata->operand.i; const char *signature = JVM_GetCPMethodSignatureUTF(context->env, @@ -2703,28 +2701,28 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta break; } - case opc_aconst_null: + case JVM_OPC_aconst_null: stack_results = opcode_in_out[opcode][1]; full_info = NULL_FULLINFO; /* special NULL */ break; - case opc_new: - case opc_checkcast: - case opc_newarray: - case opc_anewarray: - case opc_multianewarray: + case JVM_OPC_new: + case JVM_OPC_checkcast: + case JVM_OPC_newarray: + case JVM_OPC_anewarray: + case JVM_OPC_multianewarray: stack_results = opcode_in_out[opcode][1]; /* Conveniently, this result type is stored here */ full_info = this_idata->operand.fi; break; - case opc_aaload: + case JVM_OPC_aaload: stack_results = opcode_in_out[opcode][1]; /* pop_stack() saved value for us. */ full_info = context->swap_table[0]; break; - case opc_aload: + case JVM_OPC_aload: stack_results = opcode_in_out[opcode][1]; /* The register hasn't been modified, so we can use its value. */ full_info = this_idata->register_info.registers[operand]; @@ -2772,7 +2770,7 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta stack_size++; } /* outer for loop */ - if (opcode == opc_invokeinit) { + if (opcode == JVM_OPC_invokeinit) { /* If there are any instances of "from" on the stack, we need to * replace it with "to", since calling initializes all versions * of the object, obviously. */ @@ -2807,7 +2805,7 @@ merge_into_successors(context_type *context, unsigned int inumber, { instruction_data_type *idata = context->instruction_data; instruction_data_type *this_idata = &idata[inumber]; - opcode_type opcode = this_idata->opcode; + int opcode = this_idata->opcode; int operand = this_idata->operand.i; struct handler_info_type *handler_info = context->handler_info; int handler_info_length = @@ -2827,35 +2825,35 @@ merge_into_successors(context_type *context, unsigned int inumber, buffer[0] = inumber + 1; break; - case opc_ifeq: case opc_ifne: case opc_ifgt: - case opc_ifge: case opc_iflt: case opc_ifle: - case opc_ifnull: case opc_ifnonnull: - case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpgt: - case opc_if_icmpge: case opc_if_icmplt: case opc_if_icmple: - case opc_if_acmpeq: case opc_if_acmpne: + case JVM_OPC_ifeq: case JVM_OPC_ifne: case JVM_OPC_ifgt: + case JVM_OPC_ifge: case JVM_OPC_iflt: case JVM_OPC_ifle: + case JVM_OPC_ifnull: case JVM_OPC_ifnonnull: + case JVM_OPC_if_icmpeq: case JVM_OPC_if_icmpne: case JVM_OPC_if_icmpgt: + case JVM_OPC_if_icmpge: case JVM_OPC_if_icmplt: case JVM_OPC_if_icmple: + case JVM_OPC_if_acmpeq: case JVM_OPC_if_acmpne: successors_count = 2; buffer[0] = inumber + 1; buffer[1] = operand; break; - case opc_jsr: case opc_jsr_w: + case JVM_OPC_jsr: case JVM_OPC_jsr_w: if (this_idata->operand2.i != UNKNOWN_RET_INSTRUCTION) idata[this_idata->operand2.i].changed = JNI_TRUE; /* FALLTHROUGH */ - case opc_goto: case opc_goto_w: + case JVM_OPC_goto: case JVM_OPC_goto_w: successors_count = 1; buffer[0] = operand; break; - case opc_ireturn: case opc_lreturn: case opc_return: - case opc_freturn: case opc_dreturn: case opc_areturn: - case opc_athrow: + case JVM_OPC_ireturn: case JVM_OPC_lreturn: case JVM_OPC_return: + case JVM_OPC_freturn: case JVM_OPC_dreturn: case JVM_OPC_areturn: + case JVM_OPC_athrow: /* The testing for the returns is handled in pop_stack() */ successors_count = 0; break; - case opc_ret: { + case JVM_OPC_ret: { /* This is slightly slow, but good enough for a seldom used instruction. * The EXTRA_ITEM_INFO of the ITEM_ReturnAddress indicates the * address of the first instruction of the subroutine. We can return @@ -2866,16 +2864,16 @@ merge_into_successors(context_type *context, unsigned int inumber, int called_instruction = GET_EXTRA_INFO(registers[operand]); int i, count, *ptr;; for (i = context->instruction_count, count = 0; --i >= 0; ) { - if (((idata[i].opcode == opc_jsr) || - (idata[i].opcode == opc_jsr_w)) && + if (((idata[i].opcode == JVM_OPC_jsr) || + (idata[i].opcode == JVM_OPC_jsr_w)) && (idata[i].operand.i == called_instruction)) count++; } this_idata->operand2.ip = ptr = NEW(int, count + 1); *ptr++ = count; for (i = context->instruction_count, count = 0; --i >= 0; ) { - if (((idata[i].opcode == opc_jsr) || - (idata[i].opcode == opc_jsr_w)) && + if (((idata[i].opcode == JVM_OPC_jsr) || + (idata[i].opcode == JVM_OPC_jsr_w)) && (idata[i].operand.i == called_instruction)) *ptr++ = i + 1; } @@ -2886,8 +2884,8 @@ merge_into_successors(context_type *context, unsigned int inumber, } - case opc_tableswitch: - case opc_lookupswitch: + case JVM_OPC_tableswitch: + case JVM_OPC_lookupswitch: successors = this_idata->operand.ip; /* use this instead */ successors_count = *successors++; break; @@ -2907,9 +2905,9 @@ merge_into_successors(context_type *context, unsigned int inumber, handler_info = context->handler_info; for (i = handler_info_length; --i >= 0; handler_info++) { - if (handler_info->start <= inumber && handler_info->end > inumber) { + if (handler_info->start <= (int)inumber && handler_info->end > (int)inumber) { int handler = handler_info->handler; - if (opcode != opc_invokeinit) { + if (opcode != JVM_OPC_invokeinit) { merge_into_one_successor(context, inumber, handler, &this_idata->register_info, /* old */ &handler_info->stack_info, @@ -2984,9 +2982,9 @@ merge_into_one_successor(context_type *context, * ret are executed. Thus uninitialized objects can't propagate * into or out of a subroutine. */ - if (idata[from_inumber].opcode == opc_ret || - idata[from_inumber].opcode == opc_jsr || - idata[from_inumber].opcode == opc_jsr_w) { + if (idata[from_inumber].opcode == JVM_OPC_ret || + idata[from_inumber].opcode == JVM_OPC_jsr || + idata[from_inumber].opcode == JVM_OPC_jsr_w) { int new_register_count = new_register_info->register_count; fullinfo_type *new_registers = new_register_info->registers; int i; @@ -3036,7 +3034,7 @@ merge_into_one_successor(context_type *context, * that needs to get merged into the new instruction is a joining * of info from the ret instruction with stuff in the jsr instruction */ - if (idata[from_inumber].opcode == opc_ret && !isException) { + if (idata[from_inumber].opcode == JVM_OPC_ret && !isException) { int new_register_count = new_register_info->register_count; fullinfo_type *new_registers = new_register_info->registers; int new_mask_count = new_register_info->mask_count; @@ -3045,7 +3043,7 @@ merge_into_one_successor(context_type *context, int called_instruction = GET_EXTRA_INFO(new_registers[operand]); instruction_data_type *jsr_idata = &idata[to_inumber - 1]; register_info_type *jsr_reginfo = &jsr_idata->register_info; - if (jsr_idata->operand2.i != from_inumber) { + if (jsr_idata->operand2.i != (int)from_inumber) { if (jsr_idata->operand2.i != UNKNOWN_RET_INSTRUCTION) CCerror(context, "Multiple returns to single jsr"); jsr_idata->operand2.i = from_inumber; @@ -3675,7 +3673,7 @@ signature_to_fieldtype(context_type *context, char *buffer = buffer_space; char *finish = strchr(p, JVM_SIGNATURE_ENDCLASS); int length = finish - p; - if (length + 1 > sizeof(buffer_space)) { + if (length + 1 > (int)sizeof(buffer_space)) { buffer = malloc(length + 1); check_and_push(context, buffer, VM_MALLOC_BLK); } diff --git a/src/share/native/common/check_format.c b/src/share/native/common/check_format.c index 26539d133feb6dd3c04581dc214c87e5819b1da5..0b5f42077db3255d79809ed679ec414212604476 100644 --- a/src/share/native/common/check_format.c +++ b/src/share/native/common/check_format.c @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-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 @@ -246,7 +246,7 @@ VerifyClassname(char *name, jboolean allowArrayClass) /* skip over the fieldname. Slashes are okay */ p = skip_over_fieldname(name, JNI_TRUE, length); } - return (p != 0 && p - name == length); + return (p != 0 && p - name == (ptrdiff_t)length); } /* diff --git a/src/share/native/java/net/net_util.c b/src/share/native/java/net/net_util.c index 2559a0edb8c291c8d06b90f48b52d0ac6b9d418b..5634e736a341f26790d72c021a444b180ec5b028 100644 --- a/src/share/native/java/net/net_util.c +++ b/src/share/native/java/net/net_util.c @@ -82,7 +82,7 @@ void init(JNIEnv *env) { } } -jobject +JNIEXPORT jobject JNICALL NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { jobject iaObj; init(env); @@ -159,7 +159,7 @@ NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { return iaObj; } -jint +JNIEXPORT jint JNICALL NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj) { jint family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4? diff --git a/src/share/native/java/net/net_util.h b/src/share/native/java/net/net_util.h index d00a1c0be8130ee62304e5aee93f81cd98c6d5b8..9fded2f9cfcafde9d2b784f499097800ef897bdc 100644 --- a/src/share/native/java/net/net_util.h +++ b/src/share/native/java/net/net_util.h @@ -116,7 +116,7 @@ NET_AllocSockaddr(struct sockaddr **him, int *len); JNIEXPORT int JNICALL NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him, int *len, jboolean v4MappedAddress); -jobject +JNIEXPORT jobject JNICALL NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port); void initLocalAddrTable (); @@ -124,10 +124,10 @@ void initLocalAddrTable (); void NET_SetTrafficClass(struct sockaddr *him, int trafficClass); -jint +JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(struct sockaddr *him); -jint +JNIEXPORT jint JNICALL NET_SockaddrEqualsInetAddress(JNIEnv *env,struct sockaddr *him, jobject iaObj); int diff --git a/src/share/native/java/nio/Bits.c b/src/share/native/java/nio/Bits.c index 0227d6de86b91a5599d7237f8c22b9f2b78ec32e..6c87d37fc2ec866d93aec369b7f6d4475f87e3b2 100644 --- a/src/share/native/java/nio/Bits.c +++ b/src/share/native/java/nio/Bits.c @@ -67,46 +67,6 @@ #define SWAPLONG(x) ((jlong)(((jlong)SWAPINT((jint)(x)) << 32) | \ ((jlong)SWAPINT((jint)((x) >> 32)) & 0xffffffff))) -JNIEXPORT void JNICALL -Java_java_nio_Bits_copyFromByteArray(JNIEnv *env, jobject this, jobject src, - jlong srcPos, jlong dstAddr, jlong length) -{ - jbyte *bytes; - size_t size; - - while (length > 0) { - size = (length > MBYTE ? MBYTE : length); - - GETCRITICAL(bytes, env, src); - memcpy((void *)dstAddr, bytes + srcPos, size); - RELEASECRITICAL(bytes, env, src, JNI_ABORT); - - length -= size; - dstAddr += size; - srcPos += size; - } -} - -JNIEXPORT void JNICALL -Java_java_nio_Bits_copyToByteArray(JNIEnv *env, jobject this, jlong srcAddr, - jobject dst, jlong dstPos, jlong length) -{ - jbyte *bytes; - size_t size; - - while (length > 0) { - size = (length > MBYTE ? MBYTE : length); - - GETCRITICAL(bytes, env, dst); - memcpy(bytes + dstPos, (void *)srcAddr, size); - RELEASECRITICAL(bytes, env, dst, 0); - - length -= size; - srcAddr += size; - dstPos += size; - } -} - JNIEXPORT void JNICALL Java_java_nio_Bits_copyFromShortArray(JNIEnv *env, jobject this, jobject src, jlong srcPos, jlong dstAddr, jlong length) diff --git a/src/share/native/java/util/zip/zip_util.c b/src/share/native/java/util/zip/zip_util.c index 1f6e04a1f7ed36e1c7b961c67291eeba9a9bc888..5d518cf4ced4f75620e790df2da6f72216ae86fb 100644 --- a/src/share/native/java/util/zip/zip_util.c +++ b/src/share/native/java/util/zip/zip_util.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-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 @@ -722,16 +722,22 @@ ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified) } len = zip->len = ZFILE_Lseek(zfd, 0, SEEK_END); - if (len == -1) { - if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0) - *pmsg = errbuf; + if (len <= 0) { + if (len == 0) { /* zip file is empty */ + if (pmsg) { + *pmsg = "zip file is empty"; + } + } else { /* error */ + if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0) + *pmsg = errbuf; + } ZFILE_Close(zfd); freeZip(zip); return NULL; } zip->zfd = zfd; - if (readCEN(zip, -1) <= 0) { + if (readCEN(zip, -1) < 0) { /* An error occurred while trying to read the zip file */ if (pmsg != 0) { /* Set the zip error message */ @@ -947,10 +953,15 @@ jzentry * ZIP_GetEntry(jzfile *zip, char *name, jint ulen) { unsigned int hsh = hash(name); - jint idx = zip->table[hsh % zip->tablelen]; - jzentry *ze; + jint idx; + jzentry *ze = 0; ZIP_Lock(zip); + if (zip->total == 0) { + goto Finally; + } + + idx = zip->table[hsh % zip->tablelen]; /* * This while loop is an optimization where a double lookup @@ -1025,6 +1036,7 @@ ZIP_GetEntry(jzfile *zip, char *name, jint ulen) ulen = 0; } +Finally: ZIP_Unlock(zip); return ze; } diff --git a/src/share/native/sun/nio/ch/genSocketOptionRegistry.c b/src/share/native/sun/nio/ch/genSocketOptionRegistry.c new file mode 100644 index 0000000000000000000000000000000000000000..85088ace882442a3694f0e1e58b72643a799d108 --- /dev/null +++ b/src/share/native/sun/nio/ch/genSocketOptionRegistry.c @@ -0,0 +1,129 @@ +/* + * 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. + */ + +#include +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#endif + +/** + * Generates sun.nio.ch.SocketOptionRegistry, a class that maps Java-level + * socket options to the platform specific level and option. + */ + +static void out(char* s) { + printf("%s\n", s); +} + +static void emit(const char *name, char * family, int level, int optname) { + printf(" map.put(new RegistryKey(%s, %s),", name, family); + printf(" new OptionKey(%d, %d));\n", level, optname); +} + +static void emit_unspec(const char *name, int level, int optname) { + emit(name, "Net.UNSPEC", level, optname); +} + +static void emit_inet(const char *name, int level, int optname) { + emit(name, "StandardProtocolFamily.INET", level, optname); +} + +static void emit_inet6(const char *name, int level, int optname) { + emit(name, "StandardProtocolFamily.INET6", level, optname); +} + +int main(int argc, const char* argv[]) { + out("// AUTOMATICALLY GENERATED FILE - DO NOT EDIT "); + out("package sun.nio.ch; "); + out("import java.net.SocketOption; "); + out("import java.net.StandardSocketOption; "); + out("import java.net.ProtocolFamily; "); + out("import java.net.StandardProtocolFamily; "); + out("import java.util.Map; "); + out("import java.util.HashMap; "); + out("class SocketOptionRegistry { "); + out(" private SocketOptionRegistry() { } "); + out(" private static class RegistryKey { "); + out(" private final SocketOption name; "); + out(" private final ProtocolFamily family; "); + out(" RegistryKey(SocketOption name, ProtocolFamily family) { "); + out(" this.name = name; "); + out(" this.family = family; "); + out(" } "); + out(" public int hashCode() { "); + out(" return name.hashCode() + family.hashCode(); "); + out(" } "); + out(" public boolean equals(Object ob) { "); + out(" if (ob == null) return false; "); + out(" if (!(ob instanceof RegistryKey)) return false; "); + out(" RegistryKey other = (RegistryKey)ob; "); + out(" if (this.name != other.name) return false; "); + out(" if (this.family != other.family) return false; "); + out(" return true; "); + out(" } "); + out(" } "); + out(" private static class LazyInitialization { "); + out(" static final Map options = options(); "); + out(" private static Map options() { "); + out(" Map map = "); + out(" new HashMap(); "); + + emit_unspec("StandardSocketOption.SO_BROADCAST", SOL_SOCKET, SO_BROADCAST); + emit_unspec("StandardSocketOption.SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE); + emit_unspec("StandardSocketOption.SO_LINGER", SOL_SOCKET, SO_LINGER); + emit_unspec("StandardSocketOption.SO_SNDBUF", SOL_SOCKET, SO_SNDBUF); + emit_unspec("StandardSocketOption.SO_RCVBUF", SOL_SOCKET, SO_RCVBUF); + emit_unspec("StandardSocketOption.SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR); + emit_unspec("StandardSocketOption.TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY); + + emit_inet("StandardSocketOption.IP_TOS", IPPROTO_IP, IP_TOS); + emit_inet("StandardSocketOption.IP_MULTICAST_IF", IPPROTO_IP, IP_MULTICAST_IF); + emit_inet("StandardSocketOption.IP_MULTICAST_TTL", IPPROTO_IP, IP_MULTICAST_TTL); + emit_inet("StandardSocketOption.IP_MULTICAST_LOOP", IPPROTO_IP, IP_MULTICAST_LOOP); + +#ifdef AF_INET6 + emit_inet6("StandardSocketOption.IP_MULTICAST_IF", IPPROTO_IPV6, IPV6_MULTICAST_IF); + emit_inet6("StandardSocketOption.IP_MULTICAST_TTL", IPPROTO_IPV6, IPV6_MULTICAST_HOPS); + emit_inet6("StandardSocketOption.IP_MULTICAST_LOOP", IPPROTO_IPV6, IPV6_MULTICAST_LOOP); +#endif + + emit_unspec("ExtendedSocketOption.SO_OOBINLINE", SOL_SOCKET, SO_OOBINLINE); + + out(" return map; "); + out(" } "); + out(" } "); + out(" public static OptionKey findOption(SocketOption name, ProtocolFamily family) { "); + out(" RegistryKey key = new RegistryKey(name, family); "); + out(" return LazyInitialization.options.get(key); "); + out(" } "); + out("} "); + + return 0; +} diff --git a/src/share/sample/nio/multicast/MulticastAddress.java b/src/share/sample/nio/multicast/MulticastAddress.java new file mode 100644 index 0000000000000000000000000000000000000000..e1a3bf3eb90eec98e654ec5a5223b834f27e0908 --- /dev/null +++ b/src/share/sample/nio/multicast/MulticastAddress.java @@ -0,0 +1,127 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Sun Microsystems nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.UnknownHostException; +import java.net.SocketException; + +/** + * Parses and represents a multicast address. + */ + +class MulticastAddress { + private final InetAddress group; + private final int port; + private final NetworkInterface interf; + + private MulticastAddress(InetAddress group, int port, NetworkInterface interf) { + this.group = group; + this.port = port; + this.interf = interf; + } + + InetAddress group() { + return group; + } + + int port() { + return port; + } + + /** + * @return The network interface, may be {@code null} + */ + NetworkInterface interf() { + return interf; + } + + /** + * Parses a string of the form "group:port[@interface]", returning + * a MulticastAddress representing the address + */ + static MulticastAddress parse(String s) { + String[] components = s.split("@"); + if (components.length > 2) + throw new IllegalArgumentException("At most one '@' expected"); + + // get group and port + String target = components[0]; + int len = components[0].length(); + int colon = components[0].lastIndexOf(':'); + if ((colon < 1) || (colon > (len-2))) + throw new IllegalArgumentException("group:port expected"); + String groupString = target.substring(0, colon); + int port = -1; + try { + port = Integer.parseInt(target.substring(colon+1, len)); + } catch (NumberFormatException x) { + throw new IllegalArgumentException(x); + } + + // handle IPv6 literal address + if (groupString.charAt(0) == '[') { + len = groupString.length(); + if (groupString.charAt(len-1) != ']') + throw new IllegalArgumentException("missing ']'"); + groupString = groupString.substring(1,len-1); + if (groupString.length() == 0) + throw new IllegalArgumentException("missing IPv6 address"); + } + + // get group address + InetAddress group = null; + try { + group = InetAddress.getByName(groupString); + } catch (UnknownHostException x) { + throw new IllegalArgumentException(x); + } + if (!group.isMulticastAddress()) { + throw new IllegalArgumentException("'" + group.getHostAddress() + + "' is not multicast address"); + } + + // optional interface + NetworkInterface interf = null; + if (components.length == 2) { + try { + interf = NetworkInterface.getByName(components[1]); + } catch (SocketException x) { + throw new IllegalArgumentException(x); + } + if (interf == null) { + throw new IllegalArgumentException("'" + components[1] + + "' is not valid interface"); + } + } + return new MulticastAddress(group, port, interf); + } +} diff --git a/src/share/sample/nio/multicast/Reader.java b/src/share/sample/nio/multicast/Reader.java new file mode 100644 index 0000000000000000000000000000000000000000..0d1bd8672efd79027847df018e9e5309d23038d8 --- /dev/null +++ b/src/share/sample/nio/multicast/Reader.java @@ -0,0 +1,142 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Sun Microsystems nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.nio.channels.*; +import java.nio.charset.*; +import java.nio.ByteBuffer; +import java.net.*; +import java.io.IOException; +import java.util.*; + +public class Reader { + + static void usage() { + System.err.println("usage: java Reader group:port@interf [-only source...] [-block source...]"); + System.exit(-1); + } + + static void printDatagram(SocketAddress sa, ByteBuffer buf) { + System.out.format("-- datagram from %s --\n", + ((InetSocketAddress)sa).getAddress().getHostAddress()); + System.out.println(Charset.defaultCharset().decode(buf)); + } + + static void parseAddessList(String s, List list) + throws UnknownHostException + { + String[] sources = s.split(","); + for (int i=0; i includeList = new ArrayList(); + List excludeList = new ArrayList(); + int argc = 1; + while (argc < args.length) { + String option = args[argc++]; + if (argc >= args.length) + usage(); + String value = args[argc++]; + if (option.equals("-only")) { + parseAddessList(value, includeList); + continue; + } + if (option.equals("-block")) { + parseAddessList(value, excludeList); + continue; + } + usage(); + } + if (!includeList.isEmpty() && !excludeList.isEmpty()) { + usage(); + } + + // create and bind socket + ProtocolFamily family = StandardProtocolFamily.INET; + if (target.group() instanceof Inet6Address) { + family = StandardProtocolFamily.INET6; + } + DatagramChannel dc = DatagramChannel.open(family) + .setOption(StandardSocketOption.SO_REUSEADDR, true) + .bind(new InetSocketAddress(target.port())); + + if (includeList.isEmpty()) { + // join group and block addresses on the exclude list + MembershipKey key = dc.join(target.group(), target.interf()); + for (InetAddress source: excludeList) { + key.block(source); + } + } else { + // join with source-specific membership for each source + for (InetAddress source: includeList) { + dc.join(target.group(), target.interf(), source); + } + } + + // register socket with Selector + Selector sel = Selector.open(); + dc.configureBlocking(false); + dc.register(sel, SelectionKey.OP_READ); + + // print out each datagram that we receive + ByteBuffer buf = ByteBuffer.allocateDirect(4096); + for (;;) { + int updated = sel.select(); + if (updated > 0) { + Iterator iter = sel.selectedKeys().iterator(); + while (iter.hasNext()) { + SelectionKey sk = iter.next(); + iter.remove(); + + DatagramChannel ch = (DatagramChannel)sk.channel(); + SocketAddress sa = ch.receive(buf); + if (sa != null) { + buf.flip(); + printDatagram(sa, buf); + buf.rewind(); + buf.limit(buf.capacity()); + } + } + } + } + } +} diff --git a/src/share/sample/nio/multicast/Sender.java b/src/share/sample/nio/multicast/Sender.java new file mode 100644 index 0000000000000000000000000000000000000000..d72a24d5aa568e4e6474cfbb73895e7d3dfeb3aa --- /dev/null +++ b/src/share/sample/nio/multicast/Sender.java @@ -0,0 +1,71 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Sun Microsystems nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.nio.channels.*; +import java.nio.charset.Charset; +import java.net.*; +import java.io.IOException; +import java.util.*; + +/** + * Sample multicast sender to send a message in a multicast datagram + * to a given group. + */ + +public class Sender { + + private static void usage() { + System.err.println("usage: java Sender group:port[@interface] message"); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + if (args.length < 2) + usage(); + + MulticastAddress target = MulticastAddress.parse(args[0]); + + // create socket + ProtocolFamily family = StandardProtocolFamily.INET; + if (target.group() instanceof Inet6Address) + family = StandardProtocolFamily.INET6; + DatagramChannel dc = DatagramChannel.open(family).bind(new InetSocketAddress(0)); + if (target.interf() != null) { + dc.setOption(StandardSocketOption.IP_MULTICAST_IF, target.interf()); + } + + // send multicast packet + dc.send(Charset.defaultCharset().encode(args[1]), + new InetSocketAddress(target.group(), target.port())); + dc.close(); + } + +} diff --git a/src/solaris/back/util_md.h b/src/solaris/back/util_md.h index 52f7d18aaa57a08840f69d97f24530579c403749..10853f4e65a2bf7cc3a23f8db08c776ef4a83d32 100644 --- a/src/solaris/back/util_md.h +++ b/src/solaris/back/util_md.h @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-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 @@ -26,6 +26,9 @@ #ifndef JDWP_UTIL_MD_H #define JDWP_UTIL_MD_H +#include +#include /* To get uintptr_t */ + #include #include diff --git a/src/solaris/bin/java_md.c b/src/solaris/bin/java_md.c index c7c0da6d793b97e8cab93dee44c51c005f9c2750..6ecd9681c8f04c041e052792d8c07f902f695bda 100644 --- a/src/solaris/bin/java_md.c +++ b/src/solaris/bin/java_md.c @@ -289,13 +289,13 @@ CreateExecutionEnvironment(int *_argcp, if (wanted == running) { /* Find out where the JRE is that we will be using. */ if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) { - ReportErrorMessage(JRE_ERROR1); + JLI_ReportErrorMessage(JRE_ERROR1); exit(2); } /* Find the specified JVM type */ if (ReadKnownVMs(jrepath, arch, JNI_FALSE) < 1) { - ReportErrorMessage(CFG_ERROR7); + JLI_ReportErrorMessage(CFG_ERROR7); exit(1); } @@ -303,7 +303,7 @@ CreateExecutionEnvironment(int *_argcp, jvmtype = CheckJvmType(_argcp, _argvp, JNI_FALSE); if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch )) { - ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); + JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); exit(4); } } else { /* do the same speculatively or exit */ @@ -330,7 +330,7 @@ CreateExecutionEnvironment(int *_argcp, EndDataModelSpeculate: /* give up and let other code report error message */ ; #else - ReportErrorMessage(JRE_ERROR2, wanted); + JLI_ReportErrorMessage(JRE_ERROR2, wanted); exit(1); #endif } @@ -391,7 +391,7 @@ CreateExecutionEnvironment(int *_argcp, break; default: - ReportErrorMessage(JRE_ERROR3, __LINE__); + JLI_ReportErrorMessage(JRE_ERROR3, __LINE__); exit(1); /* unknown value in wanted */ break; } @@ -553,17 +553,17 @@ CreateExecutionEnvironment(int *_argcp, (void)fflush(stdout); (void)fflush(stderr); execve(newexec, argv, newenvp); - ReportErrorMessageSys(JRE_ERROR4, newexec); + JLI_ReportErrorMessageSys(JRE_ERROR4, newexec); #ifdef DUAL_MODE if (running != wanted) { - ReportErrorMessage(JRE_ERROR5, wanted, running); + JLI_ReportErrorMessage(JRE_ERROR5, wanted, running); # ifdef __solaris__ # ifdef __sparc - ReportErrorMessage(JRE_ERROR6); + JLI_ReportErrorMessage(JRE_ERROR6); # else - ReportErrorMessage(JRE_ERROR7); + JLI_ReportErrorMessage(JRE_ERROR7); # endif } # endif @@ -627,7 +627,7 @@ GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative) } if (!speculative) - ReportErrorMessage(JRE_ERROR8 JAVA_DLL); + JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); return JNI_FALSE; found: @@ -680,13 +680,13 @@ LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) if(length > 0) { location = JLI_StrStr(buf, "sparcv8plus "); if(location == NULL) { - ReportErrorMessage(JVM_ERROR3); + JLI_ReportErrorMessage(JVM_ERROR3); return JNI_FALSE; } } } #endif - ReportErrorMessage(DLL_ERROR1, __LINE__); + JLI_ReportErrorMessage(DLL_ERROR1, __LINE__); goto error; } @@ -703,7 +703,7 @@ LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) return JNI_TRUE; error: - ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); + JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); return JNI_FALSE; } @@ -848,7 +848,7 @@ SetExecname(char **argv) fptr = (int (*)())dlsym(RTLD_DEFAULT, "main"); if (fptr == NULL) { - ReportErrorMessage(DLL_ERROR3, dlerror()); + JLI_ReportErrorMessage(DLL_ERROR3, dlerror()); return JNI_FALSE; } @@ -885,7 +885,7 @@ SetExecname(char **argv) return exec_path; } -void ReportErrorMessage(const char* fmt, ...) { +void JLI_ReportErrorMessage(const char* fmt, ...) { va_list vl; va_start(vl, fmt); vfprintf(stderr, fmt, vl); @@ -893,7 +893,7 @@ void ReportErrorMessage(const char* fmt, ...) { va_end(vl); } -void ReportErrorMessageSys(const char* fmt, ...) { +void JLI_ReportErrorMessageSys(const char* fmt, ...) { va_list vl; char *emsg; @@ -912,7 +912,7 @@ void ReportErrorMessageSys(const char* fmt, ...) { va_end(vl); } -void ReportExceptionDescription(JNIEnv * env) { +void JLI_ReportExceptionDescription(JNIEnv * env) { (*env)->ExceptionDescribe(env); } @@ -1078,7 +1078,7 @@ ExecJRE(char *jre, char **argv) * Resolve the real path to the directory containing the selected JRE. */ if (realpath(jre, wanted) == NULL) { - ReportErrorMessage(JRE_ERROR9, jre); + JLI_ReportErrorMessage(JRE_ERROR9, jre); exit(1); } @@ -1087,7 +1087,7 @@ ExecJRE(char *jre, char **argv) */ SetExecname(argv); if (execname == NULL) { - ReportErrorMessage(JRE_ERROR10); + JLI_ReportErrorMessage(JRE_ERROR10); exit(1); } @@ -1106,7 +1106,7 @@ ExecJRE(char *jre, char **argv) * can be so deadly. */ if (JLI_StrLen(wanted) + JLI_StrLen(progname) + 6 > PATH_MAX) { - ReportErrorMessage(JRE_ERROR11); + JLI_ReportErrorMessage(JRE_ERROR11); exit(1); } @@ -1126,7 +1126,7 @@ ExecJRE(char *jre, char **argv) (void)fflush(stdout); (void)fflush(stderr); execv(wanted, argv); - ReportErrorMessageSys(JRE_ERROR12, wanted); + JLI_ReportErrorMessageSys(JRE_ERROR12, wanted); exit(1); } diff --git a/src/solaris/classes/sun/net/www/protocol/http/NTLMAuthentication.java b/src/solaris/classes/sun/net/www/protocol/http/NTLMAuthentication.java index 9130be50d8470379dcacccf3fd9324494c381d73..4c5c6c847952e4f7f806a31cc807717003c9f270 100644 --- a/src/solaris/classes/sun/net/www/protocol/http/NTLMAuthentication.java +++ b/src/solaris/classes/sun/net/www/protocol/http/NTLMAuthentication.java @@ -64,6 +64,7 @@ import java.net.*; */ class NTLMAuthentication extends AuthenticationInfo { + private static final long serialVersionUID = -2403849171106437142L; static char NTLM_AUTH = 'N'; diff --git a/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java b/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java index 4ee5e0617990e0e14d7908d36e8d1a15e6016951..8ebb0c223fff1e275fbe0fb24cefa3bb073ac26c 100644 --- a/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java +++ b/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java @@ -69,11 +69,11 @@ class EPollArrayWrapper { static final int EPOLL_CTL_MOD = 3; // Miscellaneous constants - static final short SIZE_EPOLLEVENT = 12; - static final short EVENT_OFFSET = 0; - static final short DATA_OFFSET = 4; - static final short FD_OFFSET = 4; - static final int NUM_EPOLLEVENTS = Math.min(fdLimit(), 8192); + static final int SIZE_EPOLLEVENT = sizeofEPollEvent(); + static final int EVENT_OFFSET = 0; + static final int DATA_OFFSET = offsetofData(); + static final int FD_OFFSET = DATA_OFFSET; + static final int NUM_EPOLLEVENTS = Math.min(fdLimit(), 8192); // Base address of the native pollArray private final long pollArrayAddress; @@ -280,6 +280,8 @@ class EPollArrayWrapper { private native void epollCtl(int epfd, int opcode, int fd, int events); private native int epollWait(long pollAddress, int numfds, long timeout, int epfd) throws IOException; + private static native int sizeofEPollEvent(); + private static native int offsetofData(); private static native int fdLimit(); private static native void interrupt(int fd); private static native void init(); diff --git a/src/solaris/instrument/FileSystemSupport_md.h b/src/solaris/instrument/FileSystemSupport_md.h index c092193f192c43fe6b0eb406498485934c1952df..a83e3d16f0a1795299513c95584a5f65a1a218cb 100644 --- a/src/solaris/instrument/FileSystemSupport_md.h +++ b/src/solaris/instrument/FileSystemSupport_md.h @@ -1,5 +1,5 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-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 @@ -23,5 +23,8 @@ * have any questions. */ +#include +#include /* For uintprt_t */ #include #include /* For MAXPATHLEN */ + diff --git a/src/solaris/javavm/export/jvm_md.h b/src/solaris/javavm/export/jvm_md.h index 2789492eeb596676249f611598e041e673baf4a5..4c6b8e14ec36d38c8fbdcb723bedf7b82e94f189 100644 --- a/src/solaris/javavm/export/jvm_md.h +++ b/src/solaris/javavm/export/jvm_md.h @@ -1,5 +1,5 @@ /* - * Copyright 1997-1999 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-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 @@ -34,6 +34,8 @@ #include /* For DIR */ #include /* For MAXPATHLEN */ #include /* For F_OK, R_OK, W_OK */ +#include /* For ptrdiff_t */ +#include /* For uintptr_t */ #define JNI_ONLOAD_SYMBOLS {"JNI_OnLoad"} #define JNI_ONUNLOAD_SYMBOLS {"JNI_OnUnload"} diff --git a/src/solaris/javavm/include/typedefs_md.h b/src/solaris/javavm/include/typedefs_md.h deleted file mode 100644 index 552a7951a7583cb1773f596a4b003f78db111ed4..0000000000000000000000000000000000000000 --- a/src/solaris/javavm/include/typedefs_md.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 1994-2002 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. - */ - -/* - * Solaris-dependent types for Green threads - */ - -#ifndef _JAVASOFT_SOLARIS_TYPES_MD_H_ -#define _JAVASOFT_SOLARIS_TYPES_MD_H_ - -#include -#include - -#ifdef __linux__ -#include -#define HAVE_INTPTR_T -#define _UINT64_T -#endif - -#define int8_t char - -/* Fix for varargs differences on PowerPC */ -#if defined(__powerpc__) -#define VARGS(x) (x) -#else -#define VARGS(x) (&x) -#endif /* __powerpc__ */ - - -#if defined(__alpha__) -#define PTR_IS_64 1 -#define LONG_IS_64 1 -#else -#define PTR_IS_32 1 -#endif - -/* don't redefine typedef's on Solaris 2.6 or Later */ - -#if !defined(_ILP32) && !defined(_LP64) - -#ifndef HAVE_INTPTR_T -#ifdef LONG_IS_64 -typedef long intptr_t; -typedef unsigned long uintptr_t; -#else -typedef int intptr_t; -typedef unsigned int uintptr_t; -#endif /* LONG_IS_64 */ -#endif /* don't HAVE_INTPTR_T */ - -#ifndef _UINT64_T -#define _UINT64_T -#ifdef LONG_IS_64 -typedef unsigned long uint64_t; -#else -typedef unsigned long long uint64_t; -#endif -#define _UINT32_T -#ifndef uint32_t /* [sbb] scaffolding */ -typedef unsigned int uint32_t; -#endif /* [sbb] scaffolding */ -#if defined(__linux__) -typedef unsigned int uint_t; -#endif -#endif - -#ifndef __BIT_TYPES_DEFINED__ -/* that should get Linux, at least */ -#ifndef _INT64_T -#define _INT64_T -#ifdef LONG_IS_64 -typedef long int64_t; -#else -typedef long long int64_t; -#endif -#define _INT32_T -#ifndef int32_t /* [sbb] scaffolding */ -typedef int int32_t; -#endif /* [sbb] scaffolding */ -#if defined(__linux__) -typedef int int_t; -#endif -#endif -#endif /* __BIT_TYPES_DEFINED__ */ - -#endif /* !defined(_ILP32) && !defined(_LP64) */ - -/* use these macros when the compiler supports the long long type */ - -#define ll_high(a) ((uint32_t)(((uint64_t)(a))>>32)) -#define ll_low(a) ((uint32_t)(a)) -#define int2ll(a) ((int64_t)(a)) -#define ll2int(a) ((int)(a)) -#define ll_add(a, b) ((int64_t)(a) + (int64_t)(b)) -#define ll_and(a, b) ((int64_t)(a) & (int64_t)(b)) -#define ll_div(a, b) ((int64_t)(a) / (int64_t)(b)) -#define ll_mul(a, b) ((int64_t)(a) * (int64_t)(b)) -#define ll_neg(a) (-(a)) -#define ll_not(a) (~(uint64_t)(a)) -#define ll_or(a, b) ((uint64_t)(a) | (b)) -#define ll_shl(a, n) ((uint64_t)(a) << (n)) -#define ll_shr(a, n) ((int64_t)(a) >> (n)) -#define ll_sub(a, b) ((uint64_t)(a) - (b)) -#define ll_ushr(a, n) ((uint64_t)(a) >>(n)) -#define ll_xor(a, b) ((int64_t)(a) ^ (int64_t)(b)) -#define uint2ll(a) ((uint64_t)(a)) -#define ll_rem(a,b) ((int64_t)(a) % (int64_t)(b)) - -extern int32_t float2l(float f); -extern int32_t double2l(double d); -extern int64_t float2ll(float f); -extern int64_t double2ll(double d); - -#define ll2float(a) ((float) (a)) -#define ll2double(a) ((double) (a)) - -/* Useful on machines where jlong and jdouble have different endianness. */ -#define ll2double_bits(a) ((void) 0) - -/* comparison operators */ -#define ll_ltz(ll) ((ll)<0) -#define ll_gez(ll) ((ll)>=0) -#define ll_eqz(a) ((a) == 0) -#define ll_nez(a) ((a) != 0) -#define ll_eq(a, b) ((a) == (b)) -#define ll_ne(a,b) ((a) != (b)) -#define ll_ge(a,b) ((a) >= (b)) -#define ll_le(a,b) ((a) <= (b)) -#define ll_lt(a,b) ((a) < (b)) -#define ll_gt(a,b) ((a) > (b)) - -#define ll_zero_const ((int64_t) 0) -#define ll_one_const ((int64_t) 1) - -extern void ll2str(int64_t a, char *s, char *limit); - -#define ll2ptr(a) ((void*)(uintptr_t)(a)) -#define ptr2ll(a) ((int64_t)(uintptr_t)(a)) - -#ifdef ppc -#define HAVE_ALIGNED_DOUBLES -#define HAVE_ALIGNED_LONGLONGS -#endif - -/* printf format modifier for printing pointers */ -#ifdef _LP64 -#define FORMAT64_MODIFIER "l" -#else -#define FORMAT64_MODIFIER "ll" -#endif - -#endif /* !_JAVASOFT_SOLARIS_TYPES_MD_H_ */ diff --git a/src/solaris/native/common/gdefs_md.h b/src/solaris/native/common/gdefs_md.h index 006e753f60ebe13624545a5fc5796ca4b70a29c1..dd74cfc2ce645b025aa2ec4bd915dc5d37d16ac2 100644 --- a/src/solaris/native/common/gdefs_md.h +++ b/src/solaris/native/common/gdefs_md.h @@ -1,5 +1,5 @@ /* - * Copyright 2000-2002 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-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 @@ -24,15 +24,12 @@ */ /* - * Solaris dependent type definitions includes intptr_t, etc + * Solaris/Linux dependent type definitions includes intptr_t, etc */ +#include +#include /* For uintptr_t */ +#include #include -/* - * Linux version of does not define intptr_t - */ -#ifdef __linux__ -#include -#include -#endif /* __linux__ */ + diff --git a/src/solaris/native/common/jlong_md.h b/src/solaris/native/common/jlong_md.h index 4460701065e2a575836d05dbf604b13e4bed6c56..a12044e475188d3aa83cece3b017d0e497ce55f6 100644 --- a/src/solaris/native/common/jlong_md.h +++ b/src/solaris/native/common/jlong_md.h @@ -1,5 +1,5 @@ /* - * Copyright 1997-2002 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-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 @@ -28,7 +28,7 @@ /* Make sure ptrdiff_t is defined */ #include -#include "typedefs.h" +#include /* For uintptr_t */ #define jlong_high(a) ((jint)((a)>>32)) #define jlong_low(a) ((jint)(a)) diff --git a/src/solaris/native/java/net/NetworkInterface.c b/src/solaris/native/java/net/NetworkInterface.c index a541744831a5a17291f2d42c50e1a258ed8c4359..14273f5c132d26893778a0d8e3fb6931fbf2e578 100644 --- a/src/solaris/native/java/net/NetworkInterface.c +++ b/src/solaris/native/java/net/NetworkInterface.c @@ -206,10 +206,10 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0 /* * Class: java_net_NetworkInterface - * Method: getByIndex + * Method: getByIndex0 * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface; */ -JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex +JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0 (JNIEnv *env, jclass cls, jint index) { netif *ifs, *curr; diff --git a/src/solaris/native/java/net/PlainDatagramSocketImpl.c b/src/solaris/native/java/net/PlainDatagramSocketImpl.c index 7c68f720582f2950e43b4416758ccc88c24ec897..dd3895cdbbbe3920aef902d56121b899650b3657 100644 --- a/src/solaris/native/java/net/PlainDatagramSocketImpl.c +++ b/src/solaris/native/java/net/PlainDatagramSocketImpl.c @@ -1741,7 +1741,7 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, jint opt) { * (for IF). */ if (index > 0) { - ni = Java_java_net_NetworkInterface_getByIndex(env, ni_class, + ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class, index); if (ni == NULL) { char errmsg[255]; diff --git a/src/solaris/native/java/net/PlainSocketImpl.c b/src/solaris/native/java/net/PlainSocketImpl.c index 1cf324b73378e092947665b65946ee615e36487a..ea07c777e72678bf5e41ea9ce62bf73195c2e8c0 100644 --- a/src/solaris/native/java/net/PlainSocketImpl.c +++ b/src/solaris/native/java/net/PlainSocketImpl.c @@ -491,27 +491,6 @@ Java_java_net_PlainSocketImpl_socketConnect(JNIEnv *env, jobject this, return; } - /* - * The socket may have been closed (dup'ed) while we were - * poll/select. In that case SO_ERROR will return 0 making - * it appear that the connection has been established. - * To avoid any race conditions we therefore grab the - * fd lock, check if the socket has been closed, and - * set the various fields whilst holding the lock - */ - fdLock = (*env)->GetObjectField(env, this, psi_fdLockID); - (*env)->MonitorEnter(env, fdLock); - - if ((*env)->GetBooleanField(env, this, psi_closePendingID)) { - - /* release fdLock */ - (*env)->MonitorExit(env, fdLock); - - JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", - "Socket closed"); - return; - } - (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); /* set the remote peer address and port */ @@ -536,11 +515,6 @@ Java_java_net_PlainSocketImpl_socketConnect(JNIEnv *env, jobject this, (*env)->SetIntField(env, this, psi_localportID, localport); } } - - /* - * Finally release fdLock - */ - (*env)->MonitorExit(env, fdLock); } /* diff --git a/src/solaris/native/java/net/net_util_md.c b/src/solaris/native/java/net/net_util_md.c index 1ff6c48dba2bab452a4415192d74b78f0a1ae728..460ce1049298a2a8bc53bb2bc48f74cea5a38a01 100644 --- a/src/solaris/native/java/net/net_util_md.c +++ b/src/solaris/native/java/net/net_util_md.c @@ -791,7 +791,7 @@ NET_SetTrafficClass(struct sockaddr *him, int trafficClass) { #endif /* AF_INET6 */ } -jint +JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(struct sockaddr *him) { #ifdef AF_INET6 if (him->sa_family == AF_INET6) { diff --git a/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c b/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c index b1f9f680b18a3a75600ed18a40250616b6b3290b..bbbccd725f91247d478927238c574a3c2a8b7c4d 100644 --- a/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c +++ b/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c @@ -198,7 +198,7 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this, JNIEXPORT jint JNICALL Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this, - jobject fdo, jlong address, + jboolean preferIPv6, jobject fdo, jlong address, jint len, jobject dest) { jint fd = fdval(env, fdo); @@ -215,7 +215,7 @@ Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this, if (NET_InetAddressToSockaddr(env, destAddress, destPort, (struct sockaddr *)&sa, - &sa_len, JNI_TRUE) != 0) { + &sa_len, preferIPv6) != 0) { return IOS_THROWN; } diff --git a/src/solaris/native/sun/nio/ch/EPollArrayWrapper.c b/src/solaris/native/sun/nio/ch/EPollArrayWrapper.c index ad9237b2e177443633999707afbd85e99e0658d0..7b4a4e738585d995369c322536fc8f1ae2a304a9 100644 --- a/src/solaris/native/sun/nio/ch/EPollArrayWrapper.c +++ b/src/solaris/native/sun/nio/ch/EPollArrayWrapper.c @@ -48,10 +48,18 @@ typedef union epoll_data { __uint64_t u64; } epoll_data_t; + +/* x86-64 has same alignment as 32-bit */ +#ifdef __x86_64__ +#define EPOLL_PACKED __attribute__((packed)) +#else +#define EPOLL_PACKED +#endif + struct epoll_event { __uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ -} __attribute__ ((__packed__)); +} EPOLL_PACKED; #ifdef __cplusplus } @@ -143,6 +151,18 @@ Java_sun_nio_ch_EPollArrayWrapper_fdLimit(JNIEnv *env, jclass this) return (jint)rlp.rlim_max; } +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPollArrayWrapper_sizeofEPollEvent(JNIEnv* env, jclass this) +{ + return sizeof(struct epoll_event); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPollArrayWrapper_offsetofData(JNIEnv* env, jclass this) +{ + return offsetof(struct epoll_event, data); +} + JNIEXPORT void JNICALL Java_sun_nio_ch_EPollArrayWrapper_epollCtl(JNIEnv *env, jobject this, jint epfd, jint opcode, jint fd, jint events) diff --git a/src/solaris/native/sun/nio/ch/FileKey.c b/src/solaris/native/sun/nio/ch/FileKey.c index 511b27f877d06022bd00d8445902ed170306a882..fc5618883a4d19edd589fec6ad3bc1d03226880c 100644 --- a/src/solaris/native/sun/nio/ch/FileKey.c +++ b/src/solaris/native/sun/nio/ch/FileKey.c @@ -33,12 +33,6 @@ static jfieldID key_st_dev; /* id for FileKey.st_dev */ static jfieldID key_st_ino; /* id for FileKey.st_ino */ -#define RESTARTABLE(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while ((_result == -1) && (errno == EINTR)); \ -} while(0) - JNIEXPORT void JNICALL Java_sun_nio_ch_FileKey_initIDs(JNIEnv *env, jclass clazz) diff --git a/src/solaris/native/sun/nio/ch/Net.c b/src/solaris/native/sun/nio/ch/Net.c index 9eb31c8926efe31048f94e3d27357a03284890ac..d9bbb6e78f49378b9cc8e17b68388298b018c16e 100644 --- a/src/solaris/native/sun/nio/ch/Net.c +++ b/src/solaris/native/sun/nio/ch/Net.c @@ -37,61 +37,171 @@ #include "net_util.h" #include "net_util_md.h" #include "nio_util.h" -#include "java_net_SocketOptions.h" #include "nio.h" -#ifdef __linux__ -#include +/** + * Definitions for source-specific multicast to allow for building + * with older header files. + */ + +#ifdef __solaris__ + +#ifndef IP_BLOCK_SOURCE + +#define IP_BLOCK_SOURCE 0x15 +#define IP_UNBLOCK_SOURCE 0x16 +#define IP_ADD_SOURCE_MEMBERSHIP 0x17 +#define IP_DROP_SOURCE_MEMBERSHIP 0x18 + +#define MCAST_BLOCK_SOURCE 0x2b +#define MCAST_UNBLOCK_SOURCE 0x2c +#define MCAST_JOIN_SOURCE_GROUP 0x2d +#define MCAST_LEAVE_SOURCE_GROUP 0x2e -#define IPV6_MULTICAST_IF 17 -#ifndef SO_BSDCOMPAT -#define SO_BSDCOMPAT 14 +#endif /* IP_BLOCK_SOURCE */ + +struct my_ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_sourceaddr; + struct in_addr imr_interface; +}; + +/* + * Use #pragma pack() construct to force 32-bit alignment on amd64. + */ +#if defined(amd64) +#pragma pack(4) #endif + +struct my_group_source_req { + uint32_t gsr_interface; /* interface index */ + struct sockaddr_storage gsr_group; /* group address */ + struct sockaddr_storage gsr_source; /* source address */ +}; + +#if defined(amd64) +#pragma pack() #endif +#endif /* __solaris__ */ + + +#ifdef __linux__ + +#ifndef IP_BLOCK_SOURCE + +#define IP_BLOCK_SOURCE 38 +#define IP_UNBLOCK_SOURCE 37 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 + +#define MCAST_BLOCK_SOURCE 43 +#define MCAST_UNBLOCK_SOURCE 44 +#define MCAST_JOIN_SOURCE_GROUP 42 +#define MCAST_LEAVE_SOURCE_GROUP 45 + +#endif /* IP_BLOCK_SOURCE */ + +struct my_ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; + struct in_addr imr_sourceaddr; +}; + +struct my_group_source_req { + uint32_t gsr_interface; /* interface index */ + struct sockaddr_storage gsr_group; /* group address */ + struct sockaddr_storage gsr_source; /* source address */ +}; + +#endif /* __linux__ */ + + +#define COPY_INET6_ADDRESS(env, source, target) \ + (*env)->GetByteArrayRegion(env, source, 0, 16, target) + +/* + * Copy IPv6 group, interface index, and IPv6 source address + * into group_source_req structure. + */ +static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index, + jbyteArray source, struct my_group_source_req* req) +{ + struct sockaddr_in6* sin6; + + req->gsr_interface = (uint32_t)index; + + sin6 = (struct sockaddr_in6*)&(req->gsr_group); + sin6->sin6_family = AF_INET6; + COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr)); + + sin6 = (struct sockaddr_in6*)&(req->gsr_source); + sin6->sin6_family = AF_INET6; + COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr)); +} + + JNIEXPORT void JNICALL Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) { /* Here because Windows native code does need to init IDs */ } +JNIEXPORT jboolean JNICALL +Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) +{ + return (ipv6_available()) ? JNI_TRUE : JNI_FALSE; +} + JNIEXPORT int JNICALL -Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean stream, - jboolean reuse) +Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, + jboolean stream, jboolean reuse) { int fd; + int type = (stream ? SOCK_STREAM : SOCK_DGRAM); + int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; -#ifdef AF_INET6 - if (ipv6_available()) - fd = socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); - else -#endif /* AF_INET6 */ - fd = socket(AF_INET, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); - + fd = socket(domain, type, 0); if (fd < 0) { return handleSocketError(env, errno); } if (reuse) { int arg = 1; - if (NET_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, - sizeof(arg)) < 0) { + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, + sizeof(arg)) < 0) { + JNU_ThrowByNameWithLastError(env, + JNU_JAVANETPKG "SocketException", + "sun.nio.ch.Net.setIntOption"); + close(fd); + return -1; + } + } +#ifdef __linux__ + /* By default, Linux uses the route default */ + if (domain == AF_INET6 && type == SOCK_DGRAM) { + int arg = 1; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg, + sizeof(arg)) < 0) { JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "sun.nio.ch.Net.setIntOption"); + close(fd); + return -1; } } +#endif return fd; } JNIEXPORT void JNICALL -Java_sun_nio_ch_Net_bind(JNIEnv *env, jclass clazz, /* ## Needs rest of PSI gunk */ - jobject fdo, jobject ia, int port) +Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jboolean preferIPv6, + jobject fdo, jobject iao, int port) { SOCKADDR sa; int sa_len = SOCKADDR_LEN; int rv = 0; - if (NET_InetAddressToSockaddr(env, ia, port, (struct sockaddr *)&sa, &sa_len, JNI_TRUE) != 0) { + if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { return; } @@ -101,27 +211,27 @@ Java_sun_nio_ch_Net_bind(JNIEnv *env, jclass clazz, /* ## Needs rest of PSI gunk } } +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) +{ + if (listen(fdval(env, fdo), backlog) < 0) + handleSocketError(env, errno); +} + JNIEXPORT jint JNICALL -Java_sun_nio_ch_Net_connect(JNIEnv *env, jclass clazz, - jobject fdo, jobject iao, jint port, - jint trafficClass) +Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, + jobject fdo, jobject iao, jint port) { SOCKADDR sa; int sa_len = SOCKADDR_LEN; int rv; - if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa, &sa_len, JNI_TRUE) != 0) { + if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa, + &sa_len, preferIPv6) != 0) + { return IOS_THROWN; } -#ifdef AF_INET6 -#if 0 - if (trafficClass != 0 && ipv6_available()) { /* ## FIX */ - NET_SetTrafficClass((struct sockaddr *)&sa, trafficClass); - } -#endif -#endif - rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); if (rv != 0) { if (errno == EINPROGRESS) { @@ -159,119 +269,79 @@ Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo) return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); } - -#ifdef NEEDED - -/* ## This is gross. We should generate platform-specific constant - * ## definitions into a .java file and use those directly. - */ - -static int -mapOption(JNIEnv *env, int opt, int *klevel, int *kopt) -{ - - switch (opt) { - - case java_net_SocketOptions_IP_TOS: - *klevel = IPPROTO_IP; - *kopt = IP_TOS; - break; - - case java_net_SocketOptions_SO_BROADCAST: - case java_net_SocketOptions_SO_KEEPALIVE: - case java_net_SocketOptions_SO_LINGER: - case java_net_SocketOptions_SO_OOBINLINE: - case java_net_SocketOptions_SO_RCVBUF: - case java_net_SocketOptions_SO_REUSEADDR: - case java_net_SocketOptions_SO_SNDBUF: - *klevel = SOL_SOCKET; - break; - - case java_net_SocketOptions_TCP_NODELAY: - *klevel = IPPROTO_IP; - *kopt = TCP_NODELAY; - return 0; - - default: - JNU_ThrowByName(env, "java/lang/IllegalArgumentException", NULL); - return -1; - } - - switch (opt) { - - case java_net_SocketOptions_SO_BROADCAST: *kopt = SO_BROADCAST; break; - case java_net_SocketOptions_SO_KEEPALIVE: *kopt = SO_KEEPALIVE; break; - case java_net_SocketOptions_SO_LINGER: *kopt = SO_LINGER; break; - case java_net_SocketOptions_SO_OOBINLINE: *kopt = SO_OOBINLINE; break; - case java_net_SocketOptions_SO_RCVBUF: *kopt = SO_RCVBUF; break; - case java_net_SocketOptions_SO_REUSEADDR: *kopt = SO_REUSEADDR; break; - case java_net_SocketOptions_SO_SNDBUF: *kopt = SO_SNDBUF; break; - - default: - return -1; - } - - return 0; -} -#endif - - JNIEXPORT jint JNICALL -Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, - jobject fdo, jint opt) +Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, + jboolean mayNeedConversion, jint level, jint opt) { - int klevel, kopt; int result; struct linger linger; + u_char carg; void *arg; - int arglen; + int arglen, n; - if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) { - JNU_ThrowByNameWithLastError(env, - JNU_JAVANETPKG "SocketException", - "Unsupported socket option"); - return -1; + /* Option value is an int except for a few specific cases */ + + arg = (void *)&result; + arglen = sizeof(result); + + if (level == IPPROTO_IP && + (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { + arg = (void*)&carg; + arglen = sizeof(carg); } - if (opt == java_net_SocketOptions_SO_LINGER) { + if (level == SOL_SOCKET && opt == SO_LINGER) { arg = (void *)&linger; arglen = sizeof(linger); - } else { - arg = (void *)&result; - arglen = sizeof(result); } - if (NET_GetSockOpt(fdval(env, fdo), klevel, kopt, arg, &arglen) < 0) { + if (mayNeedConversion) { + n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, &arglen); + } else { + n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen); + } + if (n < 0) { JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "sun.nio.ch.Net.getIntOption"); return -1; } - if (opt == java_net_SocketOptions_SO_LINGER) - return linger.l_onoff ? linger.l_linger : -1; - else - return result; + if (level == IPPROTO_IP && + (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) + { + return (jint)carg; + } + + if (level == SOL_SOCKET && opt == SO_LINGER) + return linger.l_onoff ? (jint)linger.l_linger : (jint)-1; + + return (jint)result; } JNIEXPORT void JNICALL -Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, - jobject fdo, jint opt, jint arg) +Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, + jboolean mayNeedConversion, jint level, jint opt, jint arg) { - int klevel, kopt; int result; struct linger linger; + u_char carg; void *parg; - int arglen; + int arglen, n; - if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) { - JNU_ThrowByNameWithLastError(env, - JNU_JAVANETPKG "SocketException", - "Unsupported socket option"); - return; + /* Option value is an int except for a few specific cases */ + + parg = (void*)&arg; + arglen = sizeof(arg); + + if (level == IPPROTO_IP && + (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { + parg = (void*)&carg; + arglen = sizeof(carg); + carg = (u_char)arg; } - if (opt == java_net_SocketOptions_SO_LINGER) { + if (level == SOL_SOCKET && opt == SO_LINGER) { parg = (void *)&linger; arglen = sizeof(linger); if (arg >= 0) { @@ -281,19 +351,199 @@ Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, linger.l_onoff = 0; linger.l_linger = 0; } - } else { - parg = (void *)&arg; - arglen = sizeof(arg); } - if (NET_SetSockOpt(fdval(env, fdo), klevel, kopt, parg, arglen) < 0) { + if (mayNeedConversion) { + n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen); + } else { + n = setsockopt(fdval(env, fdo), level, opt, parg, arglen); + } + if (n < 0) { JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "sun.nio.ch.Net.setIntOption"); } } +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo, + jint group, jint interf, jint source) +{ + struct ip_mreq mreq; + struct my_ip_mreq_source mreq_source; + int opt, n, optlen; + void* optval; + + if (source == 0) { + mreq.imr_multiaddr.s_addr = htonl(group); + mreq.imr_interface.s_addr = htonl(interf); + opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; + optval = (void*)&mreq; + optlen = sizeof(mreq); + } else { + mreq_source.imr_multiaddr.s_addr = htonl(group); + mreq_source.imr_sourceaddr.s_addr = htonl(source); + mreq_source.imr_interface.s_addr = htonl(interf); + opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; + optval = (void*)&mreq_source; + optlen = sizeof(mreq_source); + } + + n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); + if (n < 0) { + if (join && (errno == ENOPROTOOPT)) + return IOS_UNAVAILABLE; + handleSocketError(env, errno); + } + return 0; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo, + jint group, jint interf, jint source) +{ + struct my_ip_mreq_source mreq_source; + int n; + int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE; + + mreq_source.imr_multiaddr.s_addr = htonl(group); + mreq_source.imr_sourceaddr.s_addr = htonl(source); + mreq_source.imr_interface.s_addr = htonl(interf); + + n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, + (void*)&mreq_source, sizeof(mreq_source)); + if (n < 0) { + if (block && (errno == ENOPROTOOPT)) + return IOS_UNAVAILABLE; + handleSocketError(env, errno); + } + return 0; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo, + jbyteArray group, jint index, jbyteArray source) +{ + struct ipv6_mreq mreq6; + struct my_group_source_req req; + int opt, n, optlen; + void* optval; + + if (source == NULL) { + COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr)); + mreq6.ipv6mr_interface = (int)index; + opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; + optval = (void*)&mreq6; + optlen = sizeof(mreq6); + } else { +#ifdef __linux__ + /* Include-mode filtering broken on Linux at least to 2.6.24 */ + return IOS_UNAVAILABLE; +#else + initGroupSourceReq(env, group, index, source, &req); + opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP; + optval = (void*)&req; + optlen = sizeof(req); +#endif + } + + n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen); + if (n < 0) { + if (join && (errno == ENOPROTOOPT)) + return IOS_UNAVAILABLE; + handleSocketError(env, errno); + } + return 0; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo, + jbyteArray group, jint index, jbyteArray source) +{ + struct my_group_source_req req; + int n; + int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE; + + initGroupSourceReq(env, group, index, source, &req); + + n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, + (void*)&req, sizeof(req)); + if (n < 0) { + if (block && (errno == ENOPROTOOPT)) + return IOS_UNAVAILABLE; + handleSocketError(env, errno); + } + return 0; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf) +{ + struct in_addr in; + int arglen = sizeof(struct in_addr); + int n; + + in.s_addr = htonl(interf); + + n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, + (void*)&(in.s_addr), arglen); + if (n < 0) { + handleSocketError(env, errno); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo) +{ + struct in_addr in; + int arglen = sizeof(struct in_addr); + int n; + + n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen); + if (n < 0) { + handleSocketError(env, errno); + return -1; + } + return ntohl(in.s_addr); +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index) +{ + int value = (jint)index; + int arglen = sizeof(value); + int n; + n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, + (void*)&(index), arglen); + if (n < 0) { + handleSocketError(env, errno); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo) +{ + int index; + int arglen = sizeof(index); + int n; + + n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen); + if (n < 0) { + handleSocketError(env, errno); + return -1; + } + return (jint)index; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) +{ + int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD : + (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR; + if (shutdown(fdval(env, fdo), how) < 0) + handleSocketError(env, errno); +} /* Declared in nio_util.h */ diff --git a/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c b/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c index da92ed73d951387d33884c16514cf471e211584b..c0019d5ad4998ef2762784cce046530202f223a6 100644 --- a/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c +++ b/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c @@ -65,14 +65,6 @@ Java_sun_nio_ch_ServerSocketChannelImpl_initIDs(JNIEnv *env, jclass c) "(Ljava/net/InetAddress;I)V"); } -JNIEXPORT void JNICALL -Java_sun_nio_ch_ServerSocketChannelImpl_listen(JNIEnv *env, jclass cl, - jobject fdo, jint backlog) -{ - if (listen(fdval(env, fdo), backlog) < 0) - handleSocketError(env, errno); -} - JNIEXPORT jint JNICALL Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv *env, jobject this, jobject ssfdo, jobject newfdo, diff --git a/src/solaris/native/sun/nio/ch/SocketChannelImpl.c b/src/solaris/native/sun/nio/ch/SocketChannelImpl.c index 94c8467cf21db978f83609dfba54eb46563dabbc..7190b1b1213209e1612ed455ed91cfa4135c7102 100644 --- a/src/solaris/native/sun/nio/ch/SocketChannelImpl.c +++ b/src/solaris/native/sun/nio/ch/SocketChannelImpl.c @@ -35,10 +35,6 @@ #include #endif -#if defined(__solaris__) && !defined(_SOCKLEN_T) -typedef size_t socklen_t; /* New in SunOS 5.7, so need this for 5.6 */ -#endif - #include "jni.h" #include "jni_util.h" #include "net_util.h" @@ -88,12 +84,3 @@ Java_sun_nio_ch_SocketChannelImpl_checkConnect(JNIEnv *env, jobject this, } return 0; } - - -JNIEXPORT void JNICALL -Java_sun_nio_ch_SocketChannelImpl_shutdown(JNIEnv *env, jclass cl, - jobject fdo, jint how) -{ - if (shutdown(fdval(env, fdo), how) < 0) - handleSocketError(env, errno); -} diff --git a/src/solaris/native/sun/nio/ch/nio_util.h b/src/solaris/native/sun/nio/ch/nio_util.h index 608b0cc8999bf83b369ed3264b1608d0f5816f37..02c15ed47b1610948918e28109fef29cf77a9ef3 100644 --- a/src/solaris/native/sun/nio/ch/nio_util.h +++ b/src/solaris/native/sun/nio/ch/nio_util.h @@ -27,8 +27,15 @@ #include "jni_util.h" #include "jvm.h" #include "jlong.h" +#include #include +#define RESTARTABLE(_cmd, _result) do { \ + do { \ + _result = _cmd; \ + } while((_result == -1) && (errno == EINTR)); \ +} while(0) + /* NIO utility procedures */ diff --git a/src/windows/back/util_md.h b/src/windows/back/util_md.h index 2b9200b77a6156f47280247c6795fabf225f8357..604b3cccb9b59d77576c499e67fae25a52332068 100644 --- a/src/windows/back/util_md.h +++ b/src/windows/back/util_md.h @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-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 @@ -26,6 +26,7 @@ #ifndef JDWP_UTIL_MD_H #define JDWP_UTIL_MD_H +#include /* for uintptr_t */ #include /* for _MAx_PATH */ typedef unsigned __int64 UNSIGNED_JLONG; diff --git a/src/windows/bin/java_md.c b/src/windows/bin/java_md.c index 53e1e9a0a9399a2099f7936e7bd2a6b020618d21..2db1f25e2c4e4faed00e666d23032b0ee3de6717 100644 --- a/src/windows/bin/java_md.c +++ b/src/windows/bin/java_md.c @@ -105,26 +105,26 @@ CreateExecutionEnvironment(int *_argc, } } if (running != wanted) { - ReportErrorMessage(JRE_ERROR2, wanted); + JLI_ReportErrorMessage(JRE_ERROR2, wanted); exit(1); } /* Find out where the JRE is that we will be using. */ if (!GetJREPath(jrepath, so_jrepath)) { - ReportErrorMessage(JRE_ERROR1); + JLI_ReportErrorMessage(JRE_ERROR1); exit(2); } /* Find the specified JVM type */ if (ReadKnownVMs(jrepath, (char*)GetArch(), JNI_FALSE) < 1) { - ReportErrorMessage(CFG_ERROR7); + JLI_ReportErrorMessage(CFG_ERROR7); exit(1); } jvmtype = CheckJvmType(_argc, _argv, JNI_FALSE); jvmpath[0] = '\0'; if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) { - ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); + JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); exit(4); } /* If we got here, jvmpath has been correctly initialized. */ @@ -160,7 +160,7 @@ GetJREPath(char *path, jint pathsize) goto found; } - ReportErrorMessage(JRE_ERROR8 JAVA_DLL); + JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); return JNI_FALSE; found: @@ -212,7 +212,7 @@ LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) JLI_TraceLauncher("CRT path is %s\n", crtpath); if (_access(crtpath, 0) == 0) { if (LoadLibrary(crtpath) == 0) { - ReportErrorMessage(DLL_ERROR4, crtpath); + JLI_ReportErrorMessage(DLL_ERROR4, crtpath); return JNI_FALSE; } } @@ -220,7 +220,7 @@ LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) /* Load the Java VM DLL */ if ((handle = LoadLibrary(jvmpath)) == 0) { - ReportErrorMessage(DLL_ERROR4, (char *)jvmpath); + JLI_ReportErrorMessage(DLL_ERROR4, (char *)jvmpath); return JNI_FALSE; } @@ -230,7 +230,7 @@ LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) ifn->GetDefaultJavaVMInitArgs = (void *)GetProcAddress(handle, "JNI_GetDefaultJavaVMInitArgs"); if (ifn->CreateJavaVM == 0 || ifn->GetDefaultJavaVMInitArgs == 0) { - ReportErrorMessage(JNI_ERROR1, (char *)jvmpath); + JLI_ReportErrorMessage(JNI_ERROR1, (char *)jvmpath); return JNI_FALSE; } @@ -292,19 +292,19 @@ GetPublicJREHome(char *buf, jint bufsize) /* Find the current version of the JRE */ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, JRE_KEY, 0, KEY_READ, &key) != 0) { - ReportErrorMessage(REG_ERROR1, JRE_KEY); + JLI_ReportErrorMessage(REG_ERROR1, JRE_KEY); return JNI_FALSE; } if (!GetStringFromRegistry(key, "CurrentVersion", version, sizeof(version))) { - ReportErrorMessage(REG_ERROR2, JRE_KEY); + JLI_ReportErrorMessage(REG_ERROR2, JRE_KEY); RegCloseKey(key); return JNI_FALSE; } if (JLI_StrCmp(version, GetDotVersion()) != 0) { - ReportErrorMessage(REG_ERROR3, JRE_KEY, version, GetDotVersion() + JLI_ReportErrorMessage(REG_ERROR3, JRE_KEY, version, GetDotVersion() ); RegCloseKey(key); return JNI_FALSE; @@ -312,13 +312,13 @@ GetPublicJREHome(char *buf, jint bufsize) /* Find directory where the current version is installed. */ if (RegOpenKeyEx(key, version, 0, KEY_READ, &subkey) != 0) { - ReportErrorMessage(REG_ERROR1, JRE_KEY, version); + JLI_ReportErrorMessage(REG_ERROR1, JRE_KEY, version); RegCloseKey(key); return JNI_FALSE; } if (!GetStringFromRegistry(subkey, "JavaHome", buf, bufsize)) { - ReportErrorMessage(REG_ERROR4, JRE_KEY, version); + JLI_ReportErrorMessage(REG_ERROR4, JRE_KEY, version); RegCloseKey(key); RegCloseKey(subkey); return JNI_FALSE; @@ -370,7 +370,7 @@ jlong Counter2Micros(jlong counts) } void -ReportErrorMessage(const char* fmt, ...) { +JLI_ReportErrorMessage(const char* fmt, ...) { va_list vl; va_start(vl,fmt); @@ -394,12 +394,12 @@ ReportErrorMessage(const char* fmt, ...) { } /* - * Just like ReportErrorMessage, except that it concatenates the system + * Just like JLI_ReportErrorMessage, except that it concatenates the system * error message if any, its upto the calling routine to correctly * format the separation of the messages. */ void -ReportErrorMessageSys(const char *fmt, ...) +JLI_ReportErrorMessageSys(const char *fmt, ...) { va_list vl; @@ -462,7 +462,7 @@ ReportErrorMessageSys(const char *fmt, ...) va_end(vl); } -void ReportExceptionDescription(JNIEnv * env) { +void JLI_ReportExceptionDescription(JNIEnv * env) { if (IsJavaw()) { /* * This code should be replaced by code which opens a window with @@ -733,7 +733,7 @@ ExecJRE(char *jre, char **argv) { */ len = GetModuleFileName(NULL, path, MAXPATHLEN + 1); if (len == 0 || len > MAXPATHLEN) { - ReportErrorMessageSys(JRE_ERROR9, progname); + JLI_ReportErrorMessageSys(JRE_ERROR9, progname); exit(1); } @@ -766,7 +766,7 @@ ExecJRE(char *jre, char **argv) { * If it weren't for this semantic flaw, the code below would be ... * * execv(path, argv); - * ReportErrorMessage("Error: Exec of %s failed\n", path); + * JLI_ReportErrorMessage("Error: Exec of %s failed\n", path); * exit(1); * * The incorrect exec semantics could be addressed by: @@ -876,7 +876,7 @@ ExecJRE(char *jre, char **argv) { (LPCTSTR)NULL, /* current directory */ (LPSTARTUPINFO)&si, /* (in) startup information */ (LPPROCESS_INFORMATION)&pi)) { /* (out) process information */ - ReportErrorMessageSys(SYS_ERROR1, path); + JLI_ReportErrorMessageSys(SYS_ERROR1, path); exit(1); } @@ -884,7 +884,7 @@ ExecJRE(char *jre, char **argv) { if (GetExitCodeProcess(pi.hProcess, &exitCode) == FALSE) exitCode = 1; } else { - ReportErrorMessage(SYS_ERROR2); + JLI_ReportErrorMessage(SYS_ERROR2); exitCode = 1; } diff --git a/src/windows/hpi/src/socket_md.c b/src/windows/hpi/src/socket_md.c index 852022a4938f9165b0f6cc18c2e6c1aff4136434..8dd5f95680f53feb7a1ec11e9b9808f83632765d 100644 --- a/src/windows/hpi/src/socket_md.c +++ b/src/windows/hpi/src/socket_md.c @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-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 @@ -29,7 +29,6 @@ #include "hpi_impl.h" #include "mutex_md.h" -#include "typedefs.h" struct sockaddr; diff --git a/src/windows/hpi/src/threads_md.c b/src/windows/hpi/src/threads_md.c index 410f61c98075d3f9f5ab3b52e1fe621203f336a5..1c6b63f33b73c2d21200608666e0167f380faf6f 100644 --- a/src/windows/hpi/src/threads_md.c +++ b/src/windows/hpi/src/threads_md.c @@ -1,5 +1,5 @@ /* - * Copyright 1994-2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1994-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 @@ -35,7 +35,6 @@ #include "threads_md.h" #include "monitor_md.h" -#include "typedefs.h" /* diff --git a/src/windows/instrument/FileSystemSupport_md.h b/src/windows/instrument/FileSystemSupport_md.h index bd9c029bcbd8a86c7bf39f16077159a1cc378536..9d29ea6fef05fe336b97b105a73597ebcd60f648 100644 --- a/src/windows/instrument/FileSystemSupport_md.h +++ b/src/windows/instrument/FileSystemSupport_md.h @@ -1,5 +1,5 @@ /* - * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2004-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 @@ -23,6 +23,7 @@ * have any questions. */ +#include /* For uintprt_t */ #include #define MAXPATHLEN _MAX_PATH diff --git a/src/windows/javavm/export/jvm_md.h b/src/windows/javavm/export/jvm_md.h index 76560f6ec7d341806c671082439aba6eb3df34eb..cf98f61acb7f22ce0226f4e148a1bbc2336bcaac 100644 --- a/src/windows/javavm/export/jvm_md.h +++ b/src/windows/javavm/export/jvm_md.h @@ -53,6 +53,7 @@ typedef struct { WIN32_FIND_DATA find_data; } DIR; +#include /* For uintptr_t */ #include #define JVM_MAXPATHLEN _MAX_PATH @@ -65,6 +66,19 @@ typedef struct { JNIEXPORT void * JNICALL JVM_GetThreadInterruptEvent(); +/* + * These routines are only reentrant on Windows + */ + +JNIEXPORT struct protoent * JNICALL +JVM_GetProtoByName(char* name); + +JNIEXPORT struct hostent* JNICALL +JVM_GetHostByAddr(const char* name, int len, int type); + +JNIEXPORT struct hostent* JNICALL +JVM_GetHostByName(char* name); + /* * File I/O */ diff --git a/src/windows/javavm/include/typedefs_md.h b/src/windows/javavm/include/typedefs_md.h deleted file mode 100644 index 7c41e9aa706a489603c163df2e005a1b10621a0f..0000000000000000000000000000000000000000 --- a/src/windows/javavm/include/typedefs_md.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 1994-2002 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. - */ - -/* - * Win32 dependent type definitions - */ - -#ifndef _JAVASOFT_WIN32_TYPEDEF_MD_H_ -#define _JAVASOFT_WIN32_TYPEDEF_MD_H_ - -#include - -#define VARGS(x) (&x) - -typedef char int8_t; -typedef __int16 int16_t; -typedef __int32 int32_t; -typedef __int64 int64_t; - -typedef unsigned char uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned int uint_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; - -/* Make sure that we have the intptr_t and uintptr_t definitions */ -#ifndef _INTPTR_T_DEFINED -#ifdef _WIN64 -typedef __int64 intptr_t; -#else -typedef int intptr_t; -#endif -#define _INTPTR_T_DEFINED -#endif - -#ifndef _UINTPTR_T_DEFINED -#ifdef _WIN64 -typedef unsigned __int64 uintptr_t; -#else -typedef unsigned int uintptr_t; -#endif -#define _UINTPTR_T_DEFINED -#endif - -typedef intptr_t ssize_t; - -/* use these macros when the compiler supports the long long type */ - -#define ll_high(a) ((long)((a)>>32)) -#define ll_low(a) ((long)(a)) -#define int2ll(a) ((int64_t)(a)) -#define ll2int(a) ((int)(a)) -#define ll_add(a, b) ((a) + (b)) -#define ll_and(a, b) ((a) & (b)) -#define ll_div(a, b) ((a) / (b)) -#define ll_mul(a, b) ((a) * (b)) -#define ll_neg(a) (-(a)) -#define ll_not(a) (~(a)) -#define ll_or(a, b) ((a) | (b)) -/* THE FOLLOWING DEFINITION IS NOW A FUNCTION CALL IN ORDER TO WORKAROUND - OPTIMIZER BUG IN MSVC++ 2.1 (see system_md.c) - #define ll_shl(a, n) ((a) << (n)) */ -#define ll_shr(a, n) ((a) >> (n)) -#define ll_sub(a, b) ((a) - (b)) -#define ll_ushr(a, n) ((uint64_t)(a) >> (n)) -#define ll_xor(a, b) ((a) ^ (b)) -#define uint2ll(a) ((uint64_t)(unsigned long)(a)) -#define ll_rem(a,b) ((a) % (b)) - -int32_t float2l(float f); -int32_t double2l(double f); -int64_t float2ll(float f); -int64_t double2ll(double f); -#define ll2float(a) ((float) (a)) -#define ll2double(a) ((double) (a)) - -/* Useful on machines where jlong and jdouble have different endianness. */ -#define ll2double_bits(a) ((void) 0) - -/* comparison operators */ -#define ll_ltz(ll) ((ll) < 0) -#define ll_gez(ll) ((ll) >= 0) -#define ll_eqz(a) ((a) == 0) -#define ll_nez(a) ((a) != 0) -#define ll_eq(a, b) ((a) == (b)) -#define ll_ne(a,b) ((a) != (b)) -#define ll_ge(a,b) ((a) >= (b)) -#define ll_le(a,b) ((a) <= (b)) -#define ll_lt(a,b) ((a) < (b)) -#define ll_gt(a,b) ((a) > (b)) - -#define ll_zero_const ((int64_t) 0) -#define ll_one_const ((int64_t) 1) - -int64_t ll_shl(int64_t a, int bits); - -#define ll2ptr(a) ((void*)(a)) -#define ptr2ll(a) ((jlong)(a)) - -/* printf format modifier for printing pointers */ -#define FORMAT64_MODIFIER "I64" - -#endif /* !_JAVASOFT_WIN32_TYPEDEF_MD_H_ */ diff --git a/src/windows/native/java/net/NetworkInterface.c b/src/windows/native/java/net/NetworkInterface.c index cccf7d4403450f850ed2ef07a3f42953935fccfa..b59595c7e5ab8f072a8612b3220e52c26b19b90f 100644 --- a/src/windows/native/java/net/NetworkInterface.c +++ b/src/windows/native/java/net/NetworkInterface.c @@ -762,17 +762,17 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0 /* * Class: NetworkInterface - * Method: getByIndex + * Method: getByIndex0 * Signature: (I)LNetworkInterface; */ -JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex +JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0 (JNIEnv *env, jclass cls, jint index) { netif *ifList, *curr; jobject netifObj = NULL; if (os_supports_ipv6 && ipv6_available()) { - return Java_java_net_NetworkInterface_getByIndex_XP (env, cls, index); + return Java_java_net_NetworkInterface_getByIndex0_XP (env, cls, index); } /* get the list of interfaces */ diff --git a/src/windows/native/java/net/NetworkInterface_winXP.c b/src/windows/native/java/net/NetworkInterface_winXP.c index 87eb2eb9ab5633294b0c6539d26380c358db23c2..e2d878d781e81be4d9eb77fe6e74d6760a9b5f78 100644 --- a/src/windows/native/java/net/NetworkInterface_winXP.c +++ b/src/windows/native/java/net/NetworkInterface_winXP.c @@ -576,10 +576,10 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0_XP /* * Class: NetworkInterface - * Method: getByIndex + * Method: getByIndex0_XP * Signature: (I)LNetworkInterface; */ -JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex_XP +JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0_XP (JNIEnv *env, jclass cls, jint index) { netif *ifList, *curr; diff --git a/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c b/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c index 4ada9f964d22581cf5761c9bd38d57767c3ed2a9..ddb7a477e6f93be400ad306331eacc19b5ce4075 100644 --- a/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c +++ b/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c @@ -2090,7 +2090,7 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint o * (for IF). */ if (index > 0) { - ni = Java_java_net_NetworkInterface_getByIndex(env, ni_class, + ni = Java_java_net_NetworkInterface_getByIndex0(env, ni_class, index); if (ni == NULL) { char errmsg[255]; diff --git a/src/windows/native/java/net/net_util_md.c b/src/windows/native/java/net/net_util_md.c index 87dbdcf79e0166e5c8a6b4ca06a0cb4e8cd2aedd..ddf149684789ef1bffb4407ab9091e288ce83ab7 100644 --- a/src/windows/native/java/net/net_util_md.c +++ b/src/windows/native/java/net/net_util_md.c @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-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 @@ -28,7 +28,6 @@ #include "net_util.h" #include "jni.h" -#include "typedefs.h" #ifndef IPTOS_TOS_MASK #define IPTOS_TOS_MASK 0x1e @@ -890,7 +889,7 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr return 0; } -jint +JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(struct sockaddr *him) { if (him->sa_family == AF_INET6) { return ntohs(((struct sockaddr_in6*)him)->sin6_port); diff --git a/src/windows/native/java/net/net_util_md.h b/src/windows/native/java/net/net_util_md.h index 9b237c4dcf69c625fd7f54fddb83600b8cbfd2c3..5b3ae84e42a59c194706e9b36ec0bf1c7d66ed7e 100644 --- a/src/windows/native/java/net/net_util_md.h +++ b/src/windows/native/java/net/net_util_md.h @@ -329,7 +329,7 @@ extern jint NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout); JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0_XP (JNIEnv *env, jclass cls, jstring name); -JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex_XP +JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0_XP (JNIEnv *env, jclass cls, jint index); JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0_XP diff --git a/src/windows/native/sun/nio/ch/DatagramChannelImpl.c b/src/windows/native/sun/nio/ch/DatagramChannelImpl.c index 6d400c213c0e9909c0157fb51b1136665a315aaa..99cc716eba5bc7f27e71e761a2a15b49f80fe110 100644 --- a/src/windows/native/sun/nio/ch/DatagramChannelImpl.c +++ b/src/windows/native/sun/nio/ch/DatagramChannelImpl.c @@ -39,46 +39,9 @@ static jfieldID isa_portID; /* port in java.net.InetSocketAddress */ static jfieldID dci_senderID; /* sender in sun.nio.ch.DatagramChannelImpl */ static jfieldID dci_senderAddrID; /* sender InetAddress in sun.nio.ch.DatagramChannelImpl */ static jfieldID dci_senderPortID; /* sender port in sun.nio.ch.DatagramChannelImpl */ -static jfieldID ia_addrID; -static jfieldID ia_famID; static jclass isa_class; /* java.net.InetSocketAddress */ -static jclass ia_class; -static jmethodID isa_ctorID; /* .InetSocketAddress(InetAddress, int) */ -static jmethodID ia_ctorID; +static jmethodID isa_ctorID; /* java.net.InetSocketAddress(InetAddress, int) */ -/* - * Returns JNI_TRUE if DatagramChannelImpl has already cached an - * InetAddress/port corresponding to the socket address. - */ -static jboolean isSenderCached(JNIEnv *env, jobject this, struct sockaddr_in *sa) { - jobject senderAddr; - - /* shouldn't happen until we have dual IPv4/IPv6 stack (post-XP ?) */ - if (sa->sin_family != AF_INET) { - return JNI_FALSE; - } - - /* - * Compare source address to cached InetAddress - */ - senderAddr = (*env)->GetObjectField(env, this, dci_senderAddrID); - if (senderAddr == NULL) { - return JNI_FALSE; - } - if ((jint)ntohl(sa->sin_addr.s_addr) != - (*env)->GetIntField(env, senderAddr, ia_addrID)) { - return JNI_FALSE; - } - - /* - * Compare source port to cached port - */ - if ((jint)ntohs(sa->sin_port) != - (*env)->GetIntField(env, this, dci_senderPortID)) { - return JNI_FALSE; - } - return JNI_TRUE; -} JNIEXPORT void JNICALL Java_sun_nio_ch_DatagramChannelImpl_initIDs(JNIEnv *env, jclass clazz) @@ -99,32 +62,6 @@ Java_sun_nio_ch_DatagramChannelImpl_initIDs(JNIEnv *env, jclass clazz) "Ljava/net/InetAddress;"); dci_senderPortID = (*env)->GetFieldID(env, clazz, "cachedSenderPort", "I"); - clazz = (*env)->FindClass(env, "java/net/Inet4Address"); - ia_class = (*env)->NewGlobalRef(env, clazz); - ia_addrID = (*env)->GetFieldID(env, clazz, "address", "I"); - ia_famID = (*env)->GetFieldID(env, clazz, "family", "I"); - ia_ctorID = (*env)->GetMethodID(env, clazz, "", "()V"); -} - -/* - * Return JNI_TRUE if this Windows edition supports ICMP Port Unreachable - */ -__inline static jboolean supportPortUnreachable() { - static jboolean initDone; - static jboolean portUnreachableSupported; - - if (!initDone) { - OSVERSIONINFO ver; - ver.dwOSVersionInfoSize = sizeof(ver); - GetVersionEx(&ver); - if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT && ver.dwMajorVersion >= 5) { - portUnreachableSupported = JNI_TRUE; - } else { - portUnreachableSupported = JNI_FALSE; - } - initDone = JNI_TRUE; - } - return portUnreachableSupported; } /* @@ -140,15 +77,8 @@ jboolean purgeOutstandingICMP(JNIEnv *env, jclass clazz, jint fd) char buf[1]; fd_set tbl; struct timeval t = { 0, 0 }; - struct sockaddr_in rmtaddr; - int addrlen = sizeof(rmtaddr); - - /* - * A no-op if this OS doesn't support it. - */ - if (!supportPortUnreachable()) { - return JNI_FALSE; - } + SOCKETADDRESS sa; + int addrlen = sizeof(sa); /* * Peek at the queue to see if there is an ICMP port unreachable. If there @@ -161,7 +91,7 @@ jboolean purgeOutstandingICMP(JNIEnv *env, jclass clazz, jint fd) break; } if (recvfrom(fd, buf, 1, MSG_PEEK, - (struct sockaddr *)&rmtaddr, &addrlen) != SOCKET_ERROR) { + (struct sockaddr *)&sa, &addrlen) != SOCKET_ERROR) { break; } if (WSAGetLastError() != WSAECONNRESET) { @@ -169,7 +99,7 @@ jboolean purgeOutstandingICMP(JNIEnv *env, jclass clazz, jint fd) break; } - recvfrom(fd, buf, 1, 0, (struct sockaddr *)&rmtaddr, &addrlen); + recvfrom(fd, buf, 1, 0, (struct sockaddr *)&sa, &addrlen); got_icmp = JNI_TRUE; } @@ -182,12 +112,12 @@ Java_sun_nio_ch_DatagramChannelImpl_disconnect0(JNIEnv *env, jobject this, { jint fd = fdval(env, fdo); int rv = 0; - struct sockaddr_in psa; - int sa_len = sizeof(psa); + SOCKETADDRESS sa; + int sa_len = sizeof(sa); - memset(&psa, 0, sa_len); + memset(&sa, 0, sa_len); - rv = connect((SOCKET)fd, (struct sockaddr *)&psa, sa_len); + rv = connect((SOCKET)fd, (struct sockaddr *)&sa, sa_len); if (rv == SOCKET_ERROR) { handleSocketError(env, WSAGetLastError()); } @@ -200,10 +130,11 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this, { jint fd = fdval(env, fdo); void *buf = (void *)jlong_to_ptr(address); - struct sockaddr_in psa; - int sa_len = sizeof(psa); + SOCKETADDRESS sa; + int sa_len = sizeof(sa); BOOL retry = FALSE; jint n; + jobject senderAddr; do { retry = FALSE; @@ -211,7 +142,7 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this, (char *)buf, len, 0, - (struct sockaddr *)&psa, + (struct sockaddr *)&sa, &sa_len); if (n == SOCKET_ERROR) { @@ -233,21 +164,30 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this, } } while (retry); - if (!isSenderCached(env, this, &psa)) { - int port = ntohs(psa.sin_port); - jobject ia = (*env)->NewObject(env, ia_class, ia_ctorID); - jobject isa = NULL; - - if (psa.sin_family != AF_INET) { - JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", - "Protocol family unavailable"); + /* + * If the source address and port match the cached address + * and port in DatagramChannelImpl then we don't need to + * create InetAddress and InetSocketAddress objects. + */ + senderAddr = (*env)->GetObjectField(env, this, dci_senderAddrID); + if (senderAddr != NULL) { + if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&sa, + senderAddr)) { + senderAddr = NULL; + } else { + jint port = (*env)->GetIntField(env, this, dci_senderPortID); + if (port != NET_GetPortFromSockaddr((struct sockaddr *)&sa)) { + senderAddr = NULL; + } } + } + if (senderAddr == NULL) { + jobject isa = NULL; + int port; + jobject ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, + &port); if (ia != NULL) { - // populate InetAddress (assumes AF_INET) - (*env)->SetIntField(env, ia, ia_addrID, ntohl(psa.sin_addr.s_addr)); - - // create InetSocketAddress isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port); } @@ -258,9 +198,8 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this, // update cachedSenderInetAddress/cachedSenderPort (*env)->SetObjectField(env, this, dci_senderAddrID, ia); - (*env)->SetIntField(env, this, dci_senderPortID, port); - - // update sender + (*env)->SetIntField(env, this, dci_senderPortID, + NET_GetPortFromSockaddr((struct sockaddr *)&sa)); (*env)->SetObjectField(env, this, dci_senderID, isa); } return n; @@ -268,21 +207,20 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this, JNIEXPORT jint JNICALL Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this, - jobject fdo, jlong address, - jint len, jobject dest) + jboolean preferIPv6, jobject fdo, + jlong address, jint len, jobject dest) { jint fd = fdval(env, fdo); void *buf = (void *)jlong_to_ptr(address); - SOCKETADDRESS psa; - int sa_len = sizeof(psa); + SOCKETADDRESS sa; + int sa_len; jint rv = 0; jobject destAddress = (*env)->GetObjectField(env, dest, isa_addrID); jint destPort = (*env)->GetIntField(env, dest, isa_portID); - if (NET_InetAddressToSockaddr(env, destAddress, destPort, - (struct sockaddr *)&psa, - &sa_len, JNI_FALSE) != 0) { + (struct sockaddr *)&sa, + &sa_len, preferIPv6) != 0) { return IOS_THROWN; } @@ -290,7 +228,7 @@ Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this, buf, len, 0, - (struct sockaddr *)&psa, + (struct sockaddr *)&sa, sa_len); if (rv == SOCKET_ERROR) { int theErr = (jint)WSAGetLastError(); diff --git a/src/windows/native/sun/nio/ch/Net.c b/src/windows/native/sun/nio/ch/Net.c index b9fac794e45d19835e972b642e84b866e5832022..c89745a216fbb062728ce722903c9d16c292ad6b 100644 --- a/src/windows/native/sun/nio/ch/Net.c +++ b/src/windows/native/sun/nio/ch/Net.c @@ -36,51 +36,95 @@ #include "sun_nio_ch_Net.h" +/** + * Definitions to allow for building with older SDK include files. + */ + +#ifndef MCAST_BLOCK_SOURCE + +#define MCAST_BLOCK_SOURCE 43 +#define MCAST_UNBLOCK_SOURCE 44 +#define MCAST_JOIN_SOURCE_GROUP 45 +#define MCAST_LEAVE_SOURCE_GROUP 46 + +#endif /* MCAST_BLOCK_SOURCE */ -static jfieldID ia_addrID; -static jclass ia_class; -static jmethodID ia_ctorID; -static jfieldID ia_famID; +typedef struct my_ip_mreq_source { + IN_ADDR imr_multiaddr; + IN_ADDR imr_sourceaddr; + IN_ADDR imr_interface; +}; -/************************************************************** - * static method to store field IDs in initializers +typedef struct my_group_source_req { + ULONG gsr_interface; + SOCKADDR_STORAGE gsr_group; + SOCKADDR_STORAGE gsr_source; +}; + +/** + * Copy IPv6 address as jbytearray to target */ +#define COPY_INET6_ADDRESS(env, source, target) \ + (*env)->GetByteArrayRegion(env, source, 0, 16, target) + + JNIEXPORT void JNICALL Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) { - clazz = (*env)->FindClass(env, "java/net/Inet4Address"); - ia_class = (*env)->NewGlobalRef(env, clazz); - ia_addrID = (*env)->GetFieldID(env, clazz, "address", "I"); - ia_famID = (*env)->GetFieldID(env, clazz, "family", "I"); - ia_ctorID = (*env)->GetMethodID(env, clazz, "", "()V"); + /* nothing to do */ } +JNIEXPORT jboolean JNICALL +Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) +{ + /* + * Return true if Windows Vista or newer, and IPv6 is configured + */ + OSVERSIONINFO ver; + ver.dwOSVersionInfoSize = sizeof(ver); + GetVersionEx(&ver); + if ((ver.dwPlatformId == VER_PLATFORM_WIN32_NT) && + (ver.dwMajorVersion >= 6) && ipv6_available()) + { + return JNI_TRUE; + } + return JNI_FALSE; +} JNIEXPORT jint JNICALL -Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean stream, - jboolean reuse) +Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, + jboolean stream, jboolean reuse) { SOCKET s; + int domain = (preferIPv6) ? AF_INET6 : AF_INET; - s = socket(AF_INET, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); + s = socket(domain, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); if (s != INVALID_SOCKET) { SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0); + + /* IPV6_V6ONLY is true by default */ + if (domain == AF_INET6) { + int opt = 0; + setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + (const char *)&opt, sizeof(opt)); + } } else { NET_ThrowNew(env, WSAGetLastError(), "socket"); } + return (jint)s; } JNIEXPORT void JNICALL -Java_sun_nio_ch_Net_bind(JNIEnv *env, jclass clazz, - jobject fdo, jobject iao, jint port) +Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jboolean preferIPv6, + jobject fdo, jobject iao, jint port) { SOCKETADDRESS sa; int rv; - int sa_len = sizeof(sa); + int sa_len; - if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, JNI_FALSE) != 0) { + if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { return; } @@ -89,16 +133,25 @@ Java_sun_nio_ch_Net_bind(JNIEnv *env, jclass clazz, NET_ThrowNew(env, WSAGetLastError(), "bind"); } +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) +{ + if (listen(fdval(env,fdo), backlog) == SOCKET_ERROR) { + NET_ThrowNew(env, WSAGetLastError(), "listen"); + } +} + + JNIEXPORT jint JNICALL -Java_sun_nio_ch_Net_connect(JNIEnv *env, jclass clazz, jobject fdo, jobject iao, - jint port, jint trafficClass) +Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, jobject fdo, + jobject iao, jint port) { SOCKETADDRESS sa; int rv; - int sa_len = sizeof(sa); + int sa_len; - if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, JNI_FALSE) != 0) { - return IOS_THROWN; + if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { + return IOS_THROWN; } rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); @@ -116,7 +169,7 @@ Java_sun_nio_ch_Net_connect(JNIEnv *env, jclass clazz, jobject fdo, jobject iao, JNIEXPORT jint JNICALL Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo) { - struct sockaddr_in sa; + SOCKETADDRESS sa; int sa_len = sizeof(sa); if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { @@ -127,50 +180,64 @@ Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo) NET_ThrowNew(env, error, "getsockname"); return IOS_THROWN; } - return (jint)ntohs(sa.sin_port); + return NET_GetPortFromSockaddr((struct sockaddr *)&sa); } JNIEXPORT jobject JNICALL Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo) { - struct sockaddr_in sa; + SOCKETADDRESS sa; int sa_len = sizeof(sa); - jobject iao; + int port; if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { NET_ThrowNew(env, WSAGetLastError(), "getsockname"); return NULL; } + return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); +} - iao = (*env)->NewObject(env, ia_class, ia_ctorID); - if (iao == NULL) { - JNU_ThrowOutOfMemoryError(env, "heap allocation failure"); - } else { - (*env)->SetIntField(env, iao, ia_addrID, ntohl(sa.sin_addr.s_addr)); - } +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo) +{ + SOCKETADDRESS sa; + int sa_len = sizeof(sa); - return iao; + if (getpeername(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { + int error = WSAGetLastError(); + if (error == WSAEINVAL) { + return 0; + } + NET_ThrowNew(env, error, "getsockname"); + return IOS_THROWN; + } + return NET_GetPortFromSockaddr((struct sockaddr *)&sa); } +JNIEXPORT jobject JNICALL +Java_sun_nio_ch_Net_remoteInetAddress(JNIEnv *env, jclass clazz, jobject fdo) +{ + SOCKETADDRESS sa; + int sa_len = sizeof(sa); + int port; + + if (getpeername(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { + NET_ThrowNew(env, WSAGetLastError(), "getsockname"); + return NULL; + } + return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); +} JNIEXPORT jint JNICALL -Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, - jobject fdo, jint opt) +Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, + jboolean mayNeedConversion, jint level, jint opt) { - int klevel, kopt; - int result; + int result = 0; struct linger linger; char *arg; - int arglen; - - if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) { - JNU_ThrowByNameWithLastError(env, - JNU_JAVANETPKG "SocketException", - "Unsupported socket option"); - return IOS_THROWN; - } + int arglen, n; - if (opt == java_net_SocketOptions_SO_LINGER) { + if (level == SOL_SOCKET && opt == SO_LINGER) { arg = (char *)&linger; arglen = sizeof(linger); } else { @@ -178,34 +245,40 @@ Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, arglen = sizeof(result); } - if (NET_GetSockOpt(fdval(env, fdo), klevel, kopt, arg, &arglen) < 0) { - NET_ThrowNew(env, WSAGetLastError(), "sun.nio.ch.Net.setIntOption"); + /** + * HACK: IP_TOS is deprecated on Windows and querying the option + * returns a protocol error. NET_GetSockOpt handles this and uses + * a fallback mechanism. + */ + if (level == IPPROTO_IP && opt == IP_TOS) { + mayNeedConversion = JNI_TRUE; + } + + if (mayNeedConversion) { + n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, &arglen); + } else { + n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen); + } + if (n < 0) { + handleSocketError(env, WSAGetLastError()); return IOS_THROWN; } - if (opt == java_net_SocketOptions_SO_LINGER) + if (level == SOL_SOCKET && opt == SO_LINGER) return linger.l_onoff ? linger.l_linger : -1; else return result; } JNIEXPORT void JNICALL -Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, - jobject fdo, jint opt, jint arg) +Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, + jboolean mayNeedConversion, jint level, jint opt, jint arg) { - int klevel, kopt; struct linger linger; char *parg; - int arglen; + int arglen, n; - if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) { - JNU_ThrowByNameWithLastError(env, - JNU_JAVANETPKG "SocketException", - "Unsupported socket option"); - return; - } - - if (opt == java_net_SocketOptions_SO_LINGER) { + if (level == SOL_SOCKET && opt == SO_LINGER) { parg = (char *)&linger; arglen = sizeof(linger); if (arg >= 0) { @@ -220,7 +293,200 @@ Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, arglen = sizeof(arg); } - if (NET_SetSockOpt(fdval(env, fdo), klevel, kopt, parg, arglen) < 0) { - NET_ThrowNew(env, WSAGetLastError(), "sun.nio.ch.Net.setIntOption"); + if (mayNeedConversion) { + n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen); + } else { + n = setsockopt(fdval(env, fdo), level, opt, parg, arglen); + } + if (n < 0) + handleSocketError(env, WSAGetLastError()); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo, + jint group, jint interf, jint source) +{ + struct ip_mreq mreq; + struct my_ip_mreq_source mreq_source; + int opt, n, optlen; + void* optval; + + if (source == 0) { + mreq.imr_multiaddr.s_addr = htonl(group); + mreq.imr_interface.s_addr = htonl(interf); + opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; + optval = (void*)&mreq; + optlen = sizeof(mreq); + } else { + mreq_source.imr_multiaddr.s_addr = htonl(group); + mreq_source.imr_sourceaddr.s_addr = htonl(source); + mreq_source.imr_interface.s_addr = htonl(interf); + opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; + optval = (void*)&mreq_source; + optlen = sizeof(mreq_source); + } + + n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); + if (n < 0) { + if (join && (WSAGetLastError() == WSAENOPROTOOPT)) + return IOS_UNAVAILABLE; + handleSocketError(env, WSAGetLastError()); + } + return 0; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo, + jint group, jint interf, jint source) +{ + struct my_ip_mreq_source mreq_source; + int n; + int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE; + + mreq_source.imr_multiaddr.s_addr = htonl(group); + mreq_source.imr_sourceaddr.s_addr = htonl(source); + mreq_source.imr_interface.s_addr = htonl(interf); + + n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, + (void*)&mreq_source, sizeof(mreq_source)); + if (n < 0) { + if (block && (WSAGetLastError() == WSAENOPROTOOPT)) + return IOS_UNAVAILABLE; + handleSocketError(env, WSAGetLastError()); + } + return 0; +} + +/** + * Call setsockopt with a IPPROTO_IPV6 level socket option + * and a group_source_req structure as the option value. The + * given IPv6 group, interface index, and IPv6 source address + * are copied into the structure. + */ +static int setGroupSourceReqOption(JNIEnv* env, + jobject fdo, + int opt, + jbyteArray group, + jint index, + jbyteArray source) +{ + struct my_group_source_req req; + struct sockaddr_in6* sin6; + + req.gsr_interface = (ULONG)index; + + sin6 = (struct sockaddr_in6*)&(req.gsr_group); + sin6->sin6_family = AF_INET6; + COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr)); + + sin6 = (struct sockaddr_in6*)&(req.gsr_source); + sin6->sin6_family = AF_INET6; + COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr)); + + return setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, (void*)&req, sizeof(req)); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo, + jbyteArray group, jint index, jbyteArray source) +{ + struct ipv6_mreq mreq6; + int n; + + if (source == NULL) { + int opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; + COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr)); + mreq6.ipv6mr_interface = (int)index; + n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, + (void*)&mreq6, sizeof(mreq6)); + } else { + int opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP; + n = setGroupSourceReqOption(env, fdo, opt, group, index, source); + } + + if (n < 0) { + handleSocketError(env, errno); + } + return 0; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo, + jbyteArray group, jint index, jbyteArray source) +{ + int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE; + int n = setGroupSourceReqOption(env, fdo, opt, group, index, source); + if (n < 0) { + handleSocketError(env, errno); + } + return 0; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf) +{ + struct in_addr in; + int arglen = sizeof(struct in_addr); + int n; + + in.s_addr = htonl(interf); + + n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, + (void*)&(in.s_addr), arglen); + if (n < 0) { + handleSocketError(env, WSAGetLastError()); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo) +{ + struct in_addr in; + int arglen = sizeof(struct in_addr); + int n; + + n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen); + if (n < 0) { + handleSocketError(env, WSAGetLastError()); + return IOS_THROWN; + } + return ntohl(in.s_addr); +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index) +{ + int value = (jint)index; + int arglen = sizeof(value); + int n; + + n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, + (void*)&(index), arglen); + if (n < 0) { + handleSocketError(env, errno); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo) +{ + int index; + int arglen = sizeof(index); + int n; + + n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen); + if (n < 0) { + handleSocketError(env, errno); + return -1; + } + return (jint)index; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) { + int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SD_RECEIVE : + (jhow == sun_nio_ch_Net_SHUT_WR) ? SD_SEND : SD_BOTH; + if (shutdown(fdval(env, fdo), how) == SOCKET_ERROR) { + NET_ThrowNew(env, WSAGetLastError(), "shutdown"); } } diff --git a/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c b/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c index 36b6006e0aa48aa4d1be16fefabdce338e706154..a597d25254e68b0a8d22980b727ab37f3c718b0b 100644 --- a/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c +++ b/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c @@ -46,10 +46,6 @@ static jfieldID fd_fdID; /* java.io.FileDescriptor.fd */ static jclass isa_class; /* java.net.InetSocketAddress */ static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */ -static jclass ia_class; /* java.net.InetAddress */ -static jmethodID ia_ctorID; /* InetAddress() */ -static jfieldID ia_addrID; /* java.net.InetAddress.address */ -static jfieldID ia_famID; /* java.net.InetAddress.family */ /************************************************************** @@ -66,12 +62,6 @@ Java_sun_nio_ch_ServerSocketChannelImpl_initIDs(JNIEnv *env, jclass cls) isa_class = (*env)->NewGlobalRef(env, cls); isa_ctorID = (*env)->GetMethodID(env, cls, "", "(Ljava/net/InetAddress;I)V"); - - cls = (*env)->FindClass(env, "java/net/Inet4Address"); - ia_class = (*env)->NewGlobalRef(env, cls); - ia_ctorID = (*env)->GetMethodID(env, cls, "","()V"); - ia_addrID = (*env)->GetFieldID(env, cls, "address", "I"); - ia_famID = (*env)->GetFieldID(env, cls, "family", "I"); } JNIEXPORT void JNICALL @@ -90,8 +80,9 @@ Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv *env, jobject this, { jint ssfd = (*env)->GetIntField(env, ssfdo, fd_fdID); jint newfd; - struct sockaddr_in sa; - jobject remote_ia = 0; + SOCKETADDRESS sa; + jobject remote_ia; + int remote_port; jobject isa; jobject ia; int addrlen = sizeof(sa); @@ -106,14 +97,13 @@ Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv *env, jobject this, JNU_ThrowIOExceptionWithLastError(env, "Accept failed"); return IOS_THROWN; } - (*env)->SetIntField(env, newfdo, fd_fdID, newfd); - ia = (*env)->NewObject(env, ia_class, ia_ctorID); - (*env)->SetIntField(env, ia, ia_addrID, ntohl(sa.sin_addr.s_addr)); - (*env)->SetIntField(env, ia, ia_famID, sa.sin_family); + (*env)->SetIntField(env, newfdo, fd_fdID, newfd); + remote_ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, (int *)&remote_port); - isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, - ntohs(sa.sin_port)); + isa = (*env)->NewObject(env, isa_class, isa_ctorID, + remote_ia, remote_port); (*env)->SetObjectArrayElement(env, isaa, 0, isa); + return 1; } diff --git a/src/windows/native/sun/nio/ch/SocketChannelImpl.c b/src/windows/native/sun/nio/ch/SocketChannelImpl.c index d49d9bf29ed779c2cffab831a83039b6a08f668e..1c899256812d16e8bb9b3ebdad2497c7d9b57c4f 100644 --- a/src/windows/native/sun/nio/ch/SocketChannelImpl.c +++ b/src/windows/native/sun/nio/ch/SocketChannelImpl.c @@ -139,12 +139,3 @@ Java_sun_nio_ch_SocketChannelImpl_checkConnect(JNIEnv *env, jobject this, return 0; } - -JNIEXPORT void JNICALL -Java_sun_nio_ch_SocketChannelImpl_shutdown(JNIEnv *env, jclass cl, - jobject fdo, jint how) -{ - if (shutdown(fdval(env, fdo), how) == SOCKET_ERROR) { - NET_ThrowNew(env, WSAGetLastError(), "shutdown"); - } -} diff --git a/test/com/sun/net/httpserver/bugs/B6744329.java b/test/com/sun/net/httpserver/bugs/B6744329.java new file mode 100644 index 0000000000000000000000000000000000000000..e09fce5be5400d3b89406b7685bb64044476a7b9 --- /dev/null +++ b/test/com/sun/net/httpserver/bugs/B6744329.java @@ -0,0 +1,106 @@ +/* + * Copyright 2005-2006 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. + * + * 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. + */ + +/** + * @test + * @bug 6744329 + * @summary Exception in light weight Http server + */ + +import com.sun.net.httpserver.*; + +import java.util.*; +import java.util.concurrent.*; +import java.io.*; +import java.net.*; +import java.security.*; +import java.security.cert.*; +import javax.net.ssl.*; + +public class B6744329 { + + public static void main (String[] args) throws Exception { + Handler handler = new Handler(); + InetSocketAddress addr = new InetSocketAddress (0); + HttpServer server = HttpServer.create (addr, 0); + HttpContext ctx = server.createContext ("/test", handler); + ExecutorService executor = Executors.newCachedThreadPool(); + server.setExecutor (executor); + server.start (); + + URL url = new URL ("http://localhost:"+server.getAddress().getPort()+"/test/foo.html"); + HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); + try { + InputStream is = urlc.getInputStream(); + int c = 0; + while (is.read()!= -1) { + c ++; + } + System.out.println ("OK"); + } catch (IOException e) { + System.out.println ("exception"); + error = true; + } + server.stop(2); + executor.shutdown(); + if (error) { + throw new RuntimeException ("Test failed"); + } + } + + public static boolean error = false; + + /* this must be the same size as in ChunkedOutputStream.java + */ + final static int CHUNK_SIZE = 4096; + + static class Handler implements HttpHandler { + int invocation = 1; + public void handle (HttpExchange t) + throws IOException + { + InputStream is = t.getRequestBody(); + Headers map = t.getRequestHeaders(); + Headers rmap = t.getResponseHeaders(); + while (is.read () != -1) ; + is.close(); + /* chunked response */ + t.sendResponseHeaders (200, 0); + OutputStream os = t.getResponseBody(); + byte[] first = new byte [CHUNK_SIZE * 2]; + byte[] second = new byte [2]; + os.write (first); + os.write ('x'); + os.write ('x'); + /* An index out of bounds exception will be thrown + * below, which is caught by server, and connection + * will be closed. resulting in IOException to client + * - if bug present + */ + os.write ('x'); + os.write ('x'); + os.write ('x'); + t.close(); + } + } +} diff --git a/test/com/sun/tools/extcheck/TestExtcheckArgs.java b/test/com/sun/tools/extcheck/TestExtcheckArgs.java new file mode 100644 index 0000000000000000000000000000000000000000..0e5514b875aaa40677e7c77d4a7831657b8bd4a0 --- /dev/null +++ b/test/com/sun/tools/extcheck/TestExtcheckArgs.java @@ -0,0 +1,92 @@ +/* + * 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. + * + * 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. + */ + +/** + * @test + * @bug 6356642 + * @summary Verify that extcheck exits appropriately when invalid args are given. + * @run shell TestExtcheckArgs.sh + * @author Dave Bristor + */ + +import java.io.File; +import com.sun.tools.extcheck.Main; + +/* + * Test extcheck by using Runtime.exec instead of invoking + * com.sun.tools.extcheck.Main.main, since the latter does its own + * System.exit under the conditions checked here. + */ +public class TestExtcheckArgs { + public static void realMain(String[] args) throws Throwable { + String testJar = System.getenv("TESTJAVA") + File.separator + + "lib" + File.separator + "jconsole.jar"; + + verify(new String[] { + }, Main.INSUFFICIENT); + verify(new String[] { + "-verbose" + }, Main.MISSING); + verify(new String[] { + "-verbose", + "foo" + }, Main.DOES_NOT_EXIST); + verify(new String[] { + testJar, + "bar" + }, Main.EXTRA); + verify(new String[] { + "-verbose", + testJar, + "bar" + }, Main.EXTRA); + } + + static void verify(String[] args, String expected) throws Throwable { + try { + Main.realMain(args); + fail(); + } catch (Exception ex) { + if (ex.getMessage().startsWith(expected)) { + pass(); + } else { + fail("Unexpected message: " + ex.getMessage()); + } + } + } + + //--------------------- Infrastructure --------------------------- + static volatile int passed = 0, failed = 0; + static boolean pass() {passed++; return true;} + static boolean fail() {failed++; Thread.dumpStack(); return false;} + static boolean fail(String msg) {System.out.println(msg); return fail();} + static void unexpected(Throwable t) {failed++; t.printStackTrace();} + static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;} + static boolean equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) return pass(); + else return fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + try {realMain(args);} catch (Throwable t) {unexpected(t);} + System.out.println("\nPassed = " + passed + " failed = " + failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} diff --git a/test/com/sun/tools/extcheck/TestExtcheckArgs.sh b/test/com/sun/tools/extcheck/TestExtcheckArgs.sh new file mode 100644 index 0000000000000000000000000000000000000000..3c478c1e13df00180c616b30092819059d4816da --- /dev/null +++ b/test/com/sun/tools/extcheck/TestExtcheckArgs.sh @@ -0,0 +1,47 @@ +#! /bin/sh + +# +# 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. +# +# 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. +# + +if [ "x$TESTJAVA" = x ]; then + TESTJAVA=$1; shift + TESTCLASSES=. + TESTSRC=. +fi +export TESTJAVA + +case "`uname`" in Windows*|CYGWIN* ) PS=';';; *) PS=':';; esac + +${TESTJAVA}/bin/javac -d ${TESTCLASSES} -classpath ${TESTJAVA}/lib/tools.jar${PS}${TESTCLASSES} ${TESTSRC}/TestExtcheckArgs.java +rc=$? +if [ $rc != 0 ]; then + echo Compilation failure with exit status $rc + exit $rc +fi + +${TESTJAVA}/bin/java -classpath ${TESTJAVA}/lib/tools.jar${PS}${TESTCLASSES} TestExtcheckArgs +rc=$? +if [ $rc != 0 ]; then + echo Execution failure with exit status $rc + exit $rc +fi diff --git a/test/java/lang/ThreadGroup/NullThreadName.java b/test/java/lang/ThreadGroup/NullThreadName.java new file mode 100644 index 0000000000000000000000000000000000000000..844fd93e2d815903b4994540027c76c95d0711cc --- /dev/null +++ b/test/java/lang/ThreadGroup/NullThreadName.java @@ -0,0 +1,85 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 6576763 + * @summary (thread) Thread constructors throw undocumented NPE for null name + */ + +/* + * Verify that threads constructed with a null thread name do not get added + * to the list of unstarted thread for a thread group. We can do this by + * checking that a daemon threadGroup is desroyed after its final valid thread + * has completed. + */ + +import java.util.concurrent.CountDownLatch; +import static java.lang.System.out; + +public class NullThreadName +{ + static CountDownLatch done = new CountDownLatch(1); + + public static void main(String args[]) throws Exception { + ThreadGroup tg = new ThreadGroup("chegar-threads"); + Thread goodThread = new Thread(tg, new GoodThread(), "goodThread"); + try { + Thread badThread = new Thread(tg, new Runnable(){ + @Override + public void run() {} }, null); + } catch (NullPointerException npe) { + out.println("OK, caught expected " + npe); + } + tg.setDaemon(true); + goodThread.start(); + + done.await(); + + int count = 0; + while (goodThread.isAlive()) { + /* Hold off a little to allow the thread to complete */ + out.println("GoodThread still alive, sleeping..."); + try { Thread.sleep(2000); } + catch (InterruptedException unused) {} + + /* do not wait forever */ + if (count++ > 5) + throw new AssertionError("GoodThread is still alive!"); + } + + if (!tg.isDestroyed()) { + throw new AssertionError("Failed: Thread group is not destroyed."); + } + } + + static class GoodThread implements Runnable + { + @Override + public void run() { + out.println("Good Thread started..."); + out.println("Good Thread finishing"); + done.countDown(); + } + } +} diff --git a/test/java/lang/reflect/Generics/TestPlainArrayNotGeneric.java b/test/java/lang/reflect/Generics/TestPlainArrayNotGeneric.java new file mode 100644 index 0000000000000000000000000000000000000000..63cb15a0c52761c15d391951a1c16ff9924ddd7f --- /dev/null +++ b/test/java/lang/reflect/Generics/TestPlainArrayNotGeneric.java @@ -0,0 +1,156 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 5041784 + * @summary Check that plain arrays like String[] are never represented as + * GenericArrayType. + * @author Eamonn McManus + */ + +import java.lang.reflect.Constructor; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.GenericDeclaration; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class TestPlainArrayNotGeneric { + public String[] m1(List p1) {return null;} + public List m2(String[] p1) {return null;} + public void m3(List p1, String[] p2) {} + public void m4(List p1) {} + public TestPlainArrayNotGeneric(List p1) {} + public TestPlainArrayNotGeneric(List p1, String[] p2) {} + + public > T m5(T p1) {return null;} + public T[] m6(T[] p1, List p2) {return null;} + + public List m6(List p1) {return null;} + public > T m7(T[] p1) {return null;} + public List m8(List p1) {return null;} + public > T[] m9(T[] p1) {return null;} + + public static interface XMap extends Map, String[]> {} + public static interface YMap, V> + extends Map {} + + + private static String lastFailure; + private static int failureCount; + + public static void main(String[] args) throws Exception { + checkClass(TestPlainArrayNotGeneric.class); + + if (failureCount == 0) + System.out.println("TEST PASSED"); + else + throw new Exception("TEST FAILED: Last failure: " + lastFailure); + } + + private static void checkClass(Class c) throws Exception { + Method[] methods = c.getMethods(); + for (Method m : methods) { + check(m.getGenericReturnType(), "return type of method " + m); + check(m.getGenericParameterTypes(), "parameter", "method " + m); + check(m.getTypeParameters(), "type parameter", "method " + m); + } + + Constructor[] constructors = c.getConstructors(); + for (Constructor constr : constructors) { + check(constr.getGenericParameterTypes(), "parameter", + "constructor " + constr); + check(constr.getTypeParameters(), "type parameter", + "constructor " + constr); + } + + Class[] inners = c.getDeclaredClasses(); + for (Class inner : inners) + checkClass(inner); + } + + private static void check(Type[] types, String elementKind, String what) { + for (int i = 0; i < types.length; i++) { + Type t = types[i]; + check(t, elementKind + " " + (i+1) + " of " + what); + } + } + + private static final Set checking = new HashSet(); + + private static void check(Type t, String what) { + if (t == null || !checking.add(t)) + return; + // Avoid infinite recursion. t can be null e.g. for superclass of Object. + try { + check2(t, what); + } finally { + checking.remove(t); + } + } + + private static void check2(Type t, String what) { + if (t instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) t; + check(pt.getActualTypeArguments(), "type argument", what); + } else if (t instanceof TypeVariable) { + TypeVariable tv = (TypeVariable) t; + check(tv.getBounds(), "bound", what); + GenericDeclaration gd = tv.getGenericDeclaration(); + if (gd instanceof Type) + check((Type) gd, "declaration containing " + what); + } else if (t instanceof WildcardType) { + WildcardType wt = (WildcardType) t; + check(wt.getLowerBounds(), "lower bound", "wildcard type in " + what); + check(wt.getUpperBounds(), "upper bound", "wildcard type in " + what); + } else if (t instanceof Class) { + Class c = (Class) t; + check(c.getGenericInterfaces(), "superinterface", c.toString()); + check(c.getGenericSuperclass(), "superclass of " + c); + check(c.getTypeParameters(), "type parameter", c.toString()); + } else if (t instanceof GenericArrayType) { + GenericArrayType gat = (GenericArrayType) t; + Type comp = gat.getGenericComponentType(); + if (comp instanceof Class) { + fail("Type " + t + " uses GenericArrayType when plain " + + "array would do, in " + what); + } else + check(comp, "component type of " + what); + } else { + fail("TEST BUG: mutant Type " + t + " (a " + t.getClass().getName() + ")"); + } + } + + private static void fail(String why) { + System.out.println("FAIL: " + why); + lastFailure = why; + failureCount++; + } +} diff --git a/test/java/net/CookieHandler/TestHttpCookie.java b/test/java/net/CookieHandler/TestHttpCookie.java index c62722704addd993d43ae665ce6eca93b2e5f7de..f18cf40b9049e687579f21be69205da0d404c716 100644 --- a/test/java/net/CookieHandler/TestHttpCookie.java +++ b/test/java/net/CookieHandler/TestHttpCookie.java @@ -24,7 +24,7 @@ /** * @test * @summary Unit test for java.net.HttpCookie - * @bug 6244040 6277796 6277801 6277808 6294071 + * @bug 6244040 6277796 6277801 6277808 6294071 6692802 * @author Edward Wang */ @@ -178,6 +178,19 @@ public class TestHttpCookie { } TestHttpCookie port(String p) { return port(0, p); } + // check http only + TestHttpCookie httpOnly(int index, boolean b) { + HttpCookie cookie = cookies.get(index); + if (cookie == null || b != cookie.isHttpOnly()) { + raiseError("HttpOnly", String.valueOf(cookie.isHttpOnly()), String.valueOf(b)); + } + return this; + } + + TestHttpCookie httpOnly(boolean b) { + return httpOnly(0, b); + } + // check equality static void eq(HttpCookie ck1, HttpCookie ck2, boolean same) { testCount++; @@ -362,6 +375,10 @@ public class TestHttpCookie { } catch (IllegalArgumentException ignored) { // expected exception; no-op } + + // CR 6692802: HttpOnly flag + test("set-cookie: CUSTOMER=WILE_E_COYOTE;HttpOnly").httpOnly(true); + test("set-cookie: CUSTOMER=WILE_E_COYOTE").httpOnly(false); } static void header(String prompt) { diff --git a/test/java/net/NetworkInterface/IndexTest.java b/test/java/net/NetworkInterface/IndexTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fd6e4780dcfffebe4cd18520809cb791b68f6591 --- /dev/null +++ b/test/java/net/NetworkInterface/IndexTest.java @@ -0,0 +1,58 @@ +/* + * 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. + * + * 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. + */ + +/* @test + * @bug 6717876 + * @summary Make java.net.NetworkInterface.getIndex() public + */ + +import java.net.*; +import java.util.Enumeration; + +public class IndexTest { + public static void main(String[] args) throws Exception { + Enumeration netifs = NetworkInterface.getNetworkInterfaces(); + NetworkInterface nif = null; + while (netifs.hasMoreElements()) { + nif = netifs.nextElement(); + int index = nif.getIndex(); + if (index >= 0) { + NetworkInterface nif2 = NetworkInterface.getByIndex(index); + if (! nif.equals(nif2)) { + throw new RuntimeException("both interfaces should be equal"); + } + } + } + try { + nif = NetworkInterface.getByIndex(-1); + throw new RuntimeException("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // OK + } + // In all likelyhood, this interface should not exist. + nif = NetworkInterface.getByIndex(Integer.MAX_VALUE - 1); + if (nif != null) { + throw new RuntimeException("getByIndex() should have returned null"); + } + } +} diff --git a/test/java/nio/BufferPoolMXBean/Basic.java b/test/java/nio/BufferPoolMXBean/Basic.java new file mode 100644 index 0000000000000000000000000000000000000000..98e5f0e0bd9ba0c136711db0fe1ccc09b33e48a5 --- /dev/null +++ b/test/java/nio/BufferPoolMXBean/Basic.java @@ -0,0 +1,106 @@ +/* + * 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. + * + * 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. + */ + +/* @test + * @bug 6606598 + * @summary Unit test for java.nio.BufferPoolMXBean + */ + +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.BufferPoolMXBean; +import java.nio.channels.FileChannel; +import java.io.File; +import java.io.RandomAccessFile; +import java.lang.management.ManagementFactory; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import java.util.*; + +public class Basic { + + // static fields to ensure buffers aren't GC'ed + static List buffers; + static MappedByteBuffer mbb; + + // check counters + static void check(List pools, + int minBufferCount, + long minTotalCapacity) + { + int bufferCount = 0; + long totalCap = 0; + long totalMem = 0; + for (BufferPoolMXBean pool: pools) { + bufferCount += pool.getCount(); + totalCap += pool.getTotalCapacity(); + totalMem += pool.getMemoryUsed(); + } + if (bufferCount < minBufferCount) + throw new RuntimeException("Count less than expected"); + if (totalMem < minTotalCapacity) + throw new RuntimeException("Memory usage less than expected"); + if (totalCap < minTotalCapacity) + throw new RuntimeException("Total capacity less than expected"); + } + + public static void main(String[] args) throws Exception { + Random rand = new Random(); + + // allocate a few direct buffers + int bufferCount = 5 + rand.nextInt(20); + buffers = new ArrayList(bufferCount); + long totalCapacity = 0L; + for (int i=0; i pools = + ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class); + check(pools, bufferCount, totalCapacity); + + // using MBeanServer + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + Set mbeans = server.queryNames( + new ObjectName("java.nio:type=BufferPool,*"), null); + pools = new ArrayList(); + for (ObjectName name: mbeans) { + BufferPoolMXBean pool = ManagementFactory + .newPlatformMXBeanProxy(server, name.toString(), BufferPoolMXBean.class); + pools.add(pool); + } + check(pools, bufferCount, totalCapacity); + } +} diff --git a/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java b/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java new file mode 100644 index 0000000000000000000000000000000000000000..03b5daa68f10126f1675fbe68fece8ced9ce3b03 --- /dev/null +++ b/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java @@ -0,0 +1,220 @@ +/* + * 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. + * + * 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. + */ + +/* @test + * @bug 4527345 + * @summary Unit test for DatagramChannel's multicast support + * @build BasicMulticastTests NetworkConfiguration + */ + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.net.*; +import java.util.*; +import java.io.IOException; + +public class BasicMulticastTests { + + /** + * Tests that existing membership key is returned by join methods and that + * membership key methods return the expected results + */ + static void membershipKeyTests(NetworkInterface nif, + InetAddress group, + InetAddress source) + throws IOException + { + System.out.format("MembershipKey test using %s @ %s\n", + group.getHostAddress(), nif.getName()); + + ProtocolFamily family = (group instanceof Inet4Address) ? + StandardProtocolFamily.INET : StandardProtocolFamily.INET6; + + DatagramChannel dc = DatagramChannel.open(family) + .setOption(StandardSocketOption.SO_REUSEADDR, true) + .bind(new InetSocketAddress(source, 0)); + + // check existing key is returned + MembershipKey key = dc.join(group, nif); + MembershipKey other = dc.join(group, nif); + if (other != key) { + throw new RuntimeException("existing key not returned"); + } + + // check key + if (!key.isValid()) + throw new RuntimeException("key is not valid"); + if (!key.getGroup().equals(group)) + throw new RuntimeException("group is incorrect"); + if (!key.getNetworkInterface().equals(nif)) + throw new RuntimeException("network interface is incorrect"); + if (key.getSourceAddress() != null) + throw new RuntimeException("key is source specific"); + + // drop membership + key.drop(); + if (key.isValid()) { + throw new RuntimeException("key is still valid"); + } + + // source-specific + try { + key = dc.join(group, nif, source); + other = dc.join(group, nif, source); + if (other != key) { + throw new RuntimeException("existing key not returned"); + } + if (!key.isValid()) + throw new RuntimeException("key is not valid"); + if (!key.getGroup().equals(group)) + throw new RuntimeException("group is incorrect"); + if (!key.getNetworkInterface().equals(nif)) + throw new RuntimeException("network interface is incorrect"); + if (!key.getSourceAddress().equals(source)) + throw new RuntimeException("key's source address incorrect"); + + // drop membership + key.drop(); + if (key.isValid()) { + throw new RuntimeException("key is still valid"); + } + } catch (UnsupportedOperationException x) { + } + + // done + dc.close(); + } + + /** + * Tests exceptions for invalid arguments or scenarios + */ + static void exceptionTests(NetworkInterface nif) + throws IOException + { + System.out.println("Exception Tests"); + + DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET) + .setOption(StandardSocketOption.SO_REUSEADDR, true) + .bind(new InetSocketAddress(0)); + + InetAddress group = InetAddress.getByName("225.4.5.6"); + InetAddress notGroup = InetAddress.getByName("1.2.3.4"); + InetAddress thisHost = InetAddress.getLocalHost(); + + // IllegalStateException + MembershipKey key; + key = dc.join(group, nif); + try { + dc.join(group, nif, thisHost); + throw new RuntimeException("IllegalStateException not thrown"); + } catch (IllegalStateException x) { + } catch (UnsupportedOperationException x) { + } + key.drop(); + try { + key = dc.join(group, nif, thisHost); + try { + dc.join(group, nif); + throw new RuntimeException("IllegalStateException not thrown"); + } catch (IllegalStateException x) { + } + key.drop(); + } catch (UnsupportedOperationException x) { + } + + // IllegalArgumentException + try { + dc.join(notGroup, nif); + throw new RuntimeException("IllegalArgumentException not thrown"); + } catch (IllegalArgumentException x) { + } + try { + dc.join(notGroup, nif, thisHost); + throw new RuntimeException("IllegalArgumentException not thrown"); + } catch (IllegalArgumentException x) { + } catch (UnsupportedOperationException x) { + } + + // NullPointerException + try { + dc.join(null, nif); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + dc.join(group, null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + dc.join(group, nif, null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } catch (UnsupportedOperationException x) { + } + + dc.close(); + + // ClosedChannelException + try { + dc.join(group, nif); + throw new RuntimeException("ClosedChannelException not thrown"); + } catch (ClosedChannelException x) { + } + try { + dc.join(group, nif, thisHost); + throw new RuntimeException("ClosedChannelException not thrown"); + } catch (ClosedChannelException x) { + } catch (UnsupportedOperationException x) { + } + } + + + /** + * Probe interfaces to get interfaces that support IPv4 or IPv6 multicasting + * and invoke tests. + */ + public static void main(String[] args) throws IOException { + + // multicast groups used for the test + InetAddress ip4Group = InetAddress.getByName("225.4.5.6"); + InetAddress ip6Group = InetAddress.getByName("ff02::a"); + + + NetworkConfiguration config = NetworkConfiguration.probe(); + + NetworkInterface nif = config.ip4Interfaces().iterator().next(); + InetAddress anySource = config.ip4Addresses(nif).iterator().next(); + membershipKeyTests(nif, ip4Group, anySource); + exceptionTests(nif); + + // re-run the membership key tests with IPv6 if available + + Iterator iter = config.ip6Interfaces().iterator(); + if (iter.hasNext()) { + nif = iter.next(); + anySource = config.ip6Addresses(nif).iterator().next(); + membershipKeyTests(nif, ip6Group, anySource); + } + } +} diff --git a/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java b/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java new file mode 100644 index 0000000000000000000000000000000000000000..11e3b0be068c28d59baf9e60177dc88a543f6e9d --- /dev/null +++ b/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java @@ -0,0 +1,220 @@ +/* + * 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. + * + * 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. + */ + +/* @test + * @bug 4527345 + * @summary Unit test for DatagramChannel's multicast support + * @build MulticastSendReceiveTests NetworkConfiguration + */ + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.net.*; +import java.util.*; +import java.io.IOException; + +public class MulticastSendReceiveTests { + + static Random rand = new Random(); + + /** + * Send datagram from given local address to given multicast + * group. + */ + static int sendDatagram(InetAddress local, + NetworkInterface nif, + InetAddress group, + int port) + throws IOException + { + ProtocolFamily family = (group instanceof Inet6Address) ? + StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; + DatagramChannel dc = DatagramChannel.open(family) + .bind(new InetSocketAddress(local, 0)) + .setOption(StandardSocketOption.IP_MULTICAST_IF, nif); + int id = rand.nextInt(); + byte[] msg = Integer.toString(id).getBytes("UTF-8"); + ByteBuffer buf = ByteBuffer.wrap(msg); + System.out.format("Send message from %s -> group %s (id=0x%x)\n", + local.getHostAddress(), group.getHostAddress(), id); + dc.send(buf, new InetSocketAddress(group, port)); + dc.close(); + return id; + } + + /** + * Wait (with timeout) for datagram. + * + * @param expectedSender - expected sender address, or + * null if no datagram expected + * @param id - expected id of datagram + */ + static void receiveDatagram(DatagramChannel dc, + InetAddress expectedSender, + int id) + throws IOException + { + Selector sel = Selector.open(); + dc.configureBlocking(false); + dc.register(sel, SelectionKey.OP_READ); + ByteBuffer buf = ByteBuffer.allocateDirect(100); + + try { + for (;;) { + System.out.println("Waiting to receive message"); + sel.select(5*1000); + SocketAddress sa = dc.receive(buf); + + // no datagram received + if (sa == null) { + if (expectedSender != null) { + throw new RuntimeException("Expected message not recieved"); + } + System.out.println("No message received (correct)"); + return; + } + + // datagram received + + InetAddress sender = ((InetSocketAddress)sa).getAddress(); + buf.flip(); + byte[] bytes = new byte[buf.remaining()]; + buf.get(bytes); + int receivedId = Integer.parseInt(new String(bytes)); + + System.out.format("Received message from %s (id=0x%x)\n", + sender, receivedId); + + if (expectedSender == null) { + if (receivedId == id) + throw new RuntimeException("Message not expected"); + System.out.println("Message ignored (has wrong id)"); + } else { + if (sender.equals(expectedSender)) { + System.out.println("Message expected"); + return; + } + System.out.println("Message ignored (wrong sender)"); + } + + sel.selectedKeys().clear(); + buf.rewind(); + } + } finally { + sel.close(); + } + } + + + /** + * Exercise multicast send/receive on given group/interface + */ + static void test(NetworkInterface nif, InetAddress group, InetAddress source) + throws IOException + { + ProtocolFamily family = (group instanceof Inet6Address) ? + StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; + System.out.format("create channel to %s socket\n", family.name()); + DatagramChannel dc = DatagramChannel.open(family) + .setOption(StandardSocketOption.SO_REUSEADDR, true) + .bind(new InetSocketAddress(0)); + + // join group + System.out.format("join %s @ %s\n", group.getHostAddress(), + nif.getName()); + MembershipKey key = dc.join(group, nif); + + // send message to group + int port = ((InetSocketAddress)dc.getLocalAddress()).getPort(); + int id = sendDatagram(source, nif, group, port); + + // receive message and check id matches + receiveDatagram(dc, source, id); + + // exclude-mode filtering + + try { + System.out.format("block %s\n", source.getHostAddress()); + + // may throw UOE + key.block(source); + id = sendDatagram(source, nif, group, port); + receiveDatagram(dc, null, id); + + // unblock source, send message, message should be received + System.out.format("unblock %s\n", source.getHostAddress()); + key.unblock(source); + id = sendDatagram(source, nif, group, port); + receiveDatagram(dc, source, id); + } catch (UnsupportedOperationException x) { + System.out.println("Exclude-mode filtering not supported!"); + } + + key.drop(); + + // include-mode filtering + + InetAddress bogus = (group instanceof Inet6Address) ? + InetAddress.getByName("fe80::1234") : + InetAddress.getByName("1.2.3.4"); + System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(), + nif.getName(), bogus.getHostAddress()); + try { + // may throw UOE + key = dc.join(group, nif, bogus); + + id = sendDatagram(source, nif, group, port); + receiveDatagram(dc, null, id); + + System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(), + nif.getName(), source.getHostAddress()); + key = dc.join(group, nif, source); + + id = sendDatagram(source, nif, group, port); + receiveDatagram(dc, source, id); + } catch (UnsupportedOperationException x) { + System.out.println("Include-mode filtering not supported!"); + } + + // done + dc.close(); + } + + public static void main(String[] args) throws IOException { + NetworkConfiguration config = NetworkConfiguration.probe(); + + // multicast groups used for the test + InetAddress ip4Group = InetAddress.getByName("225.4.5.6"); + InetAddress ip6Group = InetAddress.getByName("ff02::a"); + + for (NetworkInterface nif: config.ip4Interfaces()) { + InetAddress source = config.ip4Addresses(nif).iterator().next(); + test(nif, ip4Group, source); + } + + for (NetworkInterface nif: config.ip6Interfaces()) { + InetAddress source = config.ip6Addresses(nif).iterator().next(); + test(nif, ip6Group, source); + } + } +} diff --git a/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java b/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..f1d7d5debc6f75fc9a27b44156857ac3c4b568f2 --- /dev/null +++ b/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java @@ -0,0 +1,97 @@ +/* + * 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. + * + * 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. + */ + +import java.net.*; +import java.util.*; +import java.io.IOException; + +/** + * Helper class for multicasting tests. + */ + +class NetworkConfiguration { + + private Map> ip4Interfaces; + private Map> ip6Interfaces; + + private NetworkConfiguration(Map> ip4Interfaces, + Map> ip6Interfaces) + { + this.ip4Interfaces = ip4Interfaces; + this.ip6Interfaces = ip6Interfaces; + } + + Iterable ip4Interfaces() { + return ip4Interfaces.keySet(); + } + + Iterable ip6Interfaces() { + return ip6Interfaces.keySet(); + } + + Iterable ip4Addresses(NetworkInterface nif) { + return ip4Interfaces.get(nif); + } + + Iterable ip6Addresses(NetworkInterface nif) { + return ip6Interfaces.get(nif); + } + + static NetworkConfiguration probe() throws IOException { + Map> ip4Interfaces = + new HashMap>(); + Map> ip6Interfaces = + new HashMap>(); + + // find the interfaces that support IPv4 and IPv6 + List nifs = Collections + .list(NetworkInterface.getNetworkInterfaces()); + for (NetworkInterface nif: nifs) { + // ignore intertaces that are down or don't support multicast + if (!nif.isUp() || !nif.supportsMulticast() || nif.isLoopback()) + continue; + + List addrs = Collections.list(nif.getInetAddresses()); + for (InetAddress addr: addrs) { + if (addr instanceof Inet4Address) { + List list = ip4Interfaces.get(nif); + if (list == null) { + list = new LinkedList(); + } + list.add(addr); + ip4Interfaces.put(nif, list); + } + if (addr instanceof Inet6Address) { + List list = ip6Interfaces.get(nif); + if (list == null) { + list = new LinkedList(); + } + list.add(addr); + ip6Interfaces.put(nif, list); + + } + } + } + return new NetworkConfiguration(ip4Interfaces, ip6Interfaces); + } +} diff --git a/test/java/nio/channels/DatagramChannel/SocketOptionTests.java b/test/java/nio/channels/DatagramChannel/SocketOptionTests.java new file mode 100644 index 0000000000000000000000000000000000000000..e4e85b11fb45a9c05045cc2ed571bc6bfe7172fc --- /dev/null +++ b/test/java/nio/channels/DatagramChannel/SocketOptionTests.java @@ -0,0 +1,115 @@ +/* + * 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. + * + * 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. + */ + +/* @test + * @bug 4640544 + * @summary Unit test for setOption/getOption/options methods + */ + +import java.nio.*; +import java.nio.channels.*; +import java.net.*; +import java.io.IOException; +import java.util.*; +import static java.net.StandardSocketOption.*; + +public class SocketOptionTests { + + static void checkOption(DatagramChannel dc, + SocketOption name, + T expectedValue) + throws IOException + { + T value = dc.getOption(name); + if (!value.equals(expectedValue)) + throw new RuntimeException("value not as expected"); + } + + public static void main(String[] args) throws IOException { + DatagramChannel dc = DatagramChannel.open(); + + // check supported options + Set> options = dc.options(); + List> expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF, + SO_REUSEADDR, SO_BROADCAST, IP_TOS, IP_MULTICAST_IF, IP_MULTICAST_TTL, + IP_MULTICAST_LOOP); + for (SocketOption opt: expected) { + if (!options.contains(opt)) + throw new RuntimeException(opt.name() + " should be supported"); + } + + // check specified defaults + checkOption(dc, SO_BROADCAST, false); + checkOption(dc, IP_MULTICAST_TTL, 1); // true on supported platforms + checkOption(dc, IP_MULTICAST_LOOP, true); // true on supported platforms + + // allowed to change when not bound + dc.setOption(SO_BROADCAST, true); + checkOption(dc, SO_BROADCAST, true); + dc.setOption(SO_BROADCAST, false); + checkOption(dc, SO_BROADCAST, false); + dc.setOption(SO_SNDBUF, 16*1024); // can't check + dc.setOption(SO_RCVBUF, 16*1024); // can't check + dc.setOption(SO_REUSEADDR, true); + checkOption(dc, SO_REUSEADDR, true); + dc.setOption(SO_REUSEADDR, false); + checkOption(dc, SO_REUSEADDR, false); + + // bind socket + dc.bind(new InetSocketAddress(0)); + + // allow to change when bound + dc.setOption(SO_BROADCAST, true); + checkOption(dc, SO_BROADCAST, true); + dc.setOption(SO_BROADCAST, false); + checkOption(dc, SO_BROADCAST, false); + dc.setOption(IP_TOS, 0x08); // can't check + dc.setOption(IP_MULTICAST_TTL, 2); + checkOption(dc, IP_MULTICAST_TTL, 2); + dc.setOption(IP_MULTICAST_LOOP, false); + checkOption(dc, IP_MULTICAST_LOOP, false); + dc.setOption(IP_MULTICAST_LOOP, true); + checkOption(dc, IP_MULTICAST_LOOP, true); + + + // NullPointerException + try { + dc.setOption(null, "value"); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + dc.getOption(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + + // ClosedChannelException + dc.close(); + try { + dc.setOption(IP_MULTICAST_LOOP, true); + throw new RuntimeException("ClosedChannelException not thrown"); + } catch (ClosedChannelException x) { + } + } +} diff --git a/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java b/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java new file mode 100644 index 0000000000000000000000000000000000000000..6c4a443ed0af23949405e9e17f084c20332fe5dd --- /dev/null +++ b/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java @@ -0,0 +1,84 @@ +/* + * 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. + * + * 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. + */ + +/* @test + * @bug 4640544 + * @summary Unit test for ServerSocketChannel setOption/getOption/options + * methods. + */ + +import java.nio.*; +import java.nio.channels.*; +import java.net.*; +import java.io.IOException; +import java.util.*; +import static java.net.StandardSocketOption.*; + +public class SocketOptionTests { + + static void checkOption(ServerSocketChannel ssc, SocketOption name, Object expectedValue) + throws IOException + { + Object value = ssc.getOption(name); + if (!value.equals(expectedValue)) + throw new RuntimeException("value not as expected"); + } + + public static void main(String[] args) throws IOException { + ServerSocketChannel ssc = ServerSocketChannel.open(); + + // check supported options + Set> options = ssc.options(); + if (!options.contains(SO_REUSEADDR)) + throw new RuntimeException("SO_REUSEADDR should be supported"); + if (!options.contains(SO_RCVBUF)) + throw new RuntimeException("SO_RCVBUF should be supported"); + + // allowed to change when not bound + ssc.setOption(SO_RCVBUF, 256*1024); // can't check + ssc.setOption(SO_REUSEADDR, true); + checkOption(ssc, SO_REUSEADDR, true); + ssc.setOption(SO_REUSEADDR, false); + checkOption(ssc, SO_REUSEADDR, false); + + // NullPointerException + try { + ssc.setOption(null, "value"); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + ssc.getOption(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + + // ClosedChannelException + ssc.close(); + try { + ssc.setOption(SO_REUSEADDR, true); + throw new RuntimeException("ClosedChannelException not thrown"); + } catch (ClosedChannelException x) { + } + } +} diff --git a/test/java/nio/channels/SocketChannel/SocketOptionTests.java b/test/java/nio/channels/SocketChannel/SocketOptionTests.java new file mode 100644 index 0000000000000000000000000000000000000000..b6fadced8e28c69ed078dd4609f75b5f8ecc429b --- /dev/null +++ b/test/java/nio/channels/SocketChannel/SocketOptionTests.java @@ -0,0 +1,129 @@ +/* + * 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. + * + * 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. + */ + +/* @test + * @bug 4640544 + * @summary Unit test to check SocketChannel setOption/getOption/options + * methods. + */ + +import java.nio.*; +import java.nio.channels.*; +import java.net.*; +import java.io.IOException; +import java.util.*; +import static java.net.StandardSocketOption.*; + +public class SocketOptionTests { + + static void checkOption(SocketChannel sc, SocketOption name, Object expectedValue) + throws IOException + { + Object value = sc.getOption(name); + if (!value.equals(expectedValue)) + throw new RuntimeException("value not as expected"); + } + + public static void main(String[] args) throws IOException { + SocketChannel sc = SocketChannel.open(); + + // check supported options + Set> options = sc.options(); + List expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF, + SO_KEEPALIVE, SO_REUSEADDR, SO_LINGER, TCP_NODELAY); + for (SocketOption opt: expected) { + if (!options.contains(opt)) + throw new RuntimeException(opt.name() + " should be supported"); + } + + // check specified defaults + int linger = sc.getOption(SO_LINGER); + if (linger >= 0) + throw new RuntimeException("initial value of SO_LINGER should be < 0"); + checkOption(sc, SO_KEEPALIVE, false); + checkOption(sc, TCP_NODELAY, false); + + // allowed to change when not bound + sc.setOption(SO_KEEPALIVE, true); + checkOption(sc, SO_KEEPALIVE, true); + sc.setOption(SO_KEEPALIVE, false); + checkOption(sc, SO_KEEPALIVE, false); + sc.setOption(SO_SNDBUF, 128*1024); // can't check + sc.setOption(SO_RCVBUF, 256*1024); // can't check + sc.setOption(SO_REUSEADDR, true); + checkOption(sc, SO_REUSEADDR, true); + sc.setOption(SO_REUSEADDR, false); + checkOption(sc, SO_REUSEADDR, false); + sc.setOption(SO_LINGER, 10); + linger = sc.getOption(SO_LINGER); + if (linger < 1) + throw new RuntimeException("expected linger to be enabled"); + sc.setOption(SO_LINGER, -1); + linger = sc.getOption(SO_LINGER); + if (linger >= 0) + throw new RuntimeException("expected linger to be disabled"); + sc.setOption(TCP_NODELAY, true); + checkOption(sc, TCP_NODELAY, true); + sc.setOption(TCP_NODELAY, false); // can't check + + // bind socket + sc.bind(new InetSocketAddress(0)); + + // allow to change when bound + sc.setOption(SO_KEEPALIVE, true); + checkOption(sc, SO_KEEPALIVE, true); + sc.setOption(SO_KEEPALIVE, false); + checkOption(sc, SO_KEEPALIVE, false); + + sc.setOption(SO_LINGER, 10); + linger = sc.getOption(SO_LINGER); + if (linger < 1) + throw new RuntimeException("expected linger to be enabled"); + sc.setOption(SO_LINGER, -1); + linger = sc.getOption(SO_LINGER); + if (linger >= 0) + throw new RuntimeException("expected linger to be disabled"); + sc.setOption(TCP_NODELAY, true); // can't check + sc.setOption(TCP_NODELAY, false); // can't check + + // NullPointerException + try { + sc.setOption(null, "value"); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + try { + sc.getOption(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException x) { + } + + // ClosedChannelException + sc.close(); + try { + sc.setOption(TCP_NODELAY, true); + throw new RuntimeException("ClosedChannelException not thrown"); + } catch (ClosedChannelException x) { + } + } +} diff --git a/test/java/nio/channels/TestUtil.java b/test/java/nio/channels/TestUtil.java index 63e8537eadf75577f3e5af1897d69bed48d49ab1..8a8449e0043332de2d866d91bb7daaffe4bcc901 100644 --- a/test/java/nio/channels/TestUtil.java +++ b/test/java/nio/channels/TestUtil.java @@ -38,7 +38,7 @@ public class TestUtil { // executing in a different network. public static final String HOST = "javaweb.sfbay.sun.com"; public static final String REFUSING_HOST = "jano1.sfbay.sun.com"; - public static final String FAR_HOST = "theclub.ireland.sun.com"; + public static final String FAR_HOST = "irejano.ireland.sun.com"; public static final String UNRESOLVABLE_HOST = "blah-blah.blah-blah.blah"; private TestUtil() { } @@ -102,5 +102,4 @@ public class TestUtil { static boolean onWindows() { return osName.startsWith("Windows"); } - } diff --git a/test/java/nio/channels/etc/NetworkChannelTests.java b/test/java/nio/channels/etc/NetworkChannelTests.java new file mode 100644 index 0000000000000000000000000000000000000000..5f03453ca11aba193c5c0f8299f6b589956f4ea9 --- /dev/null +++ b/test/java/nio/channels/etc/NetworkChannelTests.java @@ -0,0 +1,187 @@ +/* + * 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. + * + * 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. + */ + +/* @test + * @bug 4640544 + * @summary Unit test for channels that implement NetworkChannel + */ + +import java.nio.*; +import java.nio.channels.*; +import java.net.*; +import java.io.IOException; +import java.util.*; + +public class NetworkChannelTests { + + static interface ChannelFactory { + NetworkChannel open() throws IOException; + } + + static class BogusSocketAddress extends SocketAddress { + } + + /** + * Exercise bind method. + */ + static void bindTests(ChannelFactory factory) throws IOException { + NetworkChannel ch; + + // AlreadyBoundException + ch = factory.open().bind(new InetSocketAddress(0)); + try { + ch.bind(new InetSocketAddress(0)); + throw new RuntimeException("AlreadyBoundException not thrown"); + } catch (AlreadyBoundException x) { + } + ch.close(); + + // bind(null) + ch = factory.open().bind(null); + if (ch.getLocalAddress() == null) + throw new RuntimeException("socket not found"); + ch.close(); + + // UnsupportedAddressTypeException + ch = factory.open(); + try { + ch.bind(new BogusSocketAddress()); + throw new RuntimeException("UnsupportedAddressTypeException not thrown"); + } catch (UnsupportedAddressTypeException x) { + } + ch.close(); + + // ClosedChannelException + try { + ch.bind(new InetSocketAddress(0)); + throw new RuntimeException("ClosedChannelException not thrown"); + } catch (ClosedChannelException x) { + } + } + + /** + * Exercise getLocalAddress method. + */ + static void localAddressTests(ChannelFactory factory) throws IOException { + NetworkChannel ch; + + // not bound + ch = factory.open(); + if (ch.getLocalAddress() != null) { + throw new RuntimeException("Local address returned when not bound"); + } + + // bound + InetSocketAddress local = + (InetSocketAddress)(ch.bind(new InetSocketAddress(0)).getLocalAddress()); + if (!local.getAddress().isAnyLocalAddress()) { + if (NetworkInterface.getByInetAddress(local.getAddress()) == null) + throw new RuntimeException("not bound to local address"); + } + if (local.getPort() <= 0) + throw new RuntimeException("not bound to local port"); + + // closed + ch.close(); + if (ch.getLocalAddress() != null) { + throw new RuntimeException("Local address return when closed"); + } + } + + /** + * Exercise getConnectedAddress method (SocketChannel only) + */ + static void connectedAddressTests() throws IOException { + ServerSocketChannel ssc = ServerSocketChannel.open() + .bind(new InetSocketAddress(0)); + InetSocketAddress local = (InetSocketAddress)(ssc.getLocalAddress()); + int port = local.getPort(); + InetSocketAddress server = new InetSocketAddress(InetAddress.getLocalHost(), port); + + SocketChannel sc = SocketChannel.open(); + + // not connected + if (sc.getConnectedAddress() != null) + throw new RuntimeException("getConnectedAddress returned address when not connected"); + + // connected + sc.connect(server); + SocketAddress remote = sc.getConnectedAddress(); + if (!remote.equals(server)) + throw new RuntimeException("getConnectedAddress returned incorrect address"); + + // closed + sc.close(); + if (sc.getConnectedAddress() != null) + throw new RuntimeException("getConnectedAddress returned address when closed"); + + ssc.close(); + } + + public static void main(String[] args) throws IOException { + ChannelFactory factory; + + // -- SocketChannel -- + + factory = new ChannelFactory() { + public NetworkChannel open() throws IOException { + return SocketChannel.open(); + } + }; + + bindTests(factory); + localAddressTests(factory); + connectedAddressTests(); + + // -- ServerSocketChannel -- + + factory = new ChannelFactory() { + public NetworkChannel open() throws IOException { + return ServerSocketChannel.open(); + } + }; + + bindTests(factory); + localAddressTests(factory); + + // backlog values + ServerSocketChannel.open() + .bind(new InetSocketAddress(0), 100).close(); + ServerSocketChannel.open() + .bind(new InetSocketAddress(0), 0).close(); + ServerSocketChannel.open() + .bind(new InetSocketAddress(0), -1).close(); + + // -- DatagramChannel -- + + factory = new ChannelFactory() { + public NetworkChannel open() throws IOException { + return DatagramChannel.open(); + } + }; + + bindTests(factory); + localAddressTests(factory); + } + +} diff --git a/test/java/util/EnumSet/BogusEnumSet.java b/test/java/util/EnumSet/BogusEnumSet.java new file mode 100644 index 0000000000000000000000000000000000000000..3fcb0a7895d9d5d499221cafc58ff0bbff562d25 --- /dev/null +++ b/test/java/util/EnumSet/BogusEnumSet.java @@ -0,0 +1,93 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 6739302 + * @summary Check that deserialization preserves EnumSet integrity + * @author Josh Bloch + */ + +import java.util.*; +import java.io.*; + +public class BogusEnumSet { + public static void main(String[] args) throws Throwable { + byte[] serializedForm = { + (byte)0xac, (byte)0xed, 0x0, 0x5, 0x73, 0x72, 0x0, 0x18, + 0x6a, 0x61, 0x76, 0x61, 0x2e, 0x75, 0x74, 0x69, + 0x6c, 0x2e, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x45, + 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x74, 0x2f, 0x58, 0x6f, (byte)0xc7, + 0x7e, (byte)0xb0, (byte)0xd0, 0x7e, 0x2, 0x0, 0x1, 0x4a, 0x0, 0x8, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x78, 0x72, 0x0, + 0x11, 0x6a, 0x61, 0x76, 0x61, 0x2e, 0x75, 0x74, 0x69, + 0x6c, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x74, 0xe, + 0x3, 0x21, 0x6a, (byte)0xcd, (byte)0x8c, 0x29, (byte)0xdd, 0x2, + 0x0, 0x2, 0x4c, 0x0, 0xb, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x74, 0x0, 0x11, 0x4c, 0x6a, 0x61, 0x76, + 0x61, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x3b, 0x5b, 0x0, 0x8, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, + 0x73, 0x65, 0x74, 0x0, 0x11, 0x5b, 0x4c, 0x6a, 0x61, 0x76, 0x61, + 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x45, 0x6e, 0x75, 0x6d, 0x3b, + 0x78, 0x70, 0x76, 0x72, 0x0, 0x16, 0x6a, 0x61, 0x76, 0x61, 0x2e, + 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x54, 0x68, 0x72, 0x65, 0x61, + 0x64, 0x24, 0x53, 0x74, 0x61, 0x74, 0x65, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x78, 0x72, 0x0, 0xe, 0x6a, 0x61, + 0x76, 0x61, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x45, 0x6e, 0x75, + 0x6d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x78, + 0x70, 0x75, 0x72, 0x0, 0x19, 0x5b, 0x4c, 0x6a, 0x61, 0x76, 0x61, + 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x54, 0x68, 0x72, 0x65, 0x61, + 0x64, 0x24, 0x53, 0x74, 0x61, 0x74, 0x65, 0x3b, 0x68, (byte)0xa3, + (byte)0xb5, (byte)0xd5, 0x11, 0x7d, 0x1b, (byte)0xb3, 0x2, 0x0, + 0x0, 0x78, 0x70, 0x0, 0x0, 0x0, 0x6, 0x7e, 0x71, 0x0, 0x7e, 0x0, + 0x5, 0x74, 0x0, 0x3, 0x4e, 0x45, 0x57, 0x7e, 0x71, 0x0, 0x7e, 0x0, + 0x5, 0x74, 0x0, 0x8, 0x52, 0x55, 0x4e, 0x4e, 0x41, 0x42, 0x4c, 0x45, + 0x7e, 0x71, 0x0, 0x7e, 0x0, 0x5, 0x74, 0x0, 0x7, 0x42, 0x4c, 0x4f, + 0x43, 0x4b, 0x45, 0x44, 0x7e, 0x71, 0x0, 0x7e, 0x0, 0x5, 0x74, 0x0, + 0x7, 0x57, 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x7e, 0x71, 0x0, + 0x7e, 0x0, 0x5, 0x74, 0x0, 0xd, 0x54, 0x49, 0x4d, 0x45, 0x44, + 0x5f, 0x57, 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x7e, 0x71, 0x0, + 0x7e, 0x0, 0x5, 0x74, 0x0, 0xa, 0x54, 0x45, 0x52, 0x4d, 0x49, + 0x4e, 0x41, 0x54, 0x45, 0x44, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff + }; + + try { + // Should fail, but instead creates corrupt EnumSet + @SuppressWarnings("unchecked") + EnumSet es = (EnumSet) + deserialize(serializedForm); + + // Demonstrates corruption + System.out.println("Enum size: " + Thread.State.values().length); // 6 + System.out.println("Set size: " + es.size()); // 64 + System.out.println("Set: " + es); // Throws IndexOutOfBoundsException + throw new AssertionError("Expected exception InvalidObjectException not thrown"); + } catch (java.io.InvalidObjectException _) { /* OK */ } + } + + private static Object deserialize(byte[] sf) throws Throwable { + return new ObjectInputStream( + new ByteArrayInputStream(sf)) + .readObject(); + } +} diff --git a/test/java/util/zip/TestEmptyZip.java b/test/java/util/zip/TestEmptyZip.java new file mode 100644 index 0000000000000000000000000000000000000000..d19dee4d4469d4c233a36a066570fd4ce6b95319 --- /dev/null +++ b/test/java/util/zip/TestEmptyZip.java @@ -0,0 +1,147 @@ +/* + * 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. + * + * 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. + */ + +/* @test + * @bug 6334003 6440786 + * @summary Test ability to write and read zip files that have no entries. + * @author Dave Bristor + */ + +import java.io.*; +import java.util.*; +import java.util.zip.*; + +public class TestEmptyZip { + public static void realMain(String[] args) throws Throwable { + String zipName = "foo.zip"; + File f = new File(System.getProperty("test.scratch", "."), zipName); + if (f.exists() && !f.delete()) { + throw new Exception("failed to delete " + zipName); + } + + // Verify 0-length file cannot be read + f.createNewFile(); + ZipFile zf = null; + try { + zf = new ZipFile(f); + fail(); + } catch (Exception ex) { + check(ex.getMessage().contains("zip file is empty")); + } finally { + if (zf != null) { + zf.close(); + } + } + + ZipInputStream zis = null; + try { + zis = new ZipInputStream(new FileInputStream(f)); + ZipEntry ze = zis.getNextEntry(); + check(ze == null); + } catch (Exception ex) { + unexpected(ex); + } finally { + if (zis != null) { + zis.close(); + } + } + + f.delete(); + + // Verify 0-entries file can be written + write(f); + + // Verify 0-entries file can be read + readFile(f); + readStream(f); + + f.delete(); + } + + static void write(File f) throws Exception { + ZipOutputStream zos = null; + try { + zos = new ZipOutputStream(new FileOutputStream(f)); + zos.finish(); + zos.close(); + pass(); + } catch (Exception ex) { + unexpected(ex); + } finally { + if (zos != null) { + zos.close(); + } + } + } + + static void readFile(File f) throws Exception { + ZipFile zf = null; + try { + zf = new ZipFile(f); + + Enumeration e = zf.entries(); + while (e.hasMoreElements()) { + ZipEntry entry = (ZipEntry) e.nextElement(); + fail(); + } + zf.close(); + pass(); + } catch (Exception ex) { + unexpected(ex); + } finally { + if (zf != null) { + zf.close(); + } + } + } + + static void readStream(File f) throws Exception { + ZipInputStream zis = null; + try { + zis = new ZipInputStream(new FileInputStream(f)); + ZipEntry ze = zis.getNextEntry(); + check(ze == null); + byte[] buf = new byte[1024]; + check(zis.read(buf, 0, 1024) == -1); + } finally { + if (zis != null) { + zis.close(); + } + } + } + + //--------------------- Infrastructure --------------------------- + static volatile int passed = 0, failed = 0; + static boolean pass() {passed++; return true;} + static boolean fail() {failed++; Thread.dumpStack(); return false;} + static boolean fail(String msg) {System.out.println(msg); return fail();} + static void unexpected(Throwable t) {failed++; t.printStackTrace();} + static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;} + static boolean equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) return pass(); + else return fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + try {realMain(args);} catch (Throwable t) {unexpected(t);} + System.out.println("\nPassed = " + passed + " failed = " + failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} diff --git a/test/javax/management/MBeanInfo/NotificationInfoTest.java b/test/javax/management/MBeanInfo/NotificationInfoTest.java index 2a78e0941d5ec83869b0b7d410c67caf88cf9c4e..af1cac4e673f3727f261959e8666d4ceff994ecd 100644 --- a/test/javax/management/MBeanInfo/NotificationInfoTest.java +++ b/test/javax/management/MBeanInfo/NotificationInfoTest.java @@ -33,14 +33,16 @@ */ import java.io.*; +import java.lang.management.*; import java.lang.reflect.*; import java.net.*; import java.security.CodeSource; import java.util.*; import java.util.jar.*; import javax.management.*; -import javax.management.modelmbean.*; import javax.management.relation.*; +import javax.management.remote.*; +import javax.management.remote.rmi.*; /* * This test finds all classes in the same code-base as the JMX @@ -68,10 +70,10 @@ import javax.management.relation.*; */ public class NotificationInfoTest { // class or object names where the test failed - private static final Set/**/ failed = new TreeSet(); + private static final Set failed = new TreeSet(); // class or object names where there were no MBeanNotificationInfo entries - private static final Set/**/ suspicious = new TreeSet(); + private static final Set suspicious = new TreeSet(); public static void main(String[] args) throws Exception { System.out.println("Checking that all known MBeans that are " + @@ -86,8 +88,20 @@ public class NotificationInfoTest { .getCodeSource(); URL codeBase; if (cs == null) { - codeBase = new URL("file:" + System.getProperty("java.home") + - "/lib/rt.jar"); + String javaHome = System.getProperty("java.home"); + String[] candidates = {"/lib/rt.jar", "/classes/"}; + codeBase = null; + for (String candidate : candidates) { + File file = new File(javaHome + candidate); + if (file.exists()) { + codeBase = file.toURI().toURL(); + break; + } + } + if (codeBase == null) { + throw new Exception( + "Could not determine codeBase for java.home=" + javaHome); + } } else codeBase = cs.getLocation(); @@ -98,7 +112,7 @@ public class NotificationInfoTest { System.out.println("Testing standard MBeans..."); for (int i = 0; i < classes.length; i++) { String name = classes[i]; - Class c; + Class c; try { c = Class.forName(name); } catch (Throwable e) { @@ -109,18 +123,22 @@ public class NotificationInfoTest { System.out.println(name + ": not a NotificationBroadcaster"); continue; } + if (Modifier.isAbstract(c.getModifiers())) { + System.out.println(name + ": abstract class"); + continue; + } NotificationBroadcaster mbean; - Constructor constr; + Constructor constr; try { - constr = c.getConstructor(null); + constr = c.getConstructor(); } catch (Exception e) { System.out.println(name + ": no public no-arg constructor: " + e); continue; } try { - mbean = (NotificationBroadcaster) constr.newInstance(null); + mbean = (NotificationBroadcaster) constr.newInstance(); } catch (Exception e) { System.out.println(name + ": no-arg constructor failed: " + e); continue; @@ -161,22 +179,9 @@ public class NotificationInfoTest { } private static void checkPlatformMBeans() throws Exception { - Class managementFactory; - try { - managementFactory = - Class.forName("java.lang.management.ManagementFactory"); - } catch (Exception e) { - System.out.println("...no ManagementFactory, assuming pre-Tiger: " - + e); - return; - } - Method getPlatformMBeanServer = - managementFactory.getMethod("getPlatformMBeanServer", null); - MBeanServer mbs = (MBeanServer) - getPlatformMBeanServer.invoke(null, null); - Set mbeanNames = mbs.queryNames(null, null); - for (Iterator it = mbeanNames.iterator(); it.hasNext(); ) { - ObjectName name = (ObjectName) it.next(); + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + Set mbeanNames = mbs.queryNames(null, null); + for (ObjectName name : mbeanNames) { if (!mbs.isInstanceOf(name, NotificationBroadcaster.class.getName())) { System.out.println(name + ": not a NotificationBroadcaster"); @@ -188,31 +193,9 @@ public class NotificationInfoTest { } private static void checkRMIConnectorServer() throws Exception { - Class rmiConnectorServer; - try { - rmiConnectorServer = - Class.forName("javax.management.remote.rmi.RMIConnectorServer"); - } catch (Exception e) { - System.out.println("No RMIConnectorServer class, skipping: " + e); - return; - } - Class jmxServiceURL = - Class.forName("javax.management.remote.JMXServiceURL"); - Constructor jmxServiceURLConstructor = - jmxServiceURL.getConstructor(new Class[] {String.class}); - Object url = - jmxServiceURLConstructor.newInstance(new Object[] { - "service:jmx:rmi://" - }); - Constructor rmiConnectorServerConstructor = - rmiConnectorServer.getConstructor(new Class[] { - jmxServiceURL, Map.class - }); - Object connector = - rmiConnectorServerConstructor.newInstance(new Object[] { - url, null - }); - check((NotificationBroadcaster) connector); + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://"); + RMIConnectorServer connector = new RMIConnectorServer(url, null); + check(connector); } private static void check(String what, MBeanNotificationInfo[] mbnis) { @@ -250,30 +233,29 @@ public class NotificationInfoTest { private static String[] findStandardMBeans(URL codeBase) throws Exception { - Set names; + Set names; if (codeBase.getProtocol().equalsIgnoreCase("file") && codeBase.toString().endsWith("/")) names = findStandardMBeansFromDir(codeBase); else names = findStandardMBeansFromJar(codeBase); - Set standardMBeanNames = new TreeSet(); - for (Iterator it = names.iterator(); it.hasNext(); ) { - String name = (String) it.next(); + Set standardMBeanNames = new TreeSet(); + for (String name : names) { if (name.endsWith("MBean")) { String prefix = name.substring(0, name.length() - 5); if (names.contains(prefix)) standardMBeanNames.add(prefix); } } - return (String[]) standardMBeanNames.toArray(new String[0]); + return standardMBeanNames.toArray(new String[0]); } - private static Set findStandardMBeansFromJar(URL codeBase) + private static Set findStandardMBeansFromJar(URL codeBase) throws Exception { InputStream is = codeBase.openStream(); JarInputStream jis = new JarInputStream(is); - Set names = new TreeSet(); + Set names = new TreeSet(); JarEntry entry; while ((entry = jis.getNextJarEntry()) != null) { String name = entry.getName(); @@ -286,15 +268,15 @@ public class NotificationInfoTest { return names; } - private static Set findStandardMBeansFromDir(URL codeBase) + private static Set findStandardMBeansFromDir(URL codeBase) throws Exception { File dir = new File(new URI(codeBase.toString())); - Set names = new TreeSet(); + Set names = new TreeSet(); scanDir(dir, "", names); return names; } - private static void scanDir(File dir, String prefix, Set names) + private static void scanDir(File dir, String prefix, Set names) throws Exception { File[] files = dir.listFiles(); if (files == null) diff --git a/test/javax/management/MBeanServer/InstanceNotFoundExceptionTest.java b/test/javax/management/MBeanServer/InstanceNotFoundExceptionTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3007965538583804ef01bd8afbe80e978cb826fe --- /dev/null +++ b/test/javax/management/MBeanServer/InstanceNotFoundExceptionTest.java @@ -0,0 +1,76 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 6669137 + * @summary Test the constructors of InstanceNotFoundExceptionTest. + * @author Daniel Fuchs + * @compile InstanceNotFoundExceptionTest.java + * @run main InstanceNotFoundExceptionTest + */ + +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; + +public class InstanceNotFoundExceptionTest { + public static void main(String[] args) throws Exception { + final InstanceNotFoundException x = + new InstanceNotFoundException(); + System.out.println("InstanceNotFoundException(): "+x.getMessage()); + + final String msg = "who is toto?"; + final InstanceNotFoundException x2 = + new InstanceNotFoundException(msg); + if (!msg.equals(x2.getMessage())) + throw new Exception("Bad message: expected "+msg+ + ", got "+x2.getMessage()); + System.out.println("InstanceNotFoundException(" + + msg+"): "+x2.getMessage()); + + final InstanceNotFoundException x3 = + new InstanceNotFoundException((String)null); + if (x3.getMessage() != null) + throw new Exception("Bad message: expected "+null+ + ", got "+x3.getMessage()); + System.out.println("InstanceNotFoundException((String)null): "+ + x3.getMessage()); + + final ObjectName n = new ObjectName("who is toto?:type=msg"); + final InstanceNotFoundException x4 = + new InstanceNotFoundException(n); + if (!String.valueOf(n).equals(x4.getMessage())) + throw new Exception("Bad message: expected "+n+ + ", got "+x4.getMessage()); + System.out.println("InstanceNotFoundException(" + + n+"): "+x4.getMessage()); + + final InstanceNotFoundException x5 = + new InstanceNotFoundException((ObjectName)null); + if (!String.valueOf((ObjectName)null).equals(x5.getMessage())) + throw new Exception("Bad message: expected " + + String.valueOf((ObjectName)null)+" got "+x5.getMessage()); + System.out.println("InstanceNotFoundException((ObjectName)null): "+ + x5.getMessage()); + } +} diff --git a/test/javax/management/MBeanServerFactory/NamedMBeanServerTest.java b/test/javax/management/MBeanServerFactory/NamedMBeanServerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8a8d248cbda0152a95ecd30ff5ebaa4ceccdc735 --- /dev/null +++ b/test/javax/management/MBeanServerFactory/NamedMBeanServerTest.java @@ -0,0 +1,441 @@ +/* + * Copyright 2003 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. + * + * 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. + */ + +/* + * @test + * @summary Test named MBeanServers. + * @author Daniel Fuchs + * @bug 6299231 + * @run clean NamedMBeanServerTest + * @run build NamedMBeanServerTest + * @run main NamedMBeanServerTest + */ + +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.management.MBeanServer; +import javax.management.MBeanServerBuilder; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerFactory; + +/** + * This test can probably be leveraged in the JCK to test compatibilty + * of MBeanServerFactory *Name* method implementation. + * @author dfuchs + */ +public class NamedMBeanServerTest { + + /** + * One enum value for each way of creating an MBeanServer through the + * MBeanServerFactory + */ + public static enum Creator { + newMBeanServer() { + public MBeanServer create(String domain) { + return MBeanServerFactory.newMBeanServer(domain); + } + public String test(MBeanServer server, String domain) { + System.out.println(toString()+"("+domain+")"); + return test(server, + MBeanServerFactory.DEFAULT_MBEANSERVER_NAME, + domain); + } + public MBeanServer[] servers(Config config) { + return config.ndServers; + } + public String[] strings(Config config) { + return domains(config); + } + public String[] domains(Config config) { + return config.newDomains; + } + public String[] names(Config config) { + return null; + } + }, + createMBeanServer() { + public MBeanServer create(String domain) { + return MBeanServerFactory.createMBeanServer(domain); + } + public String test(MBeanServer server, String domain) { + System.out.println(toString()+"("+domain+")"); + return test(server,MBeanServerFactory.DEFAULT_MBEANSERVER_NAME, + domain); + } + public MBeanServer[] servers(Config config) { + return config.cdServers; + } + public String[] strings(Config config) { + return domains(config); + } + public String[] domains(Config config) { + return config.createDomains; + } + public String[] names(Config config) { + return null; + } + }, + newNamedMBeanServer() { + public MBeanServer create(String name) { + return MBeanServerFactory.newNamedMBeanServer(name,null); + } + public String test(MBeanServer server, String name) { + System.out.println(toString()+"("+name+",null)"); + return test(server,name,"DefaultDomain"); + } + public MBeanServer[] servers(Config config) { + return config.nnServers; + } + public String[] strings(Config config) { + return names(config); + } + public String[] domains(Config config) { + return null; + } + public String[] names(Config config) { + return config.newNames; + } + }, + createNamedMBeanServer() { + public MBeanServer create(String name) { + return MBeanServerFactory.createNamedMBeanServer(name,null); + } + public String test(MBeanServer server, String name) { + System.out.println(toString()+"("+name+",null)"); + return test(server,name,"DefaultDomain"); + } + public MBeanServer[] servers(Config config) { + return config.cnServers; + } + public String[] strings(Config config) { + return names(config); + } + public String[] domains(Config config) { + return null; + } + public String[] names(Config config) { + return config.createNames; + } + }; + + // creates an MBeanServer using the specified input string. + // either a domain, (for UNNAMED) or a mbeanServerName (for NAMED) + public abstract MBeanServer create(String string); + + // test the created server against the string used as input to create + // it. + public abstract String test(MBeanServer server, String ref); + + public abstract MBeanServer[] servers(Config config); + public abstract String[] strings(Config config); + public abstract String[] names(Config config); + public abstract String[] domains(Config config); + + public MBeanServer[] servers(Config config, String... refs) { + final MBeanServer[] servers = servers(config); + final String[] strings = strings(config); + final MBeanServer[] res = new MBeanServer[refs.length]; + for (int i=0;i found = + MBeanServerFactory.findMBeanServerByName(name); + if (!registered && found.contains(server)) + return " Server "+name+" found by name - " + + "but should not be registered"; + if (!registered && + !name.equals(MBeanServerFactory.DEFAULT_MBEANSERVER_NAME) && + found.size()>0) + return " Server "+name+" had too many matches: " + found.size(); + if (registered && !found.contains(server)) + return " Server "+name+" not found by name - " + + "but is registered!"; + if (registered && + !name.equals(MBeanServerFactory.DEFAULT_MBEANSERVER_NAME) && + !(found.size()==1)) + return " Server "+name+" had too many matches: " + found.size(); + return null; + } + + public static final EnumSet NAMED = + EnumSet.of(createNamedMBeanServer, newNamedMBeanServer); + public static final EnumSet UNNAMED = + EnumSet.complementOf(NAMED); + public static final EnumSet REFERENCED = + EnumSet.of(createMBeanServer, createNamedMBeanServer); + public static final EnumSet UNREFERENCED = + EnumSet.complementOf(REFERENCED); + + } + + public static class Config { + final String[] newDomains; + final String[] createDomains; + final String[] newNames; + final String[] createNames; + final MBeanServer[] ndServers; + final MBeanServer[] cdServers; + final MBeanServer[] nnServers; + final MBeanServer[] cnServers; + final Map> queries; + Config(String[][] data) { + this(data[0],data[1],data[2],data[3]); + } + Config(String[] nd, String[] cd, String[] nn, String[] cn) { + this.newDomains=nd.clone(); + this.createDomains=cd.clone(); + this.newNames=nn.clone(); + this.createNames=cn.clone(); + ndServers = new MBeanServer[nd.length]; + cdServers = new MBeanServer[cd.length]; + nnServers = new MBeanServer[nn.length]; + cnServers = new MBeanServer[cn.length]; + queries = new HashMap>(); + init(); + } + private void init() { + for (Creator c : Creator.values()) fill(c); + addQuery(null,Creator.createMBeanServer.servers(this)); + addQuery(null,Creator.createNamedMBeanServer.servers(this)); + addQuery("?*",Creator.createMBeanServer.servers(this)); + addQuery("?*",Creator.createNamedMBeanServer.servers(this)); + addQuery("*",Creator.createMBeanServer.servers(this)); + addQuery("*",Creator.createNamedMBeanServer.servers(this)); + addQuery(MBeanServerFactory.DEFAULT_MBEANSERVER_NAME, + Creator.createMBeanServer.servers(this)); + } + private void addQuery(String pattern, MBeanServer... servers) { + final Set s = getQuery(pattern); + s.addAll(Arrays.asList(servers)); + } + public Set getQuery(String pattern) { + final Set s = queries.get(pattern); + if (s != null) return s; + queries.put(pattern,new HashSet()); + return queries.get(pattern); + } + public Set getPatterns() { + return queries.keySet(); + } + private void fill(Creator creator) { + fill(creator.servers(this),creator.strings(this),creator); + } + private void fill(MBeanServer[] dest, String[] src, Creator creator) { + for(int i=0;i found = + MBeanServerFactory.findMBeanServerByName(pat); + String sep=" "; + for (MBeanServer m : found) { + System.out.print(sep+MBeanServerFactory.getMBeanServerName(m)); + sep=", "; + } + System.out.println(" ]"); + final Set founds = new HashSet(); + founds.addAll(found); + if (!founds.equals(config.getQuery(pat))) { + final String msg = + "bad result for findMBeanServerByName(\""+ + pat+"\"): expected "+config.getQuery(pat).size()+", "+ + "got "+founds.size(); + throw new Exception(msg); + } + } + } + + public static void testexception(Creator c, String name, + Class error) throws Exception { + Exception failed = null; + MBeanServer server = null; + try { + server = c.create(name); + } catch (Exception x) { + failed = x; + } finally { + if (Creator.REFERENCED.contains(c) && server!=null) { + MBeanServerFactory.releaseMBeanServer(server); + } + } + if (failed == null && error != null) { + throw new Exception("Expected "+error.getName()+ + " for "+c+"("+name+")"); + } + if (error != null && !error.isInstance(failed)) + throw new Exception("Expected "+error.getName()+ + " for "+c+"("+name+"), caught "+failed); + System.out.println(""+c+"("+name+") PASSED: "+ + (failed==null?"no exception":String.valueOf(failed))); + } + + private static final Map> failures = + new LinkedHashMap>(); + private static final Map> legacy = + new LinkedHashMap>(); + private static final String[] illegalnames = { + "", "-", ":", ";", "?", "*", "wom?bat", "ran:tan.plan", + "rin;tin.tin", "tab*mow" + + }; + private static final String[] legalnames = { + "wombat", "top.tip", "ran.tan.plan", "rin.tin.tin!" + }; + private static final String[] nofailures = { + MBeanServerFactory.DEFAULT_MBEANSERVER_NAME, "default", null + }; + static { + for (String s:illegalnames) + failures.put(s, IllegalArgumentException.class); + for (String s:nofailures) + failures.put(s, null); + legacy.putAll(failures); + for (String s:legalnames) + legacy.put(s, UnsupportedOperationException.class); + + } + + public static void test2(Map> config) + throws Exception { + for (Creator c:Creator.NAMED) { + for (String s:config.keySet()) testexception(c, s, config.get(s)); + } + } + + public static class LegacyBuilder extends MBeanServerBuilder { + + @Override + public MBeanServerDelegate newMBeanServerDelegate() { + return new MBeanServerDelegate() { + @Override + public synchronized String getMBeanServerId() { + return "gloups"; + } + }; + } + + } + public static class LegacyBuilder2 extends MBeanServerBuilder { + + @Override + public MBeanServerDelegate newMBeanServerDelegate() { + return new MBeanServerDelegate() { + @Override + public synchronized String getMBeanServerId() { + return "c'est la vie..."; + } + @Override + public synchronized void setMBeanServerName(String name) { + } + + }; + } + + } + + public static void test3(Map> config, + String builderClassName) + throws Exception { + final String builder = + System.getProperty("javax.management.builder.initial"); + System.setProperty("javax.management.builder.initial", + builderClassName); + try { + test2(config); + } finally { + if (builder != null) + System.setProperty("javax.management.builder.initial", builder); + else + System.clearProperty("javax.management.builder.initial"); + } + } + + public static void main(String[] args) throws Exception { + test(test1); + test2(failures); + test3(legacy,LegacyBuilder.class.getName()); + test3(legacy,LegacyBuilder2.class.getName()); + } +} diff --git a/test/javax/management/ObjectName/ApplyWildcardTest.java b/test/javax/management/ObjectName/ApplyWildcardTest.java index b265e7bf6e1041f8feb682cda88df9c4c6ac683c..f3544ffcf3bd0ecec6e38fcb225367d4c1685fe9 100644 --- a/test/javax/management/ObjectName/ApplyWildcardTest.java +++ b/test/javax/management/ObjectName/ApplyWildcardTest.java @@ -28,10 +28,13 @@ * with wildcards in the key properties value part. * @author Luis-Miguel Alventosa * @run clean ApplyWildcardTest + * @compile -XDignore.symbol.file=true ApplyWildcardTest.java * @run build ApplyWildcardTest * @run main ApplyWildcardTest */ +import com.sun.jmx.mbeanserver.Repository; +import com.sun.jmx.mbeanserver.Util; import javax.management.ObjectName; public class ApplyWildcardTest { @@ -74,6 +77,75 @@ public class ApplyWildcardTest { { "d:k1=\"a?b\",k2=\"c*d\"", "d:k1=\"axb\",k2=\"cyzd\"" }, { "d:k1=\"a?b\",k2=\"c*d\",*", "d:k1=\"axb\",k2=\"cyzd\",k3=\"v3\"" }, { "d:*,k1=\"a?b\",k2=\"c*d\"", "d:k1=\"axb\",k2=\"cyzd\",k3=\"v3\"" }, + + // with namespaces + + { "*//:*", "d//:k=v" }, + { "//?:*", "///:k=v" }, + { "z*x//:*", "zaxcx//:k=v" }, + { "*//:*", "d/xx/q//:k=v" }, + { "z*x//:*", "z/a/x/c/x//:k=v" }, + { "*x?//:*", "dbdbdxk//:k=v" }, + { "z*x?x//:*", "zaxcx//:k=v" }, + { "*x?f//:*", "d/xxf/qxbf//:k=v" }, + { "z*x?c*x//:*", "z/a/x/c/x//:k=v" }, + + { "*//*:*", "d/c/v//x/vgh/:k=v" }, + { "z*x//z*x:*", "zaxcx//zaxcxcx:k=v" }, + { "//*//:*", "//d/xx/q//:k=v" }, + { "z*//*//:*", "z/x/x/z//z/a/x/c/x//:k=v" }, + { "*x?//blur?g*:*", "dbdbdxk//blurhgblurgh/x/:k=v" }, + { "z*x??x//??:*", "zaxcxccx///.:k=v" }, + { "*x?f//?:*", "d/xxf/qxbf///:k=v" }, + { "z*x?c*x//*//z????//g:*", "z/a/x/c/x//gloubs/././/zargh//g:k=v" }, + { "z*x?c*x//*//:*", "z/a/x/c/x//gloubs/././/:k=v"}, + { "*//*//:*", "aza//bzb//:k=v" }, + { "*//:*", "aza//:k=v" }, + + // with or without namespaces, * can also match nothing + { "x*z:*", "xz:k=v"}, + + { "*//:*", "//:k=v" }, + { "z*x//:*", "zx//:k=v" }, + { "*x?//:*", "xk//:k=v" }, + { "z*x?x//:*", "zxcx//:k=v" }, + { "*x?f//:*", "xbf//:k=v" }, + { "z*x?c*x//:*", "zx/cx//:k=v" }, + + { "*//*:*", "//:k=v" }, + { "z*x//z*x:*", "zx//zx:k=v" }, + { "//*//:*", "////:k=v" }, + { "z*//*//:*", "z////:k=v" }, + { "*x?//blur?g*:*", "xk//blurhg:k=v" }, + { "z*x??x//??:*", "zxccx///.:k=v" }, + { "*x?f//?:*", "xbf///:k=v" }, + { "z*x?c*x//*//z????//g:*", "zx/cx////zargh//g:k=v" }, + { "z*x?c*x//*//:*", "zx/cx////:k=v"}, + { "*//*//:*", "////:k=v" }, + { "*//:*", "//:k=v" }, + + // recursive namespace meta-wildcard + {"**//D:k=v", "a//D:k=v"}, + {"**//D:k=v", "a//b//c//D:k=v"}, + {"a//**//D:k=v", "a//b//c//D:k=v"}, + {"a//**//d//D:k=v", "a//b//c//d//D:k=v"}, + {"a//**//d//D:k=v", "a//b//c//d//d//D:k=v"}, + {"a//**//d//D:k=v", "a//a//b//c//d//d//D:k=v"}, + {"a//**//d//**//e//D:k=v", "a//a//b//d//c//d//e//D:k=v"}, + + // special cases for names ending with // + { "*:*", "d//:k=v" }, + { "z*x*:*", "zaxcx//:k=v" }, + { "*:*", "d/xx/q//:k=v" }, + { "z*x??:*", "z/a/x/c/x//:k=v" }, + { "*x???:*", "dbdbdxk//:k=v" }, + { "z*x?c*x*:*", "z/a/x/c/x//:k=v" }, + { "?/*/?:*", "d/xx/q//:k=v" }, + { "**//*:*", "a//b//jmx.rmi:k=v"}, + { "**//*:*", "a//b//jmx.rmi//:k=v"}, + { "*//*:*", "wombat//:type=Wombat" }, + { "**//*:*", "jmx.rmi//:k=v"}, + }; private static final String negativeTests[][] = { @@ -114,6 +186,33 @@ public class ApplyWildcardTest { { "d:k1=\"a?b\",k2=\"c*d\"", "d:k1=\"ab\",k2=\"cd\"" }, { "d:k1=\"a?b\",k2=\"c*d\",*", "d:k1=\"ab\",k2=\"cd\",k3=\"v3\"" }, { "d:*,k1=\"a?b\",k2=\"c*d\"", "d:k1=\"ab\",k2=\"cd\",k3=\"v3\"" }, + + // with namespaces + + { "z*x?x*:*", "zaxcx//blougs:k=v" }, + { "*x?f??rata:*", "d/xxf/qxbf//rata:k=v" }, + { "z*x?c*x*b*:*", "z/a/x/c/x//b//:k=v" }, + + { "*:*", "d/c/v//x/vgh/:k=v" }, + { "z*x??z*x:*", "zaxcx//zaxcxcx:k=v" }, + { "?/*/?:*", "//d/xx/q//:k=v" }, + { "z*/?*/?:*", "z/x/x/z//z/a/x/c/x//:k=v" }, + { "*x?/?blur?g*:*", "dbdbdxk//blurhgblurgh/x/:k=v" }, + { "z*x??x/???:*", "zaxcxccx///.:k=v" }, + { "*x?f?/?:*", "d/xxf/qxbf///:k=v" }, + { "z*x?c*x/?*z????*g:*", "z/a/x/c/x//gloubs/././/zargh//g:k=v" }, + + // recursive namespace meta-wildcard + {"**//D:k=v", "D:k=v"}, + {"b//**//D:k=v", "a//b//c//D:k=v"}, + {"a//**//D:k=v", "a//D:k=v"}, + {"a//**//d//D:k=v", "a//b//c//d//e//D:k=v"}, + {"a//**//d//D:k=v", "a//b//c//D:k=v"}, + {"a//**//d//D:k=v", "a//b//c//d//d//e//D:k=v"}, + {"a//**//d//**//e//D:k=v", "a//a//b//c//d//e//D:k=v"}, + {"a//**//d//**//e//D:k=v", "a//a//b//c//e//D:k=v"}, + { "**//*:*", "jmx.rmi:k=v"}, + }; private static int runPositiveTests() { @@ -129,6 +228,8 @@ public class ApplyWildcardTest { if (result == false) { error++; System.out.println("Test failed!"); + throw new Error("test failed for "+ + "\"" + on1 + "\".apply(\"" + on2 + "\")"); } else { System.out.println("Test passed!"); } @@ -168,10 +269,85 @@ public class ApplyWildcardTest { return error; } + private static int runRepositoryPositiveTests() { + int error = 0; + for (int i = 0; i < positiveTests.length; i++) { + try { + ObjectName on1 = ObjectName.getInstance(positiveTests[i][0]); + ObjectName on2 = ObjectName.getInstance(positiveTests[i][1]); + if (on1.isPropertyPattern()) { + if (!on1.getKeyPropertyListString().equals("")) continue; + } else if (!on1.getCanonicalKeyPropertyListString() + .equals(on2.getCanonicalKeyPropertyListString())) { + continue; + } + System.out.println("Repository Positive Match Test ---------------"); + final String dom1 = on1.getDomain(); + final String dom2 = on2.getDomain(); + System.out.println("Util.wildpathmatch(\"" + dom2 + "\",\"" + dom1 + "\")"); + boolean result = + Util.wildpathmatch(dom2,dom1); + System.out.println("Result = " + result); + if (result == false) { + error++; + System.out.println("Test failed!"); + } else { + System.out.println("Test passed!"); + } + } catch (Exception e) { + error++; + System.out.println("Got Unexpected Exception = " + e.toString()); + System.out.println("Test failed!"); + } + System.out.println("----------------------------------------------"); + } + return error; + } + + private static int runRepositoryNegativeTests() { + int error = 0; + for (int i = 0; i < negativeTests.length; i++) { + try { + ObjectName on1 = ObjectName.getInstance(negativeTests[i][0]); + ObjectName on2 = ObjectName.getInstance(negativeTests[i][1]); + if (on1.isPropertyPattern()) { + if (!on1.getKeyPropertyListString().equals("")) continue; + } else if (!on1.getCanonicalKeyPropertyListString() + .equals(on2.getCanonicalKeyPropertyListString())) { + continue; + } + System.out.println("Repository Negative Match Test ---------------"); + final String dom1 = on1.getDomain(); + final String dom2 = on2.getDomain(); + System.out.println("Util.wildpathmatch(\"" + dom2 + "\",\"" + dom1 + "\")"); + boolean result = + Util.wildpathmatch(dom2,dom1); + System.out.println("Result = " + result); + if (result == true) { + error++; + System.out.println("Test failed!"); + } else { + System.out.println("Test passed!"); + } + } catch (Exception e) { + error++; + System.out.println("Got Unexpected Exception = " + e.toString()); + System.out.println("Test failed!"); + } + System.out.println("----------------------------------------------"); + } + return error; + } + public static void main(String[] args) throws Exception { + int error = 0; + if (!(new ObjectName("z*x*:*").apply(new ObjectName("zaxcx//:k=v")))) + throw new Exception(); + + // Check null values // System.out.println("----------------------------------------------"); @@ -253,6 +429,10 @@ public class ApplyWildcardTest { error += runPositiveTests(); error += runNegativeTests(); + System.out.println("----------------------------------------------"); + error += runRepositoryPositiveTests(); + System.out.println("----------------------------------------------"); + error += runRepositoryNegativeTests(); if (error > 0) { final String msg = "Test FAILED! Got " + error + " error(s)"; diff --git a/test/javax/management/ObjectName/ValueOfTest.java b/test/javax/management/ObjectName/ValueOfTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4a68a3d4c5ce55d73ae344490c40468f15ce693a --- /dev/null +++ b/test/javax/management/ObjectName/ValueOfTest.java @@ -0,0 +1,175 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 6734813 + * @summary Test the ObjectName.valueOf methods + * @author Eamonn McManus + */ + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Hashtable; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +public class ValueOfTest { + public static void main(String[] args) throws Exception { + // Calls that should work + testPositive("d:foo=bar,baz=buh"); + testPositive("foo", "bar", "baz"); + Hashtable h = new Hashtable(); + h.put("foo", "bar"); + h.put("baz", "buh"); + testPositive("domain", h); + + // Calls that should not work + testNegative("d"); + testNegative("d:"); + testNegative("d::foo=bar"); + testNegative("d:", "foo", "bar"); + testNegative("d", "foo=", "bar"); + testNegative("d:", h); + testNegative("d", new Hashtable()); + } + + private static void testPositive(Object... args) throws Exception { + Method valueOf = valueOfMethod(args); + Method getInstance = getInstanceMethod(args); + Constructor constructor = constructor(args); + + Object valueOfValue = valueOf.invoke(null, args); + Object getInstanceValue = getInstance.invoke(null, args); + Object constructorValue = constructor.newInstance(args); + + String argString = + Arrays.toString(args).replace('[', '(').replace(']', ')'); + + if (!valueOfValue.equals(getInstanceValue)) { + throw new Exception( + "valueOf" + argString + " differs from getInstance" + + argString); + } + + if (!valueOfValue.equals(constructorValue)) { + throw new Exception( + "valueOf" + argString + " differs from new ObjectName " + + argString); + } + + System.out.println("OK: valueOf" + argString); + } + + private static void testNegative(Object... args) throws Exception { + Method valueOf = valueOfMethod(args); + Method getInstance = getInstanceMethod(args); + + String argString = + Arrays.toString(args).replace('[', '(').replace(']', ')'); + + final Throwable valueOfException; + try { + valueOf.invoke(null, args); + throw new Exception("valueOf" + argString + " did not fail but should"); + } catch (InvocationTargetException e) { + valueOfException = e.getCause(); + } + if (!(valueOfException instanceof IllegalArgumentException)) { + throw new Exception( + "valueOf" + argString + " threw " + + valueOfException.getClass().getName() + " instead of " + + "IllegalArgumentException", valueOfException); + } + + final Throwable valueOfCause = valueOfException.getCause(); + if (!(valueOfCause instanceof MalformedObjectNameException)) { + throw new Exception( + "valueOf" + argString + " threw exception with wrong " + + "type of cause", valueOfCause); + } + + if (!valueOfException.getMessage().equals(valueOfCause.getMessage())) { + // The IllegalArgumentException should have the same message as + // the MalformedObjectNameException it wraps. + // This isn't specified but is desirable. + throw new Exception( + "valueOf" + argString + ": message in wrapping " + + "IllegalArgumentException (" + valueOfException.getMessage() + + ") differs from message in wrapped " + + "MalformedObjectNameException (" + valueOfCause.getMessage() + + ")"); + } + + final Throwable getInstanceException; + try { + getInstance.invoke(null, args); + throw new Exception("getInstance" + argString + " did not fail but should"); + } catch (InvocationTargetException e) { + getInstanceException = e.getCause(); + } + if (!(getInstanceException instanceof MalformedObjectNameException)) { + throw new Exception( + "getInstance" + argString + " threw wrong exception", + getInstanceException); + } + + if (!valueOfException.getMessage().equals(getInstanceException.getMessage())) { + // Again this is not specified. + throw new Exception( + "Exception message from valueOf" + argString + " (" + + valueOfException.getMessage() + ") differs from message " + + "from getInstance" + argString + " (" + + getInstanceException.getMessage() + ")"); + } + + System.out.println("OK (correct exception): valueOf" + argString); + } + + private static Method valueOfMethod(Object[] args) throws Exception { + return method("valueOf", args); + } + + private static Method getInstanceMethod(Object[] args) throws Exception { + return method("getInstance", args); + } + + private static Method method(String name, Object[] args) throws Exception { + Class[] argTypes = argTypes(args); + return ObjectName.class.getMethod(name, argTypes); + } + + private static Constructor constructor(Object[] args) throws Exception { + Class[] argTypes = argTypes(args); + return ObjectName.class.getConstructor(argTypes); + } + + private static Class[] argTypes(Object[] args) { + Class[] argTypes = new Class[args.length]; + for (int i = 0; i < args.length; i++) + argTypes[i] = args[i].getClass(); + return argTypes; + } +} diff --git a/test/javax/management/eventService/EventClientThreadTest.java b/test/javax/management/eventService/EventClientThreadTest.java new file mode 100644 index 0000000000000000000000000000000000000000..910bc9cc2d2bc04a690fe71fa4e79f508b2440bc --- /dev/null +++ b/test/javax/management/eventService/EventClientThreadTest.java @@ -0,0 +1,176 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 6747411 + * @summary Check that EventClient instances don't leak threads. + * @author Eamonn McManus + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.Set; +import java.util.TreeSet; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerNotification; +import javax.management.Notification; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.EventClient; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +public class EventClientThreadTest { + private static final int MAX_TIME_SECONDS = 20; + + private static final BlockingQueue queue = + new ArrayBlockingQueue(100); + + private static final NotificationListener queueListener = + new NotificationListener() { + public void handleNotification(Notification notification, + Object handback) { + queue.add(notification); + } + }; + + private static final NotificationFilter dummyFilter = + new NotificationFilter() { + public boolean isNotificationEnabled(Notification notification) { + return true; + } + }; + + public static void main(String[] args) throws Exception { + long start = System.currentTimeMillis(); + long deadline = start + MAX_TIME_SECONDS * 1000; + + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://"); + JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer( + url, null, mbs); + cs.start(); + JMXServiceURL addr = cs.getAddress(); + JMXConnector cc = JMXConnectorFactory.connect(addr); + MBeanServerConnection mbsc = cc.getMBeanServerConnection(); + + ThreadMXBean threads = ManagementFactory.getThreadMXBean(); + + System.out.println("Opening and closing some EventClients..."); + // If we create a connection, then create and destroy EventClients + // over it, then close it, there should be no "JMX *" threads left. + for (int i = 0; i < 5; i++) + test(mbsc); + + cc.close(); + + showTime("opening and closing initial EventClients", start); + + Set jmxThreads = threadsMatching("JMX .*"); + while (!jmxThreads.isEmpty() && System.currentTimeMillis() < deadline) { + Set jmxThreadsNow = threadsMatching("JMX .*"); + Set gone = new TreeSet(jmxThreads); + gone.removeAll(jmxThreadsNow); + for (String s : gone) + showTime("expiry of \"" + s + "\"", start); + jmxThreads = jmxThreadsNow; + Thread.sleep(10); + } + if (System.currentTimeMillis() >= deadline) { + showThreads(threads); + throw new Exception("Timed out waiting for JMX threads to expire"); + } + + showTime("waiting for JMX threads to expire", start); + + System.out.println("TEST PASSED"); + } + + static void showThreads(ThreadMXBean threads) throws Exception { + long[] ids = threads.getAllThreadIds(); + for (long id : ids) { + ThreadInfo ti = threads.getThreadInfo(id); + String name = (ti == null) ? "(defunct)" : ti.getThreadName(); + System.out.printf("%4d %s\n", id, name); + } + } + + static void showTime(String what, long start) { + long elapsed = System.currentTimeMillis() - start; + System.out.printf("Time after %s: %.3f s\n", what, elapsed / 1000.0); + } + + static Set threadsMatching(String pattern) { + Set matching = new TreeSet(); + ThreadMXBean threads = ManagementFactory.getThreadMXBean(); + long[] ids = threads.getAllThreadIds(); + for (long id : ids) { + ThreadInfo ti = threads.getThreadInfo(id); + String name = (ti == null) ? "(defunct)" : ti.getThreadName(); + if (name.matches(pattern)) + matching.add(name); + } + return matching; + } + + static void test(MBeanServerConnection mbsc) throws Exception { + final ObjectName delegateName = MBeanServerDelegate.DELEGATE_NAME; + final ObjectName testName = new ObjectName("test:type=Test"); + EventClient ec = new EventClient(mbsc); + ec.addNotificationListener(delegateName, queueListener, null, null); + mbsc.createMBean(MBeanServerDelegate.class.getName(), testName); + mbsc.unregisterMBean(testName); + final String[] expectedTypes = { + MBeanServerNotification.REGISTRATION_NOTIFICATION, + MBeanServerNotification.UNREGISTRATION_NOTIFICATION, + }; + for (String s : expectedTypes) { + Notification n = queue.poll(3, TimeUnit.SECONDS); + if (n == null) + throw new Exception("Timed out waiting for notif: " + s); + if (!(n instanceof MBeanServerNotification)) + throw new Exception("Got notif of wrong class: " + n.getClass()); + if (!n.getType().equals(s)) { + throw new Exception("Got notif of wrong type: " + n.getType() + + " (expecting " + s + ")"); + } + } + ec.removeNotificationListener(delegateName, queueListener); + + ec.addNotificationListener(delegateName, queueListener, dummyFilter, "foo"); + ec.removeNotificationListener(delegateName, queueListener, dummyFilter, "foo"); + + ec.close(); + } +} \ No newline at end of file diff --git a/test/javax/management/eventService/LeaseManagerDeadlockTest.java b/test/javax/management/eventService/LeaseManagerDeadlockTest.java index 586b244022687363ebe857ae4166444b8867466b..ab7d14d54f2e663d544718ae4ec8151a1c238e7b 100644 --- a/test/javax/management/eventService/LeaseManagerDeadlockTest.java +++ b/test/javax/management/eventService/LeaseManagerDeadlockTest.java @@ -26,6 +26,8 @@ * @bug 6717789 * @summary Check that a lock is not held when a LeaseManager expires. * @author Eamonn McManus + * @compile -XDignore.symbol.file=true LeaseManagerDeadlockTest.java + * @run main LeaseManagerDeadlockTest */ import com.sun.jmx.event.LeaseManager; diff --git a/test/javax/management/eventService/SharingThreadTest.java b/test/javax/management/eventService/SharingThreadTest.java index a3d7fd37a3c56d1482b4915bd9689753cdee8240..7339d0806da672e931ee7547a1775cb6106fa900 100644 --- a/test/javax/management/eventService/SharingThreadTest.java +++ b/test/javax/management/eventService/SharingThreadTest.java @@ -1,4 +1,4 @@ -/*/* +/* * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/test/javax/management/eventService/SubUnsubTest.java b/test/javax/management/eventService/SubUnsubTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f8889882317fb043cfb6df6ba7e60120b2189c9b --- /dev/null +++ b/test/javax/management/eventService/SubUnsubTest.java @@ -0,0 +1,125 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test SubUnsubTest + * @bug 6736611 + * @summary Test not to remove other listeners when calling unsubscribe + * @author Shanliang JIANG + * @run clean SubUnsubTest + * @run build SubUnsubTest + * @run main SubUnsubTest + */ + +import java.lang.management.ManagementFactory; +import javax.management.MBeanServer; +import javax.management.Notification; +import javax.management.NotificationFilter; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.event.EventSubscriber; +import javax.management.event.EventClient; +public class SubUnsubTest { + private static class CountListener implements NotificationListener { + volatile int count; + + public void handleNotification(Notification n, Object h) { + count++; + } + } + + public static interface SenderMBean {} + + public static class Sender extends NotificationBroadcasterSupport + implements SenderMBean { + void send() { + Notification n = new Notification("type", this, 1L); + sendNotification(n); + } + } + + public static void main(String[] args) throws Exception { + System.out.println("Testing EventSubscriber-unsubscribe method."); + + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + ObjectName name1 = new ObjectName("d:type=Sender,id=1"); + ObjectName name2 = new ObjectName("d:type=Sender,id=2"); + ObjectName pattern = new ObjectName("d:type=Sender,*"); + Sender sender1 = new Sender(); + Sender sender2 = new Sender(); + mbs.registerMBean(sender1, name1); + mbs.registerMBean(sender2, name2); + + EventSubscriber sub = EventSubscriber.getEventSubscriber(mbs); + + System.out.println("Single subscribe covering both MBeans"); + CountListener listener = new CountListener(); + + System.out.println("Subscribing and adding listeners ..."); + sub.subscribe(pattern, listener, null, null); + sub.subscribe(name2, listener, null, null); + mbs.addNotificationListener(name2, listener, null, null); + + sender1.send(); + sender2.send(); + if (listener.count != 4) { + throw new RuntimeException("Do not receive all notifications: "+ + "Expect 4, got "+listener.count); + } + + System.out.println("Unsubscribe the listener with the pattern."); + sub.unsubscribe(pattern, listener); + listener.count = 0; + sender1.send(); + sender2.send(); + if (listener.count != 2) { + throw new RuntimeException("The method unsubscribe removes wrong listeners."); + } + + System.out.println("Unsubscribe the listener with the ObjectName."); + sub.unsubscribe(name2, listener); + listener.count = 0; + sender1.send(); + sender2.send(); + if (listener.count != 1) { + throw new RuntimeException("The method unsubscribe removes wrong listeners."); + } + + System.out.println("Subscribe twice to same MBean with same listener " + + "but different handback."); + sub.subscribe(name1, listener, null, new Object()); + sub.subscribe(name1, listener, null, new Object()); + listener.count = 0; + + sub.unsubscribe(name1, listener); + sender1.send(); + if (listener.count > 0) { + throw new RuntimeException("EventSubscriber: the method unsubscribe" + + " does not remove a listener which was subscribed 2 times."); + } + + System.out.println("Bye bye!"); + return; + } +} \ No newline at end of file diff --git a/test/javax/management/mxbean/JMXServiceURLTest.java b/test/javax/management/mxbean/JMXServiceURLTest.java index 12646cf7cd3f21423cc4cbee7f77ee2446d1873e..a688ee701d5911593c4141c69fe90281c39fa782 100644 --- a/test/javax/management/mxbean/JMXServiceURLTest.java +++ b/test/javax/management/mxbean/JMXServiceURLTest.java @@ -23,16 +23,24 @@ /* * @test JMXServiceURLTest - * @bug 6607114 6670375 + * @bug 6607114 6670375 6731410 * @summary Test that JMXServiceURL works correctly in MXBeans * @author Eamonn McManus */ +import java.io.InvalidObjectException; import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.management.Attribute; import javax.management.JMX; +import javax.management.MBeanException; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenType; import javax.management.openmbean.SimpleType; @@ -56,6 +64,25 @@ public class JMXServiceURLTest { } } + private static enum Part { + PROTOCOL("protocol", SimpleType.STRING, "rmi", 25, "", "a:b", "/", "?", "#"), + HOST("host", SimpleType.STRING, "a.b.c", 25, "a..b", ".a.b", "a.b."), + PORT("port", SimpleType.INTEGER, 25, "25", -25), + PATH("URLPath", SimpleType.STRING, "/tiddly", 25, "tiddly"); + + Part(String name, OpenType openType, Object validValue, Object... bogusValues) { + this.name = name; + this.openType = openType; + this.validValue = validValue; + this.bogusValues = bogusValues; + } + + final String name; + final OpenType openType; + final Object validValue; + final Object[] bogusValues; + } + public static void main(String[] args) throws Exception { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); ObjectName name = new ObjectName("a:b=c"); @@ -91,6 +118,92 @@ public class JMXServiceURLTest { Object actualValue = cd.get(itemName); assertEquals(expectedValue, actualValue); } + + // Now make sure we reject any bogus-looking CompositeData items. + // We first try every combination of omitted items (items can be + // null but cannot be omitted), then we try every combination of + // valid and bogus items. + final Part[] parts = Part.values(); + final int nParts = parts.length; + final int maxPartMask = (1 << nParts) - 1; + // Iterate over all possibilities of included and omitted, except + // 0, because a CompositeDataSupport must have at least one element, + // and maxPartMask, where all items are included and the result is valid. + for (int mask = 1; mask < maxPartMask; mask++) { + Map cdMap = new HashMap(); + List names = new ArrayList(); + List types = new ArrayList(); + for (int i = 0; i < nParts; i++) { + if ((mask & (1 << i)) != 0) { + Part part = parts[i]; + cdMap.put(part.name, part.validValue); + names.add(part.name); + types.add(openTypeForValue(part.validValue)); + } + } + String[] nameArray = names.toArray(new String[0]); + OpenType[] typeArray = types.toArray(new OpenType[0]); + CompositeType badct = new CompositeType( + "bad", "descr", nameArray, nameArray, typeArray); + CompositeData badcd = new CompositeDataSupport(badct, cdMap); + checkBad(mbs, name, badcd); + } + + int nBogus = 1; + for (Part part : parts) + nBogus *= (part.bogusValues.length + 1); + // Iterate over all combinations of bogus values. We are basically + // treating each Part as a digit while counting up from 1. A digit + // value of 0 stands for the valid value of that Part, and 1 on + // stand for the bogus values. Hence an integer where all the digits + // are 0 would represent a valid CompositeData, which is why we + // start from 1. + for (int bogusCount = 1; bogusCount < nBogus; bogusCount++) { + List names = new ArrayList(); + List types = new ArrayList(); + int x = bogusCount; + Map cdMap = new HashMap(); + for (Part part : parts) { + int digitMax = part.bogusValues.length + 1; + int digit = x % digitMax; + Object value = (digit == 0) ? + part.validValue : part.bogusValues[digit - 1]; + cdMap.put(part.name, value); + names.add(part.name); + types.add(openTypeForValue(value)); + x /= digitMax; + } + String[] nameArray = names.toArray(new String[0]); + OpenType[] typeArray = types.toArray(new OpenType[0]); + CompositeType badct = new CompositeType( + "bad", "descr", nameArray, nameArray, typeArray); + CompositeData badcd = new CompositeDataSupport(badct, cdMap); + checkBad(mbs, name, badcd); + } + } + + private static OpenType openTypeForValue(Object value) { + if (value instanceof String) + return SimpleType.STRING; + else if (value instanceof Integer) + return SimpleType.INTEGER; + else + throw new AssertionError("Value has invalid type: " + value); + } + + private static void checkBad( + MBeanServer mbs, ObjectName name, CompositeData badcd) + throws Exception { + try { + mbs.setAttribute(name, new Attribute("Url", badcd)); + throw new Exception("Expected exception for: " + badcd); + } catch (MBeanException e) { + if (!(e.getCause() instanceof InvalidObjectException)) { + throw new Exception( + "Wrapped exception should be InvalidObjectException", e); + } + System.out.println("OK: rejected " + badcd); + } } private static void assertEquals(Object expect, Object actual) diff --git a/test/javax/management/namespace/DomainCreationTest.java b/test/javax/management/namespace/DomainCreationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..02a09868e1394d42a53bb8ae7e239102630b3d6c --- /dev/null +++ b/test/javax/management/namespace/DomainCreationTest.java @@ -0,0 +1,330 @@ +/* + * 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. + * + * 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. + */ +/* + * + * @test DomainCreationTest.java + * @bug 5072476 + * @summary Test the creation and registration of JMXDomain instances. + * @author Daniel Fuchs + * @run clean DomainCreationTest Wombat WombatMBean + * @run build DomainCreationTest Wombat WombatMBean + * @run main DomainCreationTest + */ + + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.DynamicMBean; +import javax.management.InstanceNotFoundException; +import javax.management.InvalidAttributeValueException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.NotificationEmitter; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.RuntimeMBeanException; +import javax.management.RuntimeOperationsException; +import javax.management.namespace.JMXDomain; +import javax.management.namespace.MBeanServerSupport; + +/** + * Test simple creation/registration of namespace. + * + */ +public class DomainCreationTest { + private static Map emptyEnvMap() { + return Collections.emptyMap(); + } + + + public static class LocalDomainRepository + extends MBeanServerSupport { + private final MBeanServer server; + private final String domain; + + + public class DynamicMBeanProxy implements DynamicMBean { + + private final MBeanServer server; + private final ObjectName name; + + public DynamicMBeanProxy(MBeanServer s, ObjectName n) { + this.server = s; + this.name = n; + } + + public Object getAttribute(String attribute) + throws AttributeNotFoundException, + MBeanException, ReflectionException { + try { + return server.getAttribute(name, attribute); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public void setAttribute(Attribute attribute) + throws AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException { + try { + server.setAttribute(name, attribute); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public AttributeList getAttributes(String[] attributes) { + try { + return server.getAttributes(name, attributes); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public AttributeList setAttributes(AttributeList attributes) { + try { + return server.setAttributes(name, attributes); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public Object invoke(String actionName, Object[] params, + String[] signature) throws MBeanException, + ReflectionException { + try { + return server.invoke(name, actionName, params, signature); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public MBeanInfo getMBeanInfo() { + try { + return server.getMBeanInfo(name); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + } + + public LocalDomainRepository(String domain) { + this.server = MBeanServerFactory.newMBeanServer(); + this.domain = domain; + } + + @Override + protected Set getNames() { + try { + final ObjectName name = + ObjectName.getInstance(domain+":*"); + return server.queryNames(name, null); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + return new DynamicMBeanProxy(server, name); + } + + @Override + public NotificationEmitter + getNotificationEmitterFor(ObjectName name) + throws InstanceNotFoundException { + DynamicMBean mbean = getDynamicMBeanFor(name); + if (mbean instanceof NotificationEmitter) + return (NotificationEmitter) mbean; + return null; + } + + } + + private static MBeanServer newMBeanServer() { + return MBeanServerFactory.newMBeanServer(); + } + + public static interface ThingMBean {} + public static class Thing implements ThingMBean, MBeanRegistration { + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + if (name == null) return new ObjectName(":type=Thing"); + else return name; + } + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + public void postDeregister() { + } + } + + /** + * Test that it is possible to create a dummy MBean with a null + * ObjectName - this is just a sanity check - as there are already + * other JMX tests that check that. + * + * @throws java.lang.Exception + */ + public static void testCreateWithNull() throws Exception { + final MBeanServer server = newMBeanServer(); + final ObjectInstance oi = server.registerMBean(new Thing(),null); + server.unregisterMBean(oi.getObjectName()); + System.out.println("testCreateWithNull PASSED"); + } + + /** + * Check that we can register a JMXNamespace MBean, using its standard + * ObjectName. + * @throws java.lang.Exception + */ + public static void testGoodObjectName() throws Exception { + MBeanServer server = newMBeanServer(); + final ObjectName name = + JMXDomain.getDomainObjectName("gloups"); + final ObjectInstance oi = + server.registerMBean(new JMXDomain( + new LocalDomainRepository("gloups")),name); + System.out.println("Succesfully registered namespace: "+name); + try { + if (! name.equals(oi.getObjectName())) + throw new RuntimeException("testGoodObjectName: TEST failed: " + + "namespace registered as: "+ + oi.getObjectName()+" expected: "+name); + } finally { + server.unregisterMBean(oi.getObjectName()); + } + System.out.println("Succesfully unregistered namespace: "+name); + System.out.println("testGoodObjectName PASSED"); + } + + /** + * Check that we cannot register a JMXNamespace MBean, if we don't use + * its standard ObjectName. + * @throws java.lang.Exception + */ + public static void testBadObjectName() throws Exception { + MBeanServer server = newMBeanServer(); + Throwable exp = null; + final ObjectName name = new ObjectName("d:k=v"); + try { + server.registerMBean(new JMXDomain( + new LocalDomainRepository("d")),name); + System.out.println("testBadObjectName: " + + "Error: MBean registered, no exception thrown."); + } catch(RuntimeMBeanException x) { + exp = x.getCause(); + } catch(Exception x) { + throw new RuntimeException("testBadObjectName: TEST failed: " + + "expected RuntimeMBeanException - got "+ + x); + } + if (exp == null) server.unregisterMBean(name); + if (exp == null) + throw new RuntimeException("testBadObjectName: TEST failed: " + + "expected IllegalArgumentException - got none"); + if (!(exp instanceof IllegalArgumentException)) + throw new RuntimeException("testBadObjectName: TEST failed: " + + "expected IllegalArgumentException - got "+ + exp.toString(),exp); + System.out.println("Got expected exception: "+exp); + System.out.println("testBadObjectName PASSED"); + } + + /** + * Check that we cannot register a Domain MBean in a domain that already + * exists. + * + * @throws java.lang.Exception + */ + public static void testBadDomain() throws Exception { + MBeanServer server = newMBeanServer(); + Throwable exp = null; + final ObjectName name = new ObjectName("glips:k=v"); + server.registerMBean(new Wombat(),name); + + final ObjectName dname = + JMXDomain.getDomainObjectName("glips"); + + try { + server.registerMBean(new JMXDomain( + new LocalDomainRepository("glips")),dname); + System.out.println("testBadDomain: " + + "Error: MBean registered, no exception thrown."); + } catch(RuntimeOperationsException x) { + exp = x.getCause(); + } catch(Exception x) { + throw new RuntimeException("testBadDomain: TEST failed: " + + "expected RuntimeOperationsException - got "+ + x); + } finally { + server.unregisterMBean(name); + } + if (exp == null) { + server.unregisterMBean(dname); + } + if (exp == null) + throw new RuntimeException("testBadDomain: TEST failed: " + + "expected IllegalArgumentException - got none"); + if (!(exp instanceof IllegalArgumentException)) + throw new RuntimeException("testBadDomain: TEST failed: " + + "expected IllegalArgumentException - got "+ + exp.toString(),exp); + System.out.println("Got expected exception: "+exp); + System.out.println("testBadDomain PASSED"); + } + + + public static void main(String... args) throws Exception { + testCreateWithNull(); + testGoodObjectName(); + testBadObjectName(); + testBadDomain(); + } +} diff --git a/test/javax/management/namespace/EventWithNamespaceControlTest.java b/test/javax/management/namespace/EventWithNamespaceControlTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1e3901104c7462a2666e21e9708f064ab9a936e5 --- /dev/null +++ b/test/javax/management/namespace/EventWithNamespaceControlTest.java @@ -0,0 +1,93 @@ +/* + * 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. + * + * 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. + */ + +/* + * + * @test EventWithNamespaceControlTest.java + * @summary Check -Djmx.remote.use.event.service=true and + * -Djmx.remote.delegate.event.service + * @author Daniel Fuchs + * @bug 5072476 5108776 + * @run clean EventWithNamespaceTest EventWithNamespaceControlTest + * Wombat WombatMBean JMXRemoteTargetNamespace + * NamespaceController NamespaceControllerMBean + * @compile -XDignore.symbol.file=true EventWithNamespaceTest.java + EventWithNamespaceControlTest.java + * Wombat.java WombatMBean.java JMXRemoteTargetNamespace.java + * NamespaceController.java NamespaceControllerMBean.java + * @run main/othervm -Djmx.remote.use.event.service=true EventWithNamespaceControlTest + * @run main/othervm EventWithNamespaceControlTest + * @run main/othervm -Djmx.remote.delegate.event.service=false EventWithNamespaceControlTest java.lang.UnsupportedOperationException + */ + +import java.util.Collections; +import java.util.Map; +import java.util.logging.Logger; +import javax.management.RuntimeOperationsException; + +/** + * + * @author Sun Microsystems, Inc. + */ +public class EventWithNamespaceControlTest extends EventWithNamespaceTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(EventWithNamespaceControlTest.class.getName()); + + /** Creates a new instance of EventWithNamespaceTest */ + public EventWithNamespaceControlTest() { + } + + + + public static void main(String[] args) { + final EventWithNamespaceControlTest test = + new EventWithNamespaceControlTest(); + if (args.length == 0) { + test.run(args); + System.out.println("Test successfully passed"); + } else { + try { + test.run(args); + throw new RuntimeException("Test should have failed."); + } catch (RuntimeOperationsException x) { + if (! args[0].equals(x.getCause().getClass().getName())) { + System.err.println("Unexpected wrapped exception: "+ + x.getCause()); + throw x; + } else { + System.out.println("Got expected exception: "+x.getCause()); + } + } + } + } + + public Map getServerMap() { + Map retValue = Collections.emptyMap(); + return retValue; + } + +} diff --git a/test/javax/management/namespace/EventWithNamespaceTest.java b/test/javax/management/namespace/EventWithNamespaceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..748fdbeff148742e934c7ff6155a1e8e2bb07cbe --- /dev/null +++ b/test/javax/management/namespace/EventWithNamespaceTest.java @@ -0,0 +1,241 @@ +/* + * 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. + * + * 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. + */ + +/* + * + * @test EventWithNamespaceTest.java 1.8 + * @bug 6539857 5072476 5108776 + * @summary General Namespace & Notifications test. + * @author Daniel Fuchs + * @run clean EventWithNamespaceTest Wombat WombatMBean + * JMXRemoteTargetNamespace + * NamespaceController NamespaceControllerMBean + * @compile -XDignore.symbol.file=true EventWithNamespaceTest.java + * Wombat.java WombatMBean.java JMXRemoteTargetNamespace.java + * NamespaceController.java NamespaceControllerMBean.java + * @run main EventWithNamespaceTest + */ + +import java.lang.management.ManagementFactory; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespaces; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * + * @author Sun Microsystems, Inc. + */ +public class EventWithNamespaceTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(EventWithNamespaceTest.class.getName()); + + /** Creates a new instance of EventWithNamespaceTest */ + public EventWithNamespaceTest() { + } + + private static Map singletonMap(String key, Object value) { + final Map map = new HashMap(); + map.put(key,value); + return map; + } + + public Map getServerMap() { + return singletonMap(JMXConnectorServer.DELEGATE_TO_EVENT_SERVICE,"true"); + } + + public JMXServiceURL export(MBeanServer server) + throws Exception { + final JMXServiceURL in = new JMXServiceURL("rmi",null,0); + final Map env = getServerMap(); + + final JMXConnectorServer cs = + JMXConnectorServerFactory.newJMXConnectorServer(in,env,null); + final ObjectName csname = ObjectName. + getInstance(cs.getClass().getPackage().getName()+ + ":type="+cs.getClass().getSimpleName()); + server.registerMBean(cs,csname); + cs.start(); + return cs.getAddress(); + } + + public static class Counter { + int count; + public synchronized int count() { + count++; + notifyAll(); + return count; + } + public synchronized int peek() { + return count; + } + public synchronized int waitfor(int max, long timeout) + throws InterruptedException { + final long start = System.currentTimeMillis(); + while (count < max && timeout > 0) { + final long rest = timeout - + (System.currentTimeMillis() - start); + if (rest <= 0) break; + wait(rest); + } + return count; + } + } + + public static class CounterListener + implements NotificationListener { + final private Counter counter; + public CounterListener(Counter counter) { + this.counter = counter; + } + public void handleNotification(Notification notification, + Object handback) { + System.out.println("Received notif from " + handback + + ":\n\t" + notification); + if (!notification.getSource().equals(handback)) { + System.err.println("OhOh... Unexpected source: \n\t"+ + notification.getSource()+"\n\twas expecting:\n\t"+ + handback); + } + counter.count(); + } + } + + public void simpleTest(String[] args) { + try { + final MBeanServer server1 = + ManagementFactory.getPlatformMBeanServer(); + final JMXServiceURL url1 = export(server1); + + final MBeanServer server2 = + MBeanServerFactory.createMBeanServer("server2"); + final JMXServiceURL url2 = export(server2); + + final MBeanServer server3 = + MBeanServerFactory.createMBeanServer("server3"); + final JMXServiceURL url3 = export(server3); + + final ObjectInstance ncinst = + NamespaceController.createInstance(server1); + + final NamespaceControllerMBean nc = + JMX.newMBeanProxy(server1,ncinst.getObjectName(), + NamespaceControllerMBean.class); + + final String mount2 = nc.mount(url2,"server2",null); + final String mount3 = nc.mount(url3,"server2//server3", + null); + + final ObjectName deep = + new ObjectName("server2//server3//bush:type=Wombat,name=kanga"); + server1.createMBean(Wombat.class.getName(),deep); + + System.err.println("There's a wombat in the bush!"); + + final Counter counter = new Counter(); + + final NotificationListener listener = + new CounterListener(counter); + + final JMXConnector jc = JMXConnectorFactory.connect(url1); + final MBeanServerConnection conn1 = + jc.getMBeanServerConnection(); + final ObjectName shallow = + new ObjectName("bush:"+ + deep.getKeyPropertyListString()); + final MBeanServerConnection conn2 = + JMXNamespaces.narrowToNamespace(conn1,"server2//server3"); + + final WombatMBean proxy1 = + JMX.newMBeanProxy(conn1,deep,WombatMBean.class,true); + final WombatMBean proxy2 = + JMX.newMBeanProxy(conn2,shallow,WombatMBean.class,true); + + + System.err.println("Adding first Notification Listener"); + conn1.addNotificationListener(deep,listener,null,deep); + System.err.println("Adding second Notification Listener"); + ((NotificationEmitter)proxy2). + addNotificationListener(listener,null,shallow); + final JMXConnector c3 = JMXConnectorFactory.connect(url3, + singletonMap(JMXConnector.USE_EVENT_SERVICE,"false")); + System.err.println("Adding third Notification Listener"); + c3.getMBeanServerConnection(). + addNotificationListener(shallow,listener,null,shallow); + System.err.println("Set attribute to trigger notif"); + proxy1.setCaption("I am a new Wombat!"); + System.err.println("Get attribute"); + System.err.println("New caption: "+proxy2.getCaption()); + System.err.println("Wait for Notifs..."); + final int rcvcount = counter.waitfor(3,3000); + if (rcvcount != 3) + throw new RuntimeException("simpleTest failed: "+ + "received count is " +rcvcount); + System.err.println("simpleTest: got expected "+rcvcount+ + " notifs"); + + System.err.println("removing all listeners"); + conn1.removeNotificationListener(deep,listener,null,deep); + ((NotificationEmitter)proxy2) + .removeNotificationListener(listener,null,shallow); + c3.getMBeanServerConnection(). + removeNotificationListener(shallow,listener,null,shallow); + + System.err.println("simpleTest passed: got "+rcvcount+ + " notifs"); + + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException("simpleTest failed: " + x,x); + } + } + + public void run(String[] args) { + simpleTest(args); + } + + public static void main(String[] args) { + new EventWithNamespaceTest().run(args); + } + +} diff --git a/test/javax/management/namespace/ExportNamespaceTest.java b/test/javax/management/namespace/ExportNamespaceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ec49a4c0c0c00c55f5758463aef19ca6e07d2515 --- /dev/null +++ b/test/javax/management/namespace/ExportNamespaceTest.java @@ -0,0 +1,100 @@ +/* + * 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. + * + * 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. + */ +/* + * + * @test ExportNamespaceTest.java + * @summary Test that you can export a single namespace through a + * JMXConnectorServer. + * @author Daniel Fuchs + * @bug 5072476 + * @run clean ExportNamespaceTest Wombat WombatMBean + * @run build ExportNamespaceTest Wombat WombatMBean + * @run main ExportNamespaceTest + */ + +import javax.management.JMX; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + + +/** + * Test simple creation/registration of namespace. + * + */ +public class ExportNamespaceTest { + + public static void testExport() throws Exception { + final JMXNamespace my = + new JMXNamespace(MBeanServerFactory.newMBeanServer()); + final MBeanServer s = MBeanServerFactory.newMBeanServer(); + final ObjectName myname = JMXNamespaces.getNamespaceObjectName("my"); + final ObjectName wname = ObjectName.getInstance("backyard:type=Wombat"); + my.getSourceServer().registerMBean(new Wombat(),wname); + s.registerMBean(my,myname); + + if (!s.queryNames(new ObjectName("my//b*:*"),null).contains( + JMXNamespaces.insertPath("my", wname))) { + throw new RuntimeException("1: Wombat not found: "+wname); + } + + final MBeanServer cd = JMXNamespaces.narrowToNamespace(s, "my"); + if (!cd.queryNames(new ObjectName("b*:*"),null).contains(wname)) { + throw new RuntimeException("2: Wombat not found: "+wname); + } + + final JMXServiceURL url = new JMXServiceURL("rmi",null,0); + final JMXConnectorServer server = + JMXConnectorServerFactory.newJMXConnectorServer(url, null, cd); + server.start(); + + final JMXConnector jc = JMXConnectorFactory. + connect(server.getAddress(),null); + final MBeanServerConnection mbsc = jc.getMBeanServerConnection(); + + if (!mbsc.queryNames(new ObjectName("b*:*"),null).contains(wname)) { + throw new RuntimeException("3: Wombat not found: "+wname); + } + System.out.println("Found a Wombat in my backyard."); + + final String deepThoughts = "I want to leave this backyard!"; + final WombatMBean w = JMX.newMBeanProxy(mbsc, wname, WombatMBean.class); + w.setCaption(deepThoughts); + if (!deepThoughts.equals(w.getCaption())) + throw new RuntimeException("4: Wombat is not thinking right: "+ + w.getCaption()); + + } + + public static void main(String... args) throws Exception { + testExport(); + } +} diff --git a/test/javax/management/namespace/JMXDomainTest.java b/test/javax/management/namespace/JMXDomainTest.java new file mode 100644 index 0000000000000000000000000000000000000000..258cead1ab079dc321ac9c7856c5842981aa4dcf --- /dev/null +++ b/test/javax/management/namespace/JMXDomainTest.java @@ -0,0 +1,513 @@ +/* + * 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. + * + * 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. + */ +/* + * + * @test JMXDomainTest.java + * @bug 5072476 + * @summary Basic test for JMXDomain. + * @author Daniel Fuchs + * @run clean JMXDomainTest Wombat WombatMBean + * @run build JMXDomainTest Wombat WombatMBean + * @run main JMXDomainTest + */ + + +import java.util.Collections; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.Map; +import java.util.Set; +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.DynamicMBean; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.InvalidAttributeValueException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerFactory; +import javax.management.MBeanServerNotification; +import javax.management.NotCompliantMBeanException; +import javax.management.Notification; +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.ReflectionException; +import javax.management.namespace.JMXDomain; +import javax.management.namespace.MBeanServerSupport; + +/** + * Test simple creation/registration of namespace. + * + */ +public class JMXDomainTest { + private static Map emptyEnvMap() { + return Collections.emptyMap(); + } + + + public static class LocalDomainRepository + extends MBeanServerSupport { + private final MBeanServer server; + private final String domain; + + public class DynamicMBeanProxy implements DynamicMBean { + + private final MBeanServer server; + private final ObjectName name; + + public DynamicMBeanProxy(MBeanServer s, ObjectName n) { + this.server = s; + this.name = n; + } + + public Object getAttribute(String attribute) + throws AttributeNotFoundException, + MBeanException, ReflectionException { + try { + return server.getAttribute(name, attribute); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public void setAttribute(Attribute attribute) + throws AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException { + try { + server.setAttribute(name, attribute); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public AttributeList getAttributes(String[] attributes) { + try { + return server.getAttributes(name, attributes); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public AttributeList setAttributes(AttributeList attributes) { + try { + return server.setAttributes(name, attributes); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public Object invoke(String actionName, Object[] params, + String[] signature) throws MBeanException, + ReflectionException { + try { + return server.invoke(name, actionName, params, signature); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + public MBeanInfo getMBeanInfo() { + try { + return server.getMBeanInfo(name); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + } + + public LocalDomainRepository(String domain) { + this.server = MBeanServerFactory.newMBeanServer(); + this.domain = domain; + } + + @Override + protected Set getNames() { + try { + final ObjectName name = + ObjectName.getInstance(domain+":*"); + return server.queryNames(name, null); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + if (server.isRegistered(name)) + return new DynamicMBeanProxy(server, name); + throw new InstanceNotFoundException(name); + } + + + @Override + public NotificationEmitter + getNotificationEmitterFor(final ObjectName name) + throws InstanceNotFoundException { + if (server.isInstanceOf(name, NotificationEmitter.class.getName())) { + return new NotificationEmitter() { + + public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException { + try { + server.removeNotificationListener(name, listener, filter, handback); + } catch (InstanceNotFoundException x) { + throw new IllegalArgumentException(String.valueOf(name), x); + } + } + + public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException { + try { + server.addNotificationListener(name, listener, filter, handback); + } catch (InstanceNotFoundException x) { + throw new IllegalArgumentException(String.valueOf(name), x); + } + } + + public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { + try { + server.removeNotificationListener(name, listener); + } catch (InstanceNotFoundException x) { + throw new IllegalArgumentException(String.valueOf(name), x); + } + } + + public MBeanNotificationInfo[] getNotificationInfo() { + try { + return server.getMBeanInfo(name).getNotifications(); + } catch (Exception x) { + throw new IllegalArgumentException(String.valueOf(name), x); + } + } + }; + } + return null; + } + + @Override + public ObjectInstance registerMBean(Object object, ObjectName name) + throws InstanceAlreadyExistsException, + MBeanRegistrationException, NotCompliantMBeanException { + return server.registerMBean(object, name); + } + + @Override + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, + MBeanRegistrationException { + server.unregisterMBean(name); + } + + @Override + public ObjectInstance createMBean(String className, + ObjectName name, ObjectName loaderName, Object[] params, + String[] signature, boolean useCLR) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException { + if (useCLR && loaderName == null) { + return server.createMBean(className, name, params, signature); + } + return server.createMBean(className, name, loaderName, + params, signature); + } + + + } + + private static MBeanServer newMBeanServer() { + return MBeanServerFactory.newMBeanServer(); + } + + public static interface ThingMBean {} + public static class Thing implements ThingMBean, MBeanRegistration { + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + if (name == null) return new ObjectName(":type=Thing"); + else return name; + } + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + public void postDeregister() { + } + } + + /** + * Test that it is possible to create a dummy MBean with a null + * ObjectName - this is just a sanity check - as there are already + * other JMX tests that check that. + * + * @throws java.lang.Exception + */ + public static void testCreateWithNull() throws Exception { + final MBeanServer server = newMBeanServer(); + final ObjectInstance oi = server.registerMBean(new Thing(),null); + server.unregisterMBean(oi.getObjectName()); + System.out.println("testCreateWithNull PASSED"); + } + + public static void testRegisterSimple() throws Exception { + final ObjectName name = + JMXDomain.getDomainObjectName("gloups"); + final JMXDomain jmxDomain = new JMXDomain( + MBeanServerFactory.newMBeanServer()); + testRegister("testRegisterSimple: ",name,jmxDomain); + } + + public static void testRegisterPseudoVirtual() + throws Exception { + final ObjectName name = + JMXDomain.getDomainObjectName("gloups"); + final JMXDomain jmxDomain = new JMXDomain( + new LocalDomainRepository("gloups")); + testRegister("testRegisterPseudoVirtual: ",name,jmxDomain); + } + + public static void testRegister(final String test, + final ObjectName name, + final JMXDomain jmxDomain) throws Exception { + System.out.println(test+" START"); + MBeanServer server = newMBeanServer(); + final ObjectInstance oi = + server.registerMBean(jmxDomain,name); + System.out.println(test+"Succesfully registered namespace: "+name); + if (!server.isRegistered(name)) + fail(test+name+" is not registered!"); + if (!server.queryNames(new ObjectName(name.getDomain()+":*"), null). + contains(name)) + fail(test+name+" not in queryNames"); + + final Thing thing = new Thing(); + final ObjectName thingName = new ObjectName("gloups:type=Thing"); + server.registerMBean(thing,thingName); + if (!server.isRegistered(thingName)) + fail(test+thingName+" is not registered!"); + if (!jmxDomain.getSourceServer().isRegistered(thingName)) + fail(test+thingName+" is not registered in domain!"); + if (!server.queryNames(new ObjectName(name.getDomain()+":*"), null). + contains(thingName)) + fail(test+thingName+" not in queryNames"); + + server.unregisterMBean(name); + if (server.isRegistered(thingName)) + fail(test+thingName+" is still registered!"); + if (server.queryNames(new ObjectName(name.getDomain()+":*"), null). + contains(thingName)) + fail(test+thingName+" still in queryNames"); + + server.registerMBean(jmxDomain, name); + if (!server.isRegistered(thingName)) + fail(test+thingName+" is not registered again!"); + + System.out.println(test+" PASSED"); + } + + private static MBeanServerNotification pop( + BlockingQueue queue, + String type, + ObjectName mbean, + String test) + throws InterruptedException { + final Notification n = queue.poll(1, TimeUnit.SECONDS); + if (!(n instanceof MBeanServerNotification)) + fail(test+"expected MBeanServerNotification, got "+n); + final MBeanServerNotification msn = (MBeanServerNotification)n; + if (!type.equals(msn.getType())) + fail(test+"expected "+type+", got "+msn.getType()); + if (!mbean.apply(msn.getMBeanName())) + fail(test+"expected "+mbean+", got "+msn.getMBeanName()); + System.out.println(test+" got: "+msn); + return msn; + } + private static MBeanServerNotification popADD( + BlockingQueue queue, + ObjectName mbean, + String test) + throws InterruptedException { + return pop(queue, MBeanServerNotification.REGISTRATION_NOTIFICATION, + mbean, test); + } + + private static MBeanServerNotification popREM( + BlockingQueue queue, + ObjectName mbean, + String test) + throws InterruptedException { + return pop(queue, MBeanServerNotification.UNREGISTRATION_NOTIFICATION, + mbean, test); + } + + + public static void testRegisterNotifSimple() throws Exception { + final ObjectName name = + JMXDomain.getDomainObjectName("gloups"); + final JMXDomain jmxDomain = new JMXDomain( + MBeanServerFactory.newMBeanServer()); + testRegisterNotif("testRegisterNotifSimple: ",name,jmxDomain); + } + + public static void testRegisterNotifPseudoVirtual() + throws Exception { + final ObjectName name = + JMXDomain.getDomainObjectName("gloups"); + final JMXDomain jmxDomain = new JMXDomain( + new LocalDomainRepository("gloups")); + testRegisterNotif("testRegisterNotifPseudoVirtual: ",name,jmxDomain); + } + + public static void testRegisterNotif(final String test, + final ObjectName name, + final JMXDomain jmxDomain) throws Exception { + System.out.println(test+" START"); + MBeanServer server = newMBeanServer(); + final ObjectInstance oi = + server.registerMBean(jmxDomain,name); + System.out.println(test+"Succesfully registered namespace: "+name); + if (!server.isRegistered(name)) + fail(test+name+" is not registered!"); + + final BlockingQueue queue = + new ArrayBlockingQueue(10); + + final NotificationListener l = new NotificationListener() { + + public void handleNotification(Notification notification, + Object handback) { + try { + if (!queue.offer(notification,5,TimeUnit.SECONDS)) + throw new RuntimeException("timeout exceeded"); + } catch (Exception x) { + fail(test+"failed to handle notif", x); + } + } + }; + + server.addNotificationListener(MBeanServerDelegate.DELEGATE_NAME, l, + null, null); + + final Thing thing = new Thing(); + final ObjectName thingName = new ObjectName("gloups:type=Thing"); + + server.registerMBean(thing,thingName); + if (!jmxDomain.getSourceServer().isRegistered(thingName)) + fail(test+thingName+" is not registered in domain!"); + popADD(queue, thingName, test); + server.unregisterMBean(thingName); + if (jmxDomain.getSourceServer().isRegistered(thingName)) + fail(test+thingName+" is still registered in domain!"); + popREM(queue, thingName, test); + if (queue.size() != 0) + fail(test+queue.size()+" notifs remain in queue "+queue); + + server.unregisterMBean(name); + popREM(queue, name, test); + + jmxDomain.getSourceServer().registerMBean(thing,thingName); + if (server.isRegistered(thingName)) + fail(test+thingName+" is still registered in domain!"); + jmxDomain.getSourceServer().unregisterMBean(thingName); + if (queue.size() != 0) + fail(test+queue.size()+" notifs remain in queue "+queue); + + server.registerMBean(jmxDomain, name); + if (!server.isRegistered(name)) + fail(test+name+" is not registered again!"); + popADD(queue, name, test); + if (queue.size() != 0) + fail(test+queue.size()+" notifs remain in queue "+queue); + + server.registerMBean(thing,thingName); + if (!jmxDomain.getSourceServer().isRegistered(thingName)) + fail(test+thingName+" is not registered in domain!"); + popADD(queue, thingName, test); + server.unregisterMBean(thingName); + if (jmxDomain.getSourceServer().isRegistered(thingName)) + fail(test+thingName+" is still registered in domain!"); + popREM(queue, thingName, test); + if (queue.size() != 0) + fail(test+queue.size()+" notifs remain in queue "+queue); + + System.out.println(test+" PASSED"); + } + + + + private static void fail(String msg) { + raise(new RuntimeException(msg)); + } + + private static void fail(String msg, Throwable cause) { + raise(new RuntimeException(msg,cause)); + } + + private static void raise(RuntimeException x) { + lastException = x; + exceptionCount++; + throw x; + } + + private static volatile Exception lastException = null; + private static volatile int exceptionCount = 0; + + public static void main(String... args) throws Exception { + testCreateWithNull(); + + testRegisterSimple(); + testRegisterNotifSimple(); + + testRegisterPseudoVirtual(); + testRegisterNotifPseudoVirtual(); + + if (lastException != null) + throw lastException; + } +} diff --git a/test/javax/management/namespace/JMXNamespaceSecurityTest.java b/test/javax/management/namespace/JMXNamespaceSecurityTest.java new file mode 100644 index 0000000000000000000000000000000000000000..213ffbfb63e734be4bb10ce6cd8ed85586e1e320 --- /dev/null +++ b/test/javax/management/namespace/JMXNamespaceSecurityTest.java @@ -0,0 +1,273 @@ +/* + * 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. + * + * 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. + */ + +/* + * + * @test JMXNamespaceSecurityTest.java + * @summary General JMXNamespaceSecurityTest test. + * @author Daniel Fuchs + * @bug 5072476 6299231 + * @run clean JMXNamespaceViewTest JMXNamespaceSecurityTest Wombat WombatMBean + * LazyDomainTest + * @run build JMXNamespaceSecurityTest JMXNamespaceViewTest Wombat WombatMBean + * LazyDomainTest + * @run main/othervm JMXNamespaceSecurityTest namespace.policy + */ +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; +import java.util.TreeSet; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.ObjectName; +import javax.management.namespace.JMXDomain; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.remote.JMXConnectorServer; + +/** + * + * @author Sun Microsystems, Inc. + */ +public class JMXNamespaceSecurityTest extends JMXNamespaceViewTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(JMXNamespaceSecurityTest.class.getName()); + + public static class NamedMBeanServerCreator + extends JMXNamespaceViewTest.MBeanServerConfigCreator { + public MBeanServer createMBeanServerFor(NamespaceConfig config) { + return MBeanServerFactory. + createNamedMBeanServer(config.name,config.name); + } + } + /** + * Creates a config for a hierarchy of namespaces, mixing local namespaces + * and remote namespaces using the given protocol. + * @param protocol The protocol that should be used for remote namespaces. + * @return A namespace config hierarchy. + * @throws java.lang.Exception + */ + public static NamespaceConfig[] makeConfig(String protocol) + throws Exception { + final NamespaceConfig[] config = { + // Top level namespace "top1" (local) + config("top1",wombats("wchief","w1","w2","w3"), + // top1//local1 + config("local1",wombats("wchief","ww1","ww2")), + // top1//local2 + config("local2",wombats("wchief","ww4","ww5","ww6"), + // top1//local2//local3 + config("local3",wombats("wchief","www1","www2")), + // top1//local2//rmi1 + config("rmi1",url(protocol),wombats("wchief","www3","www4","www5"))), + // top1//rmi2 + config("rmi2",url(protocol),wombats("wchief","ww7","ww8","ww9"), + // top1//rmi2//local4 + config("local4",wombats("wchief","www6","www7")), + // top1//rmi2//rmi3 + config("rmi3",url(protocol),wombats("wchief","www3","www4","www5"), + // top1//rmi2//rmi3//local5 + config("local5",wombats("wchief","wwww1"))))), + // Top level namespace "top2" (local) + config("top2",wombats("wchief","w21","w22","w23"), + // top2//local21 + config("local21",wombats("wchief","ww21","ww22")), + // top2//rmi22 + config("rmi22",url(protocol),wombats("wchief","ww27","ww28","ww29"), + // top2//rmi22//local24 + config("local24",wombats("wchief","www26","www27")), + // top2//rmi22//rmi23 + config("rmi23",url(protocol),wombats("wchief","www23","www24","www25"), + // top2//rmi22//rmi23//local25 + config("local25",wombats("wchief","wwww21"))))), + // Top level namespace "top3" (remote) + config("top3",url(protocol),wombats("wchief","w31","w32","w33"), + // top3//local31 + config("local31",wombats("wchief","ww31","ww32")), + // top3//rmi32 + config("rmi32",url(protocol),wombats("wchief","ww37","ww38","ww39"), + // top3//rmi32//local34 + config("local34",wombats("wchief","www36","www37")), + // top3//rmi32//rmi33 + config("rmi33",url(protocol),wombats("wchief","www33","www34","www35"), + // top3//rmi32//local35 + config("local35",wombats("wchief","wwww31"))))), + }; + return config; + } + + public static void test(MBeanServer server, NamespaceConfig[] namespaces) + throws Exception { + System.out.println("Launching test..."); + List cslist = load(server, + new NamedMBeanServerCreator(), namespaces); + Map inputMap = + new HashMap(); + + for (NamespaceConfig cfg : namespaces) { + fillMap(inputMap,"",cfg); + } + final MBeanServer platform = ManagementFactory.getPlatformMBeanServer(); + //if (System.getProperty("jmx.wait")!=null) { + /* + // if we wanted to lazy load the platform MBeanServer: + final LazyDomainTest.MBeanServerLoader loader = + new LazyDomainTest.MBeanServerLoader() { + public MBeanServer loadMBeanServer() { + return ManagementFactory.getPlatformMBeanServer(); + } + }; + final LazyDomainTest.MBeanServerProxy proxy = + new LazyDomainTest.MBeanServerProxy(loader); + final LazyDomainTest.LazyDomain domain = + new LazyDomainTest.LazyDomain(proxy); + server.registerMBean(domain, + JMXDomain.getDomainObjectName("java.lang")); + */ + // Mount java.lang MBeans into our private server so that + // visualvm can connect. + server.registerMBean( + new JMXDomain(platform), + JMXDomain.getDomainObjectName("java.lang")); + //} + if (System.getProperty("jmx.wait")!=null) { + platform.registerMBean(new JMXNamespace(server), + JMXNamespaces.getNamespaceObjectName("test")); + } + + System.setSecurityManager(new SecurityManager()); + + // Some sanity checks... The policy file should allow access + // to java.lang MBeans. + final ObjectName platnames = new ObjectName("java.lang:*"); + for (ObjectName o : platform.queryNames(platnames,null)) { + server.getMBeanInfo(o); + } + final Set lang = + new HashSet(server.queryNames(platnames, null)); + lang.remove(JMXDomain.getDomainObjectName("java.lang")); + if (!lang.equals(platform. + queryNames(platnames, null))) + throw new Exception("Wrong list of platform names: "+lang); + System.out.println("Got all java.lang MBeans: "+lang); + + // The policy file should allow to see all namespaces. + // check this... + final List patterns = new ArrayList(); + final Set paths = new TreeSet(); + final Set uuids = new HashSet(); + patterns.add(new ObjectName("*//:*")); + while (patterns.size()>0) { + System.out.println("server.queryNames("+patterns.get(0)+",null)"); + Set names = server.queryNames(patterns.remove(0),null); + System.out.println("found: "+names); + + for (ObjectName no : names) { + final String uuid = (String) server.getAttribute(no, "UUID"); + if (uuids.contains(uuid)) { + System.out.print("namespace "+no+", uuid="+uuid+ + " already parsed. Skipping"); + continue; + } + uuids.add(uuid); + patterns.add(new ObjectName(no.getDomain()+"*//:*")); + System.out.println("added pattern: "+ + new ObjectName(no.getDomain()+"*//:*")); + if (no.getDomain().endsWith(ClientContext.NAMESPACE+ + JMXNamespaces.NAMESPACE_SEPARATOR)) continue; + paths.add(no.getDomain().substring(0, + no.getDomain().length()- + JMXNamespaces.NAMESPACE_SEPARATOR.length())); + } + } + final TreeSet expected = new TreeSet(inputMap.keySet()); + if (!expected.equals(paths)) { + throw new Exception("wrong set of namespaces, expected "+ + expected+", got "+paths); + } + + System.out.println("Got all namespaces: "+paths); + + // Check that we can see all wombats. + // + ObjectName wchief = + new ObjectName("top1//rmi2//wombat:name=wchief,type=Wombat"); + String caption = (String) server.getAttribute(wchief,"Caption"); + System.out.println("wchief says "+caption); + Object mood = server.getAttribute(wchief,"Mood"); + System.out.println("wchief's mood on a scale of 100 is "+mood); + + ObjectName wchief2 = + new ObjectName("top1//wombat:name=wchief,type=Wombat"); + String caption2 = (String) server.getAttribute(wchief2,"Caption"); + System.out.println("wchief2 says "+caption2); + try { + Object mood2 = server.getAttribute(wchief2,"Mood"); + System.out.println("wchief2's mood on a scale of 100 is "+mood2); + throw new Exception("Expected security exception for "+ + "getAttribute("+wchief2+", \"Mood\""); + } catch (SecurityException x) { + System.out.println("wchief2's mood is unavailable: "+x); + } + try { + exportAndWaitIfNeeded(server); + } finally { + closeAll(cslist); + } + + } + /** Creates a new instance of JMXNamespaceTest */ + public JMXNamespaceSecurityTest() { + } + + public static void main(String[] args) throws Exception { + String osName = System.getProperty("os.name"); + System.out.println("os.name = " + osName); + if (!osName.equals("SunOS")) { + System.out.println("This test runs on Solaris only."); + System.out.println("Bye! Bye!"); + return; + } + final String policy = System.getProperty("test.src") + + File.separator + args[0]; + System.out.println("PolicyFile = " + policy); + System.setProperty("java.security.policy", policy); + if (!new File(System.getProperty("java.security.policy")).canRead()) + throw new IOException("no such file: "+ + System.getProperty("java.security.policy")); + test(MBeanServerFactory.createNamedMBeanServer("root","root"), + makeConfig("rmi")); + } + +} diff --git a/test/javax/management/namespace/JMXNamespaceTest.java b/test/javax/management/namespace/JMXNamespaceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a35377112aa5e08a82d4a841ae5aa3a2ffa1c1f1 --- /dev/null +++ b/test/javax/management/namespace/JMXNamespaceTest.java @@ -0,0 +1,511 @@ +/* + * 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. + * + * 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. + */ + +/* + * + * @test JMXNamespaceTest.java + * @summary General JMXNamespace test. + * @bug 5072476 + * @author Daniel Fuchs + * @run clean JMXNamespaceTest + * Wombat WombatMBean JMXRemoteTargetNamespace + * NamespaceController NamespaceControllerMBean + * @compile -XDignore.symbol.file=true JMXNamespaceTest.java + * Wombat.java WombatMBean.java JMXRemoteTargetNamespace.java + * NamespaceController.java NamespaceControllerMBean.java + * @run main/othervm JMXNamespaceTest + */ +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; +import javax.management.DynamicMBean; +import javax.management.InstanceNotFoundException; +import javax.management.InvalidAttributeValueException; +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.NotificationEmitter; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.StandardMBean; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaceMBean; +import javax.management.namespace.JMXRemoteNamespaceMBean; +import javax.management.namespace.MBeanServerConnectionWrapper; +import javax.management.namespace.MBeanServerSupport; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * + * @author Sun Microsystems, Inc. + */ +public class JMXNamespaceTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(JMXNamespaceTest.class.getName()); + + /** Creates a new instance of JMXNamespaceTest */ + public JMXNamespaceTest() { + } + + public static class WombatRepository extends MBeanServerSupport { + final Wombat wombat; + final StandardMBean mbean; + final ObjectName wombatName; + + public WombatRepository(ObjectName wombatName) { + try { + wombat = new Wombat(); + mbean = wombat; + this.wombatName = wombatName; + wombat.preRegister(null,wombatName); + } catch (Exception x) { + throw new IllegalArgumentException(x); + } + } + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + if (wombatName.equals(name)) return mbean; + else throw new InstanceNotFoundException(String.valueOf(name)); + } + + @Override + protected Set getNames() { + final Set res = Collections.singleton(wombatName); + return res; + } + + @Override + public NotificationEmitter + getNotificationEmitterFor(ObjectName name) + throws InstanceNotFoundException { + final DynamicMBean mb = getDynamicMBeanFor(name); + if (mb instanceof NotificationEmitter) + return (NotificationEmitter)mb; + return null; + } + } + + public static class SimpleTest { + public final String descr; + private final Class testClass; + private final Method method; + public SimpleTest(String descr) { + this.descr = descr; + this.testClass = JMXNamespaceTest.class; + try { + method = testClass. + getDeclaredMethod(descr,SimpleTestConf.class, + Object[].class); + } catch (NoSuchMethodException x) { + throw new IllegalArgumentException(descr+": test not found", + x); + } + } + + public void run(SimpleTestConf conf, Object... args) + throws Exception { + try { + method.invoke(null,conf,args); + } catch (InvocationTargetException x) { + final Throwable cause = x.getCause(); + if (cause instanceof Exception) throw (Exception)cause; + if (cause instanceof Error) throw (Error)cause; + throw x; + } + } + } + + public static class SimpleTestConf { + public final Wombat wombat; + public final StandardMBean mbean; + public final String dirname; + public final ObjectName handlerName; + public final ObjectName wombatNickName; + public final ObjectName wombatName; + public final JMXNamespace wombatNamespace; + public final MBeanServer server; + public final WombatMBean proxy; + public SimpleTestConf(String[] args) throws Exception { + wombat = new Wombat(); + mbean = wombat; + dirname = "wombat"; + handlerName = + new ObjectName(dirname+"//:type=JMXNamespace"); + + wombatNickName = + new ObjectName("burrow:type=Wombat"); + + wombatName = + new ObjectName(dirname+"//"+wombatNickName); + + wombatNamespace = + new JMXNamespace( + new WombatRepository(wombatNickName)); + + server = ManagementFactory.getPlatformMBeanServer(); + System.out.println(handlerName+" registered="+ + server.isRegistered(handlerName)); + server.registerMBean(wombatNamespace,handlerName); + + try { + proxy = JMX.newMBeanProxy(server,wombatName, + WombatMBean.class); + } catch (Exception x) { + server.unregisterMBean(handlerName); + throw x; + } + } + + public void close() { + try { + server.unregisterMBean(handlerName); + } catch (Exception x) { + System.out.println("Failed to close: " + x); + x.printStackTrace(); + } + } + + public void test(SimpleTest test,Object... args) + throws Exception { + try { + test.run(this,args); + passed++; + } catch (Exception x) { + failed++; + System.err.println(test.descr+" failed: " + x); + x.printStackTrace(); + } + } + + public volatile int failed = 0; + public volatile int passed = 0; + } + + static void checkValue(String name,Object expected, Object returned) + throws InvalidAttributeValueException { + if (Collections.singletonList(expected). + equals(Collections.singletonList(returned))) return; + + throw new InvalidAttributeValueException("Bad value for "+ + name+": ["+returned+"] - was expecting ["+expected+"]"); + } + + // --------------------------------------------------------------- + // SIMPLE TESTS BEGIN HERE + // --------------------------------------------------------------- + + static void getCaptionTest(SimpleTestConf env, Object... args) + throws Exception { + System.out.println(env.proxy.getCaption()); + } + + static void setCaptionTest(SimpleTestConf env, Object... args) + throws Exception { + env.proxy.setCaption((String)args[0]); + final String result = env.proxy.getCaption(); + System.out.println(result); + checkValue("Caption",args[0],result); + } + + static void queryNamesTest1(SimpleTestConf env, Object... args) + throws Exception { + final ObjectName pat = + new ObjectName(env.handlerName.getDomain()+"*:*"); + final Set res = + env.server.queryNames(pat,null); + System.out.println("queryNamesTest1: "+res); + checkValue("names",Collections.singleton(env.wombatName),res); + } + + static void queryNamesTest2(SimpleTestConf env, Object... args) + throws Exception { + final ObjectName pat = + new ObjectName("*:"+ + env.wombatName.getKeyPropertyListString()); + final Set res = + env.server.queryNames(pat,null); + System.out.println("queryNamesTest2: "+res); + checkValue("names",Collections.emptySet(),res); + } + + static void getDomainsTest(SimpleTestConf env, Object... args) + throws Exception { + final List domains = + Arrays.asList(env.server.getDomains()); + System.out.println("getDomainsTest: "+domains); + if (domains.contains(env.wombatName.getDomain())) + throw new InvalidAttributeValueException("domain: "+ + env.wombatName.getDomain()); + if (!domains.contains(env.handlerName.getDomain())) + throw new InvalidAttributeValueException("domain not found: "+ + env.handlerName.getDomain()); + } + + // --------------------------------------------------------------- + // SIMPLE TESTS END HERE + // --------------------------------------------------------------- + + private static void simpleTest(String[] args) { + final SimpleTestConf conf; + try { + conf = new SimpleTestConf(args); + try { + conf.test(new SimpleTest("getCaptionTest")); + conf.test(new SimpleTest("setCaptionTest"), + "I am a new Wombat!"); + conf.test(new SimpleTest("queryNamesTest1")); + conf.test(new SimpleTest("queryNamesTest2")); + conf.test(new SimpleTest("getDomainsTest")); + } finally { + conf.close(); + } + } catch (Exception x) { + System.err.println("simpleTest FAILED: " +x); + x.printStackTrace(); + throw new RuntimeException(x); + } + System.out.println("simpleTest: "+conf.passed+ + " PASSED, " + conf.failed + " FAILED."); + if (conf.failed>0) { + System.err.println("simpleTest FAILED ["+conf.failed+"]"); + throw new RuntimeException("simpleTest FAILED ["+conf.failed+"]"); + } else { + System.err.println("simpleTest PASSED ["+conf.passed+"]"); + } + } + + public static void recursiveTest(String[] args) { + final SimpleTestConf conf; + try { + conf = new SimpleTestConf(args); + try { + final JMXServiceURL url = + new JMXServiceURL("rmi","localHost",0); + final Map empty = Collections.emptyMap(); + final JMXConnectorServer server = + JMXConnectorServerFactory.newJMXConnectorServer(url, + empty,conf.server); + server.start(); + final JMXServiceURL address = server.getAddress(); + final JMXConnector client = + JMXConnectorFactory.connect(address, + empty); + final String[] signature = { + JMXServiceURL.class.getName(), + Map.class.getName(), + }; + final String[] signature2 = { + JMXServiceURL.class.getName(), + Map.class.getName(), + String.class.getName(), + }; + final Object[] params = { + address, + null, + }; + final MBeanServerConnection c = + client.getMBeanServerConnection(); + final ObjectName dirName1 = + new ObjectName("kanga//:type=JMXNamespace"); + c.createMBean(JMXRemoteTargetNamespace.class.getName(), + dirName1, params,signature); + c.invoke(dirName1, "connect", null, null); + try { + final MemoryMXBean memory = + JMX.newMXBeanProxy(c, + new ObjectName("kanga//"+ + ManagementFactory.MEMORY_MXBEAN_NAME), + MemoryMXBean.class); + System.out.println("HeapMemory #1: "+ + memory.getHeapMemoryUsage().toString()); + final MemoryMXBean memory2 = + JMX.newMXBeanProxy(c, + new ObjectName("kanga//kanga//"+ + ManagementFactory.MEMORY_MXBEAN_NAME), + MemoryMXBean.class); + System.out.println("HeapMemory #2: "+ + memory2.getHeapMemoryUsage().toString()); + final Object[] params2 = { + address, + null, + "kanga//kanga" + // "kanga//kanga//roo//kanga", <= cycle + }; + final ObjectName dirName2 = + new ObjectName("kanga//roo//:type=JMXNamespace"); + c.createMBean(JMXRemoteTargetNamespace.class.getName(), + dirName2, params2, signature2); + System.out.println(dirName2 + " created!"); + JMX.newMBeanProxy(c,dirName2, + JMXRemoteNamespaceMBean.class).connect(); + try { + final ObjectName wombatName1 = + new ObjectName("kanga//roo//"+conf.wombatName); + final ObjectName wombatName2 = + new ObjectName("kanga//roo//"+wombatName1); + final WombatMBean wombat1 = + JMX.newMBeanProxy(c,wombatName1,WombatMBean.class); + final WombatMBean wombat2 = + JMX.newMBeanProxy(c,wombatName2,WombatMBean.class); + final String newCaption="I am still the same old wombat"; + wombat1.setCaption(newCaption); + final String caps = conf.proxy.getCaption(); + System.out.println("Caption: "+caps); + checkValue("Caption",newCaption,caps); + final String caps1 = wombat1.getCaption(); + System.out.println("Caption #1: "+caps1); + checkValue("Caption #1",newCaption,caps1); + final String caps2 = wombat2.getCaption(); + System.out.println("Caption #2: "+caps2); + checkValue("Caption #2",newCaption,caps2); + final ObjectInstance instance = + NamespaceController.createInstance(conf.server); + final NamespaceControllerMBean controller = + JMX.newMBeanProxy(conf.server,instance.getObjectName(), + NamespaceControllerMBean.class); + final String[] dirs = controller.findNamespaces(); + System.out.println("directories: " + + Arrays.asList(dirs)); + final int depth = 4; + final String[] dirs2 = controller.findNamespaces(null,null,depth); + System.out.println("directories[depth="+depth+"]: " + + Arrays.asList(dirs2)); + for (String dir : dirs2) { + if (dir.endsWith(JMXNamespaces.NAMESPACE_SEPARATOR)) + dir = dir.substring(0,dir.length()- + JMXNamespaces.NAMESPACE_SEPARATOR.length()); + if (dir.split(JMXNamespaces.NAMESPACE_SEPARATOR).length + > (depth+1)) { + throw new RuntimeException(dir+": depth exceeds "+depth); + } + final ObjectName handlerName = + JMXNamespaces.getNamespaceObjectName(dir); + final JMXNamespaceMBean handler = + JMX.newMBeanProxy(conf.server,handlerName, + JMXNamespaceMBean.class); + try { + System.err.println("Directory "+dir+" domains: "+ + Arrays.asList(handler.getDomains())); + System.err.println("Directory "+dir+" default domain: "+ + handler.getDefaultDomain()); + System.err.println("Directory "+dir+" MBean count: "+ + handler.getMBeanCount()); + } catch(Exception x) { + System.err.println("get info failed for " + + dir +", "+handlerName+": "+x); + x.getCause().printStackTrace(); + throw x; + } + } + + } finally { + c.unregisterMBean(dirName2); + } + } finally { + c.unregisterMBean(dirName1); + client.close(); + server.stop(); + } + } finally { + conf.close(); + } + System.err.println("recursiveTest PASSED"); + } catch (Exception x) { + System.err.println("recursiveTest FAILED: " +x); + x.printStackTrace(); + throw new RuntimeException(x); + } + } + + public static void verySimpleTest(String[] args) { + System.err.println("verySimpleTest: starting"); + try { + final MBeanServer srv = MBeanServerFactory.createMBeanServer(); + srv.registerMBean(new JMXNamespace( + JMXNamespaces.narrowToNamespace(srv, "foo")), + JMXNamespaces.getNamespaceObjectName("foo")); + throw new Exception("Excpected IllegalArgumentException not raised."); + } catch (IllegalArgumentException x) { + System.err.println("verySimpleTest: got expected exception: "+x); + } catch (Exception x) { + System.err.println("verySimpleTest FAILED: " +x); + x.printStackTrace(); + throw new RuntimeException(x); + } + System.err.println("verySimpleTest: PASSED"); + } + + public static void verySimpleTest2(String[] args) { + System.err.println("verySimpleTest2: starting"); + try { + final MBeanServer srv = MBeanServerFactory.createMBeanServer(); + final JMXConnectorServer cs = JMXConnectorServerFactory. + newJMXConnectorServer(new JMXServiceURL("rmi",null,0), + null, srv); + cs.start(); + final JMXConnector cc = JMXConnectorFactory.connect(cs.getAddress()); + + srv.registerMBean(new JMXNamespace( + new MBeanServerConnectionWrapper( + JMXNamespaces.narrowToNamespace( + cc.getMBeanServerConnection(), + "foo"))), + JMXNamespaces.getNamespaceObjectName("foo")); + throw new Exception("Excpected IllegalArgumentException not raised."); + } catch (IllegalArgumentException x) { + System.err.println("verySimpleTest2: got expected exception: "+x); + } catch (Exception x) { + System.err.println("verySimpleTest2 FAILED: " +x); + x.printStackTrace(); + throw new RuntimeException(x); + } + System.err.println("verySimpleTest2: PASSED"); + } + + public static void main(String[] args) { + simpleTest(args); + recursiveTest(args); + verySimpleTest(args); + verySimpleTest2(args); + } + +} diff --git a/test/javax/management/namespace/JMXNamespaceViewTest.java b/test/javax/management/namespace/JMXNamespaceViewTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e134968296b9990c95694bd41b74ca11c6637dfe --- /dev/null +++ b/test/javax/management/namespace/JMXNamespaceViewTest.java @@ -0,0 +1,550 @@ +/* + * 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. + * + * 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. + */ +/* + * + * @test JMXNamespaceViewTest.java + * @summary Test the JMXNamespaceView class. + * @bug 5072476 + * @author Daniel Fuchs + * @run clean JMXNamespaceViewTest Wombat WombatMBean + * @run build JMXNamespaceViewTest Wombat WombatMBean + * @run main JMXNamespaceViewTest + */ + + +import java.lang.management.ManagementFactory; +import java.net.ServerSocket; +import java.rmi.registry.LocateRegistry; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.management.JMException; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaceView; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.JMXRemoteNamespace; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * A simple test to test the JMXNamespaceViewTest... + * @author dfuchs + */ +public class JMXNamespaceViewTest { + + // TODO: Remove this when contexts are added. + public static class ClientContext { + public final static String NAMESPACE = "jmx.context"; + } + + /** + * Describe the configuration of a namespace + */ + public static class NamespaceConfig { + /** name of the namespace - no // allowed **/ + public String name; + /** + * JMXServiceURL through which the namespace is exported, if it + * is a remote namespace. {@code null} if the namespace is local. + * This is an inpur URL - eg: new JMXServiceURL("rmi",null,0).toString() + * is acceptable here. + */ + public String jmxurl; + /** + * Values of the name= key for each WombatMBean contained in the + * namespace. + */ + public String[] wombats; + /** list of child namespace **/ + public NamespaceConfig[] children; + } + + /** + * Creates a NamespaceConfig record for a local namespace. + * @param name name of the namespace + * @param wombats names of WombatMBean it should contain. + * @return a NamespaceConfig. + */ + public static NamespaceConfig config(String name, String[] wombats) { + return config(name,null,wombats); + } + + /** + * Creates a NamespaceConfig record for a remote namespace. + * @param name name of the namespace + * @param jmxurl input JMXServiceURL for creating the JMXConnectorServer + * @param wombats names of WombatMBean it should contain. + * @return a NamespaceConfig. + */ + public static NamespaceConfig config(String name, String jmxurl, + String[] wombats) { + return config(name,jmxurl,wombats,(NamespaceConfig[])null); + } + + /** + * Creates a NamespaceConfig record for a local namespace. + * @param name name of the namespace + * @param wombats names of WombatMBean it should contain. + * @param children list of sub namespaces. + * @return a NamespaceConfig. + */ + public static NamespaceConfig config(String name, String[] wombats, + NamespaceConfig... children) { + return config(name,null,wombats,children); + } + + /** + * Creates a NamespaceConfig record for a remote namespace. + * @param name name of the namespace + * @param jmxurl input JMXServiceURL for creating the JMXConnectorServer + * @param wombats names of WombatMBean it should contain. + * @param children list of sub namespaces. + * @return a NamespaceConfig. + */ + static NamespaceConfig config(String name, String jmxurl, String[] wombats, + NamespaceConfig... children) { + final NamespaceConfig cfg = new NamespaceConfig(); + cfg.name=name; cfg.jmxurl=jmxurl; cfg.wombats=wombats; + cfg.children=children; + return cfg; + } + + /** + * Returns the given names. This is a utility method to ease code + * reading. + * @param names names of Wombat MBeans. + * @return the given names. + */ + static String[] wombats(String... names) { + return names; + } + + /** + * Creates a JMXServiceURL string for the given protocol. + * This is also a utility method to ease code reading. + * @param protocol The protocol name (e.g. "rmi") + * @return A JMXServiceURL string. + * @throws Exception if creation of the JMXServiceURL fails. + */ + static String url(String protocol) throws Exception { + return new JMXServiceURL(protocol,null,0).toString(); + } + + /** + * Creates a config for a hierarchy of namespaces, mixing local namespaces + * and remote namespaces using the given protocol. + * @param protocol The protocol that should be used for remote namespaces. + * @return A namespace config hierarchy. + * @throws java.lang.Exception + */ + public static NamespaceConfig[] makeConfig(String protocol) + throws Exception { + final NamespaceConfig[] config = { + // Top level namespace "top1" (local) + config("top1",wombats("wchief","w1","w2","w3"), + // top1//local1 + config("local1",wombats("wchief","ww1","ww2")), + // top1//local2 + config("local2",wombats("wchief","ww4","ww5","ww6"), + // top1//local2//local3 + config("local3",wombats("wchief","www1","www2")), + // top1//local2//rmi1 + config("rmi1",url(protocol),wombats("wchief","www3","www4","www5"))), + // top1//rmi2 + config("rmi2",url(protocol),wombats("wchief","ww7","ww8","ww9"), + // top1//rmi2//local4 + config("local4",wombats("wchief","www6","www7")), + // top1//rmi2//rmi3 + config("rmi3",url(protocol),wombats("wchief","www3","www4","www5"), + // top1//rmi2//rmi3//local5 + config("local5",wombats("wchief","wwww1"))))), + // Top level namespace "top2" (local) + config("top2",wombats("wchief","w21","w22","w23"), + // top2//local21 + config("local21",wombats("wchief","ww21","ww22")), + // top2//rmi22 + config("rmi22",url(protocol),wombats("wchief","ww27","ww28","ww29"), + // top2//rmi22//local24 + config("local24",wombats("wchief","www26","www27")), + // top2//rmi22//rmi23 + config("rmi23",url(protocol),wombats("wchief","www23","www24","www25"), + // top2//rmi22//rmi23//local25 + config("local25",wombats("wchief","wwww21"))))), + // Top level namespace "top3" (remote) + config("top3",url(protocol),wombats("wchief","w31","w32","w33"), + // top3//local31 + config("local31",wombats("wchief","ww31","ww32")), + // top3//rmi32 + config("rmi32",url(protocol),wombats("wchief","ww37","ww38","ww39"), + // top3//rmi32//local34 + config("local34",wombats("wchief","www36","www37")), + // top3//rmi32//rmi33 + config("rmi33",url(protocol),wombats("wchief","www33","www34","www35"), + // top3//rmi32//local35 + config("local35",wombats("wchief","wwww31"))))), + }; + return config; + } + + /** + * Close all connector servers in the list. + * @param cslist List of connector servers to close. + */ + public static void closeAll(List cslist) { + for (JMXConnectorServer cs : cslist) { + try { + cs.stop(); + } catch (Exception xx) { + System.err.println("Failed to stop connector: " + xx); + } + } + } + + public static class MBeanServerConfigCreator { + public MBeanServer createMBeanServerFor(NamespaceConfig config) { + return MBeanServerFactory.newMBeanServer(); + } + } + + /** + * Load the given namespace configuration inside the given MBeanServer. + * Return a list of connector servers created in the process. + * @param server The MBeanServer in which the namespaces must + * be created. + * @param namespaces The list of namespaces to create. + * @return a list of started connector servers. + * @throws java.lang.Exception failed to create the specified namespaces. + */ + public static List load(MBeanServer server, + MBeanServerConfigCreator factory, + NamespaceConfig... namespaces) throws Exception { + final List cslist = + new ArrayList(); + try { + final ObjectName creator = + new ObjectName("jmx.creator:type=JMXNamespaceCreator"); + if (System.getProperty("jmx.wait")!=null + && !server.isRegistered(creator)) { + server.registerMBean(new JMXNamespaceCreator(),creator); + } + for (NamespaceConfig cfg : namespaces) { + final MBeanServer srv = factory.createMBeanServerFor(cfg); + if (System.getProperty("jmx.wait")!=null + && !srv.isRegistered(creator)) { + srv.registerMBean(new JMXNamespaceCreator(),creator); + } + if (cfg.wombats != null) { + for (String w : cfg.wombats) { + final ObjectName n = + new ObjectName("wombat:type=Wombat,name=" + w); + final WombatMBean ww = new Wombat(); + srv.registerMBean(ww, n); + } + } + if (cfg.children != null) { + cslist.addAll(load(srv, factory, cfg.children)); + } + JMXNamespace nm; + if (cfg.jmxurl == null) { + nm = new JMXNamespace(srv); + } else { + JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(new JMXServiceURL(cfg.jmxurl), + null, srv); + srv.registerMBean(cs, + new ObjectName("jmx.remote:type=JMXConnectorServer")); + cs.start(); + cslist.add(cs); + nm = JMXRemoteNamespace. + newJMXRemoteNamespace(cs.getAddress(), + null); + } + server.registerMBean(nm, + JMXNamespaces.getNamespaceObjectName(cfg.name)); + if (nm instanceof JMXRemoteNamespace) { + server.invoke( + JMXNamespaces.getNamespaceObjectName(cfg.name), + "connect", null, null); + } + } + } catch (Exception x) { + closeAll(cslist); + throw x; + } + return cslist; + } + + /** + * Add an entry {@code } in the map for the given + * namespace and its subnamespaces. + * @param map A {@code Map}. + * @param parent The path of the parent workspace. + * @param cfg The NamespaceConfig hierarchy to index in the map. + */ + public static void fillMap(Map map, String parent, + NamespaceConfig cfg) { + + final String where; + if (parent == null || parent.equals("")) + where=cfg.name; + else + where=parent+JMXNamespaces.NAMESPACE_SEPARATOR+cfg.name; + map.put(where,cfg); + if (cfg.children==null) return; + for(NamespaceConfig child:cfg.children) { + fillMap(map,where,child); + } + } + + /** + * Compare a list of namespace names obtained from JMXNamespaceView.list() + * with the expected clildren list of the corresponding NamespaceConfig. + * @param list A list of namespace names + * @param children A list of NamespaceConfig correspondng to expected + * namespace. + * @param fail If true and the comparison yields false, throws an + * exception instead of simply returning false. + * @return true if OK, false if NOK. + */ + private static boolean compare(String[] list, NamespaceConfig[] children, + boolean fail) { + final List found = new ArrayList(Arrays.asList(list)); + if (found.contains(ClientContext.NAMESPACE)) + found.remove(ClientContext.NAMESPACE); + + if (children == null && found.size()==0) return true; + if (children == null && fail == false) return false; + if (children == null) throw new RuntimeException( + "No child expected. Found "+Arrays.toString(list)); + final Set names = new HashSet(); + for (NamespaceConfig cfg : children) { + names.add(cfg.name); + if (found.contains(cfg.name)) continue; + if (!fail) return false; + throw new RuntimeException(cfg.name+" not found in "+ + found); + } + found.removeAll(names); + if (found.size()==0) return true; + if (fail==false) return false; + throw new RuntimeException("found additional namespaces: "+ + found); + } + + /** + * Compares the result of queryNames(null,null) with a set of expected + * wombats. + * @param where The path of the namespace that was queried. + * @param list The set of ObjectNames found. + * @param wombats The expected list of wombats. + * @param fail If true and the comparison yields false, throws an + * exception instead of simply returning false. + * @return true if OK, false if NOK. + * @throws java.lang.Exception something went wrong. + */ + private static boolean compare(String where, + Setlist, String[] wombats, + boolean fail) throws Exception { + final Set found = new HashSet(); + final Set expected = new HashSet(); + for (ObjectName n : list) { + if ("Wombat".equals(n.getKeyProperty("type"))) + found.add(n); + } + for(String w : wombats) { + final ObjectName n = + new ObjectName("wombat:type=Wombat,name=" + w); + expected.add(n); + if (found.contains(n)) continue; + if (fail == false) return false; + throw new RuntimeException(where+ + ": Wombat "+w+" not found in "+found); + } + found.removeAll(expected); + if (found.size()==0) { + System.out.println(where+": found all expected: "+expected); + return true; + } + if (fail==false) return false; + throw new RuntimeException(where+": found additional MBeans: "+ + found); + } + + /** + * A generic test to test JMXNamespaceView over a namespace configuration. + * @param server The MBeanServer in which to load the namespace + * config. + * @param namespaces The namespace config to run the test over... + * @throws java.lang.Exception + */ + public static void doTest(MBeanServer server, NamespaceConfig... namespaces) + throws Exception { + List cslist = load(server, + new MBeanServerConfigCreator(), namespaces); + Map inputMap = + new HashMap(); + + for (NamespaceConfig cfg : namespaces) { + fillMap(inputMap,"",cfg); + } + try { + final JMXNamespaceView root = new JMXNamespaceView(server); + List vlist = new ArrayList(); + vlist.add(root); + + while (!vlist.isEmpty()) { + JMXNamespaceView v = vlist.remove(0); + final String where = v.isRoot()?"root":v.where(); + System.out.println(where+": "+ + v.getMBeanServerConnection().queryNames(null,null)); + for (String ns : v.list()) { + final JMXNamespaceView down = v.down(ns); + vlist.add(down); + if (!down.where().equals(v.isRoot()?ns:where+ + JMXNamespaces.NAMESPACE_SEPARATOR+ns)) { + throw new RuntimeException("path of "+down.where()+ + " should be "+(v.isRoot()?ns:where+ + JMXNamespaces.NAMESPACE_SEPARATOR+ns)); + } + if (down.up().equals(v)) continue; + throw new RuntimeException("parent of "+down.where()+ + " should be "+where); + } + final NamespaceConfig[] children; + final NamespaceConfig cfg; + if (v.isRoot()) { + children=namespaces; + cfg = null; + } else { + cfg = inputMap.get(where); + children = cfg==null?null:cfg.children; + } + compare(v.list(),children,true); + if (!v.isRoot()) { + if (where.endsWith(ClientContext.NAMESPACE)) { + System.out.println(where+": skipping queryNames analysis"); + continue; + } + //System.out.println(where+": cfg is: "+cfg); + compare(where,v.getMBeanServerConnection(). + queryNames(null, null),cfg.wombats,true); + } + } + + exportAndWaitIfNeeded(server); + } finally { + closeAll(cslist); + } + } + + public static interface JMXNamespaceCreatorMBean { + public ObjectInstance createLocalNamespace(String namespace) + throws JMException ; + public void removeLocalNamespace(String namespace) + throws JMException; + } + + public static class JMXNamespaceCreator + implements MBeanRegistration, + JMXNamespaceCreatorMBean { + + private volatile MBeanServer mbeanServer; + + public ObjectInstance createLocalNamespace(String namespace) + throws JMException { + return mbeanServer.registerMBean( + new JMXNamespace(MBeanServerFactory.newMBeanServer()), + JMXNamespaces.getNamespaceObjectName(namespace)); + } + + public void removeLocalNamespace(String namespace) + throws JMException { + mbeanServer.unregisterMBean( + JMXNamespaces.getNamespaceObjectName(namespace)); + } + + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + mbeanServer = server; + return name; + } + + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + + public void postDeregister() { + } + + } + + public static void exportAndWaitIfNeeded(MBeanServer server) + throws Exception { + if (System.getProperty("jmx.wait")!=null) { + final int port = getPortFor("rmi"); + LocateRegistry.createRegistry(port); + final JMXServiceURL url = + new JMXServiceURL("rmi",null,port, + "/jndi/rmi://localhost:"+port+"/jmxrmi"); + final JMXConnectorServer cs = + JMXConnectorServerFactory. + newJMXConnectorServer(url, null, server); + cs.start(); + try { + System.out.println("RMI Server waiting at: "+cs.getAddress()); + System.in.read(); + } finally { + cs.stop(); + } + } + } + + public static int getPortFor(String protocol) throws Exception { + final int aport = + Integer.valueOf(System.getProperty("jmx."+protocol+".port","0")); + if (aport > 0) return aport; + final ServerSocket s = new ServerSocket(0); + try { + final int port = s.getLocalPort(); + return port; + } finally { + s.close(); + } + } + + public static void main(String[] args) throws Exception { + doTest(ManagementFactory.getPlatformMBeanServer(),makeConfig("rmi")); + } + +} diff --git a/test/javax/management/namespace/JMXNamespacesTest.java b/test/javax/management/namespace/JMXNamespacesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4dc7c518a1afecf87e438ddee438791029c54bb3 --- /dev/null +++ b/test/javax/management/namespace/JMXNamespacesTest.java @@ -0,0 +1,648 @@ +/* + * 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. + * + * 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. + */ +/* + * @test JMXNamespacesTest.java + * @summary Test the static method that rewrite ObjectNames in JMXNamespacesTest + * @author Daniel Fuchs + * @bug 5072476 + * @run clean JMXNamespacesTest + * @compile -XDignore.symbol.file=true JMXNamespacesTest.java + * @run main JMXNamespacesTest + */ + +import com.sun.jmx.namespace.ObjectNameRouter; +import java.io.Serializable; +import java.util.Arrays; +import java.util.logging.Logger; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespaces; + +/** + * Class JMXNamespacesTest + * @author Sun Microsystems, 2005 - All rights reserved. + */ +public class JMXNamespacesTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(JMXNamespacesTest.class.getName()); + + /** Creates a new instance of JMXNamespacesTest */ + public JMXNamespacesTest() { + } + + public static class CustomObject implements Serializable { + ObjectName toto; + String titi; + CustomObject(String toto, String titi) { + try { + this.toto = new ObjectName(toto); + } catch (MalformedObjectNameException m) { + throw new IllegalArgumentException(m); + } + this.titi = titi; + } + private Object[] data() { + return new Object[] {toto, titi}; + } + @Override + public boolean equals(Object other) { + if (! (other instanceof CustomObject)) return false; + return Arrays.deepEquals(data(),((CustomObject)other).data()); + } + @Override + public int hashCode() { + return Arrays.deepHashCode(data()); + } + } + + public static CustomObject obj(String toto, String titi) { + return new CustomObject(toto,titi); + } + + private static String failure; + + public static void testDeepRewrite() throws Exception { + failure = null; + String s1 = "x//y//d:k=v"; + String s2 = "v//w//x//y//d:k=v"; + String p1 = "v//w"; + String p3 = "a//b"; + + System.out.println("inserting "+p1); + final CustomObject foo1 = + JMXNamespaces.deepReplaceHeadNamespace(obj(s1,s1),"",p1); + assertEquals(foo1.toto.toString(),p1+"//"+s1); + assertEquals(foo1.titi,s1); + + System.out.println("removing "+p1); + final CustomObject foo2 = + JMXNamespaces.deepReplaceHeadNamespace(obj(s2,s2),p1,""); + assertEquals(foo2.toto.toString(),s1); + assertEquals(foo2.titi,s2); + + System.out.println("removing "+p1); + final CustomObject foo3 = + JMXNamespaces.deepReplaceHeadNamespace(obj(p1+"//"+s2,s2),p1,""); + assertEquals(foo3.toto.toString(),s2); + assertEquals(foo3.titi,s2); + + System.out.println("replacing "+p1+" with "+p3); + final CustomObject foo4 = + JMXNamespaces.deepReplaceHeadNamespace(obj(s2,s2),p1,p3); + assertEquals(foo4.toto.toString(),p3+"//"+s1); + assertEquals(foo4.titi,s2); + + System.out.println("replacing "+p1+" with "+p1); + final CustomObject foo5 = + JMXNamespaces.deepReplaceHeadNamespace(obj(s2,s2),p1,p1); + assertEquals(foo5.toto.toString(),s2); + assertEquals(foo5.titi,s2); + + System.out.println("removing x//y in "+s2); + try { + final CustomObject foo7 = + JMXNamespaces.deepReplaceHeadNamespace(obj(s2,s2),"x//y",""); + failed("Remove x//y in "+s2+" should have failed!"); + } catch (IllegalArgumentException x) { + System.out.println("Received expected exception: "+x); + } + + System.out.println("replacing x//y with "+p3+" in "+s2); + try { + final CustomObject foo7 = + JMXNamespaces.deepReplaceHeadNamespace(obj(s2,s2),"x//y",p3); + failed("Replace x//y in "+s2+" should have failed!"); + } catch (IllegalArgumentException x) { + System.out.println("Received expected exception: "+x); + } + + if (failure != null) throw new Exception(failure); + } + + private static String[][] wildcards = { + { "", "*:*" }, + { "//", "//*:*" }, + { "foo", "foo//*:*" }, + { "//foo", "//foo//*:*" }, + { "////foo", "//foo//*:*" }, + { "foo//", "foo//*:*" }, + { "foo////", "foo//*:*" }, + { "//foo//", "//foo//*:*" }, + { "////foo//", "//foo//*:*" }, + { "////foo////", "//foo//*:*" }, + { "foo//bar", "foo//bar//*:*" }, + { "//foo//bar", "//foo//bar//*:*" }, + { "////foo//bar", "//foo//bar//*:*" }, + { "foo//bar//", "foo//bar//*:*" }, + { "foo//bar////", "foo//bar//*:*" }, + { "//foo//bar//", "//foo//bar//*:*" }, + { "////foo//bar//", "//foo//bar//*:*" }, + { "////foo//bar////", "//foo//bar//*:*" }, + { "foo////bar", "foo//bar//*:*" }, + { "//foo////bar", "//foo//bar//*:*" }, + { "////foo////bar", "//foo//bar//*:*" }, + { "foo////bar//", "foo//bar//*:*" }, + { "foo////bar////", "foo//bar//*:*" }, + { "//foo////bar//", "//foo//bar//*:*" }, + { "////foo////bar//", "//foo//bar//*:*" }, + { "////foo////bar////", "//foo//bar//*:*" }, + { "fo/o", "fo/o//*:*" }, + { "//f/oo", "//f/oo//*:*" }, + { "////f/o/o", "//f/o/o//*:*" }, + { "fo/o//", "fo/o//*:*" }, + { "f/oo////", "f/oo//*:*" }, + { "//fo/o//", "//fo/o//*:*" }, + { "////f/oo//", "//f/oo//*:*" }, + { "////f/o/o////", "//f/o/o//*:*" }, + { "foo//b/a/r", "foo//b/a/r//*:*" }, + { "//fo/o//bar", "//fo/o//bar//*:*" }, + { "////foo//b/ar", "//foo//b/ar//*:*" }, + { "foo//ba/r//", "foo//ba/r//*:*" }, + { "f/oo//bar////", "f/oo//bar//*:*" }, + { "//f/o/o//bar//", "//f/o/o//bar//*:*" }, + { "////foo//b/a/r//", "//foo//b/a/r//*:*" }, + { "////f/o/o//b/a/r////", "//f/o/o//b/a/r//*:*" }, + { "foo////ba/r", "foo//ba/r//*:*" }, + { "//foo////b/ar", "//foo//b/ar//*:*" }, + { "////f/oo////bar", "//f/oo//bar//*:*" }, + { "fo/o////bar//", "fo/o//bar//*:*" }, + { "foo////ba/r////", "foo//ba/r//*:*" }, + { "//fo/o////ba/r//", "//fo/o//ba/r//*:*" }, + { "////f/oo////b/ar//", "//f/oo//b/ar//*:*" }, + { "////f/o/o////b/a/r////", "//f/o/o//b/a/r//*:*" }, + }; + private final static String[] badguys = { + null, + "/", "/*:*", + "///", "///*:*" , + "/foo", "/foo//*:*", + "//foo/", "//foo///*:*" , + "/////foo", "///foo//*:*", + "/foo//", "/foo//*:*", + "foo/////", "foo///*:*", + "///foo//", "///foo//*:*", + "////foo///", "//foo///*:*" , + "/////foo/////", "///foo///*:*", + "/foo//bar", "/foo//bar//*:*", + "//foo///bar", "//foo///bar//*:*", + "/////foo////bar/", "///foo//bar///*:*", + "foo///bar//", "foo//bar///*:*", + "foo//bar/////", "foo///bar//*:*", + "///foo//bar//", "//foo///bar//*:*" , + }; + public static void testWildcard() throws Exception { + int i = 0; + for (String[] pair : wildcards) { + i++; + final String msg = "testWildcard[good,"+i+"] "+Arrays.asList(pair)+": "; + assertEquals(msg, new ObjectName(pair[1]), + JMXNamespaces.getWildcardFor(pair[0])); + } + i=0; + for (String bad : badguys) { + i++; + try { + JMXNamespaces.getWildcardFor(bad); + failed("testWildcard[bad,"+i+"] "+bad+" incorrectly accepted. " + + "IllegalArgumentException was expected"); + } catch (IllegalArgumentException x) { + // OK + } + } + if (failure != null) throw new Exception(failure); + } + + private static String[][] goodinsert = { + {"","d:k=v","d:k=v"}, + {"","//d:k=v","//d:k=v"}, + {"//","d:k=v","//d:k=v"}, + {"//","//d:k=v","//d:k=v"}, + {"//","a//d:k=v","//a//d:k=v"}, + {"//","//a//d:k=v","//a//d:k=v"}, + {"//","////a////d:k=v","//a//d:k=v"}, + {"//b","////a////d:k=v","//b//a//d:k=v"}, + {"b","////a////d:k=v","b//a//d:k=v"}, + {"b","d:k=v","b//d:k=v"}, + {"b//","d:k=v","b//d:k=v"}, + {"//b//","d:k=v","//b//d:k=v"}, + {"//b","////a////d:k=v","//b//a//d:k=v"}, + {"b//c","////a////d:k=v","b//c//a//d:k=v"}, + {"b//c","d:k=v","b//c//d:k=v"}, + {"b//c//","d:k=v","b//c//d:k=v"}, + {"//b//c//","d:k=v","//b//c//d:k=v"}, + {"","/d:k=v","/d:k=v"}, + {"","///d:k=v","///d:k=v"}, + {"//","/d:k=v","///d:k=v"}, + {"//","///d:k=v","///d:k=v"}, + {"//","a///d:k=v","//a///d:k=v"}, + {"//","//a///d:k=v","//a///d:k=v"}, + {"//","////a////d/:k=v","//a//d/:k=v"}, + {"//b","////a/////d:k=v","//b//a///d:k=v"}, + {"b","////a////d/:k=v","b//a//d/:k=v"}, + {"b","/d:k=v","b///d:k=v"}, + {"b//","/d:k=v","b///d:k=v"}, + {"//b//","/d:k=v","//b///d:k=v"}, + {"//b","////a/////d:k=v","//b//a///d:k=v"}, + {"b//c","////a/////d:k=v","b//c//a///d:k=v"}, + {"b//c","/d:k=v","b//c///d:k=v"}, + {"b//c//","/d:k=v","b//c///d:k=v"}, + {"//b//c//","d/:k=v","//b//c//d/:k=v"}, + }; + + private static String[][] badinsert = { + {"/","d:k=v"}, + {"/","//d:k=v"}, + {"///","d:k=v"}, + {"///","//d:k=v"}, + {"///","/a//d:k=v"}, + {"///","///a//d:k=v"}, + {"///","/////a////d:k=v"}, + {"//b","/////a////d:k=v"}, + {"b/","////a////d:k=v"}, + {"b/","d:k=v"}, + {"b///","d:k=v"}, + {"//b///","d:k=v"}, + {"//b/","////a////d:k=v"}, + {"b///c","////a////d:k=v"}, + {"b//c/","d:k=v"}, + {"b///c//","d:k=v"}, + {"//b///c//","d:k=v"}, + + }; + + public static void testInsertPath() throws Exception { + int i = 0; + for (String[] pair : goodinsert) { + i++; + final String msg = "testInsertPath[good,"+i+"] "+Arrays.asList(pair)+": "; + assertEquals(msg,new ObjectName(pair[2]), + JMXNamespaces.insertPath(pair[0], + new ObjectName(pair[1]))); + } + i=0; + for (String[] bad : badinsert) { + i++; + try { + JMXNamespaces.insertPath(bad[0], + new ObjectName(bad[1])); + failed("testInsertPath[bad,"+i+"] "+ + Arrays.asList(bad)+" incorrectly accepted. " + + "IllegalArgumentException was expected"); + } catch (IllegalArgumentException x) { + // OK + } + } + if (failure != null) throw new Exception(failure); + } + + private static String[][] testpath = { + {"/a/a/:k=v",""}, + {"/:k=v",""}, + {"bli:k=v",""}, + {"///a/a/:k=v",""}, + {"///:k=v",""}, + {"//bli:k=v",""}, + {"/////a/a/:k=v",""}, + {"/////:k=v",""}, + {"////bli:k=v",""}, + {"y///a/a/:k=v","y"}, + {"y///:k=v","y"}, + {"y//bli:k=v","y"}, + {"y/////a/a/:k=v","y"}, + {"y/////:k=v","y"}, + {"y////bli:k=v","y"}, + {"//y///a/a/:k=v","y"}, + {"//y///:k=v","y"}, + {"//y//bli:k=v","y"}, + {"//y/////a/a/:k=v","y"}, + {"//y/////:k=v","y"}, + {"//y////bli:k=v","y"}, + {"////y///a/a/:k=v","y"}, + {"////y///:k=v","y"}, + {"////y//bli:k=v","y"}, + {"////y/////a/a/:k=v","y"}, + {"////y/////:k=v","y"}, + {"////y////bli:k=v","y"}, + + {"z//y///a/a/:k=v","z//y"}, + {"z//y///:k=v","z//y"}, + {"z//y//bli:k=v","z//y"}, + {"z//y/////a/a/:k=v","z//y"}, + {"z//y/////:k=v","z//y"}, + {"z//y////bli:k=v","z//y"}, + {"//z//y///a/a/:k=v","z//y"}, + {"//z//y///:k=v","z//y"}, + {"//z//y//bli:k=v","z//y"}, + {"//z//y/////a/a/:k=v","z//y"}, + {"//z//y/////:k=v","z//y"}, + {"//z//y////bli:k=v","z//y"}, + {"z////y///a/a/:k=v","z//y"}, + {"z////y///:k=v","z//y"}, + {"z////y//bli:k=v","z//y"}, + {"z////y/////a/a/:k=v","z//y"}, + {"z////y/////:k=v","z//y"}, + {"z////y////bli:k=v","z//y"}, + {"//z////y///a/a/:k=v","z//y"}, + {"//z////y///:k=v","z//y"}, + {"//z////y//bli:k=v","z//y"}, + {"//z////y/////a/a/:k=v","z//y"}, + {"//z////y/////:k=v","z//y"}, + {"//z////y////bli:k=v","z//y"}, + {"////z////y///a/a/:k=v","z//y"}, + {"////z////y///:k=v","z//y"}, + {"////z////y//bli:k=v","z//y"}, + {"////z////y/////a/a/:k=v","z//y"}, + {"////z////y/////:k=v","z//y"}, + {"////z////y////bli:k=v","z//y"}, + + }; + + public static void testGetNormalizedPath() throws Exception { + int i = 0; + for (String[] pair : testpath) { + i++; + final String msg = "testGetNormalizedPath["+i+"] "+Arrays.asList(pair)+": "; + assertEquals(msg,pair[1], + JMXNamespaces.getContainingNamespace(new ObjectName(pair[0]))); + } + if (failure != null) throw new Exception(failure); + } + + private static String[][] testdomain = { + {"/a/a/","/a/a/"}, + {"/","/"}, + {"bli","bli"}, + {"///a/a/","///a/a/"}, + {"///","///"}, + {"//bli","//bli"}, + {"/////a/a/","///a/a/"}, + {"/////","///"}, + {"////bli","//bli"}, + {"y///a/a/","y///a/a/"}, + {"y///","y///"}, + {"y//bli","y//bli"}, + {"y/////a/a/","y///a/a/"}, + {"y/////","y///"}, + {"y////bli","y//bli"}, + {"//y///a/a/","//y///a/a/"}, + {"//y///","//y///"}, + {"//y//bli","//y//bli"}, + {"//y/////a/a/","//y///a/a/"}, + {"//y/////","//y///"}, + {"//y////bli","//y//bli"}, + {"////y///a/a/","//y///a/a/"}, + {"////y///","//y///"}, + {"////y//bli","//y//bli"}, + {"////y/////a/a/","//y///a/a/"}, + {"////y/////","//y///"}, + {"////y////bli","//y//bli"}, + + {"z//y///a/a/","z//y///a/a/"}, + {"z//y///","z//y///"}, + {"z//y//bli","z//y//bli"}, + {"z//y/////a/a/","z//y///a/a/"}, + {"z//y/////","z//y///"}, + {"z//y////bli","z//y//bli"}, + {"//z//y///a/a/","//z//y///a/a/"}, + {"//z//y///","//z//y///"}, + {"//z//y//bli","//z//y//bli"}, + {"//z//y/////a/a/","//z//y///a/a/"}, + {"//z//y/////","//z//y///"}, + {"//z//y////bli","//z//y//bli"}, + {"z////y///a/a/","z//y///a/a/"}, + {"z////y///","z//y///"}, + {"z////y//bli","z//y//bli"}, + {"z////y/////a/a/","z//y///a/a/"}, + {"z////y/////","z//y///"}, + {"z////y////bli","z//y//bli"}, + {"//z////y///a/a/","//z//y///a/a/"}, + {"//z////y///","//z//y///"}, + {"//z////y//bli","//z//y//bli"}, + {"//z////y/////a/a/","//z//y///a/a/"}, + {"//z////y/////","//z//y///"}, + {"//z////y////bli","//z//y//bli"}, + {"////z////y///a/a/","//z//y///a/a/"}, + {"////z////y///","//z//y///"}, + {"////z////y//bli","//z//y//bli"}, + {"////z////y/////a/a/","//z//y///a/a/"}, + {"////z////y/////","//z//y///"}, + {"////z////y////bli","//z//y//bli"}, + + {"bli//","bli//"}, + {"//bli//","//bli//"}, + {"////bli//","//bli//"}, + {"y////","y//"}, + {"y//bli//","y//bli//"}, + {"y////","y//"}, + {"y////bli//","y//bli//"}, + {"//y////","//y//"}, + {"//y//bli//","//y//bli//"}, + {"//y//////","//y//"}, + {"//y////bli//","//y//bli//"}, + {"////y////","//y//"}, + {"////y//bli////","//y//bli//"}, + {"////y//////","//y//"}, + {"////y////bli////","//y//bli//"}, + {"z//y////","z//y//"}, + {"z//y//bli//","z//y//bli//"}, + {"z//y//////","z//y//"}, + {"z//y////bli//","z//y//bli//"}, + {"//z//y////","//z//y//"}, + {"//z//y//bli//","//z//y//bli//"}, + {"//z//y//////","//z//y//"}, + {"//z//y////bli//","//z//y//bli//"}, + {"z////y////","z//y//"}, + {"z////y//bli//","z//y//bli//"}, + {"z////y//////","z//y//"}, + {"z////y////bli//","z//y//bli//"}, + {"//z////y////","//z//y//"}, + {"//z////y//bli//","//z//y//bli//"}, + {"//z////y//////","//z//y//"}, + {"//z////y////bli//","//z//y//bli//"}, + {"////z////y////","//z//y//"}, + {"////z////y//bli//","//z//y//bli//"}, + {"////z////y//////","//z//y//"}, + {"////z////y////bli//","//z//y//bli//"}, + + }; + private static String[][] testnolead = { + {"/a/a/","/a/a/"}, + {"/","/"}, + {"bli","bli"}, + {"///a/a/","/a/a/"}, + {"///","/"}, + {"//bli","bli"}, + {"/////a/a/","/a/a/"}, + {"/////","/"}, + {"////bli","bli"}, + {"y///a/a/","y///a/a/"}, + {"y///","y///"}, + {"y//bli","y//bli"}, + {"y/////a/a/","y///a/a/"}, + {"y/////","y///"}, + {"y////bli","y//bli"}, + {"//y///a/a/","y///a/a/"}, + {"//y///","y///"}, + {"//y//bli","y//bli"}, + {"//y/////a/a/","y///a/a/"}, + {"//y/////","y///"}, + {"//y////bli","y//bli"}, + {"////y///a/a/","y///a/a/"}, + {"////y///","y///"}, + {"////y//bli","y//bli"}, + {"////y/////a/a/","y///a/a/"}, + {"////y/////","y///"}, + {"////y////bli","y//bli"}, + + {"z//y///a/a/","z//y///a/a/"}, + {"z//y///","z//y///"}, + {"z//y//bli","z//y//bli"}, + {"z//y/////a/a/","z//y///a/a/"}, + {"z//y/////","z//y///"}, + {"z//y////bli","z//y//bli"}, + {"//z//y///a/a/","z//y///a/a/"}, + {"//z//y///","z//y///"}, + {"//z//y//bli","z//y//bli"}, + {"//z//y/////a/a/","z//y///a/a/"}, + {"//z//y/////","z//y///"}, + {"//z//y////bli","z//y//bli"}, + {"z////y///a/a/","z//y///a/a/"}, + {"z////y///","z//y///"}, + {"z////y//bli","z//y//bli"}, + {"z////y/////a/a/","z//y///a/a/"}, + {"z////y/////","z//y///"}, + {"z////y////bli","z//y//bli"}, + {"//z////y///a/a/","z//y///a/a/"}, + {"//z////y///","z//y///"}, + {"//z////y//bli","z//y//bli"}, + {"//z////y/////a/a/","z//y///a/a/"}, + {"//z////y/////","z//y///"}, + {"//z////y////bli","z//y//bli"}, + {"////z////y///a/a/","z//y///a/a/"}, + {"////z////y///","z//y///"}, + {"////z////y//bli","z//y//bli"}, + {"////z////y/////a/a/","z//y///a/a/"}, + {"////z////y/////","z//y///"}, + {"////z////y////bli","z//y//bli"}, + + {"bli//","bli//"}, + {"//bli//","bli//"}, + {"////bli//","bli//"}, + {"y////","y//"}, + {"y//bli//","y//bli//"}, + {"y////","y//"}, + {"y////bli//","y//bli//"}, + {"//y////","y//"}, + {"//y//bli//","y//bli//"}, + {"//y//////","y//"}, + {"//y////bli//","y//bli//"}, + {"////y////","y//"}, + {"////y//bli////","y//bli//"}, + {"////y//////","y//"}, + {"////y////bli////","y//bli//"}, + {"z//y////","z//y//"}, + {"z//y//bli//","z//y//bli//"}, + {"z//y//////","z//y//"}, + {"z//y////bli//","z//y//bli//"}, + {"//z//y////","z//y//"}, + {"//z//y//bli//","z//y//bli//"}, + {"//z//y//////","z//y//"}, + {"//z//y////bli//","z//y//bli//"}, + {"z////y////","z//y//"}, + {"z////y//bli//","z//y//bli//"}, + {"z////y//////","z//y//"}, + {"z////y////bli//","z//y//bli//"}, + {"//z////y////","z//y//"}, + {"//z////y//bli//","z//y//bli//"}, + {"//z////y//////","z//y//"}, + {"//z////y////bli//","z//y//bli//"}, + {"////z////y////","z//y//"}, + {"////z////y//bli//","z//y//bli//"}, + {"////z////y//////","z//y//"}, + {"////z////y////bli//","z//y//bli//"}, + + }; + + public static void testNormalizeDomain() throws Exception { + int i = 0; + for (String[] pair : testdomain) { + i++; + final String msg = "testNormalizeDomain["+i+", false] "+Arrays.asList(pair)+": "; + assertEquals(msg,pair[1], + ObjectNameRouter.normalizeDomain(pair[0],false)); + } + if (failure != null) throw new Exception(failure); + i = 0; + for (String[] pair : testnolead) { + i++; + final String msg = "testNormalizeDomain["+i+", true] "+Arrays.asList(pair)+": "; + assertEquals(msg,pair[1], + ObjectNameRouter.normalizeDomain(pair[0],true)); + } + if (failure != null) throw new Exception(failure); + } + + public static void main(String[] args) throws Exception { + testDeepRewrite(); + testNormalizeDomain(); + testInsertPath(); + testWildcard(); + testGetNormalizedPath(); + } + + private static void assertEquals(Object x, Object y) { + assertEquals("",x,y); + } + + private static void assertEquals(String msg, Object x, Object y) { + if (msg == null) msg=""; + if (!equal(x, y)) + failed(msg+"expected " + string(x) + "; got " + string(y)); + } + + private static boolean equal(Object x, Object y) { + if (x == y) + return true; + if (x == null || y == null) + return false; + if (x.getClass().isArray()) + return Arrays.deepEquals(new Object[] {x}, new Object[] {y}); + return x.equals(y); + } + + private static String string(Object x) { + String s = Arrays.deepToString(new Object[] {x}); + return s.substring(1, s.length() - 1); + } + + + private static void failed(String why) { + failure = why; + new Throwable("FAILED: " + why).printStackTrace(System.out); + } + +} diff --git a/test/javax/management/namespace/JMXRemoteNamespaceTest.java b/test/javax/management/namespace/JMXRemoteNamespaceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8e5f795a6ba3fc2cbdcb6d7702dba26fcecc937e --- /dev/null +++ b/test/javax/management/namespace/JMXRemoteNamespaceTest.java @@ -0,0 +1,190 @@ +/* + * 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. + * + * 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. + */ +/* + * + * @test JMXRemoteNamespaceTest.java + * @summary Basic tests on a JMXRemoteNamespace. + * @author Daniel Fuchs + * @bug 5072476 + * @run clean JMXRemoteNamespaceTest Wombat WombatMBean + * @run build JMXRemoteNamespaceTest Wombat WombatMBean + * @run main JMXRemoteNamespaceTest + */ + +import javax.management.JMX; +import javax.management.Notification; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespaces; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.NotificationListener; +import javax.management.namespace.JMXRemoteNamespace; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; +import java.io.IOException; +import javax.management.AttributeChangeNotification; + +/** + * Test simple creation/registration of namespace. + * + */ +public class JMXRemoteNamespaceTest { + + static class MyConnect implements NotificationListener { + private final JMXRemoteNamespace my; + private final List list; + private volatile int connectCount=0; + private int closeCount=0; + private final ObjectName myname; + public MyConnect(JMXRemoteNamespace my, ObjectName myname) { + this.my=my; + this.myname = myname; + list = Collections.synchronizedList(new ArrayList()); + my.addNotificationListener(this, null, null); + } + + public synchronized void connect() throws IOException { + my.connect(); + if (!my.isConnected()) + throw new IOException(myname+" should be connected"); + connectCount++; + } + + public void close() throws IOException { + my.close(); + if (my.isConnected()) + throw new IOException(myname+" shouldn't be connected"); + closeCount++; + } + + public synchronized int getConnectCount() { + return connectCount; + } + public synchronized int getClosedCount() { + return closeCount; + } + + public synchronized void handleNotification(Notification notification, + Object handback) { + list.add(notification); + } + + public synchronized void checkNotifs(int externalConnect, + int externalClosed) throws Exception { + System.err.println("Connected: "+connectCount+" time"+ + ((connectCount>1)?"s":"")); + System.err.println("Closed: "+closeCount+" time"+ + ((closeCount>1)?"s":"")); + System.err.println("Received:"); + int cl=0; + int co=0; + for (Notification n : list) { + System.err.println("\t"+n); + if (!(n instanceof AttributeChangeNotification)) + throw new Exception("Unexpected notif: "+n.getClass()); + final AttributeChangeNotification acn = + (AttributeChangeNotification)n; + if (((Boolean)acn.getNewValue()).booleanValue()) + co++; + else cl++; + if ((((Boolean)acn.getNewValue()).booleanValue()) + == (((Boolean)acn.getOldValue()).booleanValue())) { + throw new Exception("Bad values: old=new"); + } + } + if (! (list.size()==(closeCount+connectCount+ + externalClosed+externalConnect))) { + throw new Exception("Bad notif count - got "+list.size()); + } + if (cl!=(closeCount+externalClosed)) { + throw new Exception("Bad count of close notif: expected " + +(closeCount+externalClosed)+", got"+cl); + } + if (co!=(connectCount+externalConnect)) { + throw new Exception("Bad count of connect notif: expected " + +(connectCount+externalConnect)+", got"+co); + } + } + } + + public static void testConnectClose() throws Exception { + final MBeanServer myServer = MBeanServerFactory.newMBeanServer(); + final JMXConnectorServer myRMI = + JMXConnectorServerFactory.newJMXConnectorServer( + new JMXServiceURL("rmi",null,0), null, myServer); + myRMI.start(); + try { + final JMXRemoteNamespace my = + JMXRemoteNamespace.newJMXRemoteNamespace( + myRMI.getAddress(),null); + final MBeanServer s = MBeanServerFactory.newMBeanServer(); + final ObjectName myname = JMXNamespaces.getNamespaceObjectName("my"); + final ObjectName wname = ObjectName.getInstance("backyard:type=Wombat"); + myServer.registerMBean(new Wombat(),wname); + final MyConnect myc = new MyConnect(my,myname); + myc.connect(); + myc.close(); + myc.connect(); + s.registerMBean(my,myname); + myc.close(); + myc.connect(); + if (!s.queryNames(new ObjectName("my//b*:*"),null).contains( + JMXNamespaces.insertPath("my", wname))) { + throw new RuntimeException("1: Wombat not found: "+wname); + } + myc.close(); + myc.connect(); + final MBeanServer cd = JMXNamespaces.narrowToNamespace(s, "my"); + if (!cd.queryNames(new ObjectName("b*:*"),null).contains(wname)) { + throw new RuntimeException("2: Wombat not found: "+wname); + } + myc.close(); + myc.connect(); + System.out.println("Found a Wombat in my backyard."); + + final String deepThoughts = "I want to leave this backyard!"; + final WombatMBean w = JMX.newMBeanProxy(cd, wname, WombatMBean.class); + w.setCaption(deepThoughts); + if (!deepThoughts.equals(w.getCaption())) + throw new RuntimeException("4: Wombat is not thinking right: "+ + w.getCaption()); + s.unregisterMBean(myname); + if (my.isConnected()) + throw new Exception(myname+" shouldn't be connected"); + myc.connect(); + myc.close(); + myc.checkNotifs(0,1); + } finally { + myRMI.stop(); + } + + } + + public static void main(String... args) throws Exception { + testConnectClose(); + } +} diff --git a/test/javax/management/namespace/JMXRemoteTargetNamespace.java b/test/javax/management/namespace/JMXRemoteTargetNamespace.java new file mode 100644 index 0000000000000000000000000000000000000000..3d83844b1ffe1eef1c21a33dc86010711b85981a --- /dev/null +++ b/test/javax/management/namespace/JMXRemoteTargetNamespace.java @@ -0,0 +1,222 @@ +/* + * 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. + */ + + +import java.io.IOException; +import java.util.Map; +import java.util.logging.Logger; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.MBeanException; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServerConnection; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.event.EventClient; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.JMXRemoteNamespace; +import javax.management.namespace.JMXRemoteNamespaceMBean; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXServiceURL; + +// These options originally in the draft of javax/management/namespaces +// but we decided to retire them - since they could be implemented +// by subclasses. The JMXRemoteTargetNamespace is such a subclass. +// +public class JMXRemoteTargetNamespace extends JMXRemoteNamespace { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(JMXRemoteTargetNamespace.class.getName()); + public static final String CREATE_EVENT_CLIENT = + "jmx.test.create.event.client"; + + private final String sourceNamespace; + private final boolean createEventClient; + + public JMXRemoteTargetNamespace(JMXServiceURL sourceURL, + Map optionsMap) { + this(sourceURL,optionsMap,null); + } + + public JMXRemoteTargetNamespace(JMXServiceURL sourceURL, + Map optionsMap, String sourceNamespace) { + this(sourceURL,optionsMap,sourceNamespace,false); + } + + public JMXRemoteTargetNamespace(JMXServiceURL sourceURL, + Map optionsMap, String sourceNamespace, + boolean createEventClient) { + super(sourceURL,optionsMap); + this.sourceNamespace = sourceNamespace; + this.createEventClient = createEventClient(optionsMap); + } + + private boolean createEventClient(Map options) { + if (options == null) return false; + final Object createValue = options.get(CREATE_EVENT_CLIENT); + if (createValue == null) return false; + if (createValue instanceof Boolean) + return ((Boolean)createValue).booleanValue(); + if (createValue instanceof String) + return Boolean.valueOf((String)createValue); + throw new IllegalArgumentException("Bad type for value of property " + + CREATE_EVENT_CLIENT+": "+createValue.getClass().getName()); + } + + @Override + protected JMXConnector newJMXConnector(JMXServiceURL url, + Map env) throws IOException { + JMXConnector sup = super.newJMXConnector(url, env); + if (sourceNamespace == null || "".equals(sourceNamespace)) + return sup; + if (createEventClient) + sup = EventClient.withEventClient(sup); + return JMXNamespaces.narrowToNamespace(sup, sourceNamespace); + } + + + /** + * Creates a target name space to mirror a remote source name space in + * the target server. + * @param targetServer A connection to the target MBean server in which + * the new name space should be created. + * @param targetPath the name space to create in the target server. Note + * that if the target name space is a path - that is if + * {@code targetPath} contains '//', then the parent name space + * must be pre-existing in the target server. Attempting to create + * {code targetPath="a//b//c"} in {@code targetServer} + * will fail if name space {@code "a//b"} doesn't already exists + * in {@code targetServer}. + * @param sourceURL a JMX service URL that can be used to connect to the + * source MBean server. + * @param options the set of options to use when creating the + * {@link #JMXRemoteNamespace JMXRemoteNamespace} that will + * handle the new name space. + * @return An {@code ObjectInstance} representing the + * {@link JMXRemoteNamespaceMBean} which handles the + * new name space. + * + **/ + public static ObjectInstance createNamespace( + MBeanServerConnection targetServer, + String targetPath, + JMXServiceURL sourceURL, + Map options) + throws IOException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException { + final ObjectName name = + JMXNamespaces.getNamespaceObjectName(targetPath); + return createInstance(targetServer, name, sourceURL, options, null); + } + + /** + * Creates a target name space to mirror a remote source name space in + * the target server. + * @param targetServer A connection to the target MBean server in which + * the new name space should be created. + * @param targetPath the name space to create in the target server. Note + * that if the target name space is a path - that is if + * {@code targetPath} contains '//', then the parent name space + * must be pre-existing in the target server. Attempting to create + * {code targetPath="a//b//c"} in {@code targetServer} + * will fail if name space {@code "a//b"} doesn't already exists + * in {@code targetServer}. + * @param sourceURL a JMX service URL that can be used to connect to the + * source MBean server. + * @param sourcePath the source namespace path insode the source server. + * @param options the set of options to use when creating the + * {@link #JMXRemoteNamespace JMXRemoteNamespace} that will + * handle the new name space. + * @return An {@code ObjectInstance} representing the + * {@link JMXRemoteNamespaceMBean} which handles the + * new name space. + * + **/ + public static ObjectInstance createNamespace( + MBeanServerConnection targetServer, + String targetPath, + JMXServiceURL sourceURL, + Map options, + String sourcePath) + throws IOException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException { + final ObjectName name = + JMXNamespaces.getNamespaceObjectName(targetPath); + return createInstance(targetServer, name, sourceURL, options, sourcePath); + } + + /** + * Creates and registers a {@link JMXRemoteNamespaceMBean} in a target + * server, to mirror a remote source name space. + * + * @param server A connection to the target MBean server in which + * the new name space should be created. + * @param handlerName the name of the JMXRemoteNamespace to create. + * This must be a compliant name space handler name as returned + * by {@link + * JMXNamespaces#getNamespaceObjectName JMXNamespaces.getNamespaceObjectName}. + * @param sourceURL a JMX service URL that can be used to connect to the + * source MBean server. + * @param sourcePath the path inside the source server + * @param options the set of options to use when creating the + * {@link #JMXRemoteNamespace JMXRemoteNamespace} that will + * handle the new name space. + * @return An {@code ObjectInstance} representing the new + * {@link JMXRemoteNamespaceMBean} created. + * @see #createNamespace createNamespace + */ + static ObjectInstance createInstance(MBeanServerConnection server, + ObjectName handlerName, + JMXServiceURL sourceURL, Map options, + String sourcePath) + throws IOException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException { + try { + final String[] signature = { + JMXServiceURL.class.getName(), + Map.class.getName(), + String.class.getName() + }; + final Object[] params = { + sourceURL,options,sourcePath + }; + final ObjectInstance instance = + server.createMBean(JMXRemoteTargetNamespace.class.getName(), + handlerName,params,signature); + return instance; + } catch (NotCompliantMBeanException ex) { + throw new RuntimeException("unexpected exception: " + ex, ex); + } catch (ReflectionException ex) { + throw new RuntimeException("unexpected exception: " + ex, ex); + } + } + +} diff --git a/test/javax/management/namespace/LazyDomainTest.java b/test/javax/management/namespace/LazyDomainTest.java new file mode 100644 index 0000000000000000000000000000000000000000..eda9b66696d4e89a5b6208592696204fe5a6cc6d --- /dev/null +++ b/test/javax/management/namespace/LazyDomainTest.java @@ -0,0 +1,790 @@ +/* + * 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. + * + * 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. + */ +/* + * + * @test LazyDomainTest.java + * @bug 5072476 + * @summary Basic test for Lazy Domains. + * @author Daniel Fuchs + * @run clean LazyDomainTest Wombat WombatMBean + * @run build LazyDomainTest Wombat WombatMBean + * @run main LazyDomainTest + */ + + +import java.lang.management.ClassLoadingMXBean; +import java.lang.management.ManagementFactory; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.Map; +import java.util.Set; +import javax.management.JMX; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanServer; +import javax.management.MBeanServerBuilder; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerFactory; +import javax.management.MBeanServerNotification; +import javax.management.Notification; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.namespace.JMXDomain; +import javax.management.remote.MBeanServerForwarder; + +/** + * Test simple creation/registration of namespace. + * + */ +public class LazyDomainTest { + private static Map emptyEnvMap() { + return Collections.emptyMap(); + } + + + public static interface MBeanServerLoader { + public MBeanServer loadMBeanServer(); + } + + + public static class MBeanServerProxy implements InvocationHandler { + + private final static Map localMap; + static { + localMap = new HashMap(); + for (Method m : MBeanServerForwarder.class.getDeclaredMethods()) { + try { + final Method loc = MBeanServerProxy.class. + getMethod(m.getName(), m.getParameterTypes()); + localMap.put(m, loc); + } catch (Exception x) { + // not defined... + } + } + try { + localMap.put(MBeanServer.class. + getMethod("getMBeanCount", (Class[]) null), + MBeanServerProxy.class. + getMethod("getMBeanCount", (Class[]) null)); + } catch (NoSuchMethodException x) { + // OK. + } + } + + private final MBeanServerLoader loader; + private MBeanServer server; + private final Set domains; + + public MBeanServerProxy(MBeanServerLoader loader) { + if (loader == null) + throw new IllegalArgumentException("null loader"); + this.loader = loader; + this.server = null; + domains = new HashSet(); + } + + + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + if (method.getDeclaringClass().equals(Object.class)) { + return invokeMethod(this,method,args); + } + final Method local = localMap.get(method); + if (local != null) { + return invokeMethod(this,local,args); + } + if (method.getDeclaringClass().equals(MBeanServer.class)) { + return invokeMethod(getMBeanServer(),method,args); + } + throw new NoSuchMethodException(method.getName()); + } + + private Object invokeMethod(Object on, Method method, Object[] args) + throws Throwable { + try { + return method.invoke(on, args); + } catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + + public synchronized MBeanServer getMBeanServer() { + if (server == null) setMBeanServer(loader.loadMBeanServer()); + return server; + } + + public synchronized void setMBeanServer(MBeanServer mbs) { + this.server = mbs; + if (mbs != null) { + for (LazyDomain dom : domains) dom.loaded(); + domains.clear(); + } + } + + public synchronized boolean isLoaded() { + return server != null; + } + + public synchronized void add(LazyDomain dom) { + if (isLoaded()) dom.loaded(); + else domains.add(dom); + } + + public synchronized boolean remove(LazyDomain dom) { + return domains.remove(dom); + } + + public Integer getMBeanCount() { + if (isLoaded()) return server.getMBeanCount(); + else return Integer.valueOf(0); + } + } + + public static class LazyDomain extends JMXDomain { + public static MBeanServer makeProxyFor(MBeanServerProxy proxy) { + return (MBeanServer) + Proxy.newProxyInstance(LazyDomain.class.getClassLoader(), + new Class[] {MBeanServer.class, MBeanServerForwarder.class}, + proxy); + } + + private final MBeanServerProxy proxy; + private volatile NotificationListener listener; + private volatile NotificationFilter filter; + + public LazyDomain(MBeanServerProxy proxy) { + super(makeProxyFor(proxy)); + this.proxy = proxy; + } + + @Override + public Integer getMBeanCount() { + if (proxy.isLoaded()) + return super.getMBeanCount(); + return 0; + } + + + @Override + public synchronized void addMBeanServerNotificationListener( + NotificationListener listener, + NotificationFilter filter) { + if (proxy.isLoaded()) { + super.addMBeanServerNotificationListener(listener, filter); + } else { + this.listener = listener; + this.filter = filter; + proxy.add(this); + } + } + + @Override + public synchronized void removeMBeanServerNotificationListener( + NotificationListener listener) + throws ListenerNotFoundException { + if (this.listener != listener) + throw new ListenerNotFoundException(); + this.listener = null; + this.filter = null; + if (proxy.isLoaded()) + super.removeMBeanServerNotificationListener(listener); + proxy.remove(this); + } + + public synchronized void loaded() { + if (listener != null) + addMBeanServerNotificationListener(listener, filter); + } + + } + + /** + * This is a use case for e.g GlassFish: the LazyStarterDomain MBean + * is a place holder that will unregister itself and autoload a set + * of MBeans in place of its own domain when that domain is + * accessed. + * This is an abstract class, where the only abstract method + * is loadMBeans(MBeanServer). + * Subclasses should implement that method to register whatever MBeans + * in the domain previously held by that LazyStarterDomain object. + * In other words: the LazyStarterDomain MBean is 'replaced' by the + * MBeans loaded by loadMBeans(); + */ + public static abstract class LazyStarterDomain extends LazyDomain { + + /** + * This is a loader that will unregister the JMXDomain that + * created it, and register a bunch of MBeans in its place + * by calling LazyStarterDomain.loadMBeans + * + * That one gave me "la migraine". + */ + private static class HalfGrainLoader implements MBeanServerLoader { + private volatile LazyStarterDomain domain; + public MBeanServer loadMBeanServer() { + if (domain == null) + throw new IllegalStateException( + "JMXDomain MBean not registered!"); + final MBeanServer server = domain.getMBeanServer(); + final ObjectName domainName = domain.getObjectName(); + try { + server.unregisterMBean(domainName); + } catch (Exception x) { + throw new IllegalStateException("Can't unregister " + + "JMXDomain: "+x,x); + } + domain.loadMBeans(server,domainName.getDomain()); + return server; + } + public void setDomain(LazyStarterDomain domain) { + this.domain = domain; + } + } + + /** + * This is an MBeanServerProxy which create a loader for the + * LazyStarterDomain MBean. + */ + private static class DomainStarter extends MBeanServerProxy { + + public DomainStarter() { + this(new HalfGrainLoader()); + } + + private final HalfGrainLoader loader; + private DomainStarter(HalfGrainLoader loader) { + super(loader); + this.loader = loader; + } + + public void setDomain(LazyStarterDomain domain) { + loader.setDomain(domain); + } + } + + /** + * A new LazyStarterDomain. When the domain monitored by this + * MBean is accessed, this MBean will unregister itself and call + * the abstract loadMBeans(MBeanServer) method. + * Subclasses need only to implement loadMBeans(). + */ + public LazyStarterDomain() { + this(new DomainStarter()); + } + + private LazyStarterDomain(DomainStarter starter) { + super(starter); + starter.setDomain(this); + } + + // Contrarily to its LazyDomain superclass, this LazyDomain + // doesn't wrapp another MBeanServer: it simply registers a bunch + // of MBeans in its own MBeanServer. + // Thus, there's no notifications to forward. + // + @Override + public void addMBeanServerNotificationListener( + NotificationListener listener, NotificationFilter filter) { + // nothing to do. + } + + // Contrarily to its LazyDomain superclass, this LazyDomain + // doesn't wrapp another MBeanServer: it simply registers a bunch + // of MBeans in its own MBeanServer. + // Thus, there's no notifications to forward. + // + @Override + public void removeMBeanServerNotificationListener( + NotificationListener listener) throws ListenerNotFoundException { + // nothing to do + } + + // If this domain is registered, it contains no MBean. + // If it is not registered, then it no longer contain any MBean. + // The MBeanCount is thus always 0. + @Override + public Integer getMBeanCount() { + return 0; + } + + /** + * Called when the domain is first accessed. + * {@code server} is the server in which this MBean was registered. + * A subclass must override this method in order to register + * the MBeans that should be contained in domain. + * + * @param server the server in which to load the MBeans. + * @param domain the domain in which the MBeans should be registered. + */ + protected abstract void loadMBeans(MBeanServer server, String domain); + + + } + + private static MBeanServerNotification pop( + BlockingQueue queue, + String type, + ObjectName mbean, + String test) + throws InterruptedException { + final Notification n = queue.poll(1, TimeUnit.SECONDS); + if (!(n instanceof MBeanServerNotification)) + fail(test+"expected MBeanServerNotification, got "+n); + final MBeanServerNotification msn = (MBeanServerNotification)n; + if (!type.equals(msn.getType())) + fail(test+"expected "+type+", got "+msn.getType()); + if (!mbean.apply(msn.getMBeanName())) + fail(test+"expected "+mbean+", got "+msn.getMBeanName()); + System.out.println(test+" got: "+msn); + return msn; + } + private static MBeanServerNotification popADD( + BlockingQueue queue, + ObjectName mbean, + String test) + throws InterruptedException { + return pop(queue, MBeanServerNotification.REGISTRATION_NOTIFICATION, + mbean, test); + } + + private static MBeanServerNotification popREM( + BlockingQueue queue, + ObjectName mbean, + String test) + throws InterruptedException { + return pop(queue, MBeanServerNotification.UNREGISTRATION_NOTIFICATION, + mbean, test); + } + + + private static void fail(String msg) { + raise(new RuntimeException(msg)); + } + + private static void fail(String msg, Throwable cause) { + raise(new RuntimeException(msg,cause)); + } + + private static void raise(RuntimeException x) { + lastException = x; + exceptionCount++; + throw x; + } + + private static volatile Exception lastException = null; + private static volatile int exceptionCount = 0; + + // ZZZ need to add a test case with several LazyDomains, and + // need to test that nothing is loaded until the lazy domains + // are accessed... + // + + private static void registerWombats(MBeanServer server, String domain, + int count) { + try { + for (int i=0;i queue = + new ArrayBlockingQueue(100); + + // A listener that puts notifs in the queue. + final NotificationListener l = new NotificationListener() { + + public void handleNotification(Notification notification, + Object handback) { + try { + if (!queue.offer(notification, 5, TimeUnit.SECONDS)) { + throw new RuntimeException("timeout exceeded"); + } + } catch (Exception x) { + fail(test + "failed to handle notif", x); + } + } + }; + + // Create a LazyDomain for each of the platform domain. + // All platform domain share the same MBeanServer proxy, which means + // that loading one domain will also load all the others. + // + Map domainsMap = new HashMap(); + for (String dom : platformDomains) { + domainsMap.put(dom, new LazyDomain(platform)); + } + domainsMap.put("custom.awomb", new LazyDomain(customa)); + domainsMap.put("custom.bwomb", new LazyDomain(customb)); + + for (Map.Entry e : domainsMap.entrySet()) { + server.registerMBean(e.getValue(), + JMXDomain.getDomainObjectName(e.getKey())); + } + + // check that lazy MBeans are not there... + checkSize(test,server,domainsMap.size()+1); + + System.out.println(test+" registering listener with delegate."); + server.addNotificationListener(MBeanServerDelegate.DELEGATE_NAME, l, + null, null); + + // check that lazy MBeans are not there... + checkSize(test,server,domainsMap.size()+1); + + // force loading of custom.awomb. + final ObjectName awombat = new ObjectName( + "custom.awomb:type=Wombat,name=wombat#"+customCount/2); + if (!server.isRegistered(awombat)) + fail(test+"Expected "+awombat+" to be reggistered!"); + + final int oldCount = domainsMap.size()+1+customCount; + checkSize(test,server,oldCount); + + if (queue.peek() != null) + fail(test+"Received unexpected notifications: "+queue); + + + System.out.println(test+"creating a proxy for ClassLoadingMXBean."); + final ClassLoadingMXBean cl = + JMX.newMXBeanProxy(server, + new ObjectName(ManagementFactory.CLASS_LOADING_MXBEAN_NAME), + ClassLoadingMXBean.class); + + checkSize(test,server,oldCount); + + System.out.println(test+"Loaded classes: "+cl.getLoadedClassCount()); + + final int newCount = server.getMBeanCount(); + if (newCount < oldCount+6) + fail(test+"Expected at least "+(oldCount+6)+ + " MBeans. Found "+newCount); + + final ObjectName jwombat = new ObjectName("java.lang:type=Wombat"); + server.createMBean("Wombat", jwombat); + System.out.println(test+"Created "+jwombat); + checkSize(test,server,newCount+1); + + popADD(queue, jwombat, test); + if (queue.peek() != null) + fail(test+"Received unexpected notifications: "+queue); + + + int platcount = 0; + for (String dom : platformDomains) { + final Set found = + server.queryNames(new ObjectName(dom+":*"),null); + final int jcount = found.size(); + System.out.println(test+"Found "+jcount+" MBeans in "+dom+ + ": "+found); + checkSize(test,server,newCount+1); + platcount += (jcount-1); + } + checkSize(test,server,oldCount+platcount); + + final ObjectName owombat = new ObjectName("custom:type=Wombat"); + server.createMBean("Wombat", owombat); + System.out.println(test+"Created "+owombat); + checkSize(test,server,newCount+2); + popADD(queue, owombat, test); + if (queue.peek() != null) + fail(test+"Received unexpected notifications: "+queue); + + final Set jwombatView = (Set) + server.invoke(jwombat, "listMatching", new Object[] {null}, + new String[] {ObjectName.class.getName()}); + System.out.println(test+jwombat+" sees: "+jwombatView); + checkSize(test, server, newCount+2); + if (jwombatView.size() != (platcount+1)) + fail(test+jwombat+" sees "+jwombatView.size()+" MBeans - should" + + " have seen "+(platcount+1)); + + final Set platformMBeans = + ManagementFactory.getPlatformMBeanServer(). + queryNames(null, null); + if (!platformMBeans.equals(jwombatView)) + fail(test+jwombat+" should have seen "+platformMBeans); + + // check that awombat triggers loading of bwombats + final Set awombatView = (Set) + server.invoke(awombat, "listMatching", new Object[] {null}, + new String[] {ObjectName.class.getName()}); + System.out.println(test+awombat+" sees: "+awombatView); + final int totalCount = newCount+2+customCount; + checkSize(test, server, totalCount); + if (awombatView.size() != totalCount) + fail(test+jwombat+" sees "+jwombatView.size()+" MBeans - should" + + " have seen "+totalCount); + + final Set allMBeans = server. + queryNames(null, null); + if (!allMBeans.equals(awombatView)) + fail(test+awombat+" should have seen "+allMBeans); + + System.out.println(test + " PASSED"); + + } + + + public static void lazyStarterTest() throws Exception { + final String test = "lazyStarterTest: "; + System.out.println("" + + "\nThis test checks that it is possible to perform lazy loading" + + "\nof MBeans in a given domain by using a transient JMXDomain" + + "\nsubclass for that domain. "); + + System.out.println(test + " START"); + + // The "global" MBeanServer... + final MBeanServer platform = + ManagementFactory.getPlatformMBeanServer(); + + // A notification queue. + final BlockingQueue queue = + new ArrayBlockingQueue(100); + + // A listener that puts notifs in the queue. + final NotificationListener l = new NotificationListener() { + + public void handleNotification(Notification notification, + Object handback) { + try { + if (!queue.offer(notification, 5, TimeUnit.SECONDS)) { + throw new RuntimeException("timeout exceeded"); + } + } catch (Exception x) { + fail(test + "failed to handle notif", x); + } + } + }; + + System.out.println(test+" registering listener with delegate."); + platform.addNotificationListener(MBeanServerDelegate.DELEGATE_NAME, l, + null, null); + + final String ld1 = "lazy1"; + final String ld2 = "lazy2"; + final int wCount = 5; + final LazyStarterDomain lazy1 = new LazyStarterDomain() { + @Override + protected void loadMBeans(MBeanServer server, String domain) { + registerWombats(server, ld1, wCount); + } + }; + final LazyStarterDomain lazy2 = new LazyStarterDomain() { + @Override + protected void loadMBeans(MBeanServer server, String domain) { + registerWombats(server, ld2, wCount); + } + }; + final ObjectName lo1 = JMXDomain.getDomainObjectName(ld1); + final ObjectName lo2 = JMXDomain.getDomainObjectName(ld2); + + final int initial = platform.getMBeanCount(); + + platform.registerMBean(lazy1, lo1); + System.out.println(test+"registered "+lo1); + checkSize(test, platform, initial+1); + popADD(queue, lo1, test); + + platform.registerMBean(lazy2, lo2); + System.out.println(test+"registered "+lo2); + checkSize(test, platform, initial+2); + popADD(queue, lo2, test); + + + final ObjectName awombat = new ObjectName( + ld1+":type=Wombat,name=wombat#"+wCount/2); + if (!platform.isRegistered(awombat)) + fail(test+"Expected "+awombat+" to be reggistered!"); + checkSize(test,platform,initial+wCount+1); + popREM(queue, lo1, test); + final ObjectName pat1 = + new ObjectName(ld1+":type=Wombat,name=wombat#*"); + for (int i=0;i all = platform.queryNames(null, null); + popREM(queue, lo2, test); + System.out.println(test+"Now found: "+all); + checkSize(test,platform,initial+wCount+wCount); + final ObjectName pat2 = + new ObjectName(ld2+":type=Wombat,name=wombat#*"); + for (int i=0;i testConcurrent = + new HashMap(); + for (int i=0;i<(100/wCount);i++) { + final String ld = "concurrent.lazy"+i; + final LazyStarterDomain lazy = new LazyStarterDomain() { + @Override + protected void loadMBeans(MBeanServer server, String domain) { + registerWombats(server, ld, wCount-1); + } + }; + testConcurrent.put(ld, lazy); + final ObjectName lo = JMXDomain.getDomainObjectName(ld); + platform.registerMBean(lazy, lo); + popADD(queue, lo, test); + } + + System.out.println(test+"Big autoload: "+ + platform.queryNames(null,null)); + System.out.println(test+"Big after load: "+ + platform.queryNames(null,null)); + if (!platform.queryNames(JMXDomain.getDomainObjectName("*"), null). + isEmpty()) { + fail(test+" some domains are still here: "+ + platform.queryNames( + JMXDomain.getDomainObjectName("*"), null)); + } + queue.clear(); + System.out.println(test+"PASSED: The DomainDispatcher appears to be " + + "resilient to concurrent modifications."); + } + + public static void main(String... args) throws Exception { + + lazyTest(); + lazyStarterTest(); + + if (lastException != null) + throw lastException; + } +} diff --git a/test/javax/management/namespace/LeadingSeparatorsTest.java b/test/javax/management/namespace/LeadingSeparatorsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5660b275317bc98a9d25a16d11802b51a88bc35d --- /dev/null +++ b/test/javax/management/namespace/LeadingSeparatorsTest.java @@ -0,0 +1,227 @@ +/* + * 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. + * + * 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. + */ +/* + * @test LeadingSeparatorsTest.java + * @summary Test that the semantics of a leading // in ObjectName is respected. + * @author Daniel Fuchs + * @bug 5072476 + * @run clean LeadingSeparatorsTest Wombat WombatMBean + * @compile -XDignore.symbol.file=true LeadingSeparatorsTest.java + * @run build LeadingSeparatorsTest Wombat WombatMBean + * @run main LeadingSeparatorsTest + */ + +import java.lang.management.ManagementFactory; +import java.util.Arrays; +import java.util.Set; +import java.util.HashSet; +import java.util.logging.Logger; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.JMXRemoteNamespace; +import javax.management.namespace.JMXNamespace; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * Class LeadingSeparatorsTest + * @author Sun Microsystems, 2005 - All rights reserved. + */ +public class LeadingSeparatorsTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(LeadingSeparatorsTest.class.getName()); + + /** Creates a new instance of NullObjectNameTest */ + public LeadingSeparatorsTest() { + } + + public static interface MyWombatMBean extends WombatMBean { + public Set untrue(ObjectName pat) throws Exception; + } + public static class MyWombat + extends Wombat implements MyWombatMBean { + public MyWombat() throws NotCompliantMBeanException { + super(MyWombatMBean.class); + } + + public Set untrue(ObjectName pat) throws Exception { + final Set res=listMatching(pat.withDomain("*")); + final Set untrue = new HashSet(); + for (ObjectName a:res) { + untrue.add(a.withDomain(pat.getDomain()+"//"+a.getDomain())); + } + return untrue; + } + } + + static String failure=null; + + public static void testRegister() throws Exception { + final MBeanServer top = ManagementFactory.getPlatformMBeanServer(); + final MBeanServer sub = MBeanServerFactory.createMBeanServer(); + final JMXServiceURL url = new JMXServiceURL("rmi",null,0); + final JMXConnectorServer srv = + JMXConnectorServerFactory.newJMXConnectorServer(url,null,sub); + srv.start(); + + try { + + // Create a namespace rmi// that points to 'sub' and flows through + // a JMXRemoteNamespace connected to 'srv' + // The namespace rmi// will accept createMBean, but not registerMBean. + // + final JMXRemoteNamespace rmiHandler = JMXRemoteNamespace. + newJMXRemoteNamespace(srv.getAddress(),null); + top.registerMBean(rmiHandler, + JMXNamespaces.getNamespaceObjectName("rmi")); + top.invoke(JMXNamespaces.getNamespaceObjectName("rmi"), + "connect", null, null); + + // Create a namespace direct// that points to 'sub' and flows + // through a direct reference to 'sub'. + // The namespace direct// will accept createMBean, and registerMBean. + // + final JMXNamespace directHandler = new JMXNamespace(sub); + top.registerMBean(directHandler, + JMXNamespaces.getNamespaceObjectName("direct")); + + final ObjectName n1 = new ObjectName("//direct//w:type=Wombat"); + final ObjectName n2 = new ObjectName("direct//w:type=Wombat"); + final ObjectName n3 = new ObjectName("//rmi//w:type=Wombat"); + final ObjectName n4 = new ObjectName("rmi//w:type=Wombat"); + + // register wombat using an object name with a leading // + final Object obj = new MyWombat(); + // check that returned object name doesn't have the leading // + assertEquals(n2,top.registerMBean(obj, n1).getObjectName()); + System.out.println(n1+" registered"); + + // check that the registered Wombat can be accessed with all its + // names. + System.out.println(n2+" mood is: "+top.getAttribute(n2, "Mood")); + System.out.println(n1+" mood is: "+top.getAttribute(n1, "Mood")); + System.out.println(n4+" mood is: "+top.getAttribute(n4, "Mood")); + System.out.println(n3+" mood is: "+top.getAttribute(n3, "Mood")); + + // call listMatching. The result should not contain any prefix. + final Set res = (Set) + top.invoke(n3, "listMatching", + // remove rmi// from rmi//*:* + JMXNamespaces.deepReplaceHeadNamespace( + new Object[] {ObjectName.WILDCARD.withDomain("rmi//*")}, + "rmi", ""), new String[] {ObjectName.class.getName()}); + + // add rmi// prefix to all names in res. + final Set res1 = + JMXNamespaces.deepReplaceHeadNamespace(res, "", "rmi"); + System.out.println("got: "+res1); + + // compute expected result + final Set res2 = sub.queryNames(null,null); + final Set res3 = new HashSet(); + for (ObjectName o:res2) { + res3.add(o.withDomain("rmi//"+o.getDomain())); + } + System.out.println("expected: "+res3); + assertEquals(res1, res3); + + // invoke "untrue(//niark//niark:*)" + // should return a set were all ObjectNames begin with + // //niark//niark// + // + final Set res4 = (Set) + top.invoke(n3, "untrue", + // remove niark//niark : should remove nothing since + // our ObjectName begins with a leading // + JMXNamespaces.deepReplaceHeadNamespace( + new Object[] { + ObjectName.WILDCARD.withDomain("//niark//niark")}, + "niark//niark", ""), + new String[] {ObjectName.class.getName()}); + System.out.println("got: "+res4); + + // add rmi// should add nothing since the returned names have a + // leading // + // + final Set res5 = + JMXNamespaces.deepReplaceHeadNamespace(res4, "", "rmi"); + System.out.println("got#2: "+res5); + + // compute expected result + final Set res6 = new HashSet(); + for (ObjectName o:res2) { + res6.add(o.withDomain("//niark//niark//"+o.getDomain())); + } + System.out.println("expected: "+res6); + + // both res4 and res5 should be equals to the expected result. + assertEquals(res4, res6); + assertEquals(res5, res6); + + } finally { + srv.stop(); + } + + if (failure != null) + throw new Exception(failure); + + + } + private static void assertEquals(Object x, Object y) { + if (!equal(x, y)) + failed("expected " + string(x) + "; got " + string(y)); + } + + private static boolean equal(Object x, Object y) { + if (x == y) + return true; + if (x == null || y == null) + return false; + if (x.getClass().isArray()) + return Arrays.deepEquals(new Object[] {x}, new Object[] {y}); + return x.equals(y); + } + + private static String string(Object x) { + String s = Arrays.deepToString(new Object[] {x}); + return s.substring(1, s.length() - 1); + } + + + private static void failed(String why) { + failure = why; + new Throwable("FAILED: " + why).printStackTrace(System.out); + } + + public static void main(String[] args) throws Exception { + testRegister(); + } +} diff --git a/test/javax/management/namespace/MXBeanRefTest.java b/test/javax/management/namespace/MXBeanRefTest.java new file mode 100644 index 0000000000000000000000000000000000000000..afdc0ae9789cef47a50b878af5e30cae7f3dfde4 --- /dev/null +++ b/test/javax/management/namespace/MXBeanRefTest.java @@ -0,0 +1,181 @@ +/* + * 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. + * + * 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. + */ +/* + * @test MXBeanRefTest.java + * @bug 5072476 + * @summary Test that MXBean proxy references work correctly in the presence + * of namespaces. + * @author Eamonn Mcmanus + */ + +/** + * The idea is that we will create a hierarchy like this: + * a// + * X + * b// + * Y + * Z + * and we will use MXBean references so we have links like this: + * a// + * X----+ + * b// | + * / + * Y + * \ + * / + * Z + * In other words, X.getY() will return a proxy for Y, which the MXBean + * framework will map to b//Y. A proxy for a//X should then map this + * into a proxy for a//b//Y. That's easy. But then if we call getZ() + * on this proxy, the MXBean framework will return just Z, and the proxy + * must map that into a proxy for a//b//Z. + */ + +import java.lang.management.ManagementFactory; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.lang.reflect.UndeclaredThrowableException; +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.MBeanServerInvocationHandler; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.openmbean.OpenDataException; + +public class MXBeanRefTest { + + public static interface ZMXBean { + public void success(); + } + public static class ZImpl implements ZMXBean { + public void success() {} + } + + public static interface YMXBean { + public ZMXBean getZ(); + public void setZ(ZMXBean z); + } + public static class YImpl implements YMXBean { + private ZMXBean z; + + public YImpl(ZMXBean z) { + this.z = z; + } + + public ZMXBean getZ() { + return z; + } + + public void setZ(ZMXBean z) { + this.z = z; + } + } + + public static interface XMXBean { + public YMXBean getY(); + } + public static class XImpl implements XMXBean { + private final YMXBean yProxy; + + public XImpl(YMXBean yProxy) { + this.yProxy = yProxy; + } + + public YMXBean getY() { + return yProxy; + } + } + + public static void main(String[] args) throws Exception { + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + + // Set up namespace hierarchy a//b// + MBeanServer ambs = MBeanServerFactory.newMBeanServer(); + MBeanServer bmbs = MBeanServerFactory.newMBeanServer(); + JMXNamespace bHandler = new JMXNamespace(bmbs); + ObjectName bHandlerName = JMXNamespaces.getNamespaceObjectName("b"); + System.out.println(bHandlerName); + ambs.registerMBean(bHandler, bHandlerName); + JMXNamespace aHandler = new JMXNamespace(ambs); + ObjectName aHandlerName = JMXNamespaces.getNamespaceObjectName("a"); + mbs.registerMBean(aHandler, aHandlerName); + + ZMXBean z = new ZImpl(); + ObjectName zName = new ObjectName("foo:type=Z"); + bmbs.registerMBean(z, zName); + + YMXBean y = new YImpl(z); + ObjectName yName = new ObjectName("foo:type=Y"); + bmbs.registerMBean(y, yName); + + ObjectName yNameInA = new ObjectName("b//" + yName); + System.out.println("MBeanInfo for Y as seen from a//:"); + System.out.println(ambs.getMBeanInfo(yNameInA)); + YMXBean yProxyInA = JMX.newMXBeanProxy(ambs, yNameInA, YMXBean.class); + XMXBean x = new XImpl(yProxyInA); + ObjectName xName = new ObjectName("foo:type=X"); + ambs.registerMBean(x, xName); + + ObjectName xNameFromTop = new ObjectName("a//" + xName); + XMXBean xProxy = JMX.newMXBeanProxy(mbs, xNameFromTop, XMXBean.class); + System.out.println("Name of X Proxy: " + proxyName(xProxy)); + YMXBean yProxy = xProxy.getY(); + System.out.println("Name of Y Proxy: " + proxyName(yProxy)); + ZMXBean zProxy = yProxy.getZ(); + System.out.println("Name of Z Proxy: " + proxyName(zProxy)); + + System.out.println("Operation through Z proxy..."); + zProxy.success(); + + System.out.println("Changing Y's ref to Z..."); + yProxy.setZ(zProxy); + zProxy = yProxy.getZ(); + System.out.println("Name of Z Proxy now: " + proxyName(zProxy)); + System.out.println("Operation through Z proxy again..."); + zProxy.success(); + + System.out.println("Changing Y's ref to a bogus one..."); + ZMXBean zProxyBad = JMX.newMXBeanProxy(mbs, zName, ZMXBean.class); + try { + yProxy.setZ(zProxyBad); + } catch (UndeclaredThrowableException e) { + Throwable cause = e.getCause(); + if (cause instanceof OpenDataException) { + System.out.println("...correctly got UndeclaredThrowableException"); + System.out.println("...wrapping: " + cause); + } else + throw new Exception("FAILED: wrong exception: " + cause); + } + + System.out.println("Test passed"); + } + + private static ObjectName proxyName(Object proxy) { + InvocationHandler ih = Proxy.getInvocationHandler(proxy); + MBeanServerInvocationHandler mbsih = (MBeanServerInvocationHandler) ih; + return mbsih.getObjectName(); + } +} diff --git a/test/javax/management/namespace/NamespaceController.java b/test/javax/management/namespace/NamespaceController.java new file mode 100644 index 0000000000000000000000000000000000000000..f5a1c42e294d8c7f39341f27b5b33c54f2efffce --- /dev/null +++ b/test/javax/management/namespace/NamespaceController.java @@ -0,0 +1,405 @@ +/* + * 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. + */ + +import com.sun.jmx.namespace.ObjectNameRouter; +import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.JMX; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.JMXRemoteNamespaceMBean; +import javax.management.remote.JMXServiceURL; + +/** + * The {@code NamespaceController} MBean makes it possible to easily + * create mount points ({@linkplain JMXNamespace JMXNamespaces}) in an + * {@code MBeanServer}. + * There is at most one instance of NamespaceController in an + * MBeanServer - which can be created using the {@link #createInstance + * createInstance} method. The {@code NamespaceController} MBean will + * make it possible to remotely create name spaces by mounting remote + * MBeanServers into the MBeanServer in which it was registered. + */ +// This API was originally in the draft of javax/management/namespaces +// but we decided to retire it. Rather than removing all the associated +// tests I have moved the API to the test hierarchy - so it is now used as +// an additional (though somewhat complex) test case... +// +public class NamespaceController implements NamespaceControllerMBean, + NotificationEmitter, MBeanRegistration { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(NamespaceController.class.getName()); + + private static long seqNumber=0; + + private final NotificationBroadcasterSupport broadcaster = + new NotificationBroadcasterSupport(); + + private volatile MBeanServer mbeanServer = null; + + private volatile ObjectName objectName = null; + + //was: NamespaceController.class.getPackage().getName() + public static final String NAMESPACE_CONTROLLER_DOMAIN = "jmx.ns"; + + /** + * Creates a new NamespaceController. + * Using {@link #createInstance} should be preferred. + **/ + public NamespaceController() { + this(null); + } + + public NamespaceController(MBeanServer mbeanServer) { + this.mbeanServer = mbeanServer; + } + + /* + * MBeanNotification support + * You shouldn't update these methods + */ + public final void addNotificationListener(NotificationListener listener, + NotificationFilter filter, Object handback) { + broadcaster.addNotificationListener(listener, filter, handback); + } + + public MBeanNotificationInfo[] getNotificationInfo() { + return new MBeanNotificationInfo[] { + }; + } + + public final void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException { + broadcaster.removeNotificationListener(listener); + } + + public final void removeNotificationListener(NotificationListener listener, + NotificationFilter filter, Object handback) + throws ListenerNotFoundException { + broadcaster.removeNotificationListener(listener, filter, handback); + } + + public static synchronized long getNextSeqNumber() { + return seqNumber++; + } + + protected final void sendNotification(Notification n) { + if (n.getSequenceNumber()<=0) + n.setSequenceNumber(getNextSeqNumber()); + if (n.getSource()==null) + n.setSource(objectName); + broadcaster.sendNotification(n); + } + + /** + * The ObjectName with which this MBean was registered. + *

    Unless changed by subclasses, this is + * {@code + * "javax.management.namespace:type="+this.getClass().getSimpleName()}. + * @return this MBean's ObjectName, or null if this MBean was never + * registered. + **/ + public final ObjectName getObjectName() { + return objectName; + } + + /** + * The MBeanServer served by this NamespaceController. + * @return the MBeanServer served by this NamespaceController. + **/ + public final MBeanServer getMBeanServer() { + return mbeanServer; + } + + /** + * Allows the MBean to perform any operations it needs before being + * registered in the MBean server. If the name of the MBean is not + * specified, the MBean can provide a name for its registration. If + * any exception is raised, the MBean will not be registered in the + * MBean server. Subclasses which override {@code preRegister} + * must call {@code super.preRegister(name,server)}; + * @param server The MBean server in which the MBean will be registered. + * @param name The object name of the MBean. + * The name must be either {@code null} - or equal to that + * described by {@link #getObjectName}. + * @return The name under which the MBean is to be registered. + * This will be the name described by {@link #getObjectName}. + * @throws MalformedObjectNameException if the supplied name does not + * meet expected requirements. + */ + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws MalformedObjectNameException { + objectName = name; + final ObjectName single = + ObjectName.getInstance(NAMESPACE_CONTROLLER_DOMAIN+ + ":type="+this.getClass().getSimpleName()); + if (name!=null && !single.equals(name)) + throw new MalformedObjectNameException(name.toString()); + if (mbeanServer == null) mbeanServer = server; + return single; + } + + /** + * Allows the MBean to perform any operations needed after having + * been registered in the MBean server or after the registration has + * failed. + * @param registrationDone Indicates whether or not the MBean has been + * successfully registered in the MBean server. The value false means + * that the registration has failed. + */ + public void postRegister(Boolean registrationDone) { + //TODO postRegister implementation; + } + + /** + * Allows the MBean to perform any operations it needs before being + * unregistered by the MBean server. + * @throws Exception This exception will be caught by the MBean server and + * re-thrown as an MBeanRegistrationException. + */ + public void preDeregister() throws Exception { + //TODO preDeregister implementation; + } + + /** + * Allows the MBean to perform any operations needed after having been + * unregistered in the MBean server. + */ + public void postDeregister() { + //TODO postDeregister implementation; + } + + public String mount(JMXServiceURL url, + String targetPath, + Map optionsMap) + throws IOException { + return mount(url, targetPath, "", optionsMap); + } + + // see NamespaceControllerMBean + public String mount(JMXServiceURL url, + String targetPath, + String sourcePath, + Map optionsMap) + throws IOException { + + // TODO: handle description. + final String dirName = + JMXNamespaces.normalizeNamespaceName(targetPath); + + try { + final ObjectInstance moi = + JMXRemoteTargetNamespace.createNamespace(mbeanServer, + dirName,url,optionsMap, + JMXNamespaces.normalizeNamespaceName(sourcePath) + ); + final ObjectName nsMBean = moi.getObjectName(); + try { + mbeanServer.invoke(nsMBean, "connect", null,null); + } catch (Throwable t) { + mbeanServer.unregisterMBean(nsMBean); + throw t; + } + return getMountPointID(nsMBean); + } catch (InstanceAlreadyExistsException x) { + throw new IllegalArgumentException(targetPath,x); + } catch (IOException x) { + throw x; + } catch (Throwable x) { + if (x instanceof Error) throw (Error)x; + Throwable cause = x.getCause(); + if (cause instanceof IOException) + throw ((IOException)cause); + if (cause == null) cause = x; + + final IOException io = + new IOException("connect failed: "+cause); + io.initCause(cause); + throw io; + } + } + + private String getMountPointID(ObjectName dirName) { + return dirName.toString(); + } + + private ObjectName getHandlerName(String mountPointID) { + try { + final ObjectName tryit = ObjectName.getInstance(mountPointID); + final ObjectName formatted = + JMXNamespaces.getNamespaceObjectName(tryit.getDomain()); + if (!formatted.equals(tryit)) + throw new IllegalArgumentException(mountPointID+ + ": invalid mountPointID"); + return formatted; + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(mountPointID,x); + } + } + + public boolean unmount(String mountPointID) + throws IOException { + final ObjectName dirName = getHandlerName(mountPointID); + if (!mbeanServer.isRegistered(dirName)) + throw new IllegalArgumentException(mountPointID+ + ": no such name space"); + final JMXRemoteNamespaceMBean mbean = + JMX.newMBeanProxy(mbeanServer,dirName, + JMXRemoteNamespaceMBean.class); + try { + mbean.close(); + } catch (IOException io) { + LOG.fine("Failed to close properly - ignoring exception: "+io); + LOG.log(Level.FINEST, + "Failed to close properly - ignoring exception",io); + } finally { + try { + mbeanServer.unregisterMBean(dirName); + } catch (InstanceNotFoundException x) { + throw new IllegalArgumentException(mountPointID+ + ": no such name space", x); + } catch (MBeanRegistrationException x) { + final IOException io = + new IOException(mountPointID +": failed to unmount"); + io.initCause(x); + throw io; + } + } + return true; + } + + public boolean ismounted(String targetPath) { + return mbeanServer.isRegistered(JMXNamespaces.getNamespaceObjectName(targetPath)); + } + + public ObjectName getHandlerNameFor(String targetPath) { + return JMXNamespaces.getNamespaceObjectName(targetPath); + } + + public String[] findNamespaces() { + return findNamespaces(null,null,0); + } + + + private ObjectName getDirPattern(String from) { + try { + if (from == null) + return ObjectName.getInstance(ALL_NAMESPACES); + final String namespace = + ObjectNameRouter.normalizeNamespacePath(from,false,true,false); + if (namespace.equals("")) + return ObjectName.getInstance(ALL_NAMESPACES); + if (JMXNamespaces.getNamespaceObjectName(namespace).isDomainPattern()) + throw new IllegalArgumentException(from); + return ObjectName.getInstance(namespace+NAMESPACE_SEPARATOR+ALL_NAMESPACES); + } catch (MalformedObjectNameException x) { + throw new IllegalArgumentException(from,x); + } + } + + public String[] findNamespaces(String from, String regex, int depth) { + if (depth < 0) return new String[0]; + final Set res = new TreeSet(); + final ObjectName all = getDirPattern(from); + Set names = mbeanServer.queryNames(all,null); + for (ObjectName dirName : names) { + final String dir = dirName.getDomain(); + if (regex == null || dir.matches(regex)) + res.add(dir); + if (depth > 0) + res.addAll(Arrays.asList(findNamespaces(dir,regex,depth-1))); + } + return res.toArray(new String[res.size()]); + } + + /** + * Creates a {@link NamespaceController} MBean in the provided + * {@link MBeanServerConnection}. + *

    The name of the MBean is that returned by {@link #preRegister} + * as described by {@link #getObjectName}. + * @throws IOException if an {@code IOException} is raised when invoking + * the provided connection. + * @throws InstanceAlreadyExistsException if an MBean was already + * registered with the NamespaceController's name. + * @throws MBeanRegistrationException if thrown by {@link + * MBeanServerConnection#createMBean(java.lang.String,javax.management.ObjectName) + * server.createMBean} + * @throws MBeanException if thrown by {@link + * MBeanServerConnection#createMBean(java.lang.String,javax.management.ObjectName) + * server.createMBean} + * @return the {@link ObjectInstance}, as returned by {@link + * MBeanServerConnection#createMBean(java.lang.String,javax.management.ObjectName) + * server.createMBean} + **/ + public static ObjectInstance createInstance(MBeanServerConnection server) + throws IOException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException { + try { + final ObjectInstance instance = + server.createMBean(NamespaceController.class.getName(), null); + return instance; + } catch (NotCompliantMBeanException ex) { + throw new RuntimeException("unexpected exception: " + ex, ex); + } catch (ReflectionException ex) { + throw new RuntimeException("unexpected exception: " + ex, ex); + } + } + + private final static String ALL_NAMESPACES= + "*"+NAMESPACE_SEPARATOR+":"+ + JMXNamespace.TYPE_ASSIGNMENT; + +} diff --git a/test/javax/management/namespace/NamespaceControllerMBean.java b/test/javax/management/namespace/NamespaceControllerMBean.java new file mode 100644 index 0000000000000000000000000000000000000000..b7bc3457e9fc2e6f446565f8e125af84f40d59bb --- /dev/null +++ b/test/javax/management/namespace/NamespaceControllerMBean.java @@ -0,0 +1,143 @@ +/* + * 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. + */ + +import java.io.IOException; +import java.util.Map; + +import javax.management.ObjectName; +import javax.management.remote.JMXServiceURL; + +/** + * The {@link NamespaceController} MBean makes it possible to easily + * create mount points ({@link JMXNamespace JMXNamespaces}) in an + * {@code MBeanServer}. + */ +// This API was originally in the draft of javax/management/namespaces +// but we decided to retire it. Rather than removing all the associated +// tests I have moved the API to the test hierarchy - so it is now used as +// an additional (though somewhat complex) test case... +// +public interface NamespaceControllerMBean { + /** + * Mount MBeans from the source path of the source URL into the specified + * target path of the target. + * @param url URL of the mounted source. + * @param targetPath Target path in which MBeans will be mounted. + * @param optionsMap connection map and options. See {@link + * javax.management.namespace.JMXRemoteNamespace.Options + * JMXRemoteNamespace.Options} + * @throws IOException Connection with the source failed + * @throws IllegalArgumentException Supplied parameters are + * illegal, or combination of supplied parameters is illegal. + * @return A mount point id. + */ + public String mount(JMXServiceURL url, + String targetPath, + Map optionsMap) + throws IOException, IllegalArgumentException; + + /** + * Mount MBeans from the source path of the source URL into the specified + * target path of the target. + * @param url URL of the mounted source. + * @param targetPath Target path in which MBeans will be mounted. + * @param sourcePath source namespace path. + * @param optionsMap connection map and options. See {@link + * javax.management.namespace.JMXRemoteNamespace.Options + * JMXRemoteNamespace.Options} + * @throws IOException Connection with the source failed + * @throws IllegalArgumentException Supplied parameters are + * illegal, or combination of supplied parameters is illegal. + * @return A mount point id. + */ + public String mount(JMXServiceURL url, + String targetPath, + String sourcePath, + Map optionsMap) + throws IOException, IllegalArgumentException; + + /** + * Unmount a previously mounted mount point. + * @param mountPointId A mount point id, as previously returned + * by mount. + * @throws IllegalArgumentException Supplied parameters are + * illegal, or combination of supplied parameters is illegal. + * @throws IOException thrown if the mount point {@link JMXNamespace} + * couldn't be unregistered. + */ + public boolean unmount(String mountPointId) + throws IOException, IllegalArgumentException; + + /** + * Tells whether there already exists a {@link JMXNamespace} for + * the given targetPath. + * @param targetPath a target name space path. + * @return true if a {@link JMXNamespace} is registered for that + * name space path. + **/ + public boolean ismounted(String targetPath); + + /** + * Returns the handler name for the provided target name space + * path. Can throw IllegalArgumentException if the provided + * targetPath contains invalid characters (like e.g. ':'). + * @param targetPath A target name space path. + * @return the handler name for the provided target name space + * path. + **/ + public ObjectName getHandlerNameFor(String targetPath); + + /** + * Return a sorted array of locally mounted name spaces. + * This is equivalent to calling {@link + * #findNamespaces(java.lang.String,java.lang.String,int) + * findNamespaces(null,null,0)}; + * @return a sorted array of locally mounted name spaces. + **/ + public String[] findNamespaces(); + + /** + * Return a sorted array of mounted name spaces, starting at + * from (if non null), and recursively searching up to + * provided depth. + * @param from A name spaces from which to start the search. If null, + * will start searching from the MBeanServer root. + * If not null, all returned names will start with from//. + * @param regex A regular expression that the returned names must match. + * If null - no matching is performed and all found names are + * returned. If not null, then all returned names satisfy + * {@link String#matches name.matches(regex)}; + * @param depth the maximum number of levels that the search algorithm + * will cross. 0 includes only top level name spaces, 1 top level + * and first level children etc... depth is evaluated + * with regard to where the search starts - if a non null + * from parameter is provided - then {@code depth=0} + * corresponds to all name spaces found right below + * from//. + * @return A sorted array of name spaces matching the provided criteria. + * All returned names end with "//". + **/ + public String[] findNamespaces(String from, String regex, int depth); +} diff --git a/test/javax/management/namespace/NamespaceCreationTest.java b/test/javax/management/namespace/NamespaceCreationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..871bf022052030f735724ac9bea2b3bb9e46e0c8 --- /dev/null +++ b/test/javax/management/namespace/NamespaceCreationTest.java @@ -0,0 +1,263 @@ +/* + * 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. + * + * 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. + */ +/* + * + * @test NamespaceCreationTest.java + * @summary General JMXNamespace test. + * @author Daniel Fuchs + * @bug 5072476 + * @run clean NamespaceCreationTest Wombat WombatMBean + * @run build NamespaceCreationTest Wombat WombatMBean + * @run main NamespaceCreationTest + */ + + +import java.util.Collections; +import java.util.Map; +import javax.management.MBeanRegistration; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.RuntimeMBeanException; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; + +/** + * Test simple creation/registration of namespace. + * + */ +public class NamespaceCreationTest { + private static Map emptyEnvMap() { + return Collections.emptyMap(); + } + + + public static class LocalNamespace extends JMXNamespace { + + public LocalNamespace() { + super(MBeanServerFactory.newMBeanServer()); + } + + } + + private static MBeanServer newMBeanServer() { + return MBeanServerFactory.newMBeanServer(); + } + + public static interface ThingMBean {} + public static class Thing implements ThingMBean, MBeanRegistration { + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + if (name == null) return new ObjectName(":type=Thing"); + else return name; + } + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + public void postDeregister() { + } + } + + /** + * Test that it is possible to create a dummy MBean with a null + * ObjectName - this is just a sanity check - as there are already + * other JMX tests that check that. + * + * @throws java.lang.Exception + */ + public static void testCreateWithNull() throws Exception { + final MBeanServer server = newMBeanServer(); + final ObjectInstance oi = server.registerMBean(new Thing(),null); + server.unregisterMBean(oi.getObjectName()); + System.out.println("testCreateWithNull PASSED"); + } + + /** + * Check that we can register a JMXNamespace MBean, using its standard + * ObjectName. + * @throws java.lang.Exception + */ + public static void testGoodObjectName() throws Exception { + MBeanServer server = newMBeanServer(); + final ObjectName name = + JMXNamespaces.getNamespaceObjectName("gloups"); + final ObjectInstance oi = + server.registerMBean(new LocalNamespace(),name); + System.out.println("Succesfully registered namespace: "+name); + try { + if (! name.equals(oi.getObjectName())) + throw new RuntimeException("testGoodObjectName: TEST failed: " + + "namespace registered as: "+ + oi.getObjectName()+" expected: "+name); + } finally { + server.unregisterMBean(oi.getObjectName()); + } + System.out.println("Succesfully unregistered namespace: "+name); + System.out.println("testGoodObjectName PASSED"); + } + + /** + * Check that we cannot register a JMXNamespace MBean, if we don't use + * its standard ObjectName. + * @throws java.lang.Exception + */ + public static void testBadObjectName() throws Exception { + MBeanServer server = newMBeanServer(); + Throwable exp = null; + final ObjectName name = new ObjectName("d:k=v"); + try { + server.registerMBean(new LocalNamespace(),name); + System.out.println("testBadObjectName: " + + "Error: MBean registered, no exception thrown."); + } catch(RuntimeMBeanException x) { + exp = x.getCause(); + } catch(Exception x) { + throw new RuntimeException("testBadObjectName: TEST failed: " + + "expected RuntimeMBeanException - got "+ + x); + } + if (exp == null) server.unregisterMBean(name); + if (exp == null) + throw new RuntimeException("testBadObjectName: TEST failed: " + + "expected IllegalArgumentException - got none"); + if (!(exp instanceof IllegalArgumentException)) + throw new RuntimeException("testBadObjectName: TEST failed: " + + "expected IllegalArgumentException - got "+ + exp.toString(),exp); + System.out.println("Got expected exception: "+exp); + System.out.println("testBadObjectName PASSED"); + } + + /** + * Check that we cannot register a Wombat MBean in a namespace that does + * not exists. + * + * @throws java.lang.Exception + */ + public static void testBadNamespace() throws Exception { + MBeanServer server = newMBeanServer(); + Throwable exp = null; + final ObjectName name = new ObjectName("glips//d:k=v"); + + try { + server.registerMBean(new Wombat(),name); + System.out.println("testBadNamespace: " + + "Error: MBean registered, no exception thrown."); + } catch(MBeanRegistrationException x) { + exp = x.getCause(); + } catch(Exception x) { + throw new RuntimeException("testBadNamespace: TEST failed: " + + "expected MBeanRegistrationException - got "+ + x); + } + if (exp == null) server.unregisterMBean(name); + if (exp == null) + throw new RuntimeException("testBadNamespace: TEST failed: " + + "expected IllegalArgumentException - got none"); + if (!(exp instanceof IllegalArgumentException)) + throw new RuntimeException("testBadNamespace: TEST failed: " + + "expected IllegalArgumentException - got "+ + exp.toString(),exp); + System.out.println("Got expected exception: "+exp); + System.out.println("testBadNamespace PASSED"); + } + + /** + * Check that we cannot register a Wombat MBean with a domain name + * that ends with //. This is reserved for namespaces. + * + * @throws java.lang.Exception + */ + public static void testBadDomain() throws Exception { + MBeanServer server = newMBeanServer(); + Throwable exp = null; + final ObjectName name = new ObjectName("glups//:k=v"); + + try { + server.registerMBean(new Wombat(),name); + System.out.println("testBadDomain: Error: MBean registered, no exception thrown."); + } catch(RuntimeMBeanException x) { + exp = x.getCause(); + } catch(Exception x) { + throw new RuntimeException("testBadDomain: TEST failed: " + + "expected RuntimeMBeanException - got "+ + x); + } + if (exp == null) server.unregisterMBean(name); + if (exp == null) + throw new RuntimeException("testBadDomain: TEST failed: " + + "expected IllegalArgumentException - got none"); + if (!(exp instanceof IllegalArgumentException)) + throw new RuntimeException("testBadDomain: TEST failed: " + + "expected IllegalArgumentException - got "+ + exp.toString(),exp); + System.out.println("Got expected exception: "+exp); + System.out.println("testBadDomain PASSED"); + } + + /** + * Check that we cannot register a Wombat MBean as if it were a + * JMXNamespace. Only JMXNamespace MBeans can have JMX Namespace names. + * @throws java.lang.Exception + */ + public static void testBadClassName() throws Exception { + MBeanServer server = newMBeanServer(); + Throwable exp = null; + final ObjectName name = + JMXNamespaces.getNamespaceObjectName("glops"); + try { + server.registerMBean(new Wombat(),name); + System.out.println("testBadClassName: " + + "Error: MBean registered, no exception thrown."); + } catch(RuntimeMBeanException x) { + exp = x.getCause(); + } catch(Exception x) { + throw new RuntimeException("testBadClassName: TEST failed: " + + "expected RuntimeMBeanException - got "+ + x); + } + if (exp == null) server.unregisterMBean(name); + if (exp == null) + throw new RuntimeException("testBadClassName: TEST failed: " + + "expected IllegalArgumentException - got none"); + if (!(exp instanceof IllegalArgumentException)) + throw new RuntimeException("testBadClassName: TEST failed: " + + "expected IllegalArgumentException - got "+ + exp.toString(),exp); + System.out.println("Got expected exception: "+exp); + System.out.println("testBadClassName PASSED"); + } + + public static void main(String... args) throws Exception { + testCreateWithNull(); + testGoodObjectName(); + testBadObjectName(); + testBadNamespace(); + testBadDomain(); + testBadClassName(); + } +} diff --git a/test/javax/management/namespace/NamespaceNotificationsTest.java b/test/javax/management/namespace/NamespaceNotificationsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9c5a1a04a1ca29bd26ba583b0ecf3b8127c1ad63 --- /dev/null +++ b/test/javax/management/namespace/NamespaceNotificationsTest.java @@ -0,0 +1,389 @@ +/* + * 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. + * + * 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. + */ + +/* + * + * @test NamespaceNotificationsTest.java 1.12 + * @summary General Namespace & Notifications test. + * @bug 5072476 + * @author Daniel Fuchs + * @run clean NamespaceNotificationsTest + * Wombat WombatMBean JMXRemoteTargetNamespace + * NamespaceController NamespaceControllerMBean + * @compile -XDignore.symbol.file=true NamespaceNotificationsTest.java + * Wombat.java WombatMBean.java JMXRemoteTargetNamespace.java + * NamespaceController.java NamespaceControllerMBean.java + * @run main NamespaceNotificationsTest + */ +import com.sun.jmx.remote.util.EventClientConnection; +import java.lang.management.ManagementFactory; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerFactory; +import javax.management.MBeanServerNotification; +import javax.management.MalformedObjectNameException; +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.loading.MLet; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.remote.JMXAddressable; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * + * @author Sun Microsystems, Inc. + */ +public class NamespaceNotificationsTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(NamespaceNotificationsTest.class.getName()); + + /** Creates a new instance of NamespaceNotificationsTest */ + public NamespaceNotificationsTest() { + } + + + public static JMXServiceURL export(MBeanServer server) + throws Exception { + final JMXServiceURL in = new JMXServiceURL("rmi",null,0); + final JMXConnectorServer cs = + JMXConnectorServerFactory.newJMXConnectorServer(in,null,null); + final ObjectName csname = ObjectName. + getInstance(cs.getClass().getPackage().getName()+ + ":type="+cs.getClass().getSimpleName()); + server.registerMBean(cs,csname); + cs.start(); + return cs.getAddress(); + } + + public static class Counter { + int count; + public synchronized int count() { + count++; + notifyAll(); + return count; + } + public synchronized int peek() { + return count; + } + public synchronized int waitfor(int max, long timeout) + throws InterruptedException { + final long start = System.currentTimeMillis(); + while (count < max && timeout > 0) { + final long rest = timeout - + (System.currentTimeMillis() - start); + if (rest <= 0) break; + wait(rest); + } + return count; + } + } + + public static class CounterListener + implements NotificationListener { + final private Counter counter; + public CounterListener(Counter counter) { + this.counter = counter; + } + public void handleNotification(Notification notification, + Object handback) { + System.out.println("Received notif from " + handback + + ":\n\t" + notification); + if (!notification.getSource().equals(handback)) { + System.err.println("OhOh... Unexpected source: \n\t"+ + notification.getSource()+"\n\twas expecting:\n\t"+ + handback); + } + counter.count(); + } + } + + public static void simpleTest(String[] args) { + try { + final MBeanServer server1 = + ManagementFactory.getPlatformMBeanServer(); + final JMXServiceURL url1 = export(server1); + + final MBeanServer server2 = + MBeanServerFactory.createMBeanServer("server2"); + final JMXServiceURL url2 = export(server2); + + final MBeanServer server3 = + MBeanServerFactory.createMBeanServer("server3"); + final JMXServiceURL url3 = export(server3); + + final ObjectInstance ncinst = + NamespaceController.createInstance(server1); + + final NamespaceControllerMBean nc = + JMX.newMBeanProxy(server1,ncinst.getObjectName(), + NamespaceControllerMBean.class); + + final Map options = new HashMap(); + options.put(JMXRemoteTargetNamespace.CREATE_EVENT_CLIENT,"true"); + + final String mount1 = + nc.mount(url1,"server1",options); + final String mount2 = nc.mount(url2,"server1//server2", + options); + final String mount3 = nc.mount(url3, + "server1//server2//server3", + options); + final String mount13 = nc.mount( + url1, + "server3", + "server2//server3", + options); + final String mount21 = nc.mount(url1,"server2//server1", + options); + final String mount31 = nc.mount( + url1, + "server3//server1", + "server1", + options); + final String mount32 = nc.mount( + url1, + "server3//server2", + "server2", + options); + + + final ObjectName deep = + new ObjectName("server1//server2//server3//bush:type=Wombat,name=kanga"); + server1.createMBean(Wombat.class.getName(),deep); + + System.err.println("There's a wombat in the bush!"); + + final Counter counter = new Counter(); + + final NotificationListener listener = + new CounterListener(counter); + + final JMXConnector jc = JMXConnectorFactory.connect(url1); + final MBeanServerConnection aconn = + EventClientConnection.getEventConnectionFor( + jc.getMBeanServerConnection(),null); + aconn.addNotificationListener(deep,listener,null,deep); + + + final JMXServiceURL urlx = new JMXServiceURL(url1.toString()); + System.out.println("conn: "+urlx); + final JMXConnector jc2 = JMXNamespaces.narrowToNamespace( + JMXConnectorFactory.connect(urlx),"server1//server1"); + final JMXConnector jc3 = JMXNamespaces.narrowToNamespace(jc2,"server3"); + jc3.connect(); + System.out.println("JC#3: " + + ((jc3 instanceof JMXAddressable)? + ((JMXAddressable)jc3).getAddress(): + jc3.toString())); + final MBeanServerConnection bconn = + jc3.getMBeanServerConnection(); + final ObjectName shallow = + new ObjectName("bush:"+ + deep.getKeyPropertyListString()); + final WombatMBean proxy = + JMX.newMBeanProxy(EventClientConnection.getEventConnectionFor( + bconn,null),shallow,WombatMBean.class,true); + + ((NotificationEmitter)proxy). + addNotificationListener(listener,null,shallow); + proxy.setCaption("I am a new Wombat!"); + System.err.println("New caption: "+proxy.getCaption()); + final int rcvcount = counter.waitfor(2,3000); + if (rcvcount != 2) + throw new RuntimeException("simpleTest failed: "+ + "received count is " +rcvcount); + + System.err.println("simpleTest passed: got "+rcvcount+ + " notifs"); + + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new RuntimeException("simpleTest failed: " + x,x); + } + } + + public static class LocalNamespace extends + JMXNamespace { + LocalNamespace() { + super(MBeanServerFactory.newMBeanServer()); + } + + } + + public static class ContextObject { + public final K name; + public final V object; + public ContextObject(K name, V object) { + this.name = name; + this.object = object; + } + private Object[] data() { + return new Object[] {name,object}; + } + + @Override + public boolean equals(Object x) { + if (x instanceof ContextObject) + return Arrays.deepEquals(data(),((ContextObject)x).data()); + return false; + } + @Override + public int hashCode() { + return Arrays.deepHashCode(data()); + } + } + + private static ContextObject context(K k, V v) { + return new ContextObject(k,v); + } + + private static ObjectName name(String name) { + try { + return new ObjectName(name); + } catch(MalformedObjectNameException x) { + throw new IllegalArgumentException(name,x); + } + } + + public static void simpleTest2() { + try { + System.out.println("\nsimpleTest2: STARTING\n"); + final LocalNamespace foo = new LocalNamespace(); + final LocalNamespace joe = new LocalNamespace(); + final LocalNamespace bar = new LocalNamespace(); + final MBeanServer server = MBeanServerFactory.newMBeanServer(); + + server.registerMBean(foo,JMXNamespaces.getNamespaceObjectName("foo")); + server.registerMBean(joe,JMXNamespaces.getNamespaceObjectName("foo//joe")); + server.registerMBean(bar,JMXNamespaces.getNamespaceObjectName("foo//bar")); + final BlockingQueue> queue = + new ArrayBlockingQueue>(20); + + 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 name in the handback. + // + final String namespace = (String) handback; + System.out.println("Received " + mbsn.getType() + + " for MBean " + mbsn.getMBeanName() + + " from name space " + namespace); + try { + queue.offer(context(namespace,mbsn),500,TimeUnit.MILLISECONDS); + } catch (Exception x) { + System.err.println("Failed to enqueue received notif: "+mbsn); + x.printStackTrace(); + } + } + }; + + server.addNotificationListener(JMXNamespaces.insertPath("foo//joe", + MBeanServerDelegate.DELEGATE_NAME),listener,null,"foo//joe"); + server.addNotificationListener(JMXNamespaces.insertPath("foo//bar", + MBeanServerDelegate.DELEGATE_NAME),listener,null,"foo//bar"); + server.createMBean(MLet.class.getName(), + name("foo//joe//domain:type=MLet")); + checkQueue(queue,"foo//joe", + MBeanServerNotification.REGISTRATION_NOTIFICATION); + server.createMBean(MLet.class.getName(), + name("foo//bar//domain:type=MLet")); + checkQueue(queue,"foo//bar", + MBeanServerNotification.REGISTRATION_NOTIFICATION); + server.unregisterMBean( + name("foo//joe//domain:type=MLet")); + checkQueue(queue,"foo//joe", + MBeanServerNotification.UNREGISTRATION_NOTIFICATION); + server.unregisterMBean( + name("foo//bar//domain:type=MLet")); + checkQueue(queue,"foo//bar", + MBeanServerNotification.UNREGISTRATION_NOTIFICATION); + } catch (RuntimeException x) { + System.err.println("FAILED: "+x); + throw x; + } catch(Exception x) { + System.err.println("FAILED: "+x); + throw new RuntimeException("Unexpected exception: "+x,x); + } + } + + + private static void checkQueue( + BlockingQueue> q, + String path, String type) { + try { + final ContextObject ctxt = + q.poll(500,TimeUnit.MILLISECONDS); + if (ctxt == null) + throw new RuntimeException("Timeout expired: expected notif from "+ + path +", type="+type); + if (!ctxt.name.equals(path)) + throw new RuntimeException("expected notif from "+ + path +", got "+ctxt.name); + if (!ctxt.object.getType().equals(type)) + throw new RuntimeException(ctxt.name+": expected type="+ + type +", got "+ctxt.object.getType()); + if (!ctxt.object.getType().equals(type)) + throw new RuntimeException(ctxt.name+": expected type="+ + type +", got "+ctxt.object.getType()); + if (!ctxt.object.getMBeanName().equals(name("domain:type=MLet"))) + throw new RuntimeException(ctxt.name+": expected MBean=domain:type=MLet"+ + ", got "+ctxt.object.getMBeanName()); + } catch(InterruptedException x) { + throw new RuntimeException("unexpected interruption: "+x,x); + } + } + + public static void main(String[] args) { + simpleTest(args); + simpleTest2(); + } + +} diff --git a/test/javax/management/namespace/NullDomainObjectNameTest.java b/test/javax/management/namespace/NullDomainObjectNameTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3251d388a860cf07ed79729cef353270082562a3 --- /dev/null +++ b/test/javax/management/namespace/NullDomainObjectNameTest.java @@ -0,0 +1,284 @@ +/* + * 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. + * + * 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. + */ +/* + * @test NullDomainObjectNameTest.java + * @summary Test that null domains are correctly handled in namespaces. + * @author Daniel Fuchs + * @run clean NullDomainObjectNameTest Wombat WombatMBean + * @compile -XDignore.symbol.file=true NullDomainObjectNameTest.java + * @run build NullDomainObjectNameTest Wombat WombatMBean + * @run main NullDomainObjectNameTest + */ + +import com.sun.jmx.namespace.RoutingServerProxy; +import java.lang.management.ManagementFactory; +import java.util.Arrays; +import java.util.logging.Logger; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.JMXRemoteNamespace; +import javax.management.namespace.JMXNamespace; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * Class NullDomainObjectNameTest + * @author Sun Microsystems, 2005 - All rights reserved. + */ +public class NullDomainObjectNameTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(NullDomainObjectNameTest.class.getName()); + + /** Creates a new instance of NullDomainObjectNameTest */ + public NullDomainObjectNameTest() { + } + + public static class MyWombat + extends Wombat { + public MyWombat() throws NotCompliantMBeanException { + super(); + } + @Override + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + + if (name == null) + name = new ObjectName(":type=Wombat"); + + return super.preRegister(server, name); + } + + } + + static String failure=null; + + public static void testRegister() throws Exception { + final MBeanServer top = ManagementFactory.getPlatformMBeanServer(); + final MBeanServer sub = MBeanServerFactory.createMBeanServer(); + final JMXServiceURL url = new JMXServiceURL("rmi",null,0); + final JMXConnectorServer srv = + JMXConnectorServerFactory.newJMXConnectorServer(url,null,sub); + srv.start(); + + try { + + // Create a namespace rmi// that points to 'sub' and flows through + // a JMXRemoteNamespace connected to 'srv' + // The namespace rmi// will accept createMBean, but not registerMBean. + // + final JMXRemoteNamespace rmiHandler = JMXRemoteNamespace. + newJMXRemoteNamespace(srv.getAddress(), + null); + top.registerMBean(rmiHandler,JMXNamespaces.getNamespaceObjectName("rmi")); + top.invoke(JMXNamespaces.getNamespaceObjectName("rmi"), + "connect", null, null); + + // Create a namespace direct// that points to 'sub' and flows + // through a direct reference to 'sub'. + // The namespace direct// will accept createMBean, and registerMBean. + // + final JMXNamespace directHandler = new JMXNamespace(sub); + top.registerMBean(directHandler, + JMXNamespaces.getNamespaceObjectName("direct")); + + // Now cd to each of the created namespace. + // + MBeanServer cdrmi = JMXNamespaces.narrowToNamespace(top,"rmi"); + MBeanServer cddirect = JMXNamespaces.narrowToNamespace(top,"direct"); + boolean ok = false; + + // Check that calling createMBean with a null domain works + // for namespace rmi// + // + try { + final ObjectInstance moi1 = + cdrmi.createMBean(MyWombat.class.getName(), + new ObjectName(":type=Wombat")); + System.out.println(moi1.getObjectName().toString()+ + ": created through rmi//"); + assertEquals(moi1.getObjectName().getDomain(), + cddirect.getDefaultDomain()); + cddirect.unregisterMBean(moi1.getObjectName()); + } catch (MBeanRegistrationException x) { + System.out.println("Received unexpected exception: " + x); + failed("Received unexpected exception: " + x); + } + + // Check that calling refgisterMBean with a null domain works + // for namespace direct// + // + try { + final ObjectInstance moi2 = + cddirect.registerMBean(new MyWombat(), + new ObjectName(":type=Wombat")); + System.out.println(moi2.getObjectName().toString()+ + ": created through direct//"); + assertEquals(moi2.getObjectName().getDomain(), + cdrmi.getDefaultDomain()); + cdrmi.unregisterMBean(moi2.getObjectName()); + } catch (MBeanRegistrationException x) { + System.out.println("Received unexpected exception: " + x); + failed("Received unexpected exception: " + x); + } + + // Now artificially pretend that 'sub' is contained in a faked// + // namespace. + // + RoutingServerProxy proxy = + new RoutingServerProxy(sub, "", "faked", false); + + // These should fail because the ObjectName doesn't start + // with "faked//" + try { + final ObjectInstance moi3 = + proxy.registerMBean(new MyWombat(), + new ObjectName(":type=Wombat")); + System.out.println(moi3.getObjectName().toString()+ + ": created through faked//"); + failed("expected MBeanRegistrationException"); + } catch (MBeanRegistrationException x) { + System.out.println("Received expected exception: " + x); + if (!(x.getCause() instanceof IllegalArgumentException)) { + System.err.println("Bad wrapped exception: "+ x.getCause()); + failed("expected IllegalArgumentException"); + } + } + + // null should work with "faked//" + final ObjectInstance moi3 = + proxy.registerMBean(new MyWombat(),null); + assertEquals(moi3.getObjectName().getDomain(), + "faked//"+sub.getDefaultDomain()); + + System.out.println(moi3.getObjectName().toString() + + ": created through faked//"); + + // Now check that null is correctly handled (accepted or rejected) + // in queries for each of the above configs. + // + ObjectName wombat = moi3.getObjectName().withDomain( + moi3.getObjectName().getDomain().substring("faked//".length())); + ObjectInstance moi = new ObjectInstance(wombat,moi3.getClassName()); + + System.out.println("Checking queryNames(" + + "new ObjectName(\":*\"),null) with rmi//"); + assertEquals(cdrmi.queryNames( + new ObjectName(":*"),null).contains(wombat),true); + System.out.println("Checking queryNames(" + + "new ObjectName(\":*\"),null) with direct//"); + assertEquals(cddirect.queryNames( + new ObjectName(":*"),null).contains(wombat),true); + System.out.println("Checking queryMBeans(" + + "new ObjectName(\":*\"),null) with rmi//"); + assertEquals(cdrmi.queryMBeans( + new ObjectName(":*"),null).contains(moi),true); + System.out.println("Checking queryMBeans(" + + "new ObjectName(\":*\"),null) with direct//"); + assertEquals(cddirect.queryMBeans( + new ObjectName(":*"),null).contains(moi),true); + + // These should fail because the ObjectName doesn't start + // with "faked//" + try { + System.out.println("Checking queryNames(" + + "new ObjectName(\":*\"),null) with faked//"); + assertEquals(proxy.queryNames( + new ObjectName(":*"),null). + contains(moi3.getObjectName()),true); + failed("queryNames(null,null) should have failed for faked//"); + } catch (IllegalArgumentException x) { + System.out.println("Received expected exception for faked//: "+x); + } + // These should fail because the ObjectName doesn't start + // with "faked//" + try { + System.out.println("Checking queryMBeans(" + + "new ObjectName(\":*\"),null) with faked//"); + assertEquals(proxy.queryMBeans( + new ObjectName(":*"),null).contains(moi3),true); + failed("queryMBeans(null,null) should have failed for faked//"); + } catch (IllegalArgumentException x) { + System.out.println("Received expected exception for faked//: "+x); + } + + System.out.println("Checking queryNames(faked//*:*,null)"); + assertEquals(proxy.queryNames(new ObjectName("faked//*:*"),null). + contains(moi3.getObjectName()),true); + + System.out.println("Checking queryMBeans(faked//*:*,null)"); + assertEquals(proxy.queryMBeans(new ObjectName("faked//*:*"),null). + contains(moi3),true); + + proxy.unregisterMBean(moi3.getObjectName()); + + // ADD NEW TESTS HERE ^^^ + + } finally { + srv.stop(); + } + + if (failure != null) + throw new Exception(failure); + + + } + private static void assertEquals(Object x, Object y) { + if (!equal(x, y)) + failed("expected " + string(x) + "; got " + string(y)); + } + + private static boolean equal(Object x, Object y) { + if (x == y) + return true; + if (x == null || y == null) + return false; + if (x.getClass().isArray()) + return Arrays.deepEquals(new Object[] {x}, new Object[] {y}); + return x.equals(y); + } + + private static String string(Object x) { + String s = Arrays.deepToString(new Object[] {x}); + return s.substring(1, s.length() - 1); + } + + + private static void failed(String why) { + failure = why; + new Throwable("FAILED: " + why).printStackTrace(System.out); + } + + public static void main(String[] args) throws Exception { + testRegister(); + } +} diff --git a/test/javax/management/namespace/NullObjectNameTest.java b/test/javax/management/namespace/NullObjectNameTest.java new file mode 100644 index 0000000000000000000000000000000000000000..156e7661db55b816880044563b415990f47ca977 --- /dev/null +++ b/test/javax/management/namespace/NullObjectNameTest.java @@ -0,0 +1,252 @@ +/* + * 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. + * + * 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. + */ +/* + * @test NullObjectNameTest.java + * @summary Test that null ObjectName are correctly handled in namespaces. + * @author Daniel Fuchs + * @bug 5072476 + * @run clean NullObjectNameTest Wombat WombatMBean + * @compile -XDignore.symbol.file=true NullObjectNameTest.java + * @run build NullObjectNameTest Wombat WombatMBean + * @run main NullObjectNameTest + */ + +import com.sun.jmx.namespace.RoutingServerProxy; +import java.lang.management.ManagementFactory; +import java.util.Arrays; +import java.util.logging.Logger; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.JMXRemoteNamespace; +import javax.management.namespace.JMXNamespace; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +/** + * Class NullObjectNameTest + * @author Sun Microsystems, 2005 - All rights reserved. + */ +public class NullObjectNameTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(NullObjectNameTest.class.getName()); + + /** Creates a new instance of NullObjectNameTest */ + public NullObjectNameTest() { + } + + public static class MyWombat + extends Wombat { + public MyWombat() throws NotCompliantMBeanException { + super(); + } + @Override + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + + if (name == null) + name = new ObjectName(":type=Wombat"); + + return super.preRegister(server, name); + } + + } + + static String failure=null; + + public static void testRegister() throws Exception { + final MBeanServer top = ManagementFactory.getPlatformMBeanServer(); + final MBeanServer sub = MBeanServerFactory.createMBeanServer(); + final JMXServiceURL url = new JMXServiceURL("rmi",null,0); + final JMXConnectorServer srv = + JMXConnectorServerFactory.newJMXConnectorServer(url,null,sub); + srv.start(); + + try { + + // Create a namespace rmi// that points to 'sub' and flows through + // a JMXRemoteNamespace connected to 'srv' + // The namespace rmi// will accept createMBean, but not registerMBean. + // + final JMXRemoteNamespace rmiHandler = JMXRemoteNamespace. + newJMXRemoteNamespace(srv.getAddress(),null); + top.registerMBean(rmiHandler,JMXNamespaces.getNamespaceObjectName("rmi")); + top.invoke(JMXNamespaces.getNamespaceObjectName("rmi"), + "connect", null, null); + + // Create a namespace direct// that points to 'sub' and flows + // through a direct reference to 'sub'. + // The namespace direct// will accept createMBean, and registerMBean. + // + final JMXNamespace directHandler = new JMXNamespace(sub); + top.registerMBean(directHandler, + JMXNamespaces.getNamespaceObjectName("direct")); + + // Now cd to each of the created namespace. + // + MBeanServer cdrmi = JMXNamespaces.narrowToNamespace(top,"rmi"); + MBeanServer cddirect = JMXNamespaces.narrowToNamespace(top,"direct"); + boolean ok = false; + + // Check that calling createMBean with a null ObjectName fails + // gracefully for namespace rmi// (we can't add rmi// to a null + // ObjectName. + // + // TODO: do this test for all createMBean flavors! + try { + final ObjectInstance moi1 = + cdrmi.createMBean(MyWombat.class.getName(),null); + System.out.println(moi1.getObjectName().toString()+ + ": created through rmi//"); + cddirect.unregisterMBean(moi1.getObjectName()); + failed("expected MBeanRegistrationException"); + } catch (MBeanRegistrationException x) { + System.out.println("Received expected exception: " + x); + if (!(x.getCause() instanceof IllegalArgumentException)) { + System.err.println("Bad wrapped exception: "+ x.getCause()); + failed("expected IllegalArgumentException"); + } + } + + // Check that calling refgisterMBean with a null ObjectName fails + // gracefully for namespace direct// (we can't add direct// to a null + // ObjectName. + // + try { + final ObjectInstance moi2 = + cddirect.registerMBean(new MyWombat(), (ObjectName)null); + System.out.println(moi2.getObjectName().toString()+ + ": created through direct//"); + cdrmi.unregisterMBean(moi2.getObjectName()); + failed("expected MBeanRegistrationException"); + } catch (MBeanRegistrationException x) { + System.out.println("Received expected exception: " + x); + if (!(x.getCause() instanceof IllegalArgumentException)) { + System.err.println("Bad wrapped exception: "+ x.getCause()); + failed("expected IllegalArgumentException"); + } + } + + // Now artificially pretend that 'sub' is contained in a faked// + // namespace. + // We should be able to use 'null' in registerMBean/createMBean in + // this case. + // + RoutingServerProxy proxy = + new RoutingServerProxy(sub,"","faked",false); + final ObjectInstance moi3 = + proxy.registerMBean(new MyWombat(),null); + System.out.println(moi3.getObjectName().toString()+ + ": created through faked//"); + + // Now check that null is correctly handled (accepted or rejected) + // in queries for each of the above configs. + // + ObjectName wombat = moi3.getObjectName().withDomain( + moi3.getObjectName().getDomain().substring("faked//".length())); + ObjectInstance moi = new ObjectInstance(wombat,moi3.getClassName()); + + System.out.println("Checking queryNames(null,null) with rmi//"); + assertEquals(cdrmi.queryNames(null,null).contains(wombat),true); + System.out.println("Checking queryNames(null,null) with direct//"); + assertEquals(cddirect.queryNames(null,null).contains(wombat),true); + System.out.println("Checking queryMBeans(null,null) with rmi//"); + assertEquals(cdrmi.queryMBeans(null,null).contains(moi),true); + System.out.println("Checking queryMBeans(null,null) with direct//"); + assertEquals(cddirect.queryMBeans(null,null).contains(moi),true); + + try { + System.out.println("Checking queryNames(null,null) with faked//"); + assertEquals(proxy.queryNames(null,null). + contains(moi3.getObjectName()),true); + failed("queryNames(null,null) should have failed for faked//"); + } catch (IllegalArgumentException x) { + System.out.println("Received expected exception for faked//: "+x); + } + try { + System.out.println("Checking queryMBeans(null,null) with faked//"); + assertEquals(proxy.queryMBeans(null,null).contains(moi3),true); + failed("queryMBeans(null,null) should have failed for faked//"); + } catch (IllegalArgumentException x) { + System.out.println("Received expected exception for faked//: "+x); + } + System.out.println("Checking queryNames(faked//*:*,null)"); + assertEquals(proxy.queryNames(new ObjectName("faked//*:*"),null). + contains(moi3.getObjectName()),true); + + System.out.println("Checking queryMBeans(faked//*:*,null)"); + assertEquals(proxy.queryMBeans(new ObjectName("faked//*:*"),null). + contains(moi3),true); + + proxy.unregisterMBean(moi3.getObjectName()); + + // ADD NEW TESTS HERE ^^^ + + } finally { + srv.stop(); + } + + if (failure != null) + throw new Exception(failure); + + + } + private static void assertEquals(Object x, Object y) { + if (!equal(x, y)) + failed("expected " + string(x) + "; got " + string(y)); + } + + private static boolean equal(Object x, Object y) { + if (x == y) + return true; + if (x == null || y == null) + return false; + if (x.getClass().isArray()) + return Arrays.deepEquals(new Object[] {x}, new Object[] {y}); + return x.equals(y); + } + + private static String string(Object x) { + String s = Arrays.deepToString(new Object[] {x}); + return s.substring(1, s.length() - 1); + } + + + private static void failed(String why) { + failure = why; + new Throwable("FAILED: " + why).printStackTrace(System.out); + } + + public static void main(String[] args) throws Exception { + testRegister(); + } +} diff --git a/test/javax/management/namespace/QueryNamesTest.java b/test/javax/management/namespace/QueryNamesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1af597aceb938b10ee70e0f5201711b827bd4afe --- /dev/null +++ b/test/javax/management/namespace/QueryNamesTest.java @@ -0,0 +1,409 @@ +/* + * 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. + * + * 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. + */ +/* + * + * @test QueryNamesTest.java 1.4 + * @summary Test how queryNames works with Namespaces. + * @author Daniel Fuchs + * @bug 5072476 + * @run clean QueryNamesTest Wombat WombatMBean + * @run build QueryNamesTest Wombat WombatMBean + * @run main QueryNamesTest + */ + + +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.logging.Logger; +import javax.management.InstanceNotFoundException; +import javax.management.JMException; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; + +/** + * Class QueryNamesTest + * @author Sun Microsystems, 2005 - All rights reserved. + */ +public class QueryNamesTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(QueryNamesTest.class.getName()); + + public static class LocalNamespace + extends JMXNamespace { + + private static MBeanServer check(MBeanServer server) { + if (server == null) + throw new IllegalArgumentException("MBeanServer can't be null"); + return server; + } + + public LocalNamespace() { + this(MBeanServerFactory.createMBeanServer()); + } + + public LocalNamespace(MBeanServer server) { + super(check(server)); + } + + + public static String add(MBeanServerConnection server, + String nspath) + throws IOException, JMException { + server.createMBean(LocalNamespace.class.getName(), + JMXNamespaces.getNamespaceObjectName(nspath)); + return nspath; + } + } + + /** Creates a new instance of QueryNamesTest */ + public QueryNamesTest() { + } + + private static String[] namespaces = { + "greg", "greg//chichille", "greg//chichille//petard", + "greg//alambic", "greg//alambic//canette", + "greg//chichille/virgule", "greg//chichille/funeste", + "greg//chichille/virgule//bidouble", + "greg//chichille/virgule//bi/double", + "fran", "fran//gast", "fran//gast//gaf", + "fran//longtar", "fran//longtar//parcmetre" + }; + + private static void createNamespaces(MBeanServer server) throws Exception { + final LinkedList all = new LinkedList(); + try { + for (String ns : namespaces) + all.addFirst(LocalNamespace.add(server,ns)); + } catch (Exception e) { + removeNamespaces(server,all.toArray(new String[all.size()])); + throw e; + } + } + + // Dummy test that checks that all JMXNamespaces are registered, + // but are not returned by queryNames("*:*"); + // + private static void checkRegistration(MBeanServer server) + throws Exception { + final Set handlerNames = new HashSet(namespaces.length); + for (String ns : namespaces) + handlerNames.add(JMXNamespaces.getNamespaceObjectName(ns)); + for (ObjectName nh : handlerNames) // check handler registration + if (!server.isRegistered(nh)) + throw new InstanceNotFoundException("handler "+nh+ + " is not registered"); + + // global: queryNames("*:*") from top level + final Set all1 = server.queryNames(null,null); + final Set all2 = server.queryNames(ObjectName.WILDCARD,null); + if (!all1.equals(all2)) + throw new Exception("queryNames(*:*) != queryNames(null)"); + final Set common = new HashSet(all1); + common.retainAll(handlerNames); + + final Set ref = new HashSet(); + for (String ns : namespaces) { + if (!ns.contains(JMXNamespaces.NAMESPACE_SEPARATOR)) + ref.add(JMXNamespaces.getNamespaceObjectName(ns)); + } + if (!common.equals(ref)) { + throw new Exception("some handler names were not returned by " + + "wildcard query - only returned: "+common+ + ", expected: "+ref); + } + + // for each namespace: queryNames("//*:*"); + for (String ns : namespaces) { + final ObjectName pattern = new ObjectName(ns+ + JMXNamespaces.NAMESPACE_SEPARATOR+"*:*"); + final Set all4 = + server.queryNames(pattern,null); + final Set common4 = new HashSet(all4); + common4.retainAll(handlerNames); + + final Set ref4 = new HashSet(); + for (String ns2 : namespaces) { + if (! ns2.startsWith(ns+JMXNamespaces.NAMESPACE_SEPARATOR)) + continue; + if (!ns2.substring(ns.length()+ + JMXNamespaces.NAMESPACE_SEPARATOR.length()). + contains(JMXNamespaces.NAMESPACE_SEPARATOR)) + ref4.add(JMXNamespaces.getNamespaceObjectName(ns2)); + } + if (!common4.equals(ref4)) { + throw new Exception("some handler names were not returned by " + + "wildcard query on "+pattern+" - only returned: "+common4+ + ", expected: "+ref4); + } + } + } + + // Make a Map + private static Map> makeNsTree(String[] nslist) { + final Map> nsTree = + new LinkedHashMap>(nslist.length); + for (String ns : nslist) { + if (nsTree.get(ns) == null) + nsTree.put(ns,new LinkedHashSet()); + final String[] elts = ns.split(JMXNamespaces.NAMESPACE_SEPARATOR); + int last = ns.lastIndexOf(JMXNamespaces.NAMESPACE_SEPARATOR); + if (last<0) continue; + while (last > 0 && ns.charAt(last-1) == '/') last--; + final String parent = ns.substring(0,last); + if (nsTree.get(parent) == null) + nsTree.put(parent,new LinkedHashSet()); + nsTree.get(parent).add(ns); + } + return nsTree; + } + + private static class Rigolo { + final static String[] ones = { "a", "e", "i", "o", "u", "y", "ai", "oo", + "ae", "ey", "ay", "oy", "au", "ou", "eu", "oi", "ei", "ea"}; + final static String[] twos = { "b", "bz", "c", "cz", "ch", + "ct", "ck", "cs", "d", "ds", "f", "g", "gh", "h", "j", "k", "l", "m", + "n", "p", "ps", "q", "r", "s", "sh", "t", "v", "w", "x", + "z"}; + final static String[] threes = {"rr","tt","pp","ss","dd","ff","ll", "mm", "nn", + "zz", "cc", "bb"}; + final static String[] fours = {"x", "s", "ght", "cks", "rt", "rts", "ghts", "bs", + "ts", "gg" }; + final static String[] fives = { "br", "bl", "cr", "cn", "cth", "dr", + "fr", "fl", "cl", "chr", "gr", "gl", "kr", "kh", "pr", "pl", "ph", + "rh", "sr", "tr", "vr"}; + + private Random rg = new Random(); + + private String next(String[] table) { + return table[rg.nextInt(table.length)]; + } + + public String nextName(int max) { + final Random rg = new Random(); + final int nl = 3 + rg.nextInt(max); + boolean begin = rg.nextBoolean(); + StringBuilder sb = new StringBuilder(); + for (int j = 0; j < nl ; j++) { + if (begin) { + sb.append(next(ones)); + } else if (j > 0 && j < nl-1 && rg.nextInt(4)==0) { + sb.append(next(threes)); + } else if (j < nl-1 && rg.nextInt(3)==0) { + sb.append(next(fives)); + } else { + sb.append(next(twos)); + } + begin = !begin; + } + if (!begin && rg.nextInt(2)==0) + sb.append(next(fours)); + return sb.toString(); + } + + private ObjectName getWombatName(String ns, String domain, String name) + throws MalformedObjectNameException { + String d = domain; + if (ns != null && !ns.equals("")) + d = ns + JMXNamespaces.NAMESPACE_SEPARATOR + domain; + return new ObjectName(d+":type=Wombat,name="+name); + } + + public Set nextWombats(String ns) + throws MalformedObjectNameException { + final int dcount = 1 + rg.nextInt(5); + final Set wombats = new HashSet(); + for (int i = 0; i < dcount ; i++) { + final String d = nextName(7); + final int ncount = 5 + rg.nextInt(20); + for (int j = 0 ; j> nsTree = makeNsTree(namespaces); + final Random rg = new Random(); + final Rigolo rigolo = new Rigolo(); + for (String ns : namespaces) { + final ObjectName name = JMXNamespaces.getNamespaceObjectName(ns); + final String[] doms = + (String[])server.getAttribute(name,"Domains"); + final Set subs = new HashSet(); + for (String d : doms) { + if (d.endsWith(JMXNamespaces.NAMESPACE_SEPARATOR)) { + subs.add(ns+JMXNamespaces.NAMESPACE_SEPARATOR+d.substring(0, + d.length()-JMXNamespaces.NAMESPACE_SEPARATOR.length())); + } + } + + final Set expectNs = new HashSet(nsTree.get(ns)); + + if (! subs.containsAll(expectNs)) + throw new Exception("getDomains didn't return all namespaces: "+ + "returned="+subs+", expected="+expectNs); + if (! expectNs.containsAll(subs)) + throw new Exception("getDomains returned additional namespaces: "+ + "returned="+subs+", expected="+expectNs); + + final Set nsNames = server.queryNames( + new ObjectName(ns+ + JMXNamespaces.NAMESPACE_SEPARATOR+"*"+ + JMXNamespaces.NAMESPACE_SEPARATOR+":*"),null); + + final Set expect = + new HashSet(expectNs.size()); + for (String sub : expectNs) { + expect.add(JMXNamespaces.getNamespaceObjectName(sub)); + } + + if (! nsNames.containsAll(expect)) + throw new Exception("queryNames didn't return all namespaces: "+ + "returned="+nsNames+", expected="+expect); + if (! expect.containsAll(nsNames)) + throw new Exception("getDomains returned additional namespaces: "+ + "returned="+nsNames+", expected="+expect); + + } + } + + private static void addWombats(MBeanServer server, Set names) + throws Exception { + for (ObjectName on : names) { + if (! server.isRegistered(on)) { + server.createMBean(Wombat.class.getName(),on); + System.out.println("A new wombat is born: "+on); + } + } + } + + private static void addWombats(MBeanServer server, + Map> wombats) + throws Exception { + for (String ns : wombats.keySet()) { + addWombats(server,wombats.get(ns)); + } + } + + private static Map> nameWombats() + throws Exception { + final Rigolo rigolo = new Rigolo(); + final Map> wombats = + new HashMap>(namespaces.length); + + for (String ns : namespaces) { + wombats.put(ns,rigolo.nextWombats(ns)); + } + wombats.put("",rigolo.nextWombats("")); + return wombats; + } + + private static boolean removeWombats(MBeanServer server, + Map> wombats) { + boolean res = true; + for (String ns : wombats.keySet()) { + res = res && removeWombats(server,wombats.get(ns)); + } + return res; + } + + private static boolean removeWombats(MBeanServer server, + Set wombats) { + boolean res = true; + for (ObjectName on : wombats) { + try { + if (server.isRegistered(on)) + server.unregisterMBean(on); + } catch (Exception x) { + res = false; + System.out.println("Failed to remove "+on+": "+x); + } + } + return res; + } + + public static void main(String[] args) + throws Exception { + final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + Map> wombats = nameWombats(); + createNamespaces(server); + try { + addWombats(server,wombats); + System.out.println("MBeans: " +server.getMBeanCount()); + System.out.println("Visible: " +server.queryNames(null,null).size()); + System.out.println("Domains: " +Arrays.asList(server.getDomains())); + checkRegistration(server); + checkNsQuery(server); + } finally { + boolean res = true; + res = res && removeWombats(server, wombats); + if (!res) + throw new RuntimeException("failed to cleanup some namespaces"); + } + + } + + private static boolean removeNamespaces(MBeanServer server) { + final List l = Arrays.asList(namespaces); + Collections.reverse(l); + return removeNamespaces(server, l.toArray(new String[namespaces.length])); + } + + private static boolean removeNamespaces(MBeanServer server, String[] t) { + boolean success = true; + for (String ns : t) { + try { + server.unregisterMBean(JMXNamespaces.getNamespaceObjectName(ns)); + } catch (Exception x) { + System.out.println("failed to remove namespace: "+ ns); + success = false; + } + } + return success; + } + +} diff --git a/test/javax/management/namespace/RemoveNotificationListenerTest.java b/test/javax/management/namespace/RemoveNotificationListenerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a8ea2aee376fbd780bce27b0b27bcaf60ad36017 --- /dev/null +++ b/test/javax/management/namespace/RemoveNotificationListenerTest.java @@ -0,0 +1,377 @@ +/* + * 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. + * + * 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. + */ +/* + * + * @test RemoveNotificationListenerTest.java 1.8 + * @summary General RemoveNotificationListenerTest test. + * @author Daniel Fuchs + * @bug 5072476 + * @run clean RemoveNotificationListenerTest JMXRemoteTargetNamespace + * @compile -XDignore.symbol.file=true JMXRemoteTargetNamespace.java + * @run build RemoveNotificationListenerTest JMXRemoteTargetNamespace + * @run main/othervm RemoveNotificationListenerTest + */ + +import com.sun.jmx.remote.util.EventClientConnection; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.security.Principal; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; +import javax.management.JMException; +import javax.management.JMX; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.namespace.JMXNamespaces; +import javax.management.remote.JMXAuthenticator; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXConnectorServerMBean; +import javax.management.remote.JMXPrincipal; +import javax.management.remote.JMXServiceURL; +import javax.security.auth.Subject; + +/** + * Class RemoveNotificationListenerTest + */ +public class RemoveNotificationListenerTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(RemoveNotificationListenerTest.class.getName()); + + /** Creates a new instance of RemoveNotificationListenerTest */ + public RemoveNotificationListenerTest() { + } + + public static class SubjectAuthenticator implements JMXAuthenticator { + final Set authorized; + public SubjectAuthenticator(Subject[] authorized) { + this.authorized = new HashSet(Arrays.asList(authorized)); + } + + public Subject authenticate(Object credentials) { + if (authorized.contains(credentials)) + return (Subject)credentials; + else + throw new SecurityException("Subject not authorized: "+credentials); + } + + } + + public static interface LongtarMBean { + public void sendNotification(Object userData) + throws IOException, JMException; + } + public static class Longtar extends NotificationBroadcasterSupport + implements LongtarMBean { + public Longtar() { + super(new MBeanNotificationInfo[] { + new MBeanNotificationInfo(new String[] {"papillon"}, + "pv","M'enfin???") + }); + } + + public void sendNotification(Object userData) + throws IOException, JMException { + final Notification n = + new Notification("papillon",this,nextseq(),"M'enfin???"); + n.setUserData(userData); + System.out.println("Sending notification: "+userData); + sendNotification(n); + } + + private static synchronized long nextseq() {return ++seqnb;} + private static volatile long seqnb=0; + } + + private static final String NS = JMXNamespaces.NAMESPACE_SEPARATOR; + private static final String CS = "jmx.rmi:type=JMXConnectorServer"; + private static final String BD = "longtar:type=Longtar"; + + private static void createNamespace(MBeanServerConnection server, + String namespace, Subject creator, boolean forwarding) + throws Exception { + final MBeanServer sub = MBeanServerFactory.createMBeanServer(); + final JMXServiceURL url = new JMXServiceURL("rmi",null,0); + final Map smap = new HashMap(); + smap.put(JMXConnectorServer.AUTHENTICATOR, + new SubjectAuthenticator(new Subject[] {creator})); + final JMXConnectorServer rmi = + JMXConnectorServerFactory.newJMXConnectorServer(url,smap,null); + final ObjectName name = new ObjectName(CS); + sub.registerMBean(rmi,name); + rmi.start(); + final Map cmap = new HashMap(); + cmap.put(JMXConnector.CREDENTIALS,creator); + final Map options = new HashMap(cmap); + options.put(JMXRemoteTargetNamespace.CREATE_EVENT_CLIENT,"true"); + JMXRemoteTargetNamespace.createNamespace(server, + namespace, + rmi.getAddress(), + options + ); + server.invoke(JMXNamespaces.getNamespaceObjectName(namespace), + "connect", null,null); + } + private static void closeNamespace(MBeanServerConnection server, + String namespace) { + try { + final ObjectName hname = + JMXNamespaces.getNamespaceObjectName(namespace); + if (!server.isRegistered(hname)) + return; + final ObjectName sname = + new ObjectName(namespace+NS+CS); + if (!server.isRegistered(sname)) + return; + final JMXConnectorServerMBean cs = + JMX.newMBeanProxy(server,sname, + JMXConnectorServerMBean.class,true); + try { + cs.stop(); + } finally { + server.unregisterMBean(hname); + } + } catch (Throwable t) { + t.printStackTrace(); + } + } + + private static Subject newSubject(String[] principals) { + final Set ps = new HashSet(); + for (String p:principals) ps.add(new JMXPrincipal(p)); + return new Subject(true,ps,Collections.emptySet(),Collections.emptySet()); + } + + + public static void testSubject() throws Exception { + final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + final String a = "a"; + final String b = a + NS + "b"; + + final Subject s1 = newSubject(new String[] {"chichille"}); + final Subject s2 = newSubject(new String[] {"alambic"}); + final Subject s3 = newSubject(new String[] {"virgule"}); + final Subject s4 = newSubject(new String[] {"funeste"}); + + final JMXServiceURL url = new JMXServiceURL("rmi",null,0); + final Map smap = new HashMap(); + smap.put(JMXConnectorServer.AUTHENTICATOR, + new SubjectAuthenticator(new Subject[] {s1})); + final JMXConnectorServer rmi = + JMXConnectorServerFactory.newJMXConnectorServer(url,smap,null); + final ObjectName name = new ObjectName(CS); + server.registerMBean(rmi,name); + rmi.start(); + + try { + + final Map map = new HashMap(); + map.put(JMXConnector.CREDENTIALS,s1); + final JMXConnector c = + JMXConnectorFactory.connect(rmi.getAddress(),map); + final MBeanServerConnection mbsorig = c.getMBeanServerConnection(); + + final MBeanServerConnection mbs = + EventClientConnection.getEventConnectionFor(mbsorig,null); + + createNamespace(mbs,a,s2,true); + createNamespace(mbs,b,s3,true); + + final ObjectName longtar = new ObjectName(b+NS+BD); + + mbs.createMBean(Longtar.class.getName(),longtar); + final LongtarMBean proxy = + JMX.newMBeanProxy(mbs,longtar,LongtarMBean.class,true); + + + final BlockingQueue bbq = + new ArrayBlockingQueue(10); + final NotificationListener listener1 = new NotificationListener() { + public void handleNotification(Notification notification, + Object handback) { + System.out.println(notification.getSequenceNumber()+": "+ + notification.getMessage()); + bbq.add(notification); + } + }; + final NotificationListener listener2 = new NotificationListener() { + public void handleNotification(Notification notification, + Object handback) { + System.out.println(notification.getSequenceNumber()+": "+ + notification.getMessage()); + bbq.add(notification); + } + }; + + final NotificationEmitter ubpdalfdla = (NotificationEmitter)proxy; + try { + + // Add 1 NL, send 1 notif (1) + ubpdalfdla.addNotificationListener(listener1,null,listener1); + proxy.sendNotification(new Integer(1)); + // Thread.sleep(180000); + + // We should have 1 notif with userdata = 1 + final Notification n1 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n1.getUserData()).intValue() != 1) + throw new Exception("Expected 1, got"+n1.getUserData()); + + // remove NL, send 1 notif (2) => we shouldn't receive it + ubpdalfdla.removeNotificationListener(listener1,null,listener1); + proxy.sendNotification(new Integer(2)); + + // add NL, send 1 notif (3) + ubpdalfdla.addNotificationListener(listener1,null,listener1); + proxy.sendNotification(new Integer(3)); + + // we should receive only 1 notif (3) + final Notification n3 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n3.getUserData()).intValue() != 3) + throw new Exception("Expected 3, got"+n3.getUserData()); + + // remove NL, send 1 notif (4) => we shouldn't receive it. + ubpdalfdla.removeNotificationListener(listener1); + proxy.sendNotification(new Integer(4)); + + // add NL, send 1 notif (5). + ubpdalfdla.addNotificationListener(listener1,null,listener1); + proxy.sendNotification(new Integer(5)); + + // next notif in queue should be (5) + final Notification n5 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n5.getUserData()).intValue() != 5) + throw new Exception("Expected 5, got"+n5.getUserData()); + + // add 2 NL, send 1 notif (6) + ubpdalfdla.addNotificationListener(listener2,null,listener2); + ubpdalfdla.addNotificationListener(listener2,null,null); + proxy.sendNotification(new Integer(6)); + + // We have 3 NL, we should receive (6) 3 times.... + final Notification n61 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n61.getUserData()).intValue() != 6) + throw new Exception("Expected 6 (#1), got"+n61.getUserData()); + final Notification n62 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n62.getUserData()).intValue() != 6) + throw new Exception("Expected 6 (#2), got"+n62.getUserData()); + final Notification n63 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n63.getUserData()).intValue() != 6) + throw new Exception("Expected 6 (#3), got"+n63.getUserData()); + + // Remove 1 NL, send 1 notif (7) + ubpdalfdla.removeNotificationListener(listener2,null,null); + proxy.sendNotification(new Integer(7)); + + // next notifs in queue should be (7), twice... + final Notification n71 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n71.getUserData()).intValue() != 7) + throw new Exception("Expected 7 (#1), got"+n71.getUserData()); + final Notification n72 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n72.getUserData()).intValue() != 7) + throw new Exception("Expected 7 (#2), got"+n72.getUserData()); + + // Add 1 NL, send 1 notif (8) + ubpdalfdla.addNotificationListener(listener2,null,null); + proxy.sendNotification(new Integer(8)); + + // Next notifs in queue should be (8), 3 times. + final Notification n81 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n81.getUserData()).intValue() != 8) + throw new Exception("Expected 8 (#1), got"+n81.getUserData()); + final Notification n82 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n82.getUserData()).intValue() != 8) + throw new Exception("Expected 8 (#2), got"+n82.getUserData()); + final Notification n83 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n83.getUserData()).intValue() != 8) + throw new Exception("Expected 8 (#3), got"+n83.getUserData()); + + // Remove 2 NL, send 1 notif (9) + ubpdalfdla.removeNotificationListener(listener2); + proxy.sendNotification(new Integer(9)); + + // Next notifs in queue should be (9), 1 time only. + final Notification n9 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n9.getUserData()).intValue() != 9) + throw new Exception("Expected 9, got"+n9.getUserData()); + + // send 1 notif (10) + proxy.sendNotification(new Integer(10)); + + // Next notifs in queue should be (10), 1 time only. + final Notification n10 = bbq.poll(3,TimeUnit.SECONDS); + // may throw NPE => would indicate a bug. + if (((Integer)n10.getUserData()).intValue() != 10) + throw new Exception("Expected 10, got"+n10.getUserData()); + + ubpdalfdla.removeNotificationListener(listener1); + mbs.unregisterMBean(longtar); + + } finally { + c.close(); + } + } finally { + closeNamespace(server,b); + closeNamespace(server,a); + rmi.stop(); + } + + } + + public static void main(String[] args) throws Exception { + testSubject(); + } + +} diff --git a/test/javax/management/namespace/RoutingServerProxyTest.java b/test/javax/management/namespace/RoutingServerProxyTest.java new file mode 100644 index 0000000000000000000000000000000000000000..698021321d14e0f76c750aa560f6d6942d5cc892 --- /dev/null +++ b/test/javax/management/namespace/RoutingServerProxyTest.java @@ -0,0 +1,400 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test RoutingServerProxyTest.java 1.6 + * @summary General RoutingServerProxyTest test. + * @author Daniel Fuchs + * @bug 5072476 + * @run clean RoutingServerProxyTest Wombat WombatMBean + * @compile -XDignore.symbol.file=true RoutingServerProxyTest.java + * @run build RoutingServerProxyTest Wombat WombatMBean + * @run main RoutingServerProxyTest + */ + +import com.sun.jmx.namespace.RoutingServerProxy; +import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import javax.management.DynamicMBean; +import javax.management.InstanceNotFoundException; +import javax.management.JMException; +import javax.management.JMX; +import javax.management.MBeanInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationEmitter; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.StandardEmitterMBean; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.MBeanServerSupport; + +/** + * Class RoutingServerProxyTest + * + * @author Sun Microsystems, Inc. + */ +public class RoutingServerProxyTest { + + /** + * A logger for this class. + **/ + private static final Logger LOG = + Logger.getLogger(RoutingServerProxyTest.class.getName()); + + /** + * Creates a new instance of RoutingServerProxyTest + */ + public RoutingServerProxyTest() { + } + + public static class DynamicWombat extends StandardEmitterMBean { + DynamicWombat(Wombat w) throws NotCompliantMBeanException { + super(w,WombatMBean.class,w); + } + + @Override + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + final ObjectName myname = ((Wombat)getImplementation()). + preRegister(server,name); + return super.preRegister(server,myname); + } + + @Override + public void postRegister(Boolean registrationDone) { + try { + ((Wombat)getImplementation()). + postRegister(registrationDone); + } finally { + super.postRegister(registrationDone); + } + } + + @Override + public void preDeregister() throws Exception { + ((Wombat)getImplementation()). + preDeregister(); + super.preDeregister(); + + } + + @Override + public void postDeregister() { + try { + ((Wombat)getImplementation()). + postDeregister(); + } finally { + super.postDeregister(); + } + } + } + + public static class VirtualWombatHandler + extends JMXNamespace { + + public static class VirtualWombatRepository + extends MBeanServerSupport { + + final Map bush; + + VirtualWombatRepository(Map bush) { + this.bush = bush; + } + + @Override + protected Set getNames() { + return bush.keySet(); + } + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + final DynamicMBean mb = bush.get(name); + if (mb == null) { + throw new InstanceNotFoundException(String.valueOf(name)); + } + return mb; + } + + @Override + public NotificationEmitter getNotificationEmitterFor( + ObjectName name) throws InstanceNotFoundException { + DynamicMBean mbean = getDynamicMBeanFor(name); + if (mbean instanceof NotificationEmitter) { + return (NotificationEmitter) mbean; + } + return null; + } + } + VirtualWombatRepository bush; + + VirtualWombatHandler(Map bush) { + this(new VirtualWombatRepository(Collections.synchronizedMap(bush))); + } + + private VirtualWombatHandler(VirtualWombatRepository repository) { + super(repository); + bush = repository; + } + + @Override + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + final ObjectName myname = super.preRegister(server, name); + return myname; + } + + @Override + public void postRegister(Boolean registrationDone) { + if (!registrationDone.booleanValue()) { + return; + } + final MBeanServer me = JMXNamespaces.narrowToNamespace(getMBeanServer(), + getObjectName().getDomain()); + for (Map.Entry e : bush.bush.entrySet()) { + final DynamicMBean obj = e.getValue(); + try { + if (obj instanceof MBeanRegistration) { + ((MBeanRegistration) obj).preRegister(me, e.getKey()); + } + } catch (Exception x) { + System.err.println("preRegister failed for " + + e.getKey() + ": " + x); + bush.bush.remove(e.getKey()); + } + } + for (Map.Entry e : bush.bush.entrySet()) { + final Object obj = e.getValue(); + if (obj instanceof MBeanRegistration) { + ((MBeanRegistration) obj).postRegister(registrationDone); + } + } + } + + @Override + public void preDeregister() throws Exception { + for (Map.Entry e : bush.bush.entrySet()) { + final Object obj = e.getValue(); + if (obj instanceof MBeanRegistration) { + ((MBeanRegistration) obj).preDeregister(); + } + } + } + + @Override + public void postDeregister() { + for (Map.Entry e : bush.bush.entrySet()) { + final Object obj = e.getValue(); + if (obj instanceof MBeanRegistration) { + ((MBeanRegistration) obj).postDeregister(); + } + } + } + } + + public static ObjectName getWombatName(String name) + throws MalformedObjectNameException { + return ObjectName.getInstance("australian.bush:type=Wombat,name="+name); + } + + public static ObjectName addDir(String dir, ObjectName name) + throws MalformedObjectNameException { + return name.withDomain( + dir+JMXNamespaces.NAMESPACE_SEPARATOR+ name.getDomain()); + } + + public static void simpleTest() + throws JMException, IOException { + final MBeanServer master = MBeanServerFactory.createMBeanServer(); + final MBeanServer agent1 = MBeanServerFactory.createMBeanServer(); + final Wombat w1 = new Wombat(); + final Wombat w2 = new Wombat(); + final Wombat w3 = new Wombat(); + final Map wombats = + new ConcurrentHashMap(); + wombats.put(getWombatName("LittleWombat"), + new DynamicWombat(w2)); + wombats.put(getWombatName("BigWombat"), + new DynamicWombat(w3)); + final Wombat w4 = new Wombat(); + final Wombat w5 = new Wombat(); + + final JMXNamespace agent2 = + new VirtualWombatHandler(wombats); + agent1.registerMBean(w4,getWombatName("LittleWombat")); + master.registerMBean(w1,getWombatName("LittleWombat")); + master.registerMBean(new JMXNamespace(agent1), + JMXNamespaces.getNamespaceObjectName("south.east")); + master.registerMBean(agent2, + JMXNamespaces.getNamespaceObjectName("north")); + master.registerMBean(w5,addDir("south.east", + getWombatName("GrandWombat"))); + + MBeanServer se = null; + + try { + se = JMXNamespaces.narrowToNamespace(master,"south.easht"); + } catch (Exception x) { + System.out.println("Caught expected exception: "+x); + } + if (se != null) + throw new RuntimeException("Expected exception for "+ + "cd(south.easht)"); + se = JMXNamespaces.narrowToNamespace(master,"south.east"); + + MBeanServer nth = JMXNamespaces.narrowToNamespace(master,"north"); + + final ObjectName ln = getWombatName("LittleWombat"); + MBeanInfo mb1 = master.getMBeanInfo(ln); + MBeanInfo mb2 = se.getMBeanInfo(ln); + MBeanInfo mb3 = nth.getMBeanInfo(ln); + + final WombatMBean grand = JMX.newMBeanProxy(se, + getWombatName("GrandWombat"),WombatMBean.class); + final WombatMBean big = JMX.newMBeanProxy(nth, + getWombatName("BigWombat"),WombatMBean.class); + grand.getCaption(); + big.getCaption(); + grand.setCaption("I am GrandWombat"); + big.setCaption("I am BigWombat"); + + final WombatMBean grand2 = + JMX.newMBeanProxy(master,addDir("south.east", + getWombatName("GrandWombat")),WombatMBean.class); + final WombatMBean big2 = + JMX.newMBeanProxy(master,addDir("north", + getWombatName("BigWombat")),WombatMBean.class); + if (!"I am GrandWombat".equals(grand2.getCaption())) + throw new RuntimeException("bad caption for GrandWombat"+ + grand2.getCaption()); + if (!"I am BigWombat".equals(big2.getCaption())) + throw new RuntimeException("bad caption for BigWombat"+ + big2.getCaption()); + + + final Set northWombats = + nth.queryMBeans(ObjectName.WILDCARD,null); + final Set seWombats = + se.queryMBeans(ObjectName.WILDCARD,null); + if (!northWombats.equals( + agent2.getSourceServer().queryMBeans(ObjectName.WILDCARD,null))) { + throw new RuntimeException("Bad Wombat census in northern territory: got " + +northWombats+", expected "+ + agent2.getSourceServer(). + queryMBeans(ObjectName.WILDCARD,null)); + } + if (!seWombats.equals( + agent1.queryMBeans(ObjectName.WILDCARD,null))) { + throw new RuntimeException("Bad Wombat census in south east: got " + +seWombats+", expected "+ + agent1. + queryMBeans(ObjectName.WILDCARD,null)); + } + + final MBeanServer supermaster = MBeanServerFactory.createMBeanServer(); + supermaster.registerMBean(new JMXNamespace(master), + JMXNamespaces.getNamespaceObjectName("australia")); + final MBeanServer proxymaster = + JMXNamespaces.narrowToNamespace(supermaster,"australia"); + final MBeanServer sem = + JMXNamespaces.narrowToNamespace(proxymaster,"south.east"); + final MBeanServer nthm = + JMXNamespaces.narrowToNamespace(proxymaster,"north"); + final Set northWombats2 = + nthm.queryMBeans(ObjectName.WILDCARD,null); + final Set seWombats2 = + sem.queryMBeans(ObjectName.WILDCARD,null); + if (!northWombats2.equals( + agent2.getSourceServer().queryMBeans(ObjectName.WILDCARD,null))) { + throw new RuntimeException("Bad Wombat census in " + + "Australia // North"); + } + if (!seWombats2.equals( + agent1.queryMBeans(ObjectName.WILDCARD,null))) { + throw new RuntimeException("Bad Wombat census in " + + "Australia // South East"); + } + final WombatMBean grand3 = + JMX.newMBeanProxy(supermaster, + addDir("australia//south.east", + getWombatName("GrandWombat")),WombatMBean.class); + final WombatMBean big3 = + JMX.newMBeanProxy(supermaster,addDir("australia//north", + getWombatName("BigWombat")),WombatMBean.class); + if (!"I am GrandWombat".equals(grand3.getCaption())) + throw new RuntimeException("bad caption for " + + "australia//south.east//GrandWombat"+ + grand3.getCaption()); + if (!"I am BigWombat".equals(big3.getCaption())) + throw new RuntimeException("bad caption for " + + "australia//north//BigWombat"+ + big3.getCaption()); + final WombatMBean grand4 = + JMX.newMBeanProxy(sem, + getWombatName("GrandWombat"),WombatMBean.class); + final WombatMBean big4 = + JMX.newMBeanProxy(nthm, + getWombatName("BigWombat"),WombatMBean.class); + if (!"I am GrandWombat".equals(grand4.getCaption())) + throw new RuntimeException("bad caption for " + + "[australia//south.east//] GrandWombat"+ + grand4.getCaption()); + if (!"I am BigWombat".equals(big4.getCaption())) + throw new RuntimeException("bad caption for " + + "[australia//north//] BigWombat"+ + big4.getCaption()); + + if (!(nthm instanceof RoutingServerProxy)) + throw new AssertionError("expected RoutingServerProxy for nthm"); + if (!(sem instanceof RoutingServerProxy)) + throw new AssertionError("expected RoutingServerProxy for sem"); + + if (!"australia//north".equals(( + (RoutingServerProxy)nthm).getSourceNamespace())) + throw new RuntimeException("north territory should be in australia"); + if (!"australia//south.east".equals(( + (RoutingServerProxy)sem).getSourceNamespace())) + throw new RuntimeException("south east territory should be in australia"); + + } + + public static void main(String[] args) { + try { + simpleTest(); + } catch (Exception x) { + System.err.println("SimpleTest failed: "+x); + throw new RuntimeException(x); + } + } + +} diff --git a/test/javax/management/namespace/SerialParamProcessorTest.java b/test/javax/management/namespace/SerialParamProcessorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..20df761d0e28debbda750ad06a9447a03b5c3971 --- /dev/null +++ b/test/javax/management/namespace/SerialParamProcessorTest.java @@ -0,0 +1,572 @@ +/* + * 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. + * + * 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. + */ + +/* + * + * @test SerialParamProcessorTest.java 1.8 + * @summary General SerialParamProcessorTest test. + * @author Daniel Fuchs + * @bug 5072476 + * @run clean SerialParamProcessorTest Wombat WombatMBean + * @compile -XDignore.symbol.file=true SerialParamProcessorTest.java + * @run build SerialParamProcessorTest Wombat WombatMBean + * @run main SerialParamProcessorTest + */ + +import com.sun.jmx.namespace.serial.RewritingProcessor; +import java.beans.ConstructorProperties; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import javax.management.AttributeChangeNotification; +import javax.management.AttributeList; +import javax.management.JMException; +import javax.management.Notification; +import javax.management.ObjectName; +import javax.management.StandardMBean; + +/** + * Class SerialParamProcessorTest + * + * @author Sun Microsystems, Inc. + */ +public class SerialParamProcessorTest { + + /** + * Creates a new instance of SerialParamProcessorTest + */ + public SerialParamProcessorTest() { + } + + public static class MyCompositeData implements Serializable { + private static final long serialVersionUID = 3186492415099133506L; + public MyCompositeData(ObjectName foobar,ObjectName absolute, + long count, String name) { + this(foobar,absolute,count,name,new ObjectName[]{foobar,absolute}); + } + @ConstructorProperties(value={"fooBar","absolute","count","name", + "allNames"}) + public MyCompositeData(ObjectName foobar,ObjectName absolute, + long count, String name, ObjectName[] allnames) { + this.foobar = foobar; + this.absolute = absolute; + this.count = count; + this.name = name; + this.allnames = allnames; + } + ObjectName foobar,absolute,allnames[]; + long count; + String name; + public ObjectName getFooBar() { + return foobar; + } + public ObjectName getAbsolute() { + return absolute; + } + public ObjectName[] getAllNames() { + return allnames; + } + public long getCount() { + return count; + } + public String getName() { + return name; + } + private Object[] toArray() { + final Object[] props = { + getName(),getFooBar(),getAbsolute(),getAllNames(),getCount() + }; + return props; + } + @Override + public boolean equals(Object o) { + if (o instanceof MyCompositeData) + return Arrays.deepEquals(toArray(), + ((MyCompositeData)o).toArray()); + return false; + } + @Override + public int hashCode() { + return Arrays.deepHashCode(toArray()); + } + } + + public static interface MyMXBean { + public Map getAll(); + public MyCompositeData lookup(String name); + public void put(String name, MyCompositeData data); + public MyCompositeData remove(String name); + } + + public static class My implements MyMXBean { + Map datas = + new HashMap(); + public Map getAll() { + return datas; + } + public MyCompositeData lookup(String name) { + return datas.get(name); + } + public void put(String name, MyCompositeData data) { + datas.put(name,data); + } + public MyCompositeData remove(String name) { + return datas.remove(name); + } + } + + public static class BandicootClass implements Serializable { + private static final long serialVersionUID = -5494055748633966355L; + public final Object gloups; + public BandicootClass(Object gloups) { + this.gloups = gloups; + } + private Object[] toArray() { + final Object[] one = {gloups}; + return one; + } + @Override + public boolean equals(Object obj) { + if (!(obj instanceof BandicootClass)) return false; + final Object[] one = {gloups}; + return Arrays.deepEquals(toArray(),((BandicootClass)obj).toArray()); + } + @Override + public int hashCode() { + if (gloups == null) return 0; + return Arrays.deepHashCode(toArray()); + } + } + + // Need this to override equals. + public static class BandicootNotification extends Notification { + private static final long serialVersionUID = 664758643764049001L; + public BandicootNotification(String type, Object source, long seq) { + super(type,source,seq,0L,""); + } + private Object[] toArray() { + final Object[] vals = {getMessage(),getSequenceNumber(), + getSource(),getTimeStamp(),getType(),getUserData()}; + return vals; + } + @Override + public boolean equals(Object o) { + if (!(o instanceof BandicootNotification)) return false; + return Arrays.deepEquals(toArray(), + ((BandicootNotification)o).toArray()); + } + @Override + public int hashCode() { + return Arrays.deepHashCode(toArray()); + } + + } + + // Need this to override equals. + public static class BandicootAttributeChangeNotification + extends AttributeChangeNotification { + private static final long serialVersionUID = -1392435607144396125L; + public BandicootAttributeChangeNotification(Object source, + long seq, long time, String msg, String name, String type, + Object oldv, Object newv) { + super(source,seq,time,msg,name,type,oldv,newv); + } + private Object[] toArray() { + final Object[] vals = {getMessage(),getSequenceNumber(), + getSource(),getTimeStamp(),getType(),getUserData(), + getAttributeName(), getAttributeType(),getNewValue(), + getOldValue()}; + return vals; + } + @Override + public boolean equals(Object o) { + if (!(o instanceof BandicootAttributeChangeNotification)) + return false; + return Arrays.deepEquals(toArray(), + ((BandicootAttributeChangeNotification)o).toArray()); + } + @Override + public int hashCode() { + return Arrays.deepHashCode(toArray()); + } + @Override + public String toString() { + final StringBuilder b = new StringBuilder(); + b.append(this.getClass().getName()).append(": "); + b.append("[type=").append(getType()).append("]"); + b.append("[source=").append(getSource()).append("]"); + b.append("[message=").append(getMessage()).append("]"); + b.append("[sequence=").append(getSequenceNumber()).append("]"); + + b.append("[attribute=").append(getAttributeName()).append("]"); + b.append("[class=").append(getAttributeType()).append("]"); + b.append("[oldvalue=").append(getOldValue()).append("]"); + b.append("[newvalue=").append(getNewValue()).append("]"); + + b.append("[time=").append(getTimeStamp()).append("]"); + b.append("[data=").append(getUserData()).append("]"); + return b.toString(); + } + } + + private static void addToList(Object[] foos, List foolist) { + final ArrayList fal = new ArrayList(foos.length); + for (Object f : foos) { + if (f.getClass().isArray()) { + foolist.add(new BandicootClass(f)); + fal.add(new BandicootClass(f)); + } else { + foolist.add(f); + fal.add(f); + } + } + foolist.add(new BandicootClass(foos)); + foolist.add(fal); + } + + public static void testSerial(String msg, Object foo, Object bar, + RewritingProcessor procForFoo, + RewritingProcessor procForBar, List foolist, + List barlist, boolean recurse) { + System.err.println(msg+" Testing serial - "+foo.getClass().getName()); + final Object bar1 = procForFoo.rewriteInput(foo); + final Object foo1 = procForFoo.rewriteOutput(bar); + final Object bar2 = procForFoo.rewriteInput(foo1); + final Object foo2 = procForFoo.rewriteOutput(bar1); + + final Object bar3 = procForBar.rewriteOutput(foo); + final Object foo3 = procForBar.rewriteInput(bar); + final Object bar4 = procForBar.rewriteOutput(foo3); + final Object foo4 = procForBar.rewriteInput(bar3); + + final Object bar5 = procForFoo.rewriteInput(foo3); + final Object foo5 = procForFoo.rewriteOutput(bar3); + + final Object bar6 = procForBar.rewriteOutput(foo1); + final Object foo6 = procForBar.rewriteInput(bar1); + + final Object[] foos = {foo, foo1, foo2, foo3, foo4, foo5, foo6}; + final Object[] bars = {bar, bar1, bar2, bar3, bar4, bar5, bar6}; + + final Object[] foot = { foo }; + final Object[] bart = { bar }; + for (int j=1;j foolist = new LinkedList(); + final List barlist = new LinkedList(); + for (Object[] row : objects) { + i++; + Object foo = row[0]; + Object bar = row[1]; + String msg1 = "[" +foo.getClass().getName() + "] step " + + i +": "; + + testSerial(msg1,foo,bar,procForFoo,procForBar,foolist,barlist,true); + + final BandicootClass kfoo = new BandicootClass(foo); + final BandicootClass kbar = new BandicootClass(bar); + + String msg2 = "[" +kfoo.getClass().getName() + "] step " + + i +": "; + testSerial(msg2,kfoo,kbar,procForFoo,procForBar,foolist,barlist,true); + } + String msg31 = "foo[] and bar[]: "; + testSerial(msg31,foolist.toArray(),barlist.toArray(), + procForFoo,procForBar,foolist,barlist,false); + + String msg3 = "foolist and barlist: "; + testSerial(msg3,new LinkedList(foolist), + new LinkedList(barlist), + procForFoo,procForBar,foolist,barlist,false); + + final BandicootClass kfoolist = new BandicootClass(foolist); + final BandicootClass kbarlist = new BandicootClass(barlist); + String msg4 = "kfoolist and kbarlist: "; + testSerial(msg4,kfoolist,kbarlist,procForFoo,procForBar,foolist,barlist,false); + } + + /** + * The idea of this method is to convert {@code foo} things into + * {@code bar} things... + * @param foo the string to replace. + * @param bar the replacement for {@code foo} + * ({@code foo} becomes {@code bar}). + * @param sfoo a string that may contain {@code foo}, that will be embedded + * in non-replaceable parts of the domain in order to attempt to + * trick the replacement logic. + * @param sbar a string that may contain {@code bar}, that will be embedded + * in non-replaceable parts of the domain in order to attempt to + * trick the replacement logic. + **/ + public static void doSerialTest(String foo, String bar, String sfoo, + String sbar) { + try { + final RewritingProcessor procForFoo = RewritingProcessor. + newRewritingProcessor(foo,bar); + final RewritingProcessor procForBar =RewritingProcessor. + newRewritingProcessor(bar,foo); + final String foop = (foo.isEmpty())?foo:foo+"//"; + final String pfoo = (foo.isEmpty())?foo:"//"+foo; + final String barp = (bar.isEmpty())?bar:bar+"//"; + final String pbar = (bar.isEmpty())?bar:"//"+bar; + final String sfoop = (sfoo.isEmpty())?sfoo:sfoo+"//"; + final String psfoo = (sfoo.isEmpty())?sfoo:"//"+sfoo; + final String sbarp = (sbar.isEmpty())?sbar:sbar+"//"; + final String psbar = (sbar.isEmpty())?sbar:"//"+sbar; + + // A trick to avoid writing Open Data by hand... + final My tricks = new My(); + + // A treat to automagically convert trick things into Open Data. + final StandardMBean treats = + new StandardMBean(tricks,MyMXBean.class,true); + + // datas[i][0] is expected to be transformed in datas[i][1] + // + final MyCompositeData[][] datas = { + { // this foo thing: + new MyCompositeData(new ObjectName(foop+sbarp+"x:y=z"), + new ObjectName("//"+foop+sbarp+"x:y=z"),1,sfoop+sbarp+"foobar"), + // should be transformed into this bar thing: + new MyCompositeData(new ObjectName(barp+sbarp+"x:y=z"), + new ObjectName("//"+foop+sbarp+"x:y=z"),1,sfoop+sbarp+"foobar"), + }, + { // this foo thing: + new MyCompositeData(new ObjectName(foop+sfoop+"x:y=z"), + new ObjectName("//"+foop+sfoop+"x:y=z"),1,sfoop+sbarp+"barfoo"), + // should be transformed into this bar thing: + new MyCompositeData(new ObjectName(barp+sfoop+"x:y=z"), + new ObjectName("//"+foop+sfoop+"x:y=z"),1,sfoop+sbarp+"barfoo"), + } + }; + + // objects[i][0] is expected to be transformed into objects[i][1] + // + final Object[][] objects = new Object[][] { + {new Long(1), new Long(1)}, + { + new ObjectName(foop+sbarp+"x:y=z"), + new ObjectName(barp+sbarp+"x:y=z") + }, + { + new ObjectName(foop+sfoop+"x:y=z"), + new ObjectName(barp+sfoop+"x:y=z") + }, + { + new ObjectName("//"+foop+sbarp+"x:y=z"), + new ObjectName("//"+foop+sbarp+"x:y=z"), + }, + { + new ObjectName("//"+foop+sfoop+"x:y=z"), + new ObjectName("//"+foop+sfoop+"x:y=z") + }, + { + foop+sbarp+"x:y=z",foop+sbarp+"x:y=z" + }, + { + foop+sfoop+"x:y=z",foop+sfoop+"x:y=z" + }, + { + barp+sbarp+"x:y=z",barp+sbarp+"x:y=z" + }, + { + barp+sfoop+"x:y=z",barp+sfoop+"x:y=z" + }, + { + new BandicootNotification("test",new ObjectName(foop+sfoop+"x:y=z"),1L), + new BandicootNotification("test",new ObjectName(barp+sfoop+"x:y=z"),1L), + }, + { + new BandicootNotification("test",new ObjectName("//"+foop+sfoop+"x:y=z"),2L), + new BandicootNotification("test",new ObjectName("//"+foop+sfoop+"x:y=z"),2L), + }, + { + new BandicootAttributeChangeNotification( + new ObjectName(foop+sfoop+"x:y=z"),1L,2L,"blah","attrname", + ObjectName.class.getName(), + new ObjectName(foop+sfoop+"x:y=old"), + new ObjectName(foop+sfoop+"x:y=new")), + new BandicootAttributeChangeNotification( + new ObjectName(barp+sfoop+"x:y=z"),1L,2L,"blah","attrname", + ObjectName.class.getName(), + new ObjectName(barp+sfoop+"x:y=old"), + new ObjectName(barp+sfoop+"x:y=new")), + }, + { + new BandicootAttributeChangeNotification( + new ObjectName("//"+foop+sfoop+"x:y=z"),1L,2L,"blah","attrname", + ObjectName.class.getName(), + new ObjectName("//"+foop+sfoop+"x:y=old"), + new ObjectName(foop+sfoop+"x:y=new")), + new BandicootAttributeChangeNotification( + new ObjectName("//"+foop+sfoop+"x:y=z"),1L,2L,"blah","attrname", + ObjectName.class.getName(), + new ObjectName("//"+foop+sfoop+"x:y=old"), + new ObjectName(barp+sfoop+"x:y=new")), + } + }; + + // List that will merge datas & objects & datas converted to open + // types... + // + final List list = new ArrayList(); + + // Add all objects... + // + list.addAll(Arrays.asList(objects)); + + // Build Map with datas[i][0] (cfoo) + // + for (int i=0;i to TabularData + // (foo things) + final Object cfoo = treats.getAttribute("All"); + final AttributeList afoo = treats.getAttributes(new String[] {"All"}); + + // Build Map with datas[i][1] (cbar) + // + for (int i=0;i to TabularData + // (bar things) + final Object cbar = treats.getAttribute("All"); + final AttributeList abar = treats.getAttributes(new String[] {"All"}); + + // Add all datas to list + for (int i=0;i unmapped = new HashSet(); + final static Set mapped = new HashSet(); + + /** + * For each method define in one of the interfaces intf, tries + * to find a corresponding method in the reference class ref, where + * the method in ref has the same name, and takes an additional + * ObjectName as first parameter. + * + * So for instance, if ref is MBeanServer and intf is {DynamicMBean} + * the result map is: + * DynamicMBean.getAttribute -> MBeanServer.getAttribute + * DynamicMBean.setAttribute -> MBeanServer.setAttribute + * etc... + * If a method was mapped, it is additionally added to 'mapped' + * If a method couldn't be mapped, it is added to 'unmmapped'. + * In our example above, DynamicMBean.getNotificationInfo will end + * up in 'unmapped'. + * + * @param ref The reference class - to which calls will be forwarded + * with an additional ObjectName parameter inserted. + * @param intf The proxy interface classes - for which we must find an + * equivalent in 'ref' + * @return A map mapping the methods from intfs to the method of ref. + */ + static Map makeMapFor(Class ref, Class... intf) { + final Map map = new HashMap(); + for (Class clazz : intf) { + for (Method m : clazz.getMethods()) { + try { + final Method m2 = + ref.getMethod(m.getName(), + concat(ObjectName.class,m.getParameterTypes())); + map.put(m,m2); + mapped.add(m); + } catch (Exception x) { + unmapped.add(m); + } + } + } + return map; + } + + /** + * Tries to map all methods from DynamicMBean.class and + * NotificationEmitter.class to their equivalent in MBeanServer. + * This should be all the methods except + * DynamicMBean.getNotificationInfo. + */ + static final Map mbeanmap = + makeMapFor(MBeanServer.class,DynamicMBean.class, + NotificationEmitter.class); + /** + * Tries to map all methods from DynamicMBean.class and + * NotificationEmitter.class to an equivalent in DynamicWrapper. + * This time only DynamicMBean.getNotificationInfo will be mapped. + */ + static final Map selfmap = + makeMapFor(DynamicWrapper.class,DynamicMBean.class, + NotificationEmitter.class); + + /** + * Now check that we have mapped all methods. + */ + static { + unmapped.removeAll(mapped); + if (unmapped.size() > 0) + throw new ExceptionInInitializerError("Couldn't map "+ unmapped); + } + + /** + * The wrapped MBeanServer to which everything is delegated. + */ + private final MBeanServer server; + + /** + * The name of the MBean we're proxying. + */ + private final ObjectName name; + DynamicWrapper(MBeanServer server, ObjectName name) { + this.server=server; + this.name=name; + } + + /** + * Creates a new proxy for the given MBean. Implements + * NotificationEmitter/NotificationBroadcaster if the proxied + * MBean also does. + * @param name the name of the proxied MBean + * @param server the wrapped server + * @return a DynamicMBean proxy + * @throws javax.management.InstanceNotFoundException + */ + public static DynamicMBean newProxy(ObjectName name, MBeanServer server) + throws InstanceNotFoundException { + if (server.isInstanceOf(name, + NotificationEmitter.class.getName())) { + // implements NotificationEmitter + return (DynamicMBean) + Proxy.newProxyInstance( + DynamicWrapper.class.getClassLoader(), + new Class[] {NotificationEmitter.class, + DynamicMBean.class}, + new DynamicWrapper(server, name)); + } + if (server.isInstanceOf(name, + NotificationBroadcaster.class.getName())) { + // implements NotificationBroadcaster + return (DynamicMBean) + Proxy.newProxyInstance( + DynamicWrapper.class.getClassLoader(), + new Class[] {NotificationBroadcaster.class, + DynamicMBean.class}, + new DynamicWrapper(server, name)); + } + // Only implements DynamicMBean. + return (DynamicMBean) + Proxy.newProxyInstance( + DynamicWrapper.class.getClassLoader(), + new Class[] {DynamicMBean.class}, + new DynamicWrapper(server, name)); + } + + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + // Look for a method on this class (takes precedence) + final Method self = selfmap.get(method); + if (self != null) + return call(this,self,concat(name,args)); + + // no method found on this class, look for the same method + // on the wrapped MBeanServer + final Method mbean = mbeanmap.get(method); + if (mbean != null) + return call(server,mbean,concat(name,args)); + + // This isn't a method that can be forwarded to MBeanServer. + // If it's a method from Object, call it on this. + if (method.getDeclaringClass().equals(Object.class)) + return call(this,method,args); + throw new NoSuchMethodException(method.getName()); + } + + // Call a method using reflection, unwraps invocation target exceptions + public Object call(Object handle, Method m, Object[] args) + throws Throwable { + try { + return m.invoke(handle, args); + } catch (InvocationTargetException x) { + throw x.getCause(); + } + } + + // this method is called when DynamicMBean.getNotificationInfo() is + // called. This is the method that should be mapped in + // 'selfmap' + public MBeanNotificationInfo[] getNotificationInfo(ObjectName name) + throws JMException { + return server.getMBeanInfo(name).getNotifications(); + } + } + + /** + * Just so that we can call the same test twice but with two + * different implementations of VirtualMBeanServerSupport. + */ + public static interface MBeanServerWrapperFactory { + public MBeanServer wrapMBeanServer(MBeanServer wrapped); + } + + /** + * A VirtualMBeanServerSupport that wrapps an MBeanServer and does not + * use VirtualEventManager. + */ + public static class VirtualMBeanServerTest + extends MBeanServerSupport { + + final MBeanServer wrapped; + + public VirtualMBeanServerTest(MBeanServer wrapped) { + this.wrapped=wrapped; + } + + @Override + public DynamicMBean getDynamicMBeanFor(final ObjectName name) + throws InstanceNotFoundException { + if (wrapped.isRegistered(name)) + return DynamicWrapper.newProxy(name,wrapped); + throw new InstanceNotFoundException(String.valueOf(name)); + } + + @Override + protected Set getNames() { + return wrapped.queryNames(null, null); + } + + public final static MBeanServerWrapperFactory factory = + new MBeanServerWrapperFactory() { + + public MBeanServer wrapMBeanServer(MBeanServer wrapped) { + return new VirtualMBeanServerTest(wrapped); + } + @Override + public String toString() { + return VirtualMBeanServerTest.class.getName(); + } + }; + } + + /** + * A VirtualMBeanServerSupport that wrapps an MBeanServer and + * uses a VirtualEventManager. + */ + public static class VirtualMBeanServerTest2 + extends VirtualMBeanServerTest { + + final EventSubscriber sub; + final NotificationListener nl; + final VirtualEventManager mgr; + + /** + * We use an EventSubscriber to subscribe for all notifications from + * the wrapped MBeanServer, and publish them through a + * VirtualEventManager. Not a very efficient way of doing things. + * @param wrapped + */ + public VirtualMBeanServerTest2(MBeanServer wrapped) { + super(wrapped); + this.sub = EventSubscriber.getEventSubscriber(wrapped); + this.mgr = new VirtualEventManager(); + this.nl = new NotificationListener() { + public void handleNotification(Notification notification, Object handback) { + mgr.publish((ObjectName)notification.getSource(), notification); + } + }; + try { + sub.subscribe(ObjectName.WILDCARD, nl, null, null); + } catch (RuntimeException x) { + throw x; + } catch (Exception x) { + throw new IllegalStateException("can't subscribe for notifications!"); + } + } + + @Override + public NotificationEmitter + getNotificationEmitterFor(ObjectName name) + throws InstanceNotFoundException { + final DynamicMBean mbean = getDynamicMBeanFor(name); + if (mbean instanceof NotificationEmitter) + return mgr.getNotificationEmitterFor(name); + return null; + } + + public final static MBeanServerWrapperFactory factory = + new MBeanServerWrapperFactory() { + + public MBeanServer wrapMBeanServer(MBeanServer wrapped) { + return new VirtualMBeanServerTest2(wrapped); + } + @Override + public String toString() { + return VirtualMBeanServerTest2.class.getName(); + } + }; + } + + + public static void test(MBeanServerWrapperFactory factory) throws Exception { + final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + + // names[] are NotificationEmitters + final ObjectName[] emitters = new ObjectName[2]; + // shields[] have been shielded by wrapping them in a StandardMBean, + // so although the resource is an MBean that implements + // NotificationEmitter, the registered MBean (the wrapper) doesn't. + final ObjectName[] shielded = new ObjectName[2]; + + final List registered = new ArrayList(4); + + try { + // register two MBeans before wrapping + server.registerMBean(new Wombat(), + emitters[0] = new ObjectName("bush:type=Wombat,name=wom")); + registered.add(emitters[0]); + + // we shield the second MBean in a StandardMBean so that it does + // not appear as a NotificationEmitter. + server.registerMBean( + new StandardMBean(new Wombat(), WombatMBean.class), + shielded[0] = new ObjectName("bush:type=Wombat,name=womshield")); + registered.add(shielded[0]); + + final MBeanServer vserver = factory.wrapMBeanServer(server); + + // register two other MBeans after wrapping + server.registerMBean(new Wombat(), + emitters[1] = new ObjectName("bush:type=Wombat,name=bat")); + registered.add(emitters[1]); + + // we shield the second MBean in a StandardMBean so that it does + // not appear as a NotificationEmitter. + server.registerMBean( + new StandardMBean(new Wombat(), WombatMBean.class), + shielded[1] = new ObjectName("bush:type=Wombat,name=batshield")); + registered.add(shielded[1]); + + // Call test with this config - we have two wombats who broadcast + // notifs (emitters) and two wombats who don't (shielded). + test(vserver, emitters, shielded); + + System.out.println("*** Test passed for: " + factory); + } finally { + // Clean up the platform mbean server for the next test... + for (ObjectName n : registered) { + try { + server.unregisterMBean(n); + } catch (Exception x) { + x.printStackTrace(); + } + } + } + } + + /** + * Perform the actual test. + * @param vserver A virtual MBeanServerSupport implementation + * @param emitters Names of NotificationBroadcaster MBeans + * @param shielded Names of non NotificationBroadcaster MBeans + * @throws java.lang.Exception + */ + public static void test(MBeanServer vserver, ObjectName[] emitters, + ObjectName[] shielded) throws Exception { + + // To catch exception in NotificationListener + final List fail = new CopyOnWriteArrayList(); + + // A queue of received notifications + final BlockingQueue notifs = + new ArrayBlockingQueue(50); + + // A notification listener that puts the notification it receives + // in the queue. + final NotificationListener handler = new NotificationListener() { + + public void handleNotification(Notification notification, + Object handback) { + try { + notifs.put(notification); + } catch (Exception x) { + fail.add(x); + } + } + }; + + // A list of attribute names for which we might receive an + // exception. If an exception is received when getting these + // attributes - the test will not fail. + final List exceptions = Arrays.asList( new String[] { + "UsageThresholdCount","UsageThreshold","UsageThresholdExceeded", + "CollectionUsageThresholdCount","CollectionUsageThreshold", + "CollectionUsageThresholdExceeded" + }); + + // This is just a sanity check. Get all attributes of all MBeans. + for (ObjectName n : vserver.queryNames(null, null)) { + final MBeanInfo m = vserver.getMBeanInfo(n); + for (MBeanAttributeInfo mba : m.getAttributes()) { + // System.out.println(n+":"); + Object val; + try { + val = vserver.getAttribute(n, mba.getName()); + } catch (Exception x) { + // only accept exception for those attributes that + // have a valid reason to fail... + if (exceptions.contains(mba.getName())) val = x; + else throw new Exception("Failed to get " + + mba.getName() + " from " + n,x); + } + // System.out.println("\t "+mba.getName()+": "+ val); + } + } + + // The actual tests. Register for notifications with notif emitters + for (ObjectName n : emitters) { + vserver.addNotificationListener(n, handler, null, n); + } + + // Trigger the emission of notifications, check that we received them. + for (ObjectName n : emitters) { + vserver.setAttribute(n, + new Attribute("Caption","I am a new wombat!")); + final Notification notif = notifs.poll(4, TimeUnit.SECONDS); + if (!notif.getSource().equals(n)) + throw new Exception("Bad source for "+ notif); + if (fail.size() > 0) + throw new Exception("Failed to handle notif",fail.remove(0)); + } + + // Check that we didn't get more notifs than expected + if (notifs.size() > 0) + throw new Exception("Extra notifications in queue: "+notifs); + + // Check that if the MBean doesn't exist, we get InstanceNotFound. + try { + vserver.addNotificationListener(new ObjectName("toto:toto=toto"), + handler, null, null); + throw new Exception("toto:toto=toto doesn't throw INFE"); + } catch (InstanceNotFoundException x) { + System.out.println("Received "+x+" as expected."); + } + + // For those MBeans that shouldn't be NotificationEmitters, check that + // we get IllegalArgumentException + for (ObjectName n : shielded) { + try { + vserver.addNotificationListener(n, handler, null, n); + } catch (RuntimeOperationsException x) { + System.out.println("Received "+x+" as expected."); + System.out.println("Cause is: "+x.getCause()); + if (!(x.getCause() instanceof IllegalArgumentException)) + throw new Exception("was expecting IllegalArgumentException cause. Got "+x.getCause(),x); + } + } + + // Sanity check. Remove our listeners. + for (ObjectName n : emitters) { + vserver.removeNotificationListener(n, handler, null, n); + } + + // That's it. + // Sanity check: we shouldn't have received any new notif. + if (notifs.size() > 0) + throw new Exception("Extra notifications in queue: "+notifs); + // The NotifListener shouldn't have logged any new exception. + if (fail.size() > 0) + throw new Exception("Failed to handle notif",fail.remove(0)); + } + + public static void main(String[] args) throws Exception { + // test with a regular MBeanServer (no VirtualMBeanServerSupport) + final MBeanServerWrapperFactory identity = + new MBeanServerWrapperFactory() { + public MBeanServer wrapMBeanServer(MBeanServer wrapped) { + return wrapped; + } + }; + test(identity); + // test with no EventManager + test(VirtualMBeanServerTest.factory); + // test with VirtualEventManager + test(VirtualMBeanServerTest2.factory); + } +} diff --git a/test/javax/management/namespace/VirtualMBeanTest.java b/test/javax/management/namespace/VirtualMBeanTest.java new file mode 100644 index 0000000000000000000000000000000000000000..03fd3983e63b468324bb0c28e13740cb91712fdc --- /dev/null +++ b/test/javax/management/namespace/VirtualMBeanTest.java @@ -0,0 +1,409 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test VirtualMBeanTest.java + * @bug 5108776 5072476 + * @summary Test that Virtual MBeans can be implemented and emit notifs. + * @author Eamonn McManus + */ + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import javax.management.DynamicMBean; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanInfo; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.MalformedObjectNameException; +import javax.management.Notification; +import javax.management.NotificationBroadcaster; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.RuntimeOperationsException; +import javax.management.SendNotification; +import javax.management.StandardEmitterMBean; +import javax.management.StandardMBean; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.VirtualEventManager; +import javax.management.namespace.MBeanServerSupport; +import javax.management.timer.TimerMBean; + +// In this test, we check that the two main use case types for +// MBeanServerSupport work correctly: +// (1) as a special-purpose implementation of MBeanServer for a fixed number +// of MBeans (e.g. for QueryNotificationFilter) +// (2) as an MBeanServer supporting Virtual MBeans. +// In each case we are particularly interested in the notification behaviour. +// We check that the behaviour is correct when calling addNotificationListener +// (a) for an MBean that does not exist; (b) for an MBean that does exist but +// is not a NotificationEmitter; and (c) for an MBean that exists and is +// a NotificationEmitter. We also check the degenerate and usual case +// where the MBeanServerSupport subclass does not support notifications +// at all. +// +// Each subclass will have an MBean called test:type=NotEmitter that +// does not support addNotificationListener. If it also has MBeans called +// test:type=Emitter,* then they are expected to support addNL. No subclass +// will have any other MBeans, so in particular no subclass will have +// test:type=Nonexistent. +// +public class VirtualMBeanTest { + static final ObjectName + nonExistentName, notEmitterName, emitterName1, emitterName2; + static { + try { + nonExistentName = new ObjectName("test:type=NonExistent"); + notEmitterName = new ObjectName("test:type=NotEmitter"); + emitterName1 = new ObjectName("test:type=Emitter,id=1"); + emitterName2 = new ObjectName("test:type=Emitter,id=2"); + } catch (MalformedObjectNameException e) { + throw new AssertionError(e); + } + } + + static final StandardMBean.Options wrappedVisible = new StandardMBean.Options(); + static { + wrappedVisible.setWrappedObjectVisible(true); + } + + public static interface NothingMBean {} + public static class Nothing implements NothingMBean {} + public static class NothingNBS extends NotificationBroadcasterSupport + implements NothingMBean {} + + // Class that has hardwired MBeans test:type=NotEmitter, + // test:type=Broadcaster, and test:type=Emitter. + private static class HardwiredMBS extends MBeanServerSupport + implements SendNotification { + private final DynamicMBean notEmitter = + new StandardMBean(new Nothing(), NothingMBean.class, wrappedVisible); + private final StandardEmitterMBean emitter1, emitter2; + { + NothingNBS nnbs1 = new NothingNBS(); + emitter1 = new StandardEmitterMBean( + nnbs1, NothingMBean.class, wrappedVisible, nnbs1); + NothingNBS nnbs2 = new NothingNBS(); + emitter2 = new StandardEmitterMBean( + nnbs2, NothingMBean.class, wrappedVisible, nnbs2); + } + + private final Map map = + new TreeMap(); + { + map.put(notEmitterName, notEmitter); + map.put(emitterName1, emitter1); + map.put(emitterName2, emitter2); + } + + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + DynamicMBean mbean = map.get(name); + if (mbean != null) + return mbean; + else + throw new InstanceNotFoundException(name); + } + + @Override + protected Set getNames() { + return map.keySet(); + } + + @Override + public String toString() { + return "Hardwired MBeanServerSupport"; + } + + public void sendNotification(Notification notification) { + emitter1.sendNotification(notification); + emitter2.sendNotification(notification); + } + } + + // Class that has the notEmitter MBean but not either of the others, so does + // not support listeners. + private static class VirtualMBSWithoutListeners + extends MBeanServerSupport { + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + if (name.equals(notEmitterName)) { + return new StandardMBean( + new Nothing(), NothingMBean.class, wrappedVisible); + } else + throw new InstanceNotFoundException(name); + } + + @Override + protected Set getNames() { + return Collections.singleton(notEmitterName); + } + + @Override + public String toString() { + return "Virtual MBeanServerSupport without listener support"; + } + } + + // Class that has the notEmitter and emitter MBeans as Virtual MBeans, using + // VirtualEventManager to handle listeners for the emitter MBean. We + // implement the broadcaster MBean (which is a NotificationBroadcaster but + // not a NotificationEmitter) even though it's very hard to imagine a real + // use case where that would happen. + private static class VirtualMBSWithListeners + extends MBeanServerSupport implements SendNotification { + private final VirtualEventManager vem = new VirtualEventManager(); + + private static final List names = + Arrays.asList(notEmitterName, emitterName1, emitterName2); + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + if (names.contains(name)) { + return new StandardMBean( + new Nothing(), NothingMBean.class, wrappedVisible); + } else + throw new InstanceNotFoundException(name); + } + + @Override + public NotificationEmitter getNotificationEmitterFor( + ObjectName name) throws InstanceNotFoundException { + if (name.equals(emitterName1) || name.equals(emitterName2)) + return vem.getNotificationEmitterFor(name); + else if (name.equals(notEmitterName)) + return null; + else + throw new InstanceNotFoundException(name); + } + + @Override + protected Set getNames() { + return new TreeSet(Arrays.asList(notEmitterName, emitterName2)); + } + + @Override + public String toString() { + return "Virtual MBeanServerSupport with listener support"; + } + + public void sendNotification(Notification notification) { + vem.publish(emitterName1, notification); + vem.publish(emitterName2, notification); + } + } + + private static final MBeanServer[] vmbsss = { + new HardwiredMBS(), + new VirtualMBSWithoutListeners(), + new VirtualMBSWithListeners(), + }; + + public static void main(String[] args) throws Exception { + Exception lastEx = null; + for (MBeanServer vmbs : vmbsss) { + String testName = "\"" + vmbs + "\""; + System.out.println("===Test " + testName + "==="); + try { + test(vmbs); + } catch (Exception e) { + System.out.println( + "===Test " + testName + " failed with exception " + e); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + pw.flush(); + String es = sw.toString(); + System.out.println("......" + es.replace("\n", "\n......")); + lastEx = e; + } + } + if (lastEx != null) + throw lastEx; + System.out.println("TEST PASSED"); + } + + private static class NothingListener implements NotificationListener { + public void handleNotification(Notification notification, + Object handback) { + throw new UnsupportedOperationException("Not supported yet."); + } + } + + private static class QueueListener implements NotificationListener { + final BlockingQueue queue = + new ArrayBlockingQueue(10); + + public void handleNotification(Notification notification, + Object handback) { + queue.add(notification); + } + } + + private static void test(MBeanServer vmbs) throws Exception { + MBeanServer mmbs = MBeanServerFactory.newMBeanServer(); + ObjectName namespaceName = new ObjectName("test//:type=JMXNamespace"); + JMXNamespace namespace = new JMXNamespace(vmbs); + mmbs.registerMBean(namespace, namespaceName); + MBeanServer mbs = JMXNamespaces.narrowToNamespace(mmbs, "test"); + + Set names = mbs.queryNames(null, null); + //names.remove(new ObjectName(":type=JMXNamespace")); + + // Make sure that notEmitterName exists according to query... + System.out.println("Checking query"); + if (!names.contains(notEmitterName)) + throw new Exception("Bad query result: " + names); + + // ...and according to getMBeanInfo + System.out.println("Checking getMBeanInfo(" + notEmitterName + ")"); + MBeanInfo mbi = mbs.getMBeanInfo(notEmitterName); + if (mbi.getNotifications().length > 0) + throw new Exception("notEmitter has NotificationInfo"); + + // Make sure we get the right exception for getMBeanInfo on a + // non-existent MBean + System.out.println("Checking getMBeanInfo on a non-existent MBean"); + try { + mbi = mbs.getMBeanInfo(nonExistentName); + throw new Exception("getMBI succeeded but should not have"); + } catch (InstanceNotFoundException e) { + } + + // Make sure we get the right exception for addNotificationListener on a + // non-existent MBean + System.out.println( + "Checking addNotificationListener on a non-existent MBean"); + try { + mbs.addNotificationListener( + nonExistentName, new NothingListener(), null, null); + throw new Exception("addNL succeeded but should not have"); + } catch (InstanceNotFoundException e) { + } + + // Make sure we get the right exception for isInstanceOf on a + // non-existent MBean + System.out.println( + "Checking isInstanceOf on a non-existent MBean"); + for (Class c : new Class[] { + Object.class, NotificationBroadcaster.class, NotificationEmitter.class, + }) { + try { + boolean is = mbs.isInstanceOf(nonExistentName, c.getName()); + throw new Exception( + "isInstanceOf " + c.getName() + + " succeeded but should not have"); + } catch (InstanceNotFoundException e) { + } + } + + // Make sure isInstanceOf works correctly for classes without special + // treatment + System.out.println( + "Checking isInstanceOf on normal classes"); + for (ObjectName name : names) { + boolean isNothing = mbs.isInstanceOf(name, NothingMBean.class.getName()); + if (!isNothing) { + throw new Exception("isInstanceOf " + NothingMBean.class.getName() + + " returned false, should be true"); + } + boolean isTimer = mbs.isInstanceOf(name, TimerMBean.class.getName()); + if (isTimer) { + throw new Exception("isInstanceOf " + TimerMBean.class.getName() + + " returned true, should be false"); + } + } + + // Make sure that addNL on notEmitterName gets the right exception + System.out.println("Checking addNL on non-broadcaster"); + try { + mbs.addNotificationListener( + notEmitterName, new NothingListener(), null, null); + throw new Exception("addNL succeeded but should not have"); + } catch (RuntimeOperationsException e) { + if (!(e.getCause() instanceof IllegalArgumentException)) + throw new Exception("Wrong exception from addNL", e); + } + + if (!(vmbs instanceof SendNotification)) { + System.out.println("Not testing notifications for this implementation"); + return; + } + + QueueListener qListener = new QueueListener(); + + System.out.println("Testing addNL on emitters"); + mbs.addNotificationListener(emitterName1, qListener, null, null); + mbs.addNotificationListener(emitterName2, qListener, null, null); + + System.out.println("Testing that listeners work"); + Notification notif = new Notification("notif.type", "source", 0L); + + ((SendNotification) vmbs).sendNotification(notif); + testListeners(qListener, "notif.type", 2); + + System.out.println("Testing 2-arg removeNL on emitter1"); + mbs.removeNotificationListener(emitterName1, qListener); + + ((SendNotification) vmbs).sendNotification(notif); + testListeners(qListener, "notif.type", 1); + + System.out.println("Testing 4-arg removeNL on emitter2"); + mbs.removeNotificationListener(emitterName2, qListener, null, null); + + ((SendNotification) vmbs).sendNotification(notif); + testListeners(qListener, "notif.type", 0); + } + + private static void testListeners( + QueueListener qListener, String expectedNotifType, int expectedNotifs) + throws Exception { + for (int i = 1; i <= expectedNotifs; i++) { + Notification rNotif = qListener.queue.poll(1, TimeUnit.SECONDS); + if (rNotif == null) + throw new Exception("Notification " + i + " never arrived"); + if (!rNotif.getType().equals(expectedNotifType)) + throw new Exception("Wrong type notif: " + rNotif.getType()); + } + Notification xNotif = qListener.queue.poll(10, TimeUnit.MILLISECONDS); + if (xNotif != null) + throw new Exception("Extra notif: " + xNotif); + } +} diff --git a/test/javax/management/namespace/VirtualNamespaceQueryTest.java b/test/javax/management/namespace/VirtualNamespaceQueryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8af244a7bc2db73212d19e6eed4773af77aeb97a --- /dev/null +++ b/test/javax/management/namespace/VirtualNamespaceQueryTest.java @@ -0,0 +1,128 @@ +/* + * 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. + * + * 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. + */ + +/* + * + * @test VirtualNamespaceQueryTest.java + * @summary General VirtualNamespaceQueryTest test. + * @author Daniel Fuchs + * @bug 5072476 + * @run clean VirtualNamespaceQueryTest Wombat WombatMBean + * NamespaceController NamespaceControllerMBean + * JMXRemoteTargetNamespace + * @compile -XDignore.symbol.file=true VirtualNamespaceQueryTest.java + * Wombat.java WombatMBean.java + * NamespaceController.java NamespaceControllerMBean.java + * JMXRemoteTargetNamespace.java + * @run main VirtualNamespaceQueryTest + */ + +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import javax.management.DynamicMBean; +import javax.management.InstanceNotFoundException; +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.NotificationEmitter; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.StandardMBean; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.MBeanServerSupport; + +/** + * + * @author dfuchs + */ +public class VirtualNamespaceQueryTest { + public static class WombatRepository extends MBeanServerSupport { + final Wombat wombat; + final StandardMBean mbean; + final ObjectName wombatName; + + public WombatRepository(ObjectName wombatName) { + try { + wombat = new Wombat(); + mbean = wombat; + this.wombatName = wombatName; + wombat.preRegister(null,wombatName); + } catch (Exception x) { + throw new IllegalArgumentException(x); + } + } + + @Override + public DynamicMBean getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + if (wombatName.equals(name)) return mbean; + else throw new InstanceNotFoundException(String.valueOf(name)); + } + + @Override + protected Set getNames() { + final Set res = Collections.singleton(wombatName); + return res; + } + + @Override + public NotificationEmitter getNotificationEmitterFor( + ObjectName name) throws InstanceNotFoundException { + DynamicMBean mb = getDynamicMBeanFor(name); + if (mb instanceof NotificationEmitter) + return (NotificationEmitter)mb; + return null; + } + } + public static class WombatNamespace extends JMXNamespace { + public WombatNamespace(ObjectName wombatName) { + super(new WombatRepository(wombatName)); + } + } + + public static void simpleTest() throws Exception { + final MBeanServer server = MBeanServerFactory.newMBeanServer(); + final ObjectName wombatName = new ObjectName("burrow:type=Wombat"); + final JMXNamespace ns = new WombatNamespace(wombatName); + server.registerMBean(ns, JMXNamespaces.getNamespaceObjectName("wombats")); + final Set dirs = + server.queryNames(new ObjectName("wombats//*//:type=JMXNamespace"), + wombatName); + System.out.println("all dirs: "+dirs); + if (dirs.size()>0) + throw new RuntimeException("Unexpected ObjectNames returned: "+dirs); + + final ObjectInstance inst = NamespaceController.createInstance(server); + final NamespaceControllerMBean controller = + JMX.newMBeanProxy(server, inst.getObjectName(), + NamespaceControllerMBean.class); + final String[] dirNames = controller.findNamespaces(null,null,2); + System.err.println(Arrays.toString(dirNames)); + } + + public static void main(String[] args) throws Exception { + simpleTest(); + } +} diff --git a/test/javax/management/namespace/VirtualPropsTest.java b/test/javax/management/namespace/VirtualPropsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..904cc5359d7f08fedf03364b0057959b810f8fb0 --- /dev/null +++ b/test/javax/management/namespace/VirtualPropsTest.java @@ -0,0 +1,179 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 5108776 5072476 + * @summary Test the properties use case for Virtual MBeans that is documented + * in MBeanServerSupport. + * @author Eamonn McManus + */ + +import java.lang.management.ManagementFactory; +import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import javax.management.DynamicMBean; +import javax.management.InstanceNotFoundException; +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.StandardMBean; +import javax.management.namespace.JMXNamespace; +import javax.management.namespace.JMXNamespaces; +import javax.management.namespace.VirtualEventManager; +import javax.management.namespace.MBeanServerSupport; + +public class VirtualPropsTest { + public static interface PropertyMBean { + public String getValue(); + } + + public static 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 getDynamicMBeanFor(ObjectName name) + throws InstanceNotFoundException { + ObjectName namePattern = newObjectName( + "com.example:type=Property,name=\"*\""); + if (!namePattern.apply(name)) + throw new InstanceNotFoundException(name); + + String propName = ObjectName.unquote(name.getKeyProperty("name")); + if (System.getProperty(propName) == null) + throw new InstanceNotFoundException(name); + PropertyMBean propMBean = new PropertyImpl(propName); + return new StandardMBean(propMBean, PropertyMBean.class, false); + } + + @Override + protected Set getNames() { + 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; + } + + private final VirtualEventManager vem = new VirtualEventManager(); + + @Override + public NotificationEmitter getNotificationEmitterFor( + ObjectName name) throws InstanceNotFoundException { + getDynamicMBeanFor(name); // check that the name is valid + return vem.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.publish(objectName, n); + } + } + + static class QueueListener implements NotificationListener { + BlockingQueue q = new ArrayBlockingQueue(10); + public void handleNotification(Notification notification, + Object handback) { + q.add(notification); + } + } + + public static void main(String[] args) throws Exception { + MBeanServer mmbs = ManagementFactory.getPlatformMBeanServer(); + String namespace = "props"; + PropsMBS pmbs = new PropsMBS(); + Object namespaceMBean = new JMXNamespace(pmbs); + mmbs.registerMBean(namespaceMBean, new ObjectName( + namespace + "//:type=JMXNamespace")); + MBeanServer mbs = JMXNamespaces.narrowToNamespace(mmbs, namespace); + + Properties props = System.getProperties(); + + int nprops = props.stringPropertyNames().size(); + if (nprops != mbs.getMBeanCount()) { + throw new Exception(String.format("Properties: %d; MBeans: %d", + nprops, mbs.getMBeanCount())); + } + + for (String propName : props.stringPropertyNames()) { + ObjectName propObjectName = new ObjectName( + "com.example:type=Property,name=" + ObjectName.quote(propName)); + PropertyMBean propProx = JMX.newMBeanProxy( + mbs, propObjectName, PropertyMBean.class); + String propValue = propProx.getValue(); + String realPropValue = props.getProperty(propName); + if (!realPropValue.equals(propValue)) { + throw new Exception(String.format("Property %s: value is \"%s\"; " + + "mbean says \"%s\"", propName, realPropValue, propValue)); + } + } + + ObjectName fooPropObjectName = + new ObjectName("com.example:type=Property,name=\"java.home\""); + QueueListener ql = new QueueListener(); + mbs.addNotificationListener(fooPropObjectName, ql, null, null); + pmbs.propertyChanged("java.home", "bar"); + Notification n = ql.q.poll(1, TimeUnit.SECONDS); + if (n == null) + throw new Exception("Notif didn't arrive"); + if (!"bar".equals(n.getUserData())) + throw new Exception("Bad user data: " + n.getUserData()); + + System.out.println("TEST PASSED"); + } +} diff --git a/test/javax/management/namespace/Wombat.java b/test/javax/management/namespace/Wombat.java new file mode 100644 index 0000000000000000000000000000000000000000..bef648c0fc99a2f24f5deb099010953ee68e89e3 --- /dev/null +++ b/test/javax/management/namespace/Wombat.java @@ -0,0 +1,259 @@ +/* + * 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. + * + * 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. + */ + +import java.util.Random; +import java.util.Set; +import javax.management.AttributeChangeNotification; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.NotCompliantMBeanException; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.StandardMBean; + + +/** + * Dynamic MBean based on StandardMBean + * Class Wombat + * Wombat Description + * @author dfuchs + */ +public class Wombat extends StandardMBean + implements WombatMBean, NotificationEmitter, MBeanRegistration { + + /** + * Attribute : Caption + */ + private String caption = "I'm a wombat"; + + private final long MAX_SEED = 36000; + private final long seed; + private final long period; + private volatile int mood = 0; + + public int getMood() { + final long degree = seed + (System.currentTimeMillis()/period)%MAX_SEED; + final double angle = ((double)degree)/100; + mood = (int)(100.0*Math.sin(angle)); + return mood; + } + + public Wombat() throws NotCompliantMBeanException { + this(WombatMBean.class); + } + + public Wombat(Class clazz) + throws NotCompliantMBeanException { + super(clazz); + final Random r = new Random(); + seed = ((r.nextLong() % MAX_SEED) + MAX_SEED)%MAX_SEED; + period = 200 + (((r.nextLong()%80)+80)%80)*10; + } + + /** + * Next are the methods to compute MBeanInfo. + * You shouldn't update these methods. + */ + @Override + protected String getDescription(MBeanInfo info) { + return "Wombats are strange beasts. You will find them down under " + + "and in some computer programms."; + } + + @Override + protected String getDescription(MBeanAttributeInfo info) { + String description = null; + if (info.getName().equals("Caption")) { + description = "A simple caption to describe a wombat"; + } + if (info.getName().equals("Mood")) { + description = "This Wombat's mood on a [-100,+100] scale."+ + " -100 means that this wombat is very angry."; + } + return description; + } + + @Override + protected String getDescription(MBeanOperationInfo op, + MBeanParameterInfo param, + int sequence) { + return null; + } + + @Override + protected String getParameterName(MBeanOperationInfo op, + MBeanParameterInfo param, + int sequence) { + return null; + } + + @Override + protected String getDescription(MBeanOperationInfo info) { + String description = null; + return description; + } + + @Override + public MBeanInfo getMBeanInfo() { + MBeanInfo mbinfo = super.getMBeanInfo(); + return new MBeanInfo(mbinfo.getClassName(), + mbinfo.getDescription(), + mbinfo.getAttributes(), + mbinfo.getConstructors(), + mbinfo.getOperations(), + getNotificationInfo()); + } + + /** + * Get A simple caption to describe a wombat + */ + public synchronized String getCaption() { + return caption; + } + + /** + * Set A simple caption to describe a wombat + */ + public void setCaption(String value) { + final String oldValue; + synchronized (this) { + oldValue = caption; + caption = value; + } + final AttributeChangeNotification notif = + new AttributeChangeNotification(objectName, + getNextSeqNumber(), + System.currentTimeMillis(), + "Caption changed","Caption", + String.class.getName(),oldValue,value); + broadcaster.sendNotification(notif); + } + + /** + * MBeanNotification support + * You shouldn't update these methods + */ + public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException { + broadcaster.addNotificationListener(listener, filter, handback); + } + + public MBeanNotificationInfo[] getNotificationInfo() { + return new MBeanNotificationInfo[] { + new MBeanNotificationInfo(new String[] { + AttributeChangeNotification.ATTRIBUTE_CHANGE}, + javax.management.AttributeChangeNotification.class.getName(), + "Sent when the caption changes") + }; + } + + 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 synchronized long getNextSeqNumber() { + return seqNumber++; + } + + private long seqNumber; + + private final NotificationBroadcasterSupport broadcaster = new NotificationBroadcasterSupport(); + + /** + * Allows the MBean to perform any operations it needs before being + * registered in the MBean server. If the name of the MBean is not + * specified, the MBean can provide a name for its registration. If + * any exception is raised, the MBean will not be registered in the + * MBean server. + * @param server The MBean server in which the MBean will be registered. + * @param name The object name of the MBean. This name is null if the + * name parameter to one of the createMBean or registerMBean methods in + * the MBeanServer interface is null. In that case, this method must + * return a non-null ObjectName for the new MBean. + * @return The name under which the MBean is to be registered. This value + * must not be null. If the name parameter is not null, it will usually + * but not necessarily be the returned value. + * @throws Exception This exception will be caught by the MBean server and + * re-thrown as an MBeanRegistrationException. + */ + @Override + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + objectName = name; + mbeanServer = server; + return super.preRegister(server, name); + } + + /** + * Allows the MBean to perform any operations needed after having + * been registered in the MBean server or after the registration has + * failed. + * @param registrationDone Indicates wether or not the MBean has been + * successfully registered in the MBean server. The value false means + * that the registration has failed. + */ + @Override + public void postRegister(Boolean registrationDone) { + super.postRegister(registrationDone); + } + + /** + * Allows the MBean to perform any operations it needs before being + * unregistered by the MBean server. + * @throws Exception This exception will be caught by the MBean server and + * re-thrown as an MBeanRegistrationException. + */ + @Override + public void preDeregister() throws Exception { + super.preDeregister(); + } + + /** + * Allows the MBean to perform any operations needed after having been + * unregistered in the MBean server. + */ + @Override + public void postDeregister() { + super.postDeregister(); + } + + public Set listMatching(ObjectName pattern) { + return mbeanServer.queryNames(pattern, null); + } + + private MBeanServer mbeanServer; + + private ObjectName objectName; +} diff --git a/test/javax/management/namespace/WombatMBean.java b/test/javax/management/namespace/WombatMBean.java new file mode 100644 index 0000000000000000000000000000000000000000..73f4875317e85dc8cba42c6e4328167b50d2df70 --- /dev/null +++ b/test/javax/management/namespace/WombatMBean.java @@ -0,0 +1,59 @@ + +/* + * 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. + * + * 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. + */ + +import java.util.Set; +import javax.management.ObjectName; + +/** + * Interface WombatMBean + * Wombat Description + * @author dfuchs + */ +public interface WombatMBean +{ + /** + * This Wombat's mood on a [-100,+100] scale. + * -100 means that this wombat is very angry. + * @return The wombat's mood. + */ + public int getMood(); + + /** + * Get A simple caption to describe a wombat + */ + public String getCaption(); + + /** + * Set A simple caption to describe a wombat + */ + public void setCaption(String value); + + /** + * List matching MBeans in the same server. + * @param pattern an ObjectName pattern or null. + * @return A list of matching MBeans. + */ + public Set listMatching(ObjectName pattern); + +} diff --git a/test/javax/management/namespace/namespace.policy b/test/javax/management/namespace/namespace.policy new file mode 100644 index 0000000000000000000000000000000000000000..e77bb79c91e87e091194e37257308c4035c3703d --- /dev/null +++ b/test/javax/management/namespace/namespace.policy @@ -0,0 +1,85 @@ +grant codebase "file:/-" { + permission java.util.PropertyPermission "jmx.wait", "read"; + permission java.util.PropertyPermission "jmx.rmi.port", "read"; + permission java.net.SocketPermission "*", "accept,connect,resolve"; + permission java.security.SecurityPermission "*"; + + // Attribute Caption: allow get everywhere + // ================== + + // allow getAttribute(*:*,Caption) in all MBeanServers + permission javax.management.MBeanPermission "#Caption", "getAttribute"; + // allow getAttribute(*:*,Caption) in all namespaces recursively. + permission javax.management.namespace.JMXNamespacePermission "Caption", + "getAttribute"; + + // Attribute Mood: allow get only in MBeanServers named rmi* + // =============== + + // allow to get attribute Mood of Wombat MBeans only in namespaces + // whose name match rmi*, wherever they are. + // for this we need two permissions: + permission javax.management.namespace.JMXNamespacePermission + "*::Mood[**//rmi*//wombat:*]", + "getAttribute"; + permission javax.management.namespace.JMXNamespacePermission + "*::Mood[rmi*//wombat:*]", + "getAttribute"; + + // allow to get attribute mood in any MBeanServer whose name starts with + // rmi + permission javax.management.MBeanPermission "rmi*::#Mood", + "getAttribute"; + + // Attribute UUID: + // =============== + + // allow to get attribute "UUID" everywhere. + permission javax.management.namespace.JMXNamespacePermission + "*::UUID[*//**//:*]", + "getAttribute"; + permission javax.management.MBeanPermission + "#UUID[*//:*]", + "getAttribute"; + + + + // Let getMBeanInfo and queryNames through everywhere... + // + permission javax.management.namespace.JMXNamespacePermission "[]", + "getMBeanInfo,queryNames"; + permission javax.management.MBeanPermission "*", + "getMBeanInfo,queryNames"; + + // special permission for all wombats: + // + permission javax.management.namespace.JMXNamespacePermission + "[**//*:type=Wombat,*]", + "getObjectInstance,isInstanceOf,queryMBeans"; + permission javax.management.MBeanPermission "[*:type=Wombat,*]", + "getObjectInstance,isInstanceOf,queryMBeans"; + + // allow JMXNamespace::getDefaultDomain + permission javax.management.namespace.JMXNamespacePermission + "*::DefaultDomain", + "getAttribute"; + + // These permissions are required to connect visualvm. + // + permission javax.management.MBeanPermission "default::[java.lang:*]", + "getObjectInstance,isInstanceOf,getAttribute,getMBeanInfo,queryNames,queryMBeans"; + permission javax.management.MBeanPermission "root::", + "isInstanceOf,queryNames,queryMBeans,getAttribute,getMBeanInfo,getObjectInstance,getDomains"; + permission javax.management.namespace.JMXNamespacePermission + "[**//JMImplementation:type=MBeanServerDelegate]", + "addNotificationListener,removeNotificationListener,isInstanceOf,queryNames,queryMBeans,getAttribute,getMBeanInfo,getObjectInstance"; + permission javax.management.MBeanPermission + "javax.management.MBeanServerDelegate", + "addNotificationListener,removeNotificationListener,isInstanceOf,queryNames,queryMBeans,getAttribute,getMBeanInfo,getObjectInstance"; + + // Thread monitoring + permission java.lang.management.ManagementPermission "monitor"; + permission javax.management.MBeanPermission "*::sun.management.*#*[java.lang:*]", "invoke"; +}; + + diff --git a/test/javax/xml/crypto/dsig/GenerationTests.java b/test/javax/xml/crypto/dsig/GenerationTests.java index dea5335d29ab3b9ab047d3d8fd7537f09a8b8634..bb4aff50ba41747260e0feddda65e164a7085dc2 100644 --- a/test/javax/xml/crypto/dsig/GenerationTests.java +++ b/test/javax/xml/crypto/dsig/GenerationTests.java @@ -92,6 +92,7 @@ public class GenerationTests { private static Certificate signingCert; private static KeyStore ks; private final static String DIR = System.getProperty("test.src", "."); +// private final static String DIR = "."; private final static String DATA_DIR = DIR + System.getProperty("file.separator") + "data"; private final static String KEYSTORE = @@ -202,6 +203,9 @@ public class GenerationTests { DOMSignContext dsc = new DOMSignContext(signingKey, envelope); sig.sign(dsc); +// StringWriter sw = new StringWriter(); +// dumpDocument(doc, sw); +// System.out.println(sw.toString()); DOMValidateContext dvc = new DOMValidateContext (kvks, envelope.getFirstChild()); diff --git a/test/sun/nio/cs/CheckICNE.java b/test/sun/nio/cs/CheckICNE.java new file mode 100644 index 0000000000000000000000000000000000000000..4b3e905f1d0c7deb59805222493e5f2e36da950e --- /dev/null +++ b/test/sun/nio/cs/CheckICNE.java @@ -0,0 +1,58 @@ +/* + * 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. + * + * 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. + */ + +/* @test + @bug 4849617 + @summary Checks "+" is a legal character for charset name + */ +import java.nio.charset.*; + +public class CheckICNE { + static int failed = 0; + public static void main (String[] args) throws Exception { + try { + Charset.forName("abc+"); + } catch (UnsupportedCharsetException uce) {} + + try { + java.nio.charset.Charset.forName("+abc"); + } catch (IllegalCharsetNameException icne) {} + + String[] euros = {"PC-Multilingual-850+euro", + "ebcdic-us-037+euro", + "ebcdic-de-273+euro", + "ebcdic-no-277+euro", + "ebcdic-dk-277+euro", + "ebcdic-fi-278+euro", + "ebcdic-se-278+euro", + "ebcdic-it-280+euro", + "ebcdic-es-284+euro", + "ebcdic-gb-285+euro", + "ebcdic-fr-277+euro", + "ebcdic-international-500+euro", + "ebcdic-s-871+euro" + }; + + System.out.println("Test Passed!"); + } +} diff --git a/test/sun/nio/cs/TestUTF8.java b/test/sun/nio/cs/TestUTF8.java new file mode 100644 index 0000000000000000000000000000000000000000..967054573a0fe31e175111434d214de139eb7743 --- /dev/null +++ b/test/sun/nio/cs/TestUTF8.java @@ -0,0 +1,393 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 4486841 + * @summary Test UTF-8 charset + */ + +import java.nio.charset.*; +import java.nio.*; +import java.util.*; + +public class TestUTF8 { + static char[] decode(byte[] bb, String csn, boolean testDirect) + throws Exception { + CharsetDecoder dec = Charset.forName(csn).newDecoder(); + ByteBuffer bbf; + CharBuffer cbf; + if (testDirect) { + bbf = ByteBuffer.allocateDirect(bb.length); + cbf = ByteBuffer.allocateDirect(bb.length*2).asCharBuffer(); + bbf.put(bb).flip(); + } else { + bbf = ByteBuffer.wrap(bb); + cbf = CharBuffer.allocate(bb.length); + } + CoderResult cr = dec.decode(bbf, cbf, true); + if (cr != CoderResult.UNDERFLOW) + throw new RuntimeException("Decoding err: " + csn); + char[] cc = new char[cbf.position()]; + cbf.flip(); cbf.get(cc); + return cc; + + } + + static CoderResult decodeCR(byte[] bb, String csn, boolean testDirect) + throws Exception { + CharsetDecoder dec = Charset.forName(csn).newDecoder(); + ByteBuffer bbf; + CharBuffer cbf; + if (testDirect) { + bbf = ByteBuffer.allocateDirect(bb.length); + cbf = ByteBuffer.allocateDirect(bb.length*2).asCharBuffer(); + bbf.put(bb).flip(); + } else { + bbf = ByteBuffer.wrap(bb); + cbf = CharBuffer.allocate(bb.length); + } + return dec.decode(bbf, cbf, true); + } + + static byte[] encode(char[] cc, String csn, boolean testDirect) + throws Exception { + ByteBuffer bbf; + CharBuffer cbf; + CharsetEncoder enc = Charset.forName(csn).newEncoder(); + if (testDirect) { + bbf = ByteBuffer.allocateDirect(cc.length * 4); + cbf = ByteBuffer.allocateDirect(cc.length * 2).asCharBuffer(); + cbf.put(cc).flip(); + } else { + bbf = ByteBuffer.allocate(cc.length * 4); + cbf = CharBuffer.wrap(cc); + } + + CoderResult cr = enc.encode(cbf, bbf, true); + if (cr != CoderResult.UNDERFLOW) + throw new RuntimeException("Encoding err: " + csn); + byte[] bb = new byte[bbf.position()]; + bbf.flip(); bbf.get(bb); + return bb; + } + + static CoderResult encodeCR(char[] cc, String csn, boolean testDirect) + throws Exception { + ByteBuffer bbf; + CharBuffer cbf; + CharsetEncoder enc = Charset.forName(csn).newEncoder(); + if (testDirect) { + bbf = ByteBuffer.allocateDirect(cc.length * 4); + cbf = ByteBuffer.allocateDirect(cc.length * 2).asCharBuffer(); + cbf.put(cc).flip(); + } else { + bbf = ByteBuffer.allocate(cc.length * 4); + cbf = CharBuffer.wrap(cc); + } + return enc.encode(cbf, bbf, true); + } + + static char[] getUTFChars() { + char[] cc = new char[0x10000 - 0xe000 + 0xd800 + //bmp + (0x110000 - 0x10000) * 2]; //supp + int pos = 0; + int i = 0; + for (i = 0; i < 0xd800; i++) + cc[pos++] = (char)i; + for (i = 0xe000; i < 0x10000; i++) + cc[pos++] = (char)i; + for (i = 0x10000; i < 0x110000; i++) { + pos += Character.toChars(i, cc, pos); + } + return cc; + } + + static int to3ByteUTF8(char c, byte[] bb, int pos) { + bb[pos++] = (byte)(0xe0 | ((c >> 12))); + bb[pos++] = (byte)(0x80 | ((c >> 06) & 0x3f)); + bb[pos++] = (byte)(0x80 | ((c >> 00) & 0x3f)); + return 3; + } + + static void checkRoundtrip(String csn) throws Exception { + System.out.printf(" Check roundtrip <%s>...", csn); + char[] cc = getUTFChars(); + byte[] bb = encode(cc, csn, false); + char[] ccO = decode(bb, csn, false); + + if (!Arrays.equals(cc, ccO)) { + System.out.printf(" non-direct failed"); + } + bb = encode(cc, csn, true); + ccO = decode(bb, csn, true); + if (!Arrays.equals(cc, ccO)) { + System.out.printf(" (direct) failed"); + } + System.out.println(); + } + + static void check6ByteSurrs(String csn) throws Exception { + System.out.printf(" Check 6-byte Surrogates <%s>...%n", csn); + byte[] bb = new byte[(0x110000 - 0x10000) * 6]; + char[] cc = new char[(0x110000 - 0x10000) * 2]; + int bpos = 0; + int cpos = 0; + for (int i = 0x10000; i < 0x110000; i++) { + Character.toChars(i, cc, cpos); + bpos += to3ByteUTF8(cc[cpos], bb, bpos); + bpos += to3ByteUTF8(cc[cpos + 1], bb, bpos); + cpos += 2; + } + + char[] ccO = decode(bb, csn, false); + if (!Arrays.equals(cc, ccO)) { + System.out.printf(" decoding failed%n"); + } + ccO = decode(bb, csn, true); + if (!Arrays.equals(cc, ccO)) { + System.out.printf(" decoding(direct) failed%n"); + } + } + + static void compare(String csn1, String csn2) throws Exception { + System.out.printf(" Diff <%s> <%s>...%n", csn1, csn2); + char[] cc = getUTFChars(); + + byte[] bb1 = encode(cc, csn1, false); + byte[] bb2 = encode(cc, csn2, false); + if (!Arrays.equals(bb1, bb2)) + System.out.printf(" encoding failed%n"); + char[] cc1 = decode(bb1, csn1, false); + char[] cc2 = decode(bb1, csn2, false); + if (!Arrays.equals(cc1, cc2)) { + System.out.printf(" decoding failed%n"); + } + + bb1 = encode(cc, csn1, true); + bb2 = encode(cc, csn2, true); + if (!Arrays.equals(bb1, bb2)) + System.out.printf(" encoding (direct) failed%n"); + cc1 = decode(bb1, csn1, true); + cc2 = decode(bb1, csn2, true); + if (!Arrays.equals(cc1, cc2)) { + System.out.printf(" decoding (direct) failed%n"); + } + } + + // The first byte is the length of malformed bytes + static byte[][] malformed = { + // One-byte sequences: + {1, (byte)0xFF }, + {1, (byte)0xC0 }, + {1, (byte)0x80 }, + + {1, (byte)0xFF, (byte)0xFF}, // all ones + {1, (byte)0xA0, (byte)0x80}, // 101x first byte first nibble + + // Two-byte sequences: + {1, (byte)0xC0, (byte)0x80}, // invalid first byte + {1, (byte)0xC1, (byte)0xBF}, // invalid first byte + {1, (byte)0xC2, (byte)0x00}, // invalid second byte + {1, (byte)0xC2, (byte)0xC0}, // invalid second byte + {1, (byte)0xD0, (byte)0x00}, // invalid second byte + {1, (byte)0xD0, (byte)0xC0}, // invalid second byte + {1, (byte)0xDF, (byte)0x00}, // invalid second byte + {1, (byte)0xDF, (byte)0xC0}, // invalid second byte + + // Three-byte sequences + {1, (byte)0xE0, (byte)0x80, (byte)0x80}, // 111x first byte first nibble + {1, (byte)0xE0, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded + {1, (byte)0xE0, (byte)0x81, (byte)0xBF }, // U+007F zero-padded + {1, (byte)0xE0, (byte)0x9F, (byte)0xBF }, // U+07FF zero-padded + + {1, (byte)0xE0, (byte)0xC0, (byte)0xBF }, // invalid second byte + {2, (byte)0xE0, (byte)0xA0, (byte)0x7F }, // invalid third byte + {2, (byte)0xE0, (byte)0xA0, (byte)0xC0 }, // invalid third byte + {1, (byte)0xFF, (byte)0xFF, (byte)0xFF }, // all ones + {1, (byte)0xE0, (byte)0xC0, (byte)0x80 }, // invalid second byte + {1, (byte)0xE0, (byte)0x80, (byte)0xC0 }, // invalid first byte + + // Four-byte sequences + {1, (byte)0xF0, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded + {1, (byte)0xF0, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F zero-padded + {1, (byte)0xF0, (byte)0x80, (byte)0x9F, (byte)0xBF }, // U+007F zero-padded + {1, (byte)0xF0, (byte)0x8F, (byte)0xBF, (byte)0xBF }, // U+07FF zero-padded + + {1, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF }, // all ones + {1, (byte)0xF0, (byte)0x80, (byte)0x80, (byte)0x80}, // invalid second byte + {1, (byte)0xF0, (byte)0xC0, (byte)0x80, (byte)0x80 }, // invalid second byte + {2, (byte)0xF0, (byte)0x90, (byte)0xC0, (byte)0x80 }, // invalid third byte + {3, (byte)0xF0, (byte)0x90, (byte)0x80, (byte)0xC0 }, // invalid third byte + + {1, (byte)0xF1, (byte)0xC0, (byte)0x80, (byte)0x80 }, // invalid second byte + {2, (byte)0xF1, (byte)0x80, (byte)0xC0, (byte)0x80 }, // invalid third byte + {3, (byte)0xF1, (byte)0x80, (byte)0x80, (byte)0xC0 }, // invalid forth byte + {1, (byte)0xF4, (byte)0x90, (byte)0x80, (byte)0xC0 }, // out-range 4-byte + {1, (byte)0xF4, (byte)0xC0, (byte)0x80, (byte)0xC0 }, // out-range 4-byte + {1, (byte)0xF5, (byte)0x80, (byte)0x80, (byte)0xC0 }, // out-range 4-byte + + // Five-byte sequences + {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80}, // invalid first byte + {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded + {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F zero-padded + {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xBF }, // U+07FF zero-padded + {5, (byte)0xF8, (byte)0x80, (byte)0x8F, (byte)0xBF, (byte)0xBF }, // U+FFFF zero-padded + + {1, (byte)0xF8, (byte)0xC0, (byte)0x80, (byte)0x80, (byte)0x80}, + {2, (byte)0xF8, (byte)0x80, (byte)0xC0, (byte)0x80, (byte)0x80 }, + {3, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0xC1, (byte)0xBF }, + {4, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xC0 }, + + // Six-byte sequences + {6, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded + {6, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F zero-padded + {6, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xBF }, // U+07FF zero-padded + {6, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x8F, (byte)0xBF, (byte)0xBF }, // U+FFFF zero-padded + {1, (byte)0xF8, (byte)0xC0, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, + {2, (byte)0xF8, (byte)0x80, (byte)0xC0, (byte)0x80, (byte)0x80, (byte)0x80 }, + {3, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0xC1, (byte)0xBF, (byte)0x80 }, + {4, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xC0, (byte)0x80 }, + {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0x80, (byte)0xC0 }, + }; + + static void checkMalformed(String csn) throws Exception { + boolean failed = false; + System.out.printf(" Check malformed <%s>...%n", csn); + for (boolean direct: new boolean[] {false, true}) { + for (byte[] bins : malformed) { + int mlen = bins[0]; + byte[] bin = Arrays.copyOfRange(bins, 1, bins.length); + CoderResult cr = decodeCR(bin, csn, direct); + String ashex = ""; + for (int i = 0; i < bin.length; i++) { + if (i > 0) ashex += " "; + ashex += Integer.toBinaryString((int)bin[i] & 0xff); + } + if (!cr.isMalformed()) { + System.out.printf(" FAIL(direct=%b): [%s] not malformed.\n", direct, ashex); + failed = true; + } else if (cr.length() != mlen) { + System.out.printf(" FAIL(direct=%b): [%s] malformed[len=%d].\n", direct, ashex, cr.length()); + failed = true; + } + } + } + if (failed) + throw new RuntimeException("Check malformed failed " + csn); + } + + static boolean check(CharsetDecoder dec, byte[] utf8s, boolean direct, int[] flow) { + int inPos = flow[0]; + int inLen = flow[1]; + int outPos = flow[2]; + int outLen = flow[3]; + int expedInPos = flow[4]; + int expedOutPos = flow[5]; + CoderResult expedCR = (flow[6]==0)?CoderResult.UNDERFLOW + :CoderResult.OVERFLOW; + ByteBuffer bbf; + CharBuffer cbf; + if (direct) { + bbf = ByteBuffer.allocateDirect(inPos + utf8s.length); + cbf = ByteBuffer.allocateDirect((outPos + outLen)*2).asCharBuffer(); + } else { + bbf = ByteBuffer.allocate(inPos + utf8s.length); + cbf = CharBuffer.allocate(outPos + outLen); + } + bbf.position(inPos); + bbf.put(utf8s).flip().position(inPos).limit(inPos + inLen); + cbf.position(outPos); + dec.reset(); + CoderResult cr = dec.decode(bbf, cbf, false); + if (cr != expedCR || + bbf.position() != expedInPos || + cbf.position() != expedOutPos) { + System.out.printf("Expected(direct=%5b): [", direct); + for (int i:flow) System.out.print(" " + i); + System.out.println("] CR=" + cr + + ", inPos=" + bbf.position() + + ", outPos=" + cbf.position()); + return false; + } + return true; + } + + static void checkUnderOverflow(String csn) throws Exception { + System.out.printf(" Check under/overflow <%s>...%n", csn); + CharsetDecoder dec = Charset.forName(csn).newDecoder(); + boolean failed = false; + byte[] utf8s = new String("\u007f\u07ff\ue000\ud800\udc00").getBytes("UTF-8"); + int inlen = utf8s.length; + + for (int inoff = 0; inoff < 20; inoff++) { + for (int outoff = 0; outoff < 20; outoff++) { + int[][] Flows = { + //inpos, inLen, outPos, outLen, inPosEP, outposEP, under(0)/over(1) + {inoff, inlen, outoff, 1, inoff + 1, outoff + 1, 1}, + {inoff, inlen, outoff, 2, inoff + 3, outoff + 2, 1}, + {inoff, inlen, outoff, 3, inoff + 6, outoff + 3, 1}, + {inoff, inlen, outoff, 4, inoff + 6, outoff + 3, 1}, + {inoff, inlen, outoff, 5, inoff + 10,outoff + 5, 0}, + // underflow + {inoff, 1, outoff, 5, inoff + 1, outoff + 1, 0}, + {inoff, 2, outoff, 5, inoff + 1, outoff + 1, 0}, + {inoff, 3, outoff, 5, inoff + 3, outoff + 2, 0}, + {inoff, 4, outoff, 5, inoff + 3, outoff + 2, 0}, + {inoff, 5, outoff, 5, inoff + 3, outoff + 2, 0}, + {inoff, 6, outoff, 5, inoff + 6, outoff + 3, 0}, + {inoff, 7, outoff, 5, inoff + 6, outoff + 3, 0}, + {inoff, 8, outoff, 5, inoff + 6, outoff + 3, 0}, + {inoff, 9, outoff, 5, inoff + 6, outoff + 3, 0}, + {inoff, 10, outoff, 5, inoff + 10,outoff + 5, 0}, + // 2-byte underflow/overflow + {inoff, 2, outoff, 1, inoff + 1, outoff + 1, 0}, + {inoff, 3, outoff, 1, inoff + 1, outoff + 1, 1}, + // 3-byte underflow/overflow + {inoff, 4, outoff, 2, inoff + 3, outoff + 2, 0}, + {inoff, 5, outoff, 2, inoff + 3, outoff + 2, 0}, + {inoff, 6, outoff, 2, inoff + 3, outoff + 2, 1}, + // 4-byte underflow/overflow + {inoff, 7, outoff, 4, inoff + 6, outoff + 3, 0}, + {inoff, 8, outoff, 4, inoff + 6, outoff + 3, 0}, + {inoff, 9, outoff, 4, inoff + 6, outoff + 3, 0}, + {inoff, 10, outoff, 4, inoff + 6, outoff + 3, 1}, + }; + for (boolean direct: new boolean[] {false, true}) { + for (int[] flow: Flows) { + if (!check(dec, utf8s, direct, flow)) + failed = true; + } + }}} + if (failed) + throw new RuntimeException("Check under/overflow failed " + csn); + } + + public static void main(String[] args) throws Exception { + checkRoundtrip("UTF-8"); + check6ByteSurrs("UTF-8"); + //compare("UTF-8", "UTF-8-OLD"); + checkMalformed("UTF-8"); + checkUnderOverflow("UTF-8"); + } +}