OpenJDK / amber / amber
changeset 852:d776f58e8a63
Merge
author | duke |
---|---|
date | Wed, 05 Jul 2017 16:39:18 +0200 |
parents | 9ab23b73f1b9 49d52a53975d |
children | a7fdb5ff3e2c |
files | |
diffstat | 121 files changed, 6900 insertions(+), 1270 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags-top-repo Thu Jul 17 11:28:32 2008 -0700 +++ b/.hgtags-top-repo Wed Jul 05 16:39:18 2017 +0200 @@ -5,3 +5,4 @@ 56652b46f328937f6b9b5130f1e4cd80f48868ef jdk7-b28 31e08f70e88d77c2053f91c21b49a04296bdc59a jdk7-b29 2dab2f712e1832c92acfa63ec0337048b9422c20 jdk7-b30 +3300a35a0bd56d695b92fe0b34f03ebbfc939064 jdk7-b31
--- a/README-builds.html Thu Jul 17 11:28:32 2008 -0700 +++ b/README-builds.html Wed Jul 05 16:39:18 2017 +0200 @@ -5,15 +5,12 @@ </head> <body style="background-color:lightcyan"> <!-- ====================================================== --> - <table width="100%" style="background-color:white"> + + <table width="100%"> <tr> <td align="center"> - <a href="http://openjdk.java.net" border="0"> - <img alt="OpenJDK" - src="http://openjdk.java.net/images/openjdk.png" - width=256 - style="border-style: none"/> - </a> + <img alt="OpenJDK" + src="http://openjdk.java.net/images/openjdk.png" + width=256 /> </td> </tr> <tr> @@ -54,6 +51,7 @@ <li><a href="#bootjdk">Bootstrap JDK</a> </li> <li><a href="#binaryplugs">Binary Plugs</a> </li> <li><a href="#importjdk">Optional Import JDK</a> </li> + <li><a href="#ant">Ant</a> </li> <li><a href="#cacerts">Certificate Authority File (cacert)</a> </li> <li><a href="#compilers">Compilers</a> <ul> @@ -424,24 +422,37 @@ you should use <tt>gmake</tt> which will be located in either the <tt>/opt/sfw/bin</tt> or <tt>/usr/sfw/bin</tt> directory. + In more recent versions of Solaris GNU make can be found + at <tt>/usr/bin/gmake</tt>. </li> <li> <strong>Windows:</strong> Make sure you start your build inside a bash/sh/ksh shell. <br> <b>WARNING:</b> Watch out for make version 3.81, it may - not work due to a lack of support for drive letter paths - like <tt>C:/</tt>. See - <a href="#gmake">section on gmake</a>. + not work due to a lack of support for MS-DOS drive letter paths + like <tt>C:/</tt> or <tt>C:\</tt>. Use a 3.80 version, or find a newer - version that has this problem fixed. + version that has this problem fixed, like 3.82. The older 3.80 version of make.exe can be downloaded with this <a href="http://cygwin.paracoda.com/release/make/make-3.80-1.tar.bz2" target="_blank"> link</a>. + Use of this older 3.80 make.exe may require that you install the + libintl2.dll library or libintl2 cygwin package which is + no longer installed by default by the cygwin installer. + <br> Also see the <a href="http://developer.mozilla.org/en/docs/Windows_build_prerequisites_using_cygwin#make" target="_blank"> mozilla developer center</a> on this topic. + <br> + It's hoped that when make 3.82 starts shipping in a future cygwin + release that this MS-DOS path issue will be fixed. + In addition to the above 3.80 make.exe you can download + this + <a href="http://www.cmake.org/files/cygwin/make.exe"> + www.cmake.org make.exe</a> which will not have a libintl2.dll + dependency. </li> </ul> <p> @@ -507,6 +518,11 @@ Install or upgrade the <a href="#freetype">FreeType development package</a>. </li> + <li> + Install + <a href="#ant">Ant</a>, set + <tt><a href="#ANT_HOME">ANT_HOME</a></tt>. + </li> </ol> </blockquote> <!-- ------------------------------------------------------ --> @@ -567,6 +583,11 @@ <a href="#cups">CUPS Include files</a>, set <tt><a href="#ALT_CUPS_HEADERS_PATH">ALT_CUPS_HEADERS_PATH</a></tt>. </li> + <li> + Install + <a href="#ant">Ant</a>, set + <tt><a href="#ANT_HOME">ANT_HOME</a></tt>. + </li> </ol> </blockquote> <!-- ------------------------------------------------------ --> @@ -654,6 +675,11 @@ Install <a href="#dxsdk">Microsoft DirectX SDK</a>. </li> + <li> + Install + <a href="#ant">Ant</a>, set + <tt><a href="#ANT_HOME">ANT_HOME</a></tt>. + </li> </ol> </blockquote> <!-- ------------------------------------------------------ --> @@ -736,6 +762,22 @@ and the build will copy the needed files from this import area. </blockquote> <!-- ------------------------------------------------------ --> + <h4><a name="ant">Ant</a></h4> + <blockquote> + All OpenJDK builds require access to least Ant 1.6.5. + The Ant tool is available from the + <a href="http://ant.apache.org/antlibs/bindownload.cgi" target="_blank"> + Ant download site</a>. + You should always set + <tt><a href="#ANT_HOME">ANT_HOME</a></tt> + to point to the location of + the Ant installation, this is the directory pathname + that contains a <tt>bin and lib</tt>. + It's also a good idea to also place its <tt>bin</tt> directory + in the <tt>PATH</tt> environment variable, although it's + not absolutely required. + </blockquote> + <!-- ------------------------------------------------------ --> <h4><a name="cacerts">Certificate Authority File (cacert)</a></h4> <blockquote> See <a href="http://en.wikipedia.org/wiki/Certificate_Authority" target="_blank"> @@ -915,6 +957,21 @@ and <tt><a href="#ALT_FREETYPE_HEADERS_PATH">ALT_FREETYPE_HEADERS_PATH</a></tt> to refer to place where library and header files are installed. + <p> + Building the freetype 2 libraries from scratch is also possible, + however on Windows refer to the + <a href="http://freetype.freedesktop.org/wiki/FreeType_DLL"> + Windows FreeType DLL build instructions</a>. + <p> + Note that by default FreeType is built with byte code hinting + support disabled due to licensing restrictions. + In this case, text appearance and metrics are expected to + differ from Sun's official JDK build. + See + <a href="http://freetype.sourceforge.net/freetype2/index.html"> + the SourceForge FreeType2 Home Page + </a> + for more information. </blockquote> <!-- ------------------------------------------------------ --> <h4><a name="alsa">Advanced Linux Sound Architecture (ALSA) (Linux only)</a></h4> @@ -1036,7 +1093,8 @@ <tr> <td>make.exe</td> <td>Devel</td> - <td>make: The GNU version of the 'make' utility</td> + <td>make: The GNU version of the 'make' utility<br> + <b>NOTE</b>: See <a href="#gmake">the GNU make section</a></td> </tr> <tr> <td>m4.exe</td> @@ -1050,7 +1108,7 @@ <td>cpio: A program to manage archives of files</td> </tr> <tr> - <td>awk.exe</td> + <td>gawk.exe</td> <td>Utils</td> <td>awk: Pattern-directed scanning and processing language</td> </tr> @@ -1061,17 +1119,17 @@ </tr> <tr> <td>zip.exe</td> - <td>Utils</td> + <td>Archive</td> <td>zip: Package and compress (archive) files</td> </tr> <tr> <td>unzip.exe</td> - <td>Utils</td> + <td>Archive</td> <td>unzip: Extract compressed files in a ZIP archive</td> </tr> <tr> <td>free.exe</td> - <td>Utils</td> + <td>Procps</td> <td>free: Display amount of free and used memory in the system</td> </tr> </tbody> @@ -1224,46 +1282,6 @@ document) that can impact the build are: <blockquote> <dl> - <dt><a name="path"><tt>PATH</tt></a> </dt> - <dd>Typically you want to set the <tt>PATH</tt> to include: - <ul> - <li>The location of the GNU make binary</li> - <li>The location of the Bootstrap JDK <tt>java</tt> - (see <a href="#bootjdk">Bootstrap JDK</a>)</li> - <li>The location of the C/C++ compilers - (see <a href="#compilers"><tt>compilers</tt></a>)</li> - <li>The location or locations for the Unix command utilities - (e.g. <tt>/usr/bin</tt>)</li> - </ul> - </dd> - <dt><tt>MILESTONE</tt> </dt> - <dd> - The milestone name for the build (<i>e.g.</i>"beta"). - The default value is "internal". - </dd> - <dt><tt>BUILD_NUMBER</tt> </dt> - <dd> - The build number for the build (<i>e.g.</i> "b27"). - The default value is "b00". - </dd> - <dt><a name="arch_data_model"><tt>ARCH_DATA_MODEL</tt></a></dt> - <dd>The <tt>ARCH_DATA_MODEL</tt> variable - is used to specify whether the build is to generate 32-bit or 64-bit - binaries. - The Solaris build supports either 32-bit or 64-bit builds, but - Windows and Linux will support only one, depending on the specific - OS being used. - Normally, setting this variable is only necessary on Solaris. - Set <tt>ARCH_DATA_MODEL</tt> to <tt>32</tt> for generating 32-bit binaries, - or to <tt>64</tt> for generating 64-bit binaries. - </dd> - <dt><a name="ALT_BOOTDIR"><tt>ALT_BOOTDIR</tt></a></dt> - <dd> - The location of the bootstrap JDK installation. - See <a href="#bootjdk">Bootstrap JDK</a> for more information. - You should always install your own local Bootstrap JDK and - always set <tt>ALT_BOOTDIR</tt> explicitly. - </dd> <dt><a name="ALT_BINARY_PLUGS_PATH"><tt>ALT_BINARY_PLUGS_PATH</tt></a></dt> <dd> The location of the binary plugs installation. @@ -1272,98 +1290,32 @@ recent Binary Plugs install image and set this variable to that location. </dd> - <dt><a name="ALT_JDK_IMPORT_PATH"><tt>ALT_JDK_IMPORT_PATH</tt></a></dt> - <dd> - The location of a previously built JDK installation. - See <a href="#importjdk">Optional Import JDK</a> for more information. - </dd> - <dt><a name="ALT_OUTPUTDIR"><tt>ALT_OUTPUTDIR</tt></a> </dt> - <dd> - An override for specifying the (absolute) path of where the - build output is to go. - The default output directory will be build/<i>platform</i>. - </dd> - <dt><a name="ALT_COMPILER_PATH"><tt>ALT_COMPILER_PATH</tt></a> </dt> - <dd> - The location of the C/C++ compiler. - The default varies depending on the platform. - </dd> - <dt><tt><a name="ALT_CACERTS_FILE">ALT_CACERTS_FILE</a></tt></dt> + <dt><a name="ALT_BOOTDIR"><tt>ALT_BOOTDIR</tt></a></dt> <dd> - The location of the <a href="#cacerts">cacerts</a> file. - The default will refer to - <tt>jdk/src/share/lib/security/cacerts</tt>. - </dd> - <dt><a name="ALT_CUPS_HEADERS_PATH"><tt>ALT_CUPS_HEADERS_PATH</tt></a> </dt> - <dd> - The location of the CUPS header files. - See <a href="#cups">CUPS information</a> for more information. - If this path does not exist the fallback path is - <tt>/usr/include</tt>. - </dd> - <dt><a name="ALT_FREETYPE_LIB_PATH"><tt>ALT_FREETYPE_LIB_PATH</tt></a></dt> - <dd> - The location of the FreeType shared library. - See <a href="#freetype">FreeType information</a> for details. - </dd> - <dt><a name="ALT_FREETYPE_HEADERS_PATH"><tt>ALT_FREETYPE_HEADERS_PATH</tt></a></dt> - <dd> - The location of the FreeType header files. - See <a href="#freetype">FreeType information</a> for details. - </dd> - <dt><a name="ALT_JDK_DEVTOOLS_PATH"><tt>ALT_JDK_DEVTOOLS_PATH</tt></a></dt> - <dd> - The default root location of the devtools. - The default value is - <tt>$(ALT_SLASH_JAVA)/devtools</tt>. + The location of the bootstrap JDK installation. + See <a href="#bootjdk">Bootstrap JDK</a> for more information. + You should always install your own local Bootstrap JDK and + always set <tt>ALT_BOOTDIR</tt> explicitly. </dd> - <dt><tt><a name="ALT_DEVTOOLS_PATH">ALT_DEVTOOLS_PATH</a></tt> </dt> - <dd> - The location of tools like the - <a href="#zip"><tt>zip</tt> and <tt>unzip</tt></a> - binaries, but might also contain the GNU make utility - (<tt><i>gmake</i></tt>). - So this area is a bit of a grab bag, especially on Windows. - The default value depends on the platform and - Unix Commands being used. - On Linux the default will be - <tt>$(ALT_JDK_DEVTOOLS_PATH)/linux/bin</tt>, - on Solaris - <tt>$(ALT_JDK_DEVTOOLS_PATH)/<i>{sparc,i386}</i>/bin</tt>, - on Windows with MKS - <tt>%SYSTEMDRIVE%/UTILS</tt>, - and on Windows with CYGWIN - <tt>/usr/bin</tt>. - </dd> - <dt><a name="ALT_UNIXCOMMAND_PATH"><tt>ALT_UNIXCOMMAND_PATH</tt></a> </dt> + <dt><a name="ALT_BUILD_BINARY_PLUGS_PATH"><tt>ALT_BUILD_BINARY_PLUGS_PATH</tt></a></dt> <dd> - An override for specifying where the - Unix command set are located. - The default location varies depending on the platform, - <tt>"%SYSTEMDRIVE%/MKSNT"</tt> or - <tt>$(ROOTDIR)</tt> on Windows with MKS, otherwise it's - <tt>"/bin"</tt> or <tt>/usr/bin</tt>. - </dd> - <dt><a name="ALT_UNIXCCS_PATH"><tt>ALT_UNIXCCS_PATH</tt></a></dt> - <dd> - <strong>Solaris only:</strong> - An override for specifying where the Unix CCS - command set are located. - The default location is <tt>/usr/ccs/bin</tt> - </dd> - <dt><a name="ALT_USRBIN_PATH"><tt>ALT_USRBIN_PATH</tt></a></dt> - <dd> - An override for specifying where the - Unix <tt>/usr/bin</tt> commands are located. You usually do not need - to set this variable: the default location is <tt>/usr/bin</tt>) - </dd> - <dt><a name="ALT_SLASHJAVA"><tt>ALT_SLASHJAVA</tt></a></dt> - <dd> - The default root location for many of the ALT path locations - of the following ALT variables. - The default value is - <tt>"/java"</tt> on Solaris and Linux, - <tt>"J:"</tt> on Windows. + These are useful in managing builds on multiple platforms. + The default network location for all of the binary plug images + for all platforms. + If <tt><a href="#ALT_BINARY_PLUGS_PATH">ALT_BINARY_PLUGS_PATH</a></tt> + is not set, this directory will be used and should contain + the following directories: + <tt>solaris-sparc</tt>, + <tt>solaris-i586</tt>, + <tt>solaris-sparcv9</tt>, + <tt>solaris-amd64</tt>, + <tt>linux-i586</tt>, + <tt>linux-amd64</tt>, + <tt>windows-i586</tt>, + and + <tt>windows-amd64</tt>. + Where each of these directories contain the binary plugs image + for that platform. </dd> <dt><a name="ALT_BUILD_JDK_IMPORT_PATH"><tt>ALT_BUILD_JDK_IMPORT_PATH</tt></a></dt> <dd> @@ -1385,56 +1337,166 @@ Where each of these directories contain the import JDK image for that platform. </dd> - <dt><a name="ALT_BUILD_BINARY_PLUGS_PATH"><tt>ALT_BUILD_BINARY_PLUGS_PATH</tt></a></dt> + <dt><tt><a name="ALT_CACERTS_FILE">ALT_CACERTS_FILE</a></tt></dt> + <dd> + The location of the <a href="#cacerts">cacerts</a> file. + The default will refer to + <tt>jdk/src/share/lib/security/cacerts</tt>. + </dd> + <dt><a name="ALT_COMPILER_PATH"><tt>ALT_COMPILER_PATH</tt></a> </dt> + <dd> + The location of the C/C++ compiler. + The default varies depending on the platform. + </dd> + <dt><a name="ALT_CUPS_HEADERS_PATH"><tt>ALT_CUPS_HEADERS_PATH</tt></a> </dt> + <dd> + The location of the CUPS header files. + See <a href="#cups">CUPS information</a> for more information. + If this path does not exist the fallback path is + <tt>/usr/include</tt>. + </dd> + <dt><tt><a name="ALT_DEVTOOLS_PATH">ALT_DEVTOOLS_PATH</a></tt> </dt> + <dd> + The location of tools like the + <a href="#zip"><tt>zip</tt> and <tt>unzip</tt></a> + binaries, but might also contain the GNU make utility + (<tt><i>gmake</i></tt>). + So this area is a bit of a grab bag, especially on Windows. + The default value depends on the platform and + Unix Commands being used. + On Linux the default will be + <tt>$(ALT_JDK_DEVTOOLS_PATH)/linux/bin</tt>, + on Solaris + <tt>$(ALT_JDK_DEVTOOLS_PATH)/<i>{sparc,i386}</i>/bin</tt>, + on Windows with MKS + <tt>%SYSTEMDRIVE%/UTILS</tt>, + and on Windows with CYGWIN + <tt>/usr/bin</tt>. + </dd> + <dt><tt><a name="ALT_DXSDK_PATH">ALT_DXSDK_PATH</a></tt> </dt> <dd> - These are useful in managing builds on multiple platforms. - The default network location for all of the binary plug images - for all platforms. - If <tt><a href="#ALT_BINARY_PLUGS_PATH">ALT_BINARY_PLUGS_PATH</a></tt> - is not set, this directory will be used and should contain - the following directories: - <tt>solaris-sparc</tt>, - <tt>solaris-i586</tt>, - <tt>solaris-sparcv9</tt>, - <tt>solaris-amd64</tt>, - <tt>linux-i586</tt>, - <tt>linux-amd64</tt>, - <tt>windows-i586</tt>, - and - <tt>windows-amd64</tt>. - Where each of these directories contain the binary plugs image - for that platform. + <strong>Windows Only:</strong> + The location of the + <a href="#dxsdk">Microsoft DirectX 9 SDK</a>. + The default will be to try and use the DirectX environment + variable <tt>DXSDK_DIR</tt>, + failing that, look in <tt>C:/DXSDK</tt>. + </dd> + <dt><a name="ALT_FREETYPE_HEADERS_PATH"><tt>ALT_FREETYPE_HEADERS_PATH</tt></a></dt> + <dd> + The location of the FreeType header files. + See <a href="#freetype">FreeType information</a> for details. + </dd> + <dt><a name="ALT_FREETYPE_LIB_PATH"><tt>ALT_FREETYPE_LIB_PATH</tt></a></dt> + <dd> + The location of the FreeType shared library. + See <a href="#freetype">FreeType information</a> for details. </dd> - <dt><strong>Windows specific:</strong></dt> + <dt><a name="ALT_JDK_DEVTOOLS_PATH"><tt>ALT_JDK_DEVTOOLS_PATH</tt></a></dt> + <dd> + The default root location of the devtools. + The default value is + <tt>$(ALT_SLASH_JAVA)/devtools</tt>. + </dd> + <dt><a name="ALT_JDK_IMPORT_PATH"><tt>ALT_JDK_IMPORT_PATH</tt></a></dt> + <dd> + The location of a previously built JDK installation. + See <a href="#importjdk">Optional Import JDK</a> for more information. + </dd> + <dt><a name="ALT_MSDEVTOOLS_PATH"><tt>ALT_MSDEVTOOLS_PATH</tt></a> </dt> + <dd> + <strong>Windows Only:</strong> + The location of the Microsoft Visual Studio .NET 2003 + tools 'bin' directory. + The default is usually derived from + <a href="#ALT_COMPILER_PATH"><tt>ALT_COMPILER_PATH</tt></a>. + </dd> + <dt><tt><a name="ALT_MSVCR71_DLL_PATH">ALT_MSVCR71_DLL_PATH</a></tt> </dt> <dd> - <dl> - <dt><a name="ALT_MSDEVTOOLS_PATH"><tt>ALT_MSDEVTOOLS_PATH</tt></a> </dt> - <dd> - The location of the Microsoft Visual Studio .NET 2003 - tools 'bin' directory. - The default is usually derived from - <a href="#ALT_COMPILER_PATH"><tt>ALT_COMPILER_PATH</tt></a>. - </dd> - <dt><tt><a name="ALT_DXSDK_PATH">ALT_DXSDK_PATH</a></tt> </dt> - <dd> - The location of the - <a href="#dxsdk">Microsoft DirectX 9 SDK</a>. - The default will be to try and use the DirectX environment - variable <tt>DXSDK_DIR</tt>, - failing that, look in <tt>C:/DXSDK</tt>. - </dd> - <dt><tt><a name="ALT_MSVCRT_DLL_PATH">ALT_MSVCRT_DLL_PATH</a></tt> </dt> - <dd> - The location of the - <a href="#msvcrt"><tt>MSVCRT.DLL</tt></a>. - </dd> - <dt><tt><a name="ALT_MSVCR71_DLL_PATH">ALT_MSVCR71_DLL_PATH</a></tt> </dt> - <dd> - <strong>i586 only:</strong> - The location of the - <a href="#msvcr71"><tt>MSVCR71.DLL</tt></a>. - </dd> - </dl> + <strong>Windows i586 only:</strong> + The location of the + <a href="#msvcr71"><tt>MSVCR71.DLL</tt></a>. + </dd> + <dt><tt><a name="ALT_MSVCRT_DLL_PATH">ALT_MSVCRT_DLL_PATH</a></tt> </dt> + <dd> + <strong>Windows Only:</strong> + The location of the + <a href="#msvcrt"><tt>MSVCRT.DLL</tt></a>. + </dd> + <dt><a name="ALT_OUTPUTDIR"><tt>ALT_OUTPUTDIR</tt></a> </dt> + <dd> + An override for specifying the (absolute) path of where the + build output is to go. + The default output directory will be build/<i>platform</i>. + </dd> + <dt><a name="ALT_SLASHJAVA"><tt>ALT_SLASHJAVA</tt></a></dt> + <dd> + The default root location for many of the ALT path locations + of the following ALT variables. + The default value is + <tt>"/java"</tt> on Solaris and Linux, + <tt>"J:"</tt> on Windows. + </dd> + <dt><a name="ALT_UNIXCCS_PATH"><tt>ALT_UNIXCCS_PATH</tt></a></dt> + <dd> + <strong>Solaris only:</strong> + An override for specifying where the Unix CCS + command set are located. + The default location is <tt>/usr/ccs/bin</tt> + </dd> + <dt><a name="ALT_UNIXCOMMAND_PATH"><tt>ALT_UNIXCOMMAND_PATH</tt></a> </dt> + <dd> + An override for specifying where the + Unix command set are located. + The default location varies depending on the platform, + <tt>"%SYSTEMDRIVE%/MKSNT"</tt> or + <tt>$(ROOTDIR)</tt> on Windows with MKS, otherwise it's + <tt>"/bin"</tt> or <tt>/usr/bin</tt>. + </dd> + <dt><a name="ALT_USRBIN_PATH"><tt>ALT_USRBIN_PATH</tt></a></dt> + <dd> + An override for specifying where the + Unix <tt>/usr/bin</tt> commands are located. You usually do not need + to set this variable: the default location is <tt>/usr/bin</tt>) + </dd> + <dt><a name="ANT_HOME"><tt>ANT_HOME</tt></a></dt> + <dd> + The location of the Ant installation. + See <a href="#ant">Ant</a> for more information. + You should always set <tt>ANT_HOME</tt> explicitly. + </dd> + <dt><a name="arch_data_model"><tt>ARCH_DATA_MODEL</tt></a></dt> + <dd>The <tt>ARCH_DATA_MODEL</tt> variable + is used to specify whether the build is to generate 32-bit or 64-bit + binaries. + The Solaris build supports either 32-bit or 64-bit builds, but + Windows and Linux will support only one, depending on the specific + OS being used. + Normally, setting this variable is only necessary on Solaris. + Set <tt>ARCH_DATA_MODEL</tt> to <tt>32</tt> for generating 32-bit binaries, + or to <tt>64</tt> for generating 64-bit binaries. + </dd> + <dt><tt>BUILD_NUMBER</tt> </dt> + <dd> + The build number for the build (<i>e.g.</i> "b27"). + The default value is "b00". + </dd> + <dt><tt>MILESTONE</tt> </dt> + <dd> + The milestone name for the build (<i>e.g.</i>"beta"). + The default value is "internal". + </dd> + <dt><a name="path"><tt>PATH</tt></a> </dt> + <dd>Typically you want to set the <tt>PATH</tt> to include: + <ul> + <li>The location of the GNU make binary</li> + <li>The location of the Bootstrap JDK <tt>java</tt> + (see <a href="#bootjdk">Bootstrap JDK</a>)</li> + <li>The location of the C/C++ compilers + (see <a href="#compilers"><tt>compilers</tt></a>)</li> + <li>The location or locations for the Unix command utilities + (e.g. <tt>/usr/bin</tt>)</li> + </ul> </dd> </dl> </blockquote>
--- a/hotspot/.hgtags Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/.hgtags Wed Jul 05 16:39:18 2017 +0200 @@ -5,3 +5,4 @@ c14dab40ed9bf45ad21150bd70c9c80cdf655415 jdk7-b28 4f91c08b3e4498213a9c5a24898f7d9c38cf86fb jdk7-b29 d1605aabd0a15ecf93787c47de63073c33fba52d jdk7-b30 +9c2ecc2ffb125f14fab3857fe7689598956348a0 jdk7-b31
--- a/hotspot/src/os/linux/vm/os_linux.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -2414,8 +2414,20 @@ return ::mprotect(bottom, size, prot) == 0; } -bool os::protect_memory(char* addr, size_t size) { - return linux_mprotect(addr, size, PROT_READ); +// Set protections specified +bool os::protect_memory(char* addr, size_t bytes, ProtType prot, + bool is_committed) { + unsigned int p = 0; + switch (prot) { + case MEM_PROT_NONE: p = PROT_NONE; break; + case MEM_PROT_READ: p = PROT_READ; break; + case MEM_PROT_RW: p = PROT_READ|PROT_WRITE; break; + case MEM_PROT_RWX: p = PROT_READ|PROT_WRITE|PROT_EXEC; break; + default: + ShouldNotReachHere(); + } + // is_committed is unused. + return linux_mprotect(addr, bytes, p); } bool os::guard_memory(char* addr, size_t size) { @@ -3704,8 +3716,9 @@ // Mark the polling page as readable void os::make_polling_page_readable(void) { - if( !protect_memory((char *)_polling_page, Linux::page_size()) ) + if( !linux_mprotect((char *)_polling_page, Linux::page_size(), PROT_READ)) { fatal("Could not enable polling page"); + } }; int os::active_processor_count() {
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -2965,10 +2965,21 @@ return retVal == 0; } -// Protect memory (make it read-only. (Used to pass readonly pages through +// Protect memory (Used to pass readonly pages through // JNI GetArray<type>Elements with empty arrays.) -bool os::protect_memory(char* addr, size_t bytes) { - return solaris_mprotect(addr, bytes, PROT_READ); +bool os::protect_memory(char* addr, size_t bytes, ProtType prot, + bool is_committed) { + unsigned int p = 0; + switch (prot) { + case MEM_PROT_NONE: p = PROT_NONE; break; + case MEM_PROT_READ: p = PROT_READ; break; + case MEM_PROT_RW: p = PROT_READ|PROT_WRITE; break; + case MEM_PROT_RWX: p = PROT_READ|PROT_WRITE|PROT_EXEC; break; + default: + ShouldNotReachHere(); + } + // is_committed is unused. + return solaris_mprotect(addr, bytes, p); } // guard_memory and unguard_memory only happens within stack guard pages.
--- a/hotspot/src/os/windows/vm/os_windows.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -2170,6 +2170,7 @@ // Windows 98 reports faulting addresses incorrectly if (!MacroAssembler::needs_explicit_null_check((intptr_t)addr) || !os::win32::is_nt()) { + return Handle_Exception(exceptionInfo, SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL)); } @@ -2563,9 +2564,33 @@ return VirtualFree(addr, 0, MEM_RELEASE) != 0; } -bool os::protect_memory(char* addr, size_t bytes) { +// Set protections specified +bool os::protect_memory(char* addr, size_t bytes, ProtType prot, + bool is_committed) { + unsigned int p = 0; + switch (prot) { + case MEM_PROT_NONE: p = PAGE_NOACCESS; break; + case MEM_PROT_READ: p = PAGE_READONLY; break; + case MEM_PROT_RW: p = PAGE_READWRITE; break; + case MEM_PROT_RWX: p = PAGE_EXECUTE_READWRITE; break; + default: + ShouldNotReachHere(); + } + DWORD old_status; - return VirtualProtect(addr, bytes, PAGE_READONLY, &old_status) != 0; + + // Strange enough, but on Win32 one can change protection only for committed + // memory, not a big deal anyway, as bytes less or equal than 64K + if (!is_committed && !commit_memory(addr, bytes)) { + fatal("cannot commit protection page"); + } + // One cannot use os::guard_memory() here, as on Win32 guard page + // have different (one-shot) semantics, from MSDN on PAGE_GUARD: + // + // Pages in the region become guard pages. Any attempt to access a guard page + // causes the system to raise a STATUS_GUARD_PAGE exception and turn off + // the guard page status. Guard pages thus act as a one-time access alarm. + return VirtualProtect(addr, bytes, p, &old_status) != 0; } bool os::guard_memory(char* addr, size_t bytes) {
--- a/hotspot/src/os_cpu/linux_sparc/vm/assembler_linux_sparc.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/os_cpu/linux_sparc/vm/assembler_linux_sparc.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -27,12 +27,6 @@ #include <asm-sparc/traps.h> -bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { - // Since the linux kernel resides at the low end of - // user address space, no null pointer check is needed. - return offset < 0 || offset >= 0x100000; -} - void MacroAssembler::read_ccr_trap(Register ccr_save) { // No implementation breakpoint_trap();
--- a/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_32.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_32.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -39,10 +39,3 @@ movptr(thread, tls); } - -bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { - // Linux kernel guarantees that the first page is always unmapped. Don't - // assume anything more than that. - bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size(); - return !offset_in_first_page; -}
--- a/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_64.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/os_cpu/linux_x86/vm/assembler_linux_x86_64.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -65,22 +65,3 @@ popq(rax); } } - -bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { - // Exception handler checks the nmethod's implicit null checks table - // only when this method returns false. - if (UseCompressedOops) { - // The first page after heap_base is unmapped and - // the 'offset' is equal to [heap_base + offset] for - // narrow oop implicit null checks. - uintptr_t heap_base = (uintptr_t)Universe::heap_base(); - if ((uintptr_t)offset >= heap_base) { - // Normalize offset for the next check. - offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1)); - } - } - // Linux kernel guarantees that the first page is always unmapped. Don't - // assume anything more than that. - bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size(); - return !offset_in_first_page; -}
--- a/hotspot/src/os_cpu/solaris_sparc/vm/assembler_solaris_sparc.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/assembler_solaris_sparc.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -28,18 +28,6 @@ #include <sys/trap.h> // For trap numbers #include <v9/sys/psr_compat.h> // For V8 compatibility -bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { - // The first page of virtual addresses is unmapped on SPARC. - // Thus, any access the VM makes through a null pointer with an offset of - // less than 4K will get a recognizable SIGSEGV, which the signal handler - // will transform into a NullPointerException. - // (Actually, the first 64K or so is unmapped, but it's simpler - // to depend only on the first 4K or so.) - - bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size(); - return !offset_in_first_page; -} - void MacroAssembler::read_ccr_trap(Register ccr_save) { // Execute a trap to get the PSR, mask and shift // to get the condition codes.
--- a/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_32.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_32.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -79,9 +79,3 @@ if (thread != rax) popl(rax); popl(thread); } - -bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { - // Identical to Sparc/Solaris code - bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size(); - return !offset_in_first_page; -}
--- a/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_64.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/os_cpu/solaris_x86/vm/assembler_solaris_x86_64.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -85,22 +85,3 @@ popq(rax); } } - -bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { - // Identical to Sparc/Solaris code - - // Exception handler checks the nmethod's implicit null checks table - // only when this method returns false. - if (UseCompressedOops) { - // The first page after heap_base is unmapped and - // the 'offset' is equal to [heap_base + offset] for - // narrow oop implicit null checks. - uintptr_t heap_base = (uintptr_t)Universe::heap_base(); - if ((uintptr_t)offset >= heap_base) { - // Normalize offset for the next check. - offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1)); - } - } - bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size(); - return !offset_in_first_page; -}
--- a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_32.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_32.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -58,7 +58,3 @@ "Thread Pointer Offset has not been initialized"); movl(thread, Address(thread, ThreadLocalStorage::get_thread_ptr_offset())); } - -bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { - return offset < 0 || (int)os::vm_page_size() <= offset; -}
--- a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_64.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86_64.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -65,19 +65,3 @@ popq(rax); } } - -bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { - // Exception handler checks the nmethod's implicit null checks table - // only when this method returns false. - if (UseCompressedOops) { - // The first page after heap_base is unmapped and - // the 'offset' is equal to [heap_base + offset] for - // narrow oop implicit null checks. - uintptr_t heap_base = (uintptr_t)Universe::heap_base(); - if ((uintptr_t)offset >= heap_base) { - // Normalize offset for the next check. - offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1)); - } - } - return offset < 0 || os::vm_page_size() <= offset; -}
--- a/hotspot/src/share/vm/asm/assembler.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/share/vm/asm/assembler.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -246,6 +246,24 @@ } } +bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { + // Exception handler checks the nmethod's implicit null checks table + // only when this method returns false. +#ifndef SPARC + // Sparc does not have based addressing + if (UseCompressedOops) { + // The first page after heap_base is unmapped and + // the 'offset' is equal to [heap_base + offset] for + // narrow oop implicit null checks. + uintptr_t heap_base = (uintptr_t)Universe::heap_base(); + if ((uintptr_t)offset >= heap_base) { + // Normalize offset for the next check. + offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1)); + } + } +#endif // SPARC + return offset < 0 || os::vm_page_size() <= offset; +} #ifndef PRODUCT void Label::print_instructions(MacroAssembler* masm) const {
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -61,6 +61,8 @@ if (_virtual_space != NULL) { delete _virtual_space; _virtual_space = NULL; + // Release memory reserved in the space. + rs.release(); } return false; }
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -108,8 +108,8 @@ // size than is needed or wanted for the perm gen. Use the "compound // alignment" ReservedSpace ctor to avoid having to use the same page size for // all gens. - ReservedSpace heap_rs(pg_max_size, pg_align, og_max_size + yg_max_size, - og_align); + ReservedHeapSpace heap_rs(pg_max_size, pg_align, og_max_size + yg_max_size, + og_align); os::trace_page_sizes("ps perm", pg_min_size, pg_max_size, pg_page_sz, heap_rs.base(), pg_max_size); os::trace_page_sizes("ps main", og_min_size + yg_min_size,
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -422,6 +422,8 @@ return vspace; } delete vspace; + // Release memory reserved in the space. + rs.release(); } return 0;
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -71,13 +71,8 @@ void PSVirtualSpace::release() { DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this)); - if (reserved_low_addr() != NULL) { - if (special()) { - os::release_memory_special(reserved_low_addr(), reserved_size()); - } else { - (void)os::release_memory(reserved_low_addr(), reserved_size()); - } - } + // This may not release memory it didn't reserve. + // Use rs.release() to release the underlying memory instead. _reserved_low_addr = _reserved_high_addr = NULL; _committed_low_addr = _committed_high_addr = NULL; _special = false;
--- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -222,8 +222,8 @@ *_total_reserved = total_reserved; *_n_covered_regions = n_covered_regions; - *heap_rs = ReservedSpace(total_reserved, alignment, - UseLargePages, heap_address); + *heap_rs = ReservedHeapSpace(total_reserved, alignment, + UseLargePages, heap_address); return heap_address; }
--- a/hotspot/src/share/vm/prims/jni.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/share/vm/prims/jni.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -2173,8 +2173,7 @@ size_t size = os::vm_allocation_granularity(); bad_address = os::reserve_memory(size); if (bad_address != NULL) { - os::commit_memory(bad_address, size); - os::protect_memory(bad_address, size); + os::protect_memory(bad_address, size, os::MEM_PROT_READ); } } return bad_address;
--- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -1176,8 +1176,7 @@ // by ergonomics. if (MaxHeapSize <= max_heap_for_compressed_oops()) { if (FLAG_IS_DEFAULT(UseCompressedOops)) { - // Leave compressed oops off by default. Uncomment - // the following line to return it to default status. + // Turn off until bug is fixed. // FLAG_SET_ERGO(bool, UseCompressedOops, true); } } else {
--- a/hotspot/src/share/vm/runtime/os.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -922,8 +922,9 @@ // time and expensive page trap spinning, 'SerializePageLock' is used to block // the mutator thread if such case is encountered. See bug 6546278 for details. Thread::muxAcquire(&SerializePageLock, "serialize_thread_states"); - os::protect_memory( (char *)os::get_memory_serialize_page(), os::vm_page_size() ); - os::unguard_memory( (char *)os::get_memory_serialize_page(), os::vm_page_size() ); + os::protect_memory((char *)os::get_memory_serialize_page(), + os::vm_page_size(), MEM_PROT_READ, /*is_committed*/true ); + os::unguard_memory((char *)os::get_memory_serialize_page(), os::vm_page_size()); Thread::muxRelease(&SerializePageLock); }
--- a/hotspot/src/share/vm/runtime/os.hpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/share/vm/runtime/os.hpp Wed Jul 05 16:39:18 2017 +0200 @@ -193,7 +193,11 @@ static bool commit_memory(char* addr, size_t size, size_t alignment_hint); static bool uncommit_memory(char* addr, size_t bytes); static bool release_memory(char* addr, size_t bytes); - static bool protect_memory(char* addr, size_t bytes); + + enum ProtType { MEM_PROT_NONE, MEM_PROT_READ, MEM_PROT_RW, MEM_PROT_RWX }; + static bool protect_memory(char* addr, size_t bytes, ProtType prot, + bool is_committed = false); + static bool guard_memory(char* addr, size_t bytes); static bool unguard_memory(char* addr, size_t bytes); static char* map_memory(int fd, const char* file_name, size_t file_offset,
--- a/hotspot/src/share/vm/runtime/virtualspace.cpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp Wed Jul 05 16:39:18 2017 +0200 @@ -28,12 +28,15 @@ // ReservedSpace ReservedSpace::ReservedSpace(size_t size) { - initialize(size, 0, false, NULL); + initialize(size, 0, false, NULL, 0); } ReservedSpace::ReservedSpace(size_t size, size_t alignment, - bool large, char* requested_address) { - initialize(size, alignment, large, requested_address); + bool large, + char* requested_address, + const size_t noaccess_prefix) { + initialize(size+noaccess_prefix, alignment, large, requested_address, + noaccess_prefix); } char * @@ -105,7 +108,8 @@ ReservedSpace::ReservedSpace(const size_t prefix_size, const size_t prefix_align, const size_t suffix_size, - const size_t suffix_align) + const size_t suffix_align, + const size_t noaccess_prefix) { assert(prefix_size != 0, "sanity"); assert(prefix_align != 0, "sanity"); @@ -118,12 +122,16 @@ assert((suffix_align & prefix_align - 1) == 0, "suffix_align not divisible by prefix_align"); + // Add in noaccess_prefix to prefix_size; + const size_t adjusted_prefix_size = prefix_size + noaccess_prefix; + const size_t size = adjusted_prefix_size + suffix_size; + // On systems where the entire region has to be reserved and committed up // front, the compound alignment normally done by this method is unnecessary. const bool try_reserve_special = UseLargePages && prefix_align == os::large_page_size(); if (!os::can_commit_large_page_memory() && try_reserve_special) { - initialize(prefix_size + suffix_size, prefix_align, true); + initialize(size, prefix_align, true, NULL, noaccess_prefix); return; } @@ -131,15 +139,19 @@ _size = 0; _alignment = 0; _special = false; + _noaccess_prefix = 0; + + // Assert that if noaccess_prefix is used, it is the same as prefix_align. + assert(noaccess_prefix == 0 || + noaccess_prefix == prefix_align, "noaccess prefix wrong"); // Optimistically try to reserve the exact size needed. - const size_t size = prefix_size + suffix_size; char* addr = os::reserve_memory(size, NULL, prefix_align); if (addr == NULL) return; // Check whether the result has the needed alignment (unlikely unless // prefix_align == suffix_align). - const size_t ofs = size_t(addr) + prefix_size & suffix_align - 1; + const size_t ofs = size_t(addr) + adjusted_prefix_size & suffix_align - 1; if (ofs != 0) { // Wrong alignment. Release, allocate more space and do manual alignment. // @@ -153,11 +165,11 @@ } const size_t extra = MAX2(ofs, suffix_align - ofs); - addr = reserve_and_align(size + extra, prefix_size, prefix_align, + addr = reserve_and_align(size + extra, adjusted_prefix_size, prefix_align, suffix_size, suffix_align); if (addr == NULL) { // Try an even larger region. If this fails, address space is exhausted. - addr = reserve_and_align(size + suffix_align, prefix_size, + addr = reserve_and_align(size + suffix_align, adjusted_prefix_size, prefix_align, suffix_size, suffix_align); } } @@ -165,10 +177,12 @@ _base = addr; _size = size; _alignment = prefix_align; + _noaccess_prefix = noaccess_prefix; } void ReservedSpace::initialize(size_t size, size_t alignment, bool large, - char* requested_address) { + char* requested_address, + const size_t noaccess_prefix) { const size_t granularity = os::vm_allocation_granularity(); assert((size & granularity - 1) == 0, "size not aligned to os::vm_allocation_granularity()"); @@ -181,6 +195,7 @@ _size = 0; _special = false; _alignment = 0; + _noaccess_prefix = 0; if (size == 0) { return; } @@ -220,7 +235,8 @@ // important. If available space is not detected, return NULL. if (requested_address != 0) { - base = os::attempt_reserve_memory_at(size, requested_address); + base = os::attempt_reserve_memory_at(size, + requested_address-noaccess_prefix); } else { base = os::reserve_memory(size, NULL, alignment); } @@ -259,6 +275,11 @@ _base = base; _size = size; _alignment = MAX2(alignment, (size_t) os::vm_page_size()); + _noaccess_prefix = noaccess_prefix; + + // Assert that if noaccess_prefix is used, it is the same as alignment. + assert(noaccess_prefix == 0 || + noaccess_prefix == _alignment, "noaccess prefix wrong"); assert(markOopDesc::encode_pointer_as_mark(_base)->decode_pointer() == _base, "area must be distinguisable from marks for mark-sweep"); @@ -274,6 +295,7 @@ _base = base; _size = size; _alignment = alignment; + _noaccess_prefix = 0; _special = special; } @@ -320,17 +342,58 @@ void ReservedSpace::release() { if (is_reserved()) { + char *real_base = _base - _noaccess_prefix; + const size_t real_size = _size + _noaccess_prefix; if (special()) { - os::release_memory_special(_base, _size); + os::release_memory_special(real_base, real_size); } else{ - os::release_memory(_base, _size); + os::release_memory(real_base, real_size); } _base = NULL; _size = 0; + _noaccess_prefix = 0; _special = false; } } +void ReservedSpace::protect_noaccess_prefix(const size_t size) { + // If there is noaccess prefix, return. + if (_noaccess_prefix == 0) return; + + assert(_noaccess_prefix >= (size_t)os::vm_page_size(), + "must be at least page size big"); + + // Protect memory at the base of the allocated region. + // If special, the page was committed (only matters on windows) + if (!os::protect_memory(_base, _noaccess_prefix, os::MEM_PROT_NONE, + _special)) { + fatal("cannot protect protection page"); + } + + _base += _noaccess_prefix; + _size -= _noaccess_prefix; + assert((size == _size) && ((uintptr_t)_base % _alignment == 0), + "must be exactly of required size and alignment"); +} + +ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, + bool large, char* requested_address) : + ReservedSpace(size, alignment, large, + requested_address, + UseCompressedOops ? lcm(os::vm_page_size(), alignment) : 0) { + // Only reserved space for the java heap should have a noaccess_prefix + // if using compressed oops. + protect_noaccess_prefix(size); +} + +ReservedHeapSpace::ReservedHeapSpace(const size_t prefix_size, + const size_t prefix_align, + const size_t suffix_size, + const size_t suffix_align) : + ReservedSpace(prefix_size, prefix_align, suffix_size, suffix_align, + UseCompressedOops ? lcm(os::vm_page_size(), prefix_align) : 0) { + protect_noaccess_prefix(prefix_size+suffix_size); +} // VirtualSpace @@ -348,6 +411,7 @@ _lower_alignment = 0; _middle_alignment = 0; _upper_alignment = 0; + _special = false; } @@ -402,7 +466,8 @@ void VirtualSpace::release() { - (void)os::release_memory(low_boundary(), reserved_size()); + // This does not release memory it never reserved. + // Caller must release via rs.release(); _low_boundary = NULL; _high_boundary = NULL; _low = NULL;
--- a/hotspot/src/share/vm/runtime/virtualspace.hpp Thu Jul 17 11:28:32 2008 -0700 +++ b/hotspot/src/share/vm/runtime/virtualspace.hpp Wed Jul 05 16:39:18 2017 +0200 @@ -29,13 +29,15 @@ private: char* _base; size_t _size; + size_t _noaccess_prefix; size_t _alignment; bool _special; // ReservedSpace ReservedSpace(char* base, size_t size, size_t alignment, bool special); void initialize(size_t size, size_t alignment, bool large, - char* requested_address = NULL); + char* requested_address, + const size_t noaccess_prefix); // Release parts of an already-reserved memory region [addr, addr + len) to // get a new region that has "compound alignment." Return the start of the @@ -59,13 +61,19 @@ const size_t suffix_size, const size_t suffix_align); + protected: + // Create protection page at the beginning of the space. + void protect_noaccess_prefix(const size_t size); + public: // Constructor ReservedSpace(size_t size); ReservedSpace(size_t size, size_t alignment, bool large, - char* requested_address = NULL); + char* requested_address = NULL, + const size_t noaccess_prefix = 0); ReservedSpace(const size_t prefix_size, const size_t prefix_align, - const size_t suffix_size, const size_t suffix_align); + const size_t suffix_size, const size_t suffix_align, + const size_t noaccess_prefix); // Accessors char* base() const { return _base; } @@ -73,6 +81,8 @@ size_t alignment() const { return _alignment; } bool special() const { return _special; } + size_t noaccess_prefix() const { return _noaccess_prefix; } + bool is_reserved() const { return _base != NULL; } void release(); @@ -104,6 +114,16 @@ return last_part(partition_size, alignment()); } +// Class encapsulating behavior specific of memory space reserved for Java heap +class ReservedHeapSpace : public ReservedSpace { +public: + // Constructor + ReservedHeapSpace(size_t size, size_t forced_base_alignment, + bool large, char* requested_address); + ReservedHeapSpace(const size_t prefix_size, const size_t prefix_align, + const size_t suffix_size, const size_t suffix_align); +}; + // VirtualSpace is data structure for committing a previously reserved address range in smaller chunks. class VirtualSpace VALUE_OBJ_CLASS_SPEC {
--- a/jdk/.hgtags Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/.hgtags Wed Jul 05 16:39:18 2017 +0200 @@ -5,3 +5,4 @@ 02e4c5348592a8d7fc2cba28bc5f8e35c0e17277 jdk7-b28 e21f4266466cd1306b176aaa08b2cd8337a9be3d jdk7-b29 b6d6877c1155621a175dccd12dc14c54f938fb8b jdk7-b30 +b7474b739d13bacd9972f88ac91f6350b7b0be12 jdk7-b31
--- a/jdk/make/com/sun/java/pack/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/com/sun/java/pack/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -97,9 +97,6 @@ /D "J2SE_FTYPE=0x1L" RES = $(OBJDIR)/$(PGRM).res - - # Files built here do not compile with warning level 3 if warnings are fatal - COMPILER_WARNINGS_FATAL=false else LDOUTPUT = -o #Have a space LDDFLAGS += -lc
--- a/jdk/make/com/sun/security/auth/module/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/com/sun/security/auth/module/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -55,9 +55,6 @@ EXTRA_LIBS += netapi32.lib user32.lib mpr.lib endif #fdlibm # code generates errors when compiled at warning level 3 and warnings are fatal - ifeq ($(ARCH_DATA_MODEL), 64) - COMPILER_WARNINGS_FATAL=false - endif # ARCH_DATA_MODEL endif # windows ifeq ($(PLATFORM), solaris)
--- a/jdk/make/common/Defs-linux.gmk Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/common/Defs-linux.gmk Wed Jul 05 16:39:18 2017 +0200 @@ -149,10 +149,9 @@ PIC_CODE_LARGE = -fPIC PIC_CODE_SMALL = -fpic GLOBAL_KPIC = $(PIC_CODE_LARGE) +CFLAGS_COMMON += $(GLOBAL_KPIC) $(GCC_WARNINGS) ifeq ($(ARCH), amd64) - CFLAGS_COMMON += $(GLOBAL_KPIC) $(GCC_WARNINGS) -pipe -else - CFLAGS_COMMON += $(GLOBAL_KPIC) $(GCC_WARNINGS) + CFLAGS_COMMON += -pipe endif # Linux 64bit machines use Dwarf2, which can be HUGE, have fastdebug use -g1
--- a/jdk/make/common/Defs-solaris.gmk Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/common/Defs-solaris.gmk Wed Jul 05 16:39:18 2017 +0200 @@ -40,6 +40,9 @@ # LDLIBS (set $(EXTRA_LIBS) instead) # LDLIBS_COMMON (set $(EXTRA_LIBS) instead) # LINTFLAGS (set $(OTHER_LINTFLAGS) instead) +# +# Note: CPPFLAGS are used in C and C++ compiles. +# # Get shared JDK settings include $(JDK_MAKE_SHARED_DIR)/Defs.gmk @@ -112,6 +115,10 @@ # Required with many of the source files. # -mt Assume multi-threaded (important) # +# The more unusual options to the Sun C compiler: +# +w Print more warnings +# +w2 Maximum warnings +# # # Debug flag for C and C++ compiler @@ -140,15 +147,34 @@ CXXFLAGS_DEBUG_OPTION = -g0 $(CC_FASTDEBUG_OPT) endif -CFLAGS_COMMON = -v -mt -L$(OBJDIR) -xc99=%none +CFLAGS_COMMON = -L$(OBJDIR) + +# Do not allow C99 language features like declarations in code etc. +CFLAGS_COMMON += -xc99=%none + +# Allow C++ comments in C code CFLAGS_COMMON += -xCC -CFLAGS_COMMON += -errshort=tags + +# Show error message tags on errors +CFLAGS_COMMON += -errshort=tags +CXXFLAGS_COMMON += -errtags=yes + +# Optimization flags CFLAGS_OPT = $(POPT) + +# Debug version flags CFLAGS_DBG = $(CFLAGS_DEBUG_OPTION) -CFLAGS_COMMON += -Xa $(CFLAGS_REQUIRED) + +# Required C compiler flags +CFLAGS_COMMON += -Xa $(CFLAGS_REQUIRED) + +# Maximum warnings all the time +CXXFLAGS_COMMON += +w +CFLAGS_COMMON += -v # Assume MT behavior all the time (important) -CXXFLAGS_COMMON = -mt +CXXFLAGS_COMMON += -mt +CFLAGS_COMMON += -mt # Assume no C++ exceptions are used CXXFLAGS_COMMON += -features=no%except -DCC_NOEX @@ -237,8 +263,8 @@ # OTHER_CFLAGS += -DPERTURBALOT # -CPPFLAGS_COMMON = -D$(ARCH_FAMILY) -D__solaris__ -D_REENTRANT -CPPFLAGS_OPT = +CPPFLAGS_COMMON = -D__solaris__ -D$(ARCH_FAMILY) +CPPFLAGS_OPT = -DNDEBUG CPPFLAGS_DBG = -DDEBUG ifeq ($(ARCH_FAMILY), i586)
--- a/jdk/make/common/Defs-windows.gmk Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/common/Defs-windows.gmk Wed Jul 05 16:39:18 2017 +0200 @@ -283,7 +283,7 @@ ifeq ($(ARCH), amd64) CPPFLAGS_COMMON += -D_AMD64_ -Damd64 else - CPPFLAGS_COMMON += -DWIN32 -D_X86_ -Dx86 + CPPFLAGS_COMMON += -D_X86_ -Dx86 endif CPPFLAGS_COMMON += -DWIN32_LEAN_AND_MEAN @@ -293,16 +293,23 @@ CFLAGS_COMMON += -Fd$(OBJDIR)/$(basename $(@F)).pdb -Fm$(OBJDIR)/$(basename $(@F)).map # +# Use -wdNNNN to disable warning NNNN. +# C4800 is a warning about bool performance casts (can't make go away) +# +COMPILER_WARNINGS_TO_IGNORE = 4800 +CFLAGS_COMMON += $(COMPILER_WARNINGS_TO_IGNORE:%=-wd%) + +# # Add warnings and extra on 64bit issues # ifeq ($(ARCH_DATA_MODEL), 64) CFLAGS_COMMON += -Wp64 endif -CFLAGS_COMMON += -W$(COMPILER_WARNING_LEVEL) # # Treat compiler warnings as errors, if requested # +CFLAGS_COMMON += -W$(COMPILER_WARNING_LEVEL) ifeq ($(COMPILER_WARNINGS_FATAL),true) CFLAGS_COMMON += -WX endif @@ -352,17 +359,9 @@ # BUILD_WIN_SA=1 # on the make command. ifdef BUILD_WIN_SA - ifeq ($(ARCH), amd64) - INCLUDE_SA = true - else - INCLUDE_SA = true - endif + INCLUDE_SA = true else - ifeq ($(ARCH), amd64) - INCLUDE_SA = false - else - INCLUDE_SA = false - endif + INCLUDE_SA = false endif endif @@ -404,7 +403,6 @@ else JDK_UPDATE_VER := 0 endif -JDK_VER = $(JDK_MINOR_VERSION),$(JDK_MICRO_VERSION),$(JDK_UPDATE_VER),$(COOKED_BUILD_NUMBER) RC_FLAGS = /l 0x409 /r @@ -414,15 +412,23 @@ RC_FLAGS += $(MS_RC_DEBUG_OPTION) endif -ifndef COPYRIGHT_YEAR - COPYRIGHT_YEAR = 2007 -endif +# Values for the RC variables defined in RC_FLAGS +JDK_RC_BUILD_ID = $(FULL_VERSION) +JDK_RC_COMPANY = $(COMPANY_NAME) +JDK_RC_COMPONENT = $(PRODUCT_NAME) $(JDK_RC_PLATFORM_NAME) binary +JDK_RC_VER = \ + $(JDK_MINOR_VERSION).$(JDK_MICRO_VERSION).$(JDK_UPDATE_VER).$(COOKED_BUILD_NUMBER) +JDK_RC_COPYRIGHT = Copyright \xA9 $(COPYRIGHT_YEAR) +JDK_RC_NAME = \ + $(PRODUCT_NAME) $(JDK_RC_PLATFORM_NAME) $(JDK_MINOR_VERSION) $(JDK_UPDATE_META_TAG) +JDK_RC_FVER = \ + $(JDK_MINOR_VERSION),$(JDK_MICRO_VERSION),$(JDK_UPDATE_VER),$(COOKED_BUILD_NUMBER) # J2SE name required here -RC_FLAGS += -d "J2SE_BUILD_ID=$(FULL_VERSION)" \ - -d "J2SE_COMPANY=$(COMPANY_NAME)" \ - -d "J2SE_COMPONENT=$(PRODUCT_NAME) Platform SE binary" \ - -d "J2SE_VER=$(JDK_MINOR_VERSION).$(JDK_MICRO_VERSION).$(JDK_UPDATE_VER).$(COOKED_BUILD_NUMBER)" \ - -d "J2SE_COPYRIGHT=Copyright \xA9 $(COPYRIGHT_YEAR)" \ - -d "J2SE_NAME=$(PRODUCT_NAME) Platform SE $(JDK_MINOR_VERSION) $(JDK_UPDATE_META_TAG)" \ - -d "J2SE_FVER=$(JDK_VER)" +RC_FLAGS += -d "J2SE_BUILD_ID=$(JDK_RC_BUILD_ID)" \ + -d "J2SE_COMPANY=$(JDK_RC_COMPANY)" \ + -d "J2SE_COMPONENT=$(JDK_RC_COMPONENT)" \ + -d "J2SE_VER=$(JDK_RC_VER)" \ + -d "J2SE_COPYRIGHT=$(JDK_RC_COPYRIGHT)" \ + -d "J2SE_NAME=$(JDK_RC_NAME)" \ + -d "J2SE_FVER=$(JDK_RC_FVER)"
--- a/jdk/make/common/Defs.gmk Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/common/Defs.gmk Wed Jul 05 16:39:18 2017 +0200 @@ -703,7 +703,7 @@ ifdef ALT_COPYRIGHT_YEAR COPYRIGHT_YEAR = $(ALT_COPYRIGHT_YEAR) else - COPYRIGHT_YEAR = $(shell $(DATE) '+%Y') + COPYRIGHT_YEAR := $(shell $(DATE) '+%Y') endif # Install of imported file (JDK_IMPORT_PATH, or some other external location)
--- a/jdk/make/common/shared/Compiler-gcc.gmk Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/common/shared/Compiler-gcc.gmk Wed Jul 05 16:39:18 2017 +0200 @@ -73,23 +73,18 @@ REQUIRED_CC_VER = 4.0 REQUIRED_GCC_VER = 4.0.* else - ifeq ($(ARCH_DATA_MODEL), 32) - # i586 REQUIRED_CC_VER = 3.2 - REQUIRED_GCC_VER = 3.2.1* - REQUIRED_GCC_VER_INT = 3.2.1-7a - else - ifeq ($(ARCH), amd64) - # amd64 - REQUIRED_CC_VER = 3.2 - REQUIRED_GCC_VER = 3.2.* - endif - ifeq ($(ARCH), ia64) - # ia64 - REQUIRED_CC_VER = 3.2 - REQUIRED_GCC_VER = 2.9[56789].* - endif - endif + ifeq ($(ARCH_DATA_MODEL), 32) + REQUIRED_GCC_VER = 3.2.1* + REQUIRED_GCC_VER_INT = 3.2.1-7a + else + ifeq ($(ARCH), amd64) + REQUIRED_GCC_VER = 3.2.* + endif + ifeq ($(ARCH), ia64) + REQUIRED_GCC_VER = 2.9[56789].* + endif + endif endif # Option used to create a shared library SHARED_LIBRARY_FLAG = -shared -mimpure-text
--- a/jdk/make/common/shared/Defs-java.gmk Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/common/shared/Defs-java.gmk Wed Jul 05 16:39:18 2017 +0200 @@ -107,7 +107,10 @@ ifeq ($(DEBUG_CLASSFILES),true) JAVACFLAGS += -g endif -ifeq ($(COMPILER_WARNINGS_FATAL), true) +ifeq ($(JAVAC_MAX_WARNINGS), true) + JAVACFLAGS += -Xlint:all +endif +ifeq ($(JAVAC_WARNINGS_FATAL), true) JAVACFLAGS += -Werror endif @@ -180,7 +183,10 @@ # The javac options supplied to the boot javac is limited. This compiler # should only be used to build the 'make/tools' sources, which are not # class files that end up in the classes directory. -ifeq ($(COMPILER_WARNINGS_FATAL), true) +ifeq ($(JAVAC_MAX_WARNINGS), true) + BOOT_JAVACFLAGS += -Xlint:all +endif +ifeq ($(JAVAC_WARNINGS_FATAL), true) BOOT_JAVACFLAGS += -Werror endif BOOT_JAVACFLAGS += -encoding ascii
--- a/jdk/make/common/shared/Defs.gmk Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/common/shared/Defs.gmk Wed Jul 05 16:39:18 2017 +0200 @@ -188,16 +188,18 @@ endif # Default names -LAUNCHER_NAME = java -PRODUCT_NAME = Java(TM) -PRODUCT_SUFFIX = SE Runtime Environment -COMPANY_NAME = Sun Microsystems, Inc. - ifdef OPENJDK LAUNCHER_NAME = openjdk PRODUCT_NAME = OpenJDK PRODUCT_SUFFIX = Runtime Environment - COMPANY_NAME = + JDK_RC_PLATFORM_NAME = Platform + COMPANY_NAME = N/A +else + LAUNCHER_NAME = java + PRODUCT_NAME = Java(TM) + PRODUCT_SUFFIX = SE Runtime Environment + JDK_RC_PLATFORM_NAME = Platform SE + COMPANY_NAME = Sun Microsystems, Inc. endif RUNTIME_NAME = $(PRODUCT_NAME) $(PRODUCT_SUFFIX)
--- a/jdk/make/common/shared/Platform.gmk Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/common/shared/Platform.gmk Wed Jul 05 16:39:18 2017 +0200 @@ -373,35 +373,41 @@ REQUIRED_DXSDK_VER = 0x0700 OS_VENDOR = Microsoft # How much RAM does this machine have: - ifeq ($(USING_CYGWIN),true) - # CYGWIN has the 'free' utility - _MB_OF_MEMORY := \ - $(shell free -m | grep Mem: | awk '{print $$2;}' ) - else - # Windows 2000 has the mem utility, but two memory areas - # extended memory is what is beyond 1024M - _B_OF_EXT_MEMORY := \ - $(shell mem 2> $(DEV_NULL) | grep 'total contiguous extended memory' | awk '{print $$1;}') - ifeq ($(_B_OF_EXT_MEMORY),) - _B_OF_MEMORY := \ - $(shell mem 2> $(DEV_NULL) | grep 'total conventional memory' | awk '{print $$1;}') + ifeq ($(JDK_HAS_MEM_INFO),) + ifeq ($(USING_CYGWIN),true) + # CYGWIN has the 'free' utility + _MB_OF_MEMORY := \ + $(shell free -m | grep Mem: | awk '{print $$2;}' ) else - _B_OF_MEMORY := \ - $(shell expr 1048576 '+' $(_B_OF_EXT_MEMORY) 2> $(DEV_NULL)) + # Windows 2000 has the mem utility, but two memory areas + # extended memory is what is beyond 1024M + _B_OF_EXT_MEMORY := \ + $(shell mem 2> $(DEV_NULL) | \ + grep 'total contiguous extended memory' | awk '{print $$1;}') + ifeq ($(_B_OF_EXT_MEMORY),) + _B_OF_MEMORY := \ + $(shell mem 2> $(DEV_NULL) | \ + grep 'total conventional memory' | awk '{print $$1;}') + else + _B_OF_MEMORY := \ + $(shell expr 1048576 '+' $(_B_OF_EXT_MEMORY) 2> $(DEV_NULL)) + endif + ifeq ($(_B_OF_MEMORY),) + # Windows 2003 has the systeminfo utility use it if mem doesn't work + _MB_OF_MEMORY := \ + $(shell systeminfo 2> $(DEV_NULL) | \ + grep 'Total Physical Memory:' | \ + awk '{print $$4;}' | sed -e 's@,@@') + else + _MB_OF_MEMORY := $(shell expr $(_B_OF_MEMORY) '/' 1024 2> $(DEV_NULL)) + endif endif - ifeq ($(_B_OF_MEMORY),) - # Windows 2003 has the systeminfo utility use it if mem doesn't work - _MB_OF_MEMORY := \ - $(shell systeminfo 2> $(DEV_NULL) | grep 'Total Physical Memory:' | awk '{print $$4;}' | sed -e 's@,@@') + ifeq ($(shell expr $(_MB_OF_MEMORY) '+' 0 2> $(DEV_NULL)), $(_MB_OF_MEMORY)) + MB_OF_MEMORY := $(_MB_OF_MEMORY) else - _MB_OF_MEMORY := $(shell expr $(_B_OF_MEMORY) '/' 1024 2> $(DEV_NULL)) + MB_OF_MEMORY := 512 endif endif - ifeq ($(shell expr $(_MB_OF_MEMORY) '+' 0 2> $(DEV_NULL)), $(_MB_OF_MEMORY)) - MB_OF_MEMORY := $(_MB_OF_MEMORY) - else - MB_OF_MEMORY := 512 - endif endif REQUIRED_ZIP_VER = 2.2 @@ -446,30 +452,38 @@ # system swapping during the build. # If we don't know, assume 512. Subtract 128 from MB for VM MAX. # Don't set VM max over 1024-128=896. -ifneq ($(MB_OF_MEMORY),) - LOW_MEMORY_MACHINE := $(shell \ - if [ $(MB_OF_MEMORY) -le 512 ] ; then \ - echo "true"; \ - else \ - echo "false"; \ - fi) - MAX_VM_MEMORY := $(shell \ - if [ $(MB_OF_MEMORY) -le 1024 ] ; then \ - expr $(MB_OF_MEMORY) '-' 128 2> $(DEV_NULL) ; \ - else \ - echo "896"; \ - fi) - MIN_VM_MEMORY := $(shell \ - if [ $(MAX_VM_MEMORY) -le 128 ] ; then \ - expr $(MAX_VM_MEMORY) '-' 8 2> $(DEV_NULL) ; \ - else \ - echo "128"; \ - fi) -else - MB_OF_MEMORY := unknown - LOW_MEMORY_MACHINE := true - MAX_VM_MEMORY := 384 - MIN_VM_MEMORY := 128 +ifeq ($(JDK_HAS_MEM_INFO),) + JDK_HAS_MEM_INFO=true + export JDK_HAS_MEM_INFO + ifneq ($(MB_OF_MEMORY),) + LOW_MEMORY_MACHINE := $(shell \ + if [ $(MB_OF_MEMORY) -le 512 ] ; then \ + echo "true"; \ + else \ + echo "false"; \ + fi) + MAX_VM_MEMORY := $(shell \ + if [ $(MB_OF_MEMORY) -le 1024 ] ; then \ + expr $(MB_OF_MEMORY) '-' 128 2> $(DEV_NULL) ; \ + else \ + echo "896"; \ + fi) + MIN_VM_MEMORY := $(shell \ + if [ $(MAX_VM_MEMORY) -le 128 ] ; then \ + expr $(MAX_VM_MEMORY) '-' 8 2> $(DEV_NULL) ; \ + else \ + echo "128"; \ + fi) + else + MB_OF_MEMORY := unknown + LOW_MEMORY_MACHINE := true + MAX_VM_MEMORY := 384 + MIN_VM_MEMORY := 128 + endif + export MB_OF_MEMORY + export LOW_MEMORY_MACHINE + export MAX_VM_MEMORY + export MIN_VM_MEMORY endif # If blanks in the username, use the first 4 words and pack them together
--- a/jdk/make/java/fdlibm/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/java/fdlibm/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -46,8 +46,6 @@ _OPT = $(CC_NO_OPT) OTHER_CFLAGS = CPPFLAGS_DBG += -DLOGGING - # Files built here do not compile with warning level 3 if warnings are fatal - COMPILER_WARNINGS_FATAL=false endif #
--- a/jdk/make/java/hpi/windows/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/java/hpi/windows/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -37,8 +37,6 @@ # windows compiler flags ifeq ($(PLATFORM),windows) CPPFLAGS_DBG += -DLOGGING - # Files built here do not compile with warning level 3 if warnings are fatal - COMPILER_WARNINGS_FATAL=false endif FILES_c = \
--- a/jdk/make/java/java/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/java/java/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -37,8 +37,6 @@ # windows compiler flags ifeq ($(PLATFORM),windows) OTHER_CFLAGS = - # Files built here do not compile with warning level 3 if warnings are fatal - COMPILER_WARNINGS_FATAL=false # build directly into BINDIR... LIB_LOCATION = $(BINDIR) # Exported functions
--- a/jdk/make/java/java_crw_demo/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/java/java_crw_demo/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -48,11 +48,6 @@ OTHER_INCLUDES = -I$(SRCDIR) # -# This removes all asserts in the optimized version -# -CPPFLAGS_OPT += -DNDEBUG - -# # Library to compile. # include $(BUILDDIR)/common/Library.gmk
--- a/jdk/make/java/java_hprof_demo/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/java/java_hprof_demo/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -92,11 +92,6 @@ INIT += $(LIBDIR)/jvm.hprof.txt # -# This removes all asserts in the optimized version -# -CPPFLAGS_OPT += -DNDEBUG - -# # This puts logging code in # CPPFLAGS_DBG += -DHPROF_LOGGING
--- a/jdk/make/java/jli/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/java/jli/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -115,9 +115,6 @@ -export:JLI_ManifestIterate \ -export:JLI_SetTraceLauncher - # Files from zlib built here do not compile with warning level 3 - # if warnings are fatal - COMPILER_WARNINGS_FATAL=false endif OTHER_INCLUDES += -I$(LAUNCHER_SHARE_SRC)
--- a/jdk/make/java/net/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/java/net/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -94,8 +94,6 @@ ifeq ($(PLATFORM), windows) OTHER_LDLIBS = ws2_32.lib $(JVMLIB) - # Will not compile at warning level 3 if warnings are fatal - COMPILER_WARNINGS_FATAL=false else OTHER_LDLIBS = $(LIBSOCKET) -lnsl -ldl $(JVMLIB) endif
--- a/jdk/make/java/nio/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/java/nio/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -134,7 +134,6 @@ $(OBJDIR)/../../../java.lang/java/$(OBJDIRNAME)/FileDescriptor_md.obj endif ifeq ($(PLATFORM), linux) -COMPILER_WARNINGS_FATAL=true OTHER_LDLIBS += -L$(LIBDIR)/$(LIBARCH) -ljava -lnet -lpthread -ldl endif ifeq ($(PLATFORM), solaris)
--- a/jdk/make/java/npt/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/java/npt/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -53,11 +53,6 @@ OTHER_INCLUDES = -I$(SRCDIR) -I$(PSRCDIR) # -# This removes all asserts in the optimized version -# -CPPFLAGS_OPT += -DNDEBUG - -# # Library to compile. # include $(BUILDDIR)/common/Library.gmk
--- a/jdk/make/java/verify/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/java/verify/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -43,8 +43,6 @@ # JAVALIB = EXTRA_LIBS = - # Files built here do not compile with warning level 3 if warnings are fatal - COMPILER_WARNINGS_FATAL=false endif #
--- a/jdk/make/java/zip/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/java/zip/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -49,9 +49,6 @@ ifneq ($(PLATFORM), windows) OTHER_CFLAGS += -DUSE_MMAP -else - # Files built here do not compile with warning level 3 if warnings are fatal - COMPILER_WARNINGS_FATAL=false endif #
--- a/jdk/make/jpda/back/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/jpda/back/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -53,11 +53,6 @@ endif # PLATFORM # -# This turns off all assert() checking in the optimized library -# -CPPFLAGS_OPT += -DNDEBUG - -# # This controls the ability to do logging in the library. # CPPFLAGS_DBG += -DJDWP_LOGGING
--- a/jdk/make/jpda/transport/shmem/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/jpda/transport/shmem/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -36,13 +36,6 @@ include $(BUILDDIR)/common/Defs.gmk -# 64-bit windows does not build at -W3 if warnings are fatal -ifeq ($(PLATFORM), windows) - ifeq ($(ARCH_DATA_MODEL), 64) - COMPILER_WARNINGS_FATAL=false - endif -endif - FILES_c = \ SharedMemoryTransport.c \ SharedMemoryConnection.c \
--- a/jdk/make/jpda/transport/socket/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/jpda/transport/socket/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -36,11 +36,6 @@ include $(BUILDDIR)/common/Defs.gmk -ifeq ($(PLATFORM), windows) - # Files built here do not compile with warning level 3 if warnings are fatal - COMPILER_WARNINGS_FATAL=false -endif - ifeq ($(PLATFORM), linux) OTHER_LDLIBS += -lnsl $(LIBSOCKET) -lpthread endif
--- a/jdk/make/sun/cmm/kcms/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/sun/cmm/kcms/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -47,8 +47,6 @@ ifeq ($(PLATFORM), windows) # Override the default version info with our own resource file (see 5043594) VERSIONINFO_RESOURCE = $(CLOSED_SRC)/share/native/sun/java2d/cmm/kcms/cmm.rc - # Files built here do not compile with warning level 3 if warnings are fatal - COMPILER_WARNINGS_FATAL=false endif # Rules
--- a/jdk/make/sun/font/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/sun/font/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -77,9 +77,6 @@ ifeq ($(PLATFORM), windows) - # Files built here do not compile with warning level 3 if warnings are fatal - COMPILER_WARNINGS_FATAL=false - LDLIBS += user32.lib gdi32.lib $(OBJDIR)/../../../sun.awt/awt/$(OBJDIRNAME)/awt.lib OTHER_CFLAGS += -DCC_NOEX
--- a/jdk/make/sun/font/t2k/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/sun/font/t2k/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -64,9 +64,6 @@ ifeq ($(PLATFORM), windows) - # Files built here do not compile with warning level 3 if warnings are fatal - COMPILER_WARNINGS_FATAL=false - # t2k imports several shared methods from fontmanager.dll LDLIBS += user32.lib $(OBJDIR)/../../../sun.font/fontmanager/$(OBJDIRNAME)/fontmanager.lib
--- a/jdk/make/sun/jdbc/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/sun/jdbc/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -69,11 +69,6 @@ INIT += $(ODBC_FAKE_LIBRARIES) endif -ifeq ($(PLATFORM),windows) - # Files built here do not compile with warning level 3 if warnings are fatal - COMPILER_WARNINGS_FATAL=false -endif - # # Rules #
--- a/jdk/make/sun/jpeg/Makefile Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/make/sun/jpeg/Makefile Wed Jul 05 16:39:18 2017 +0200 @@ -73,10 +73,5 @@ # vpath %.c $(SHARE_SRC)/native/$(PKGDIR)/image/jpeg -ifeq ($(PLATFORM), windows) - # Files built here do not compile with warning level 3 if warnings are fatal - COMPILER_WARNINGS_FATAL=false -endif # PLATFORM - CLASSES.export += java.io.InputStream
--- a/jdk/src/share/back/eventFilter.c Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/back/eventFilter.c Wed Jul 05 16:39:18 2017 +0200 @@ -492,14 +492,17 @@ char *sourceName = 0; jvmtiError error = JVMTI_FUNC_PTR(gdata->jvmti,GetSourceFileName) (gdata->jvmti, clazz, &sourceName); - if (error == JVMTI_ERROR_NONE) { - if (sourceName == 0 || !patternStringMatch(sourceName, desiredNamePattern)) { - /* We have no match */ - jvmtiDeallocate(sourceName); - return JNI_FALSE; - } + if (error == JVMTI_ERROR_NONE && + sourceName != 0 && + patternStringMatch(sourceName, desiredNamePattern)) { + // got a hit - report the event + jvmtiDeallocate(sourceName); + break; } + // We have no match, we have no source file name, + // or we got a JVM TI error. Don't report the event. jvmtiDeallocate(sourceName); + return JNI_FALSE; } break; }
--- a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java Wed Jul 05 16:39:18 2017 +0200 @@ -84,8 +84,13 @@ 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; /** * This is the default class for MBean manipulation on the agent side. It @@ -433,36 +438,26 @@ if (instance instanceof MBeanRegistration) preDeregisterInvoke((MBeanRegistration) instance); - repository.remove(name); - // may throw InstanceNotFoundException - - /** - * Checks if the unregistered MBean is a ClassLoader - * If so, it removes the MBean from the default loader repository. - */ + final Object resource = getResource(instance); - Object resource = getResource(instance); - if (resource instanceof ClassLoader - && resource != server.getClass().getClassLoader()) { - final ModifiableClassLoaderRepository clr = - instantiator.getClassLoaderRepository(); - if (clr != null) clr.removeClassLoader(name); - } + // Unregisters the MBean from the repository. + // Returns the resource context that was used. + // The returned context does nothing for regular MBeans. + // For ClassLoader MBeans and JMXNamespace (and JMXDomain) + // MBeans - the context makes it possible to unregister these + // objects from the appropriate framework artifacts, such as + // the CLR or the dispatcher, from within the repository lock. + // In case of success, we also need to call context.done() at the + // end of this method. + // + final ResourceContext context = + unregisterFromRepository(resource, instance, name); - // --------------------- - // Send deletion event - // --------------------- - if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { - MBEANSERVER_LOGGER.logp(Level.FINER, - DefaultMBeanServerInterceptor.class.getName(), - "unregisterMBean", "Send delete notification of object " + - name.getCanonicalName()); - } - sendNotification(MBeanServerNotification.UNREGISTRATION_NOTIFICATION, - name); if (instance instanceof MBeanRegistration) postDeregisterInvoke((MBeanRegistration) instance); + + context.done(); } public ObjectInstance getObjectInstance(ObjectName name) @@ -939,15 +934,22 @@ } ObjectName logicalName = name; + logicalName = preRegister(mbean, server, name); - if (mbean instanceof MBeanRegistration) { - MBeanRegistration reg = (MBeanRegistration) mbean; - logicalName = preRegisterInvoke(reg, name, server); + // preRegister returned successfully, so from this point on we + // must call postRegister(false) if there is any problem. + boolean registered = false; + boolean registerFailed = false; + ResourceContext context = null; + + try { + mbean = injectResources(mbean, server, logicalName); + if (mbean instanceof DynamicMBean2) { try { ((DynamicMBean2) mbean).preRegister2(server, logicalName); + registerFailed = true; // until we succeed } catch (Exception e) { - postRegisterInvoke(reg, false, false); if (e instanceof RuntimeException) throw (RuntimeException) e; if (e instanceof InstanceAlreadyExistsException) @@ -960,86 +962,102 @@ logicalName = ObjectName.getInstance(nonDefaultDomain(logicalName)); } - } + + checkMBeanPermission(classname, null, logicalName, "registerMBean"); - checkMBeanPermission(classname, null, logicalName, "registerMBean"); + if (logicalName == null) { + final RuntimeException wrapped = + new IllegalArgumentException("No object name specified"); + throw new RuntimeOperationsException(wrapped, + "Exception occurred trying to register the MBean"); + } + + final Object resource = getResource(mbean); - final ObjectInstance result; - if (logicalName!=null) { - result = new ObjectInstance(logicalName, classname); - internal_addObject(mbean, logicalName); - } else { - if (mbean instanceof MBeanRegistration) - postRegisterInvoke((MBeanRegistration) mbean, false, true); - final RuntimeException wrapped = - new IllegalArgumentException("No object name specified"); - throw new RuntimeOperationsException(wrapped, - "Exception occurred trying to register the MBean"); + // Register the MBean with the repository. + // Returns the resource context that was used. + // The returned context does nothing for regular MBeans. + // For ClassLoader MBeans and JMXNamespace (and JMXDomain) + // MBeans - the context makes it possible to register these + // objects with the appropriate framework artifacts, such as + // the CLR or the dispatcher, from within the repository lock. + // In case of success, we also need to call context.done() at the + // end of this method. + // + context = registerWithRepository(resource, mbean, logicalName); + + registerFailed = false; + registered = true; + } finally { + postRegister(mbean, registered, registerFailed); } - if (mbean instanceof MBeanRegistration) - postRegisterInvoke((MBeanRegistration) mbean, true, false); - - /** - * Checks if the newly registered MBean is a ClassLoader - * If so, tell the ClassLoaderRepository (CLR) about it. We do - * this even if the object is a PrivateClassLoader. In that - * case, the CLR remembers the loader for use when it is - * explicitly named (e.g. as the loader in createMBean) but - * does not add it to the list that is consulted by - * ClassLoaderRepository.loadClass. - */ - final Object resource = getResource(mbean); - if (resource instanceof ClassLoader) { - final ModifiableClassLoaderRepository clr = - instantiator.getClassLoaderRepository(); - if (clr == null) { - final RuntimeException wrapped = - new IllegalArgumentException( - "Dynamic addition of class loaders is not supported"); - throw new RuntimeOperationsException(wrapped, - "Exception occurred trying to register the MBean as a class loader"); - } - clr.addClassLoader(logicalName, (ClassLoader) resource); - } - - return result; + context.done(); + return new ObjectInstance(logicalName, classname); } - private static ObjectName preRegisterInvoke(MBeanRegistration moi, - ObjectName name, - MBeanServer mbs) - throws InstanceAlreadyExistsException, MBeanRegistrationException { - - final ObjectName newName; - + private static void throwMBeanRegistrationException(Throwable t, String where) + throws MBeanRegistrationException { try { - newName = moi.preRegister(mbs, name); + throw t; } catch (RuntimeException e) { - throw new RuntimeMBeanException(e, - "RuntimeException thrown in preRegister method"); + throw new RuntimeMBeanException( + e, "RuntimeException thrown " + where); } catch (Error er) { - throw new RuntimeErrorException(er, - "Error thrown in preRegister method"); + throw new RuntimeErrorException(er, "Error thrown " + where); } catch (MBeanRegistrationException r) { throw r; } catch (Exception ex) { - throw new MBeanRegistrationException(ex, - "Exception thrown in preRegister method"); + throw new MBeanRegistrationException(ex, "Exception thrown " + where); + } catch (Throwable t1) { + throw new RuntimeException(t); // neither Error nor Exception?? + } + } + + private static ObjectName preRegister( + DynamicMBean mbean, MBeanServer mbs, ObjectName name) + throws InstanceAlreadyExistsException, MBeanRegistrationException { + + ObjectName newName = null; + + try { + if (mbean instanceof MBeanRegistration) + newName = ((MBeanRegistration) mbean).preRegister(mbs, name); + } catch (Throwable t) { + throwMBeanRegistrationException(t, "in preRegister method"); } if (newName != null) return newName; else return name; } - private static void postRegisterInvoke(MBeanRegistration moi, - boolean registrationDone, - boolean registerFailed) { + private static DynamicMBean injectResources( + DynamicMBean mbean, MBeanServer mbs, ObjectName name) + throws MBeanRegistrationException { + try { + Object resource = getResource(mbean); + MBeanInjector.inject(resource, mbs, name); + if (MBeanInjector.injectsSendNotification(resource)) { + NotificationBroadcasterSupport nbs = + new NotificationBroadcasterSupport(); + MBeanInjector.injectSendNotification(resource, nbs); + mbean = NotifySupport.wrap(mbean, nbs); + } + return mbean; + } catch (Throwable t) { + throwMBeanRegistrationException(t, "injecting @Resources"); + return null; // not reached + } + } - if (registerFailed && moi instanceof DynamicMBean2) - ((DynamicMBean2) moi).registerFailed(); + private static void postRegister( + DynamicMBean mbean, boolean registrationDone, boolean registerFailed) { + + if (registerFailed && mbean instanceof DynamicMBean2) + ((DynamicMBean2) mbean).registerFailed(); try { - moi.postRegister(registrationDone); + if (mbean instanceof MBeanRegistration) + ((MBeanRegistration) mbean).postRegister(registrationDone); } catch (RuntimeException e) { throw new RuntimeMBeanException(e, "RuntimeException thrown in postRegister method"); @@ -1053,17 +1071,8 @@ throws MBeanRegistrationException { try { moi.preDeregister(); - } catch (RuntimeException e) { - throw new RuntimeMBeanException(e, - "RuntimeException thrown in preDeregister method"); - } catch (Error er) { - throw new RuntimeErrorException(er, - "Error thrown in preDeregister method"); - } catch (MBeanRegistrationException t) { - throw t; - } catch (Exception ex) { - throw new MBeanRegistrationException(ex, - "Exception thrown in preDeregister method"); + } catch (Throwable t) { + throwMBeanRegistrationException(t, "in preDeregister method"); } } @@ -1104,12 +1113,19 @@ } private static Object getResource(DynamicMBean mbean) { - if (mbean instanceof DynamicMBean2) - return ((DynamicMBean2) mbean).getResource(); + if (mbean instanceof DynamicWrapperMBean) + return ((DynamicWrapperMBean) mbean).getWrappedObject(); else return mbean; } + private static ClassLoader getResourceLoader(DynamicMBean mbean) { + if (mbean instanceof DynamicWrapperMBean) + return ((DynamicWrapperMBean) mbean).getWrappedClassLoader(); + else + return mbean.getClass().getClassLoader(); + } + private ObjectName nonDefaultDomain(ObjectName name) { if (name == null || name.getDomain().length() > 0) return name; @@ -1123,14 +1139,7 @@ if one is supplied where it shouldn't be). */ final String completeName = domain + name; - try { - return new ObjectName(completeName); - } catch (MalformedObjectNameException e) { - final String msg = - "Unexpected default domain problem: " + completeName + ": " + - e; - throw EnvHelp.initCause(new IllegalArgumentException(msg), e); - } + return Util.newObjectName(completeName); } public String getDefaultDomain() { @@ -1211,7 +1220,7 @@ } NotificationListener listenerWrapper = - getListenerWrapper(listener, name, broadcaster, true); + getListenerWrapper(listener, name, instance, true); broadcaster.addNotificationListener(listenerWrapper, filter, handback); } @@ -1335,7 +1344,6 @@ DynamicMBean instance = getMBean(name); checkMBeanPermission(instance, null, name, "removeNotificationListener"); - Object resource = getResource(instance); /* We could simplify the code by assigning broadcaster after assigning listenerWrapper, but that would change the error @@ -1348,7 +1356,7 @@ getNotificationBroadcaster(name, instance, reqClass); NotificationListener listenerWrapper = - getListenerWrapper(listener, name, resource, false); + getListenerWrapper(listener, name, instance, false); if (listenerWrapper == null) throw new ListenerNotFoundException("Unknown listener"); @@ -1366,8 +1374,10 @@ private static <T extends NotificationBroadcaster> T getNotificationBroadcaster(ObjectName name, Object instance, Class<T> reqClass) { - if (instance instanceof DynamicMBean2) - instance = ((DynamicMBean2) instance).getResource(); + if (reqClass.isInstance(instance)) + return reqClass.cast(instance); + if (instance instanceof DynamicWrapperMBean) + instance = ((DynamicWrapperMBean) instance).getWrappedObject(); if (reqClass.isInstance(instance)) return reqClass.cast(instance); final RuntimeException exc = @@ -1415,24 +1425,31 @@ checkMBeanPermission(instance, null, name, "isInstanceOf"); try { - if (instance instanceof DynamicMBean2) { - Object resource = ((DynamicMBean2) instance).getResource(); - ClassLoader loader = resource.getClass().getClassLoader(); - Class<?> c = Class.forName(className, false, loader); - return c.isInstance(resource); - } + Object resource = getResource(instance); - final String cn = getClassName(instance); - if (cn.equals(className)) + final String resourceClassName = + (resource instanceof DynamicMBean) ? + getClassName((DynamicMBean) resource) : + resource.getClass().getName(); + + if (resourceClassName.equals(className)) return true; - final ClassLoader cl = instance.getClass().getClassLoader(); + final ClassLoader cl = getResourceLoader(instance); final Class<?> classNameClass = Class.forName(className, false, cl); - if (classNameClass.isInstance(instance)) + if (classNameClass.isInstance(resource)) return true; - final Class<?> instanceClass = Class.forName(cn, false, cl); - return classNameClass.isAssignableFrom(instanceClass); + // Ensure that isInstanceOf(NotificationEmitter) is true when + // the MBean is a NotificationEmitter by virtue of a @Resource + // annotation specifying a SendNotification resource. + // This is a hack. + if (instance instanceof NotificationBroadcaster && + classNameClass.isAssignableFrom(NotificationEmitter.class)) + return true; + + final Class<?> resourceClass = Class.forName(resourceClassName, false, cl); + return classNameClass.isAssignableFrom(resourceClass); } catch (Exception x) { /* Could be SecurityException or ClassNotFoundException */ if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) { @@ -1457,7 +1474,7 @@ DynamicMBean instance = getMBean(mbeanName); checkMBeanPermission(instance, null, mbeanName, "getClassLoaderFor"); - return getResource(instance).getClass().getClassLoader(); + return getResourceLoader(instance); } /** @@ -1489,40 +1506,6 @@ } /** - * Adds a MBean in the repository - */ - private void internal_addObject(DynamicMBean object, ObjectName logicalName) - throws InstanceAlreadyExistsException { - - // ------------------------------ - // ------------------------------ - - // Let the repository do the work. - - try { - repository.addMBean(object, logicalName); - } catch (InstanceAlreadyExistsException e) { - if (object instanceof MBeanRegistration) { - postRegisterInvoke((MBeanRegistration) object, false, true); - } - throw e; - } - - // --------------------- - // Send create event - // --------------------- - if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { - MBEANSERVER_LOGGER.logp(Level.FINER, - DefaultMBeanServerInterceptor.class.getName(), - "addObject", "Send create notification of object " + - logicalName.getCanonicalName()); - } - - sendNotification(MBeanServerNotification.REGISTRATION_NOTIFICATION, - logicalName ) ; - } - - /** * Sends an MBeanServerNotifications with the specified type for the * MBean with the specified ObjectName */ @@ -1712,9 +1695,10 @@ */ private NotificationListener getListenerWrapper(NotificationListener l, ObjectName name, - Object mbean, + DynamicMBean mbean, boolean create) { - ListenerWrapper wrapper = new ListenerWrapper(l, name, mbean); + Object resource = getResource(mbean); + ListenerWrapper wrapper = new ListenerWrapper(l, name, resource); synchronized (listenerWrappers) { WeakReference<ListenerWrapper> ref = listenerWrappers.get(wrapper); if (ref != null) { @@ -1758,6 +1742,7 @@ listener.handleNotification(notification, handback); } + @Override public boolean equals(Object o) { if (!(o instanceof ListenerWrapper)) return false; @@ -1774,6 +1759,7 @@ */ } + @Override public int hashCode() { return (System.identityHashCode(listener) ^ System.identityHashCode(mbean)); @@ -1851,4 +1837,213 @@ } } + // ------------------------------------------------------------------ + // + // Dealing with registration of special MBeans in the repository. + // + // ------------------------------------------------------------------ + + /** + * A RegistrationContext that makes it possible to perform additional + * post registration actions (or post unregistration actions) outside + * of the repository lock, once postRegister (or postDeregister) has + * been called. + * The method {@code done()} will be called in registerMBean or + * unregisterMBean, at the end. + */ + private static interface ResourceContext extends RegistrationContext { + public void done(); + /** An empty ResourceContext which does nothing **/ + public static final ResourceContext NONE = new ResourceContext() { + public void done() {} + public void registering() {} + public void unregistered() {} + }; + } + + /** + * Adds a MBean in the repository, + * sends MBeanServerNotification.REGISTRATION_NOTIFICATION, + * returns ResourceContext for special resources such as ClassLoaders + * or JMXNamespaces. For regular MBean this method returns + * ResourceContext.NONE. + * @return a ResourceContext for special resources such as ClassLoaders + * or JMXNamespaces. + */ + private ResourceContext registerWithRepository( + final Object resource, + final DynamicMBean object, + final ObjectName logicalName) + throws InstanceAlreadyExistsException, + MBeanRegistrationException { + + // Creates a registration context, if needed. + // + final ResourceContext context = + makeResourceContextFor(resource, logicalName); + + + repository.addMBean(object, logicalName, context); + // May throw InstanceAlreadyExistsException + + // --------------------- + // Send create event + // --------------------- + if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { + MBEANSERVER_LOGGER.logp(Level.FINER, + DefaultMBeanServerInterceptor.class.getName(), + "addObject", "Send create notification of object " + + logicalName.getCanonicalName()); + } + + sendNotification( + MBeanServerNotification.REGISTRATION_NOTIFICATION, + logicalName); + + return context; + } + + /** + * Removes a MBean in the repository, + * sends MBeanServerNotification.UNREGISTRATION_NOTIFICATION, + * returns ResourceContext for special resources such as ClassLoaders + * or JMXNamespaces, or null. For regular MBean this method returns + * ResourceContext.NONE. + * + * @return a ResourceContext for special resources such as ClassLoaders + * or JMXNamespaces. + */ + private ResourceContext unregisterFromRepository( + final Object resource, + final DynamicMBean object, + final ObjectName logicalName) + throws InstanceNotFoundException { + + // Creates a registration context, if needed. + // + final ResourceContext context = + makeResourceContextFor(resource, logicalName); + + + repository.remove(logicalName, context); + + // --------------------- + // Send deletion event + // --------------------- + if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { + MBEANSERVER_LOGGER.logp(Level.FINER, + DefaultMBeanServerInterceptor.class.getName(), + "unregisterMBean", "Send delete notification of object " + + logicalName.getCanonicalName()); + } + + sendNotification(MBeanServerNotification.UNREGISTRATION_NOTIFICATION, + logicalName); + return context; + } + + /** + * Registers a ClassLoader with the CLR. + * This method is called by the ResourceContext from within the + * repository lock. + * @param loader The ClassLoader. + * @param logicalName The ClassLoader MBean ObjectName. + */ + private void addClassLoader(ClassLoader loader, + final ObjectName logicalName) { + /** + * Called when the newly registered MBean is a ClassLoader + * If so, tell the ClassLoaderRepository (CLR) about it. We do + * this even if the loader is a PrivateClassLoader. In that + * case, the CLR remembers the loader for use when it is + * explicitly named (e.g. as the loader in createMBean) but + * does not add it to the list that is consulted by + * ClassLoaderRepository.loadClass. + */ + final ModifiableClassLoaderRepository clr = + instantiator.getClassLoaderRepository(); + if (clr == null) { + final RuntimeException wrapped = + new IllegalArgumentException( + "Dynamic addition of class loaders" + + " is not supported"); + throw new RuntimeOperationsException(wrapped, + "Exception occurred trying to register" + + " the MBean as a class loader"); + } + clr.addClassLoader(logicalName, loader); + } + + /** + * Unregisters a ClassLoader from the CLR. + * This method is called by the ResourceContext from within the + * repository lock. + * @param loader The ClassLoader. + * @param logicalName The ClassLoader MBean ObjectName. + */ + private void removeClassLoader(ClassLoader loader, + final ObjectName logicalName) { + /** + * Removes the MBean from the default loader repository. + */ + if (loader != server.getClass().getClassLoader()) { + final ModifiableClassLoaderRepository clr = + instantiator.getClassLoaderRepository(); + if (clr != null) { + clr.removeClassLoader(logicalName); + } + } + } + + /** + * Creates a ResourceContext for a ClassLoader MBean. + * The resource context makes it possible to add the ClassLoader to + * (ResourceContext.registering) or resp. remove the ClassLoader from + * (ResourceContext.unregistered) the CLR + * when the associated MBean is added to or resp. removed from the + * repository. + * + * @param loader The ClassLoader MBean being registered or + * unregistered. + * @param logicalName The name of the ClassLoader MBean. + * @return a ResourceContext that takes in charge the addition or removal + * of the loader to or from the CLR. + */ + private ResourceContext createClassLoaderContext( + final ClassLoader loader, + final ObjectName logicalName) { + return new ResourceContext() { + + public void registering() { + addClassLoader(loader, logicalName); + } + + public void unregistered() { + removeClassLoader(loader, logicalName); + } + + public void done() { + } + }; + } + + /** + * Creates a ResourceContext for the given resource. + * If the resource does not need a ResourceContext, returns + * ResourceContext.NONE. + * At this time, only JMXNamespaces and ClassLoaders need a + * ResourceContext. + * + * @param resource The resource being registered or unregistered. + * @param logicalName The name of the associated MBean. + * @return + */ + private ResourceContext makeResourceContextFor(Object resource, + ObjectName logicalName) { + if (resource instanceof ClassLoader) { + return createClassLoaderContext((ClassLoader) resource, + logicalName); + } + return ResourceContext.NONE; + } }
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java Wed Jul 05 16:39:18 2017 +0200 @@ -686,7 +686,7 @@ final String msg = "Cannot convert SortedSet with non-null comparator: " + comparator; - throw new OpenDataException(msg); + throw openDataException(msg, new IllegalArgumentException(msg)); } } final Object[] openArray = (Object[]) @@ -800,7 +800,7 @@ final String msg = "Cannot convert SortedMap with non-null comparator: " + comparator; - throw new OpenDataException(msg); + throw openDataException(msg, new IllegalArgumentException(msg)); } } final TabularType tabularType = (TabularType) getOpenType();
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/DynamicMBean2.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/DynamicMBean2.java Wed Jul 05 16:39:18 2017 +0200 @@ -25,7 +25,7 @@ package com.sun.jmx.mbeanserver; -import javax.management.DynamicMBean; +import javax.management.DynamicWrapperMBean; import javax.management.MBeanServer; import javax.management.ObjectName; @@ -35,17 +35,7 @@ * * @since 1.6 */ -public interface DynamicMBean2 extends DynamicMBean { - /** - * The resource corresponding to this MBean. This is the object whose - * class name should be reflected by the MBean's - * getMBeanInfo().getClassName() for example. For a "plain" - * DynamicMBean it will be "this". For an MBean that wraps another - * object, like javax.management.StandardMBean, it will be the wrapped - * object. - */ - public Object getResource(); - +public interface DynamicMBean2 extends DynamicWrapperMBean { /** * The name of this MBean's class, as used by permission checks. * This is typically equal to getResource().getClass().getName().
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java Wed Jul 05 16:39:18 2017 +0200 @@ -25,23 +25,39 @@ package com.sun.jmx.mbeanserver; +import com.sun.jmx.remote.util.EnvHelp; +import java.beans.BeanInfo; +import java.beans.PropertyDescriptor; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Array; import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.logging.Level; +import javax.management.AttributeNotFoundException; +import javax.management.Description; import javax.management.Descriptor; +import javax.management.DescriptorFields; import javax.management.DescriptorKey; import javax.management.DynamicMBean; import javax.management.ImmutableDescriptor; +import javax.management.MBean; import javax.management.MBeanInfo; +import javax.management.MXBean; import javax.management.NotCompliantMBeanException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.MXBeanMappingFactory; +import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER; +import com.sun.jmx.mbeanserver.Util; import com.sun.jmx.remote.util.EnvHelp; import java.beans.BeanInfo; import java.beans.PropertyDescriptor; @@ -133,8 +149,12 @@ } } - public static void checkCompliance(Class mbeanClass) - throws NotCompliantMBeanException { + public static void checkCompliance(Class<?> mbeanClass) + throws NotCompliantMBeanException { + + // Check that @Resource is used correctly (if it used). + MBeanInjector.validate(mbeanClass); + // Is DynamicMBean? // if (DynamicMBean.class.isAssignableFrom(mbeanClass)) @@ -157,21 +177,39 @@ } catch (NotCompliantMBeanException e) { mxbeanException = e; } + // Is @MBean or @MXBean class? + // In fact we find @MBean or @MXBean as a hacky variant of + // getStandardMBeanInterface or getMXBeanInterface. If we get here + // then nothing worked. final String msg = "MBean class " + mbeanClass.getName() + " does not implement " + - "DynamicMBean, neither follows the Standard MBean conventions (" + - mbeanException.toString() + ") nor the MXBean conventions (" + - mxbeanException.toString() + ")"; + "DynamicMBean; does not follow the Standard MBean conventions (" + + mbeanException.toString() + "); does not follow the MXBean conventions (" + + mxbeanException.toString() + "); and does not have or inherit the @" + + MBean.class.getSimpleName() + " or @" + MXBean.class.getSimpleName() + + " annotation"; throw new NotCompliantMBeanException(msg); } + /** + * <p>Make a DynamicMBean out of the existing MBean object. The object + * may already be a DynamicMBean, or it may be a Standard MBean or + * MXBean, possibly defined using {@code @MBean} or {@code @MXBean}.</p> + * @param mbean the object to convert to a DynamicMBean. + * @param <T> a type parameter defined for implementation convenience + * (which would have to be removed if this method were part of the public + * API). + * @return the converted DynamicMBean. + * @throws NotCompliantMBeanException if {@code mbean} is not a compliant + * MBean object, including the case where it is null. + */ public static <T> DynamicMBean makeDynamicMBean(T mbean) throws NotCompliantMBeanException { if (mbean == null) throw new NotCompliantMBeanException("Null MBean object"); if (mbean instanceof DynamicMBean) return (DynamicMBean) mbean; - final Class mbeanClass = mbean.getClass(); + final Class<?> mbeanClass = mbean.getClass(); Class<? super T> c = null; try { c = Util.cast(getStandardMBeanInterface(mbeanClass)); @@ -270,7 +308,7 @@ * Return <code>null</code> if the MBean is a DynamicMBean, * or if no MBean interface is found. */ - public static Class getMBeanInterface(Class baseClass) { + public static Class<?> getMBeanInterface(Class<?> baseClass) { // Check if the given class implements the MBean interface // or the Dynamic MBean interface if (isDynamic(baseClass)) return null; @@ -291,10 +329,12 @@ * @throws NotCompliantMBeanException The specified class is * not a JMX compliant Standard MBean. */ - public static Class getStandardMBeanInterface(Class baseClass) - throws NotCompliantMBeanException { - Class current = baseClass; - Class mbeanInterface = null; + public static <T> Class<? super T> getStandardMBeanInterface(Class<T> baseClass) + throws NotCompliantMBeanException { + if (baseClass.isAnnotationPresent(MBean.class)) + return baseClass; + Class<? super T> current = baseClass; + Class<? super T> mbeanInterface = null; while (current != null) { mbeanInterface = findMBeanInterface(current, current.getName()); @@ -321,8 +361,10 @@ * @throws NotCompliantMBeanException The specified class is * not a JMX compliant MXBean. */ - public static Class getMXBeanInterface(Class baseClass) + public static <T> Class<? super T> getMXBeanInterface(Class<T> baseClass) throws NotCompliantMBeanException { + if (hasMXBeanAnnotation(baseClass)) + return baseClass; try { return MXBeanSupport.findMXBeanInterface(baseClass); } catch (Exception e) { @@ -345,19 +387,24 @@ * ------------------------------------------ */ + static boolean hasMXBeanAnnotation(Class<?> c) { + MXBean m = c.getAnnotation(MXBean.class); + return (m != null && m.value()); + } /** * Try to find the MBean interface corresponding to the class aName * - i.e. <i>aName</i>MBean, from within aClass and its superclasses. **/ - private static Class findMBeanInterface(Class aClass, String aName) { - Class current = aClass; + private static <T> Class<? super T> findMBeanInterface( + Class<T> aClass, String aName) { + Class<? super T> current = aClass; while (current != null) { - final Class[] interfaces = current.getInterfaces(); + final Class<?>[] interfaces = current.getInterfaces(); final int len = interfaces.length; for (int i=0;i<len;i++) { - final Class inter = - implementsMBean(interfaces[i], aName); + Class<? super T> inter = Util.cast(interfaces[i]); + inter = implementsMBean(inter, aName); if (inter != null) return inter; } current = current.getSuperclass(); @@ -365,6 +412,48 @@ return null; } + public static String descriptionForElement(AnnotatedElement elmt) { + if (elmt == null) + return null; + Description d = elmt.getAnnotation(Description.class); + if (d == null) + return null; + return d.value(); + } + + public static String descriptionForParameter( + Annotation[] parameterAnnotations) { + for (Annotation a : parameterAnnotations) { + if (a instanceof Description) + return ((Description) a).value(); + } + return null; + } + + public static String nameForParameter( + Annotation[] parameterAnnotations) { + for (Annotation a : parameterAnnotations) { + Class<? extends Annotation> ac = a.annotationType(); + // You'd really have to go out of your way to have more than + // one @Name annotation, so we don't check for that. + if (ac.getSimpleName().equals("Name")) { + try { + Method value = ac.getMethod("value"); + if (value.getReturnType() == String.class && + value.getParameterTypes().length == 0) { + return (String) value.invoke(a); + } + } catch (Exception e) { + MBEANSERVER_LOGGER.log( + Level.WARNING, + "Unexpected exception getting @" + ac.getName(), + e); + } + } + } + return null; + } + public static Descriptor descriptorForElement(final AnnotatedElement elmt) { if (elmt == null) return ImmutableDescriptor.EMPTY_DESCRIPTOR; @@ -372,41 +461,18 @@ return descriptorForAnnotations(annots); } + public static Descriptor descriptorForAnnotation(Annotation annot) { + return descriptorForAnnotations(new Annotation[] {annot}); + } + public static Descriptor descriptorForAnnotations(Annotation[] annots) { if (annots.length == 0) return ImmutableDescriptor.EMPTY_DESCRIPTOR; Map<String, Object> descriptorMap = new HashMap<String, Object>(); for (Annotation a : annots) { - Class<? extends Annotation> c = a.annotationType(); - Method[] elements = c.getMethods(); - for (Method element : elements) { - DescriptorKey key = element.getAnnotation(DescriptorKey.class); - if (key != null) { - String name = key.value(); - Object value; - try { - value = element.invoke(a); - } catch (RuntimeException e) { - // we don't expect this - except for possibly - // security exceptions? - // RuntimeExceptions shouldn't be "UndeclaredThrowable". - // anyway... - // - throw e; - } catch (Exception e) { - // we don't expect this - throw new UndeclaredThrowableException(e); - } - value = annotationToField(value); - Object oldValue = descriptorMap.put(name, value); - if (oldValue != null && !equals(oldValue, value)) { - final String msg = - "Inconsistent values for descriptor field " + name + - " from annotations: " + value + " :: " + oldValue; - throw new IllegalArgumentException(msg); - } - } - } + if (a instanceof DescriptorFields) + addDescriptorFieldsToMap(descriptorMap, (DescriptorFields) a); + addAnnotationFieldsToMap(descriptorMap, a); } if (descriptorMap.isEmpty()) @@ -415,6 +481,62 @@ return new ImmutableDescriptor(descriptorMap); } + private static void addDescriptorFieldsToMap( + Map<String, Object> descriptorMap, DescriptorFields df) { + for (String field : df.value()) { + int eq = field.indexOf('='); + if (eq < 0) { + throw new IllegalArgumentException( + "@DescriptorFields string must contain '=': " + + field); + } + String name = field.substring(0, eq); + String value = field.substring(eq + 1); + addToMap(descriptorMap, name, value); + } + } + + private static void addAnnotationFieldsToMap( + Map<String, Object> descriptorMap, Annotation a) { + Class<? extends Annotation> c = a.annotationType(); + Method[] elements = c.getMethods(); + for (Method element : elements) { + DescriptorKey key = element.getAnnotation(DescriptorKey.class); + if (key != null) { + String name = key.value(); + Object value; + try { + value = element.invoke(a); + } catch (RuntimeException e) { + // we don't expect this - except for possibly + // security exceptions? + // RuntimeExceptions shouldn't be "UndeclaredThrowable". + // anyway... + throw e; + } catch (Exception e) { + // we don't expect this + throw new UndeclaredThrowableException(e); + } + if (!key.omitIfDefault() || + !equals(value, element.getDefaultValue())) { + value = annotationToField(value); + addToMap(descriptorMap, name, value); + } + } + } + } + + private static void addToMap( + Map<String, Object> descriptorMap, String name, Object value) { + Object oldValue = descriptorMap.put(name, value); + if (oldValue != null && !equals(oldValue, value)) { + final String msg = + "Inconsistent values for descriptor field " + name + + " from annotations: " + value + " :: " + oldValue; + throw new IllegalArgumentException(msg); + } + } + /** * Throws a NotCompliantMBeanException or a SecurityException. * @param notCompliant the class which was under examination @@ -473,8 +595,13 @@ // The only other possibility is that the value is another // annotation, or that the language has evolved since this code // was written. We don't allow for either of those currently. + // If it is indeed another annotation, then x will be a proxy + // with an unhelpful name like $Proxy2. So we extract the + // proxy's interface to use that in the exception message. + if (Proxy.isProxyClass(c)) + c = c.getInterfaces()[0]; // array "can't be empty" throw new IllegalArgumentException("Illegal type for annotation " + - "element: " + x.getClass().getName()); + "element using @DescriptorKey: " + c.getName()); } // This must be consistent with the check for duplicate field values in @@ -490,15 +617,15 @@ * @param c The interface to be tested * @param clName The name of the class implementing this interface */ - private static Class implementsMBean(Class c, String clName) { + private static <T> Class<? super T> implementsMBean(Class<T> c, String clName) { String clMBeanName = clName + "MBean"; if (c.getName().equals(clMBeanName)) { return c; } - Class[] interfaces = c.getInterfaces(); + Class<?>[] interfaces = c.getInterfaces(); for (int i = 0;i < interfaces.length; i++) { if (interfaces[i].getName().equals(clMBeanName)) - return interfaces[i]; + return Util.cast(interfaces[i]); } return null;
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanAnalyzer.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanAnalyzer.java Wed Jul 05 16:39:18 2017 +0200 @@ -33,6 +33,10 @@ import java.util.List; import java.util.Map; import java.util.Set; +import javax.management.MBean; +import javax.management.MXBean; +import javax.management.ManagedAttribute; +import javax.management.ManagedOperation; import javax.management.NotCompliantMBeanException; /** @@ -125,18 +129,26 @@ for (Method m : methods) { final String name = m.getName(); final int nParams = m.getParameterTypes().length; + final boolean managedOp = m.isAnnotationPresent(ManagedOperation.class); + final boolean managedAttr = m.isAnnotationPresent(ManagedAttribute.class); + if (managedOp && managedAttr) { + throw new NotCompliantMBeanException("Method " + name + + " has both @ManagedOperation and @ManagedAttribute"); + } final M cm = introspector.mFrom(m); String attrName = ""; - if (name.startsWith("get")) - attrName = name.substring(3); - else if (name.startsWith("is") - && m.getReturnType() == boolean.class) - attrName = name.substring(2); + if (!managedOp) { + if (name.startsWith("get")) + attrName = name.substring(3); + else if (name.startsWith("is") + && m.getReturnType() == boolean.class) + attrName = name.substring(2); + } if (attrName.length() != 0 && nParams == 0 - && m.getReturnType() != void.class) { + && m.getReturnType() != void.class && !managedOp) { // It's a getter // Check we don't have both isX and getX AttrMethods<M> am = attrMap.get(attrName); @@ -153,7 +165,7 @@ attrMap.put(attrName, am); } else if (name.startsWith("set") && name.length() > 3 && nParams == 1 && - m.getReturnType() == void.class) { + m.getReturnType() == void.class && !managedOp) { // It's a setter attrName = name.substring(3); AttrMethods<M> am = attrMap.get(attrName); @@ -166,6 +178,9 @@ } am.setter = cm; attrMap.put(attrName, am); + } else if (managedAttr) { + throw new NotCompliantMBeanException("Method " + name + + " has @ManagedAttribute but is not a valid getter or setter"); } else { // It's an operation List<M> cms = opMap.get(name);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,291 @@ +/* + * 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. + */ + +package com.sun.jmx.mbeanserver; + +import java.lang.ref.WeakReference; +import java.security.PrivilegedAction; +import java.util.Map; +import java.util.WeakHashMap; +import javax.annotation.Resource; +import javax.management.MBeanServer; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; + +import static com.sun.jmx.mbeanserver.Util.newMap; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.security.AccessController; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.management.SendNotification; + +public class MBeanInjector { + private static Class<?>[] injectedClasses = { + MBeanServer.class, ObjectName.class, SendNotification.class, + }; + + public static void inject(Object mbean, MBeanServer mbs, ObjectName name) + throws Exception { + ClassInjector injector = injectorForClass(mbean.getClass()); + injector.inject(mbean, MBeanServer.class, mbs); + injector.inject(mbean, ObjectName.class, name); + } + + public static boolean injectsSendNotification(Object mbean) + throws NotCompliantMBeanException { + ClassInjector injector = injectorForClass(mbean.getClass()); + return injector.injects(SendNotification.class); + } + + public static void injectSendNotification(Object mbean, SendNotification sn) + throws Exception { + ClassInjector injector = injectorForClass(mbean.getClass()); + injector.inject(mbean, SendNotification.class, sn); + } + + public static void validate(Class<?> c) throws NotCompliantMBeanException { + injectorForClass(c); + } + + private static class ClassInjector { + private Map<Class<?>, List<Field>> fields; + private Map<Class<?>, List<Method>> methods; + + ClassInjector(Class<?> c) throws NotCompliantMBeanException { + fields = newMap(); + methods = newMap(); + + Class<?> sup = c.getSuperclass(); + ClassInjector supInjector; + if (sup == null) { + supInjector = null; + } else { + supInjector = injectorForClass(sup); + fields.putAll(supInjector.fields); + methods.putAll(supInjector.methods); + } + + addMembers(c); + eliminateOverriddenMethods(); + + // If we haven't added any new fields or methods to what we + // inherited, then we can share the parent's maps. + if (supInjector != null) { + if (fields.equals(supInjector.fields)) + fields = supInjector.fields; + if (methods.equals(supInjector.methods)) + methods = supInjector.methods; + } + } + + boolean injects(Class<?> c) { + return (fields.get(c) != null || methods.get(c) != null); + } + + <T> void inject(Object instance, Class<T> type, T resource) + throws Exception { + List<Field> fs = fields.get(type); + if (fs != null) { + for (Field f : fs) + f.set(instance, resource); + } + List<Method> ms = methods.get(type); + if (ms != null) { + for (Method m : ms) { + try { + m.invoke(instance, resource); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof Error) + throw (Error) cause; + else + throw (Exception) cause; + } + } + } + } + + private void eliminateOverriddenMethods() { + /* Covariant overriding is unlikely, but it is possible that the + * parent has a @Resource method that we override with another + * @Resource method. We don't want to invoke both methods, + * because polymorphism means we would actually invoke the same + * method twice. + */ + for (Map.Entry<Class<?>, List<Method>> entry : methods.entrySet()) { + List<Method> list = entry.getValue(); + list = MBeanAnalyzer.eliminateCovariantMethods(list); + entry.setValue(list); + } + } + + /* + * Find Fields or Methods within the given Class that we can inject + * resource references into. Suppose we want to know if a Field can get + * a reference to an ObjectName. We'll accept fields like this: + * + * @Resource + * private transient ObjectName name; + * + * or like this: + * + * @Resource(type = ObjectName.class) + * private transient Object name; + * + * but not like this: + * + * @Resource + * private transient Object name; + * + * (Plain @Resource is equivalent to @Resource(type = Object.class).) + * + * We don't want to inject into everything that might possibly accept + * an ObjectName reference, because examples like the last one above + * could also accept an MBeanServer reference or any other sort of + * reference. + * + * So we accept a Field if it has a @Resource annotation and either + * (a) its type is ObjectName or a subclass and its @Resource type is + * compatible with ObjectName (e.g. it is Object); or + * (b) its type is compatible with ObjectName and its @Resource type + * is exactly ObjectName. Fields that meet these criteria will not + * meet the same criteria with respect to other types such as MBeanServer. + * + * The same logic applies mutatis mutandis to Methods such as this: + * + * @Resource + * private void setObjectName1(ObjectName name) + * @Resource(type = Object.class) + * private void setObjectName2(Object name) + */ + private void addMembers(final Class<?> c) + throws NotCompliantMBeanException { + AccessibleObject[][] memberArrays = + AccessController.doPrivileged( + new PrivilegedAction<AccessibleObject[][]>() { + public AccessibleObject[][] run() { + return new AccessibleObject[][] { + c.getDeclaredFields(), c.getDeclaredMethods() + }; + } + }); + for (AccessibleObject[] members : memberArrays) { + for (final AccessibleObject member : members) { + Resource res = member.getAnnotation(Resource.class); + if (res == null) + continue; + + final Field field; + final Method method; + final Class<?> memberType; + final int modifiers; + if (member instanceof Field) { + field = (Field) member; + memberType = field.getType(); + modifiers = field.getModifiers(); + method = null; + } else { + field = null; + method = (Method) member; + Class<?>[] paramTypes = method.getParameterTypes(); + if (paramTypes.length != 1) { + throw new NotCompliantMBeanException( + "@Resource method must have exactly 1 " + + "parameter: " + method); + } + if (method.getReturnType() != void.class) { + throw new NotCompliantMBeanException( + "@Resource method must return void: " + + method); + } + memberType = paramTypes[0]; + modifiers = method.getModifiers(); + } + + if (Modifier.isStatic(modifiers)) { + throw new NotCompliantMBeanException( + "@Resource method or field cannot be static: " + + member); + } + + for (Class<?> injectedClass : injectedClasses) { + Class<?>[] types = {memberType, res.type()}; + boolean accept = false; + for (int i = 0; i < 2; i++) { + if (types[i] == injectedClass && + types[1 - i].isAssignableFrom(injectedClass)) { + accept = true; + break; + } + } + if (accept) { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { + member.setAccessible(true); + return null; + } + }); + addToMap(fields, injectedClass, field); + addToMap(methods, injectedClass, method); + } + } + } + } + } + + private static <K, V> void addToMap(Map<K, List<V>> map, K key, V value) { + if (value == null) + return; + List<V> list = map.get(key); + if (list == null) + list = Collections.singletonList(value); + else { + if (list.size() == 1) + list = new ArrayList<V>(list); + list.add(value); + } + map.put(key, list); + } + } + + private static synchronized ClassInjector injectorForClass(Class<?> c) + throws NotCompliantMBeanException { + WeakReference<ClassInjector> wr = injectorMap.get(c); + ClassInjector ci = (wr == null) ? null : wr.get(); + if (ci == null) { + ci = new ClassInjector(c); + injectorMap.put(c, new WeakReference<ClassInjector>(ci)); + } + return ci; + } + + private static Map<Class<?>, WeakReference<ClassInjector>> injectorMap = + new WeakHashMap<Class<?>, WeakReference<ClassInjector>>(); +}
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java Wed Jul 05 16:39:18 2017 +0200 @@ -36,20 +36,28 @@ import java.lang.reflect.Type; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.WeakHashMap; +import javax.management.Description; import javax.management.Descriptor; import javax.management.ImmutableDescriptor; import javax.management.IntrospectionException; import javax.management.InvalidAttributeValueException; +import javax.management.MBean; import javax.management.MBeanAttributeInfo; import javax.management.MBeanConstructorInfo; import javax.management.MBeanException; import javax.management.MBeanInfo; import javax.management.MBeanNotificationInfo; import javax.management.MBeanOperationInfo; +import javax.management.MXBean; +import javax.management.ManagedAttribute; +import javax.management.ManagedOperation; import javax.management.NotCompliantMBeanException; import javax.management.NotificationBroadcaster; +import javax.management.NotificationInfo; +import javax.management.NotificationInfos; import javax.management.ReflectionException; /** @@ -153,6 +161,25 @@ abstract MBeanAttributeInfo getMBeanAttributeInfo(String attributeName, M getter, M setter) throws IntrospectionException; + final String getAttributeDescription( + String attributeName, String defaultDescription, + Method getter, Method setter) throws IntrospectionException { + String g = Introspector.descriptionForElement(getter); + String s = Introspector.descriptionForElement(setter); + if (g == null) { + if (s == null) + return defaultDescription; + else + return s; + } else if (s == null || g.equals(s)) { + return g; + } else { + throw new IntrospectionException( + "Inconsistent @Description on getter and setter for " + + "attribute " + attributeName); + } + } + /** * Construct an MBeanOperationInfo for the given operation based on * the M it was derived from. @@ -184,8 +211,12 @@ } void checkCompliance(Class<?> mbeanType) throws NotCompliantMBeanException { - if (!mbeanType.isInterface()) { - throw new NotCompliantMBeanException("Not an interface: " + + if (!mbeanType.isInterface() && + !mbeanType.isAnnotationPresent(MBean.class) && + !Introspector.hasMXBeanAnnotation(mbeanType)) { + throw new NotCompliantMBeanException("Not an interface and " + + "does not have @" + MBean.class.getSimpleName() + + " or @" + MXBean.class.getSimpleName() + " annotation: " + mbeanType.getName()); } } @@ -194,7 +225,12 @@ * Get the methods to be analyzed to build the MBean interface. */ List<Method> getMethods(final Class<?> mbeanType) throws Exception { - return Arrays.asList(mbeanType.getMethods()); + if (mbeanType.isInterface()) + return Arrays.asList(mbeanType.getMethods()); + + final List<Method> methods = newList(); + getAnnotatedMethods(mbeanType, methods); + return methods; } final PerInterface<M> getPerInterface(Class<?> mbeanInterface) @@ -232,8 +268,11 @@ MBeanAnalyzer<M> analyzer) throws IntrospectionException { final MBeanInfoMaker maker = new MBeanInfoMaker(); analyzer.visit(maker); - final String description = + final String defaultDescription = "Information on the management interface of the MBean"; + String description = Introspector.descriptionForElement(mbeanInterface); + if (description == null) + description = defaultDescription; return maker.makeMBeanInfo(mbeanInterface, description); } @@ -407,7 +446,15 @@ throws NotCompliantMBeanException { MBeanInfo mbi = getClassMBeanInfo(resource.getClass(), perInterface); - MBeanNotificationInfo[] notifs = findNotifications(resource); + MBeanNotificationInfo[] notifs; + try { + notifs = findNotifications(resource); + } catch (RuntimeException e) { + NotCompliantMBeanException x = + new NotCompliantMBeanException(e.getMessage()); + x.initCause(e); + throw x; + } Descriptor d = getSpecificMBeanDescriptor(); boolean anyNotifs = (notifs != null && notifs.length > 0); if (!anyNotifs && ImmutableDescriptor.EMPTY_DESCRIPTOR.equals(d)) @@ -460,13 +507,43 @@ } } + /* + * Add to "methods" every public method that has the @ManagedAttribute + * or @ManagedOperation annotation, in the given class or any of + * its superclasses or superinterfaces. + * + * We always add superclass or superinterface methods first, so that + * the stable sort used by eliminateCovariantMethods will put the + * method from the most-derived class last. This means that we will + * see the version of the @ManagedAttribute (or ...Operation) annotation + * from that method, which might have a different description or whatever. + */ + private static void getAnnotatedMethods(Class<?> c, List<Method> methods) + throws Exception { + Class<?> sup = c.getSuperclass(); + if (sup != null) + getAnnotatedMethods(sup, methods); + Class<?>[] intfs = c.getInterfaces(); + for (Class<?> intf : intfs) + getAnnotatedMethods(intf, methods); + for (Method m : c.getMethods()) { + // We are careful not to add m if it is inherited from a parent + // class or interface, because duplicate methods lead to nasty + // behaviour in eliminateCovariantMethods. + if (m.getDeclaringClass() == c && + (m.isAnnotationPresent(ManagedAttribute.class) || + m.isAnnotationPresent(ManagedOperation.class))) + methods.add(m); + } + } + static MBeanNotificationInfo[] findNotifications(Object moi) { if (!(moi instanceof NotificationBroadcaster)) return null; MBeanNotificationInfo[] mbn = ((NotificationBroadcaster) moi).getNotificationInfo(); if (mbn == null || mbn.length == 0) - return null; + return findNotificationsFromAnnotations(moi.getClass()); MBeanNotificationInfo[] result = new MBeanNotificationInfo[mbn.length]; for (int i = 0; i < mbn.length; i++) { @@ -478,11 +555,81 @@ return result; } + private static MBeanNotificationInfo[] findNotificationsFromAnnotations( + Class<?> mbeanClass) { + Class<?> c = getAnnotatedNotificationInfoClass(mbeanClass); + if (c == null) + return null; + NotificationInfo ni = c.getAnnotation(NotificationInfo.class); + NotificationInfos nis = c.getAnnotation(NotificationInfos.class); + List<NotificationInfo> list = newList(); + if (ni != null) + list.add(ni); + if (nis != null) + list.addAll(Arrays.asList(nis.value())); + if (list.isEmpty()) + return null; + List<MBeanNotificationInfo> mbnis = newList(); + for (NotificationInfo x : list) { + // The Descriptor includes any fields explicitly specified by + // x.descriptorFields(), plus any fields from the contained + // @Description annotation. + Descriptor d = new ImmutableDescriptor(x.descriptorFields()); + d = ImmutableDescriptor.union( + d, Introspector.descriptorForAnnotation(x.description())); + MBeanNotificationInfo mbni = new MBeanNotificationInfo( + x.types(), x.notificationClass().getName(), + x.description().value(), d); + mbnis.add(mbni); + } + return mbnis.toArray(new MBeanNotificationInfo[mbnis.size()]); + } + + private static final Map<Class<?>, WeakReference<Class<?>>> + annotatedNotificationInfoClasses = newWeakHashMap(); + + private static Class<?> getAnnotatedNotificationInfoClass(Class<?> baseClass) { + synchronized (annotatedNotificationInfoClasses) { + WeakReference<Class<?>> wr = + annotatedNotificationInfoClasses.get(baseClass); + if (wr != null) + return wr.get(); + Class<?> c = null; + if (baseClass.isAnnotationPresent(NotificationInfo.class) || + baseClass.isAnnotationPresent(NotificationInfos.class)) { + c = baseClass; + } else { + Class<?>[] intfs = baseClass.getInterfaces(); + for (Class<?> intf : intfs) { + Class<?> c1 = getAnnotatedNotificationInfoClass(intf); + if (c1 != null) { + if (c != null) { + throw new IllegalArgumentException( + "Class " + baseClass.getName() + " inherits " + + "@NotificationInfo(s) from both " + + c.getName() + " and " + c1.getName()); + } + c = c1; + } + } + } + // Record the result of the search. If no @NotificationInfo(s) + // were found, c is null, and we store a WeakReference(null). + // This prevents us from having to search again and fail again. + annotatedNotificationInfoClasses.put(baseClass, + new WeakReference<Class<?>>(c)); + return c; + } + } + private static MBeanConstructorInfo[] findConstructors(Class<?> c) { Constructor[] cons = c.getConstructors(); MBeanConstructorInfo[] mbc = new MBeanConstructorInfo[cons.length]; for (int i = 0; i < cons.length; i++) { - final String descr = "Public constructor of the MBean"; + String descr = "Public constructor of the MBean"; + Description d = cons[i].getAnnotation(Description.class); + if (d != null) + descr = d.value(); mbc[i] = new MBeanConstructorInfo(descr, cons[i]); } return mbc;
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java Wed Jul 05 16:39:18 2017 +0200 @@ -263,10 +263,14 @@ return resource.getClass().getName(); } - public final Object getResource() { + public final Object getWrappedObject() { return resource; } + public final ClassLoader getWrappedClassLoader() { + return resource.getClass().getClassLoader(); + } + public final Class<?> getMBeanInterface() { return perInterface.getMBeanInterface(); }
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java Wed Jul 05 16:39:18 2017 +0200 @@ -35,6 +35,7 @@ import java.lang.reflect.Type; import java.util.Map; import java.util.WeakHashMap; +import javax.management.Description; import javax.management.Descriptor; import javax.management.ImmutableDescriptor; import javax.management.IntrospectionException; @@ -43,6 +44,7 @@ import javax.management.MBeanException; import javax.management.MBeanOperationInfo; import javax.management.MBeanParameterInfo; +import javax.management.ManagedOperation; import javax.management.NotCompliantMBeanException; import javax.management.openmbean.MXBeanMappingFactory; import javax.management.openmbean.OpenMBeanAttributeInfoSupport; @@ -180,7 +182,10 @@ final boolean isWritable = (setter != null); final boolean isIs = isReadable && getName(getter).startsWith("is"); - final String description = attributeName; + final String description = getAttributeDescription( + attributeName, attributeName, + getter == null ? null : getter.getMethod(), + setter == null ? null : setter.getMethod()); final OpenType<?> openType; final Type originalType; @@ -229,13 +234,17 @@ MBeanOperationInfo getMBeanOperationInfo(String operationName, ConvertingMethod operation) { final Method method = operation.getMethod(); - final String description = operationName; + String description = operationName; /* Ideally this would be an empty string, but - OMBOperationInfo constructor forbids that. Also, we - could consult an annotation to get a useful - description. */ + OMBOperationInfo constructor forbids that. */ + Description d = method.getAnnotation(Description.class); + if (d != null) + description = d.value(); - final int impact = MBeanOperationInfo.UNKNOWN; + int impact = MBeanOperationInfo.UNKNOWN; + ManagedOperation annot = method.getAnnotation(ManagedOperation.class); + if (annot != null) + impact = annot.impact().getCode(); final OpenType<?> returnType = operation.getOpenReturnType(); final Type originalReturnType = operation.getGenericReturnType(); @@ -247,8 +256,15 @@ boolean openParameterTypes = true; Annotation[][] annots = method.getParameterAnnotations(); for (int i = 0; i < paramTypes.length; i++) { - final String paramName = "p" + i; - final String paramDescription = paramName; + String paramName = Introspector.nameForParameter(annots[i]); + if (paramName == null) + paramName = "p" + i; + + String paramDescription = + Introspector.descriptionForParameter(annots[i]); + if (paramDescription == null) + paramDescription = paramName; + final OpenType<?> openType = paramTypes[i]; final Type originalType = originalParamTypes[i]; Descriptor descriptor =
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanSupport.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanSupport.java Wed Jul 05 16:39:18 2017 +0200 @@ -161,7 +161,7 @@ synchronized (lock) { this.mxbeanLookup = MXBeanLookup.Plain.lookupFor(server); - this.mxbeanLookup.addReference(name, getResource()); + this.mxbeanLookup.addReference(name, getWrappedObject()); this.objectName = name; } } @@ -170,7 +170,7 @@ public void unregister() { synchronized (lock) { if (mxbeanLookup != null) { - if (mxbeanLookup.removeReference(objectName, getResource())) + if (mxbeanLookup.removeReference(objectName, getWrappedObject())) objectName = null; } // XXX: need to revisit the whole register/unregister logic in
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/NotifySupport.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,186 @@ +/* + * 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. + */ + +package com.sun.jmx.mbeanserver; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.DynamicMBean; +import javax.management.DynamicWrapperMBean; +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.MBeanServer; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.ReflectionException; + +/** + * Create wrappers for DynamicMBean that implement NotificationEmitter + * and SendNotification. + */ +public class NotifySupport + implements DynamicMBean2, NotificationEmitter, MBeanRegistration { + + private final DynamicMBean mbean; + private final NotificationBroadcasterSupport nbs; + + public static DynamicMBean wrap( + DynamicMBean mbean, NotificationBroadcasterSupport nbs) { + return new NotifySupport(mbean, nbs); + } + + private NotifySupport(DynamicMBean mbean, NotificationBroadcasterSupport nbs) { + this.mbean = mbean; + this.nbs = nbs; + } + + public static NotificationBroadcasterSupport getNB(DynamicMBean mbean) { + if (mbean instanceof NotifySupport) + return ((NotifySupport) mbean).nbs; + else + return null; + } + + public String getClassName() { + if (mbean instanceof DynamicMBean2) + return ((DynamicMBean2) mbean).getClassName(); + Object w = mbean; + if (w instanceof DynamicWrapperMBean) + w = ((DynamicWrapperMBean) w).getWrappedObject(); + return w.getClass().getName(); + } + + public void preRegister2(MBeanServer mbs, ObjectName name) throws Exception { + if (mbean instanceof DynamicMBean2) + ((DynamicMBean2) mbean).preRegister2(mbs, name); + } + + public void registerFailed() { + if (mbean instanceof DynamicMBean2) + ((DynamicMBean2) mbean).registerFailed(); + } + + public Object getWrappedObject() { + if (mbean instanceof DynamicWrapperMBean) + return ((DynamicWrapperMBean) mbean).getWrappedObject(); + else + return mbean; + } + + public ClassLoader getWrappedClassLoader() { + if (mbean instanceof DynamicWrapperMBean) + return ((DynamicWrapperMBean) mbean).getWrappedClassLoader(); + else + return mbean.getClass().getClassLoader(); + } + + public Object getAttribute(String attribute) throws AttributeNotFoundException, + MBeanException, + ReflectionException { + return mbean.getAttribute(attribute); + } + + public void setAttribute(Attribute attribute) throws AttributeNotFoundException, + InvalidAttributeValueException, + MBeanException, + ReflectionException { + mbean.setAttribute(attribute); + } + + public AttributeList setAttributes(AttributeList attributes) { + return mbean.setAttributes(attributes); + } + + public Object invoke(String actionName, Object[] params, String[] signature) + throws MBeanException, ReflectionException { + return mbean.invoke(actionName, params, signature); + } + + public MBeanInfo getMBeanInfo() { + return mbean.getMBeanInfo(); + } + + public AttributeList getAttributes(String[] attributes) { + return mbean.getAttributes(attributes); + } + + public void removeNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object handback) throws ListenerNotFoundException { + nbs.removeNotificationListener(listener, filter, handback); + } + + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException { + nbs.removeNotificationListener(listener); + } + + public MBeanNotificationInfo[] getNotificationInfo() { + return nbs.getNotificationInfo(); + } + + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object handback) { + nbs.addNotificationListener(listener, filter, handback); + } + + public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { + if (mbr() != null) + return mbr().preRegister(server, name); + else + return name; + } + + public void postRegister(Boolean registrationDone) { + if (mbr() != null) + mbr().postRegister(registrationDone); + } + + public void preDeregister() throws Exception { + if (mbr() != null) + mbr().preDeregister(); + } + + public void postDeregister() { + if (mbr() != null) + mbr().postDeregister(); + } + + private MBeanRegistration mbr() { + if (mbean instanceof MBeanRegistration) + return (MBeanRegistration) mbean; + else + return null; + } +}
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Repository.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Repository.java Wed Jul 05 16:39:18 2017 +0200 @@ -29,6 +29,7 @@ import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -39,7 +40,6 @@ import javax.management.DynamicMBean; import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; -import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.QueryExp; import javax.management.RuntimeOperationsException; @@ -52,6 +52,27 @@ */ public class Repository { + /** + * An interface that allows the caller to get some control + * over the registration. + * @see #addMBean + * @see #remove + */ + public interface RegistrationContext { + /** + * Called by {@link #addMBean}. + * Can throw a RuntimeOperationsException to cancel the + * registration. + */ + public void registering(); + + /** + * Called by {@link #remove}. + * Any exception thrown by this method will be ignored. + */ + public void unregistered(); + } + // Private fields --------------------------------------------> /** @@ -115,7 +136,6 @@ /** * Builds a new ObjectNamePattern object from an ObjectName pattern * constituents. - * @param domain pattern.getDomain(). * @param propertyListPattern pattern.isPropertyListPattern(). * @param propertyValuePattern pattern.isPropertyValuePattern(). * @param canonicalProps pattern.getCanonicalKeyPropertyListString(). @@ -216,16 +236,6 @@ } } - private void addNewDomMoi(final DynamicMBean object, final String dom, - final ObjectName name) { - final Map<String,NamedObject> moiTb = - new HashMap<String,NamedObject>(); - moiTb.put(name.getCanonicalKeyPropertyListString(), - new NamedObject(name, object)); - domainTb.put(dom, moiTb); - nbElements++; - } - /** Match a string against a shell-style pattern. The only pattern characters recognised are <code>?</code>, standing for any one character, and <code>*</code>, standing for any string of @@ -306,6 +316,50 @@ } } + private void addNewDomMoi(final DynamicMBean object, + final String dom, + final ObjectName name, + final RegistrationContext context) { + final Map<String,NamedObject> moiTb = + new HashMap<String,NamedObject>(); + final String key = name.getCanonicalKeyPropertyListString(); + addMoiToTb(object,name,key,moiTb,context); + domainTb.put(dom, moiTb); + nbElements++; + } + + private void registering(RegistrationContext context) { + if (context == null) return; + try { + context.registering(); + } catch (RuntimeOperationsException x) { + throw x; + } catch (RuntimeException x) { + throw new RuntimeOperationsException(x); + } + } + + private void unregistering(RegistrationContext context, ObjectName name) { + if (context == null) return; + try { + context.unregistered(); + } catch (Exception x) { + // shouldn't come here... + MBEANSERVER_LOGGER.log(Level.FINE, + "Unexpected exception while unregistering "+name, + x); + } + } + + private void addMoiToTb(final DynamicMBean object, + final ObjectName name, + final String key, + final Map<String,NamedObject> moiTb, + final RegistrationContext context) { + registering(context); + moiTb.put(key,new NamedObject(name, object)); + } + /** * Retrieves the named object contained in repository * from the given objectname. @@ -355,12 +409,12 @@ domainTb = new HashMap<String,Map<String,NamedObject>>(5); if (domain != null && domain.length() != 0) - this.domain = domain; + this.domain = domain.intern(); // we use == domain later on... else this.domain = ServiceName.DOMAIN; - // Creates an new hastable for the default domain - domainTb.put(this.domain.intern(), new HashMap<String,NamedObject>()); + // Creates a new hashtable for the default domain + domainTb.put(this.domain, new HashMap<String,NamedObject>()); } /** @@ -395,10 +449,21 @@ /** * Stores an MBean associated with its object name in the repository. * - * @param object MBean to be stored in the repository. - * @param name MBean object name. + * @param object MBean to be stored in the repository. + * @param name MBean object name. + * @param context A registration context. If non null, the repository + * will call {@link RegistrationContext#registering() + * context.registering()} from within the repository + * lock, when it has determined that the {@code object} + * can be stored in the repository with that {@code name}. + * If {@link RegistrationContext#registering() + * context.registering()} throws an exception, the + * operation is abandonned, the MBean is not added to the + * repository, and a {@link RuntimeOperationsException} + * is thrown. */ - public void addMBean(final DynamicMBean object, ObjectName name) + public void addMBean(final DynamicMBean object, ObjectName name, + final RegistrationContext context) throws InstanceAlreadyExistsException { if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { @@ -431,7 +496,7 @@ lock.writeLock().lock(); try { - // Domain cannot be JMImplementation if entry does not exists + // Domain cannot be JMImplementation if entry does not exist if ( !to_default_domain && dom.equals("JMImplementation") && domainTb.containsKey("JMImplementation")) { @@ -440,21 +505,21 @@ "Repository: domain name cannot be JMImplementation")); } - // If domain not already exists, add it to the hash table + // If domain does not already exist, add it to the hash table final Map<String,NamedObject> moiTb = domainTb.get(dom); if (moiTb == null) { - addNewDomMoi(object, dom, name); + addNewDomMoi(object, dom, name, context); return; - } - - // Add instance if not already present - String cstr = name.getCanonicalKeyPropertyListString(); - NamedObject elmt= moiTb.get(cstr); - if (elmt != null) { - throw new InstanceAlreadyExistsException(name.toString()); } else { - nbElements++; - moiTb.put(cstr, new NamedObject(name, object)); + // Add instance if not already present + String cstr = name.getCanonicalKeyPropertyListString(); + NamedObject elmt= moiTb.get(cstr); + if (elmt != null) { + throw new InstanceAlreadyExistsException(name.toString()); + } else { + nbElements++; + addMoiToTb(object,name,cstr,moiTb,context); + } } } finally { @@ -533,7 +598,7 @@ // ":*", ":[key=value],*" : names in defaultDomain // "domain:*", "domain:[key=value],*" : names in the specified domain - // Surely one of the most frequent case ... query on the whole world + // Surely one of the most frequent cases ... query on the whole world ObjectName name; if (pattern == null || pattern.getCanonicalName().length() == 0 || @@ -546,8 +611,7 @@ // If pattern is not a pattern, retrieve this mbean ! if (!name.isPattern()) { - final NamedObject no; - no = retrieveNamedObject(name); + final NamedObject no = retrieveNamedObject(name); if (no != null) result.add(no); return result; } @@ -577,12 +641,22 @@ return result; } + if (!name.isDomainPattern()) { + final Map<String,NamedObject> moiTb = domainTb.get(name.getDomain()); + if (moiTb == null) return Collections.emptySet(); + if (allNames) + result.addAll(moiTb.values()); + else + addAllMatching(moiTb, result, namePattern); + return result; + } + // Pattern matching in the domain name (*, ?) char[] dom2Match = name.getDomain().toCharArray(); - for (String domain : domainTb.keySet()) { - char[] theDom = domain.toCharArray(); + for (String dom : domainTb.keySet()) { + char[] theDom = dom.toCharArray(); if (wildmatch(theDom, dom2Match)) { - final Map<String,NamedObject> moiTb = domainTb.get(domain); + final Map<String,NamedObject> moiTb = domainTb.get(dom); if (allNames) result.addAll(moiTb.values()); else @@ -599,11 +673,21 @@ * Removes an MBean from the repository. * * @param name name of the MBean to remove. + * @param context A registration context. If non null, the repository + * will call {@link RegistrationContext#unregistered() + * context.unregistered()} from within the repository + * lock, just after the mbean associated with + * {@code name} is removed from the repository. + * If {@link RegistrationContext#unregistered() + * context.unregistered()} is not expected to throw any + * exception. If it does, the exception is logged + * and swallowed. * * @exception InstanceNotFoundException The MBean does not exist in * the repository. */ - public void remove(final ObjectName name) + public void remove(final ObjectName name, + final RegistrationContext context) throws InstanceNotFoundException { // Debugging stuff @@ -645,6 +729,9 @@ if (dom == domain) domainTb.put(domain, new HashMap<String,NamedObject>()); } + + unregistering(context,name); + } finally { lock.writeLock().unlock(); }
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanIntrospector.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanIntrospector.java Wed Jul 05 16:39:18 2017 +0200 @@ -35,6 +35,7 @@ import javax.management.MBeanAttributeInfo; import javax.management.MBeanException; import javax.management.MBeanOperationInfo; +import javax.management.ManagedOperation; import javax.management.NotCompliantMBeanException; import javax.management.NotificationBroadcaster; import javax.management.NotificationBroadcasterSupport; @@ -118,22 +119,32 @@ @Override MBeanAttributeInfo getMBeanAttributeInfo(String attributeName, - Method getter, Method setter) { + Method getter, Method setter) throws IntrospectionException { - final String description = "Attribute exposed for management"; - try { - return new MBeanAttributeInfo(attributeName, description, - getter, setter); - } catch (IntrospectionException e) { - throw new RuntimeException(e); // should not happen - } + String description = getAttributeDescription( + attributeName, "Attribute exposed for management", + getter, setter); + return new MBeanAttributeInfo(attributeName, description, + getter, setter); } @Override MBeanOperationInfo getMBeanOperationInfo(String operationName, Method operation) { - final String description = "Operation exposed for management"; - return new MBeanOperationInfo(description, operation); + final String defaultDescription = "Operation exposed for management"; + String description = Introspector.descriptionForElement(operation); + if (description == null) + description = defaultDescription; + + int impact = MBeanOperationInfo.UNKNOWN; + ManagedOperation annot = operation.getAnnotation(ManagedOperation.class); + if (annot != null) + impact = annot.impact().getCode(); + + MBeanOperationInfo mboi = new MBeanOperationInfo(description, operation); + return new MBeanOperationInfo( + mboi.getName(), mboi.getDescription(), mboi.getSignature(), + mboi.getReturnType(), impact, mboi.getDescriptor()); } @Override
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanSupport.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanSupport.java Wed Jul 05 16:39:18 2017 +0200 @@ -41,26 +41,24 @@ public class StandardMBeanSupport extends MBeanSupport<Method> { /** - <p>Construct a Standard MBean that wraps the given resource using the - given Standard MBean interface.</p> - - @param resource the underlying resource for the new MBean. - - @param mbeanInterface the interface to be used to determine - the MBean's management interface. - - @param <T> a type parameter that allows the compiler to check - that {@code resource} implements {@code mbeanInterface}, - provided that {@code mbeanInterface} is a class constant like - {@code SomeMBean.class}. - - @throws IllegalArgumentException if {@code resource} is null or - if it does not implement the class {@code mbeanInterface} or if - that class is not a valid Standard MBean interface. - */ - public <T> StandardMBeanSupport(T resource, Class<T> mbeanInterface) + * <p>Construct a Standard MBean that wraps the given resource using the + * given Standard MBean interface.</p> + * + * @param resource the underlying resource for the new MBean. + * @param mbeanInterfaceType the class or interface to be used to determine + * the MBean's management interface. An interface if this is a + * classic Standard MBean; a class if this is a {@code @ManagedResource}. + * @param <T> a type parameter that allows the compiler to check + * that {@code resource} implements {@code mbeanInterfaceType}, + * provided that {@code mbeanInterfaceType} is a class constant like + * {@code SomeMBean.class}. + * @throws IllegalArgumentException if {@code resource} is null or + * if it does not implement the class {@code mbeanInterfaceType} or if + * that class is not a valid Standard MBean interface. + */ + public <T> StandardMBeanSupport(T resource, Class<T> mbeanInterfaceType) throws NotCompliantMBeanException { - super(resource, mbeanInterface, (MXBeanMappingFactory) null); + super(resource, mbeanInterfaceType, (MXBeanMappingFactory) null); } @Override @@ -86,13 +84,14 @@ @Override public MBeanInfo getMBeanInfo() { MBeanInfo mbi = super.getMBeanInfo(); - Class<?> resourceClass = getResource().getClass(); - if (StandardMBeanIntrospector.isDefinitelyImmutableInfo(resourceClass)) + Class<?> resourceClass = getWrappedObject().getClass(); + if (!getMBeanInterface().isInterface() || + StandardMBeanIntrospector.isDefinitelyImmutableInfo(resourceClass)) return mbi; return new MBeanInfo(mbi.getClassName(), mbi.getDescription(), mbi.getAttributes(), mbi.getConstructors(), mbi.getOperations(), - MBeanIntrospector.findNotifications(getResource()), + MBeanIntrospector.findNotifications(getWrappedObject()), mbi.getDescriptor()); } }
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java Wed Jul 05 16:39:18 2017 +0200 @@ -38,6 +38,7 @@ import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; +import java.util.WeakHashMap; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; @@ -71,6 +72,10 @@ return new LinkedHashMap<K, V>(); } + static <K, V> WeakHashMap<K, V> newWeakHashMap() { + return new WeakHashMap<K, V>(); + } + static <E> Set<E> newSet() { return new HashSet<E>(); }
--- a/jdk/src/share/classes/com/sun/tools/jdi/EventSetImpl.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/tools/jdi/EventSetImpl.java Wed Jul 05 16:39:18 2017 +0200 @@ -208,8 +208,9 @@ } public String toString() { - return eventName() + "@" + location().toString() + - " in thread " + thread().name(); + return eventName() + "@" + + ((location() == null) ? " null" : location().toString()) + + " in thread " + thread().name(); } }
--- a/jdk/src/share/classes/com/sun/tools/jdi/MonitorInfoImpl.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/tools/jdi/MonitorInfoImpl.java Wed Jul 05 16:39:18 2017 +0200 @@ -40,11 +40,12 @@ int stack_depth; MonitorInfoImpl(VirtualMachine vm, ObjectReference mon, - ThreadReference thread, int dpth) { + ThreadReferenceImpl thread, int dpth) { super(vm); this.monitor = mon; this.thread = thread; this.stack_depth = dpth; + thread.addListener(this); }
--- a/jdk/src/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java Wed Jul 05 16:39:18 2017 +0200 @@ -35,12 +35,34 @@ static final int SUSPEND_STATUS_SUSPENDED = 0x1; static final int SUSPEND_STATUS_BREAK = 0x2; - private ThreadGroupReference threadGroup; private int suspendedZombieCount = 0; - // This is cached only while the VM is suspended - private static class Cache extends ObjectReferenceImpl.Cache { - String name = null; + /* + * Some objects can only be created while a thread is suspended and are valid + * only while the thread remains suspended. Examples are StackFrameImpl + * and MonitorInfoImpl. When the thread resumes, these objects have to be + * marked as invalid so that their methods can throw + * InvalidStackFrameException if they are called. To do this, such objects + * register themselves as listeners of the associated thread. When the + * thread is resumed, its listeners are notified and mark themselves + * invalid. + * Also, note that ThreadReferenceImpl itself caches some info that + * is valid only as long as the thread is suspended. When the thread + * is resumed, that cache must be purged. + * Lastly, note that ThreadReferenceImpl and its super, ObjectReferenceImpl + * cache some info that is only valid as long as the entire VM is suspended. + * If _any_ thread is resumed, this cache must be purged. To handle this, + * both ThreadReferenceImpl and ObjectReferenceImpl register themselves as + * VMListeners so that they get notified when all threads are suspended and + * when any thread is resumed. + */ + + // This is cached for the life of the thread + private ThreadGroupReference threadGroup; + + // This is cached only while this one thread is suspended. Each time + // the thread is resumed, we clear this and start with a fresh one. + private static class LocalCache { JDWP.ThreadReference.Status status = null; List<StackFrame> frames = null; int framesStart = -1; @@ -52,6 +74,17 @@ boolean triedCurrentContended = false; } + private LocalCache localCache; + + private void resetLocalCache() { + localCache = new LocalCache(); + } + + // This is cached only while all threads in the VM are suspended + // Yes, someone could change the name of a thread while it is suspended. + private static class Cache extends ObjectReferenceImpl.Cache { + String name = null; + } protected ObjectReferenceImpl.Cache newCache() { return new Cache(); } @@ -59,8 +92,10 @@ // Listeners - synchronized on vm.state() private List<WeakReference<ThreadListener>> listeners = new ArrayList<WeakReference<ThreadListener>>(); + ThreadReferenceImpl(VirtualMachine aVm, long aRef) { super(aVm,aRef); + resetLocalCache(); vm.state().addListener(this); } @@ -72,10 +107,24 @@ * VMListener implementation */ public boolean vmNotSuspended(VMAction action) { - synchronized (vm.state()) { - processThreadAction(new ThreadAction(this, - ThreadAction.THREAD_RESUMABLE)); + if (action.resumingThread() == null) { + // all threads are being resumed + synchronized (vm.state()) { + processThreadAction(new ThreadAction(this, + ThreadAction.THREAD_RESUMABLE)); + } + } + + /* + * Othewise, only one thread is being resumed: + * if it is us, + * we have already done our processThreadAction to notify our + * listeners when we processed the resume. + * if it is not us, + * we don't want to notify our listeners + * because we are not being resumed. + */ return super.vmNotSuspended(action); } @@ -191,23 +240,19 @@ } private JDWP.ThreadReference.Status jdwpStatus() { - JDWP.ThreadReference.Status status = null; + JDWP.ThreadReference.Status myStatus = localCache.status; try { - Cache local = (Cache)getCache(); - - if (local != null) { - status = local.status; - } - if (status == null) { - status = JDWP.ThreadReference.Status.process(vm, this); - if (local != null) { - local.status = status; + if (myStatus == null) { + myStatus = JDWP.ThreadReference.Status.process(vm, this); + if ((myStatus.suspendStatus & SUSPEND_STATUS_SUSPENDED) != 0) { + // thread is suspended, we can cache the status. + localCache.status = myStatus; } } - } catch (JDWPException exc) { + } catch (JDWPException exc) { throw exc.toJDIException(); } - return status; + return myStatus; } public int status() { @@ -245,8 +290,7 @@ public ThreadGroupReference threadGroup() { /* - * Thread group can't change, so it's cached more conventionally - * than other things in this class. + * Thread group can't change, so it's cached once and for all. */ if (threadGroup == null) { try { @@ -260,19 +304,10 @@ } public int frameCount() throws IncompatibleThreadStateException { - int frameCount = -1; try { - Cache local = (Cache)getCache(); - - if (local != null) { - frameCount = local.frameCount; - } - if (frameCount == -1) { - frameCount = JDWP.ThreadReference.FrameCount + if (localCache.frameCount == -1) { + localCache.frameCount = JDWP.ThreadReference.FrameCount .process(vm, this).frameCount; - if (local != null) { - local.frameCount = frameCount; - } } } catch (JDWPException exc) { switch (exc.errorCode()) { @@ -283,7 +318,7 @@ throw exc.toJDIException(); } } - return frameCount; + return localCache.frameCount; } public List<StackFrame> frames() throws IncompatibleThreadStateException { @@ -297,23 +332,25 @@ /** * Is the requested subrange within what has been retrieved? - * local is known to be non-null + * local is known to be non-null. Should only be called from + * a sync method. */ - private boolean isSubrange(Cache local, - int start, int length, List frames) { - if (start < local.framesStart) { + private boolean isSubrange(LocalCache localCache, + int start, int length) { + if (start < localCache.framesStart) { return false; } if (length == -1) { - return (local.framesLength == -1); + return (localCache.framesLength == -1); } - if (local.framesLength == -1) { - if ((start + length) > (local.framesStart + frames.size())) { + if (localCache.framesLength == -1) { + if ((start + length) > (localCache.framesStart + + localCache.frames.size())) { throw new IndexOutOfBoundsException(); } return true; } - return ((start + length) <= (local.framesStart + local.framesLength)); + return ((start + length) <= (localCache.framesStart + localCache.framesLength)); } public List<StackFrame> frames(int start, int length) @@ -329,51 +366,42 @@ * Private version of frames() allows "-1" to specify all * remaining frames. */ - private List<StackFrame> privateFrames(int start, int length) + synchronized private List<StackFrame> privateFrames(int start, int length) throws IncompatibleThreadStateException { - List<StackFrame> frames = null; + + // Lock must be held while creating stack frames so if that two threads + // do this at the same time, one won't clobber the subset created by the other. + try { - Cache local = (Cache)getCache(); - - if (local != null) { - frames = local.frames; - } - if (frames == null || !isSubrange(local, start, length, frames)) { + if (localCache.frames == null || !isSubrange(localCache, start, length)) { JDWP.ThreadReference.Frames.Frame[] jdwpFrames = JDWP.ThreadReference.Frames. - process(vm, this, start, length).frames; + process(vm, this, start, length).frames; int count = jdwpFrames.length; - frames = new ArrayList<StackFrame>(count); + localCache.frames = new ArrayList<StackFrame>(count); - // Lock must be held while creating stack frames. - // so that a resume will not resume a partially - // created stack. - synchronized (vm.state()) { - for (int i = 0; i<count; i++) { - if (jdwpFrames[i].location == null) { - throw new InternalException("Invalid frame location"); - } - StackFrame frame = new StackFrameImpl(vm, this, - jdwpFrames[i].frameID, - jdwpFrames[i].location); - // Add to the frame list - frames.add(frame); + for (int i = 0; i<count; i++) { + if (jdwpFrames[i].location == null) { + throw new InternalException("Invalid frame location"); } + StackFrame frame = new StackFrameImpl(vm, this, + jdwpFrames[i].frameID, + jdwpFrames[i].location); + // Add to the frame list + localCache.frames.add(frame); } - if (local != null) { - local.frames = frames; - local.framesStart = start; - local.framesLength = length; - } + localCache.framesStart = start; + localCache.framesLength = length; + return Collections.unmodifiableList(localCache.frames); } else { - int fromIndex = start - local.framesStart; + int fromIndex = start - localCache.framesStart; int toIndex; if (length == -1) { - toIndex = frames.size() - fromIndex; + toIndex = localCache.frames.size() - fromIndex; } else { toIndex = fromIndex + length; } - frames = frames.subList(fromIndex, toIndex); + return Collections.unmodifiableList(localCache.frames.subList(fromIndex, toIndex)); } } catch (JDWPException exc) { switch (exc.errorCode()) { @@ -384,28 +412,18 @@ throw exc.toJDIException(); } } - return Collections.unmodifiableList(frames); } public List<ObjectReference> ownedMonitors() throws IncompatibleThreadStateException { - List<ObjectReference> monitors = null; try { - Cache local = (Cache)getCache(); - - if (local != null) { - monitors = local.ownedMonitors; - } - if (monitors == null) { - monitors = Arrays.asList( + if (localCache.ownedMonitors == null) { + localCache.ownedMonitors = Arrays.asList( (ObjectReference[])JDWP.ThreadReference.OwnedMonitors. process(vm, this).owned); - if (local != null) { - local.ownedMonitors = monitors; - if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) { - vm.printTrace(description() + - " temporarily caching owned monitors"+ - " (count = " + monitors.size() + ")"); - } + if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) { + vm.printTrace(description() + + " temporarily caching owned monitors"+ + " (count = " + localCache.ownedMonitors.size() + ")"); } } } catch (JDWPException exc) { @@ -417,29 +435,22 @@ throw exc.toJDIException(); } } - return monitors; + return localCache.ownedMonitors; } public ObjectReference currentContendedMonitor() throws IncompatibleThreadStateException { - ObjectReference monitor = null; try { - Cache local = (Cache)getCache(); - - if (local != null && local.triedCurrentContended) { - monitor = local.contendedMonitor; - } else { - monitor = JDWP.ThreadReference.CurrentContendedMonitor. + if (localCache.contendedMonitor == null && + !localCache.triedCurrentContended) { + localCache.contendedMonitor = JDWP.ThreadReference.CurrentContendedMonitor. process(vm, this).monitor; - if (local != null) { - local.triedCurrentContended = true; - local.contendedMonitor = monitor; - if ((monitor != null) && - ((vm.traceFlags & vm.TRACE_OBJREFS) != 0)) { - vm.printTrace(description() + - " temporarily caching contended monitor"+ - " (id = " + monitor.uniqueID() + ")"); - } + localCache.triedCurrentContended = true; + if ((localCache.contendedMonitor != null) && + ((vm.traceFlags & vm.TRACE_OBJREFS) != 0)) { + vm.printTrace(description() + + " temporarily caching contended monitor"+ + " (id = " + localCache.contendedMonitor.uniqueID() + ")"); } } } catch (JDWPException exc) { @@ -450,40 +461,31 @@ throw exc.toJDIException(); } } - return monitor; + return localCache.contendedMonitor; } public List<MonitorInfo> ownedMonitorsAndFrames() throws IncompatibleThreadStateException { - List<MonitorInfo> monitors = null; try { - Cache local = (Cache)getCache(); - - if (local != null) { - monitors = local.ownedMonitorsInfo; - } - if (monitors == null) { + if (localCache.ownedMonitorsInfo == null) { JDWP.ThreadReference.OwnedMonitorsStackDepthInfo.monitor[] minfo; minfo = JDWP.ThreadReference.OwnedMonitorsStackDepthInfo.process(vm, this).owned; - monitors = new ArrayList<MonitorInfo>(minfo.length); + localCache.ownedMonitorsInfo = new ArrayList<MonitorInfo>(minfo.length); for (int i=0; i < minfo.length; i++) { JDWP.ThreadReference.OwnedMonitorsStackDepthInfo.monitor mi = minfo[i]; MonitorInfo mon = new MonitorInfoImpl(vm, minfo[i].monitor, this, minfo[i].stack_depth); - monitors.add(mon); + localCache.ownedMonitorsInfo.add(mon); } - if (local != null) { - local.ownedMonitorsInfo = monitors; - if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) { - vm.printTrace(description() + - " temporarily caching owned monitors"+ - " (count = " + monitors.size() + ")"); + if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) { + vm.printTrace(description() + + " temporarily caching owned monitors"+ + " (count = " + localCache.ownedMonitorsInfo.size() + ")"); } } - } } catch (JDWPException exc) { switch (exc.errorCode()) { case JDWP.Error.THREAD_NOT_SUSPENDED: @@ -493,7 +495,7 @@ throw exc.toJDIException(); } } - return monitors; + return localCache.ownedMonitorsInfo; } public void popFrames(StackFrame frame) throws IncompatibleThreadStateException { @@ -511,7 +513,7 @@ } public void forceEarlyReturn(Value returnValue) throws InvalidTypeException, - ClassNotLoadedException, + ClassNotLoadedException, IncompatibleThreadStateException { if (!vm.canForceEarlyReturn()) { throw new UnsupportedOperationException( @@ -604,6 +606,9 @@ iter.remove(); } } + + // Discard our local cache + resetLocalCache(); } } }
--- a/jdk/src/share/classes/com/sun/tools/jdi/VMAction.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/tools/jdi/VMAction.java Wed Jul 05 16:39:18 2017 +0200 @@ -38,10 +38,18 @@ static final int VM_NOT_SUSPENDED = 2; int id; + ThreadReference resumingThread; VMAction(VirtualMachine vm, int id) { + this(vm, null, id); + } + + // For id = VM_NOT_SUSPENDED, if resumingThread != null, then it is + // the only thread that is being resumed. + VMAction(VirtualMachine vm, ThreadReference resumingThread, int id) { super(vm); this.id = id; + this.resumingThread = resumingThread; } VirtualMachine vm() { return (VirtualMachine)getSource(); @@ -49,4 +57,8 @@ int id() { return id; } + + ThreadReference resumingThread() { + return resumingThread; + } }
--- a/jdk/src/share/classes/com/sun/tools/jdi/VMState.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/tools/jdi/VMState.java Wed Jul 05 16:39:18 2017 +0200 @@ -116,16 +116,25 @@ } /** - * Tell listeners to invalidate suspend-sensitive caches. + * All threads are resuming */ - synchronized void thaw() { + void thaw() { + thaw(null); + } + + /** + * Tell listeners to invalidate suspend-sensitive caches. + * If resumingThread != null, then only that thread is being + * resumed. + */ + synchronized void thaw(ThreadReference resumingThread) { if (cache != null) { if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) { vm.printTrace("Clearing VM suspended cache"); } disableCache(); } - processVMAction(new VMAction(vm, VMAction.VM_NOT_SUSPENDED)); + processVMAction(new VMAction(vm, resumingThread, VMAction.VM_NOT_SUSPENDED)); } private synchronized void processVMAction(VMAction action) {
--- a/jdk/src/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java Wed Jul 05 16:39:18 2017 +0200 @@ -146,8 +146,9 @@ public boolean threadResumable(ThreadAction action) { /* * If any thread is resumed, the VM is considered not suspended. + * Just one thread is being resumed so pass it to thaw. */ - state.thaw(); + state.thaw(action.thread()); return true; }
--- a/jdk/src/share/classes/java/nio/channels/SelectionKey.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/java/nio/channels/SelectionKey.java Wed Jul 05 16:39:18 2017 +0200 @@ -191,7 +191,7 @@ * @throws IllegalArgumentException * If a bit in the set does not correspond to an operation that * is supported by this key's channel, that is, if - * <tt>set & ~(channel().validOps()) != 0</tt> + * <tt>(ops & ~channel().validOps()) != 0</tt> * * @throws CancelledKeyException * If this key has been cancelled
--- a/jdk/src/share/classes/javax/management/BinaryRelQueryExp.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/BinaryRelQueryExp.java Wed Jul 05 16:39:18 2017 +0200 @@ -192,6 +192,7 @@ return "(" + exp1 + ") " + relOpString() + " (" + exp2 + ")"; } + @Override String toQueryString() { return exp1 + " " + relOpString() + " " + exp2; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/Description.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,180 @@ +/* + * 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. + */ + +package javax.management; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.ResourceBundle; + +/** + * <p>The textual description of an MBean or part of an MBean. This + * description is intended to be displayed to users to help them + * understand what the MBean does. Ultimately it will be the value of + * the {@code getDescription()} method of an {@link MBeanInfo}, {@link + * MBeanAttributeInfo}, or similar.</p> + * + * <p>This annotation applies to Standard MBean interfaces and to + * MXBean interfaces, as well as to MBean classes defined using the + * {@link MBean @MBean} or {@link MXBean @MXBean} annotations. For + * example, a Standard MBean might be defined like this:</p> + * + * <pre> + * <b>{@code @Description}</b>("Application configuration") + * public interface ConfigurationMBean { + * <b>{@code @Description}</b>("Cache size in bytes") + * public int getCacheSize(); + * public void setCacheSize(int size); + * + * <b>{@code @Description}</b>("Last time the configuration was changed, " + + * "in milliseconds since 1 Jan 1970") + * public long getLastChangedTime(); + * + * <b>{@code @Description}</b>("Save the configuration to a file") + * public void save( + * <b>{@code @Description}</b>("Optional name of the file, or null for the default name") + * String fileName); + * } + * </pre> + * + * <p>The {@code MBeanInfo} for this MBean will have a {@link + * MBeanInfo#getDescription() getDescription()} that is {@code + * "Application configuration"}. It will contain an {@code + * MBeanAttributeInfo} for the {@code CacheSize} attribute that is + * defined by the methods {@code getCacheSize} and {@code + * setCacheSize}, and another {@code MBeanAttributeInfo} for {@code + * LastChangedTime}. The {@link MBeanAttributeInfo#getDescription() + * getDescription()} for {@code CacheSize} will be {@code "Cache size + * in bytes"}. Notice that there is no need to add a + * {@code @Description} to both {@code getCacheSize} and {@code + * setCacheSize} - either alone will do. But if you do add a + * {@code @Description} to both, it must be the same.</p> + * + * <p>The {@code MBeanInfo} will also contain an {@link + * MBeanOperationInfo} where {@link + * MBeanOperationInfo#getDescription() getDescription()} is {@code + * "Save the configuration to a file"}. This {@code + * MBeanOperationInfo} will contain an {@link MBeanParameterInfo} + * where {@link MBeanParameterInfo#getDescription() getDescription()} + * is {@code "Optional name of the file, or null for the default + * name"}.</p> + * + * <p>The {@code @Description} annotation can also be applied to the + * public constructors of the implementation class. Continuing the + * above example, the {@code Configuration} class implementing {@code + * ConfigurationMBean} might look like this:</p> + * + * <pre> + * public class Configuration implements ConfigurationMBean { + * <b>{@code @Description}</b>("A Configuration MBean with the default file name") + * public Configuration() { + * this(DEFAULT_FILE_NAME); + * } + * + * <b>{@code @Description}</b>("A Configuration MBean with a specified file name") + * public Configuration( + * <b>{@code @Description}</b>("Name of the file the configuration is stored in") + * String fileName) {...} + * ... + * } + * </pre> + * + * <p>The {@code @Description} annotation also works in MBeans that + * are defined using the {@code @MBean} or {@code @MXBean} annotation + * on classes. Here is an alternative implementation of {@code + * Configuration} that does not use an {@code ConfigurationMBean} + * interface.</p> + * + * <pre> + * <b>{@code @MBean}</b> + * <b>{@code @Description}</b>("Application configuration") + * public class Configuration { + * <b>{@code @Description}</b>("A Configuration MBean with the default file name") + * public Configuration() { + * this(DEFAULT_FILE_NAME); + * } + * + * <b>{@code @Description}</b>("A Configuration MBean with a specified file name") + * public Configuration( + * <b>{@code @Description}</b>("Name of the file the configuration is stored in") + * String fileName) {...} + * + * <b>{@code @ManagedAttribute}</b> + * <b>{@code @Description}</b>("Cache size in bytes") + * public int getCacheSize() {...} + * <b>{@code @ManagedAttribute}</b> + * public void setCacheSize(int size) {...} + * + * <b>{@code @ManagedOperation}</b> + * <b>{@code @Description}</b>("Last time the configuration was changed, " + + * "in milliseconds since 1 Jan 1970") + * public long getLastChangedTime() {...} + * + * <b>{@code @ManagedOperation}</b> + * <b>{@code @Description}</b>("Save the configuration to a file") + * public void save( + * <b>{@code @Description}</b>("Optional name of the file, or null for the default name") + * String fileName) {...} + * ... + * } + * </pre> + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, + ElementType.TYPE}) +public @interface Description { + /** + * <p>The description.</p> + */ + String value(); + + /** + * <p>The base name for the {@link ResourceBundle} in which the key given in + * the {@code descriptionResourceKey} field can be found, for example + * {@code "com.example.myapp.MBeanResources"}. If a non-default value + * is supplied for this element, it will appear in the + * <a href="Descriptor.html#descriptionResourceBundleBaseName"><!-- + * -->{@code Descriptor}</a> for the annotated item.</p> + */ + @DescriptorKey( + value = "descriptionResourceBundleBaseName", omitIfDefault = true) + String bundleBaseName() default ""; + + /** + * <p>A resource key for the description of this element. In + * conjunction with the {@link #bundleBaseName bundleBaseName}, + * this can be used to find a localized version of the description. + * If a non-default value + * is supplied for this element, it will appear in the + * <a href="Descriptor.html#descriptionResourceKey"><!-- + * -->{@code Descriptor}</a> for the annotated item.</p> + */ + @DescriptorKey(value = "descriptionResourceKey", omitIfDefault = true) + String key() default ""; +}
--- a/jdk/src/share/classes/javax/management/Descriptor.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/Descriptor.java Wed Jul 05 16:39:18 2017 +0200 @@ -38,6 +38,7 @@ import java.util.ResourceBundle; import javax.management.openmbean.CompositeData; +import javax.management.openmbean.MXBeanMappingFactory; import javax.management.openmbean.OpenMBeanAttributeInfoSupport; import javax.management.openmbean.OpenMBeanOperationInfoSupport; import javax.management.openmbean.OpenMBeanParameterInfoSupport; @@ -117,21 +118,19 @@ * deprecation, for example {@code "1.3 Replaced by the Capacity * attribute"}.</td> * - * <tr><td>descriptionResource<br>BundleBaseName</td><td>String</td><td>Any</td> + * <tr id="descriptionResourceBundleBaseName"> + * <td>descriptionResource<br>BundleBaseName</td><td>String</td><td>Any</td> * * <td>The base name for the {@link ResourceBundle} in which the key given in * the {@code descriptionResourceKey} field can be found, for example - * {@code "com.example.myapp.MBeanResources"}. The meaning of this - * field is defined by this specification but the field is not set or - * used by the JMX API itself.</td> + * {@code "com.example.myapp.MBeanResources"}.</td> * - * <tr><td>descriptionResourceKey</td><td>String</td><td>Any</td> + * <tr id="descriptionResourceKey"> + * <td>descriptionResourceKey</td><td>String</td><td>Any</td> * * <td>A resource key for the description of this element. In * conjunction with the {@code descriptionResourceBundleBaseName}, - * this can be used to find a localized version of the description. - * The meaning of this field is defined by this specification but the - * field is not set or used by the JMX API itself.</td> + * this can be used to find a localized version of the description.</td> * * <tr><td>enabled</td><td>String</td> * <td>MBeanAttributeInfo<br>MBeanNotificationInfo<br>MBeanOperationInfo</td> @@ -216,6 +215,14 @@ * StandardMBean} class will have this field in its MBeanInfo * Descriptor.</td> * + * <tr><td id="mxbeanMappingFactoryClass"><i>mxbeanMappingFactoryClass</i> + * </td><td>String</td> + * <td>MBeanInfo</td> + * + * <td>The name of the {@link MXBeanMappingFactory} class that was used for this + * MXBean, if it was not the {@linkplain MXBeanMappingFactory#DEFAULT default} + * one.</td> + * * <tr><td><a name="openType"><i>openType</i></a><td>{@link OpenType}</td> * <td>MBeanAttributeInfo<br>MBeanOperationInfo<br>MBeanParameterInfo</td> *
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/DescriptorFields.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,137 @@ +/* + * 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. + */ + +package javax.management; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * <p>Annotation that adds fields to a {@link Descriptor}. This can be the + * Descriptor for an MBean, or for an attribute, operation, or constructor + * in an MBean, or for a parameter of an operation or constructor.</p> + * + * <p>Consider this Standard MBean interface, for example:</p> + * + * <pre> + * public interface CacheControlMBean { + * <b>@DescriptorFields("units=bytes")</b> + * public long getCacheSize(); + * } + * </pre> + * + * <p>When a Standard MBean is made using this interface, the usual rules + * mean that it will have an attribute called {@code CacheSize} of type + * {@code long}. The {@code DescriptorFields} annotation will ensure + * that the {@link MBeanAttributeInfo} for this attribute will have a + * {@code Descriptor} that has a field called {@code units} with + * corresponding value {@code bytes}.</p> + * + * <p>Similarly, if the interface looks like this:</p> + * + * <pre> + * public interface CacheControlMBean { + * <b>@DescriptorFields({"units=bytes", "since=1.5"})</b> + * public long getCacheSize(); + * } + * </pre> + * + * <p>then the resulting {@code Descriptor} will contain the following + * fields:</p> + * + * <table border="2"> + * <tr><th>Name</th><th>Value</th></tr> + * <tr><td>units</td><td>"bytes"</td></tr> + * <tr><td>since</td><td>"1.5"</td></tr> + * </table> + * + * <p>The {@code @DescriptorFields} annotation can be applied to:</p> + * + * <ul> + * <li>a Standard MBean or MXBean interface; + * <li>a method in such an interface; + * <li>a parameter of a method in a Standard MBean or MXBean interface + * when that method is an operation (not a getter or setter for an attribute); + * <li>a public constructor in the class that implements a Standard MBean + * or MXBean; + * <li>a parameter in such a constructor. + * </ul> + * + * <p>Other uses of the annotation will either fail to compile or be + * ignored.</p> + * + * <p>Interface annotations are checked only on the exact interface + * that defines the management interface of a Standard MBean or an + * MXBean, not on its parent interfaces. Method annotations are + * checked only in the most specific interface in which the method + * appears; in other words, if a child interface overrides a method + * from a parent interface, only {@code @DescriptorFields} annotations in + * the method in the child interface are considered. + * + * <p>The Descriptor fields contributed in this way must be consistent + * with each other and with any fields contributed by {@link + * DescriptorKey @DescriptorKey} annotations. That is, two + * different annotations, or two members of the same annotation, must + * not define a different value for the same Descriptor field. Fields + * from annotations on a getter method must also be consistent with + * fields from annotations on the corresponding setter method.</p> + * + * <p>The Descriptor resulting from these annotations will be merged + * with any Descriptor fields provided by the implementation, such as + * the <a href="Descriptor.html#immutableInfo">{@code + * immutableInfo}</a> field for an MBean. The fields from the annotations + * must be consistent with these fields provided by the implementation.</p> + * + * <h4>{@literal @DescriptorFields and @DescriptorKey}</h4> + * + * <p>The {@link DescriptorKey @DescriptorKey} annotation provides + * another way to use annotations to define Descriptor fields. + * <code>@DescriptorKey</code> requires more work but is also more + * robust, because there is less risk of mistakes such as misspelling + * the name of the field or giving an invalid value. + * <code>@DescriptorFields</code> is more convenient but includes + * those risks. <code>@DescriptorFields</code> is more + * appropriate for occasional use, but for a Descriptor field that you + * add in many places, you should consider a purpose-built annotation + * using <code>@DescriptorKey</code>. + * + * @since 1.7 + */ +@Documented +@Inherited // for @MBean and @MXBean classes +@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, + ElementType.PARAMETER, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface DescriptorFields { + /** + * <p>The descriptor fields. Each element of the string looks like + * {@code "name=value"}.</p> + */ + public String[] value(); +}
--- a/jdk/src/share/classes/javax/management/DescriptorKey.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/DescriptorKey.java Wed Jul 05 16:39:18 2017 +0200 @@ -33,6 +33,11 @@ * an MBean, or for an attribute, operation, or constructor in an * MBean, or for a parameter of an operation or constructor.</p> * + * <p>(The {@link DescriptorFields @DescriptorFields} annotation + * provides another way to add fields to a {@code Descriptor}. See + * the documentation for that annotation for a comparison of the + * two possibilities.)</p> + * * <p>Consider this annotation for example:</p> * * <pre> @@ -57,7 +62,7 @@ * <p>When a Standard MBean is made from the {@code CacheControlMBean}, * the usual rules mean that it will have an attribute called * {@code CacheSize} of type {@code long}. The {@code @Units} - * attribute, given the above definition, will ensure that the + * annotation, given the above definition, will ensure that the * {@link MBeanAttributeInfo} for this attribute will have a * {@code Descriptor} that has a field called {@code units} with * corresponding value {@code bytes}.</p> @@ -125,12 +130,13 @@ * the method in the child interface are considered. * * <p>The Descriptor fields contributed in this way by different - * annotations on the same program element must be consistent. That - * is, two different annotations, or two members of the same - * annotation, must not define a different value for the same - * Descriptor field. Fields from annotations on a getter method must - * also be consistent with fields from annotations on the - * corresponding setter method.</p> + * annotations on the same program element must be consistent with + * each other and with any fields contributed by a {@link + * DescriptorFields @DescriptorFields} annotation. That is, two + * different annotations, or two members of the same annotation, must + * not define a different value for the same Descriptor field. Fields + * from annotations on a getter method must also be consistent with + * fields from annotations on the corresponding setter method.</p> * * <p>The Descriptor resulting from these annotations will be merged * with any Descriptor fields provided by the implementation, such as @@ -169,4 +175,36 @@ @Target(ElementType.METHOD) public @interface DescriptorKey { String value(); + + /** + * <p>Do not include this field in the Descriptor if the annotation + * element has its default value. For example, suppose {@code @Units} is + * defined like this:</p> + * + * <pre> + * @Documented + * @Target(ElementType.METHOD) + * @Retention(RetentionPolicy.RUNTIME) + * public @interface Units { + * @DescriptorKey("units") + * String value(); + * + * <b>@DescriptorKey(value = "descriptionResourceKey", + * omitIfDefault = true)</b> + * String resourceKey() default ""; + * + * <b>@DescriptorKey(value = "descriptionResourceBundleBaseName", + * omitIfDefault = true)</b> + * String resourceBundleBaseName() default ""; + * } + * </pre> + * + * <p>Then consider a usage such as {@code @Units("bytes")} or + * {@code @Units(value = "bytes", resourceKey = "")}, where the + * {@code resourceKey} and {@code resourceBundleBaseNames} elements + * have their default values. In this case the Descriptor resulting + * from these annotations will not include a {@code descriptionResourceKey} + * or {@code descriptionResourceBundleBaseName} field.</p> + */ + boolean omitIfDefault() default false; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/DynamicWrapperMBean.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.management; + +/** + * <p>An MBean can implement this interface to affect how the MBeanServer's + * {@link MBeanServer#getClassLoaderFor getClassLoaderFor} and + * {@link MBeanServer#isInstanceOf isInstanceOf} methods behave. + * If these methods should refer to a wrapped object rather than the + * MBean object itself, then the {@link #getWrappedObject} method should + * return that wrapped object.</p> + * + * @see MBeanServer#getClassLoaderFor + * @see MBeanServer#isInstanceOf + */ +public interface DynamicWrapperMBean extends DynamicMBean { + /** + * <p>The resource corresponding to this MBean. This is the object whose + * class name should be reflected by the MBean's + * {@link MBeanServer#getMBeanInfo getMBeanInfo()}.<!-- + * -->{@link MBeanInfo#getClassName getClassName()} for example. For a "plain" + * DynamicMBean it will be "this". For an MBean that wraps another + * object, in the manner of {@link javax.management.StandardMBean}, it will be the + * wrapped object.</p> + * + * @return The resource corresponding to this MBean. + */ + public Object getWrappedObject(); + + /** + * <p>The {@code ClassLoader} for this MBean, which can be used to + * retrieve resources associated with the MBean for example. Usually, + * it will be + * {@link #getWrappedObject()}.{@code getClass().getClassLoader()}. + * + * @return The {@code ClassLoader} for this MBean. + */ + public ClassLoader getWrappedClassLoader(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/Impact.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,105 @@ +/* + * 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. + */ + +package javax.management; + +/** + * <p>Defines the impact of an MBean operation, in particular whether it + * has an effect on the MBean or simply returns information. This enum + * is used in the {@link ManagedOperation @ManagedOperation} annotation. + * Its {@link #getCode()} method can be used to get an {@code int} suitable + * for use as the {@code impact} parameter in an {@link MBeanOperationInfo} + * constructor.</p> + */ +public enum Impact { + /** + * The operation is read-like: it returns information but does not change + * any state. + * @see MBeanOperationInfo#INFO + */ + INFO(MBeanOperationInfo.INFO), + + /** + * The operation is write-like: it has an effect but does not return + * any information from the MBean. + * @see MBeanOperationInfo#ACTION + */ + ACTION(MBeanOperationInfo.ACTION), + + /** + * The operation is both read-like and write-like: it has an effect, + * and it also returns information from the MBean. + * @see MBeanOperationInfo#ACTION_INFO + */ + ACTION_INFO(MBeanOperationInfo.ACTION_INFO), + + /** + * The impact of the operation is unknown or cannot be expressed + * using one of the other values. + * @see MBeanOperationInfo#UNKNOWN + */ + UNKNOWN(MBeanOperationInfo.UNKNOWN); + + private final int code; + + /** + * An instance of this enumeration, with the corresponding {@code int} + * code used by the {@link MBeanOperationInfo} constructors. + * + * @param code the code used by the {@code MBeanOperationInfo} constructors. + */ + Impact(int code) { + this.code = code; + } + + /** + * The equivalent {@code int} code used by the {@link MBeanOperationInfo} + * constructors. + * @return the {@code int} code. + */ + public int getCode() { + return code; + } + + /** + * Return the {@code Impact} value corresponding to the given {@code int} + * code. The {@code code} is the value that would be used in an + * {@code MBeanOperationInfo} constructor. + * + * @param code the {@code int} code. + * + * @return an {@code Impact} value {@code x} such that + * {@code code == x.}{@link #getCode()}, or {@code Impact.UNKNOWN} + * if there is no such value. + */ + public static Impact forCode(int code) { + switch (code) { + case MBeanOperationInfo.ACTION: return ACTION; + case MBeanOperationInfo.INFO: return INFO; + case MBeanOperationInfo.ACTION_INFO: return ACTION_INFO; + default: return UNKNOWN; + } + } +}
--- a/jdk/src/share/classes/javax/management/JMX.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/JMX.java Wed Jul 05 16:39:18 2017 +0200 @@ -26,6 +26,7 @@ package javax.management; import com.sun.jmx.mbeanserver.Introspector; +import com.sun.jmx.mbeanserver.MBeanInjector; import com.sun.jmx.remote.util.ClassLogger; import java.beans.BeanInfo; import java.beans.PropertyDescriptor; @@ -130,6 +131,7 @@ * </pre> * * @see javax.management.JMX.ProxyOptions + * @see javax.management.StandardMBean.Options */ public static class MBeanOptions implements Serializable, Cloneable { private static final long serialVersionUID = -6380842449318177843L; @@ -739,4 +741,28 @@ // exactly the string "MXBean" since that would mean there // was no package name, which is pretty unlikely in practice. } + + /** + * <p>Test if an MBean can emit notifications. An MBean can emit + * notifications if either it implements {@link NotificationBroadcaster} + * (perhaps through its child interface {@link NotificationEmitter}), or + * it uses <a href="MBeanRegistration.html#injection">resource + * injection</a> to obtain an instance of {@link SendNotification} + * through which it can send notifications.</p> + * + * @param mbean an MBean object. + * @return true if the given object is a valid MBean that can emit + * notifications; false if the object is a valid MBean but that + * cannot emit notifications. + * @throws NotCompliantMBeanException if the given object is not + * a valid MBean. + */ + public static boolean isNotificationSource(Object mbean) + throws NotCompliantMBeanException { + if (mbean instanceof NotificationBroadcaster) + return true; + Object resource = (mbean instanceof DynamicWrapperMBean) ? + ((DynamicWrapperMBean) mbean).getWrappedObject() : mbean; + return (MBeanInjector.injectsSendNotification(resource)); + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/MBean.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package javax.management; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * <p>Indicates that the annotated class is a Standard MBean. A Standard + * MBean class can be defined as in this example:</p> + * + * <pre> + * {@code @MBean} + * public class Configuration { + * {@link ManagedAttribute @ManagedAttribute} + * public int getCacheSize() {...} + * {@code @ManagedAttribute} + * public void setCacheSize(int size); + * + * {@code @ManagedAttribute} + * public long getLastChangedTime(); + * + * {@link ManagedOperation @ManagedOperation} + * public void save(); + * } + * </pre> + * + * <p>The class must be public. Public methods within the class can be + * annotated with {@code @ManagedOperation} to indicate that they are + * MBean operations. Public getter and setter methods within the class + * can be annotated with {@code @ManagedAttribute} to indicate that they define + * MBean attributes.</p> + * + * <p>If the MBean is to be an MXBean rather than a Standard MBean, then + * the {@link MXBean @MXBean} annotation must be used instead of + * {@code @MBean}.</p> + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +public @interface MBean { +}
--- a/jdk/src/share/classes/javax/management/MBeanOperationInfo.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/MBeanOperationInfo.java Wed Jul 05 16:39:18 2017 +0200 @@ -46,25 +46,30 @@ new MBeanOperationInfo[0]; /** - * Indicates that the operation is read-like, - * it basically returns information. + * Indicates that the operation is read-like: + * it returns information but does not change any state. + * @see Impact#INFO */ public static final int INFO = 0; /** - * Indicates that the operation is a write-like, - * and would modify the MBean in some way, typically by writing some value - * or changing a configuration. + * Indicates that the operation is write-like: it has an effect but does + * not return any information from the MBean. + * @see Impact#ACTION */ public static final int ACTION = 1; /** - * Indicates that the operation is both read-like and write-like. + * Indicates that the operation is both read-like and write-like: + * it has an effect, and it also returns information from the MBean. + * @see Impact#ACTION_INFO */ public static final int ACTION_INFO = 2; /** - * Indicates that the operation has an "unknown" nature. + * Indicates that the impact of the operation is unknown or cannot be + * expressed using one of the other values. + * @see Impact#UNKNOWN */ public static final int UNKNOWN = 3; @@ -120,8 +125,9 @@ * describing the parameters(arguments) of the method. This may be * null with the same effect as a zero-length array. * @param type The type of the method's return value. - * @param impact The impact of the method, one of <CODE>INFO, - * ACTION, ACTION_INFO, UNKNOWN</CODE>. + * @param impact The impact of the method, one of + * {@link #INFO}, {@link #ACTION}, {@link #ACTION_INFO}, + * {@link #UNKNOWN}. */ public MBeanOperationInfo(String name, String description, @@ -140,8 +146,9 @@ * describing the parameters(arguments) of the method. This may be * null with the same effect as a zero-length array. * @param type The type of the method's return value. - * @param impact The impact of the method, one of <CODE>INFO, - * ACTION, ACTION_INFO, UNKNOWN</CODE>. + * @param impact The impact of the method, one of + * {@link #INFO}, {@link #ACTION}, {@link #ACTION_INFO}, + * {@link #UNKNOWN}. * @param descriptor The descriptor for the operation. This may be null * which is equivalent to an empty descriptor. * @@ -319,9 +326,14 @@ for (int i = 0; i < classes.length; i++) { Descriptor d = Introspector.descriptorForAnnotations(annots[i]); - final String pn = "p" + (i + 1); - params[i] = - new MBeanParameterInfo(pn, classes[i].getName(), "", d); + String description = Introspector.descriptionForParameter(annots[i]); + if (description == null) + description = ""; + String name = Introspector.nameForParameter(annots[i]); + if (name == null) + name = "p" + (i + 1); + params[i] = new MBeanParameterInfo( + name, classes[i].getName(), description, d); } return params;
--- a/jdk/src/share/classes/javax/management/MBeanRegistration.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/MBeanRegistration.java Wed Jul 05 16:39:18 2017 +0200 @@ -27,9 +27,101 @@ /** - * Can be implemented by an MBean in order to + * <p>Can be implemented by an MBean in order to * carry out operations before and after being registered or unregistered from - * the MBean server. + * the MBean Server. An MBean can also implement this interface in order + * to get a reference to the MBean Server and/or its name within that + * MBean Server.</p> + * + * <h4 id="injection">Resource injection</h4> + * + * <p>As an alternative to implementing {@code MBeanRegistration}, if all that + * is needed is the MBean Server or ObjectName then an MBean can use + * <em>resource injection</em>.</p> + * + * <p>If a field in the MBean object has type {@link ObjectName} and has + * the {@link javax.annotation.Resource @Resource} annotation, + * then the {@code ObjectName} under which the MBean is registered is + * assigned to that field during registration. Likewise, if a field has type + * {@link MBeanServer} and the <code>@Resource</code> annotation, then it will + * be set to the {@code MBeanServer} in which the MBean is registered.</p> + * + * <p>For example:</p> + * + * <pre> + * public Configuration implements ConfigurationMBean { + * @Resource + * private volatile MBeanServer mbeanServer; + * @Resource + * private volatile ObjectName objectName; + * ... + * void unregisterSelf() throws Exception { + * mbeanServer.unregisterMBean(objectName); + * } + * } + * </pre> + * + * <p>Resource injection can also be used on fields of type + * {@link SendNotification} to simplify notification sending. Such a field + * will get a reference to an object of type {@code SendNotification} when + * the MBean is registered, and it can use this reference to send notifications. + * For example:</p> + * + * <pre> + * public Configuration implements ConfigurationMBean { + * @Resource + * private volatile SendNotification sender; + * ... + * private void updated() { + * Notification n = new Notification(...); + * sender.sendNotification(n); + * } + * } + * </pre> + * + * <p>A field to be injected must not be static. It is recommended that + * such fields be declared {@code volatile}.</p> + * + * <p>It is also possible to use the <code>@Resource</code> annotation on + * methods. Such a method must have a {@code void} return type and a single + * argument of the appropriate type, for example {@code ObjectName}.</p> + * + * <p>Any number of fields and methods may have the <code>@Resource</code> + * annotation. All fields and methods with type {@code ObjectName} + * (for example) will receive the same {@code ObjectName} value.</p> + * + * <p>Resource injection is available for all types of MBeans, not just + * Standard MBeans.</p> + * + * <p>If an MBean implements the {@link DynamicWrapperMBean} interface then + * resource injection happens on the object returned by that interface's + * {@link DynamicWrapperMBean#getWrappedObject() getWrappedObject()} method + * rather than on the MBean object itself. + * + * <p>Resource injection happens after the {@link #preRegister preRegister} + * method is called (if any), and before the MBean is actually registered + * in the MBean Server. If a <code>@Resource</code> method throws + * an exception, the effect is the same as if {@code preRegister} had + * thrown the exception. In particular it will prevent the MBean from being + * registered.</p> + * + * <p>Resource injection can be used on a field or method where the type + * is a parent of the injected type, if the injected type is explicitly + * specified in the <code>@Resource</code> annotation. For example:</p> + * + * <pre> + * @Resource(type = MBeanServer.class) + * private volatile MBeanServerConnection mbsc; + * </pre> + * + * <p>Formally, suppose <em>R</em> is the type in the <code>@Resource</code> + * annotation and <em>T</em> is the type of the method parameter or field. + * Then one of <em>R</em> and <em>T</em> must be a subtype of the other + * (or they must be the same type). Injection happens if this subtype + * is {@code MBeanServer}, {@code ObjectName}, or {@code SendNotification}. + * Otherwise the <code>@Resource</code> annotation is ignored.</p> + * + * <p>Resource injection in MBeans is new in version 2.0 of the JMX API.</p> * * @since 1.5 */ @@ -38,12 +130,12 @@ /** * Allows the MBean to perform any operations it needs before - * being registered in the MBean server. If the name of the MBean + * 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. + * registered in the MBean Server. * - * @param server The MBean server in which the MBean will be registered. + * @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 <code>createMBean</code> or @@ -57,7 +149,7 @@ * the returned value. * * @exception java.lang.Exception This exception will be caught by - * the MBean server and re-thrown as an {@link + * the MBean Server and re-thrown as an {@link * MBeanRegistrationException}. */ public ObjectName preRegister(MBeanServer server,
--- a/jdk/src/share/classes/javax/management/MBeanServer.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/MBeanServer.java Wed Jul 05 16:39:18 2017 +0200 @@ -61,7 +61,7 @@ * <CODE>ObjectName</CODE> is: <BR> * <CODE>JMImplementation:type=MBeanServerDelegate</CODE>.</p> * - * <p>An object obtained from the {@link + * <p id="security">An object obtained from the {@link * MBeanServerFactory#createMBeanServer(String) createMBeanServer} or * {@link MBeanServerFactory#newMBeanServer(String) newMBeanServer} * methods of the {@link MBeanServerFactory} class applies security @@ -661,13 +661,16 @@ ReflectionException; /** - * <p>Return the {@link java.lang.ClassLoader} that was used for - * loading the class of the named MBean.</p> + * <p>Return the {@link java.lang.ClassLoader} that was used for loading + * the class of the named MBean. If the MBean implements the {@link + * DynamicWrapperMBean} interface, then the returned value is the + * result of the {@link DynamicWrapperMBean#getWrappedClassLoader()} + * method.</p> * * @param mbeanName The ObjectName of the MBean. * * @return The ClassLoader used for that MBean. If <var>l</var> - * is the MBean's actual ClassLoader, and <var>r</var> is the + * is the value specified by the rules above, and <var>r</var> is the * returned value, then either: * * <ul>
--- a/jdk/src/share/classes/javax/management/MBeanServerConnection.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/MBeanServerConnection.java Wed Jul 05 16:39:18 2017 +0200 @@ -839,6 +839,12 @@ * * <p>Otherwise, the result is false.</p> * + * <p>If the MBean implements the {@link DynamicWrapperMBean} + * interface, then in the above rules X is the result of the MBean's {@link + * DynamicWrapperMBean#getWrappedObject() getWrappedObject()} method and L + * is the result of its {@link DynamicWrapperMBean#getWrappedClassLoader() + * getWrappedClassLoader()} method. + * * @param name The <CODE>ObjectName</CODE> of the MBean. * @param className The name of the class. *
--- a/jdk/src/share/classes/javax/management/MXBean.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/MXBean.java Wed Jul 05 16:39:18 2017 +0200 @@ -27,6 +27,7 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -57,11 +58,13 @@ import javax.management.openmbean.TabularType; /** - <p>Annotation to mark an interface explicitly as being an MXBean - interface, or as not being an MXBean interface. By default, an + <p>Annotation to mark a class or interface explicitly as being an MXBean, + or as not being an MXBean. By default, an interface is an MXBean interface if its name ends with {@code - MXBean}, as in {@code SomethingMXBean}. The following interfaces - are MXBean interfaces:</p> + MXBean}, as in {@code SomethingMXBean}. A class is never an MXBean by + default.</p> + + <p>The following interfaces are MXBean interfaces:</p> <pre> public interface WhatsitMXBean {} @@ -82,6 +85,11 @@ public interface MisleadingMXBean {} </pre> + <p>A class can be annotated with {@code @MXBean} to indicate that it + is an MXBean. In this case, its methods should have <code>@{@link + ManagedAttribute}</code> or <code>@{@link ManagedOperation}</code> + annotations, as described for <code>@{@link MBean}</code>.</p> + <h3 id="MXBean-spec">MXBean specification</h3> <p>The MXBean concept provides a simple way to code an MBean @@ -1246,9 +1254,24 @@ @since 1.6 */ +/* + * This annotation is @Inherited because if an MXBean is defined as a + * class using annotations, then its subclasses are also MXBeans. + * For example: + * @MXBean + * public class Super { + * @ManagedAttribute + * public String getName() {...} + * } + * public class Sub extends Super {} + * Here Sub is an MXBean. + * + * The @Inherited annotation has no effect when applied to an interface. + */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) +@Inherited public @interface MXBean { /** True if the annotated interface is an MXBean interface.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/ManagedAttribute.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package javax.management; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * <p>Indicates that a method in an MBean class defines an MBean attribute. + * This annotation must be applied to a public method of a public class + * that is itself annotated with an {@link MBean @MBean} or + * {@link MXBean @MXBean} annotation, or inherits such an annotation from + * a superclass.</p> + * + * <p>The annotated method must be a getter or setter. In other words, + * it must look like one of the following...</p> + * + * <pre> + * <i>T</i> get<i>Foo</i>() + * void set<i>Foo</i>(<i>T</i> param) + * </pre> + * + * <p>...where <i>{@code T}</i> is any type and <i>{@code Foo}</i> is the + * name of the attribute. For any attribute <i>{@code Foo}</i>, if only + * a {@code get}<i>{@code Foo}</i> method has a {@code ManagedAttribute} + * annotation, then <i>{@code Foo}</i> is a read-only attribute. If only + * a {@code set}<i>{@code Foo}</i> method has a {@code ManagedAttribute} + * annotation, then <i>{@code Foo}</i> is a write-only attribute. If + * both {@code get}<i>{@code Foo}</i> and {@code set}<i>{@code Foo}</i> + * methods have the annotation, then <i>{@code Foo}</i> is a read-write + * attribute. In this last case, the type <i>{@code T}</i> must be the + * same in both methods.</p> + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Documented +public @interface ManagedAttribute { +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/ManagedOperation.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package javax.management; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * <p>Indicates that a method in an MBean class defines an MBean operation. + * This annotation can be applied to:</p> + * + * <ul> + * <li>A public method of a public class + * that is itself annotated with an {@link MBean @MBean} or + * {@link MXBean @MXBean} annotation, or inherits such an annotation from + * a superclass.</li> + * <li>A method of an MBean or MXBean interface. + * </ul> + * + * <p>Every method in an MBean or MXBean interface defines an MBean + * operation even without this annotation, but the annotation allows + * you to specify the impact of the operation:</p> + * + * <pre> + * public interface ConfigurationMBean { + * {@code @ManagedOperation}(impact = {@link Impact#ACTION Impact.ACTION}) + * public void save(); + * ... + * } + * </pre> + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Documented +public @interface ManagedOperation { + /** + * <p>The impact of this operation, as shown by + * {@link MBeanOperationInfo#getImpact()}. + */ + Impact impact() default Impact.UNKNOWN; +}
--- a/jdk/src/share/classes/javax/management/NotQueryExp.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/NotQueryExp.java Wed Jul 05 16:39:18 2017 +0200 @@ -91,6 +91,7 @@ return "not (" + exp + ")"; } + @Override String toQueryString() { return "not (" + Query.toString(exp) + ")"; }
--- a/jdk/src/share/classes/javax/management/NotificationBroadcasterSupport.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/NotificationBroadcasterSupport.java Wed Jul 05 16:39:18 2017 +0200 @@ -58,7 +58,8 @@ * * @since 1.5 */ -public class NotificationBroadcasterSupport implements NotificationEmitter { +public class NotificationBroadcasterSupport + implements NotificationEmitter, SendNotification { /** * Constructs a NotificationBroadcasterSupport where each listener is invoked by the * thread sending the notification. This constructor is equivalent to
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/NotificationInfo.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,117 @@ +/* + * 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. + */ + +package javax.management; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * <p>Specifies the kinds of notification an MBean can emit. In both the + * following examples, the MBean emits notifications of type + * {@code "com.example.notifs.create"} and of type + * {@code "com.example.notifs.destroy"}:</p> + * + * <pre> + * // Example one: a Standard MBean + * {@code @NotificationInfo}(types={"com.example.notifs.create", + * "com.example.notifs.destroy"}) + * public interface CacheMBean {...} + * + * public class Cache implements CacheMBean {...} + * </pre> + * + * <pre> + * // Example two: an annotated MBean + * {@link MBean @MBean} + * {@code @NotificationInfo}(types={"com.example.notifs.create", + * "com.example.notifs.destroy"}) + * public class Cache {...} + * </pre> + * + * <p>Each {@code @NotificationInfo} produces an {@link + * MBeanNotificationInfo} inside the {@link MBeanInfo} of each MBean + * to which the annotation applies.</p> + * + * <p>If you need to specify different notification classes, or different + * descriptions for different notification types, then you can group + * several {@code @NotificationInfo} annotations into a containing + * {@link NotificationInfos @NotificationInfos} annotation. + * + * <p>The {@code NotificationInfo} and {@code NotificationInfos} + * annotations can be applied to the MBean implementation class, or to + * any parent class or interface. These annotations on a class take + * precedence over annotations on any superclass or superinterface. + * If an MBean does not have these annotations on its class or any + * superclass, then superinterfaces are examined. It is an error for + * more than one superinterface to have these annotations, unless one + * of them is a child of all the others.</p> + */ +@Documented +@Inherited +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface NotificationInfo { + /** + * <p>The {@linkplain Notification#getType() notification types} + * that this MBean can emit.</p> + */ + String[] types(); + + /** + * <p>The class that emitted notifications will have. It is recommended + * that this be {@link Notification}, or one of its standard subclasses + * in the JMX API.</p> + */ + Class<? extends Notification> notificationClass() default Notification.class; + + /** + * <p>The description of this notification. For example: + * + * <pre> + * {@code @NotificationInfo}( + * types={"com.example.notifs.create"}, + * description={@code @Description}("object created")) + * </pre> + */ + Description description() default @Description(""); + + /** + * <p>Additional descriptor fields for the derived {@code + * MBeanNotificationInfo}. They are specified in the same way as + * for the {@link DescriptorFields @DescriptorFields} annotation, + * for example:</p> + * <pre> + * {@code @NotificationInfo}( + * types={"com.example.notifs.create"}, + * descriptorFields={"severity=6"}) + * </pre> + */ + String[] descriptorFields() default {}; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/NotificationInfos.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,72 @@ +/* + * 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. + */ + +package javax.management; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.management.remote.JMXConnectionNotification; + +/** + * <p>Specifies the kinds of notification an MBean can emit, when this + * cannot be represented by a single {@link NotificationInfo + * @NotificationInfo} annotation.</p> + * + * <p>For example, this annotation specifies that an MBean can emit + * {@link AttributeChangeNotification} and {@link + * JMXConnectionNotification}:</p> + * + * <pre> + * {@code @NotificationInfos}( + * {@code @NotificationInfo}( + * types = {{@link AttributeChangeNotification#ATTRIBUTE_CHANGE}}, + * notificationClass = AttributeChangeNotification.class), + * {@code @NotificationInfo}( + * types = {{@link JMXConnectionNotification#OPENED}, + * {@link JMXConnectionNotification#CLOSED}}, + * notificationClass = JMXConnectionNotification.class) + * ) + * </pre> + * + * <p>If an MBean has both {@code NotificationInfo} and {@code + * NotificationInfos} on the same class or interface, the effect is + * the same as if the {@code NotificationInfo} were moved inside the + * {@code NotificationInfos}.</p> + */ +@Documented +@Inherited +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface NotificationInfos { + /** + * <p>The {@link NotificationInfo} annotations.</p> + */ + NotificationInfo[] value(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/management/SendNotification.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package javax.management; + +/** + * Interface implemented by objects that can be asked to send a notification. + */ +public interface SendNotification { + /** + * Sends a notification. + * + * @param notification The notification to send. + */ + public void sendNotification(Notification notification); +}
--- a/jdk/src/share/classes/javax/management/StandardEmitterMBean.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/StandardEmitterMBean.java Wed Jul 05 16:39:18 2017 +0200 @@ -25,6 +25,9 @@ package javax.management; +import com.sun.jmx.mbeanserver.MBeanInjector; +import static javax.management.JMX.MBeanOptions; + /** * <p>An MBean whose management interface is determined by reflection * on a Java interface, and that emits notifications.</p> @@ -62,7 +65,7 @@ * @since 1.6 */ public class StandardEmitterMBean extends StandardMBean - implements NotificationEmitter { + implements NotificationEmitter, SendNotification { private final NotificationEmitter emitter; private final MBeanNotificationInfo[] notificationInfo; @@ -76,9 +79,10 @@ * for {@code implementation} and {@code emitter} to be the same object.</p> * * <p>If {@code emitter} is an instance of {@code - * NotificationBroadcasterSupport} then the MBean's {@link #sendNotification + * SendNotification} (for example, a {@link NotificationBroadcasterSupport}), + * then the MBean's {@link #sendNotification * sendNotification} method will call {@code emitter.}{@link - * NotificationBroadcasterSupport#sendNotification sendNotification}.</p> + * SendNotification#sendNotification sendNotification}.</p> * * <p>The array returned by {@link #getNotificationInfo()} on the * new MBean is a copy of the array returned by @@ -90,20 +94,18 @@ * * @param implementation the implementation of the MBean interface. * @param mbeanInterface a Standard MBean interface. - * @param emitter the object that will handle notifications. + * @param emitter the object that will handle notifications. If null, + * a new {@code NotificationEmitter} will be constructed that also + * implements {@link SendNotification}. * * @throws IllegalArgumentException if the {@code mbeanInterface} * does not follow JMX design patterns for Management Interfaces, or * if the given {@code implementation} does not implement the - * specified interface, or if {@code emitter} is null. + * specified interface. */ public <T> StandardEmitterMBean(T implementation, Class<T> mbeanInterface, NotificationEmitter emitter) { - super(implementation, mbeanInterface, false); - if (emitter == null) - throw new IllegalArgumentException("Null emitter"); - this.emitter = emitter; - this.notificationInfo = emitter.getNotificationInfo(); + this(implementation, mbeanInterface, false, emitter); } /** @@ -118,9 +120,10 @@ * same object.</p> * * <p>If {@code emitter} is an instance of {@code - * NotificationBroadcasterSupport} then the MBean's {@link #sendNotification + * SendNotification} (for example, a {@link NotificationBroadcasterSupport}), + * then the MBean's {@link #sendNotification * sendNotification} method will call {@code emitter.}{@link - * NotificationBroadcasterSupport#sendNotification sendNotification}.</p> + * SendNotification#sendNotification sendNotification}.</p> * * <p>The array returned by {@link #getNotificationInfo()} on the * new MBean is a copy of the array returned by @@ -134,21 +137,69 @@ * @param mbeanInterface a Standard MBean interface. * @param isMXBean If true, the {@code mbeanInterface} parameter * names an MXBean interface and the resultant MBean is an MXBean. - * @param emitter the object that will handle notifications. + * @param emitter the object that will handle notifications. If null, + * a new {@code NotificationEmitter} will be constructed that also + * implements {@link SendNotification}. * * @throws IllegalArgumentException if the {@code mbeanInterface} * does not follow JMX design patterns for Management Interfaces, or * if the given {@code implementation} does not implement the - * specified interface, or if {@code emitter} is null. + * specified interface. */ public <T> StandardEmitterMBean(T implementation, Class<T> mbeanInterface, boolean isMXBean, NotificationEmitter emitter) { - super(implementation, mbeanInterface, isMXBean); + this(implementation, mbeanInterface, + isMXBean ? MBeanOptions.MXBEAN : null, emitter); + } + + /** + * <p>Make an MBean whose management interface is specified by {@code + * mbeanInterface}, with the given implementation and options, and where + * notifications are handled by the given {@code NotificationEmitter}. + * Options select whether to make a Standard MBean or an MXBean, and + * whether the result of {@link #getWrappedObject()} is the {@code + * StandardEmitterMBean} object or the given implementation. The resultant + * MBean implements the {@code NotificationEmitter} interface by forwarding + * its methods to {@code emitter}. It is legal and useful for {@code + * implementation} and {@code emitter} to be the same object.</p> + * + * <p>If {@code emitter} is an instance of {@code + * SendNotification} (for example, a {@link NotificationBroadcasterSupport}), + * then the MBean's {@link #sendNotification + * sendNotification} method will call {@code emitter.}{@link + * SendNotification#sendNotification sendNotification}.</p> + * + * <p>The array returned by {@link #getNotificationInfo()} on the + * new MBean is a copy of the array returned by + * {@code emitter.}{@link NotificationBroadcaster#getNotificationInfo + * getNotificationInfo()} at the time of construction. If the array + * returned by {@code emitter.getNotificationInfo()} later changes, + * that will have no effect on this object's + * {@code getNotificationInfo()}.</p> + * + * @param implementation the implementation of the MBean interface. + * @param mbeanInterface a Standard MBean interface. + * @param options MBeanOptions that control the operation of the resulting + * MBean. + * @param emitter the object that will handle notifications. If null, + * a new {@code NotificationEmitter} will be constructed that also + * implements {@link SendNotification}. + * + * @throws IllegalArgumentException if the {@code mbeanInterface} + * does not follow JMX design patterns for Management Interfaces, or + * if the given {@code implementation} does not implement the + * specified interface. + */ + public <T> StandardEmitterMBean(T implementation, Class<T> mbeanInterface, + MBeanOptions options, + NotificationEmitter emitter) { + super(implementation, mbeanInterface, options); if (emitter == null) - throw new IllegalArgumentException("Null emitter"); + emitter = defaultEmitter(); this.emitter = emitter; this.notificationInfo = emitter.getNotificationInfo(); + injectEmitter(); } /** @@ -159,9 +210,10 @@ * by forwarding its methods to {@code emitter}.</p> * * <p>If {@code emitter} is an instance of {@code - * NotificationBroadcasterSupport} then the MBean's {@link #sendNotification + * SendNotification} (for example, a {@link NotificationBroadcasterSupport}), + * then the MBean's {@link #sendNotification * sendNotification} method will call {@code emitter.}{@link - * NotificationBroadcasterSupport#sendNotification sendNotification}.</p> + * SendNotification#sendNotification sendNotification}.</p> * * <p>The array returned by {@link #getNotificationInfo()} on the * new MBean is a copy of the array returned by @@ -175,20 +227,17 @@ * the given {@code mbeanInterface}.</p> * * @param mbeanInterface a StandardMBean interface. - * @param emitter the object that will handle notifications. + * @param emitter the object that will handle notifications. If null, + * a new {@code NotificationEmitter} will be constructed that also + * implements {@link SendNotification}. * * @throws IllegalArgumentException if the {@code mbeanInterface} * does not follow JMX design patterns for Management Interfaces, or - * if {@code this} does not implement the specified interface, or - * if {@code emitter} is null. + * if {@code this} does not implement the specified interface. */ protected StandardEmitterMBean(Class<?> mbeanInterface, NotificationEmitter emitter) { - super(mbeanInterface, false); - if (emitter == null) - throw new IllegalArgumentException("Null emitter"); - this.emitter = emitter; - this.notificationInfo = emitter.getNotificationInfo(); + this(mbeanInterface, false, emitter); } /** @@ -200,9 +249,10 @@ * forwarding its methods to {@code emitter}.</p> * * <p>If {@code emitter} is an instance of {@code - * NotificationBroadcasterSupport} then the MBean's {@link #sendNotification + * SendNotification} (for example, a {@link NotificationBroadcasterSupport}), + * then the MBean's {@link #sendNotification * sendNotification} method will call {@code emitter.}{@link - * NotificationBroadcasterSupport#sendNotification sendNotification}.</p> + * SendNotification#sendNotification sendNotification}.</p> * * <p>The array returned by {@link #getNotificationInfo()} on the * new MBean is a copy of the array returned by @@ -218,20 +268,86 @@ * @param mbeanInterface a StandardMBean interface. * @param isMXBean If true, the {@code mbeanInterface} parameter * names an MXBean interface and the resultant MBean is an MXBean. - * @param emitter the object that will handle notifications. + * @param emitter the object that will handle notifications. If null, + * a new {@code NotificationEmitter} will be constructed that also + * implements {@link SendNotification}. * * @throws IllegalArgumentException if the {@code mbeanInterface} * does not follow JMX design patterns for Management Interfaces, or - * if {@code this} does not implement the specified interface, or - * if {@code emitter} is null. + * if {@code this} does not implement the specified interface. */ protected StandardEmitterMBean(Class<?> mbeanInterface, boolean isMXBean, NotificationEmitter emitter) { - super(mbeanInterface, isMXBean); + this(mbeanInterface, isMXBean ? MBeanOptions.MXBEAN : null, emitter); + } + + /** + * <p>Make an MBean whose management interface is specified by {@code + * mbeanInterface}, with the given options, and where notifications are + * handled by the given {@code NotificationEmitter}. This constructor can + * be used to make either Standard MBeans or MXBeans. The resultant MBean + * implements the {@code NotificationEmitter} interface by forwarding its + * methods to {@code emitter}.</p> + * + * <p>If {@code emitter} is an instance of {@code + * SendNotification} (for example, a {@link NotificationBroadcasterSupport}), + * then the MBean's {@link #sendNotification + * sendNotification} method will call {@code emitter.}{@link + * SendNotification#sendNotification sendNotification}.</p> + * + * <p>The array returned by {@link #getNotificationInfo()} on the + * new MBean is a copy of the array returned by + * {@code emitter.}{@link NotificationBroadcaster#getNotificationInfo + * getNotificationInfo()} at the time of construction. If the array + * returned by {@code emitter.getNotificationInfo()} later changes, + * that will have no effect on this object's + * {@code getNotificationInfo()}.</p> + * + * <p>This constructor must be called from a subclass that implements + * the given {@code mbeanInterface}.</p> + * + * @param mbeanInterface a StandardMBean interface. + * @param options MBeanOptions that control the operation of the resulting + * MBean. + * @param emitter the object that will handle notifications. If null, + * a new {@code NotificationEmitter} will be constructed that also + * implements {@link SendNotification}. + * + * @throws IllegalArgumentException if the {@code mbeanInterface} + * does not follow JMX design patterns for Management Interfaces, or + * if {@code this} does not implement the specified interface. + */ + protected StandardEmitterMBean(Class<?> mbeanInterface, MBeanOptions options, + NotificationEmitter emitter) { + super(mbeanInterface, options); if (emitter == null) - throw new IllegalArgumentException("Null emitter"); + emitter = defaultEmitter(); this.emitter = emitter; this.notificationInfo = emitter.getNotificationInfo(); + injectEmitter(); + } + + private NotificationEmitter defaultEmitter() { + MBeanNotificationInfo[] mbnis = getNotificationInfo(); + // Will be null unless getNotificationInfo() is overridden, + // since the notificationInfo field has not been set at this point. + if (mbnis == null) + mbnis = getMBeanInfo().getNotifications(); + return new NotificationBroadcasterSupport(mbnis); + } + + private void injectEmitter() { + if (emitter instanceof SendNotification) { + try { + Object resource = getImplementation(); + SendNotification send = (SendNotification) emitter; + MBeanInjector.injectSendNotification(resource, send); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } } public void removeNotificationListener(NotificationListener listener) @@ -259,10 +375,10 @@ /** * <p>Sends a notification.</p> * - * <p>If the {@code emitter} parameter to the constructor was an - * instance of {@code NotificationBroadcasterSupport} then this - * method will call {@code emitter.}{@link - * NotificationBroadcasterSupport#sendNotification + * <p>If the {@code emitter} parameter to the constructor was + * an instance of {@link SendNotification}, such as {@link + * NotificationBroadcasterSupport}, then this method will call {@code + * emitter.}{@link SendNotification#sendNotification * sendNotification}.</p> * * @param n the notification to send. @@ -271,13 +387,12 @@ * constructor was not a {@code NotificationBroadcasterSupport}. */ public void sendNotification(Notification n) { - if (emitter instanceof NotificationBroadcasterSupport) - ((NotificationBroadcasterSupport) emitter).sendNotification(n); + if (emitter instanceof SendNotification) + ((SendNotification) emitter).sendNotification(n); else { final String msg = "Cannot sendNotification when emitter is not an " + - "instance of NotificationBroadcasterSupport: " + - emitter.getClass().getName(); + "instance of SendNotification: " + emitter.getClass().getName(); throw new ClassCastException(msg); } } @@ -292,6 +407,7 @@ * @param info The default MBeanInfo derived by reflection. * @return the MBeanNotificationInfo[] for the new MBeanInfo. */ + @Override MBeanNotificationInfo[] getNotifications(MBeanInfo info) { return getNotificationInfo(); }
--- a/jdk/src/share/classes/javax/management/StandardMBean.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/StandardMBean.java Wed Jul 05 16:39:18 2017 +0200 @@ -27,6 +27,7 @@ import com.sun.jmx.mbeanserver.DescriptorCache; import com.sun.jmx.mbeanserver.Introspector; +import com.sun.jmx.mbeanserver.MBeanInjector; import com.sun.jmx.mbeanserver.MBeanSupport; import com.sun.jmx.mbeanserver.MXBeanSupport; import com.sun.jmx.mbeanserver.StandardMBeanSupport; @@ -125,7 +126,78 @@ * * @since 1.5 */ -public class StandardMBean implements DynamicMBean, MBeanRegistration { +public class StandardMBean implements DynamicWrapperMBean, MBeanRegistration { + + /** + * <p>Options controlling the behavior of {@code StandardMBean} instances.</p> + */ + public static class Options extends JMX.MBeanOptions { + private static final long serialVersionUID = 5107355471177517164L; + + private boolean wrappedVisible; + + /** + * <p>Construct an {@code Options} object where all options have + * their default values.</p> + */ + public Options() {} + + @Override + public Options clone() { + return (Options) super.clone(); + } + + /** + * <p>Defines whether the {@link StandardMBean#getWrappedObject() + * getWrappedObject} method returns the wrapped object.</p> + * + * <p>If this option is true, then {@code getWrappedObject()} will return + * the same object as {@link StandardMBean#getImplementation() + * getImplementation}. Otherwise, it will return the + * StandardMBean instance itself. The setting of this option + * affects the behavior of {@link MBeanServer#getClassLoaderFor + * MBeanServer.getClassLoaderFor} and {@link MBeanServer#isInstanceOf + * MBeanServer.isInstanceOf}. The default value is false for + * compatibility reasons, but true is a better value for most new code.</p> + * + * @return true if this StandardMBean's {@link + * StandardMBean#getWrappedObject getWrappedObject} returns the wrapped + * object. + */ + public boolean isWrappedObjectVisible() { + return this.wrappedVisible; + } + + /** + * <p>Set the {@link #isWrappedObjectVisible WrappedObjectVisible} option + * to the given value.</p> + * @param visible the new value. + */ + public void setWrappedObjectVisible(boolean visible) { + this.wrappedVisible = visible; + } + + // Canonical objects for each of (MXBean,!MXBean) x (WVisible,!WVisible) + private static final Options[] CANONICALS = { + new Options(), new Options(), new Options(), new Options(), + }; + static { + CANONICALS[1].setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT); + CANONICALS[2].setWrappedObjectVisible(true); + CANONICALS[3].setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT); + CANONICALS[3].setWrappedObjectVisible(true); + } + @Override + MBeanOptions[] canonicals() { + return CANONICALS; + } + + @Override + boolean same(MBeanOptions opts) { + return (super.same(opts) && opts instanceof Options && + ((Options) opts).wrappedVisible == wrappedVisible); + } + } private final static DescriptorCache descriptors = DescriptorCache.getInstance(JMX.proof); @@ -347,7 +419,7 @@ * the management interface associated with the given * implementation. * @param options MBeanOptions that control the operation of the resulting - * MBean, as documented in the {@link MBeanOptions} class. + * MBean. * @param <T> Allows the compiler to check * that {@code implementation} does indeed implement the class * described by {@code mbeanInterface}. The compiler can only @@ -381,7 +453,7 @@ * @param mbeanInterface The Management Interface exported by this * MBean. * @param options MBeanOptions that control the operation of the resulting - * MBean, as documented in the {@link MBeanOptions} class. + * MBean. * * @exception IllegalArgumentException if the <var>mbeanInterface</var> * does not follow JMX design patterns for Management Interfaces, or @@ -441,7 +513,67 @@ * @see #setImplementation **/ public Object getImplementation() { - return mbean.getResource(); + return mbean.getWrappedObject(); + } + + /** + * <p>Get the wrapped implementation object or return this object.</p> + * + * <p>For compatibility reasons, this method only returns the wrapped + * implementation object if the {@link Options#isWrappedObjectVisible + * WrappedObjectVisible} option was specified when this StandardMBean + * was created. Otherwise it returns {@code this}.</p> + * + * <p>If you want the MBeanServer's {@link MBeanServer#getClassLoaderFor + * getClassLoaderFor} and {@link MBeanServer#isInstanceOf + * isInstanceOf} methods to refer to the wrapped implementation and + * not this StandardMBean object, then you must set the + * {@code WrappedObjectVisible} option, for example using:</p> + * + * <pre> + * StandardMBean.Options opts = new StandardMBean.Options(); + * opts.setWrappedObjectVisible(true); + * StandardMBean mbean = new StandardMBean(impl, MyMBean.class, opts); + * </pre> + * + * @return The wrapped implementation object, or this StandardMBean + * instance. + */ + public Object getWrappedObject() { + if (options instanceof Options && + ((Options) options).isWrappedObjectVisible()) + return getImplementation(); + else + return this; + } + + /** + * <p>Get the ClassLoader of the wrapped implementation object or of this + * object.</p> + * + * <p>For compatibility reasons, this method only returns the ClassLoader + * of the wrapped implementation object if the {@link + * Options#isWrappedObjectVisible WrappedObjectVisible} option was + * specified when this StandardMBean was created. Otherwise it returns + * {@code this.getClass().getClassLoader()}.</p> + * + * <p>If you want the MBeanServer's {@link MBeanServer#getClassLoaderFor + * getClassLoaderFor} and {@link MBeanServer#isInstanceOf + * isInstanceOf} methods to refer to the wrapped implementation and + * not this StandardMBean object, then you must set the + * {@code WrappedObjectVisible} option, for example using:</p> + * + * <pre> + * StandardMBean.Options opts = new StandardMBean.Options(); + * opts.setWrappedObjectVisible(true); + * StandardMBean mbean = new StandardMBean(impl, MyMBean.class, opts); + * </pre> + * + * @return The ClassLoader of the wrapped Cimplementation object, or of + * this StandardMBean instance. + */ + public ClassLoader getWrappedClassLoader() { + return getWrappedObject().getClass().getClassLoader(); } /** @@ -457,7 +589,7 @@ * @return The class of the implementation of this Standard MBean (or MXBean). **/ public Class<?> getImplementationClass() { - return mbean.getResource().getClass(); + return mbean.getWrappedObject().getClass(); } /** @@ -559,7 +691,7 @@ MBeanSupport msupport = mbean; final MBeanInfo bi = msupport.getMBeanInfo(); - final Object impl = msupport.getResource(); + final Object impl = msupport.getWrappedObject(); final boolean immutableInfo = immutableInfo(this.getClass()); @@ -1184,6 +1316,7 @@ public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { mbean.register(server, name); + MBeanInjector.inject(mbean.getWrappedObject(), server, name); return name; }
--- a/jdk/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/modelmbean/RequiredModelMBean.java Wed Jul 05 16:39:18 2017 +0200 @@ -23,7 +23,7 @@ * have any questions. */ /* - * @author IBM Corp. + * @(#)author IBM Corp. * * Copyright IBM Corp. 1999-2000. All rights reserved. */ @@ -55,6 +55,7 @@ import javax.management.AttributeList; import javax.management.AttributeNotFoundException; import javax.management.Descriptor; +import javax.management.DynamicWrapperMBean; import javax.management.InstanceNotFoundException; import javax.management.InvalidAttributeValueException; import javax.management.ListenerNotFoundException; @@ -115,7 +116,7 @@ */ public class RequiredModelMBean - implements ModelMBean, MBeanRegistration, NotificationEmitter { + implements ModelMBean, MBeanRegistration, NotificationEmitter, DynamicWrapperMBean { /*************************************/ /* attributes */ @@ -133,6 +134,9 @@ * and operations will be executed */ private Object managedResource = null; + /* true if getWrappedObject returns the wrapped resource */ + private boolean visible; + /* records the registering in MBeanServer */ private boolean registered = false; private transient MBeanServer server = null; @@ -318,9 +322,13 @@ * * @param mr Object that is the managed resource * @param mr_type The type of reference for the managed resource. - * <br>Can be: "ObjectReference", "Handle", "IOR", "EJBHandle", - * or "RMIReference". - * <br>In this implementation only "ObjectReference" is supported. + * <br>Can be: "ObjectReference", "VisibleObjectReference", + * "Handle", "IOR", "EJBHandle", or "RMIReference". + * <br>In this implementation only "ObjectReference" and + * "VisibleObjectReference" are supported. The two + * types are equivalent except for the behavior of the + * {@link #getWrappedObject()} and {@link #getWrappedClassLoader()} + * methods. * * @exception MBeanException The initializer of the object has * thrown an exception. @@ -340,10 +348,11 @@ "setManagedResource(Object,String)","Entry"); } + visible = "visibleObjectReference".equalsIgnoreCase(mr_type); + // check that the mr_type is supported by this JMXAgent // only "objectReference" is supported - if ((mr_type == null) || - (! mr_type.equalsIgnoreCase("objectReference"))) { + if (!"objectReference".equalsIgnoreCase(mr_type) && !visible) { if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { MODELMBEAN_LOGGER.logp(Level.FINER, RequiredModelMBean.class.getName(), @@ -369,6 +378,51 @@ } /** + * <p>Get the managed resource for this Model MBean. For compatibility + * reasons, the managed resource is only returned if the resource type + * specified to {@link #setManagedResource setManagedResource} was {@code + * "visibleObjectReference"}. Otherwise, {@code this} is returned.</p> + * + * @return The value that was specified to {@link #setManagedResource + * setManagedResource}, if the resource type is {@code + * "visibleObjectReference"}. Otherwise, {@code this}. + */ + public Object getWrappedObject() { + if (visible) + return managedResource; + else + return this; + } + + /** + * <p>Get the ClassLoader of the managed resource for this Model MBean. For + * compatibility reasons, the ClassLoader of the managed resource is only + * returned if the resource type specified to {@link #setManagedResource + * setManagedResource} was {@code "visibleObjectReference"}. Otherwise, + * {@code this.getClass().getClassLoader()} is returned.</p> + * + * @return The ClassLoader of the value that was specified to + * {@link #setManagedResource setManagedResource}, if the resource + * type is {@code "visibleObjectReference"}. Otherwise, {@code + * this.getClass().getClassLoader()}. + */ + public ClassLoader getWrappedClassLoader() { + return getWrappedObject().getClass().getClassLoader(); + } + + private static boolean isTrue(Descriptor d, String field) { + if (d == null) + return false; + Object x = d.getFieldValue(field); + if (x instanceof Boolean) + return (Boolean) x; + if (!(x instanceof String)) + return false; + String s = (String) x; + return ("true".equalsIgnoreCase(s) || "T".equalsIgnoreCase(s)); + } + + /** * <p>Instantiates this MBean instance with the data found for * the MBean in the persistent store. The data loaded could include * attribute and operation values.</p>
--- a/jdk/src/share/classes/javax/management/monitor/package.html Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/monitor/package.html Wed Jul 05 16:39:18 2017 +0200 @@ -38,14 +38,17 @@ so within the access control context of the {@link javax.management.monitor.Monitor#start} caller.</p> - <p>The value being monitored can be a simple value contained within a - complex type. For example, the {@link java.lang.management.MemoryMXBean - MemoryMXBean} defined in <tt>java.lang.management</tt> has an attribute - <tt>HeapMemoryUsage</tt> of type {@link java.lang.management.MemoryUsage - MemoryUsage}. To monitor the amount of <i>used</i> memory, described by - the <tt>used</tt> property of <tt>MemoryUsage</tt>, you could monitor - "<tt>HeapMemoryUsage.used</tt>". That string would be the argument to - {@link javax.management.monitor.MonitorMBean#setObservedAttribute(String) + <p id="complex">The value being monitored can be a simple value + contained within a complex type. For example, the {@link + java.lang.management.MemoryMXBean MemoryMXBean} defined in + <tt>java.lang.management</tt> has an attribute + <tt>HeapMemoryUsage</tt> of type {@link + java.lang.management.MemoryUsage MemoryUsage}. To monitor the + amount of <i>used</i> memory, described by the <tt>used</tt> + property of <tt>MemoryUsage</tt>, you could monitor + "<tt>HeapMemoryUsage.used</tt>". That string would be the + argument to {@link + javax.management.monitor.MonitorMBean#setObservedAttribute(String) setObservedAttribute}.</p> <p>The rules used to interpret an <tt>ObservedAttribute</tt> like
--- a/jdk/src/share/classes/javax/management/package.html Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/javax/management/package.html Wed Jul 05 16:39:18 2017 +0200 @@ -56,41 +56,41 @@ resource. It has a <em>management interface</em> consisting of:</p> - <ul> - <li>named and typed attributes that can be read and/or - written</li> - - <li>named and typed operations that can be invoked</li> + <ul> + <li>named and typed attributes that can be read and/or + written</li> - <li>typed notifications that can be emitted by the MBean.</li> - </ul> + <li>named and typed operations that can be invoked</li> + + <li>typed notifications that can be emitted by the MBean.</li> + </ul> - <p>For example, an MBean representing an application's - configuration could have attributes representing the different - configuration items. Reading the <code>CacheSize</code> - attribute would return the current value of that item. - Writing it would update the item, potentially changing the - behavior of the running application. An operation such as - <code>save</code> could store the current configuration - persistently. A notification such as - <code>ConfigurationChangedNotification</code> could be sent - every time the configuration is changed.</p> + <p>For example, an MBean representing an application's + configuration could have attributes representing the different + configuration items. Reading the <code>CacheSize</code> + attribute would return the current value of that item. + Writing it would update the item, potentially changing the + behavior of the running application. An operation such as + <code>save</code> could store the current configuration + persistently. A notification such as + <code>ConfigurationChangedNotification</code> could be sent + every time the configuration is changed.</p> - <p>In the standard usage of the JMX API, MBeans are implemented - as Java objects. However, as explained below, these objects are - not usually referenced directly.</p> + <p>In the standard usage of the JMX API, MBeans are implemented + as Java objects. However, as explained below, these objects are + not usually referenced directly.</p> - <h3>Standard MBeans</h3> + <h3>Standard MBeans</h3> - <p>To make MBean implementation simple, the JMX API includes the - notion of <em>Standard MBeans</em>. A Standard MBean is one - whose attributes and operations are deduced from a Java - interface using certain naming patterns, similar to those used - by JavaBeans<sup><font size="-1">TM</font></sup>. For - example, consider an interface like this:</p> + <p>To make MBean implementation simple, the JMX API includes the + notion of <em>Standard MBeans</em>. A Standard MBean is one + whose attributes and operations are deduced from a Java + interface using certain naming patterns, similar to those used + by JavaBeans<sup><font size="-1">TM</font></sup>. For + example, consider an interface like this:</p> - <pre> + <pre> public interface ConfigurationMBean { public int getCacheSize(); public void setCacheSize(int size); @@ -128,107 +128,148 @@ class.</p> - <h3>MXBeans</h3> - - <p>An <em>MXBean</em> is a variant of Standard MBean where complex - types are mapped to a standard set of types defined in the - {@link javax.management.openmbean} package. MXBeans are appropriate - if you would otherwise need to reference application-specific - classes in your MBean interface. They are described in detail - in the specification for {@link javax.management.MXBean MXBean}. + <h3 id="stdannot">Defining Standard MBeans with annotations</h3> + <p>As an alternative to creating an interface such as + <code>ConfigurationMBean</code> and a class that implements it, + you can write just the class, and use annotations to pick out the + public methods that will make up the management interface. For + example, the following class has the same management interface + as a <code>Configuration</code> class that implements the + <code>ConfigurationMBean</code> interface above.</p> - <h3>Dynamic MBeans</h3> + <pre> + {@link javax.management.MBean @MBean} + public class Configuration { + {@link javax.management.ManagedAttribute @ManagedAttribute} + public int getCacheSize() {...} + @ManagedAttribute + public void setCacheSize(int size) {...} + + @ManagedAttribute + public long getLastChangedTime() {...} - <p>A <em>Dynamic MBean</em> is an MBean that defines its - management interface at run-time. For example, a configuration - MBean could determine the names and types of the attributes it - exposes by parsing an XML file.</p> + {@link javax.management.ManagedOperation @ManagedOperation} + public void save() {...} + ... + } + </pre> - <p>Any Java object of a class that implements the {@link - javax.management.DynamicMBean DynamicMBean} interface is a - Dynamic MBean.</p> + <p>This approach simplifies development, but it does have two + potential drawbacks. First, if you run the Javadoc tool on + this class, the documentation of the management interface may + be mixed in with the documentation of non-management methods + in the class. Second, you cannot make a proxy + as described <a href="#proxy">below</a> if you do not have an + interface like <code>ConfigurationMBean</code>.</p> - <h3>Open MBeans</h3> + <h3>MXBeans</h3> - <p>An <em>Open MBean</em> is a kind of Dynamic MBean where the - types of attributes and of operation parameters and return - values are built using a small set of predefined Java classes. - Open MBeans facilitate operation with remote management programs - that do not necessarily have access to application-specific - types, including non-Java programs. Open MBeans are defined by - the package <a href="openmbean/package-summary.html"><code> - javax.management.openmbean</code></a>.</p> + <p>An <em>MXBean</em> is a variant of Standard MBean where complex + types are mapped to a standard set of types defined in the + {@link javax.management.openmbean} package. MXBeans are appropriate + if you would otherwise need to reference application-specific + classes in your MBean interface. They are described in detail + in the specification for {@link javax.management.MXBean MXBean}.</p> + + <p>You can define MXBeans using annotations as described + in the <a href="#stdannot">previous section</a>, but + using the <code>@MXBean</code> annotation instead of + <code>@MBean</code>.</p> - <h3>Model MBeans</h3> + <h3>Dynamic MBeans</h3> - <p>A <em>Model MBean</em> is a kind of Dynamic MBean that acts - as a bridge between the management interface and the - underlying managed resource. Both the management interface and - the managed resource are specified as Java objects. The same - Model MBean implementation can be reused many times with - different management interfaces and managed resources, and it can - provide common functionality such as persistence and caching. - Model MBeans are defined by the package - <a href="modelmbean/package-summary.html"><code> - javax.management.modelmbean</code></a>.</p> + <p>A <em>Dynamic MBean</em> is an MBean that defines its + management interface at run-time. For example, a configuration + MBean could determine the names and types of the attributes it + exposes by parsing an XML file.</p> + + <p>Any Java object of a class that implements the {@link + javax.management.DynamicMBean DynamicMBean} interface is a + Dynamic MBean.</p> - <h2>MBean Server</h2> - - <p>To be useful, an MBean must be registered in an <em>MBean - Server</em>. An MBean Server is a repository of MBeans. - Usually the only access to the MBeans is through the MBean - Server. In other words, code no longer accesses the Java - object implementing the MBean directly, but instead accesses - the MBean by name through the MBean Server. Each MBean has a - unique name within the MBean Server, defined by the {@link - javax.management.ObjectName ObjectName} class.</p> - - <p>An MBean Server is an object implementing the interface - {@link javax.management.MBeanServer MBeanServer}. - The most convenient MBean Server to use is the - <em>Platform MBean Server</em>. This is a - single MBean Server that can be shared by different managed - components running within the same Java Virtual Machine. The - Platform MBean Server is accessed with the method {@link - java.lang.management.ManagementFactory#getPlatformMBeanServer()}.</p> + <h3>Open MBeans</h3> + + <p>An <em>Open MBean</em> is a kind of Dynamic MBean where the + types of attributes and of operation parameters and return + values are built using a small set of predefined Java classes. + Open MBeans facilitate operation with remote management programs + that do not necessarily have access to application-specific + types, including non-Java programs. Open MBeans are defined by + the package <a href="openmbean/package-summary.html"><code> + javax.management.openmbean</code></a>.</p> + - <p>Application code can also create a new MBean Server, or - access already-created MBean Servers, using the {@link - javax.management.MBeanServerFactory MBeanServerFactory} class.</p> + <h3>Model MBeans</h3> + + <p>A <em>Model MBean</em> is a kind of Dynamic MBean that acts + as a bridge between the management interface and the + underlying managed resource. Both the management interface and + the managed resource are specified as Java objects. The same + Model MBean implementation can be reused many times with + different management interfaces and managed resources, and it can + provide common functionality such as persistence and caching. + Model MBeans are defined by the package + <a href="modelmbean/package-summary.html"><code> + javax.management.modelmbean</code></a>.</p> - <h3>Creating MBeans in the MBean Server</h3> + <h2>MBean Server</h2> - <p>There are two ways to create an MBean. One is to construct a - Java object that will be the MBean, then use the {@link - javax.management.MBeanServer#registerMBean registerMBean} - method to register it in the MBean Server. The other is to - create and register the MBean in a single operation using one - of the {@link javax.management.MBeanServer#createMBean(String, - javax.management.ObjectName) createMBean} methods.</p> + <p>To be useful, an MBean must be registered in an <em>MBean + Server</em>. An MBean Server is a repository of MBeans. + Usually the only access to the MBeans is through the MBean + Server. In other words, code no longer accesses the Java + object implementing the MBean directly, but instead accesses + the MBean by name through the MBean Server. Each MBean has a + unique name within the MBean Server, defined by the {@link + javax.management.ObjectName ObjectName} class.</p> - <p>The <code>registerMBean</code> method is simpler for local - use, but cannot be used remotely. The - <code>createMBean</code> method can be used remotely, but - sometimes requires attention to class loading issues.</p> + <p>An MBean Server is an object implementing the interface + {@link javax.management.MBeanServer MBeanServer}. + The most convenient MBean Server to use is the + <em>Platform MBean Server</em>. This is a + single MBean Server that can be shared by different managed + components running within the same Java Virtual Machine. The + Platform MBean Server is accessed with the method {@link + java.lang.management.ManagementFactory#getPlatformMBeanServer()}.</p> - <p>An MBean can perform actions when it is registered in or - unregistered from an MBean Server if it implements the {@link - javax.management.MBeanRegistration MBeanRegistration} - interface.</p> + <p>Application code can also create a new MBean Server, or + access already-created MBean Servers, using the {@link + javax.management.MBeanServerFactory MBeanServerFactory} class.</p> - <h3>Accessing MBeans in the MBean Server</h3> + <h3>Creating MBeans in the MBean Server</h3> + + <p>There are two ways to create an MBean. One is to construct a + Java object that will be the MBean, then use the {@link + javax.management.MBeanServer#registerMBean registerMBean} + method to register it in the MBean Server. The other is to + create and register the MBean in a single operation using one + of the {@link javax.management.MBeanServer#createMBean(String, + javax.management.ObjectName) createMBean} methods.</p> - <p>Given an <code>ObjectName</code> <code>name</code> and an - <code>MBeanServer</code> <code>mbs</code>, you can access - attributes and operations as in this example:</p> + <p>The <code>registerMBean</code> method is simpler for local + use, but cannot be used remotely. The + <code>createMBean</code> method can be used remotely, but + sometimes requires attention to class loading issues.</p> - <pre> + <p>An MBean can perform actions when it is registered in or + unregistered from an MBean Server if it implements the {@link + javax.management.MBeanRegistration MBeanRegistration} + interface.</p> + + + <h3>Accessing MBeans in the MBean Server</h3> + + <p>Given an <code>ObjectName</code> <code>name</code> and an + <code>MBeanServer</code> <code>mbs</code>, you can access + attributes and operations as in this example:</p> + + <pre> int cacheSize = mbs.getAttribute(name, "CacheSize"); {@link javax.management.Attribute Attribute} newCacheSize = new Attribute("CacheSize", new Integer(2000)); @@ -236,9 +277,9 @@ mbs.invoke(name, "save", new Object[0], new Class[0]); </pre> - <p>Alternatively, if you have a Java interface that corresponds - to the management interface for the MBean, you can use an - <em>MBean proxy</em> like this:</p> + <p id="proxy">Alternatively, if you have a Java interface that + corresponds to the management interface for the MBean, you can use an + <em>MBean proxy</em> like this:</p> <pre> ConfigurationMBean conf = @@ -264,66 +305,116 @@ perform the query.</p> - <h2>Notifications</h2> - - <p>A <em>notification</em> is an instance of the {@link - javax.management.Notification Notification} class or a - subclass. In addition to its Java class, it has a - <em>type</em> string that can distinguish it from other - notifications of the same class.</p> - - <p>An MBean that will emit notifications must implement the - {@link javax.management.NotificationBroadcaster - NotificationBroadcaster} or {@link - javax.management.NotificationEmitter NotificationEmitter} - interface. Usually, it does this by subclassing {@link - javax.management.NotificationBroadcasterSupport - NotificationBroadcasterSupport} or by delegating to an instance - of that class.</p> + <h3>MBean lifecycle and resource injection</h3> - <p>Notifications can be received by a <em>listener</em>, which - is an object that implements the {@link - javax.management.NotificationListener NotificationListener} - interface. You can add a listener to an MBean with the method - {@link - javax.management.MBeanServer#addNotificationListener(ObjectName, - NotificationListener, NotificationFilter, Object)}. - You can optionally supply a <em>filter</em> to this method, to - select only notifications of interest. A filter is an object - that implements the {@link javax.management.NotificationFilter - NotificationFilter} interface.</p> + <p>An MBean can implement the {@link javax.management.MBeanRegistration + MBeanRegistration} interface in order to be told when it is registered + and unregistered in the MBean Server. Additionally, the {@link + javax.management.MBeanRegistration#preRegister preRegister} method + allows the MBean to get a reference to the <code>MBeanServer</code> + object and to get its <code>ObjectName</code> within the MBean + Server.</p> - <p>An MBean can be a listener for notifications emitted by other - MBeans in the same MBean Server. In this case, it implements - {@link javax.management.NotificationListener - NotificationListener} and the method {@link - javax.management.MBeanServer#addNotificationListener(ObjectName, - ObjectName, NotificationFilter, Object)} is used to listen.</p> + <p>If the only reason to implement <code>MBeanRegistration</code> is to + discover the <code>MBeanServer</code> and <code>ObjectName</code>, <a + href="MBeanRegistration.html#injection">resource injection</a> may be + more convenient.</p> - <h2>Remote Access to MBeans</h2> + <h2>Notifications</h2> + + <p>A <em>notification</em> is an instance of the {@link + javax.management.Notification Notification} class or a + subclass. In addition to its Java class, it has a + <em>type</em> string that can distinguish it from other + notifications of the same class.</p> + + <p>If an MBean is to emit notifications, it must do one of two things.</p> - <p>An MBean Server can be accessed remotely through a - <em>connector</em>. A connector allows a remote Java - application to access an MBean Server in essentially the same - way as a local one. The package - <a href="remote/package-summary.html"><code> - javax.management.remote</code></a> defines connectors.</p> + <ul> + <li>It can implement the interface {@link + javax.management.NotificationEmitter NotificationEmitter} (or + its parent {@link javax.management.NotificationBroadcaster + NotificationBroadcaster}), usually by subclassing + {@link javax.management.NotificationBroadcasterSupport + NotificationBroadcasterSupport} or delegating to an instance of + that class.</li> + <li>It can use <a href="MBeanRegistration.html#injection">resource + injection</a> to obtain a {@link javax.management.SendNotification + SendNotification} object that it can use to send + notifications.</li> + </ul> + + <p>The two classes below illustrate these two techniques:</p> + + <pre> + // Implementing NotificationEmitter (via NotificationBroadcasterSupport) + public class Configuration <b>extends NotificationBroadcasterSupport</b> + implements ConfigurationMBean { + ... + private void updated() { + Notification n = new Notification(...); + <b>{@link javax.management.NotificationBroadcasterSupport#sendNotification + sendNotification}(n)</b>; + } + } - <p>The JMX specification also defines the notion of an - <em>adaptor</em>. An adaptor translates between requests in a - protocol such as SNMP or HTML and accesses to an MBean Server. - So for example an SNMP GET operation might result in a - <code>getAttribute</code> on the MBean Server.</p> + // Getting a SendNotification through resource injection + public class Configuration implements ConfigurationMBean { + <b>@Resource</b> + private volatile SendNotification sender; + ... + private void updated() { + Notification n = new Notification(...); + <b>sender.sendNotification(n)</b>; + } + } + </pre> + + + <p>Notifications can be received by a <em>listener</em>, which + is an object that implements the {@link + javax.management.NotificationListener NotificationListener} + interface. You can add a listener to an MBean with the method + {@link + javax.management.MBeanServer#addNotificationListener(ObjectName, + NotificationListener, NotificationFilter, Object)}. + You can optionally supply a <em>filter</em> to this method, to + select only notifications of interest. A filter is an object + that implements the {@link javax.management.NotificationFilter + NotificationFilter} interface.</p> - <p id="spec"> - @see <a href="{@docRoot}/../technotes/guides/jmx/index.html"> - Java SE 6 Platform documentation on JMX technology</a> - in particular the - <a href="{@docRoot}/../technotes/guides/jmx/JMX_1_4_specification.pdf"> - JMX Specification, version 1.4(pdf).</a> + <p>An MBean can be a listener for notifications emitted by other + MBeans in the same MBean Server. In this case, it implements + {@link javax.management.NotificationListener + NotificationListener} and the method {@link + javax.management.MBeanServer#addNotificationListener(ObjectName, + ObjectName, NotificationFilter, Object)} is used to listen.</p> + + + <h2>Remote Access to MBeans</h2> - @since 1.5 + <p>An MBean Server can be accessed remotely through a + <em>connector</em>. A connector allows a remote Java + application to access an MBean Server in essentially the same + way as a local one. The package + <a href="remote/package-summary.html"><code> + javax.management.remote</code></a> defines connectors.</p> + + <p>The JMX specification also defines the notion of an + <em>adaptor</em>. An adaptor translates between requests in a + protocol such as SNMP or HTML and accesses to an MBean Server. + So for example an SNMP GET operation might result in a + <code>getAttribute</code> on the MBean Server.</p> + + <p id="spec"> + @see <a href="{@docRoot}/../technotes/guides/jmx/index.html"> + Java SE 6 Platform documentation on JMX technology</a> + in particular the + <a href="{@docRoot}/../technotes/guides/jmx/JMX_1_4_specification.pdf"> + JMX Specification, version 1.4(pdf).</a> + + @since 1.5 </body> </html>
--- a/jdk/src/share/classes/sun/nio/ch/SelectorImpl.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/SelectorImpl.java Wed Jul 05 16:39:18 2017 +0200 @@ -142,18 +142,20 @@ // Precondition: Synchronized on this, keys, and selectedKeys Set cks = cancelledKeys(); synchronized (cks) { - Iterator i = cks.iterator(); - while (i.hasNext()) { - SelectionKeyImpl ski = (SelectionKeyImpl)i.next(); - try { - implDereg(ski); - } catch (SocketException se) { - IOException ioe = new IOException( - "Error deregistering key"); - ioe.initCause(se); - throw ioe; - } finally { - i.remove(); + if (!cks.isEmpty()) { + Iterator i = cks.iterator(); + while (i.hasNext()) { + SelectionKeyImpl ski = (SelectionKeyImpl)i.next(); + try { + implDereg(ski); + } catch (SocketException se) { + IOException ioe = new IOException( + "Error deregistering key"); + ioe.initCause(se); + throw ioe; + } finally { + i.remove(); + } } } }
--- a/jdk/test/com/sun/jdi/MonitorFrameInfo.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/test/com/sun/jdi/MonitorFrameInfo.java Wed Jul 05 16:39:18 2017 +0200 @@ -25,7 +25,8 @@ * @test * @bug 6230699 * @summary Test ThreadReference.ownedMonitorsAndFrames() - * + * @bug 6701700 + * @summary MonitorInfo objects aren't invalidated when the owning thread is resumed * @author Swamy Venkataramanappa * * @run build TestScaffold VMConnection TargetListener TargetAdapter @@ -100,15 +101,15 @@ if (!mainThread.frame(0).location().method().name() .equals("foo3")) { - failure("frame failed"); + failure("FAILED: frame failed"); } if (mainThread.frames().size() != (initialSize + 3)) { - failure("frames size failed"); + failure("FAILED: frames size failed"); } if (mainThread.frames().size() != mainThread.frameCount()) { - failure("frames size not equal to frameCount"); + failure("FAILED: frames size not equal to frameCount"); } /* Test monitor frame info. @@ -119,13 +120,32 @@ if (monitors.size() != expectedCount) { failure("monitors count is not equal to expected count"); } + MonitorInfo mon = null; for (int j=0; j < monitors.size(); j++) { - MonitorInfo mon = (MonitorInfo)monitors.get(j); + mon = (MonitorInfo)monitors.get(j); System.out.println("Monitor obj " + mon.monitor() + "depth =" +mon.stackDepth()); if (mon.stackDepth() != expectedDepth[j]) { - failure("monitor stack depth is not equal to expected depth"); + failure("FAILED: monitor stack depth is not equal to expected depth"); } } + + // The last gotten monInfo is in mon. When we resume the thread, + // it should become invalid. We will step out of the top frame + // so that the frame depth in this mon object will no longer be correct. + // That is why the monInfo's have to become invalid when the thread is + // resumed. + stepOut(mainThread); + boolean ok = false; + try { + System.out.println("*** Saved Monitor obj " + mon.monitor() + "depth =" +mon.stackDepth()); + } catch(InvalidStackFrameException ee) { + // ok + ok = true; + System.out.println("Got expected InvalidStackFrameException after a resume"); + } + if (!ok) { + failure("FAILED: MonitorInfo object was not invalidated by a resume"); + } } else { System.out.println("can not get monitors frame info"); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/com/sun/jdi/ResumeOneThreadTest.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,233 @@ +/* + * 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 6700889 + * @summary Thread resume invalidates all stack frames, even from other threads + * + * @author jjh + * + * @run build TestScaffold VMConnection TargetListener TargetAdapter + * @run compile -g ResumeOneThreadTest.java + * @run main ResumeOneThreadTest + */ +import com.sun.jdi.*; +import com.sun.jdi.event.*; +import com.sun.jdi.request.*; + +import java.util.*; + +class ResumeOneThreadTarg extends Thread { + static String name1 = "Thread 1"; + static String name2 = "Thread 2"; + + public ResumeOneThreadTarg(String name) { + super(name); + } + + public static void main(String[] args) { + System.out.println(" Debuggee: Howdy!"); + ResumeOneThreadTarg t1 = new ResumeOneThreadTarg(name1); + ResumeOneThreadTarg t2 = new ResumeOneThreadTarg(name2); + + t1.start(); + t2.start(); + } + + // This just starts two threads. Each runs to a bkpt. + public void run() { + if (getName().equals(name1)) { + run1(); + } else { + run2(); + } + } + + public void bkpt1(String p1) { + System.out.println(" Debuggee: bkpt 1"); + } + + public void run1() { + bkpt1("Hello Alviso!"); + } + + + + public void bkpt2() { + System.out.println(" Debuggee: bkpt 2"); + } + + public void run2() { + bkpt2(); + } +} + +/********** test program **********/ + +public class ResumeOneThreadTest extends TestScaffold { + ReferenceType targetClass; + ThreadReference mainThread; + + BreakpointRequest request1; + BreakpointRequest request2; + + ThreadReference thread1 = null; + ThreadReference thread2 = null;; + boolean theVMisDead = false; + + ResumeOneThreadTest (String args[]) { + super(args); + } + + public static void main(String[] args) throws Exception { + new ResumeOneThreadTest(args).startTests(); + } + + + synchronized public void breakpointReached(BreakpointEvent event) { + println("-- Got bkpt at: " + event.location()); + ThreadReference eventThread = event.thread(); + + if (eventThread.name().equals(ResumeOneThreadTarg.name1)) { + thread1 = eventThread; + } + + if (eventThread.name().equals(ResumeOneThreadTarg.name2)) { + thread2 = eventThread; + } + } + + public void vmDied(VMDeathEvent event) { + theVMisDead = true; + } + + synchronized public void eventSetComplete(EventSet set) { + if (theVMisDead) { + return; + } + if (thread1 == null || thread2 == null) { + // Don't do a set.resume(), just let the other thread + // keep running until it hits its bkpt. + return; + } + + // Both threads are stopped at their bkpts. Get a StackFrame from + // Thread 1 then resume Thread 2 and verify that the saved StackFrame is + // still valid. + + // suspend everything. + println("-- All threads suspended"); + vm().suspend(); + + StackFrame t1sf0 = null; + try { + t1sf0 = thread1.frame(0); + } catch (IncompatibleThreadStateException ee) { + failure("FAILED: Exception: " + ee); + } + + println("-- t1sf0 args: " + t1sf0.getArgumentValues()); + + // Ok, we have a StackFrame for thread 1. Resume just thread 2 + // Note that thread 2 has been suspended twice - by the SUSPEND_ALL + // bkpt, and by the above vm().suspend(), so we have to resume + // it twice. + request2.disable(); + + thread2.resume(); + thread2.resume(); + println("-- Did Resume on thread 2"); + + // Can we get frames for thread1? + try { + StackFrame t1sf0_1 = thread1.frame(0); + if (!t1sf0.equals(t1sf0_1)) { + failure("FAILED: Got a different frame 0 for thread 1 after resuming thread 2"); + } + } catch (IncompatibleThreadStateException ee) { + failure("FAILED: Could not get frames for thread 1: Exception: " + ee); + } catch (Exception ee) { + failure("FAILED: Could not get frames for thread 1: Exception: " + ee); + } + + + try { + println("-- t1sf0 args: " + t1sf0.getArgumentValues()); + } catch (InvalidStackFrameException ee) { + // This is the failure. + failure("FAILED Got InvalidStackFrameException"); + vm().dispose(); + throw(ee); + } + + // Let the debuggee finish + request1.disable(); + thread1.resume(); + vm().resume(); + println("--------------"); + } + + /********** test core **********/ + + protected void runTests() throws Exception { + + /* + * Get to the top of main() + * to determine targetClass and mainThread + */ + BreakpointEvent bpe = startToMain("ResumeOneThreadTarg"); + targetClass = bpe.location().declaringType(); + mainThread = bpe.thread(); + EventRequestManager erm = vm().eventRequestManager(); + final Thread mainThread = Thread.currentThread(); + + /* + * Set event requests + */ + + Location loc1 = findMethod(targetClass, "bkpt1", "(Ljava/lang/String;)V").location(); + request1 = erm.createBreakpointRequest(loc1); + request1.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + request1.enable(); + + Location loc2 = findMethod(targetClass, "bkpt2", "()V").location(); + request2 = erm.createBreakpointRequest(loc2); + request2.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + request2.enable(); + + /* + * resume the target, listening for events + */ + listenUntilVMDisconnect(); + /* + * deal with results of test + * if anything has called failure("foo") testFailed will be true + */ + if (!testFailed) { + println("ResumeOneThreadTest: passed"); + } else { + throw new Exception("ResumeOneThreadTest: failed"); + } + } +}
--- a/jdk/test/com/sun/jdi/SourceNameFilterTest.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/test/com/sun/jdi/SourceNameFilterTest.java Wed Jul 05 16:39:18 2017 +0200 @@ -23,7 +23,7 @@ /** * @test - * @bug 4836939 + * @bug 4836939 6646613 * @summary JDI add addSourceNameFilter to ClassPrepareRequest * * @author jjh @@ -31,7 +31,11 @@ * @run build TestScaffold VMConnection TargetListener TargetAdapter * @run compile -g SourceNameFilterTest.java * @run main SourceNameFilterTest + * @run compile -g:none SourceNameFilterTest.java + * @run main SourceNameFilterTest */ +// The compile -g:none suppresses the lineNumber table to trigger bug 6646613. + import com.sun.jdi.*; import com.sun.jdi.event.*; import com.sun.jdi.request.*; @@ -84,7 +88,6 @@ boolean gotEvent1 = false; boolean gotEvent2 = false; boolean gotEvent3 = false; - ClassPrepareRequest cpReq; boolean shouldResume = false; SourceNameFilterTest (String args[]) { @@ -151,6 +154,18 @@ */ BreakpointEvent bpe = startToMain("SourceNameFilterTarg"); targetClass = bpe.location().declaringType(); + boolean noSourceName = false; + try { + targetClass.sourceName(); + } catch (AbsentInformationException ee) { + noSourceName = true; + } + if (noSourceName) { + println("-- Running with no source names"); + } else { + println("-- Running with source names"); + } + mainThread = bpe.thread(); EventRequestManager erm = vm().eventRequestManager(); addListener(this); @@ -175,7 +190,9 @@ /* * This should cause us to get a class prepare event for - * LoadedLater3 + * LoadedLater3 except in the case where -g:none + * was used to compile so that there is no LineNumberTable + * and therefore, no source name for the class. */ cpReq = erm.createClassPrepareRequest(); cpReq.addSourceNameFilter("SourceNameFilterTest.java"); @@ -186,17 +203,21 @@ if (!gotEvent1) { failure("failure: Did not get a class prepare request " + - "for Loadedlater1"); + "for LoadedLater1"); } if (gotEvent2) { failure("failure: Did get a class prepare request " + - "for Loadedlater2"); + "for LoadedLater2"); } - if (!gotEvent3) { + if (gotEvent3 && noSourceName) { + failure("failure: Did get a class prepare request " + + "for LoadedLater3"); + } + else if (!gotEvent3 && !noSourceName) { failure("failure: Did not get a class prepare request " + - "for Loadedlater3"); + "for LoadedLater3"); } /*
--- a/jdk/test/com/sun/jdi/VMConnection.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/test/com/sun/jdi/VMConnection.java Wed Jul 05 16:39:18 2017 +0200 @@ -115,7 +115,7 @@ return cmdLine; } // Insert the options at position 1. Blanks in args are not allowed! - String[] v1 = opts.split(" "); + String[] v1 = opts.split(" +"); String[] retVal = new String[cmdLine.length + v1.length]; retVal[0] = cmdLine[0]; System.arraycopy(v1, 0, retVal, 1, v1.length);
--- a/jdk/test/java/nio/channels/FileChannel/ExpandingMap.java Thu Jul 17 11:28:32 2008 -0700 +++ b/jdk/test/java/nio/channels/FileChannel/ExpandingMap.java Wed Jul 05 16:39:18 2017 +0200 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4938372 + * @bug 4938372 6541641 * @summary Flushing dirty pages prior to unmap can cause Cleaner thread to * abort VM if memory system has pages locked */ @@ -39,7 +39,7 @@ public class ExpandingMap { - public static void main(String[] args) throws IOException { + public static void main(String[] args) throws Exception { int initialSize = 20480*1024; int maximumMapSize = 16*1024*1024; @@ -103,6 +103,13 @@ } } + fc.close(); + // cleanup the ref to mapped buffers so they can be GCed + for (int i = 0; i < buffers.length; i++) + buffers[i] = null; + System.gc(); + // Take a nap to wait for the Cleaner to cleanup those unrefed maps + Thread.sleep(1000); System.out.println("TEST PASSED"); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/Selector/Wakeup.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,197 @@ +/* + * Copyright 2001-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 + * @bug 6405995 + * @summary Unit test for selector wakeup and interruption + * @library .. + */ + +import java.io.*; +import java.net.*; +import java.nio.*; +import java.nio.channels.*; +import java.util.Random; + +public class Wakeup { + + static void sleep(int millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException x) { + x.printStackTrace(); + } + } + + static class Sleeper extends TestThread { + volatile boolean started = false; + volatile int entries = 0; + volatile int wakeups = 0; + volatile boolean wantInterrupt = false; + volatile boolean gotInterrupt = false; + volatile Exception exception = null; + volatile boolean closed = false; + Object gate = new Object(); + + Selector sel; + + Sleeper(Selector sel) { + super("Sleeper", System.err); + this.sel = sel; + } + + public void go() throws Exception { + started = true; + for (;;) { + synchronized (gate) { } + entries++; + try { + sel.select(); + } catch (ClosedSelectorException x) { + closed = true; + } + boolean intr = Thread.currentThread().isInterrupted(); + wakeups++; + System.err.println("Wakeup " + wakeups + + (closed ? " (closed)" : "") + + (intr ? " (intr)" : "")); + if (wakeups > 1000) + throw new Exception("Too many wakeups"); + if (closed) + return; + if (wantInterrupt) { + while (!Thread.interrupted()) + Thread.yield(); + gotInterrupt = true; + wantInterrupt = false; + } + } + } + + } + + private static int checkedWakeups = 0; + + private static void check(Sleeper sleeper, boolean intr) + throws Exception + { + checkedWakeups++; + if (sleeper.wakeups > checkedWakeups) { + sleeper.finish(100); + throw new Exception("Sleeper has run ahead"); + } + int n = 0; + while (sleeper.wakeups < checkedWakeups) { + sleep(50); + if ((n += 50) > 1000) { + sleeper.finish(100); + throw new Exception("Sleeper appears to be dead (" + + checkedWakeups + ")"); + } + } + if (sleeper.wakeups > checkedWakeups) { + sleeper.finish(100); + throw new Exception("Too many wakeups: Expected " + + checkedWakeups + + ", got " + sleeper.wakeups); + } + if (intr) { + n = 0; + // Interrupts can sometimes be delayed, so wait + while (!sleeper.gotInterrupt) { + sleep(50); + if ((n += 50) > 1000) { + sleeper.finish(100); + throw new Exception("Interrupt never delivered"); + } + } + sleeper.gotInterrupt = false; + } + System.err.println("Check " + checkedWakeups + + (intr ? " (intr " + n + ")" : "")); + } + + public static void main(String[] args) throws Exception { + + Selector sel = Selector.open(); + + // Wakeup before select + sel.wakeup(); + + Sleeper sleeper = new Sleeper(sel); + + sleeper.start(); + while (!sleeper.started) + sleep(50); + + check(sleeper, false); // 1 + + for (int i = 2; i < 5; i++) { + // Wakeup during select + sel.wakeup(); + check(sleeper, false); // 2 .. 4 + } + + // Double wakeup + synchronized (sleeper.gate) { + sel.wakeup(); + check(sleeper, false); // 5 + sel.wakeup(); + sel.wakeup(); + } + check(sleeper, false); // 6 + + // Interrupt + synchronized (sleeper.gate) { + sleeper.wantInterrupt = true; + sleeper.interrupt(); + check(sleeper, true); // 7 + } + + // Interrupt before select + while (sleeper.entries < 8) + Thread.yield(); + synchronized (sleeper.gate) { + sel.wakeup(); + check(sleeper, false); // 8 + sleeper.wantInterrupt = true; + sleeper.interrupt(); + sleep(50); + } + check(sleeper, true); // 9 + + // Close during select + while (sleeper.entries < 10) + Thread.yield(); + synchronized (sleeper.gate) { + sel.close(); + check(sleeper, false); // 10 + } + + if (sleeper.finish(200) == 0) + throw new Exception("Test failed"); + if (!sleeper.closed) + throw new Exception("Selector not closed"); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/Introspector/AnnotatedMBeanTest.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,337 @@ +/* + * 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. + * + * 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 %M% %I% + * @bug 6323980 + * @summary Test MBeans defined with @MBean + * @author Eamonn McManus + * @run main/othervm -ea AnnotatedMBeanTest + */ + +import java.io.File; +import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import javax.management.Attribute; +import javax.management.Descriptor; +import javax.management.DescriptorKey; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.MXBean; +import javax.management.MalformedObjectNameException; +import javax.management.ManagedAttribute; +import javax.management.ManagedOperation; +import javax.management.MBean; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeType; + +public class AnnotatedMBeanTest { + private static MBeanServer mbs; + private static final ObjectName objectName; + static { + try { + objectName = new ObjectName("test:type=Test"); + } catch (MalformedObjectNameException e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) throws Exception { + if (!AnnotatedMBeanTest.class.desiredAssertionStatus()) + throw new Exception("Test must be run with -ea"); + + File policyFile = File.createTempFile("jmxperms", ".policy"); + policyFile.deleteOnExit(); + PrintWriter pw = new PrintWriter(policyFile); + pw.println("grant {"); + pw.println(" permission javax.management.MBeanPermission \"*\", \"*\";"); + pw.println(" permission javax.management.MBeanServerPermission \"*\";"); + pw.println(" permission javax.management.MBeanTrustPermission \"*\";"); + pw.println("};"); + pw.close(); + + System.setProperty("java.security.policy", policyFile.getAbsolutePath()); + System.setSecurityManager(new SecurityManager()); + + String failure = null; + + for (Method m : AnnotatedMBeanTest.class.getDeclaredMethods()) { + if (Modifier.isStatic(m.getModifiers()) && + m.getName().startsWith("test") && + m.getParameterTypes().length == 0) { + mbs = MBeanServerFactory.newMBeanServer(); + try { + m.invoke(null); + System.out.println(m.getName() + " OK"); + } catch (InvocationTargetException ite) { + System.out.println(m.getName() + " got exception:"); + Throwable t = ite.getCause(); + t.printStackTrace(System.out); + failure = m.getName() + ": " + t.toString(); + } + } + } + if (failure == null) + System.out.println("TEST PASSED"); + else + throw new Exception("TEST FAILED: " + failure); + } + + public static class Stats { + private final int used; + private final int size; + private final boolean interesting; + + public Stats(int used, int size, boolean interesting) { + this.used = used; + this.size = size; + this.interesting = interesting; + } + + public int getUsed() { + return used; + } + + public int getSize() { + return size; + } + + public boolean isInteresting() { + return interesting; + } + } + + @Retention(RetentionPolicy.RUNTIME) + public static @interface Units { + @DescriptorKey("units") + String value(); + } + + @MBean + public static class Cache { + private int used = 23; + private int size = 99; + + @ManagedAttribute + @Units("bytes") + public int getUsed() { + return used; + } + + @ManagedAttribute + public int getSize() { + return size; + } + + @ManagedAttribute + public void setSize(int x) { + this.size = x; + } + + @ManagedAttribute + public boolean isInteresting() { + return false; + } + + @ManagedAttribute + public Stats getStats() { + return new Stats(used, size, false); + } + + @ManagedOperation + public int dropOldest(int n) { + return 55; + } + + private void irrelevantMethod() {} + private int getIrrelevant() {return 0;} + public int getIrrelevant2() {return 0;} + + public int otherIrrelevantMethod() {return 5;} + } + + public static class SubCache extends Cache { + // SubCache does not have the @MBean annotation + // but its parent does. It doesn't add any @ManagedAttribute or + // @ManagedOperation methods, so its management interface + // should be the same. + private void irrelevantMethod2() {} + public int otherIrrelevantMethod3() {return 0;} + + public int getX() {return 0;} + public void setX(int x) {} + } + + @MXBean + public static class CacheMX { + private int used = 23; + private int size = 99; + + @ManagedAttribute + @Units("bytes") + public int getUsed() { + return used; + } + + @ManagedAttribute + public int getSize() { + return size; + } + + @ManagedAttribute + public void setSize(int x) { + this.size = x; + } + + @ManagedAttribute + public boolean isInteresting() { + return false; + } + + @ManagedAttribute + public Stats getStats() { + return new Stats(used, size, false); + } + + @ManagedOperation + public int dropOldest(int n) { + return 55; + } + + private void irrelevantMethod() {} + private int getIrrelevant() {return 0;} + public int getIrrelevant2() {return 0;} + + public int otherIrrelevantMethod() {return 5;} + } + + public static class SubCacheMX extends CacheMX { + private void irrelevantMethod2() {} + public int otherIrrelevantMethod3() {return 0;} + + public int getX() {return 0;} + public void setX(int x) {} + } + + private static void testSimpleManagedResource() throws Exception { + testResource(new Cache(), false); + } + + private static void testSubclassManagedResource() throws Exception { + testResource(new SubCache(), false); + } + + private static void testMXBeanResource() throws Exception { + testResource(new CacheMX(), true); + } + + private static void testSubclassMXBeanResource() throws Exception { + testResource(new SubCacheMX(), true); + } + + private static void testResource(Object resource, boolean mx) throws Exception { + mbs.registerMBean(resource, objectName); + + MBeanInfo mbi = mbs.getMBeanInfo(objectName); + assert mbi.getDescriptor().getFieldValue("mxbean").equals(Boolean.toString(mx)); + + MBeanAttributeInfo[] mbais = mbi.getAttributes(); + + assert mbais.length == 4: mbais.length; + + for (MBeanAttributeInfo mbai : mbais) { + String name = mbai.getName(); + if (name.equals("Used")) { + assert mbai.isReadable(); + assert !mbai.isWritable(); + assert !mbai.isIs(); + assert mbai.getType().equals("int"); + assert "bytes".equals(mbai.getDescriptor().getFieldValue("units")); + } else if (name.equals("Size")) { + assert mbai.isReadable(); + assert mbai.isWritable(); + assert !mbai.isIs(); + assert mbai.getType().equals("int"); + } else if (name.equals("Interesting")) { + assert mbai.isReadable(); + assert !mbai.isWritable(); + assert mbai.isIs(); + assert mbai.getType().equals("boolean"); + } else if (name.equals("Stats")) { + assert mbai.isReadable(); + assert !mbai.isWritable(); + assert !mbai.isIs(); + Descriptor d = mbai.getDescriptor(); + if (mx) { + assert mbai.getType().equals(CompositeData.class.getName()); + assert d.getFieldValue("originalType").equals(Stats.class.getName()); + CompositeType ct = (CompositeType) d.getFieldValue("openType"); + Set<String> names = new HashSet<String>( + Arrays.asList("used", "size", "interesting")); + assert ct.keySet().equals(names) : ct.keySet(); + } else { + assert mbai.getType().equals(Stats.class.getName()); + } + } else + assert false : name; + } + + MBeanOperationInfo[] mbois = mbi.getOperations(); + + assert mbois.length == 1: mbois.length; + + MBeanOperationInfo mboi = mbois[0]; + assert mboi.getName().equals("dropOldest"); + assert mboi.getReturnType().equals("int"); + MBeanParameterInfo[] mbpis = mboi.getSignature(); + assert mbpis.length == 1: mbpis.length; + assert mbpis[0].getType().equals("int"); + + assert mbs.getAttribute(objectName, "Used").equals(23); + + assert mbs.getAttribute(objectName, "Size").equals(99); + mbs.setAttribute(objectName, new Attribute("Size", 55)); + assert mbs.getAttribute(objectName, "Size").equals(55); + + assert mbs.getAttribute(objectName, "Interesting").equals(false); + + Object stats = mbs.getAttribute(objectName, "Stats"); + assert (mx ? CompositeData.class : Stats.class).isInstance(stats) : stats.getClass(); + + int ret = (Integer) mbs.invoke( + objectName, "dropOldest", new Object[] {66}, new String[] {"int"}); + assert ret == 55; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/Introspector/AnnotatedNotificationInfoTest.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,271 @@ +/* + * 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. + * + * 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 %M% %I% + * @bug 6323980 + * @summary Test @NotificationInfo annotation + * @author Eamonn McManus + * @run main/othervm -ea AnnotatedNotificationInfoTest + */ + +import java.io.Serializable; +import java.lang.management.ManagementFactory; +import java.lang.reflect.Field; +import javax.annotation.Resource; +import javax.management.AttributeChangeNotification; +import javax.management.Description; +import javax.management.Descriptor; +import javax.management.ImmutableDescriptor; +import javax.management.MBean; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanServer; +import javax.management.MXBean; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationInfo; +import javax.management.NotificationInfos; +import javax.management.ObjectName; +import javax.management.SendNotification; + +public class AnnotatedNotificationInfoTest { + // Data for the first test. This tests that MBeanNotificationInfo + // is correctly derived from @NotificationInfo. + // Every static field called mbean* is expected to be an MBean + // with a single MBeanNotificationInfo that has the same value + // in each case. + + @NotificationInfo( + types = {"foo", "bar"}, + notificationClass = AttributeChangeNotification.class, + description = @Description( + value = "description", + bundleBaseName = "bundle", + key = "key"), + descriptorFields = {"foo=bar"}) + public static interface Intf1MBean {} + + public static class Intf1 + extends NotificationBroadcasterSupport implements Intf1MBean {} + + private static Object mbeanIntf1 = new Intf1(); + + @NotificationInfos( + @NotificationInfo( + types = {"foo", "bar"}, + notificationClass = AttributeChangeNotification.class, + description = @Description( + value = "description", + bundleBaseName = "bundle", + key = "key"), + descriptorFields = {"foo=bar"})) + public static interface Intf2MBean {} + + public static class Intf2 + extends NotificationBroadcasterSupport implements Intf2MBean {} + + private static Object mbeanIntf2 = new Intf2(); + + @NotificationInfos({}) + @NotificationInfo( + types = {"foo", "bar"}, + notificationClass = AttributeChangeNotification.class, + description = @Description( + value = "description", + bundleBaseName = "bundle", + key = "key"), + descriptorFields = {"foo=bar"}) + public static interface Intf3MBean {} + + public static class Intf3 + extends NotificationBroadcasterSupport implements Intf3MBean {} + + private static Object mbeanIntf3 = new Intf3(); + + @NotificationInfo( + types = {"foo", "bar"}, + notificationClass = AttributeChangeNotification.class, + description = @Description( + value = "description", + bundleBaseName = "bundle", + key = "key"), + descriptorFields = {"foo=bar"}) + public static interface ParentIntf {} + + public static interface Intf4MBean extends Serializable, ParentIntf, Cloneable {} + + public static class Intf4 + extends NotificationBroadcasterSupport implements Intf4MBean {} + + private static Object mbeanIntf4 = new Intf4(); + + @NotificationInfo( + types = {"foo", "bar"}, + notificationClass = AttributeChangeNotification.class, + description = @Description( + value = "description", + bundleBaseName = "bundle", + key = "key"), + descriptorFields = {"foo=bar"}) + public static interface Intf5MXBean {} + + public static class Intf5Impl + extends NotificationBroadcasterSupport implements Intf5MXBean {} + + private static Object mbeanIntf5 = new Intf5Impl(); + + public static interface Impl1MBean {} + + @NotificationInfo( + types = {"foo", "bar"}, + notificationClass = AttributeChangeNotification.class, + description = @Description( + value = "description", + bundleBaseName = "bundle", + key = "key"), + descriptorFields = {"foo=bar"}) + public static class Impl1 + extends NotificationBroadcasterSupport implements Impl1MBean {} + + private static Object mbeanImpl1 = new Impl1(); + + @NotificationInfo( + types = {"foo", "bar"}, + notificationClass = AttributeChangeNotification.class, + description = @Description( + value = "description", + bundleBaseName = "bundle", + key = "key"), + descriptorFields = {"foo=bar"}) + public static class ParentImpl extends NotificationBroadcasterSupport {} + + public static interface Impl2MBean {} + + public static class Impl2 extends ParentImpl implements Impl2MBean {} + + private static Object mbeanImpl2 = new Impl2(); + + public static interface Impl3MXBean {} + + @NotificationInfo( + types = {"foo", "bar"}, + notificationClass = AttributeChangeNotification.class, + description = @Description( + value = "description", + bundleBaseName = "bundle", + key = "key"), + descriptorFields = {"foo=bar"}) + public static class Impl3 + extends NotificationBroadcasterSupport implements Impl3MXBean {} + + private static Object mbeanImpl3 = new Impl3(); + + public static class Impl4 extends ParentImpl implements Impl3MXBean {} + + private static Object mbeanImpl4 = new Impl4(); + + @MBean + @NotificationInfo( + types = {"foo", "bar"}, + notificationClass = AttributeChangeNotification.class, + description = @Description( + value = "description", + bundleBaseName = "bundle", + key = "key"), + descriptorFields = {"foo=bar"}) + public static class MBean1 extends NotificationBroadcasterSupport {} + + private static Object mbeanMBean1 = new MBean1(); + + @MBean + public static class MBean2 extends ParentImpl {} + + private static Object mbeanMBean2 = new MBean2(); + + // Following disabled until we support it +// @MBean +// @NotificationInfo( +// types = {"foo", "bar"}, +// notificationClass = AttributeChangeNotification.class, +// description = @Description( +// value = "description", +// bundleBaseName = "bundle", +// key = "key"), +// descriptorFields = {"foo=bar"}) +// public static class MBean3 { +// @Resource +// private volatile SendNotification send; +// } +// +// private static Object mbeanMBean3 = new MBean3(); + + @MXBean + @NotificationInfo( + types = {"foo", "bar"}, + notificationClass = AttributeChangeNotification.class, + description = @Description( + value = "description", + bundleBaseName = "bundle", + key = "key"), + descriptorFields = {"foo=bar"}) + public static class MXBean1 extends NotificationBroadcasterSupport {} + + private static Object mbeanMXBean1 = new MXBean1(); + + @MXBean + public static class MXBean2 extends ParentImpl {} + + private static Object mbeanMXBean2 = new MXBean2(); + + public static void main(String[] args) throws Exception { + if (!AnnotatedNotificationInfoTest.class.desiredAssertionStatus()) + throw new Exception("Test must be run with -ea"); + + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + ObjectName on = new ObjectName("a:b=c"); + + Descriptor expectedDescriptor = new ImmutableDescriptor( + "foo=bar", "descriptionResourceBundleBaseName=bundle", + "descriptionResourceKey=key"); + MBeanNotificationInfo expected = new MBeanNotificationInfo( + new String[] {"foo", "bar"}, + AttributeChangeNotification.class.getName(), + "description", + expectedDescriptor); + + System.out.println("Testing MBeans..."); + for (Field mbeanField : + AnnotatedNotificationInfoTest.class.getDeclaredFields()) { + if (!mbeanField.getName().startsWith("mbean")) + continue; + System.out.println("..." + mbeanField.getName()); + Object mbean = mbeanField.get(null); + mbs.registerMBean(mbean, on); + MBeanInfo mbi = mbs.getMBeanInfo(on); + MBeanNotificationInfo[] mbnis = mbi.getNotifications(); + assert mbnis.length == 1 : mbnis.length; + assert mbnis[0].equals(expected) : mbnis[0]; + mbs.unregisterMBean(on); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/Introspector/MBeanDescriptionTest.java Wed Jul 05 16:39:18 2017 +0200 @@ -0,0 +1,830 @@ +/* + * 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. + * + * 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 %M% %I% + * @bug 6323980 + * @summary Test @Description + * @author Eamonn McManus + */ + +import java.lang.management.ManagementFactory; +import javax.management.Description; +import javax.management.IntrospectionException; +import javax.management.MBean; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanFeatureInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.MBeanServer; +import javax.management.MXBean; +import javax.management.ManagedAttribute; +import javax.management.ManagedOperation; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import javax.management.StandardMBean; + +public class MBeanDescriptionTest { + private static String failure; + private static final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + private static final ObjectName name; + static { + try { + name = new ObjectName("a:b=c"); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static interface Interface { + @Description("A description") + public String getA(); + + @Description("B description") + public int getB(); + public void setB(int x); + + public boolean isC(); + @Description("C description") + public void setC(boolean x); + + @Description("D description") + public void setD(float x); + + @Description("H description") + public int getH(); + @Description("H description") + public void setH(int x); + + public String getE(); + + public int getF(); + public void setF(int x); + + public void setG(boolean x); + + @Description("opA description") + public int opA( + @Description("p1 description") + int p1, + @Description("p2 description") + int p2); + + public void opB(float x); + } + + @Description("MBean description") + public static interface TestMBean extends Interface {} + + public static class Test implements TestMBean { + @Description("0-arg constructor description") + public Test() {} + + public Test(String why) {} + + @Description("2-arg constructor description") + public Test( + @Description("p1 description") + int x, + @Description("p2 description") + String y) { + } + + public String getA() { + return null; + } + + public int getB() { + return 0; + } + + public void setB(int x) { + } + + public boolean isC() { + return false; + } + + public void setC(boolean x) { + } + + public void setD(float x) { + } + + public String getE() { + return null; + } + + public int getF() { + return 0; + } + + public void setF(int x) { + } + + public void setG(boolean x) { + } + + public int getH() { + return 0; + } + + public void setH(int x) { + } + + public int opA(int p1, int p2) { + return 0; + } + + public void opB(float x) { + } + } + + public static class TestSub extends Test { + @Description("0-arg constructor description") + public TestSub() {} + + public TestSub(String why) {} + + @Description("2-arg constructor description") + public TestSub( + @Description("p1 description") + int x, + @Description("p2 description") + String y) { + } + } + + public static class StandardSub extends StandardMBean implements TestMBean { + @Description("0-arg constructor description") + public StandardSub() { + super(TestMBean.class, false); + } + + public StandardSub(String why) { + super(TestMBean.class, false); + } + + @Description("2-arg constructor description") + public StandardSub( + @Description("p1 description") + int x, + @Description("p2 description") + String y) { + super(TestMBean.class, false); + } + + public String getA() { + return null; + } + + public int getB() { + return 0; + } + + public void setB(int x) { + } + + public boolean isC() { + return false; + } + + public void setC(boolean x) { + } + + public void setD(float x) { + } + + public String getE() { + return null; + } + + public int getF() { + return 0; + } + + public void setF(int x) { + } + + public void setG(boolean x) { + } + + public int opA(int p1, int p2) { + return 0; + } + + public void opB(float x) { + } + + public int getH() { + return 0; + } + + public void setH(int x) { + } + } + + @Description("MBean description") + public static interface TestMXBean extends Interface {} + + public static class TestMXBeanImpl implements TestMXBean { + @Description("0-arg constructor description") + public TestMXBeanImpl() {} + + public TestMXBeanImpl(String why) {} + + @Description("2-arg constructor description") + public TestMXBeanImpl( + @Description("p1 description") + int x, + @Description("p2 description") + String y) { + } + + public String getA() { + return null; + } + + public int getB() { + return 0; + } + + public void setB(int x) { + } + + public boolean isC() { + return false; + } + + public void setC(boolean x) { + } + + public void setD(float x) { + } + + public String getE() { + return null; + } + + public int getF() { + return 0; + } + + public void setF(int x) { + } + + public void setG(boolean x) { + } + + public int opA(int p1, int p2) { + return 0; + } + + public void opB(float x) { + } + + public int getH() { + return 0; + } + + public void setH(int x) { + } + } + + public static class StandardMXSub extends StandardMBean implements TestMXBean { + @Description("0-arg constructor description") + public StandardMXSub() { + super(TestMXBean.class, true); + } + + public StandardMXSub(String why) { + super(TestMXBean.class, true); + } + + @Description("2-arg constructor description") + public StandardMXSub( + @Description("p1 description") + int x, + @Description("p2 description") + String y) { + super(TestMXBean.class, true); + } + + public String getA() { + return null; + } + + public int getB() { + return 0; + } + + public void setB(int x) { + } + + public boolean isC() { + return false; + } + + public void setC(boolean x) { + } + + public void setD(float x) { + } + + public String getE() { + return null; + } + + public int getF() { + return 0; + } + + public void setF(int x) { + } + + public void setG(boolean x) { + } + + public int opA(int p1, int p2) { + return 0; + } + + public void opB(float x) { + } + + public int getH() { + return 0; + } + + public void setH(int x) { + } + } + + @MBean + @Description("MBean description") + public static class AnnotatedMBean { + @Description("0-arg constructor description") + public AnnotatedMBean() {} + + public AnnotatedMBean(String why) {} + + @Description("2-arg constructor description") + public AnnotatedMBean( + @Description("p1 description") + int x, + @Description("p2 description") + String y) {} + + @ManagedAttribute + @Description("A description") + public String getA() { + return null; + } + + @ManagedAttribute + @Description("B description") + public int getB() { + return 0; + } + + @ManagedAttribute + public void setB(int x) { + } + + @ManagedAttribute + public boolean isC() { + return false; + } + + @ManagedAttribute + @Description("C description") + public void setC(boolean x) { + } + + @ManagedAttribute + @Description("D description") + public void setD(float x) { + } + + @ManagedAttribute + public String getE() { + return null; + } + + @ManagedAttribute + public int getF() { + return 0; + } + + @ManagedAttribute + public void setF(int x) { + } + + @ManagedAttribute + public void setG(boolean x) { + } + + @ManagedAttribute + @Description("H description") + public int getH() { + return 0; + } + + @ManagedAttribute + @Description("H description") + public void setH(int x) { + } + + @ManagedOperation + @Description("opA description") + public int opA( + @Description("p1 description") int p1, + @Description("p2 description") int p2) { + return 0; + } + + @ManagedOperation + public void opB(float x) { + } + } + + @MXBean + @Description("MBean description") + public static class AnnotatedMXBean { + @Description("0-arg constructor description") + public AnnotatedMXBean() {} + + public AnnotatedMXBean(String why) {} + + @Description("2-arg constructor description") + public AnnotatedMXBean( + @Description("p1 description") + int x, + @Description("p2 description") + String y) {} + + @ManagedAttribute + @Description("A description") + public String getA() { + return null; + } + + @ManagedAttribute + @Description("B description") + public int getB() { + return 0; + } + + @ManagedAttribute + public void setB(int x) { + } + + @ManagedAttribute + public boolean isC() { + return false; + } + + @ManagedAttribute + @Description("C description") + public void setC(boolean x) { + } + + @ManagedAttribute + @Description("D description") + public void setD(float x) { + } + + @ManagedAttribute + public String getE() { + return null; + } + + @ManagedAttribute + public int getF() { + return 0; + } + + @ManagedAttribute + public void setF(int x) { + } + + @ManagedAttribute + public void setG(boolean x) { + } + + @ManagedAttribute + @Description("H description") + public int getH() { + return 0; + } + + @ManagedAttribute + @Description("H description") + public void setH(int x) { + } + + @ManagedOperation + @Description("opA description") + public int opA( + @Description("p1 description") int p1, + @Description("p2 description") int p2) { + return 0; + } + + @ManagedOperation + public void opB(float x) { + } + } + + // Negative tests follow. + + // Inconsistent descriptions + public static interface BadInterface { + @Description("foo") + public String getFoo(); + @Description("bar") + public void setFoo(String x); + } + + public static interface BadMBean extends BadInterface {} + + public static class Bad implements BadMBean { + public String getFoo() { + return null; + } + + public void setFoo(String x) { + } + } + + public static interface BadMXBean extends BadInterface {} + + public static class BadMXBeanImpl implements BadMXBean { + public String getFoo() { + return null; + } + + public void setFoo(String x) { + } + } + + private static interface Defaults { + public String defaultAttributeDescription(String name); + public String defaultOperationDescription(String name); + public String defaultParameterDescription(int index); + } + + private static class StandardDefaults implements Defaults { + public String defaultAttributeDescription(String name) { + return "Attribute exposed for management"; + } + + public String defaultOperationDescription(String name) { + return "Operation exposed for management"; + } + + public String defaultParameterDescription(int index) { + return ""; + } + } + private static final Defaults standardDefaults = new StandardDefaults(); + + private static class MXBeanDefaults implements Defaults { + public String defaultAttributeDescription(String name) { + return name; + } + + public String defaultOperationDescription(String name) { + return name; + } + + public String defaultParameterDescription(int index) { + return "p" + index; + } + } + private static final Defaults mxbeanDefaults = new MXBeanDefaults(); + + private static class TestCase { + final String name; + final Object mbean; + final Defaults defaults; + TestCase(String name, Object mbean, Defaults defaults) { + this.name = name; + this.mbean = mbean; + this.defaults = defaults; + } + } + + private static class ExceptionTest { + final String name; + final Object mbean;