--- 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;
+ ExceptionTest(String name, Object mbean) {
+ this.name = name;
+ this.mbean = mbean;
+ }
+ }
+
+ private static final TestCase[] tests = {
+ new TestCase("Standard MBean", new Test(), standardDefaults),
+ new TestCase("Standard MBean subclass", new TestSub(), standardDefaults),
+ new TestCase("StandardMBean delegating",
+ new StandardMBean(new Test(), TestMBean.class, false),
+ standardDefaults),
+ new TestCase("StandardMBean delegating to subclass",
+ new StandardMBean(new TestSub(), TestMBean.class, false),
+ standardDefaults),
+ new TestCase("StandardMBean subclass", new StandardSub(), standardDefaults),
+
+ new TestCase("MXBean", new TestMXBeanImpl(), mxbeanDefaults),
+ new TestCase("StandardMBean MXBean delegating",
+ new StandardMBean(new TestMXBeanImpl(), TestMXBean.class, true),
+ mxbeanDefaults),
+ new TestCase("StandardMBean MXBean subclass",
+ new StandardMXSub(), mxbeanDefaults),
+
+ new TestCase("@MBean", new AnnotatedMBean(), standardDefaults),
+ new TestCase("@MXBean", new AnnotatedMXBean(), mxbeanDefaults),
+ new TestCase("StandardMBean @MBean delegating",
+ new StandardMBean(new AnnotatedMBean(), null, false),
+ standardDefaults),
+ new TestCase("StandardMBean @MXBean delegating",
+ new StandardMBean(new AnnotatedMXBean(), null, true),
+ mxbeanDefaults),
+ };
+
+ private static final ExceptionTest[] exceptionTests = {
+ new ExceptionTest("Standard MBean with inconsistent get/set", new Bad()),
+ new ExceptionTest("MXBean with inconsistent get/set", new BadMXBeanImpl()),
+ };
+
+ public static void main(String[] args) throws Exception {
+ System.out.println("=== Testing correct MBeans ===");
+ for (TestCase test : tests) {
+ System.out.println("Testing " + test.name + "...");
+ mbs.registerMBean(test.mbean, name);
+ boolean expectConstructors =
+ (test.mbean.getClass() != StandardMBean.class);
+ check(mbs.getMBeanInfo(name), test.defaults, expectConstructors);
+ mbs.unregisterMBean(name);
+ }
+ System.out.println();
+
+ System.out.println("=== Testing incorrect MBeans ===");
+ for (ExceptionTest test : exceptionTests) {
+ System.out.println("Testing " + test.name);
+ try {
+ mbs.registerMBean(test.mbean, name);
+ fail("Registration succeeded but should not have");
+ mbs.unregisterMBean(name);
+ } catch (NotCompliantMBeanException e) {
+ // OK
+ } catch (Exception e) {
+ fail("Registration failed with wrong exception: " +
+ "expected NotCompliantMBeanException, got " +
+ e.getClass().getName());
+ }
+ }
+ System.out.println();
+
+ if (failure == null)
+ System.out.println("TEST PASSED");
+ else
+ throw new Exception("TEST FAILED: " + failure);
+ }
+
+ private static void check(
+ MBeanInfo mbi, Defaults defaults, boolean expectConstructors)
+ throws Exception {
+ assertEquals("MBean description", mbi.getDescription());
+
+ // These attributes have descriptions
+ for (String attr : new String[] {"A", "B", "C", "D", "H"}) {
+ MBeanAttributeInfo mbai = getAttributeInfo(mbi, attr);
+ assertEquals(attr + " description", mbai.getDescription());
+ }
+
+ // These attributes don't have descriptions
+ for (String attr : new String[] {"E", "F", "G"}) {
+ // If we ever change the default description, we'll need to change
+ // this test accordingly.
+ MBeanAttributeInfo mbai = getAttributeInfo(mbi, attr);
+ assertEquals(
+ defaults.defaultAttributeDescription(attr), mbai.getDescription());
+ }
+
+ // This operation has a description, as do its parameters
+ MBeanOperationInfo opA = getOperationInfo(mbi, "opA");
+ assertEquals("opA description", opA.getDescription());
+ checkSignature(opA.getSignature());
+
+ // This operation has the default description, as does its parameter
+ MBeanOperationInfo opB = getOperationInfo(mbi, "opB");
+ assertEquals(defaults.defaultOperationDescription("opB"), opB.getDescription());
+ MBeanParameterInfo opB0 = opB.getSignature()[0];
+ assertEquals(defaults.defaultParameterDescription(0), opB0.getDescription());
+
+ if (expectConstructors) {
+ // The 0-arg and 2-arg constructors have descriptions
+ MBeanConstructorInfo con0 = getConstructorInfo(mbi, 0);
+ assertEquals("0-arg constructor description", con0.getDescription());
+ MBeanConstructorInfo con2 = getConstructorInfo(mbi, 2);
+ assertEquals("2-arg constructor description", con2.getDescription());
+ checkSignature(con2.getSignature());
+
+ // The 1-arg constructor does not have a description.
+ // The default description for constructors and their
+ // parameters is the same for all types of MBean.
+ MBeanConstructorInfo con1 = getConstructorInfo(mbi, 1);
+ assertEquals("Public constructor of the MBean", con1.getDescription());
+ assertEquals("", con1.getSignature()[0].getDescription());
+ }
+ }
+
+ private static void checkSignature(MBeanParameterInfo[] params) {
+ for (int i = 0; i < params.length; i++) {
+ MBeanParameterInfo mbpi = params[i];
+ assertEquals("p" + (i+1) + " description", mbpi.getDescription());
+ }
+ }
+
+ private static MBeanAttributeInfo getAttributeInfo(MBeanInfo mbi, String attr)
+ throws Exception {
+ return getFeatureInfo(mbi.getAttributes(), attr);
+ }
+
+ private static MBeanOperationInfo getOperationInfo(MBeanInfo mbi, String op)
+ throws Exception {
+ return getFeatureInfo(mbi.getOperations(), op);
+ }
+
+ private static MBeanConstructorInfo getConstructorInfo(MBeanInfo mbi, int nparams)
+ throws Exception {
+ for (MBeanConstructorInfo mbci : mbi.getConstructors()) {
+ if (mbci.getSignature().length == nparams)
+ return mbci;
+ }
+ throw new Exception("Constructor not found: " + nparams);
+ }
+
+ private static <T extends MBeanFeatureInfo> T getFeatureInfo(
+ T[] features, String name) throws Exception {
+ for (T feature : features) {
+ if (feature.getName().equals(name))
+ return feature;
+ }
+ throw new Exception("Feature not found: " + name);
+ }
+
+ private static void assertEquals(Object expected, Object actual) {
+ if (!expected.equals(actual))
+ fail("Expected " + string(expected) + ", got " + string(actual));
+ }
+
+ private static String string(Object x) {
+ if (x instanceof String)
+ return quote((String) x);
+ else
+ return String.valueOf(x);
+ }
+
+ private static String quote(String s) {
+ return '"' + s.replace("\\", "\\\\").replace("\"", "\\\"") + '"';
+ }
+
+ private static void fail(String why) {
+ StackTraceElement[] stack = new Throwable().getStackTrace();
+ int n = 0;
+ for (StackTraceElement elmt : stack) {
+ String method = elmt.getMethodName();
+ if (method.equals("fail") || method.equals("assertEquals") ||
+ method.equals("checkSignature"))
+ continue;
+ n = elmt.getLineNumber();
+ break;
+ }
+ System.out.println("FAILED: " + why + " (line " + n + ")");
+ failure = why;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/Introspector/ParameterNameTest.java Wed Jul 05 16:39:18 2017 +0200
@@ -0,0 +1,116 @@
+/*
+ * 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 that parameter names can be specified with @Name.
+ * @author Eamonn McManus
+ */
+
+import javax.management.MBean;
+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.ObjectName;
+
+import annot.Name;
+import javax.management.ManagedOperation;
+
+public class ParameterNameTest {
+ public static interface NoddyMBean {
+ public int add(int x, @Name("y") int y);
+ }
+
+ public static class Noddy implements NoddyMBean {
+ public int add(int x, int y) {
+ return x + y;
+ }
+ }
+
+ public static interface NoddyMXBean {
+ public int add(int x, @Name("y") int y);
+ }
+
+ public static class NoddyImpl implements NoddyMXBean {
+ public int add(int x, int y) {
+ return x + y;
+ }
+ }
+
+ @MBean
+ public static class NoddyAnnot {
+ @ManagedOperation
+ public int add(int x, @Name("y") int y) {
+ return x + y;
+ }
+ }
+
+ @MXBean
+ public static class NoddyAnnotMX {
+ @ManagedOperation
+ public int add(int x, @Name("y") int y) {
+ return x + y;
+ }
+ }
+
+ private static final Object[] mbeans = {
+ new Noddy(), new NoddyImpl(), new NoddyAnnot(), new NoddyAnnotMX(),
+ };
+
+ public static void main(String[] args) throws Exception {
+ MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+ ObjectName name = new ObjectName("a:b=c");
+ for (Object mbean : mbeans) {
+ System.out.println("Testing " + mbean.getClass().getName());
+ mbs.registerMBean(mbean, name);
+ MBeanInfo mbi = mbs.getMBeanInfo(name);
+ MBeanOperationInfo[] mbois = mbi.getOperations();
+ assertEquals(1, mbois.length);
+ MBeanParameterInfo[] mbpis = mbois[0].getSignature();
+ assertEquals(2, mbpis.length);
+ boolean mx = Boolean.parseBoolean(
+ (String) mbi.getDescriptor().getFieldValue("mxbean"));
+ assertEquals(mx ? "p0" : "p1", mbpis[0].getName());
+ assertEquals("y", mbpis[1].getName());
+ mbs.unregisterMBean(name);
+ }
+ System.out.println("TEST PASSED");
+ }
+
+ private static void assertEquals(Object expect, Object actual)
+ throws Exception {
+ boolean eq;
+ if (expect == null)
+ eq = (actual == null);
+ else
+ eq = expect.equals(actual);
+ if (!eq) {
+ throw new Exception(
+ "TEST FAILED: expected " + expect + ", found " + actual);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/Introspector/ResourceInjectionTest.java Wed Jul 05 16:39:18 2017 +0200
@@ -0,0 +1,656 @@
+/*
+ * 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 resource injection via @Resource
+ * @author Eamonn McManus
+ * @run main/othervm -ea ResourceInjectionTest
+ */
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.Serializable;
+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 javax.annotation.Resource;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.DynamicMBean;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBean;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+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.NotCompliantMBeanException;
+import javax.management.Notification;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.SendNotification;
+import javax.management.StandardEmitterMBean;
+import javax.management.StandardMBean;
+import javax.management.openmbean.MXBeanMappingFactory;
+
+public class ResourceInjectionTest {
+ private static MBeanServer mbs;
+ private static final ObjectName objectName;
+ static {
+ try {
+ objectName = new ObjectName("test:type=Test");
+ } catch (MalformedObjectNameException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /* This is somewhat nasty. In the current state of affairs, a
+ * StandardEmitterMBean can only get the
+ * MBeanServer to rewrite the source of a Notification from
+ * the originating object's reference to its ObjectName IF
+ * StandardEmitterMBean.getResource() returns a reference to the
+ * wrapped object. By default it doesn't, and you need to specify
+ * the option below to make it do so. We may hope that this is
+ * obscure enough for users to run into it rarely if ever.
+ */
+ private static final StandardMBean.Options withWrappedVisible;
+ private static final StandardMBean.Options withWrappedVisibleMX;
+ static {
+ withWrappedVisible = new StandardMBean.Options();
+ withWrappedVisible.setWrappedObjectVisible(true);
+ withWrappedVisibleMX = withWrappedVisible.clone();
+ withWrappedVisibleMX.setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT);
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ private static @interface ExpectException {
+ Class<? extends Exception> value();
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (!ResourceInjectionTest.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 : ResourceInjectionTest.class.getDeclaredMethods()) {
+ if (Modifier.isStatic(m.getModifiers()) &&
+ m.getName().startsWith("test") &&
+ m.getParameterTypes().length == 0) {
+ ExpectException expexc = m.getAnnotation(ExpectException.class);
+ mbs = MBeanServerFactory.newMBeanServer();
+ try {
+ m.invoke(null);
+ if (expexc != null) {
+ failure =
+ m.getName() + " did not got expected exception " +
+ expexc.value().getName();
+ System.out.println(failure);
+ } else
+ System.out.println(m.getName() + " OK");
+ } catch (InvocationTargetException ite) {
+ Throwable t = ite.getCause();
+ String prob = null;
+ if (expexc != null) {
+ if (expexc.value().isInstance(t)) {
+ System.out.println(m.getName() + " OK (got expected " +
+ expexc.value().getName() + ")");
+ } else
+ prob = "got wrong exception";
+ } else
+ prob = "got exception";
+ if (prob != null) {
+ failure = m.getName() + ": " + prob + " " +
+ t.getClass().getName();
+ System.out.println(failure);
+ t.printStackTrace(System.out);
+ }
+ }
+ }
+ }
+ if (failure == null)
+ System.out.println("TEST PASSED");
+ else
+ throw new Exception("TEST FAILED: " + failure);
+ }
+
+ private static interface Send {
+ public void send();
+ }
+
+ // Test @Resource in MBean defined by annotations
+
+ @MBean
+ public static class Annotated {
+ @Resource
+ private volatile MBeanServer mbeanServer;
+ @Resource
+ private volatile ObjectName myName;
+
+ @ManagedAttribute
+ public ObjectName getMyName() {
+ return myName;
+ }
+
+ @ManagedOperation
+ public void unregisterSelf()
+ throws InstanceNotFoundException, MBeanRegistrationException {
+ mbeanServer.unregisterMBean(myName);
+ }
+ }
+
+ private static void testAnnotated() throws Exception {
+ testMBean(new Annotated());
+ }
+
+ private static void testAnnotatedWrapped() throws Exception {
+ testMBean(new StandardMBean(new Annotated(), null));
+ }
+
+ @MBean
+ public static class AnnotatedSend extends Annotated implements Send {
+ @Resource
+ private volatile SendNotification sender;
+
+ @ManagedOperation
+ public void send() {
+ sender.sendNotification(new Notification("type", this, 0L));
+ }
+ }
+
+ private static void testAnnotatedSend() throws Exception {
+ testMBean(new AnnotatedSend());
+ }
+
+ private static void testAnnotatedSendWrapped() throws Exception {
+ testMBean(new StandardEmitterMBean(
+ new AnnotatedSend(), null, withWrappedVisible, null));
+ }
+
+ // Test @Resource in MXBean defined by annotations
+
+ @MXBean
+ public static class AnnotatedMX {
+ @Resource
+ private volatile MBeanServer mbeanServer;
+ @Resource
+ private volatile ObjectName myName;
+
+ @ManagedAttribute
+ public ObjectName getMyName() {
+ return myName;
+ }
+
+ @ManagedOperation
+ public void unregisterSelf()
+ throws InstanceNotFoundException, MBeanRegistrationException {
+ mbeanServer.unregisterMBean(myName);
+ }
+ }
+
+ private static void testAnnotatedMX() throws Exception {
+ testMBean(new AnnotatedMX());
+ }
+
+ private static void testAnnotatedMXWrapped() throws Exception {
+ testMBean(new StandardMBean(new AnnotatedMX(), null, true));
+ }
+
+ public static class AnnotatedMXSend extends AnnotatedMX implements Send {
+ @Resource
+ private volatile SendNotification sender;
+
+ @ManagedOperation
+ public void send() {
+ sender.sendNotification(new Notification("type", this, 0L));
+ }
+ }
+
+ private static void testAnnotatedMXSend() throws Exception {
+ testMBean(new AnnotatedMXSend());
+ }
+
+ private static void testAnnotatedMXSendWrapped() throws Exception {
+ testMBean(new StandardEmitterMBean(
+ new AnnotatedMXSend(), null, withWrappedVisibleMX, null));
+ }
+
+ // Test @Resource in Standard MBean
+
+ public static interface SimpleStandardMBean {
+ public ObjectName getMyName();
+ public void unregisterSelf() throws Exception;
+ }
+
+ public static class SimpleStandard implements SimpleStandardMBean {
+ @Resource(type = MBeanServer.class)
+ private volatile Object mbeanServer;
+ @Resource(type = ObjectName.class)
+ private volatile Object myName;
+
+ public ObjectName getMyName() {
+ return (ObjectName) myName;
+ }
+
+ public void unregisterSelf() throws Exception {
+ ((MBeanServer) mbeanServer).unregisterMBean(getMyName());
+ }
+ }
+
+ private static void testStandard() throws Exception {
+ testMBean(new SimpleStandard());
+ }
+
+ private static void testStandardWrapped() throws Exception {
+ testMBean(new StandardMBean(new SimpleStandard(), SimpleStandardMBean.class));
+ }
+
+ public static interface SimpleStandardSendMBean extends SimpleStandardMBean {
+ public void send();
+ }
+
+ public static class SimpleStandardSend
+ extends SimpleStandard implements SimpleStandardSendMBean {
+ @Resource(type = SendNotification.class)
+ private volatile Object sender;
+
+ public void send() {
+ ((SendNotification) sender).sendNotification(
+ new Notification("type", this, 0L));
+ }
+ }
+
+ private static void testStandardSend() throws Exception {
+ testMBean(new SimpleStandardSend());
+ }
+
+ private static void testStandardSendWrapped() throws Exception {
+ testMBean(new StandardEmitterMBean(
+ new SimpleStandardSend(), SimpleStandardSendMBean.class,
+ withWrappedVisible, null));
+ }
+
+ // Test @Resource in MXBean
+
+ public static interface SimpleMXBean {
+ public ObjectName getMyName();
+ public void unregisterSelf() throws Exception;
+ }
+
+ public static class SimpleMX implements SimpleMXBean {
+ @Resource(type = MBeanServer.class)
+ private volatile Object mbeanServer;
+ @Resource(type = ObjectName.class)
+ private volatile Object myName;
+
+ public ObjectName getMyName() {
+ return (ObjectName) myName;
+ }
+
+ public void unregisterSelf() throws Exception {
+ ((MBeanServer) mbeanServer).unregisterMBean(getMyName());
+ }
+ }
+
+ private static void testMX() throws Exception {
+ testMBean(new SimpleMX());
+ }
+
+ private static void testMXWrapped() throws Exception {
+ testMBean(new StandardMBean(new SimpleMX(), SimpleMXBean.class, true));
+ }
+
+ public static interface SimpleMXBeanSend extends SimpleMXBean {
+ public void send();
+ }
+
+ public MBeanServer getMbs() {
+ return mbs;
+ }
+
+ public static class SimpleMXSend extends SimpleMX implements SimpleMXBeanSend {
+ @Resource(type = SendNotification.class)
+ private volatile Object sender;
+
+ public void send() {
+ ((SendNotification) sender).sendNotification(
+ new Notification("type", this, 0L));
+ }
+ }
+
+ private static void testMXSend() throws Exception {
+ testMBean(new SimpleMXSend());
+ }
+
+ private static void testMXSendWrapped() throws Exception {
+ testMBean(new StandardEmitterMBean(
+ new SimpleMXSend(), SimpleMXBeanSend.class,
+ withWrappedVisibleMX, null));
+ }
+
+ // Test @Resource in Dynamic MBean
+
+ private static class SimpleDynamic implements DynamicMBean {
+ private MBeanServer mbeanServer;
+ private ObjectName myName;
+
+ @Resource
+ private synchronized void setMBeanServer(MBeanServer mbs) {
+ mbeanServer = mbs;
+ }
+
+ @Resource(type = ObjectName.class)
+ private synchronized void setObjectName(Serializable name) {
+ myName = (ObjectName) name;
+ }
+
+ public synchronized Object getAttribute(String attribute)
+ throws AttributeNotFoundException {
+ if (attribute.equals("MyName"))
+ return myName;
+ throw new AttributeNotFoundException(attribute);
+ }
+
+ public void setAttribute(Attribute attribute)
+ throws AttributeNotFoundException {
+ throw new AttributeNotFoundException(attribute.getName());
+ }
+
+ public synchronized AttributeList getAttributes(String[] attributes) {
+ AttributeList list = new AttributeList();
+ for (String name : attributes) {
+ if (name.equals("MyName"))
+ list.add(new Attribute("MyName", myName));
+ }
+ return list;
+ }
+
+ public AttributeList setAttributes(AttributeList attributes) {
+ return new AttributeList();
+ }
+
+ public synchronized Object invoke(
+ String actionName, Object[] params, String[] signature)
+ throws MBeanException, ReflectionException {
+ if (actionName.equals("unregisterSelf") &&
+ (params == null || params.length == 0) &&
+ (signature == null || signature.length == 0)) {
+ try {
+ mbeanServer.unregisterMBean(myName);
+ return null;
+ } catch (Exception x) {
+ throw new MBeanException(x);
+ }
+ } else {
+ Exception x = new NoSuchMethodException(
+ actionName + Arrays.toString(signature));
+ throw new MBeanException(x);
+ }
+ }
+
+ public MBeanInfo getMBeanInfo() {
+ DynamicMBean mbean = new StandardMBean(
+ new SimpleStandard(), SimpleStandardMBean.class, false);
+ return mbean.getMBeanInfo();
+ }
+ }
+
+ private static void testDynamic() throws Exception {
+ testMBean(new SimpleDynamic());
+ }
+
+ private static class SimpleDynamicSend extends SimpleDynamic {
+ private SendNotification sender;
+
+ @Resource
+ private synchronized void setSender(SendNotification sender) {
+ this.sender = sender;
+ }
+
+ @Override
+ public synchronized Object invoke(
+ String actionName, Object[] params, String[] signature)
+ throws MBeanException, ReflectionException {
+ if (actionName.equals("send")) {
+ sender.sendNotification(new Notification("type", this, 0L));
+ return null;
+ } else
+ return super.invoke(actionName, params, signature);
+ }
+ }
+
+ private static void testDynamicSend() throws Exception {
+ testMBean(new SimpleDynamicSend());
+ }
+
+ // Test that @Resource classes don't have to be public
+ // They can even be defined within methods!
+ // But you can't have any @ManagedAttributes or @ManagedOperations
+ // in such MBeans so their utility is limited.
+
+ private static void testNonPublic() throws Exception {
+ @MBean
+ class NonPublic {
+ @Resource
+ ObjectName myName;
+ }
+ assert !Modifier.isPublic(NonPublic.class.getModifiers());
+ NonPublic mbean = new NonPublic();
+ mbs.registerMBean(mbean, objectName);
+ assert objectName.equals(mbean.myName);
+ }
+
+ // Test inheritance and multiple injections of the same value
+
+ private static class ManyResources extends AnnotatedSend {
+ @Resource
+ private volatile ObjectName myName; // same name as in parent!
+ @Resource(type=ObjectName.class)
+ private volatile Object myOtherName;
+ private volatile ObjectName myThirdName;
+ private volatile ObjectName myFourthName;
+ private volatile int methodCalls;
+ @Resource
+ private volatile SendNotification send1;
+ @Resource(type = SendNotification.class)
+ private volatile Object send2;
+
+ @Resource
+ void setMyName(ObjectName name) {
+ myThirdName = name;
+ methodCalls++;
+ }
+
+ @Resource(type=ObjectName.class)
+ private void setMyNameAgain(ObjectName name) {
+ myFourthName = name;
+ methodCalls++;
+ }
+
+ void check() {
+ assert objectName.equals(myName) : myName;
+ for (ObjectName name : new ObjectName[] {
+ (ObjectName)myOtherName, myThirdName, myFourthName
+ }) {
+ assert myName == name : name;
+ }
+ assert methodCalls == 2 : methodCalls;
+ assert send1 != null && send2 == send1;
+ }
+ }
+
+ private static void testManyResources() throws Exception {
+ ManyResources mr = new ManyResources();
+ testMBean(mr);
+ mr.check();
+ }
+
+ // Test that method override doesn't lead to multiple calls of the same method
+
+ private static class ManyResourcesSub extends ManyResources {
+ private boolean called;
+
+ @Override
+ @Resource
+ void setMyName(ObjectName name) {
+ super.setMyName(name);
+ called = true;
+ }
+
+ void check2() {
+ assert called;
+ }
+ }
+
+ private static void testOverride() throws Exception {
+ ManyResourcesSub mrs = new ManyResourcesSub();
+ testMBean(mrs);
+ mrs.check();
+ mrs.check2();
+ }
+
+ // Test that @Resource is illegal on static fields
+
+ @MBean
+ public static class StaticResource {
+ @Resource
+ private static ObjectName name;
+ }
+
+ @ExpectException(NotCompliantMBeanException.class)
+ private static void testStaticResource() throws Exception {
+ testMBean(new StaticResource());
+ }
+
+ // Test that @Resource is illegal on static methods
+
+ @MBean
+ public static class StaticResourceMethod {
+ @Resource
+ private static void setObjectName(ObjectName name) {}
+ }
+
+ @ExpectException(NotCompliantMBeanException.class)
+ private static void testStaticResourceMethod() throws Exception {
+ testMBean(new StaticResourceMethod());
+ }
+
+ // Test that @Resource is illegal on methods that don't return void
+
+ @MBean
+ public static class NonVoidMethod {
+ @Resource
+ private String setObjectName(ObjectName name) {
+ return "oops";
+ }
+ }
+
+ @ExpectException(NotCompliantMBeanException.class)
+ private static void testNonVoidMethod() throws Exception {
+ testMBean(new NonVoidMethod());
+ }
+
+ // Test that @Resource is illegal on methods with no arguments
+
+ @MBean
+ public static class NoArgMethod {
+ @Resource(type=ObjectName.class)
+ private void setObjectName() {}
+ }
+
+ @ExpectException(NotCompliantMBeanException.class)
+ private static void testNoArgMethod() throws Exception {
+ testMBean(new NoArgMethod());
+ }
+
+ // Test that @Resource is illegal on methods with more than one argument
+
+ @MBean
+ public static class MultiArgMethod {
+ @Resource
+ private void setObjectName(ObjectName name, String what) {}
+ }
+
+ @ExpectException(NotCompliantMBeanException.class)
+ private static void testMultiArgMethod() throws Exception {
+ testMBean(new MultiArgMethod());
+ }
+
+ private static class CountListener implements NotificationListener {
+ volatile int count;
+ public void handleNotification(Notification notification, Object handback) {
+ count++;
+ }
+ }
+
+ private static void testMBean(Object mbean) throws Exception {
+ mbs.registerMBean(mbean, objectName);
+
+ final ObjectName name = (ObjectName) mbs.getAttribute(objectName, "MyName");
+ assert objectName.equals(name) : name;
+
+ if (mbean instanceof Send || mbean instanceof NotificationEmitter) {
+ assert mbs.isInstanceOf(name, NotificationEmitter.class.getName());
+ CountListener countL = new CountListener();
+ mbs.addNotificationListener(name, countL, null, null);
+ NotificationListener checkSource = new NotificationListener() {
+ public void handleNotification(Notification n, Object h) {
+ assert n.getSource().equals(name) : n.getSource();
+ }
+ };
+ mbs.addNotificationListener(name, checkSource, null, null);
+ mbs.invoke(objectName, "send", null, null);
+ assert countL.count == 1;
+ mbs.removeNotificationListener(name, checkSource);
+ mbs.removeNotificationListener(name, countL, null, null);
+ }
+
+ mbs.invoke(objectName, "unregisterSelf", null, null);
+ assert !mbs.isRegistered(objectName);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/Introspector/annot/Name.java Wed Jul 05 16:39:18 2017 +0200
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package annot;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Name {
+ String value();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/mxbean/ComparatorExceptionTest.java Wed Jul 05 16:39:18 2017 +0200
@@ -0,0 +1,90 @@
+/*
+ * 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
+ * @bug 6601652
+ * @summary Test exception when SortedMap or SortedSet has non-null Comparator
+ * @author Eamonn McManus
+ */
+
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+
+public class ComparatorExceptionTest {
+ public static interface TestMXBean {
+ public SortedSet<String> getSortedSet();
+ public SortedMap<String, String> getSortedMap();
+ }
+
+ public static class TestImpl implements TestMXBean {
+ public SortedSet<String> getSortedSet() {
+ return new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
+ }
+
+ public SortedMap<String, String> getSortedMap() {
+ return new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
+ }
+ }
+
+ private static String failure;
+
+ private static void fail(String why) {
+ failure = "FAILED: " + why;
+ System.out.println(failure);
+ }
+
+ public static void main(String[] args) throws Exception {
+ MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+ ObjectName name = new ObjectName("a:b=c");
+ mbs.registerMBean(new TestImpl(), name);
+
+ for (String attr : new String[] {"SortedSet", "SortedMap"}) {
+ try {
+ Object value = mbs.getAttribute(name, attr);
+ fail("get " + attr + " did not throw exception");
+ } catch (Exception e) {
+ Throwable t = e;
+ while (!(t instanceof IllegalArgumentException)) {
+ if (t == null)
+ break;
+ t = t.getCause();
+ }
+ if (t != null)
+ System.out.println("Correct exception for " + attr);
+ else {
+ fail("get " + attr + " got wrong exception");
+ e.printStackTrace(System.out);
+ }
+ }
+ }
+
+ if (failure != null)
+ throw new Exception(failure);
+ }
+}
--- a/jdk/test/javax/management/mxbean/MXBeanTest.java Thu Jul 17 11:28:32 2008 -0700
+++ b/jdk/test/javax/management/mxbean/MXBeanTest.java Wed Jul 05 16:39:18 2017 +0200
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6175517 6278707 6318827 6305746 6392303
+ * @bug 6175517 6278707 6318827 6305746 6392303 6600709
* @summary General MXBean test.
* @author Eamonn McManus
* @run clean MXBeanTest MerlinMXBean TigerMXBean
@@ -40,7 +40,8 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
-import javax.management.Attribute;
+import java.util.Map;
+import java.util.SortedMap;
import javax.management.JMX;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
@@ -55,10 +56,6 @@
import javax.management.openmbean.ArrayType;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataInvocationHandler;
-import javax.management.openmbean.OpenMBeanAttributeInfo;
-import javax.management.openmbean.OpenMBeanInfo;
-import javax.management.openmbean.OpenMBeanOperationInfo;
-import javax.management.openmbean.OpenMBeanParameterInfo;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;
import javax.management.openmbean.TabularData;
@@ -81,10 +78,8 @@
if (failures == 0)
System.out.println("Test passed");
- else {
- System.out.println("TEST FAILURES: " + failures);
- System.exit(1);
- }
+ else
+ throw new Exception("TEST FAILURES: " + failures);
}
private static int failures = 0;
@@ -561,6 +556,11 @@
return false;
return deepEqual(o1, o2, namedMXBeans);
}
+ if (o1 instanceof Map) {
+ if (!(o2 instanceof Map))
+ return false;
+ return equalMap((Map) o1, (Map) o2, namedMXBeans);
+ }
if (o1 instanceof CompositeData && o2 instanceof CompositeData) {
return compositeDataEqual((CompositeData) o1, (CompositeData) o2,
namedMXBeans);
@@ -600,6 +600,21 @@
return true;
}
+ private static boolean equalMap(Map<?,?> m1, Map<?,?> m2,
+ NamedMXBeans namedMXBeans) {
+ if (m1.size() != m2.size())
+ return false;
+ if ((m1 instanceof SortedMap) != (m2 instanceof SortedMap))
+ return false;
+ for (Object k1 : m1.keySet()) {
+ if (!m2.containsKey(k1))
+ return false;
+ if (!equal(m1.get(k1), m2.get(k1), namedMXBeans))
+ return false;
+ }
+ return true;
+ }
+
// This is needed to work around a bug (5095277)
// in CompositeDataSupport.equals
private static boolean compositeDataEqual(CompositeData cd1,
@@ -655,7 +670,7 @@
/* I wanted to call this method toString(Object), but oddly enough
this meant that I couldn't call it from the inner class
MXBeanImplInvocationHandler, because the inherited Object.toString()
- prevented that. Surprising behaviour. */
+ prevented that. */
static String string(Object o) {
if (o == null)
return "null";
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/mxbean/SameObjectTwoNamesTest.java Wed Jul 05 16:39:18 2017 +0200
@@ -0,0 +1,76 @@
+/*
+ * 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 SameObjectTwoNamesTest.java
+ * @bug 6283873
+ * @summary Check that registering the same MXBean under two different
+ * names produces an exception
+ * @author Alexander Shusherov
+ * @author Eamonn McManus
+ * @run main SameObjectTwoNamesTest
+ * @run main/othervm -Djmx.mxbean.multiname=true SameObjectTwoNamesTest
+ */
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+
+public class SameObjectTwoNamesTest {
+
+ public static void main(String[] args) throws Exception {
+ boolean expectException =
+ (System.getProperty("jmx.mxbean.multiname") == null);
+ try {
+ ObjectName objectName1 = new ObjectName("test:index=1");
+ ObjectName objectName2 = new ObjectName("test:index=2");
+ MBeanServer mbs = MBeanServerFactory.createMBeanServer();
+ MXBC_SimpleClass01 mxBeanObject = new MXBC_SimpleClass01();
+
+ mbs.registerMBean(mxBeanObject, objectName1);
+
+ mbs.registerMBean(mxBeanObject, objectName2);
+
+ if (expectException) {
+ throw new Exception("TEST FAILED: " +
+ "InstanceAlreadyExistsException was not thrown");
+ } else
+ System.out.println("Correctly got no exception with compat property");
+ } catch (InstanceAlreadyExistsException e) {
+ if (expectException) {
+ System.out.println("Got expected InstanceAlreadyExistsException:");
+ e.printStackTrace(System.out);
+ } else {
+ throw new Exception(
+ "TEST FAILED: Got exception even though compat property set", e);
+ }
+ }
+ System.out.println("TEST PASSED");
+ }
+
+ public interface MXBC_Simple01MXBean {}
+
+ public static class MXBC_SimpleClass01 implements MXBC_Simple01MXBean {}
+
+}