Merge
diff --git a/.hgtags-top-repo b/.hgtags-top-repo
index c0b9b72..75e4e32 100644
--- a/.hgtags-top-repo
+++ b/.hgtags-top-repo
@@ -14,3 +14,4 @@
744554f5a3290e11c71cd2ddb1aff49e431f9ed0 jdk7-b37
cc47a76899ed33a2c513cb688348244c9b5a1288 jdk7-b38
ab523b49de1fc73fefe6855ce1e0349bdbd7af29 jdk7-b39
+44be42de6693063fb191989bf0e188de2fa51e7c jdk7-b40
diff --git a/README-builds.html b/README-builds.html
index 8783bf8..ce77a65 100644
--- a/README-builds.html
+++ b/README-builds.html
@@ -98,7 +98,8 @@
<h2><a name="MBE">Minimum Build Environments</a></h2>
<blockquote>
This file often describes specific requirements for what we call the
- "minimum build environments" (MBE) for the JDK.
+ "minimum build environments" (MBE) for this
+ specific release of the JDK,
Building with the MBE will generate the most compatible
bits that install on, and run correctly on, the most variations
of the same base OS and hardware architecture.
@@ -116,22 +117,22 @@
<tr>
<th>Base OS and Architecture</th>
<th>OS</th>
- <th>Compiler</th>
+ <th>C/C++ Compiler</th>
</tr>
</thead>
<tbody>
<tr>
- <td>Linux X86 (32bit)</td>
- <td>Red Hat Enterprise Linux 4 </td>
+ <td>Linux X86 (32-bit)</td>
+ <td>Fedora 9</td>
<td>gcc 4 </td>
</tr>
<tr>
- <td>Linux X64 (64bit)</td>
- <td>Red Hat Enterprise Linux 4 </td>
+ <td>Linux X64 (64-bit)</td>
+ <td>Fedora 9</td>
<td>gcc 4 </td>
</tr>
<tr>
- <td>Solaris SPARC (32bit)</td>
+ <td>Solaris SPARC (32-bit)</td>
<td>Solaris 10 + patches
<br>
See <a href="http://sunsolve.sun.com/pub-cgi/show.pl?target=patches/JavaSE" target="_blank">
@@ -140,7 +141,7 @@
<td>Sun Studio 12</td>
</tr>
<tr>
- <td>Solaris SPARCV9 (64bit)</td>
+ <td>Solaris SPARCV9 (64-bit)</td>
<td>Solaris 10 + patches
<br>
See <a href="http://sunsolve.sun.com/pub-cgi/show.pl?target=patches/JavaSE" target="_blank">
@@ -149,7 +150,7 @@
<td>Sun Studio 12</td>
</tr>
<tr>
- <td>Solaris X86 (32bit)</td>
+ <td>Solaris X86 (32-bit)</td>
<td>Solaris 10 + patches
<br>
See <a href="http://sunsolve.sun.com/pub-cgi/show.pl?target=patches/JavaSE" target="_blank">
@@ -158,7 +159,7 @@
<td>Sun Studio 12</td>
</tr>
<tr>
- <td>Solaris X64 (64bit)</td>
+ <td>Solaris X64 (64-bit)</td>
<td>Solaris 10 + patches
<br>
See <a href="http://sunsolve.sun.com/pub-cgi/show.pl?target=patches/JavaSE" target="_blank">
@@ -167,17 +168,28 @@
<td>Sun Studio 12</td>
</tr>
<tr>
- <td>Windows X86 (32bit)</td>
+ <td>Windows X86 (32-bit)</td>
<td>Windows XP</td>
- <td>Microsoft Visual Studio .NET 2003 Professional</td>
+ <td>Microsoft Visual Studio C++ 2008 Standard Edition</td>
</tr>
<tr>
- <td>Windows X64 (64bit)</td>
+ <td>Windows X64 (64-bit)</td>
<td>Windows Server 2003 - Enterprise x64 Edition</td>
<td>Microsoft Platform SDK - April 2005</td>
</tr>
</tbody>
</table>
+ <p>
+ These same sources do indeed build on many more systems than the
+ above older generation systems, again the above is just a minimum.
+ <p>
+ Compilation problems with newer or different C/C++ compilers is a
+ common problem.
+ Similarly, compilation problems related to changes to the
+ <tt>/usr/include</tt> or system header files is also a
+ common problem with newer or unreleased OS versions.
+ Please report these types of problems as bugs so that they
+ can be dealt with accordingly.
</blockquote>
<!-- ------------------------------------------------------ -->
<hr>
@@ -488,7 +500,7 @@
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, like 3.82.
+ version that has this problem fixed.
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>.
@@ -575,8 +587,8 @@
</li>
<li>
Install
- <a href="#ant">Ant</a>, set
- <tt><a href="#ANT_HOME">ANT_HOME</a></tt>.
+ <a href="#ant">Ant</a>,
+ make sure it is in your PATH.
</li>
</ol>
</blockquote>
@@ -592,7 +604,7 @@
Approximately 1.4 GB of free disk
space is needed for a 32-bit build.
<p>
- If you are building the 64bit version, you should
+ If you are building the 64-bit version, you should
run the command "isainfo -v" to verify that you have a
64-bit installation, it should say <tt>sparcv9</tt> or
<tt>amd64</tt>.
@@ -640,8 +652,8 @@
</li>
<li>
Install
- <a href="#ant">Ant</a>, set
- <tt><a href="#ANT_HOME">ANT_HOME</a></tt>.
+ <a href="#ant">Ant</a>,
+ make sure it is in your PATH.
</li>
</ol>
</blockquote>
@@ -650,11 +662,11 @@
<h3><a name="windows">Basic Windows System Setup</a></h3>
<blockquote>
<strong>i586 only:</strong>
- The minimum recommended hardware for building the 32bit or X86
+ The minimum recommended hardware for building the 32-bit or X86
Windows version is an Pentium class processor or better, at least
512 MB of RAM, and approximately 600 MB of free disk space.
<strong>
- NOTE: The Windows 2000 build machines need to use the
+ NOTE: The Windows build machines need to use the
file system NTFS.
Build machines formatted to FAT32 will not work
because FAT32 doesn't support case-sensitivity in file names.
@@ -719,8 +731,11 @@
</li>
<li>
Install the
- <a href="#msvc">Microsoft Visual Studio .NET 2003 Professional</a> (32bit) or the
- <a href="#mssdk">Microsoft Platform SDK</a> (64bit).
+ <a href="#msvc">Microsoft Visual Studio Compilers</a> (32-bit).
+ </li>
+ <li>
+ Install the
+ <a href="#mssdk">Microsoft Platform SDK</a>.
</li>
<li>
Setup all environment variables for compilers
@@ -732,7 +747,8 @@
</li>
<li>
Install
- <a href="#ant">Ant</a>, set
+ <a href="#ant">Ant</a>,
+ make sure it is in your PATH and set
<tt><a href="#ANT_HOME">ANT_HOME</a></tt>.
</li>
</ol>
@@ -787,7 +803,9 @@
you must first download and install the appropriate
binary plug bundles for the OpenJDK, go to the
<a href="http://openjdk.java.net" target="_blank">OpenJDK</a> site and select
- the "<b>Bundles(7)</b>" link and download the binaryplugs for
+ the
+ "<b>Bundles(7)</b>"
+ link and download the binaryplugs for
your particular platform.
The file downloaded is a jar file that must be extracted by running
the jar file with:
@@ -823,14 +841,12 @@
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
+ You should always make sure <tt>ant</tt> is in your PATH, and
+ on Windows you may also need to 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>
@@ -862,25 +878,9 @@
<blockquote>
<strong><a name="gcc">Linux gcc/binutils</a></strong>
<blockquote>
- The GNU gcc compiler version should be 3.2.2 or newer.
- The binutils package should be 2.11.93.0.2-11 or newer.
+ The GNU gcc compiler version should be 4 or newer.
The compiler used should be the default compiler installed
in <tt>/usr/bin</tt>.
- <p>
- Older Linux systems may require a gcc and bunutils update.
- The Redhat Enterprise Advanced Server 2.1 update 2 system
- is one of these systems.
- RedHat Linux users can obtain this binutils package from
- <a href="http://www.redhat.com"
- target="_blank">Redhat web site</a>.
- You will need to remove the default compiler and binutils
- packages and install the required packages
- into the default location on the system.
- However if you have a new video card driver, like
- Geforce 4 it is best to use
- the same compiler as the kernel was built with to
- build the new video card driver module.
- So you should build the modules before making this change.
</blockquote>
<strong><a name="studio">Solaris: Sun Studio</a></strong>
<blockquote>
@@ -903,19 +903,20 @@
are also an option, although these compilers have not
been extensively used yet.
</blockquote>
- <strong><a name="msvc">Windows i586: Microsoft Visual Studio .NET 2003 Professional</a></strong>
+ <strong><a name="msvc">Windows i586: Microsoft Visual Studio Compilers</a></strong>
<blockquote>
The 32-bit OpenJDK Windows build
- requires Microsoft Visual Studio .NET 2003 (VS2003) Professional
+ requires
+ Microsoft Visual Studio C++ 2008 (VS2008) Standard
Edition compiler.
The compiler and other tools are expected to reside
- in the location defined by the variable <tt>VS71COMNTOOLS</tt> which
- is set by the Microsoft Visual Studio .NET installer.
+ in the location defined by the variable
+ <tt>VS90COMNTOOLS</tt> which
+ is set by the Microsoft Visual Studio installer.
<p>
Once the compiler is installed,
it is recommended that you run <tt>VCVARS32.BAT</tt>
to set the compiler environment variables
- <tt>MSVCDIR</tt>,
<tt>INCLUDE</tt>,
<tt>LIB</tt>, and
<tt>PATH</tt>
@@ -923,16 +924,12 @@
OpenJDK.
The above environment variables <b>MUST</b> be set.
<p>
- The Microsoft Visual Studio .NET 2005 (VS2005) compiler
- will not work at this time due to the new runtime dll
- and the manifest requirements.
- <p>
<b>WARNING:</b> Make sure you check out the
<a href="#cygwin">CYGWIN link.exe WARNING</a>.
The path <tt>/usr/bin</tt> must be after the path to the
Visual Studio product.
</blockquote>
- <strong><a name="mssdk">Windows X64: Microsoft Platform SDK April 2005</a></strong>
+ <strong><a name="mssdk">Windows: Microsoft Platform SDK</a></strong>
<blockquote>
On <b>X64</b>, the Microsoft Platform Software
Development Kit (SDK), April 2005 Edition compiler,
@@ -953,10 +950,9 @@
OpenJDK.
The above environment variables <b>MUST</b> be set.
<p>
- Note that this compiler may say it's version is a
- Microsoft Visual Studio .NET 2005 (VS2005), but be careful,
- it will not match the official VS2005 product.
- This Platform SDK compiler is only used on X64 builds.
+ This Platform SDK compiler is only used on X64 builds
+ but other parts of the Platform SDK may be used
+ for the X86 builds.
</blockquote>
</blockquote>
<!-- ------------------------------------------------------ -->
@@ -1241,37 +1237,37 @@
<strong><a name="msvcrt"><tt>MSVCRT.DLL</tt></a></strong>
<blockquote>
<strong>i586 only:</strong>
- The OpenJDK 32bit build requires access to
- <tt>MSVCRT.DLL</tt> version 6.00.8337.0 or newer.
+ The OpenJDK 32-bit build requires access to a redistributable
+ <tt>MSVCRT.DLL</tt>.
If the <tt>MSVCRT.DLL</tt> is not installed in
the system32 directory set the
<a href="#ALT_MSVCRT_DLL_PATH"><tt>ALT_MSVCRT_DLL_PATH</tt></a>
- variable to the location.
+ variable to the location of this file.
<p>
<strong>X64 only:</strong>
- The OpenJDK 64bit build requires access to
- <tt>MSVCRT.DLL</tt> version 7.0.3790.0 or newer, which is
+ The OpenJDK 64-bit build requires access to a redistributable
+ <tt>MSVCRT.DLL</tt>, which is
usually supplied by the
<a href="#mssdk">Platform SDK</a>.
If it is not available from the Platform SDK,
set the
<a href="#ALT_MSVCRT_DLL_PATH"><tt>ALT_MSVCRT_DLL_PATH</tt></a>
- variable to the location.
+ variable to the location of this file.
</blockquote>
- <strong><tt><a name="msvcr71">MSVCR71.DLL</a></tt></strong>
+ <strong><tt><a name="msvcr90">MSVCR90.DLL</a></tt></strong>
<blockquote>
<strong>i586 only:</strong>
The
OpenJDK
- build requires access to
- MSVCR71.DLL version 7.10.3052.4 or newer which should be
+ build requires access to a redistributable
+ <tt>MSVCR90.DLL</tt> which should be
supplied by the
- <a href="#msvc">Visual Studio product</a>
- If the <tt>MSVCR71.DLL</tt> is not available from the
+ <a href="#msvc">Visual Studio product</a>.
+ If the <tt>MSVCR90.DLL</tt> is not available from the
Visual Studio product
set the
- <a href="#ALT_MSVCR71_DLL_PATH"><tt>ALT_MSVCR71_DLL_PATH</tt></a>
- variable to the location.
+ <a href="#ALT_MSVCR90_DLL_PATH"><tt>ALT_MSVCR90_DLL_PATH</tt></a>
+ variable to the location of this file.
</blockquote>
</blockquote>
<!-- ------------------------------------------------------ -->
@@ -1359,13 +1355,38 @@
document) that can impact the build are:
<blockquote>
<dl>
- <dt><a name="ALT_BINARY_PLUGS_PATH"><tt>ALT_BINARY_PLUGS_PATH</tt></a></dt>
+ <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 location of the binary plugs installation.
- See <a href="#binaryplugs">Binary Plugs</a> for more information.
- You should always have a local copy of a
- recent Binary Plugs install image
- and set this variable to that location.
+ 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>
@@ -1374,25 +1395,89 @@
You should always install your own local Bootstrap JDK and
always set <tt>ALT_BOOTDIR</tt> explicitly.
</dd>
- <dt><a name="ALT_BUILD_BINARY_PLUGS_PATH"><tt>ALT_BUILD_BINARY_PLUGS_PATH</tt></a></dt>
+ <dt><a name="ALT_BINARY_PLUGS_PATH"><tt>ALT_BINARY_PLUGS_PATH</tt></a></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.
+ The location of the binary plugs installation.
+ See <a href="#binaryplugs">Binary Plugs</a> for more information.
+ You should always have a local copy of a
+ 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>
+ <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>.
+ </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>,
+ and on Windows with CYGWIN
+ <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_SLASH_JAVA"><tt>ALT_SLASH_JAVA</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_BUILD_JDK_IMPORT_PATH"><tt>ALT_BUILD_JDK_IMPORT_PATH</tt></a></dt>
<dd>
@@ -1414,166 +1499,57 @@
Where each of these directories contain the import JDK image
for that platform.
</dd>
- <dt><tt><a name="ALT_CACERTS_FILE">ALT_CACERTS_FILE</a></tt></dt>
+ <dt><a name="ALT_BUILD_BINARY_PLUGS_PATH"><tt>ALT_BUILD_BINARY_PLUGS_PATH</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>.
+ 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_COMPILER_PATH"><tt>ALT_COMPILER_PATH</tt></a> </dt>
+ <dt><strong>Windows specific:</strong></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>
- <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><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>
- <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_SLASH_JAVA"><tt>ALT_SLASH_JAVA</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>
+ <dl>
+ <dt><a name="ALT_MSDEVTOOLS_PATH"><tt>ALT_MSDEVTOOLS_PATH</tt></a> </dt>
+ <dd>
+ The location of the
+ Microsoft Visual Studio
+ 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_MSVCR90_DLL_PATH">ALT_MSVCR90_DLL_PATH</a></tt> </dt>
+ <dd>
+ <strong>i586 only:</strong>
+ The location of the
+ <a href="#msvcr90"><tt>MSVCR90.DLL</tt></a>.
+ </dd>
+ </dl>
</dd>
</dl>
</blockquote>
@@ -1661,8 +1637,8 @@
This is caused by a missing libstdc++.a library.
This is installed as part of a specific package
(e.g. libstdc++.so.devel.386).
- By default some 64bit Linux versions (e.g. Fedora)
- only install the 64bit version of the libstdc++ package.
+ By default some 64-bit Linux versions (e.g. Fedora)
+ only install the 64-bit version of the libstdc++ package.
Various parts of the JDK build require a static
link of the C++ runtime libraries to allow for maximum
portability of the built images.
diff --git a/corba/.hgtags b/corba/.hgtags
index ae11865..73edf0f 100644
--- a/corba/.hgtags
+++ b/corba/.hgtags
@@ -14,3 +14,4 @@
59d5848bdedebe91cc2753acce78911bcb4a66db jdk7-b37
08be802754b0296c91a7713b6d85a015dbcd5349 jdk7-b38
55078b6661e286e90387d1d9950bd865f5cc436e jdk7-b39
+184e21992f47a8d730df1adc5b21a108f3125489 jdk7-b40
diff --git a/hotspot/.hgtags b/hotspot/.hgtags
index f7cd42c..8971443 100644
--- a/hotspot/.hgtags
+++ b/hotspot/.hgtags
@@ -14,3 +14,4 @@
9ee9cf798b59e7d51f8c0a686959f313867a55d6 jdk7-b37
d9bc824aa078573829bb66572af847e26e1bd12e jdk7-b38
49ca90d77f34571b0757ebfcb8a7848ef2696b88 jdk7-b39
+81a0cbe3b28460ce836109934ece03db7afaf9cc jdk7-b40
diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version
index 9673d78..fe716dd 100644
--- a/hotspot/make/hotspot_version
+++ b/hotspot/make/hotspot_version
@@ -35,7 +35,7 @@
HS_MAJOR_VER=14
HS_MINOR_VER=0
-HS_BUILD_NUMBER=07
+HS_BUILD_NUMBER=08
JDK_MAJOR_VER=1
JDK_MINOR_VER=7
diff --git a/hotspot/make/linux/makefiles/top.make b/hotspot/make/linux/makefiles/top.make
index 46362ca..1c212c6 100644
--- a/hotspot/make/linux/makefiles/top.make
+++ b/hotspot/make/linux/makefiles/top.make
@@ -85,9 +85,9 @@
AD_Dir = $(GENERATED)/adfiles
ADLC = $(AD_Dir)/adlc
-AD_Spec = $(GAMMADIR)/src/cpu/$(Platform_arch)/vm/$(Platform_arch).ad
+AD_Spec = $(GAMMADIR)/src/cpu/$(Platform_arch)/vm/$(Platform_arch_model).ad
AD_Src = $(GAMMADIR)/src/share/vm/adlc
-AD_Names = ad_$(Platform_arch).hpp ad_$(Platform_arch).cpp
+AD_Names = ad_$(Platform_arch_model).hpp ad_$(Platform_arch_model).cpp
AD_Files = $(AD_Names:%=$(AD_Dir)/%)
# AD_Files_If_Required/COMPILER1 = ad_stuff
diff --git a/hotspot/make/solaris/makefiles/amd64.make b/hotspot/make/solaris/makefiles/amd64.make
index 7ce14ea..b05414d 100644
--- a/hotspot/make/solaris/makefiles/amd64.make
+++ b/hotspot/make/solaris/makefiles/amd64.make
@@ -26,7 +26,6 @@
CFLAGS += -DVM_LITTLE_ENDIAN
# Not included in includeDB because it has no dependencies
-# Obj_Files += solaris_amd64.o
Obj_Files += solaris_x86_64.o
#
@@ -38,8 +37,6 @@
# _lwp_create_interpose must have a frame
OPT_CFLAGS/os_solaris_x86_64.o = -xO1
-# force C++ interpreter to be full optimization
-#OPT_CFLAGS/interpret.o = -fast -O4
# Temporary until SS10 C++ compiler is fixed
OPT_CFLAGS/generateOptoStub.o = -xO2
@@ -51,8 +48,6 @@
# gcc
# The serviceability agent relies on frame pointer (%rbp) to walk thread stack
CFLAGS += -fno-omit-frame-pointer
-# force C++ interpreter to be full optimization
-#OPT_CFLAGS/interpret.o = -O3
else
# error
diff --git a/hotspot/make/solaris/makefiles/debug.make b/hotspot/make/solaris/makefiles/debug.make
index 69eb236..4fdf4a7 100644
--- a/hotspot/make/solaris/makefiles/debug.make
+++ b/hotspot/make/solaris/makefiles/debug.make
@@ -30,7 +30,7 @@
ifeq ("${Platform_compiler}", "sparcWorks")
-ifeq ($(COMPILER_REV),5.8)
+ifeq ($(COMPILER_REV_NUMERIC),508)
# SS11 SEGV when compiling with -g and -xarch=v8, using different backend
DEBUG_CFLAGS/compileBroker.o = $(DEBUG_CFLAGS) -xO0
DEBUG_CFLAGS/jvmtiTagMap.o = $(DEBUG_CFLAGS) -xO0
diff --git a/hotspot/make/solaris/makefiles/dtrace.make b/hotspot/make/solaris/makefiles/dtrace.make
index bcc7819..0ba875d 100644
--- a/hotspot/make/solaris/makefiles/dtrace.make
+++ b/hotspot/make/solaris/makefiles/dtrace.make
@@ -87,17 +87,16 @@
XLIBJVM_DB = 64/$(LIBJVM_DB)
XLIBJVM_DTRACE = 64/$(LIBJVM_DTRACE)
-XARCH = $(subst sparcv9,v9,$(shell echo $(ISA)))
$(XLIBJVM_DB): $(DTRACE_SRCDIR)/$(JVM_DB).c $(JVMOFFS).h $(LIBJVM_DB_MAPFILE)
@echo Making $@
$(QUIETLY) mkdir -p 64/ ; \
- $(CC) $(SYMFLAG) $(ARCHFLAG/$(XARCH)) -D$(TYPE) -I. -I$(GENERATED) \
+ $(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. -I$(GENERATED) \
$(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -lc
$(XLIBJVM_DTRACE): $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE)
@echo Making $@
$(QUIETLY) mkdir -p 64/ ; \
- $(CC) $(SYMFLAG) $(ARCHFLAG/$(XARCH)) -D$(TYPE) -I. \
+ $(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. \
$(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c -lc -lthread -ldoor
endif # ifneq ("${ISA}","${BUILDARCH}")
@@ -116,27 +115,25 @@
$(QUIETLY) $(LINK.CC) -z nodefs -o $@ $(DTRACE_SRCDIR)/$(GENOFFS)Main.c \
./lib$(GENOFFS).so
-# $@.tmp is created first. It's to avoid empty $(JVMOFFS).h produced in error case.
+CONDITIONALLY_UPDATE_JVMOFFS_TARGET = \
+ cmp -s $@ $@.tmp; \
+ case $$? in \
+ 0) rm -f $@.tmp;; \
+ *) rm -f $@ && mv $@.tmp $@ && echo Updated $@;; \
+ esac
+
+# $@.tmp is created first to avoid an empty $(JVMOFFS).h if an error occurs.
$(JVMOFFS).h: $(GENOFFS)
- $(QUIETLY) LD_LIBRARY_PATH=. ./$(GENOFFS) -header > $@.tmp ; \
- if [ `diff $@.tmp $@ > /dev/null 2>&1; echo $$?` -ne 0 ] ; \
- then rm -f $@; mv $@.tmp $@; echo Updated $@ ; \
- else rm -f $@.tmp; \
- fi
+ $(QUIETLY) LD_LIBRARY_PATH=. ./$(GENOFFS) -header > $@.tmp
+ $(QUIETLY) $(CONDITIONALLY_UPDATE_JVMOFFS_TARGET)
$(JVMOFFS)Index.h: $(GENOFFS)
- $(QUIETLY) LD_LIBRARY_PATH=. ./$(GENOFFS) -index > $@.tmp ; \
- if [ `diff $@.tmp $@ > /dev/null 2>&1; echo $$?` -ne 0 ] ; \
- then rm -f $@; mv $@.tmp $@; echo Updated $@ ; \
- else rm -f $@.tmp; \
- fi
+ $(QUIETLY) LD_LIBRARY_PATH=. ./$(GENOFFS) -index > $@.tmp
+ $(QUIETLY) $(CONDITIONALLY_UPDATE_JVMOFFS_TARGET)
$(JVMOFFS).cpp: $(GENOFFS) $(JVMOFFS).h $(JVMOFFS)Index.h
- $(QUIETLY) LD_LIBRARY_PATH=. ./$(GENOFFS) -table > $@.tmp ; \
- if [ `diff $@.tmp $@ > /dev/null 2>&1; echo $$?` -ne 0 ] ; \
- then rm -f $@; mv $@.tmp $@; echo Updated $@ ; \
- else rm -f $@.tmp; \
- fi
+ $(QUIETLY) LD_LIBRARY_PATH=. ./$(GENOFFS) -table > $@.tmp
+ $(QUIETLY) $(CONDITIONALLY_UPDATE_JVMOFFS_TARGET)
$(JVMOFFS.o): $(JVMOFFS).h $(JVMOFFS).cpp
$(QUIETLY) $(CCC) -c -I. -o $@ $(ARCHFLAG) -D$(TYPE) $(JVMOFFS).cpp
diff --git a/hotspot/make/solaris/makefiles/fastdebug.make b/hotspot/make/solaris/makefiles/fastdebug.make
index 3ac2ae2..084814d 100644
--- a/hotspot/make/solaris/makefiles/fastdebug.make
+++ b/hotspot/make/solaris/makefiles/fastdebug.make
@@ -37,7 +37,7 @@
OPT_CFLAGS/SLOWER = -xO2
# Problem with SS12 compiler, dtrace doesn't like the .o files (bug 6693876)
-ifeq ($(COMPILER_REV), 5.9)
+ifeq ($(COMPILER_REV_NUMERIC), 509)
# To avoid jvm98 crash
OPT_CFLAGS/instanceKlass.o = $(OPT_CFLAGS/SLOWER)
# Not clear this workaround could be skipped in some cases.
@@ -46,47 +46,41 @@
OPT_CFLAGS/jni.o = $(OPT_CFLAGS/SLOWER)
endif
-ifeq ($(COMPILER_REV), 5.5)
+ifeq ($(COMPILER_REV_NUMERIC), 505)
# CC 5.5 has bug 4908364 with -xO4 (Fixed in 5.6)
OPT_CFLAGS/library_call.o = $(OPT_CFLAGS/SLOWER)
-endif # COMPILER_REV == 5.5
+endif # COMPILER_REV_NUMERIC == 505
-ifeq ($(shell expr $(COMPILER_REV) \<= 5.4), 1)
+ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \<= 504), 1)
# Compilation of *_<arch>.cpp can take an hour or more at O3. Use O2
# See comments at top of sparc.make.
-OPT_CFLAGS/ad_$(Platform_arch).o = $(OPT_CFLAGS/SLOWER)
-OPT_CFLAGS/dfa_$(Platform_arch).o = $(OPT_CFLAGS/SLOWER)
-endif # COMPILER_REV <= 5.4
+OPT_CFLAGS/ad_$(Platform_arch_model).o = $(OPT_CFLAGS/SLOWER)
+OPT_CFLAGS/dfa_$(Platform_arch_model).o = $(OPT_CFLAGS/SLOWER)
+endif # COMPILER_REV_NUMERIC <= 504
-ifeq (${COMPILER_REV}, 5.0)
-# Avoid a compiler bug caused by using -xO<level> -g<level>
-# Since the bug also occurs with -xO0, use an innocuous value (must not be null)
-OPT_CFLAGS/c1_LIROptimizer_i486.o = -c
-endif
-
-ifeq ($(shell expr $(COMPILER_REV) \< 5.5), 1)
-# Same problem with Solaris/x86 compiler (both 5.0 and 5.2) on ad_i486.cpp.
-# CC build time is also too long for ad_i486_{gen,misc}.o
-OPT_CFLAGS/ad_i486.o = -c
-OPT_CFLAGS/ad_i486_gen.o = -c
-OPT_CFLAGS/ad_i486_misc.o = -c
-ifeq ($(Platform_arch), i486)
+ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \< 505), 1)
+# Same problem with Solaris/x86 compiler (both 5.0 and 5.2) on ad_x86_{32,64}.cpp.
+# CC build time is also too long for ad_$(Platform_arch_model)_{gen,misc}.o
+OPT_CFLAGS/ad_$(Platform_arch_model).o = -c
+OPT_CFLAGS/ad_$(Platform_arch_model)_gen.o = -c
+OPT_CFLAGS/ad_$(Platform_arch_model)_misc.o = -c
+ifeq ($(Platform_arch), x86)
# Same problem for the wrapper roosts: jni.o jvm.o
OPT_CFLAGS/jni.o = -c
OPT_CFLAGS/jvm.o = -c
# Same problem in parse2.o (probably the Big Switch over bytecodes)
OPT_CFLAGS/parse2.o = -c
-endif # Platform_arch == i486
+endif # Platform_arch == x86
endif
# Frame size > 100k if we allow inlining via -g0!
DEBUG_CFLAGS/bytecodeInterpreter.o = -g
DEBUG_CFLAGS/bytecodeInterpreterWithChecks.o = -g
-ifeq ($(Platform_arch), i486)
+ifeq ($(Platform_arch), x86)
# ube explodes on x86
OPT_CFLAGS/bytecodeInterpreter.o = -xO1
OPT_CFLAGS/bytecodeInterpreterWithChecks.o = -xO1
-endif # Platform_arch == i486
+endif # Platform_arch == x86
endif # Platform_compiler == sparcWorks
diff --git a/hotspot/make/solaris/makefiles/i486.make b/hotspot/make/solaris/makefiles/i486.make
index a8f92a3..320035f 100644
--- a/hotspot/make/solaris/makefiles/i486.make
+++ b/hotspot/make/solaris/makefiles/i486.make
@@ -35,17 +35,13 @@
ifeq ("${Platform_compiler}", "sparcWorks")
# _lwp_create_interpose must have a frame
-OPT_CFLAGS/os_solaris_i486.o = -xO1
-# force C++ interpreter to be full optimization
-OPT_CFLAGS/interpret.o = -fast -O4
+OPT_CFLAGS/os_solaris_x86.o = -xO1
else
ifeq ("${Platform_compiler}", "gcc")
# gcc
# _lwp_create_interpose must have a frame
-OPT_CFLAGS/os_solaris_i486.o = -fno-omit-frame-pointer
-# force C++ interpreter to be full optimization
-OPT_CFLAGS/interpret.o = -O3
+OPT_CFLAGS/os_solaris_x86.o = -fno-omit-frame-pointer
#
else
# error
@@ -57,7 +53,7 @@
ifeq ("${Platform_compiler}", "sparcWorks")
# ILD is gone as of SS11 (5.8), not supported in SS10 (5.7)
-ifeq ($(shell expr $(COMPILER_REV) \< 5.7), 1)
+ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \< 507), 1)
#
# Bug in ild causes it to fail randomly. Until we get a fix we can't
# use ild.
diff --git a/hotspot/make/solaris/makefiles/jvmg.make b/hotspot/make/solaris/makefiles/jvmg.make
index ada307a..e660300 100644
--- a/hotspot/make/solaris/makefiles/jvmg.make
+++ b/hotspot/make/solaris/makefiles/jvmg.make
@@ -30,7 +30,7 @@
ifeq ("${Platform_compiler}", "sparcWorks")
-ifeq ($(COMPILER_REV),5.8)
+ifeq ($(COMPILER_REV_NUMERIC),508)
# SS11 SEGV when compiling with -g and -xarch=v8, using different backend
DEBUG_CFLAGS/compileBroker.o = $(DEBUG_CFLAGS) -xO0
DEBUG_CFLAGS/jvmtiTagMap.o = $(DEBUG_CFLAGS) -xO0
diff --git a/hotspot/make/solaris/makefiles/optimized.make b/hotspot/make/solaris/makefiles/optimized.make
index 1f91c31..69848b7 100644
--- a/hotspot/make/solaris/makefiles/optimized.make
+++ b/hotspot/make/solaris/makefiles/optimized.make
@@ -33,7 +33,7 @@
ifeq ("${Platform_compiler}", "sparcWorks")
# Problem with SS12 compiler, dtrace doesn't like the .o files (bug 6693876)
-ifeq ($(COMPILER_REV),5.9)
+ifeq ($(COMPILER_REV_NUMERIC),509)
# Not clear this workaround could be skipped in some cases.
OPT_CFLAGS/vmGCOperations.o = $(OPT_CFLAGS/SLOWER) -g
OPT_CFLAGS/java.o = $(OPT_CFLAGS/SLOWER) -g
@@ -41,9 +41,9 @@
endif
# Workaround SS11 bug 6345274 (all platforms) (Fixed in SS11 patch and SS12)
-ifeq ($(COMPILER_REV),5.8))
+ifeq ($(COMPILER_REV_NUMERIC),508))
OPT_CFLAGS/ciTypeFlow.o = $(OPT_CFLAGS/O2)
-endif # COMPILER_REV == 5.8
+endif # COMPILER_REV_NUMERIC == 508
endif # Platform_compiler == sparcWorks
diff --git a/hotspot/make/solaris/makefiles/product.make b/hotspot/make/solaris/makefiles/product.make
index 66e5353..10c6b45 100644
--- a/hotspot/make/solaris/makefiles/product.make
+++ b/hotspot/make/solaris/makefiles/product.make
@@ -41,7 +41,7 @@
ifeq ("${Platform_compiler}", "sparcWorks")
# Problem with SS12 compiler, dtrace doesn't like the .o files (bug 6693876)
-ifeq ($(COMPILER_REV),5.9)
+ifeq ($(COMPILER_REV_NUMERIC),509)
# Not clear this workaround could be skipped in some cases.
OPT_CFLAGS/vmGCOperations.o = $(OPT_CFLAGS/SLOWER) -g
OPT_CFLAGS/java.o = $(OPT_CFLAGS/SLOWER) -g
@@ -49,9 +49,9 @@
endif
# Workaround SS11 bug 6345274 (all platforms) (Fixed in SS11 patch and SS12)
-ifeq ($(COMPILER_REV),5.8)
+ifeq ($(COMPILER_REV_NUMERIC),508)
OPT_CFLAGS/ciTypeFlow.o = $(OPT_CFLAGS/O2)
-endif # COMPILER_REV == 5.8
+endif # COMPILER_REV_NUMERIC == 508
endif # Platform_compiler == sparcWorks
diff --git a/hotspot/make/solaris/makefiles/sparc.make b/hotspot/make/solaris/makefiles/sparc.make
index 6f332cf..e089494 100644
--- a/hotspot/make/solaris/makefiles/sparc.make
+++ b/hotspot/make/solaris/makefiles/sparc.make
@@ -26,7 +26,7 @@
ASFLAGS += $(AS_ARCHFLAG)
ifeq ("${Platform_compiler}", "sparcWorks")
-ifeq ($(shell expr $(COMPILER_REV) \< 5.5), 1)
+ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \< 505), 1)
# For 5.2 ad_sparc file is compiled with -O2 %%%% remove when adlc is fixed
OPT_CFLAGS/ad_sparc.o = $(OPT_CFLAGS/SLOWER)
OPT_CFLAGS/dfa_sparc.o = $(OPT_CFLAGS/SLOWER)
@@ -39,7 +39,7 @@
OPT_CFLAGS/jniHandles.o = $(OPT_CFLAGS/O2)
# CC brings an US-II to its knees compiling the vmStructs asserts under -xO4
OPT_CFLAGS/vmStructs.o = $(OPT_CFLAGS/O2)
-endif
+endif # COMPILER_REV_NUMERIC < 505
else
# Options for gcc
OPT_CFLAGS/ad_sparc.o = $(OPT_CFLAGS/SLOWER)
diff --git a/hotspot/make/solaris/makefiles/sparcWorks.make b/hotspot/make/solaris/makefiles/sparcWorks.make
index 5bbe70f..501268e 100644
--- a/hotspot/make/solaris/makefiles/sparcWorks.make
+++ b/hotspot/make/solaris/makefiles/sparcWorks.make
@@ -41,9 +41,9 @@
# Get the last thing on the line that looks like x.x+ (x is a digit).
COMPILER_REV := \
-$(shell $(CPP) -V 2>&1 | sed -e 's/^.*\([1-9]\.[0-9][0-9]*\).*/\1/')
+$(shell $(CPP) -V 2>&1 | sed -n 's/^.*[ ,\t]C++[ ,\t]\([1-9]\.[0-9][0-9]*\).*/\1/p')
C_COMPILER_REV := \
-$(shell $(CC) -V 2>&1 | grep -i "cc:" | sed -e 's/^.*\([1-9]\.[0-9][0-9]*\).*/\1/')
+$(shell $(CC) -V 2>&1 | sed -n 's/^.*[ ,\t]C[ ,\t]\([1-9]\.[0-9][0-9]*\).*/\1/p')
# Pick which compiler is validated
ifeq ($(JDK_MINOR_VERSION),6)
@@ -60,17 +60,19 @@
ENFORCE_COMPILER_REV${ENFORCE_COMPILER_REV} := ${VALIDATED_COMPILER_REV}
ifneq (${COMPILER_REV},${ENFORCE_COMPILER_REV})
dummy_target_to_enforce_compiler_rev:=\
-$(info WARNING: You are using CC version ${COMPILER_REV} \
-and should be using version ${ENFORCE_COMPILER_REV})
+$(shell echo >&2 WARNING: You are using CC version ${COMPILER_REV} \
+and should be using version ${ENFORCE_COMPILER_REV}. Set ENFORCE_COMPILER_REV=${COMPILER_REV} to avoid this warning.)
endif
ENFORCE_C_COMPILER_REV${ENFORCE_C_COMPILER_REV} := ${VALIDATED_C_COMPILER_REV}
ifneq (${C_COMPILER_REV},${ENFORCE_C_COMPILER_REV})
dummy_target_to_enforce_c_compiler_rev:=\
-$(info WARNING: You are using cc version ${C_COMPILER_REV} \
-and should be using version ${ENFORCE_C_COMPILER_REV})
+$(shell echo >&2 WARNING: You are using cc version ${C_COMPILER_REV} \
+and should be using version ${ENFORCE_C_COMPILER_REV}. Set ENFORCE_C_COMPILER_REV=${C_COMPILER_REV} to avoid this warning.)
endif
+COMPILER_REV_NUMERIC := $(shell echo $(COMPILER_REV) | awk -F. '{ print $$1 * 100 + $$2 }')
+
# Fail the build if __fabsf is used. __fabsf exists only in Solaris 8 2/04
# and newer; objects with a dependency on this symbol will not run on older
# Solaris 8.
@@ -120,7 +122,7 @@
ARCHFLAG_NEW/amd64 = -m64
# Select the ARCHFLAGs and other SS12 (5.9) options
-ifeq ($(shell expr $(COMPILER_REV) \>= 5.9), 1)
+ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 509), 1)
ARCHFLAG/sparc = $(ARCHFLAG_NEW/sparc)
ARCHFLAG/sparcv9 = $(ARCHFLAG_NEW/sparcv9)
ARCHFLAG/i486 = $(ARCHFLAG_NEW/i486)
@@ -150,7 +152,7 @@
# Begin current (>=5.6) Forte compiler options #
#################################################
-ifeq ($(shell expr $(COMPILER_REV) \>= 5.6), 1)
+ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 506), 1)
ifeq ("${Platform_arch}", "sparc")
@@ -167,7 +169,7 @@
# Begin current (>=5.5) Forte compiler options #
#################################################
-ifeq ($(shell expr $(COMPILER_REV) \>= 5.5), 1)
+ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 505), 1)
CFLAGS += $(ARCHFLAG)
AOUT_FLAGS += $(ARCHFLAG)
@@ -255,7 +257,7 @@
LFLAGS += -mt
-endif # COMPILER_REV >= 5.5
+endif # COMPILER_REV_NUMERIC >= 505
######################################
# End 5.5 Forte compiler options #
@@ -265,7 +267,7 @@
# Begin 5.2 Forte compiler options #
######################################
-ifeq ($(COMPILER_REV), 5.2)
+ifeq ($(COMPILER_REV_NUMERIC), 502)
CFLAGS += $(ARCHFLAG)
AOUT_FLAGS += $(ARCHFLAG)
@@ -324,7 +326,7 @@
LFLAGS += -library=Crun
LIBS += -library=Crun -lCrun
-endif # COMPILER_REV == 5.2
+endif # COMPILER_REV_NUMERIC == 502
##################################
# End 5.2 Forte compiler options #
@@ -333,7 +335,7 @@
##################################
# Begin old 5.1 compiler options #
##################################
-ifeq ($(COMPILER_REV), 5.1)
+ifeq ($(COMPILER_REV_NUMERIC), 501)
_JUNK_ := $(shell echo >&2 \
"*** ERROR: sparkWorks.make incomplete for 5.1 compiler")
@@ -347,7 +349,7 @@
# Begin old 5.0 compiler options #
##################################
-ifeq (${COMPILER_REV}, 5.0)
+ifeq (${COMPILER_REV_NUMERIC}, 500)
# Had to hoist this higher apparently because of other changes. Must
# come before -xarch specification.
@@ -379,7 +381,7 @@
ifeq ("${Platform_arch_model}", "x86_32")
OPT_CFLAGS=-xtarget=pentium $(EXTRA_OPT_CFLAGS)
-ifeq ("${COMPILER_REV}", "5.0")
+ifeq ("${COMPILER_REV_NUMERIC}", "500")
# SC5.0 tools on x86 are flakey at -xO4
OPT_CFLAGS+=-xO3
else
@@ -405,13 +407,13 @@
PICFLAG/BETTER = $(PICFLAG/DEFAULT)
PICFLAG/BYFILE = $(PICFLAG/$@)$(PICFLAG/DEFAULT$(PICFLAG/$@))
-endif # COMPILER_REV = 5.0
+endif # COMPILER_REV_NUMERIC = 500
################################
# End old 5.0 compiler options #
################################
-ifeq ("${COMPILER_REV}", "4.2")
+ifeq ("${COMPILER_REV_NUMERIC}", "402")
# 4.2 COMPILERS SHOULD NO LONGER BE USED
_JUNK_ := $(shell echo >&2 \
"*** ERROR: SC4.2 compilers are not supported by this code base!")
@@ -443,7 +445,7 @@
LINK_MODE/optimized = -Bsymbolic -znodefs
# Have thread local errnos
-ifeq ($(shell expr $(COMPILER_REV) \>= 5.5), 1)
+ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 505), 1)
CFLAGS += -mt
else
CFLAGS += -D_REENTRANT
@@ -460,7 +462,7 @@
# The -g0 setting allows the C++ frontend to inline, which is a big win.
# Special global options for SS12
-ifeq ($(COMPILER_REV),5.9)
+ifeq ($(COMPILER_REV_NUMERIC),509)
# There appears to be multiple issues with the new Dwarf2 debug format, so
# we tell the compiler to use the older 'stabs' debug format all the time.
# Note that this needs to be used in optimized compiles too to be 100%.
@@ -479,8 +481,8 @@
#DEBUG_CFLAGS += -Qoption ccfe -xglobalstatic
#FASTDEBUG_CFLAGS += -Qoption ccfe -xglobalstatic
-ifeq (${COMPILER_REV}, 5.2)
-COMPILER_DATE := $(shell $(CPP) -V 2>&1 | awk '{ print $$NF; }')
+ifeq (${COMPILER_REV_NUMERIC}, 502)
+COMPILER_DATE := $(shell $(CPP) -V 2>&1 | sed -n '/^.*[ ]C++[ ]\([1-9]\.[0-9][0-9]*\)/p' | awk '{ print $$NF; }')
ifeq (${COMPILER_DATE}, 2001/01/31)
# disable -g0 in fastdebug since SC6.1 dated 2001/01/31 seems to be buggy
# use an innocuous value because it will get -g if it's empty
@@ -493,7 +495,7 @@
CFLAGS += $(CFLAGS_BROWSE)
# ILD is gone as of SS11 (5.8), not supportted in SS10 (5.7)
-ifeq ($(shell expr $(COMPILER_REV) \< 5.7), 1)
+ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \< 507), 1)
# use ild when debugging (but when optimizing we want reproducible results)
ILDFLAG = $(ILDFLAG/$(VERSION))
ILDFLAG/debug = -xildon
diff --git a/hotspot/make/solaris/makefiles/sparcv9.make b/hotspot/make/solaris/makefiles/sparcv9.make
index c05d04b..9ee08dd 100644
--- a/hotspot/make/solaris/makefiles/sparcv9.make
+++ b/hotspot/make/solaris/makefiles/sparcv9.make
@@ -26,7 +26,7 @@
ASFLAGS += $(AS_ARCHFLAG)
ifeq ("${Platform_compiler}", "sparcWorks")
-ifeq ($(shell expr $(COMPILER_REV) \< 5.5), 1)
+ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \< 505), 1)
# When optimized fully, stubGenerator_sparc.cpp
# has bogus code for the routine
# StubGenerator::generate_flush_callers_register_windows()
diff --git a/hotspot/make/solaris/makefiles/top.make b/hotspot/make/solaris/makefiles/top.make
index 4b235d4..6affc87 100644
--- a/hotspot/make/solaris/makefiles/top.make
+++ b/hotspot/make/solaris/makefiles/top.make
@@ -83,9 +83,9 @@
AD_Dir = $(GENERATED)/adfiles
ADLC = $(AD_Dir)/adlc
-AD_Spec = $(GAMMADIR)/src/cpu/$(Platform_arch)/vm/$(Platform_arch).ad
+AD_Spec = $(GAMMADIR)/src/cpu/$(Platform_arch)/vm/$(Platform_arch_model).ad
AD_Src = $(GAMMADIR)/src/share/vm/adlc
-AD_Names = ad_$(Platform_arch).hpp ad_$(Platform_arch).cpp
+AD_Names = ad_$(Platform_arch_model).hpp ad_$(Platform_arch_model).cpp
AD_Files = $(AD_Names:%=$(AD_Dir)/%)
# AD_Files_If_Required/COMPILER1 = ad_stuff
diff --git a/hotspot/make/solaris/makefiles/vm.make b/hotspot/make/solaris/makefiles/vm.make
index 70a1197..32850b1 100644
--- a/hotspot/make/solaris/makefiles/vm.make
+++ b/hotspot/make/solaris/makefiles/vm.make
@@ -101,7 +101,7 @@
ifeq ("${Platform_compiler}", "sparcWorks")
# The whole megilla:
-ifeq ($(shell expr $(COMPILER_REV) \>= 5.5), 1)
+ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 505), 1)
# Old Comment: List the libraries in the order the compiler was designed for
# Not sure what the 'designed for' comment is referring too above.
# The order may not be too significant anymore, but I have placed this
diff --git a/hotspot/make/windows/makefiles/adlc.make b/hotspot/make/windows/makefiles/adlc.make
index b2f8132..b6feb0e 100644
--- a/hotspot/make/windows/makefiles/adlc.make
+++ b/hotspot/make/windows/makefiles/adlc.make
@@ -102,6 +102,12 @@
adlc.exe: main.obj adlparse.obj archDesc.obj arena.obj dfa.obj dict2.obj filebuff.obj \
forms.obj formsopt.obj formssel.obj opcodes.obj output_c.obj output_h.obj
$(LINK) $(LINK_FLAGS) /subsystem:console /out:$@ $**
+!if "$(MT)" != ""
+# The previous link command created a .manifest file that we want to
+# insert into the linked artifact so we do not need to track it
+# separately. Use ";#2" for .dll and ";#1" for .exe:
+ $(MT) /manifest $@.manifest /outputresource:$@;#1
+!endif
$(GENERATED_NAMES_IN_INCL): $(Platform_arch_model).ad adlc.exe includeDB.current
rm -f $(GENERATED_NAMES)
diff --git a/hotspot/make/windows/makefiles/compile.make b/hotspot/make/windows/makefiles/compile.make
index bf6f3be..ddc9ea1 100644
--- a/hotspot/make/windows/makefiles/compile.make
+++ b/hotspot/make/windows/makefiles/compile.make
@@ -30,7 +30,7 @@
# /W3 Warning level 3
# /Zi Include debugging information
# /WX Treat any warning error as a fatal error
-# /MD Use dynamic multi-threaded runtime (msvcrt.dll or msvc*71.dll)
+# /MD Use dynamic multi-threaded runtime (msvcrt.dll or msvc*NN.dll)
# /MTd Use static multi-threaded runtime debug versions
# /O1 Optimize for size (/Os), skips /Oi
# /O2 Optimize for speed (/Ot), adds /Oi to /O1
@@ -80,8 +80,10 @@
CPP=ARCH_ERROR
!endif
-# MSC_VER is a 4 digit number that tells us what compiler is being used, it is
-# generated when the local.make file is created by the script gen_msc_ver.sh.
+# MSC_VER is a 4 digit number that tells us what compiler is being used
+# and is generated when the local.make file is created by build.make
+# via the script get_msc_ver.sh
+#
# If MSC_VER is set, it overrides the above default setting.
# But it should be set.
# Possible values:
@@ -89,13 +91,14 @@
# 1300 and 1310 is VS2003 or VC7
# 1399 is our fake number for the VS2005 compiler that really isn't 1400
# 1400 is for VS2005
+# 1500 is for VS2008
# Do not confuse this MSC_VER with the predefined macro _MSC_VER that the
# compiler provides, when MSC_VER==1399, _MSC_VER will be 1400.
# Normally they are the same, but a pre-release of the VS2005 compilers
# in the Windows 64bit Platform SDK said it was 1400 when it was really
# closer to VS2003 in terms of option spellings, so we use 1399 for that
# 1400 version that really isn't 1400.
-# See the file gen_msc_ver.sh for more info.
+# See the file get_msc_ver.sh for more info.
!if "x$(MSC_VER)" == "x"
COMPILER_NAME=$(DEFAULT_COMPILER_NAME)
!else
@@ -115,6 +118,9 @@
!if "$(MSC_VER)" == "1400"
COMPILER_NAME=VS2005
!endif
+!if "$(MSC_VER)" == "1500"
+COMPILER_NAME=VS2008
+!endif
!endif
# Add what version of the compiler we think this is to the compile line
@@ -160,7 +166,25 @@
# externals at link time. Even with /GS-, you need bufferoverflowU.lib.
# NOTE: Currently we decided to not use /GS-
BUFFEROVERFLOWLIB = bufferoverflowU.lib
-LINK_FLAGS = $(LINK_FLAGS) $(BUFFEROVERFLOWLIB)
+LINK_FLAGS = /manifest $(LINK_FLAGS) $(BUFFEROVERFLOWLIB)
+# Manifest Tool - used in VS2005 and later to adjust manifests stored
+# as resources inside build artifacts.
+MT=mt.exe
+!if "$(BUILDARCH)" == "i486"
+# VS2005 on x86 restricts the use of certain libc functions without this
+CPP_FLAGS=$(CPP_FLAGS) /D _CRT_SECURE_NO_DEPRECATE
+!endif
+!endif
+
+!if "$(COMPILER_NAME)" == "VS2008"
+PRODUCT_OPT_OPTION = /O2 /Oy-
+FASTDEBUG_OPT_OPTION = /O2 /Oy-
+DEBUG_OPT_OPTION = /Od
+GX_OPTION = /EHsc
+LINK_FLAGS = /manifest $(LINK_FLAGS)
+# Manifest Tool - used in VS2005 and later to adjust manifests stored
+# as resources inside build artifacts.
+MT=mt.exe
!if "$(BUILDARCH)" == "i486"
# VS2005 on x86 restricts the use of certain libc functions without this
CPP_FLAGS=$(CPP_FLAGS) /D _CRT_SECURE_NO_DEPRECATE
diff --git a/hotspot/make/windows/makefiles/debug.make b/hotspot/make/windows/makefiles/debug.make
index afd987d..9bb52cc 100644
--- a/hotspot/make/windows/makefiles/debug.make
+++ b/hotspot/make/windows/makefiles/debug.make
@@ -50,6 +50,12 @@
$(LINK) @<<
$(LINK_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files)
<<
+!if "$(MT)" != ""
+# The previous link command created a .manifest file that we want to
+# insert into the linked artifact so we do not need to track it
+# separately. Use ";#2" for .dll and ";#1" for .exe:
+ $(MT) /manifest $@.manifest /outputresource:$@;#2
+!endif
!include $(WorkSpace)/make/windows/makefiles/shared.make
!include $(WorkSpace)/make/windows/makefiles/sa.make
diff --git a/hotspot/make/windows/makefiles/defs.make b/hotspot/make/windows/makefiles/defs.make
index 4b2fc14..c264f9f 100644
--- a/hotspot/make/windows/makefiles/defs.make
+++ b/hotspot/make/windows/makefiles/defs.make
@@ -25,7 +25,7 @@
# The common definitions for hotspot windows builds.
# Include the top level defs.make under make directory instead of this one.
# This file is included into make/defs.make.
-# On windows it is only used to construct parameters for
+# On windows it is only used to construct parameters for
# make/windows/build.make when make/Makefile is used to build VM.
SLASH_JAVA ?= J:
@@ -69,7 +69,7 @@
JDK_INCLUDE_SUBDIR=win32
-# HOTSPOT_RELEASE_VERSION and HOTSPOT_BUILD_VERSION are defined
+# HOTSPOT_RELEASE_VERSION and HOTSPOT_BUILD_VERSION are defined
# and added to MAKE_ARGS list in $(GAMMADIR)/make/defs.make.
# next parameters are defined in $(GAMMADIR)/make/defs.make.
@@ -125,7 +125,7 @@
endif
ifeq ($(BUILD_WIN_SA), 1)
- ifeq ($(ARCH),ia64)
+ ifeq ($(ARCH),ia64)
BUILD_WIN_SA = 0
endif
endif
@@ -154,7 +154,7 @@
EXPORT_LIST += $(EXPORT_JRE_BIN_DIR)/sawindbg.dll
EXPORT_LIST += $(EXPORT_JRE_BIN_DIR)/sawindbg.pdb
EXPORT_LIST += $(EXPORT_JRE_BIN_DIR)/sawindbg.map
- EXPORT_LIST += $(EXPORT_LIB_DIR)/sa-jdi.jar
+ EXPORT_LIST += $(EXPORT_LIB_DIR)/sa-jdi.jar
# Must pass this down to nmake.
MAKE_ARGS += BUILD_WIN_SA=1
endif
diff --git a/hotspot/make/windows/makefiles/fastdebug.make b/hotspot/make/windows/makefiles/fastdebug.make
index 064592b..e15aaaa 100644
--- a/hotspot/make/windows/makefiles/fastdebug.make
+++ b/hotspot/make/windows/makefiles/fastdebug.make
@@ -50,6 +50,13 @@
$(LINK) @<<
$(LINK_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files)
<<
+!if "$(MT)" != ""
+# The previous link command created a .manifest file that we want to
+# insert into the linked artifact so we do not need to track it
+# separately. Use ";#2" for .dll and ";#1" for .exe:
+ $(MT) /manifest $@.manifest /outputresource:$@;#2
+!endif
+
!include $(WorkSpace)/make/windows/makefiles/shared.make
!include $(WorkSpace)/make/windows/makefiles/sa.make
diff --git a/hotspot/make/windows/makefiles/product.make b/hotspot/make/windows/makefiles/product.make
index a143d6c..a26ffbc 100644
--- a/hotspot/make/windows/makefiles/product.make
+++ b/hotspot/make/windows/makefiles/product.make
@@ -61,6 +61,12 @@
$(LINK_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files)
<<
!endif
+!if "$(MT)" != ""
+# The previous link command created a .manifest file that we want to
+# insert into the linked artifact so we do not need to track it
+# separately. Use ";#2" for .dll and ";#1" for .exe:
+ $(MT) /manifest $@.manifest /outputresource:$@;#2
+!endif
!include $(WorkSpace)/make/windows/makefiles/shared.make
!include $(WorkSpace)/make/windows/makefiles/sa.make
diff --git a/hotspot/make/windows/makefiles/sa.make b/hotspot/make/windows/makefiles/sa.make
index 57fd493..01886c1 100644
--- a/hotspot/make/windows/makefiles/sa.make
+++ b/hotspot/make/windows/makefiles/sa.make
@@ -92,13 +92,18 @@
!else
SA_CFLAGS = /nologo $(MS_RUNTIME_OPTION) /W3 /Gm $(GX_OPTION) /ZI /Od /D "WIN32" /D "_WINDOWS" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
!endif
-
+!if "$(MT)" != ""
+ SA_LINK_FLAGS = /manifest $(SA_LINK_FLAGS)
+!endif
SASRCFILE = $(AGENT_DIR)/src/os/win32/windbg/sawindbg.cpp
SA_LFLAGS = $(SA_LINK_FLAGS) /nologo /subsystem:console /map /debug /machine:$(MACHINE)
# Note that we do not keep sawindbj.obj around as it would then
# get included in the dumpbin command in build_vm_def.sh
+# In VS2005 or VS2008 the link command creates a .manifest file that we want
+# to insert into the linked artifact so we do not need to track it separately.
+# Use ";#2" for .dll and ";#1" for .exe in the MT command below:
$(SAWINDBG): $(SASRCFILE)
set INCLUDE=$(SA_INCLUDE)$(INCLUDE)
$(CPP) @<<
@@ -109,6 +114,9 @@
<<
set LIB=$(SA_LIB)$(LIB)
$(LINK) /out:$@ /DLL sawindbg.obj dbgeng.lib $(SA_LFLAGS)
+!if "$(MT)" != ""
+ $(MT) /manifest $(@F).manifest /outputresource:$(@F);#2
+!endif
-@rm -f sawindbg.obj
cleanall :
diff --git a/hotspot/make/windows/projectfiles/common/Makefile b/hotspot/make/windows/projectfiles/common/Makefile
index c6793f9..ebc3cd9 100644
--- a/hotspot/make/windows/projectfiles/common/Makefile
+++ b/hotspot/make/windows/projectfiles/common/Makefile
@@ -56,7 +56,8 @@
$(HOTSPOTWORKSPACE)/src/share/vm/gc_implementation/includeDB_gc_shared \
$(HOTSPOTWORKSPACE)/src/share/vm/gc_implementation/includeDB_gc_parNew \
$(HOTSPOTWORKSPACE)/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge \
- $(HOTSPOTWORKSPACE)/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep
+ $(HOTSPOTWORKSPACE)/src/share/vm/gc_implementation/includeDB_gc_concurrentMarkSweep \
+ $(HOTSPOTWORKSPACE)/src/share/vm/gc_implementation/includeDB_gc_g1
IncludeDBs_kernel =$(IncludeDBs_base) \
diff --git a/hotspot/src/cpu/x86/vm/register_definitions_x86.cpp b/hotspot/src/cpu/x86/vm/register_definitions_x86.cpp
index 1be2c13..0aceac8 100644
--- a/hotspot/src/cpu/x86/vm/register_definitions_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/register_definitions_x86.cpp
@@ -22,9 +22,6 @@
*
*/
-// make sure the defines don't screw up the declarations later on in this file
-#define DONT_USE_REGISTER_DEFINES
-
#include "incls/_precompiled.incl"
#include "incls/_register_definitions_x86.cpp.incl"
diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp
index c4386d8..0594086 100644
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp
@@ -3756,7 +3756,6 @@
int maxClamped = MIN2(iaLimits.maxPrio, (int)iaInfo->ia_uprilim);
iaInfo->ia_upri = scale_to_lwp_priority(iaLimits.minPrio, maxClamped, newPrio);
iaInfo->ia_uprilim = IA_NOCHANGE;
- iaInfo->ia_nice = IA_NOCHANGE;
iaInfo->ia_mode = IA_NOCHANGE;
if (ThreadPriorityVerbose) {
tty->print_cr ("IA: [%d...%d] %d->%d\n",
diff --git a/hotspot/src/share/vm/adlc/archDesc.cpp b/hotspot/src/share/vm/adlc/archDesc.cpp
index 0aa1506..9702fb4 100644
--- a/hotspot/src/share/vm/adlc/archDesc.cpp
+++ b/hotspot/src/share/vm/adlc/archDesc.cpp
@@ -212,9 +212,9 @@
// Initialize I/O Files
_ADL_file._name = NULL; _ADL_file._fp = NULL;
// Machine dependent output files
- _DFA_file._name = "dfa_i486.cpp"; _DFA_file._fp = NULL;
- _HPP_file._name = "ad_i486.hpp"; _HPP_file._fp = NULL;
- _CPP_file._name = "ad_i486.cpp"; _CPP_file._fp = NULL;
+ _DFA_file._name = NULL; _DFA_file._fp = NULL;
+ _HPP_file._name = NULL; _HPP_file._fp = NULL;
+ _CPP_file._name = NULL; _CPP_file._fp = NULL;
_bug_file._name = "bugs.out"; _bug_file._fp = NULL;
// Initialize Register & Pipeline Form Pointers
diff --git a/hotspot/src/share/vm/c1/c1_IR.cpp b/hotspot/src/share/vm/c1/c1_IR.cpp
index 005114b..ccb6abf 100644
--- a/hotspot/src/share/vm/c1/c1_IR.cpp
+++ b/hotspot/src/share/vm/c1/c1_IR.cpp
@@ -574,12 +574,23 @@
TRACE_LINEAR_SCAN(3, tty->print_cr("backward branch"));
assert(is_visited(cur), "block must be visisted when block is active");
assert(parent != NULL, "must have parent");
- assert(parent->number_of_sux() == 1, "loop end blocks must have one successor (critical edges are split)");
cur->set(BlockBegin::linear_scan_loop_header_flag);
cur->set(BlockBegin::backward_branch_target_flag);
parent->set(BlockBegin::linear_scan_loop_end_flag);
+
+ // When a loop header is also the start of an exception handler, then the backward branch is
+ // an exception edge. Because such edges are usually critical edges which cannot be split, the
+ // loop must be excluded here from processing.
+ if (cur->is_set(BlockBegin::exception_entry_flag)) {
+ // Make sure that dominators are correct in this weird situation
+ _iterative_dominators = true;
+ return;
+ }
+ assert(parent->number_of_sux() == 1 && parent->sux_at(0) == cur,
+ "loop end blocks must have one successor (critical edges are split)");
+
_loop_end_blocks.append(parent);
return;
}
diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp
index 1d27954..cb2be0f 100644
--- a/hotspot/src/share/vm/ci/ciEnv.cpp
+++ b/hotspot/src/share/vm/ci/ciEnv.cpp
@@ -484,11 +484,16 @@
} else if (tag.is_double()) {
return ciConstant((jdouble)cpool->double_at(index));
} else if (tag.is_string() || tag.is_unresolved_string()) {
- oop string = cpool->string_at(index, THREAD);
- if (HAS_PENDING_EXCEPTION) {
- CLEAR_PENDING_EXCEPTION;
- record_out_of_memory_failure();
- return ciConstant();
+ oop string = NULL;
+ if (cpool->is_pseudo_string_at(index)) {
+ string = cpool->pseudo_string_at(index);
+ } else {
+ string = cpool->string_at(index, THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ CLEAR_PENDING_EXCEPTION;
+ record_out_of_memory_failure();
+ return ciConstant();
+ }
}
ciObject* constant = get_object(string);
assert (constant->is_instance(), "must be an instance, or not? ");
diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp
index 7ee8ce9..45d0147 100644
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp
@@ -168,11 +168,23 @@
// Got utf8 string, guarantee utf8_length+1 bytes, set stream position forward.
cfs->guarantee_more(utf8_length+1, CHECK); // utf8 string, tag/access_flags
cfs->skip_u1_fast(utf8_length);
+
// Before storing the symbol, make sure it's legal
if (_need_verify) {
verify_legal_utf8((unsigned char*)utf8_buffer, utf8_length, CHECK);
}
+ if (AnonymousClasses && has_cp_patch_at(index)) {
+ Handle patch = clear_cp_patch_at(index);
+ guarantee_property(java_lang_String::is_instance(patch()),
+ "Illegal utf8 patch at %d in class file %s",
+ index, CHECK);
+ char* str = java_lang_String::as_utf8_string(patch());
+ // (could use java_lang_String::as_symbol instead, but might as well batch them)
+ utf8_buffer = (u1*) str;
+ utf8_length = (int) strlen(str);
+ }
+
unsigned int hash;
symbolOop result = SymbolTable::lookup_only((char*)utf8_buffer, utf8_length, hash);
if (result == NULL) {
@@ -245,7 +257,7 @@
int klass_ref_index = cp->klass_ref_index_at(index);
int name_and_type_ref_index = cp->name_and_type_ref_index_at(index);
check_property(valid_cp_range(klass_ref_index, length) &&
- cp->tag_at(klass_ref_index).is_klass_reference(),
+ is_klass_reference(cp, klass_ref_index),
"Invalid constant pool index %u in class file %s",
klass_ref_index,
CHECK_(nullHandle));
@@ -326,16 +338,46 @@
} // end of switch
} // end of for
+ if (_cp_patches != NULL) {
+ // need to treat this_class specially...
+ assert(AnonymousClasses, "");
+ int this_class_index;
+ {
+ cfs->guarantee_more(8, CHECK_(nullHandle)); // flags, this_class, super_class, infs_len
+ u1* mark = cfs->current();
+ u2 flags = cfs->get_u2_fast();
+ this_class_index = cfs->get_u2_fast();
+ cfs->set_current(mark); // revert to mark
+ }
+
+ for (index = 1; index < length; index++) { // Index 0 is unused
+ if (has_cp_patch_at(index)) {
+ guarantee_property(index != this_class_index,
+ "Illegal constant pool patch to self at %d in class file %s",
+ index, CHECK_(nullHandle));
+ patch_constant_pool(cp, index, cp_patch_at(index), CHECK_(nullHandle));
+ }
+ }
+ // Ensure that all the patches have been used.
+ for (index = 0; index < _cp_patches->length(); index++) {
+ guarantee_property(!has_cp_patch_at(index),
+ "Unused constant pool patch at %d in class file %s",
+ index, CHECK_(nullHandle));
+ }
+ }
+
if (!_need_verify) {
return cp;
}
// second verification pass - checks the strings are of the right format.
+ // but not yet to the other entries
for (index = 1; index < length; index++) {
jbyte tag = cp->tag_at(index).value();
switch (tag) {
case JVM_CONSTANT_UnresolvedClass: {
symbolHandle class_name(THREAD, cp->unresolved_klass_at(index));
+ // check the name, even if _cp_patches will overwrite it
verify_legal_class_name(class_name, CHECK_(nullHandle));
break;
}
@@ -378,6 +420,73 @@
}
+void ClassFileParser::patch_constant_pool(constantPoolHandle cp, int index, Handle patch, TRAPS) {
+ assert(AnonymousClasses, "");
+ BasicType patch_type = T_VOID;
+ switch (cp->tag_at(index).value()) {
+
+ case JVM_CONSTANT_UnresolvedClass :
+ // Patching a class means pre-resolving it.
+ // The name in the constant pool is ignored.
+ if (patch->klass() == SystemDictionary::class_klass()) { // %%% java_lang_Class::is_instance
+ guarantee_property(!java_lang_Class::is_primitive(patch()),
+ "Illegal class patch at %d in class file %s",
+ index, CHECK);
+ cp->klass_at_put(index, java_lang_Class::as_klassOop(patch()));
+ } else {
+ guarantee_property(java_lang_String::is_instance(patch()),
+ "Illegal class patch at %d in class file %s",
+ index, CHECK);
+ symbolHandle name = java_lang_String::as_symbol(patch(), CHECK);
+ cp->unresolved_klass_at_put(index, name());
+ }
+ break;
+
+ case JVM_CONSTANT_UnresolvedString :
+ // Patching a string means pre-resolving it.
+ // The spelling in the constant pool is ignored.
+ // The constant reference may be any object whatever.
+ // If it is not a real interned string, the constant is referred
+ // to as a "pseudo-string", and must be presented to the CP
+ // explicitly, because it may require scavenging.
+ cp->pseudo_string_at_put(index, patch());
+ break;
+
+ case JVM_CONSTANT_Integer : patch_type = T_INT; goto patch_prim;
+ case JVM_CONSTANT_Float : patch_type = T_FLOAT; goto patch_prim;
+ case JVM_CONSTANT_Long : patch_type = T_LONG; goto patch_prim;
+ case JVM_CONSTANT_Double : patch_type = T_DOUBLE; goto patch_prim;
+ patch_prim:
+ {
+ jvalue value;
+ BasicType value_type = java_lang_boxing_object::get_value(patch(), &value);
+ guarantee_property(value_type == patch_type,
+ "Illegal primitive patch at %d in class file %s",
+ index, CHECK);
+ switch (value_type) {
+ case T_INT: cp->int_at_put(index, value.i); break;
+ case T_FLOAT: cp->float_at_put(index, value.f); break;
+ case T_LONG: cp->long_at_put(index, value.j); break;
+ case T_DOUBLE: cp->double_at_put(index, value.d); break;
+ default: assert(false, "");
+ }
+ }
+ break;
+
+ default:
+ // %%% TODO: put method handles into CONSTANT_InterfaceMethodref, etc.
+ guarantee_property(!has_cp_patch_at(index),
+ "Illegal unexpected patch at %d in class file %s",
+ index, CHECK);
+ return;
+ }
+
+ // On fall-through, mark the patch as used.
+ clear_cp_patch_at(index);
+}
+
+
+
class NameSigHash: public ResourceObj {
public:
symbolOop _name; // name
@@ -448,25 +557,32 @@
int index;
for (index = 0; index < length; index++) {
u2 interface_index = cfs->get_u2(CHECK_(nullHandle));
+ KlassHandle interf;
check_property(
valid_cp_range(interface_index, cp->length()) &&
- cp->tag_at(interface_index).is_unresolved_klass(),
+ is_klass_reference(cp, interface_index),
"Interface name has bad constant pool index %u in class file %s",
interface_index, CHECK_(nullHandle));
- symbolHandle unresolved_klass (THREAD, cp->klass_name_at(interface_index));
+ if (cp->tag_at(interface_index).is_klass()) {
+ interf = KlassHandle(THREAD, cp->resolved_klass_at(interface_index));
+ } else {
+ symbolHandle unresolved_klass (THREAD, cp->klass_name_at(interface_index));
- // Don't need to check legal name because it's checked when parsing constant pool.
- // But need to make sure it's not an array type.
- guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY,
- "Bad interface name in class file %s", CHECK_(nullHandle));
+ // Don't need to check legal name because it's checked when parsing constant pool.
+ // But need to make sure it's not an array type.
+ guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY,
+ "Bad interface name in class file %s", CHECK_(nullHandle));
- vmtimer->suspend(); // do not count recursive loading twice
- // Call resolve_super so classcircularity is checked
- klassOop k = SystemDictionary::resolve_super_or_fail(class_name,
- unresolved_klass, class_loader, protection_domain,
- false, CHECK_(nullHandle));
- KlassHandle interf (THREAD, k);
- vmtimer->resume();
+ vmtimer->suspend(); // do not count recursive loading twice
+ // Call resolve_super so classcircularity is checked
+ klassOop k = SystemDictionary::resolve_super_or_fail(class_name,
+ unresolved_klass, class_loader, protection_domain,
+ false, CHECK_(nullHandle));
+ interf = KlassHandle(THREAD, k);
+ vmtimer->resume();
+
+ cp->klass_at_put(interface_index, interf()); // eagerly resolve
+ }
if (!Klass::cast(interf())->is_interface()) {
THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", nullHandle);
@@ -877,8 +993,7 @@
"Illegal exception table handler in class file %s", CHECK_(nullHandle));
if (catch_type_index != 0) {
guarantee_property(valid_cp_range(catch_type_index, cp->length()) &&
- (cp->tag_at(catch_type_index).is_klass() ||
- cp->tag_at(catch_type_index).is_unresolved_klass()),
+ is_klass_reference(cp, catch_type_index),
"Catch type in exception table has bad constant type in class file %s", CHECK_(nullHandle));
}
}
@@ -1117,7 +1232,7 @@
} else if (tag == ITEM_Object) {
u2 class_index = u2_array[i2++] = cfs->get_u2(CHECK);
guarantee_property(valid_cp_range(class_index, cp->length()) &&
- cp->tag_at(class_index).is_unresolved_klass(),
+ is_klass_reference(cp, class_index),
"Bad class index %u in StackMap in class file %s",
class_index, CHECK);
} else if (tag == ITEM_Uninitialized) {
@@ -1183,7 +1298,7 @@
checked_exception = cfs->get_u2_fast();
check_property(
valid_cp_range(checked_exception, cp->length()) &&
- cp->tag_at(checked_exception).is_klass_reference(),
+ is_klass_reference(cp, checked_exception),
"Exception name has bad type at constant pool %u in class file %s",
checked_exception, CHECK_NULL);
}
@@ -1918,7 +2033,7 @@
check_property(
inner_class_info_index == 0 ||
(valid_cp_range(inner_class_info_index, cp_size) &&
- cp->tag_at(inner_class_info_index).is_klass_reference()),
+ is_klass_reference(cp, inner_class_info_index)),
"inner_class_info_index %u has bad constant type in class file %s",
inner_class_info_index, CHECK_0);
// Outer class index
@@ -1926,7 +2041,7 @@
check_property(
outer_class_info_index == 0 ||
(valid_cp_range(outer_class_info_index, cp_size) &&
- cp->tag_at(outer_class_info_index).is_klass_reference()),
+ is_klass_reference(cp, outer_class_info_index)),
"outer_class_info_index %u has bad constant type in class file %s",
outer_class_info_index, CHECK_0);
// Inner class name
@@ -2088,7 +2203,7 @@
}
// Validate the constant pool indices and types
if (!cp->is_within_bounds(class_index) ||
- !cp->tag_at(class_index).is_klass_reference()) {
+ !is_klass_reference(cp, class_index)) {
classfile_parse_error("Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK);
}
if (method_index != 0 &&
@@ -2349,6 +2464,7 @@
instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
Handle class_loader,
Handle protection_domain,
+ GrowableArray<Handle>* cp_patches,
symbolHandle& parsed_name,
TRAPS) {
// So that JVMTI can cache class file in the state before retransformable agents
@@ -2380,6 +2496,7 @@
}
}
+ _cp_patches = cp_patches;
instanceKlassHandle nullHandle;
@@ -2510,14 +2627,22 @@
CHECK_(nullHandle));
} else {
check_property(valid_cp_range(super_class_index, cp_size) &&
- cp->tag_at(super_class_index).is_unresolved_klass(),
+ is_klass_reference(cp, super_class_index),
"Invalid superclass index %u in class file %s",
super_class_index,
CHECK_(nullHandle));
// The class name should be legal because it is checked when parsing constant pool.
// However, make sure it is not an array type.
+ bool is_array = false;
+ if (cp->tag_at(super_class_index).is_klass()) {
+ super_klass = instanceKlassHandle(THREAD, cp->resolved_klass_at(super_class_index));
+ if (_need_verify)
+ is_array = super_klass->oop_is_array();
+ } else if (_need_verify) {
+ is_array = (cp->unresolved_klass_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY);
+ }
if (_need_verify) {
- guarantee_property(cp->unresolved_klass_at(super_class_index)->byte_at(0) != JVM_SIGNATURE_ARRAY,
+ guarantee_property(!is_array,
"Bad superclass name in class file %s", CHECK_(nullHandle));
}
}
@@ -2557,7 +2682,7 @@
objArrayHandle methods_default_annotations(THREAD, methods_default_annotations_oop);
// We check super class after class file is parsed and format is checked
- if (super_class_index > 0) {
+ if (super_class_index > 0 && super_klass.is_null()) {
symbolHandle sk (THREAD, cp->klass_name_at(super_class_index));
if (access_flags.is_interface()) {
// Before attempting to resolve the superclass, check for class format
@@ -2574,6 +2699,9 @@
CHECK_(nullHandle));
KlassHandle kh (THREAD, k);
super_klass = instanceKlassHandle(THREAD, kh());
+ cp->klass_at_put(super_class_index, super_klass()); // eagerly resolve
+ }
+ if (super_klass.not_null()) {
if (super_klass->is_interface()) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
@@ -3000,6 +3128,7 @@
this_klass->set_method_ordering(method_ordering());
this_klass->set_initial_method_idnum(methods->length());
this_klass->set_name(cp->klass_name_at(this_class_index));
+ cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve
this_klass->set_protection_domain(protection_domain());
this_klass->set_fields_annotations(fields_annotations());
this_klass->set_methods_annotations(methods_annotations());
diff --git a/hotspot/src/share/vm/classfile/classFileParser.hpp b/hotspot/src/share/vm/classfile/classFileParser.hpp
index a29905f..4a58fca 100644
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp
@@ -33,6 +33,7 @@
u2 _major_version;
u2 _minor_version;
symbolHandle _class_name;
+ GrowableArray<Handle>* _cp_patches; // overrides for CP entries
bool _has_finalizer;
bool _has_empty_finalizer;
@@ -203,6 +204,35 @@
char* skip_over_field_name(char* name, bool slash_ok, unsigned int length);
char* skip_over_field_signature(char* signature, bool void_ok, unsigned int length, TRAPS);
+ bool has_cp_patch_at(int index) {
+ assert(AnonymousClasses, "");
+ assert(index >= 0, "oob");
+ return (_cp_patches != NULL
+ && index < _cp_patches->length()
+ && _cp_patches->adr_at(index)->not_null());
+ }
+ Handle cp_patch_at(int index) {
+ assert(has_cp_patch_at(index), "oob");
+ return _cp_patches->at(index);
+ }
+ Handle clear_cp_patch_at(int index) {
+ Handle patch = cp_patch_at(index);
+ _cp_patches->at_put(index, Handle());
+ assert(!has_cp_patch_at(index), "");
+ return patch;
+ }
+ void patch_constant_pool(constantPoolHandle cp, int index, Handle patch, TRAPS);
+
+ // Wrapper for constantTag.is_klass_[or_]reference.
+ // In older versions of the VM, klassOops cannot sneak into early phases of
+ // constant pool construction, but in later versions they can.
+ // %%% Let's phase out the old is_klass_reference.
+ bool is_klass_reference(constantPoolHandle cp, int index) {
+ return ((LinkWellKnownClasses || AnonymousClasses)
+ ? cp->tag_at(index).is_klass_or_reference()
+ : cp->tag_at(index).is_klass_reference());
+ }
+
public:
// Constructor
ClassFileParser(ClassFileStream* st) { set_stream(st); }
@@ -218,6 +248,14 @@
Handle class_loader,
Handle protection_domain,
symbolHandle& parsed_name,
+ TRAPS) {
+ return parseClassFile(name, class_loader, protection_domain, NULL, parsed_name, THREAD);
+ }
+ instanceKlassHandle parseClassFile(symbolHandle name,
+ Handle class_loader,
+ Handle protection_domain,
+ GrowableArray<Handle>* cp_patches,
+ symbolHandle& parsed_name,
TRAPS);
// Verifier checks
diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp
index 7727163..0908e1c 100644
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp
@@ -937,6 +937,8 @@
Handle class_loader,
Handle protection_domain,
ClassFileStream* st,
+ KlassHandle host_klass,
+ GrowableArray<Handle>* cp_patches,
TRAPS) {
symbolHandle parsed_name;
@@ -953,10 +955,10 @@
instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name,
class_loader,
protection_domain,
+ cp_patches,
parsed_name,
THREAD);
-
// We don't redefine the class, so we just need to clean up whether there
// was an error or not (don't want to modify any system dictionary
// data structures).
@@ -973,6 +975,30 @@
}
}
+ if (host_klass.not_null() && k.not_null()) {
+ assert(AnonymousClasses, "");
+ // If it's anonymous, initialize it now, since nobody else will.
+ k->set_host_klass(host_klass());
+
+ {
+ MutexLocker mu_r(Compile_lock, THREAD);
+
+ // Add to class hierarchy, initialize vtables, and do possible
+ // deoptimizations.
+ add_to_hierarchy(k, CHECK_NULL); // No exception, but can block
+
+ // But, do not add to system dictionary.
+ }
+
+ k->eager_initialize(THREAD);
+
+ // notify jvmti
+ if (JvmtiExport::should_post_class_load()) {
+ assert(THREAD->is_Java_thread(), "thread->is_Java_thread()");
+ JvmtiExport::post_class_load((JavaThread *) THREAD, k());
+ }
+ }
+
return k();
}
diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp
index 38d27d8..beade18 100644
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp
+++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp
@@ -228,6 +228,16 @@
Handle class_loader,
Handle protection_domain,
ClassFileStream* st,
+ TRAPS) {
+ KlassHandle nullHandle;
+ return parse_stream(class_name, class_loader, protection_domain, st, nullHandle, NULL, THREAD);
+ }
+ static klassOop parse_stream(symbolHandle class_name,
+ Handle class_loader,
+ Handle protection_domain,
+ ClassFileStream* st,
+ KlassHandle host_klass,
+ GrowableArray<Handle>* cp_patches,
TRAPS);
// Resolve from stream (called by jni_DefineClass and JVM_DefineClass)
diff --git a/hotspot/src/share/vm/classfile/verifier.cpp b/hotspot/src/share/vm/classfile/verifier.cpp
index 8373f9b..179de12 100644
--- a/hotspot/src/share/vm/classfile/verifier.cpp
+++ b/hotspot/src/share/vm/classfile/verifier.cpp
@@ -1600,7 +1600,11 @@
types = (1 << JVM_CONSTANT_Double) | (1 << JVM_CONSTANT_Long);
verify_cp_type(index, cp, types, CHECK_VERIFY(this));
}
- if (tag.is_string() || tag.is_unresolved_string()) {
+ if (tag.is_string() && cp->is_pseudo_string_at(index)) {
+ current_frame->push_stack(
+ VerificationType::reference_type(
+ vmSymbols::java_lang_Object()), CHECK_VERIFY(this));
+ } else if (tag.is_string() || tag.is_unresolved_string()) {
current_frame->push_stack(
VerificationType::reference_type(
vmSymbols::java_lang_String()), CHECK_VERIFY(this));
diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentGCThread.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentGCThread.cpp
deleted file mode 100644
index 8ed8b80..0000000
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentGCThread.cpp
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright 2001-2005 Sun Microsystems, Inc. All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * 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.
- *
- */
-
-// CopyrightVersion 1.2
-
-# include "incls/_precompiled.incl"
-# include "incls/_concurrentGCThread.cpp.incl"
-
-bool ConcurrentGCThread::_should_terminate = false;
-bool ConcurrentGCThread::_has_terminated = false;
-int ConcurrentGCThread::_CGC_flag = CGC_nil;
-
-SuspendibleThreadSet ConcurrentGCThread::_sts;
-
-ConcurrentGCThread::ConcurrentGCThread() {
- _sts.initialize();
-};
-
-void ConcurrentGCThread::stopWorldAndDo(VoidClosure* op) {
- MutexLockerEx x(Heap_lock,
- Mutex::_no_safepoint_check_flag);
- // warning("CGC: about to try stopping world");
- SafepointSynchronize::begin();
- // warning("CGC: successfully stopped world");
- op->do_void();
- SafepointSynchronize::end();
- // warning("CGC: successfully restarted world");
-}
-
-void ConcurrentGCThread::safepoint_synchronize() {
- _sts.suspend_all();
-}
-
-void ConcurrentGCThread::safepoint_desynchronize() {
- _sts.resume_all();
-}
-
-void ConcurrentGCThread::create_and_start() {
- if (os::create_thread(this, os::cgc_thread)) {
- // XXX: need to set this to low priority
- // unless "agressive mode" set; priority
- // should be just less than that of VMThread.
- os::set_priority(this, NearMaxPriority);
- if (!_should_terminate && !DisableStartThread) {
- os::start_thread(this);
- }
- }
-}
-
-void ConcurrentGCThread::initialize_in_thread() {
- this->record_stack_base_and_size();
- this->initialize_thread_local_storage();
- this->set_active_handles(JNIHandleBlock::allocate_block());
- // From this time Thread::current() should be working.
- assert(this == Thread::current(), "just checking");
-}
-
-void ConcurrentGCThread::wait_for_universe_init() {
- MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
- while (!is_init_completed() && !_should_terminate) {
- CGC_lock->wait(Mutex::_no_safepoint_check_flag, 200);
- }
-}
-
-void ConcurrentGCThread::terminate() {
- // Signal that it is terminated
- {
- MutexLockerEx mu(Terminator_lock,
- Mutex::_no_safepoint_check_flag);
- _has_terminated = true;
- Terminator_lock->notify();
- }
-
- // Thread destructor usually does this..
- ThreadLocalStorage::set_thread(NULL);
-}
-
-
-void SuspendibleThreadSet::initialize_work() {
- MutexLocker x(STS_init_lock);
- if (!_initialized) {
- _m = new Monitor(Mutex::leaf,
- "SuspendibleThreadSetLock", true);
- _async = 0;
- _async_stop = false;
- _async_stopped = 0;
- _initialized = true;
- }
-}
-
-void SuspendibleThreadSet::join() {
- initialize();
- MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
- while (_async_stop) _m->wait(Mutex::_no_safepoint_check_flag);
- _async++;
- assert(_async > 0, "Huh.");
-}
-
-void SuspendibleThreadSet::leave() {
- assert(_initialized, "Must be initialized.");
- MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
- _async--;
- assert(_async >= 0, "Huh.");
- if (_async_stop) _m->notify_all();
-}
-
-void SuspendibleThreadSet::yield(const char* id) {
- assert(_initialized, "Must be initialized.");
- if (_async_stop) {
- MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
- if (_async_stop) {
- _async_stopped++;
- assert(_async_stopped > 0, "Huh.");
- if (_async_stopped == _async) {
- if (ConcGCYieldTimeout > 0) {
- double now = os::elapsedTime();
- guarantee((now - _suspend_all_start) * 1000.0 <
- (double)ConcGCYieldTimeout,
- "Long delay; whodunit?");
- }
- }
- _m->notify_all();
- while (_async_stop) _m->wait(Mutex::_no_safepoint_check_flag);
- _async_stopped--;
- assert(_async >= 0, "Huh");
- _m->notify_all();
- }
- }
-}
-
-void SuspendibleThreadSet::suspend_all() {
- initialize(); // If necessary.
- if (ConcGCYieldTimeout > 0) {
- _suspend_all_start = os::elapsedTime();
- }
- MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
- assert(!_async_stop, "Only one at a time.");
- _async_stop = true;
- while (_async_stopped < _async) _m->wait(Mutex::_no_safepoint_check_flag);
-}
-
-void SuspendibleThreadSet::resume_all() {
- assert(_initialized, "Must be initialized.");
- MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
- assert(_async_stopped == _async, "Huh.");
- _async_stop = false;
- _m->notify_all();
-}
-
-static void _sltLoop(JavaThread* thread, TRAPS) {
- SurrogateLockerThread* slt = (SurrogateLockerThread*)thread;
- slt->loop();
-}
-
-SurrogateLockerThread::SurrogateLockerThread() :
- JavaThread(&_sltLoop),
- _monitor(Mutex::nonleaf, "SLTMonitor"),
- _buffer(empty)
-{}
-
-SurrogateLockerThread* SurrogateLockerThread::make(TRAPS) {
- klassOop k =
- SystemDictionary::resolve_or_fail(vmSymbolHandles::java_lang_Thread(),
- true, CHECK_NULL);
- instanceKlassHandle klass (THREAD, k);
- instanceHandle thread_oop = klass->allocate_instance_handle(CHECK_NULL);
-
- const char thread_name[] = "Surrogate Locker Thread (CMS)";
- Handle string = java_lang_String::create_from_str(thread_name, CHECK_NULL);
-
- // Initialize thread_oop to put it into the system threadGroup
- Handle thread_group (THREAD, Universe::system_thread_group());
- JavaValue result(T_VOID);
- JavaCalls::call_special(&result, thread_oop,
- klass,
- vmSymbolHandles::object_initializer_name(),
- vmSymbolHandles::threadgroup_string_void_signature(),
- thread_group,
- string,
- CHECK_NULL);
-
- SurrogateLockerThread* res;
- {
- MutexLocker mu(Threads_lock);
- res = new SurrogateLockerThread();
-
- // At this point it may be possible that no osthread was created for the
- // JavaThread due to lack of memory. We would have to throw an exception
- // in that case. However, since this must work and we do not allow
- // exceptions anyway, check and abort if this fails.
- if (res == NULL || res->osthread() == NULL) {
- vm_exit_during_initialization("java.lang.OutOfMemoryError",
- "unable to create new native thread");
- }
- java_lang_Thread::set_thread(thread_oop(), res);
- java_lang_Thread::set_priority(thread_oop(), NearMaxPriority);
- java_lang_Thread::set_daemon(thread_oop());
-
- res->set_threadObj(thread_oop());
- Threads::add(res);
- Thread::start(res);
- }
- os::yield(); // This seems to help with initial start-up of SLT
- return res;
-}
-
-void SurrogateLockerThread::manipulatePLL(SLT_msg_type msg) {
- MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag);
- assert(_buffer == empty, "Should be empty");
- assert(msg != empty, "empty message");
- _buffer = msg;
- while (_buffer != empty) {
- _monitor.notify();
- _monitor.wait(Mutex::_no_safepoint_check_flag);
- }
-}
-
-// ======= Surrogate Locker Thread =============
-
-void SurrogateLockerThread::loop() {
- BasicLock pll_basic_lock;
- SLT_msg_type msg;
- debug_only(unsigned int owned = 0;)
-
- while (/* !isTerminated() */ 1) {
- {
- MutexLocker x(&_monitor);
- // Since we are a JavaThread, we can't be here at a safepoint.
- assert(!SafepointSynchronize::is_at_safepoint(),
- "SLT is a JavaThread");
- // wait for msg buffer to become non-empty
- while (_buffer == empty) {
- _monitor.notify();
- _monitor.wait();
- }
- msg = _buffer;
- }
- switch(msg) {
- case acquirePLL: {
- instanceRefKlass::acquire_pending_list_lock(&pll_basic_lock);
- debug_only(owned++;)
- break;
- }
- case releaseAndNotifyPLL: {
- assert(owned > 0, "Don't have PLL");
- instanceRefKlass::release_and_notify_pending_list_lock(&pll_basic_lock);
- debug_only(owned--;)
- break;
- }
- case empty:
- default: {
- guarantee(false,"Unexpected message in _buffer");
- break;
- }
- }
- {
- MutexLocker x(&_monitor);
- // Since we are a JavaThread, we can't be here at a safepoint.
- assert(!SafepointSynchronize::is_at_safepoint(),
- "SLT is a JavaThread");
- _buffer = empty;
- _monitor.notify();
- }
- }
- assert(!_monitor.owned_by_self(), "Should unlock before exit.");
-}
-
-
-// ===== STS Access From Outside CGCT =====
-
-void ConcurrentGCThread::stsYield(const char* id) {
- assert( Thread::current()->is_ConcurrentGC_thread(),
- "only a conc GC thread can call this" );
- _sts.yield(id);
-}
-
-bool ConcurrentGCThread::stsShouldYield() {
- assert( Thread::current()->is_ConcurrentGC_thread(),
- "only a conc GC thread can call this" );
- return _sts.should_yield();
-}
-
-void ConcurrentGCThread::stsJoin() {
- assert( Thread::current()->is_ConcurrentGC_thread(),
- "only a conc GC thread can call this" );
- _sts.join();
-}
-
-void ConcurrentGCThread::stsLeave() {
- assert( Thread::current()->is_ConcurrentGC_thread(),
- "only a conc GC thread can call this" );
- _sts.leave();
-}
diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentGCThread.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentGCThread.hpp
deleted file mode 100644
index db6cc90..0000000
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentGCThread.hpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright 2001-2005 Sun Microsystems, Inc. All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * 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.
- *
- */
-
-class VoidClosure;
-
-// A SuspendibleThreadSet is (obviously) a set of threads that can be
-// suspended. A thread can join and later leave the set, and periodically
-// yield. If some thread (not in the set) requests, via suspend_all, that
-// the threads be suspended, then the requesting thread is blocked until
-// all the threads in the set have yielded or left the set. (Threads may
-// not enter the set when an attempted suspension is in progress.) The
-// suspending thread later calls resume_all, allowing the suspended threads
-// to continue.
-
-class SuspendibleThreadSet {
- Monitor* _m;
- int _async;
- bool _async_stop;
- int _async_stopped;
- bool _initialized;
- double _suspend_all_start;
-
- void initialize_work();
-
- public:
- SuspendibleThreadSet() : _initialized(false) {}
-
- // Add the current thread to the set. May block if a suspension
- // is in progress.
- void join();
- // Removes the current thread from the set.
- void leave();
- // Returns "true" iff an suspension is in progress.
- bool should_yield() { return _async_stop; }
- // Suspends the current thread if a suspension is in progress (for
- // the duration of the suspension.)
- void yield(const char* id);
- // Return when all threads in the set are suspended.
- void suspend_all();
- // Allow suspended threads to resume.
- void resume_all();
- // Redundant initializations okay.
- void initialize() {
- // Double-check dirty read idiom.
- if (!_initialized) initialize_work();
- }
-};
-
-
-class ConcurrentGCThread: public NamedThread {
- friend class VMStructs;
-
-protected:
- static bool _should_terminate;
- static bool _has_terminated;
-
- enum CGC_flag_type {
- CGC_nil = 0x0,
- CGC_dont_suspend = 0x1,
- CGC_CGC_safepoint = 0x2,
- CGC_VM_safepoint = 0x4
- };
-
- static int _CGC_flag;
-
- static bool CGC_flag_is_set(int b) { return (_CGC_flag & b) != 0; }
- static int set_CGC_flag(int b) { return _CGC_flag |= b; }
- static int reset_CGC_flag(int b) { return _CGC_flag &= ~b; }
-
- void stopWorldAndDo(VoidClosure* op);
-
- // All instances share this one set.
- static SuspendibleThreadSet _sts;
-
- // Create and start the thread (setting it's priority high.)
- void create_and_start();
-
- // Do initialization steps in the thread: record stack base and size,
- // init thread local storage, set JNI handle block.
- void initialize_in_thread();
-
- // Wait until Universe::is_fully_initialized();
- void wait_for_universe_init();
-
- // Record that the current thread is terminating, and will do more
- // concurrent work.
- void terminate();
-
-public:
- // Constructor
-
- ConcurrentGCThread();
- ~ConcurrentGCThread() {} // Exists to call NamedThread destructor.
-
- // Tester
- bool is_ConcurrentGC_thread() const { return true; }
-
- static void safepoint_synchronize();
- static void safepoint_desynchronize();
-
- // All overridings should probably do _sts::yield, but we allow
- // overriding for distinguished debugging messages. Default is to do
- // nothing.
- virtual void yield() {}
-
- bool should_yield() { return _sts.should_yield(); }
-
- // they are prefixed by sts since there are already yield() and
- // should_yield() (non-static) methods in this class and it was an
- // easy way to differentiate them.
- static void stsYield(const char* id);
- static bool stsShouldYield();
- static void stsJoin();
- static void stsLeave();
-
-};
-
-// The SurrogateLockerThread is used by concurrent GC threads for
-// manipulating Java monitors, in particular, currently for
-// manipulating the pending_list_lock. XXX
-class SurrogateLockerThread: public JavaThread {
- friend class VMStructs;
- public:
- enum SLT_msg_type {
- empty = 0, // no message
- acquirePLL, // acquire pending list lock
- releaseAndNotifyPLL // notify and release pending list lock
- };
- private:
- // the following are shared with the CMSThread
- SLT_msg_type _buffer; // communication buffer
- Monitor _monitor; // monitor controlling buffer
- BasicLock _basicLock; // used for PLL locking
-
- public:
- static SurrogateLockerThread* make(TRAPS);
-
- SurrogateLockerThread();
-
- bool is_hidden_from_external_view() const { return true; }
-
- void loop(); // main method
-
- void manipulatePLL(SLT_msg_type msg);
-
-};
diff --git a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp
index 7d1092bd..1573832 100644
--- a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp
+++ b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp
@@ -30,7 +30,7 @@
_perm(perm), _lock(NULL)
{}
-PtrQueue::~PtrQueue() {
+void PtrQueue::flush() {
if (!_perm && _buf != NULL) {
if (_index == _sz) {
// No work to do.
@@ -41,8 +41,9 @@
_buf[byte_index_to_index((int)i)] = NULL;
}
qset()->enqueue_complete_buffer(_buf);
- _buf = NULL;
}
+ _buf = NULL;
+ _index = 0;
}
}
diff --git a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp
index 3079200..8998010 100644
--- a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp
+++ b/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.hpp
@@ -62,7 +62,9 @@
// given PtrQueueSet.
PtrQueue(PtrQueueSet*, bool perm = false);
// Release any contained resources.
- ~PtrQueue();
+ void flush();
+ // Calls flush() when destroyed.
+ ~PtrQueue() { flush(); }
// Associate a lock with a ptr queue.
void set_lock(Mutex* lock) { _lock = lock; }
diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp
index 40fb6a1..310ad40 100644
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.cpp
@@ -90,10 +90,10 @@
*/
bool skip_dead = ((PSMarkSweep::total_invocations() % MarkSweepAlwaysCompactCount) != 0);
- ssize_t allowed_deadspace = 0;
+ size_t allowed_deadspace = 0;
if (skip_dead) {
- int ratio = allowed_dead_ratio();
- allowed_deadspace = (space()->capacity_in_bytes() * ratio / 100) / HeapWordSize;
+ const size_t ratio = allowed_dead_ratio();
+ allowed_deadspace = space()->capacity_in_words() * ratio / 100;
}
// Fetch the current destination decorator
@@ -271,10 +271,10 @@
dest->set_compaction_top(compact_top);
}
-bool PSMarkSweepDecorator::insert_deadspace(ssize_t& allowed_deadspace_words,
- HeapWord* q, size_t deadlength) {
- allowed_deadspace_words -= deadlength;
- if (allowed_deadspace_words >= 0) {
+bool PSMarkSweepDecorator::insert_deadspace(size_t& allowed_deadspace_words,
+ HeapWord* q, size_t deadlength) {
+ if (allowed_deadspace_words >= deadlength) {
+ allowed_deadspace_words -= deadlength;
oop(q)->set_mark(markOopDesc::prototype()->set_marked());
const size_t aligned_min_int_array_size =
align_object_size(typeArrayOopDesc::header_size(T_INT));
diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.hpp
index 4c7cfdc..affd17e 100644
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.hpp
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweepDecorator.hpp
@@ -39,14 +39,16 @@
HeapWord* _first_dead;
HeapWord* _end_of_live;
HeapWord* _compaction_top;
- unsigned int _allowed_dead_ratio;
+ size_t _allowed_dead_ratio;
- bool insert_deadspace(ssize_t& allowed_deadspace_words, HeapWord* q, size_t word_len);
+ bool insert_deadspace(size_t& allowed_deadspace_words, HeapWord* q,
+ size_t word_len);
public:
PSMarkSweepDecorator(MutableSpace* space, ObjectStartArray* start_array,
- unsigned int allowed_dead_ratio) :
- _space(space), _start_array(start_array), _allowed_dead_ratio(allowed_dead_ratio) { }
+ size_t allowed_dead_ratio) :
+ _space(space), _start_array(start_array),
+ _allowed_dead_ratio(allowed_dead_ratio) { }
// During a compacting collection, we need to collapse objects into
// spaces in a given order. We want to fill space A, space B, and so
@@ -57,14 +59,14 @@
static PSMarkSweepDecorator* destination_decorator();
// Accessors
- MutableSpace* space() { return _space; }
- ObjectStartArray* start_array() { return _start_array; }
+ MutableSpace* space() { return _space; }
+ ObjectStartArray* start_array() { return _start_array; }
- HeapWord* compaction_top() { return _compaction_top; }
- void set_compaction_top(HeapWord* value) { _compaction_top = value; }
+ HeapWord* compaction_top() { return _compaction_top; }
+ void set_compaction_top(HeapWord* value) { _compaction_top = value; }
- unsigned int allowed_dead_ratio() { return _allowed_dead_ratio; }
- void set_allowed_dead_ratio(unsigned int value) { _allowed_dead_ratio = value; }
+ size_t allowed_dead_ratio() { return _allowed_dead_ratio; }
+ void set_allowed_dead_ratio(size_t value) { _allowed_dead_ratio = value; }
// Work methods
void adjust_pointers();
diff --git a/hotspot/src/share/vm/includeDB_gc_parallel b/hotspot/src/share/vm/includeDB_gc_parallel
index 1120e9b..a032185 100644
--- a/hotspot/src/share/vm/includeDB_gc_parallel
+++ b/hotspot/src/share/vm/includeDB_gc_parallel
@@ -30,6 +30,12 @@
compiledICHolderKlass.cpp oop.pcgc.inline.hpp
+constantPoolKlass.cpp cardTableRS.hpp
+constantPoolKlass.cpp oop.pcgc.inline.hpp
+constantPoolKlass.cpp psPromotionManager.inline.hpp
+constantPoolKlass.cpp psScavenge.inline.hpp
+constantPoolKlass.cpp parOopClosures.inline.hpp
+
genCollectedHeap.cpp concurrentMarkSweepThread.hpp
genCollectedHeap.cpp vmCMSOperations.hpp
diff --git a/hotspot/src/share/vm/memory/space.cpp b/hotspot/src/share/vm/memory/space.cpp
index 37e6f61..8252944 100644
--- a/hotspot/src/share/vm/memory/space.cpp
+++ b/hotspot/src/share/vm/memory/space.cpp
@@ -997,11 +997,11 @@
}
-int TenuredSpace::allowed_dead_ratio() const {
+size_t TenuredSpace::allowed_dead_ratio() const {
return MarkSweepDeadRatio;
}
-int ContigPermSpace::allowed_dead_ratio() const {
+size_t ContigPermSpace::allowed_dead_ratio() const {
return PermMarkSweepDeadRatio;
}
diff --git a/hotspot/src/share/vm/memory/space.hpp b/hotspot/src/share/vm/memory/space.hpp
index 8edfd49..a102c5f 100644
--- a/hotspot/src/share/vm/memory/space.hpp
+++ b/hotspot/src/share/vm/memory/space.hpp
@@ -421,7 +421,7 @@
// The maximum percentage of objects that can be dead in the compacted
// live part of a compacted space ("deadwood" support.)
- virtual int allowed_dead_ratio() const { return 0; };
+ virtual size_t allowed_dead_ratio() const { return 0; };
// Some contiguous spaces may maintain some data structures that should
// be updated whenever an allocation crosses a boundary. This function
@@ -507,7 +507,7 @@
\
size_t allowed_deadspace = 0; \
if (skip_dead) { \
- int ratio = allowed_dead_ratio(); \
+ const size_t ratio = allowed_dead_ratio(); \
allowed_deadspace = (capacity() * ratio / 100) / HeapWordSize; \
} \
\
@@ -1079,7 +1079,7 @@
friend class VMStructs;
protected:
// Mark sweep support
- int allowed_dead_ratio() const;
+ size_t allowed_dead_ratio() const;
public:
// Constructor
TenuredSpace(BlockOffsetSharedArray* sharedOffsetArray,
@@ -1094,7 +1094,7 @@
friend class VMStructs;
protected:
// Mark sweep support
- int allowed_dead_ratio() const;
+ size_t allowed_dead_ratio() const;
public:
// Constructor
ContigPermSpace(BlockOffsetSharedArray* sharedOffsetArray, MemRegion mr) :
diff --git a/hotspot/src/share/vm/memory/tenuredGeneration.hpp b/hotspot/src/share/vm/memory/tenuredGeneration.hpp
index 18aa8b3..a7c22c9 100644
--- a/hotspot/src/share/vm/memory/tenuredGeneration.hpp
+++ b/hotspot/src/share/vm/memory/tenuredGeneration.hpp
@@ -73,7 +73,6 @@
// Mark sweep support
void compute_new_size();
- int allowed_dead_ratio() const;
virtual void gc_prologue(bool full);
virtual void gc_epilogue(bool full);
diff --git a/hotspot/src/share/vm/oops/constantPoolKlass.cpp b/hotspot/src/share/vm/oops/constantPoolKlass.cpp
index c112597..593b746 100644
--- a/hotspot/src/share/vm/oops/constantPoolKlass.cpp
+++ b/hotspot/src/share/vm/oops/constantPoolKlass.cpp
@@ -35,6 +35,7 @@
c->set_tags(NULL);
c->set_cache(NULL);
c->set_pool_holder(NULL);
+ c->set_flags(0);
// only set to non-zero if constant pool is merged by RedefineClasses
c->set_orig_length(0);
// all fields are initialized; needed for GC
@@ -261,10 +262,32 @@
void constantPoolKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) {
assert(obj->is_constantPool(), "should be constant pool");
+ constantPoolOop cp = (constantPoolOop) obj;
+ if (AnonymousClasses && cp->has_pseudo_string() && cp->tags() != NULL) {
+ oop* base = (oop*)cp->base();
+ for (int i = 0; i < cp->length(); ++i, ++base) {
+ if (cp->tag_at(i).is_string()) {
+ if (PSScavenge::should_scavenge(base)) {
+ pm->claim_or_forward_breadth(base);
+ }
+ }
+ }
+ }
}
void constantPoolKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
assert(obj->is_constantPool(), "should be constant pool");
+ constantPoolOop cp = (constantPoolOop) obj;
+ if (AnonymousClasses && cp->has_pseudo_string() && cp->tags() != NULL) {
+ oop* base = (oop*)cp->base();
+ for (int i = 0; i < cp->length(); ++i, ++base) {
+ if (cp->tag_at(i).is_string()) {
+ if (PSScavenge::should_scavenge(base)) {
+ pm->claim_or_forward_depth(base);
+ }
+ }
+ }
+ }
}
#endif // SERIALGC
@@ -278,6 +301,11 @@
assert(obj->is_constantPool(), "must be constantPool");
Klass::oop_print_on(obj, st);
constantPoolOop cp = constantPoolOop(obj);
+ if (cp->flags() != 0) {
+ st->print(" - flags : 0x%x", cp->flags());
+ if (cp->has_pseudo_string()) st->print(" has_pseudo_string");
+ st->cr();
+ }
// Temp. remove cache so we can do lookups with original indicies.
constantPoolCacheHandle cache (THREAD, cp->cache());
@@ -302,7 +330,11 @@
break;
case JVM_CONSTANT_UnresolvedString :
case JVM_CONSTANT_String :
- anObj = cp->string_at(index, CATCH);
+ if (cp->is_pseudo_string_at(index)) {
+ anObj = cp->pseudo_string_at(index);
+ } else {
+ anObj = cp->string_at(index, CATCH);
+ }
anObj->print_value_on(st);
st->print(" {0x%lx}", (address)anObj);
break;
@@ -382,8 +414,12 @@
"should be symbol or instance");
}
if (cp->tag_at(i).is_string()) {
- guarantee((*base)->is_perm(), "should be in permspace");
- guarantee((*base)->is_instance(), "should be instance");
+ if (!cp->has_pseudo_string()) {
+ guarantee((*base)->is_perm(), "should be in permspace");
+ guarantee((*base)->is_instance(), "should be instance");
+ } else {
+ // can be non-perm, can be non-instance (array)
+ }
}
base++;
}
diff --git a/hotspot/src/share/vm/oops/constantPoolOop.cpp b/hotspot/src/share/vm/oops/constantPoolOop.cpp
index cd8a9d1..263b7bb 100644
--- a/hotspot/src/share/vm/oops/constantPoolOop.cpp
+++ b/hotspot/src/share/vm/oops/constantPoolOop.cpp
@@ -25,6 +25,18 @@
# include "incls/_precompiled.incl"
# include "incls/_constantPoolOop.cpp.incl"
+void constantPoolOopDesc::set_flag_at(FlagBit fb) {
+ const int MAX_STATE_CHANGES = 2;
+ for (int i = MAX_STATE_CHANGES + 10; i > 0; i--) {
+ int oflags = _flags;
+ int nflags = oflags | (1 << (int)fb);
+ if (Atomic::cmpxchg(nflags, &_flags, oflags) == oflags)
+ return;
+ }
+ assert(false, "failed to cmpxchg flags");
+ _flags |= (1 << (int)fb); // better than nothing
+}
+
klassOop constantPoolOopDesc::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS) {
// A resolved constantPool entry will contain a klassOop, otherwise a symbolOop.
// It is not safe to rely on the tag bit's here, since we don't have a lock, and the entry and
@@ -333,8 +345,10 @@
oop entry = *(obj_at_addr(which));
if (entry->is_symbol()) {
return ((symbolOop)entry)->as_C_string();
- } else {
+ } else if (java_lang_String::is_instance(entry)) {
return java_lang_String::as_utf8_string(entry);
+ } else {
+ return (char*)"<pseudo-string>";
}
}
@@ -385,6 +399,19 @@
}
+bool constantPoolOopDesc::is_pseudo_string_at(int which) {
+ oop entry = *(obj_at_addr(which));
+ if (entry->is_symbol())
+ // Not yet resolved, but it will resolve to a string.
+ return false;
+ else if (java_lang_String::is_instance(entry))
+ return false; // actually, it might be a non-interned or non-perm string
+ else
+ // truly pseudo
+ return true;
+}
+
+
bool constantPoolOopDesc::klass_name_at_matches(instanceKlassHandle k,
int which) {
// Names are interned, so we can compare symbolOops directly
diff --git a/hotspot/src/share/vm/oops/constantPoolOop.hpp b/hotspot/src/share/vm/oops/constantPoolOop.hpp
index 907d71d..5627059 100644
--- a/hotspot/src/share/vm/oops/constantPoolOop.hpp
+++ b/hotspot/src/share/vm/oops/constantPoolOop.hpp
@@ -41,6 +41,7 @@
typeArrayOop _tags; // the tag array describing the constant pool's contents
constantPoolCacheOop _cache; // the cache holding interpreter runtime information
klassOop _pool_holder; // the corresponding class
+ int _flags; // a few header bits to describe contents for GC
int _length; // number of elements in the array
// only set to non-zero if constant pool is merged by RedefineClasses
int _orig_length;
@@ -49,6 +50,16 @@
void tag_at_put(int which, jbyte t) { tags()->byte_at_put(which, t); }
void release_tag_at_put(int which, jbyte t) { tags()->release_byte_at_put(which, t); }
+ enum FlagBit {
+ FB_has_pseudo_string = 2
+ };
+
+ int flags() const { return _flags; }
+ void set_flags(int f) { _flags = f; }
+ bool flag_at(FlagBit fb) const { return (_flags & (1 << (int)fb)) != 0; }
+ void set_flag_at(FlagBit fb);
+ // no clear_flag_at function; they only increase
+
private:
intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(constantPoolOopDesc)); }
oop* tags_addr() { return (oop*)&_tags; }
@@ -82,6 +93,9 @@
public:
typeArrayOop tags() const { return _tags; }
+ bool has_pseudo_string() const { return flag_at(FB_has_pseudo_string); }
+ void set_pseudo_string() { set_flag_at(FB_has_pseudo_string); }
+
// Klass holding pool
klassOop pool_holder() const { return _pool_holder; }
void set_pool_holder(klassOop k) { oop_store_without_check((oop*)&_pool_holder, (oop) k); }
@@ -272,6 +286,27 @@
return string_at_impl(h_this, which, CHECK_NULL);
}
+ // A "pseudo-string" is an non-string oop that has found is way into
+ // a String entry.
+ // Under AnonymousClasses this can happen if the user patches a live
+ // object into a CONSTANT_String entry of an anonymous class.
+ // Method oops internally created for method handles may also
+ // use pseudo-strings to link themselves to related metaobjects.
+
+ bool is_pseudo_string_at(int which);
+
+ oop pseudo_string_at(int which) {
+ assert(tag_at(which).is_string(), "Corrupted constant pool");
+ return *obj_at_addr(which);
+ }
+
+ void pseudo_string_at_put(int which, oop x) {
+ assert(AnonymousClasses, "");
+ set_pseudo_string(); // mark header
+ assert(tag_at(which).is_string() || tag_at(which).is_unresolved_string(), "Corrupted constant pool");
+ string_at_put(which, x); // this works just fine
+ }
+
// only called when we are sure a string entry is already resolved (via an
// earlier string_at call.
oop resolved_string_at(int which) {
@@ -293,6 +328,7 @@
// UTF8 char* representation was chosen to avoid conversion of
// java_lang_Strings at resolved entries into symbolOops
// or vice versa.
+ // Caller is responsible for checking for pseudo-strings.
char* string_at_noresolve(int which);
jint name_and_type_at(int which) {
diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp
index e96bd6b..8586ecb 100644
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp
@@ -147,6 +147,10 @@
oop _class_loader;
// Protection domain.
oop _protection_domain;
+ // Host class, which grants its access privileges to this class also.
+ // This is only non-null for an anonymous class (AnonymousClasses enabled).
+ // The host class is either named, or a previously loaded anonymous class.
+ klassOop _host_klass;
// Class signers.
objArrayOop _signers;
// Name of source file containing this klass, NULL if not specified.
@@ -375,6 +379,11 @@
oop protection_domain() { return _protection_domain; }
void set_protection_domain(oop pd) { oop_store((oop*) &_protection_domain, pd); }
+ // host class
+ oop host_klass() const { return _host_klass; }
+ void set_host_klass(oop host) { oop_store((oop*) &_host_klass, host); }
+ bool is_anonymous() const { return _host_klass != NULL; }
+
// signers
objArrayOop signers() const { return _signers; }
void set_signers(objArrayOop s) { oop_store((oop*) &_signers, oop(s)); }
@@ -709,6 +718,7 @@
oop* adr_constants() const { return (oop*)&this->_constants;}
oop* adr_class_loader() const { return (oop*)&this->_class_loader;}
oop* adr_protection_domain() const { return (oop*)&this->_protection_domain;}
+ oop* adr_host_klass() const { return (oop*)&this->_host_klass;}
oop* adr_signers() const { return (oop*)&this->_signers;}
oop* adr_source_file_name() const { return (oop*)&this->_source_file_name;}
oop* adr_source_debug_extension() const { return (oop*)&this->_source_debug_extension;}
diff --git a/hotspot/src/share/vm/oops/instanceKlassKlass.cpp b/hotspot/src/share/vm/oops/instanceKlassKlass.cpp
index 66e884f..94a6bee 100644
--- a/hotspot/src/share/vm/oops/instanceKlassKlass.cpp
+++ b/hotspot/src/share/vm/oops/instanceKlassKlass.cpp
@@ -81,6 +81,7 @@
MarkSweep::mark_and_push(ik->adr_source_debug_extension());
MarkSweep::mark_and_push(ik->adr_inner_classes());
MarkSweep::mark_and_push(ik->adr_protection_domain());
+ MarkSweep::mark_and_push(ik->adr_host_klass());
MarkSweep::mark_and_push(ik->adr_signers());
MarkSweep::mark_and_push(ik->adr_generic_signature());
MarkSweep::mark_and_push(ik->adr_class_annotations());
@@ -120,6 +121,7 @@
PSParallelCompact::mark_and_push(cm, ik->adr_source_debug_extension());
PSParallelCompact::mark_and_push(cm, ik->adr_inner_classes());
PSParallelCompact::mark_and_push(cm, ik->adr_protection_domain());
+ PSParallelCompact::mark_and_push(cm, ik->adr_host_klass());
PSParallelCompact::mark_and_push(cm, ik->adr_signers());
PSParallelCompact::mark_and_push(cm, ik->adr_generic_signature());
PSParallelCompact::mark_and_push(cm, ik->adr_class_annotations());
@@ -159,6 +161,7 @@
blk->do_oop(ik->adr_constants());
blk->do_oop(ik->adr_class_loader());
blk->do_oop(ik->adr_protection_domain());
+ blk->do_oop(ik->adr_host_klass());
blk->do_oop(ik->adr_signers());
blk->do_oop(ik->adr_source_file_name());
blk->do_oop(ik->adr_source_debug_extension());
@@ -211,6 +214,8 @@
if (mr.contains(adr)) blk->do_oop(adr);
adr = ik->adr_protection_domain();
if (mr.contains(adr)) blk->do_oop(adr);
+ adr = ik->adr_host_klass();
+ if (mr.contains(adr)) blk->do_oop(adr);
adr = ik->adr_signers();
if (mr.contains(adr)) blk->do_oop(adr);
adr = ik->adr_source_file_name();
@@ -260,6 +265,7 @@
MarkSweep::adjust_pointer(ik->adr_constants());
MarkSweep::adjust_pointer(ik->adr_class_loader());
MarkSweep::adjust_pointer(ik->adr_protection_domain());
+ MarkSweep::adjust_pointer(ik->adr_host_klass());
MarkSweep::adjust_pointer(ik->adr_signers());
MarkSweep::adjust_pointer(ik->adr_source_file_name());
MarkSweep::adjust_pointer(ik->adr_source_debug_extension());
@@ -295,6 +301,11 @@
pm->claim_or_forward_breadth(pd_addr);
}
+ oop* hk_addr = ik->adr_host_klass();
+ if (PSScavenge::should_scavenge(hk_addr)) {
+ pm->claim_or_forward_breadth(hk_addr);
+ }
+
oop* sg_addr = ik->adr_signers();
if (PSScavenge::should_scavenge(sg_addr)) {
pm->claim_or_forward_breadth(sg_addr);
@@ -318,6 +329,11 @@
pm->claim_or_forward_depth(pd_addr);
}
+ oop* hk_addr = ik->adr_host_klass();
+ if (PSScavenge::should_scavenge(hk_addr)) {
+ pm->claim_or_forward_depth(hk_addr);
+ }
+
oop* sg_addr = ik->adr_signers();
if (PSScavenge::should_scavenge(sg_addr)) {
pm->claim_or_forward_depth(sg_addr);
@@ -421,6 +437,7 @@
ik->set_constants(NULL);
ik->set_class_loader(NULL);
ik->set_protection_domain(NULL);
+ ik->set_host_klass(NULL);
ik->set_signers(NULL);
ik->set_source_file_name(NULL);
ik->set_source_debug_extension(NULL);
@@ -526,6 +543,7 @@
st->print(" - constants: "); ik->constants()->print_value_on(st); st->cr();
st->print(" - class loader: "); ik->class_loader()->print_value_on(st); st->cr();
st->print(" - protection domain: "); ik->protection_domain()->print_value_on(st); st->cr();
+ st->print(" - host class: "); ik->host_klass()->print_value_on(st); st->cr();
st->print(" - signers: "); ik->signers()->print_value_on(st); st->cr();
if (ik->source_file_name() != NULL) {
st->print(" - source file: ");
@@ -626,7 +644,7 @@
ik->_verify_count = Universe::verify_count();
#endif
// Verify that klass is present in SystemDictionary
- if (ik->is_loaded()) {
+ if (ik->is_loaded() && !ik->is_anonymous()) {
symbolHandle h_name (thread, ik->name());
Handle h_loader (thread, ik->class_loader());
Handle h_obj(thread, obj);
@@ -764,6 +782,9 @@
if (ik->protection_domain() != NULL) {
guarantee(ik->protection_domain()->is_oop(), "should be oop");
}
+ if (ik->host_klass() != NULL) {
+ guarantee(ik->host_klass()->is_oop(), "should be oop");
+ }
if (ik->signers() != NULL) {
guarantee(ik->signers()->is_objArray(), "should be obj array");
}
diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp
index 8d1fba0..a028f65 100644
--- a/hotspot/src/share/vm/oops/klass.cpp
+++ b/hotspot/src/share/vm/oops/klass.cpp
@@ -478,6 +478,24 @@
const char* Klass::external_name() const {
+ if (oop_is_instance()) {
+ instanceKlass* ik = (instanceKlass*) this;
+ if (ik->is_anonymous()) {
+ assert(AnonymousClasses, "");
+ intptr_t hash = ik->java_mirror()->identity_hash();
+ char hash_buf[40];
+ sprintf(hash_buf, "/" UINTX_FORMAT, (uintx)hash);
+ size_t hash_len = strlen(hash_buf);
+
+ size_t result_len = name()->utf8_length();
+ char* result = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1);
+ name()->as_klass_external_name(result, (int) result_len + 1);
+ assert(strlen(result) == result_len, "");
+ strcpy(result + result_len, hash_buf);
+ assert(strlen(result) == result_len + hash_len, "");
+ return result;
+ }
+ }
return name()->as_klass_external_name();
}
diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp
index 1342091..844d637 100644
--- a/hotspot/src/share/vm/opto/c2_globals.hpp
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp
@@ -256,10 +256,10 @@
develop(intx, PrintIdealGraphPort, 4444, \
"Ideal graph printer to network port") \
\
- develop(ccstr, PrintIdealGraphAddress, "127.0.0.1", \
+ notproduct(ccstr, PrintIdealGraphAddress, "127.0.0.1", \
"IP address to connect to visualizer") \
\
- develop(ccstr, PrintIdealGraphFile, NULL, \
+ notproduct(ccstr, PrintIdealGraphFile, NULL, \
"File to dump ideal graph to. If set overrides the " \
"use of the network") \
\
diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp
index 892f501..37cee06 100644
--- a/hotspot/src/share/vm/opto/macro.cpp
+++ b/hotspot/src/share/vm/opto/macro.cpp
@@ -1673,7 +1673,6 @@
if (klass_node == NULL) {
Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes());
klass_node = transform_later( LoadKlassNode::make(_igvn, mem, k_adr, _igvn.type(k_adr)->is_ptr()) );
- klass_node->init_req(0, ctrl);
}
Node *proto_node = make_load(ctrl, mem, klass_node, Klass::prototype_header_offset_in_bytes() + sizeof(oopDesc), TypeX_X, TypeX_X->basic_type());
diff --git a/hotspot/src/share/vm/opto/parse.hpp b/hotspot/src/share/vm/opto/parse.hpp
index 0a68a35..d33acba 100644
--- a/hotspot/src/share/vm/opto/parse.hpp
+++ b/hotspot/src/share/vm/opto/parse.hpp
@@ -175,7 +175,7 @@
bool is_SEL_backedge(Block* pred) const{ return is_SEL_head() && pred->rpo() >= rpo(); }
bool is_invariant_local(uint i) const {
const JVMState* jvms = start_map()->jvms();
- if (!jvms->is_loc(i)) return false;
+ if (!jvms->is_loc(i) || flow()->outer()->has_irreducible_entry()) return false;
return flow()->is_invariant_local(i - jvms->locoff());
}
bool can_elide_SEL_phi(uint i) const { assert(is_SEL_head(),""); return is_invariant_local(i); }
diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp
index 81302b7..7f83234 100644
--- a/hotspot/src/share/vm/prims/jvm.cpp
+++ b/hotspot/src/share/vm/prims/jvm.cpp
@@ -744,6 +744,7 @@
// common code for JVM_DefineClass() and JVM_DefineClassWithSource()
static jclass jvm_define_class_common(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source, TRAPS) {
+ if (source == NULL) source = "__JVM_DefineClass__";
// Since exceptions can be thrown, class initialization can take place
// if name is NULL no check for class name in .class stream has to be made.
@@ -782,7 +783,7 @@
JVM_ENTRY(jclass, JVM_DefineClass(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd))
JVMWrapper2("JVM_DefineClass %s", name);
- return jvm_define_class_common(env, name, loader, buf, len, pd, "__JVM_DefineClass__", THREAD);
+ return jvm_define_class_common(env, name, loader, buf, len, pd, NULL, THREAD);
JVM_END
diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h
index 131e0dd..7dbc38d 100644
--- a/hotspot/src/share/vm/prims/jvm.h
+++ b/hotspot/src/share/vm/prims/jvm.h
@@ -422,6 +422,14 @@
const jbyte *buf, jsize len, jobject pd,
const char *source);
+/* Define a class with a source (MLVM) */
+JNIEXPORT jclass JNICALL
+JVM_DefineClassWithCP(JNIEnv *env, const char *name, jobject loader,
+ const jbyte *buf, jsize len, jobject pd,
+ const char *source,
+ // same args as JVM_DefineClassWithSource to this point
+ jobjectArray constants);
+
/*
* Reflection support functions
*/
diff --git a/hotspot/src/share/vm/prims/unsafe.cpp b/hotspot/src/share/vm/prims/unsafe.cpp
index c17e021..081f19f 100644
--- a/hotspot/src/share/vm/prims/unsafe.cpp
+++ b/hotspot/src/share/vm/prims/unsafe.cpp
@@ -837,6 +837,163 @@
}
UNSAFE_END
+#define DAC_Args CLS"[B["OBJ
+// define a class but do not make it known to the class loader or system dictionary
+// - host_class: supplies context for linkage, access control, protection domain, and class loader
+// - data: bytes of a class file, a raw memory address (length gives the number of bytes)
+// - cp_patches: where non-null entries exist, they replace corresponding CP entries in data
+
+// When you load an anonymous class U, it works as if you changed its name just before loading,
+// to a name that you will never use again. Since the name is lost, no other class can directly
+// link to any member of U. Just after U is loaded, the only way to use it is reflectively,
+// through java.lang.Class methods like Class.newInstance.
+
+// Access checks for linkage sites within U continue to follow the same rules as for named classes.
+// The package of an anonymous class is given by the package qualifier on the name under which it was loaded.
+// An anonymous class also has special privileges to access any member of its host class.
+// This is the main reason why this loading operation is unsafe. The purpose of this is to
+// allow language implementations to simulate "open classes"; a host class in effect gets
+// new code when an anonymous class is loaded alongside it. A less convenient but more
+// standard way to do this is with reflection, which can also be set to ignore access
+// restrictions.
+
+// Access into an anonymous class is possible only through reflection. Therefore, there
+// are no special access rules for calling into an anonymous class. The relaxed access
+// rule for the host class is applied in the opposite direction: A host class reflectively
+// access one of its anonymous classes.
+
+// If you load the same bytecodes twice, you get two different classes. You can reload
+// the same bytecodes with or without varying CP patches.
+
+// By using the CP patching array, you can have a new anonymous class U2 refer to an older one U1.
+// The bytecodes for U2 should refer to U1 by a symbolic name (doesn't matter what the name is).
+// The CONSTANT_Class entry for that name can be patched to refer directly to U1.
+
+// This allows, for example, U2 to use U1 as a superclass or super-interface, or as
+// an outer class (so that U2 is an anonymous inner class of anonymous U1).
+// It is not possible for a named class, or an older anonymous class, to refer by
+// name (via its CP) to a newer anonymous class.
+
+// CP patching may also be used to modify (i.e., hack) the names of methods, classes,
+// or type descriptors used in the loaded anonymous class.
+
+// Finally, CP patching may be used to introduce "live" objects into the constant pool,
+// instead of "dead" strings. A compiled statement like println((Object)"hello") can
+// be changed to println(greeting), where greeting is an arbitrary object created before
+// the anonymous class is loaded. This is useful in dynamic languages, in which
+// various kinds of metaobjects must be introduced as constants into bytecode.
+// Note the cast (Object), which tells the verifier to expect an arbitrary object,
+// not just a literal string. For such ldc instructions, the verifier uses the
+// type Object instead of String, if the loaded constant is not in fact a String.
+
+static oop
+Unsafe_DefineAnonymousClass_impl(JNIEnv *env,
+ jclass host_class, jbyteArray data, jobjectArray cp_patches_jh,
+ HeapWord* *temp_alloc,
+ TRAPS) {
+
+ if (UsePerfData) {
+ ClassLoader::unsafe_defineClassCallCounter()->inc();
+ }
+
+ if (data == NULL) {
+ THROW_0(vmSymbols::java_lang_NullPointerException());
+ }
+
+ jint length = typeArrayOop(JNIHandles::resolve_non_null(data))->length();
+ jint word_length = (length + sizeof(HeapWord)-1) / sizeof(HeapWord);
+ HeapWord* body = NEW_C_HEAP_ARRAY(HeapWord, word_length);
+ if (body == NULL) {
+ THROW_0(vmSymbols::java_lang_OutOfMemoryError());
+ }
+
+ // caller responsible to free it:
+ (*temp_alloc) = body;
+
+ {
+ jbyte* array_base = typeArrayOop(JNIHandles::resolve_non_null(data))->byte_at_addr(0);
+ Copy::conjoint_words((HeapWord*) array_base, body, word_length);
+ }
+
+ u1* class_bytes = (u1*) body;
+ int class_bytes_length = (int) length;
+ if (class_bytes_length < 0) class_bytes_length = 0;
+ if (class_bytes == NULL
+ || host_class == NULL
+ || length != class_bytes_length)
+ THROW_0(vmSymbols::java_lang_IllegalArgumentException());
+
+ objArrayHandle cp_patches_h;
+ if (cp_patches_jh != NULL) {
+ oop p = JNIHandles::resolve_non_null(cp_patches_jh);
+ if (!p->is_objArray())
+ THROW_0(vmSymbols::java_lang_IllegalArgumentException());
+ cp_patches_h = objArrayHandle(THREAD, (objArrayOop)p);
+ }
+
+ KlassHandle host_klass(THREAD, java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(host_class)));
+ const char* host_source = host_klass->external_name();
+ Handle host_loader(THREAD, host_klass->class_loader());
+ Handle host_domain(THREAD, host_klass->protection_domain());
+
+ GrowableArray<Handle>* cp_patches = NULL;
+ if (cp_patches_h.not_null()) {
+ int alen = cp_patches_h->length();
+ for (int i = alen-1; i >= 0; i--) {
+ oop p = cp_patches_h->obj_at(i);
+ if (p != NULL) {
+ Handle patch(THREAD, p);
+ if (cp_patches == NULL)
+ cp_patches = new GrowableArray<Handle>(i+1, i+1, Handle());
+ cp_patches->at_put(i, patch);
+ }
+ }
+ }
+
+ ClassFileStream st(class_bytes, class_bytes_length, (char*) host_source);
+
+ instanceKlassHandle anon_klass;
+ {
+ symbolHandle no_class_name;
+ klassOop anonk = SystemDictionary::parse_stream(no_class_name,
+ host_loader, host_domain,
+ &st, host_klass, cp_patches,
+ CHECK_NULL);
+ if (anonk == NULL) return NULL;
+ anon_klass = instanceKlassHandle(THREAD, anonk);
+ }
+
+ // let caller initialize it as needed...
+
+ return anon_klass->java_mirror();
+}
+
+UNSAFE_ENTRY(jclass, Unsafe_DefineAnonymousClass(JNIEnv *env, jobject unsafe, jclass host_class, jbyteArray data, jobjectArray cp_patches_jh))
+{
+ UnsafeWrapper("Unsafe_DefineAnonymousClass");
+ ResourceMark rm(THREAD);
+
+ HeapWord* temp_alloc = NULL;
+
+ jobject res_jh = NULL;
+
+ { oop res_oop = Unsafe_DefineAnonymousClass_impl(env,
+ host_class, data, cp_patches_jh,
+ &temp_alloc, THREAD);
+ if (res_oop != NULL)
+ res_jh = JNIHandles::make_local(env, res_oop);
+ }
+
+ // try/finally clause:
+ if (temp_alloc != NULL) {
+ FREE_C_HEAP_ARRAY(HeapWord, temp_alloc);
+ }
+
+ return (jclass) res_jh;
+}
+UNSAFE_END
+
+
UNSAFE_ENTRY(void, Unsafe_MonitorEnter(JNIEnv *env, jobject unsafe, jobject jobj))
UnsafeWrapper("Unsafe_MonitorEnter");
@@ -1292,6 +1449,9 @@
{CC"copyMemory", CC"("ADR ADR"J)V", FN_PTR(Unsafe_CopyMemory)}
};
+JNINativeMethod anonk_methods[] = {
+ {CC"defineAnonymousClass", CC"("DAC_Args")"CLS, FN_PTR(Unsafe_DefineAnonymousClass)},
+};
#undef CC
#undef FN_PTR
@@ -1354,6 +1514,15 @@
}
}
}
+ if (AnonymousClasses) {
+ env->RegisterNatives(unsafecls, anonk_methods, sizeof(anonk_methods)/sizeof(JNINativeMethod));
+ if (env->ExceptionOccurred()) {
+ if (PrintMiscellaneous && (Verbose || WizardMode)) {
+ tty->print_cr("Warning: SDK 1.7 Unsafe.defineClass (anonymous version) not found.");
+ }
+ env->ExceptionClear();
+ }
+ }
int status = env->RegisterNatives(unsafecls, methods, sizeof(methods)/sizeof(JNINativeMethod));
if (env->ExceptionOccurred()) {
if (PrintMiscellaneous && (Verbose || WizardMode)) {
diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp
index cba2b99..a2476f9 100644
--- a/hotspot/src/share/vm/runtime/globals.hpp
+++ b/hotspot/src/share/vm/runtime/globals.hpp
@@ -493,7 +493,7 @@
develop(bool, DeoptimizeALot, false, \
"deoptimize at every exit from the runtime system") \
\
- develop(ccstrlist, DeoptimizeOnlyAt, "", \
+ notproduct(ccstrlist, DeoptimizeOnlyAt, "", \
"a comma separated list of bcis to deoptimize at") \
\
product(bool, DeoptimizeRandom, false, \
@@ -2792,7 +2792,7 @@
product(intx, TargetSurvivorRatio, 50, \
"Desired percentage of survivor space used after scavenge") \
\
- product(intx, MarkSweepDeadRatio, 5, \
+ product(uintx, MarkSweepDeadRatio, 5, \
"Percentage (0-100) of the old gen allowed as dead wood." \
"Serial mark sweep treats this as both the min and max value." \
"CMS uses this value only if it falls back to mark sweep." \
@@ -2801,7 +2801,7 @@
"either completely full or completely empty. Par compact also" \
"has a smaller default value; see arguments.cpp.") \
\
- product(intx, PermMarkSweepDeadRatio, 20, \
+ product(uintx, PermMarkSweepDeadRatio, 20, \
"Percentage (0-100) of the perm gen allowed as dead wood." \
"See MarkSweepDeadRatio for collector-specific comments.") \
\
@@ -3230,6 +3230,9 @@
"Skip assert() and verify() which page-in unwanted shared " \
"objects. ") \
\
+ product(bool, AnonymousClasses, false, \
+ "support sun.misc.Unsafe.defineAnonymousClass") \
+ \
product(bool, TaggedStackInterpreter, false, \
"Insert tags in interpreter execution stack for oopmap generaion")\
\
diff --git a/hotspot/src/share/vm/runtime/perfMemory.cpp b/hotspot/src/share/vm/runtime/perfMemory.cpp
index 0ae679b..d48d7b5 100644
--- a/hotspot/src/share/vm/runtime/perfMemory.cpp
+++ b/hotspot/src/share/vm/runtime/perfMemory.cpp
@@ -25,6 +25,14 @@
# include "incls/_precompiled.incl"
# include "incls/_perfMemory.cpp.incl"
+// Prefix of performance data file.
+const char PERFDATA_NAME[] = "hsperfdata";
+
+// Add 1 for the '_' character between PERFDATA_NAME and pid. The '\0' terminating
+// character will be included in the sizeof(PERFDATA_NAME) operation.
+static const size_t PERFDATA_FILENAME_LEN = sizeof(PERFDATA_NAME) +
+ UINT_CHARS + 1;
+
char* PerfMemory::_start = NULL;
char* PerfMemory::_end = NULL;
char* PerfMemory::_top = NULL;
diff --git a/hotspot/src/share/vm/runtime/perfMemory.hpp b/hotspot/src/share/vm/runtime/perfMemory.hpp
index 812ab3b..0909bfa 100644
--- a/hotspot/src/share/vm/runtime/perfMemory.hpp
+++ b/hotspot/src/share/vm/runtime/perfMemory.hpp
@@ -95,7 +95,7 @@
} PerfDataEntry;
// Prefix of performance data file.
-static const char PERFDATA_NAME[] = "hsperfdata";
+extern const char PERFDATA_NAME[];
// UINT_CHARS contains the number of characters holding a process id
// (i.e. pid). pid is defined as unsigned "int" so the maximum possible pid value
@@ -103,11 +103,6 @@
// string.
static const size_t UINT_CHARS = 10;
-// Add 1 for the '_' character between PERFDATA_NAME and pid. The '\0' terminating
-// character will be included in the sizeof(PERFDATA_NAME) operation.
-static const size_t PERFDATA_FILENAME_LEN = sizeof(PERFDATA_NAME) +
- UINT_CHARS + 1;
-
/* the PerfMemory class manages creation, destruction,
* and allocation of the PerfData region.
*/
diff --git a/hotspot/src/share/vm/runtime/reflection.cpp b/hotspot/src/share/vm/runtime/reflection.cpp
index d57b667..3bc1b02 100644
--- a/hotspot/src/share/vm/runtime/reflection.cpp
+++ b/hotspot/src/share/vm/runtime/reflection.cpp
@@ -456,10 +456,32 @@
return can_relax_access_check_for(current_class, new_class, classloader_only);
}
+static bool under_host_klass(instanceKlass* ik, klassOop host_klass) {
+ DEBUG_ONLY(int inf_loop_check = 1000 * 1000 * 1000);
+ for (;;) {
+ klassOop hc = (klassOop) ik->host_klass();
+ if (hc == NULL) return false;
+ if (hc == host_klass) return true;
+ ik = instanceKlass::cast(hc);
+
+ // There's no way to make a host class loop short of patching memory.
+ // Therefore there cannot be a loop here unles there's another bug.
+ // Still, let's check for it.
+ assert(--inf_loop_check > 0, "no host_klass loop");
+ }
+}
+
bool Reflection::can_relax_access_check_for(
klassOop accessor, klassOop accessee, bool classloader_only) {
instanceKlass* accessor_ik = instanceKlass::cast(accessor);
instanceKlass* accessee_ik = instanceKlass::cast(accessee);
+
+ // If either is on the other's host_klass chain, access is OK,
+ // because one is inside the other.
+ if (under_host_klass(accessor_ik, accessee) ||
+ under_host_klass(accessee_ik, accessor))
+ return true;
+
if (RelaxAccessControlCheck ||
(accessor_ik->major_version() < JAVA_1_5_VERSION &&
accessee_ik->major_version() < JAVA_1_5_VERSION)) {
diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp
index 4d97d62..2e4c636 100644
--- a/hotspot/src/share/vm/runtime/thread.cpp
+++ b/hotspot/src/share/vm/runtime/thread.cpp
@@ -1422,6 +1422,7 @@
thread->clear_pending_exception();
}
+
// For any new cleanup additions, please check to see if they need to be applied to
// cleanup_failed_attach_current_thread as well.
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
@@ -1592,37 +1593,60 @@
JvmtiExport::cleanup_thread(this);
}
+#ifndef SERIALGC
+ // We must flush G1-related buffers before removing a thread from
+ // the list of active threads.
+ if (UseG1GC) {
+ flush_barrier_queues();
+ }
+#endif
+
// Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread
Threads::remove(this);
}
-void JavaThread::cleanup_failed_attach_current_thread() {
-
- if (get_thread_profiler() != NULL) {
- get_thread_profiler()->disengage();
- ResourceMark rm;
- get_thread_profiler()->print(get_thread_name());
- }
-
- if (active_handles() != NULL) {
- JNIHandleBlock* block = active_handles();
- set_active_handles(NULL);
- JNIHandleBlock::release_block(block);
- }
-
- if (free_handle_block() != NULL) {
- JNIHandleBlock* block = free_handle_block();
- set_free_handle_block(NULL);
- JNIHandleBlock::release_block(block);
- }
-
- if (UseTLAB) {
- tlab().make_parsable(true); // retire TLAB, if any
- }
-
- Threads::remove(this);
- delete this;
+#ifndef SERIALGC
+// Flush G1-related queues.
+void JavaThread::flush_barrier_queues() {
+ satb_mark_queue().flush();
+ dirty_card_queue().flush();
}
+#endif
+
+void JavaThread::cleanup_failed_attach_current_thread() {
+ if (get_thread_profiler() != NULL) {
+ get_thread_profiler()->disengage();
+ ResourceMark rm;
+ get_thread_profiler()->print(get_thread_name());
+ }
+
+ if (active_handles() != NULL) {
+ JNIHandleBlock* block = active_handles();
+ set_active_handles(NULL);
+ JNIHandleBlock::release_block(block);
+ }
+
+ if (free_handle_block() != NULL) {
+ JNIHandleBlock* block = free_handle_block();
+ set_free_handle_block(NULL);
+ JNIHandleBlock::release_block(block);
+ }
+
+ if (UseTLAB) {
+ tlab().make_parsable(true); // retire TLAB, if any
+ }
+
+#ifndef SERIALGC
+ if (UseG1GC) {
+ flush_barrier_queues();
+ }
+#endif
+
+ Threads::remove(this);
+ delete this;
+}
+
+
JavaThread* JavaThread::active() {
diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp
index 8d05504..1ee5c72 100644
--- a/hotspot/src/share/vm/runtime/thread.hpp
+++ b/hotspot/src/share/vm/runtime/thread.hpp
@@ -793,6 +793,8 @@
DirtyCardQueue _dirty_card_queue; // Thread-local log for dirty cards.
// Set of all such queues.
static DirtyCardQueueSet _dirty_card_queue_set;
+
+ void flush_barrier_queues();
#endif // !SERIALGC
friend class VMThread;
diff --git a/hotspot/src/share/vm/utilities/array.hpp b/hotspot/src/share/vm/utilities/array.hpp
index 1c22950..7dee671 100644
--- a/hotspot/src/share/vm/utilities/array.hpp
+++ b/hotspot/src/share/vm/utilities/array.hpp
@@ -40,11 +40,18 @@
_length = 0;
_data = NULL;
DEBUG_ONLY(init_nesting();)
+ // client may call initialize, at most once
}
ResourceArray(size_t esize, int length) {
+ DEBUG_ONLY(_data = NULL);
+ initialize(esize, length);
+ }
+
+ void initialize(size_t esize, int length) {
assert(length >= 0, "illegal length");
+ assert(_data == NULL, "must be new object");
_length = length;
_data = resource_allocate_bytes(esize * length);
DEBUG_ONLY(init_nesting();)
@@ -111,7 +118,10 @@
/* creation */ \
array_name() : base_class() {} \
array_name(const int length) : base_class(esize, length) {} \
- array_name(const int length, const etype fx) : base_class(esize, length) { \
+ array_name(const int length, const etype fx) { initialize(length, fx); } \
+ void initialize(const int length) { base_class::initialize(esize, length); } \
+ void initialize(const int length, const etype fx) { \
+ initialize(length); \
for (int i = 0; i < length; i++) ((etype*)_data)[i] = fx; \
} \
\
@@ -157,16 +167,29 @@
\
public: \
/* creation */ \
- stack_name() : array_name() { _size = 0; } \
- stack_name(const int size) : array_name(size){ _length = 0; _size = size; } \
- stack_name(const int size, const etype fx) : array_name(size, fx) { _size = size; } \
+ stack_name() : array_name() { _size = 0; } \
+ stack_name(const int size) { initialize(size); } \
+ stack_name(const int size, const etype fx) { initialize(size, fx); } \
+ void initialize(const int size, const etype fx) { \
+ _size = size; \
+ array_name::initialize(size, fx); \
+ /* _length == size, allocation and size are the same */ \
+ } \
+ void initialize(const int size) { \
+ _size = size; \
+ array_name::initialize(size); \
+ _length = 0; /* reset length to zero; _size records the allocation */ \
+ } \
\
/* standard operations */ \
int size() const { return _size; } \
\
- void push(const etype x) { \
- if (length() >= size()) expand(esize, length(), _size); \
- ((etype*)_data)[_length++] = x; \
+ int push(const etype x) { \
+ int len = length(); \
+ if (len >= size()) expand(esize, len, _size); \
+ ((etype*)_data)[len] = x; \
+ _length = len+1; \
+ return len; \
} \
\
etype pop() { \
@@ -235,7 +258,7 @@
int capacity() const { return size(); } \
void clear() { truncate(0); } \
void trunc_to(const int length) { truncate(length); } \
- void append(const etype x) { push(x); } \
+ int append(const etype x) { return push(x); } \
void appendAll(const stack_name* stack) { push_all(stack); } \
etype last() const { return top(); } \
}; \
diff --git a/hotspot/src/share/vm/utilities/constantTag.hpp b/hotspot/src/share/vm/utilities/constantTag.hpp
index b8a213f..07a8be7 100644
--- a/hotspot/src/share/vm/utilities/constantTag.hpp
+++ b/hotspot/src/share/vm/utilities/constantTag.hpp
@@ -71,6 +71,7 @@
bool is_string_index() const { return _tag == JVM_CONSTANT_StringIndex; }
bool is_klass_reference() const { return is_klass_index() || is_unresolved_klass(); }
+ bool is_klass_or_reference() const{ return is_klass() || is_klass_reference(); }
bool is_field_or_method() const { return is_field() || is_method() || is_interface_method(); }
bool is_symbol() const { return is_utf8(); }
diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp
index 10a1b16..20241e5 100644
--- a/hotspot/src/share/vm/utilities/debug.cpp
+++ b/hotspot/src/share/vm/utilities/debug.cpp
@@ -567,7 +567,7 @@
}
// the InlineCacheBuffer is using stubs generated into a buffer blob
if (InlineCacheBuffer::contains(addr)) {
- tty->print_cr(INTPTR_FORMAT "is pointing into InlineCacheBuffer", addr);
+ tty->print_cr(INTPTR_FORMAT " is pointing into InlineCacheBuffer", addr);
return;
}
VtableStub* v = VtableStubs::stub_containing(addr);
@@ -595,7 +595,7 @@
return;
}
- if (Universe::heap()->is_in_reserved(addr)) {
+ if (Universe::heap()->is_in(addr)) {
HeapWord* p = Universe::heap()->block_start(addr);
bool print = false;
// If we couldn't find it it just may mean that heap wasn't parseable
@@ -621,24 +621,28 @@
}
return;
}
+ } else if (Universe::heap()->is_in_reserved(addr)) {
+ tty->print_cr(INTPTR_FORMAT " is an unallocated location in the heap", addr);
+ return;
}
+
if (JNIHandles::is_global_handle((jobject) addr)) {
- tty->print_cr(INTPTR_FORMAT "is a global jni handle", addr);
+ tty->print_cr(INTPTR_FORMAT " is a global jni handle", addr);
return;
}
if (JNIHandles::is_weak_global_handle((jobject) addr)) {
- tty->print_cr(INTPTR_FORMAT "is a weak global jni handle", addr);
+ tty->print_cr(INTPTR_FORMAT " is a weak global jni handle", addr);
return;
}
if (JNIHandleBlock::any_contains((jobject) addr)) {
- tty->print_cr(INTPTR_FORMAT "is a local jni handle", addr);
+ tty->print_cr(INTPTR_FORMAT " is a local jni handle", addr);
return;
}
for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) {
- // Check for priviledge stack
+ // Check for privilege stack
if (thread->privileged_stack_top() != NULL && thread->privileged_stack_top()->contains(addr)) {
- tty->print_cr(INTPTR_FORMAT "is pointing into the priviledge stack for thread: " INTPTR_FORMAT, addr, thread);
+ tty->print_cr(INTPTR_FORMAT " is pointing into the privilege stack for thread: " INTPTR_FORMAT, addr, thread);
return;
}
// If the addr is a java thread print information about that.
@@ -659,7 +663,7 @@
return;
}
- tty->print_cr(INTPTR_FORMAT "is pointing to unknown location", addr);
+ tty->print_cr(INTPTR_FORMAT " is pointing to unknown location", addr);
}
diff --git a/hotspot/src/share/vm/utilities/growableArray.hpp b/hotspot/src/share/vm/utilities/growableArray.hpp
index 208b145..ab4eeb5 100644
--- a/hotspot/src/share/vm/utilities/growableArray.hpp
+++ b/hotspot/src/share/vm/utilities/growableArray.hpp
@@ -111,6 +111,12 @@
}
void* raw_allocate(int elementSize);
+
+ // some uses pass the Thread explicitly for speed (4990299 tuning)
+ void* raw_allocate(Thread* thread, int elementSize) {
+ assert(on_stack(), "fast ResourceObj path only");
+ return (void*)resource_allocate_bytes(thread, elementSize * _max);
+ }
};
template<class E> class GrowableArray : public GenericGrowableArray {
@@ -121,6 +127,11 @@
void raw_at_put_grow(int i, const E& p, const E& fill);
void clear_and_deallocate();
public:
+ GrowableArray(Thread* thread, int initial_size) : GenericGrowableArray(initial_size, 0, false) {
+ _data = (E*)raw_allocate(thread, sizeof(E));
+ for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E();
+ }
+
GrowableArray(int initial_size, bool C_heap = false) : GenericGrowableArray(initial_size, 0, C_heap) {
_data = (E*)raw_allocate(sizeof(E));
for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E();
@@ -159,10 +170,12 @@
void print();
- void append(const E& elem) {
+ int append(const E& elem) {
check_nesting();
if (_len == _max) grow(_len);
- _data[_len++] = elem;
+ int idx = _len++;
+ _data[idx] = elem;
+ return idx;
}
void append_if_missing(const E& elem) {
diff --git a/hotspot/src/share/vm/utilities/hashtable.cpp b/hotspot/src/share/vm/utilities/hashtable.cpp
index 58d675d..8efa44a 100644
--- a/hotspot/src/share/vm/utilities/hashtable.cpp
+++ b/hotspot/src/share/vm/utilities/hashtable.cpp
@@ -43,9 +43,11 @@
entry = _free_list;
_free_list = _free_list->next();
} else {
- const int block_size = 500;
- if (_first_free_entry == _end_block) {
+ if (_first_free_entry + _entry_size >= _end_block) {
+ int block_size = MIN2(512, MAX2((int)_table_size / 2, (int)_number_of_entries));
int len = _entry_size * block_size;
+ len = 1 << log2_intptr(len); // round down to power of 2
+ assert(len >= _entry_size, "");
_first_free_entry = NEW_C_HEAP_ARRAY(char, len);
_end_block = _first_free_entry + len;
}
@@ -53,6 +55,7 @@
_first_free_entry += _entry_size;
}
+ assert(_entry_size % HeapWordSize == 0, "");
entry->set_hash(hashValue);
return entry;
}
diff --git a/jdk/.hgtags b/jdk/.hgtags
index 8b57d70..66dce59 100644
--- a/jdk/.hgtags
+++ b/jdk/.hgtags
@@ -14,3 +14,4 @@
14f50aee4989b75934d385c56a83da0c23d2f68b jdk7-b37
cc5f810b5af8a3a83b0df5a29d9e24d7a0ff8086 jdk7-b38
4e51997582effa006dde5c6d8b8820b2045b9c7f jdk7-b39
+2201dad60231a3c3e0346e3a0250d69ca3b71fd4 jdk7-b40
diff --git a/jdk/src/share/classes/com/sun/jmx/defaults/ServiceName.java b/jdk/src/share/classes/com/sun/jmx/defaults/ServiceName.java
index f70730b..a01ea89 100644
--- a/jdk/src/share/classes/com/sun/jmx/defaults/ServiceName.java
+++ b/jdk/src/share/classes/com/sun/jmx/defaults/ServiceName.java
@@ -69,9 +69,9 @@
/**
* The version of the JMX specification implemented by this product.
* <BR>
- * The value is <CODE>1.4</CODE>.
+ * The value is <CODE>2.0</CODE>.
*/
- public static final String JMX_SPEC_VERSION = "1.4";
+ public static final String JMX_SPEC_VERSION = "2.0";
/**
* The vendor of the JMX specification implemented by this product.
diff --git a/jdk/src/share/classes/com/sun/jmx/event/EventParams.java b/jdk/src/share/classes/com/sun/jmx/event/EventParams.java
index 7d875e1..c0e7663 100644
--- a/jdk/src/share/classes/com/sun/jmx/event/EventParams.java
+++ b/jdk/src/share/classes/com/sun/jmx/event/EventParams.java
@@ -41,7 +41,7 @@
@SuppressWarnings("cast") // cast for jdk 1.5
public static long getLeaseTimeout() {
- long timeout = EventClient.DEFAULT_LEASE_TIMEOUT;
+ long timeout = EventClient.DEFAULT_REQUESTED_LEASE_TIME;
try {
final GetPropertyAction act =
new GetPropertyAction(DEFAULT_LEASE_TIMEOUT);
diff --git a/jdk/src/share/classes/com/sun/jmx/event/LeaseManager.java b/jdk/src/share/classes/com/sun/jmx/event/LeaseManager.java
index 09a7a03..2db6fea 100644
--- a/jdk/src/share/classes/com/sun/jmx/event/LeaseManager.java
+++ b/jdk/src/share/classes/com/sun/jmx/event/LeaseManager.java
@@ -29,6 +29,7 @@
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
@@ -143,9 +144,10 @@
private final Runnable callback;
private ScheduledFuture<?> scheduled; // If null, the lease has expired.
+ private static final ThreadFactory threadFactory =
+ new DaemonThreadFactory("JMX LeaseManager %d");
private final ScheduledExecutorService executor
- = Executors.newScheduledThreadPool(1,
- new DaemonThreadFactory("JMX LeaseManager %d"));
+ = Executors.newScheduledThreadPool(1, threadFactory);
private static final ClassLogger logger =
new ClassLogger("javax.management.event", "LeaseManager");
diff --git a/jdk/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java b/jdk/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java
index 4a47d4c..cfb4009 100644
--- a/jdk/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java
@@ -55,9 +55,19 @@
import javax.management.namespace.MBeanServerSupport;
import javax.management.remote.IdentityMBeanServerForwarder;
+/**
+ * <p>An {@link MBeanServerForwarder} that simulates the existence of a
+ * given MBean. Requests for that MBean, call it X, are intercepted by the
+ * forwarder, and requests for any other MBean are forwarded to the next
+ * forwarder in the chain. Requests such as queryNames which can span both the
+ * X and other MBeans are handled by merging the results for X with the results
+ * from the next forwarder, unless the "visible" parameter is false, in which
+ * case X is invisible to such requests.</p>
+ */
public class SingleMBeanForwarder extends IdentityMBeanServerForwarder {
private final ObjectName mbeanName;
+ private final boolean visible;
private DynamicMBean mbean;
private MBeanServer mbeanMBS = new MBeanServerSupport() {
@@ -85,10 +95,20 @@
return null;
}
+ // This will only be called if mbeanName has an empty domain.
+ // In that case a getAttribute (e.g.) of that name will have the
+ // domain replaced by MBeanServerSupport with the default domain,
+ // so we must be sure that the default domain is empty too.
+ @Override
+ public String getDefaultDomain() {
+ return mbeanName.getDomain();
+ }
};
- public SingleMBeanForwarder(ObjectName mbeanName, DynamicMBean mbean) {
+ public SingleMBeanForwarder(
+ ObjectName mbeanName, DynamicMBean mbean, boolean visible) {
this.mbeanName = mbeanName;
+ this.visible = visible;
setSingleMBean(mbean);
}
@@ -213,8 +233,10 @@
@Override
public String[] getDomains() {
- TreeSet<String> domainSet =
- new TreeSet<String>(Arrays.asList(super.getDomains()));
+ String[] domains = super.getDomains();
+ if (!visible)
+ return domains;
+ TreeSet<String> domainSet = new TreeSet<String>(Arrays.asList(domains));
domainSet.add(mbeanName.getDomain());
return domainSet.toArray(new String[domainSet.size()]);
}
@@ -222,7 +244,7 @@
@Override
public Integer getMBeanCount() {
Integer count = super.getMBeanCount();
- if (!super.isRegistered(mbeanName))
+ if (visible && !super.isRegistered(mbeanName))
count++;
return count;
}
@@ -284,7 +306,7 @@
*/
private boolean applies(ObjectName pattern) {
// we know pattern is not null.
- if (!pattern.apply(mbeanName))
+ if (!visible || !pattern.apply(mbeanName))
return false;
final String dompat = pattern.getDomain();
@@ -306,10 +328,12 @@
@Override
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
Set<ObjectInstance> names = super.queryMBeans(name, query);
- if (name == null || applies(name) ) {
- // Don't assume mbs.queryNames returns a writable set.
- names = Util.cloneSet(names);
- names.addAll(mbeanMBS.queryMBeans(name, query));
+ if (visible) {
+ if (name == null || applies(name) ) {
+ // Don't assume mbs.queryNames returns a writable set.
+ names = Util.cloneSet(names);
+ names.addAll(mbeanMBS.queryMBeans(name, query));
+ }
}
return names;
}
@@ -317,10 +341,12 @@
@Override
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
Set<ObjectName> names = super.queryNames(name, query);
- if (name == null || applies(name)) {
- // Don't assume mbs.queryNames returns a writable set.
- names = Util.cloneSet(names);
- names.addAll(mbeanMBS.queryNames(name, query));
+ if (visible) {
+ if (name == null || applies(name)) {
+ // Don't assume mbs.queryNames returns a writable set.
+ names = Util.cloneSet(names);
+ names.addAll(mbeanMBS.queryNames(name, query));
+ }
}
return names;
}
diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java
index 14ee0ac..4fc25e9 100644
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java
@@ -122,7 +122,7 @@
* {@link javax.management.MBeanServerFactory#newMBeanServer(java.lang.String)}
* instead.
* <p>
- * By default, {@link MBeanServerInterceptor} are disabled. Use
+ * By default, interceptors are disabled. Use
* {@link #JmxMBeanServer(java.lang.String,javax.management.MBeanServer,javax.management.MBeanServerDelegate,boolean)} to enable them.
* </ul>
* @param domain The default domain name used by this MBeanServer.
@@ -239,7 +239,7 @@
this.mBeanServerDelegateObject = delegate;
this.outerShell = outer;
- final Repository repository = new Repository(domain,fairLock);
+ final Repository repository = new Repository(domain);
this.mbsInterceptor =
new NamespaceDispatchInterceptor(outer, delegate, instantiator,
repository);
diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java b/jdk/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java
deleted file mode 100644
index 49f8751..0000000
--- a/jdk/src/share/classes/com/sun/jmx/namespace/JMXNamespaceUtils.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package com.sun.jmx.namespace;
-
-import com.sun.jmx.defaults.JmxProperties;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Map;
-import java.util.WeakHashMap;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.management.ListenerNotFoundException;
-import javax.management.MBeanServerConnection;
-import javax.management.NotificationFilter;
-import javax.management.NotificationListener;
-import javax.management.event.EventClient;
-import javax.management.event.EventClientDelegateMBean;
-import javax.management.namespace.JMXNamespace;
-import javax.management.namespace.JMXNamespaces;
-import javax.management.remote.JMXAddressable;
-import javax.management.remote.JMXConnector;
-import javax.management.remote.JMXServiceURL;
-import javax.security.auth.Subject;
-
-/**
- * A collection of methods that provide JMXConnector wrappers for
- * JMXRemoteNamepaces underlying connectors.
- * <p><b>
- * This API is a Sun internal API and is subject to changes without notice.
- * </b></p>
- * @since 1.7
- */
-public final class JMXNamespaceUtils {
-
- /**
- * A logger for this class.
- **/
- private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
-
-
- private static <K,V> Map<K,V> newWeakHashMap() {
- return new WeakHashMap<K,V>();
- }
-
- /** There are no instances of this class */
- private JMXNamespaceUtils() {
- }
-
- // returns un unmodifiable view of a map.
- public static <K,V> Map<K,V> unmodifiableMap(Map<K,V> aMap) {
- if (aMap == null || aMap.isEmpty())
- return Collections.emptyMap();
- return Collections.unmodifiableMap(aMap);
- }
-
-
- /**
- * A base class that helps writing JMXConnectors that return
- * MBeanServerConnection wrappers.
- * This base class wraps an inner JMXConnector (the source), and preserve
- * its caching policy. If a connection is cached in the source, its wrapper
- * will be cached in this connector too.
- * Author's note: rewriting this with java.lang.reflect.Proxy could be
- * envisaged. It would avoid the combinatory sub-classing introduced by
- * JMXAddressable.
- * <p>
- * Note: all the standard JMXConnector implementations are serializable.
- * This implementation here is not. Should it be?
- * I believe it must not be serializable unless it becomes
- * part of a public API (either standard or officially exposed
- * and supported in a documented com.sun package)
- **/
- static class JMXCachingConnector
- implements JMXConnector {
-
- // private static final long serialVersionUID = -2279076110599707875L;
-
- final JMXConnector source;
-
- // if this object is made serializable, then the variable below
- // needs to become volatile transient and be lazyly-created...
- private final
- Map<MBeanServerConnection,MBeanServerConnection> connectionMap;
-
-
- public JMXCachingConnector(JMXConnector source) {
- this.source = checkNonNull(source, "source");
- connectionMap = newWeakHashMap();
- }
-
- private MBeanServerConnection
- getCached(MBeanServerConnection inner) {
- return connectionMap.get(inner);
- }
-
- private MBeanServerConnection putCached(final MBeanServerConnection inner,
- final MBeanServerConnection wrapper) {
- if (inner == wrapper) return wrapper;
- synchronized (this) {
- final MBeanServerConnection concurrent =
- connectionMap.get(inner);
- if (concurrent != null) return concurrent;
- connectionMap.put(inner,wrapper);
- }
- return wrapper;
- }
-
- public void addConnectionNotificationListener(NotificationListener
- listener, NotificationFilter filter, Object handback) {
- source.addConnectionNotificationListener(listener,filter,handback);
- }
-
- public void close() throws IOException {
- source.close();
- }
-
- public void connect() throws IOException {
- source.connect();
- }
-
- public void connect(Map<String,?> env) throws IOException {
- source.connect(env);
- }
-
- public String getConnectionId() throws IOException {
- return source.getConnectionId();
- }
-
- /**
- * Preserve caching policy of the underlying connector.
- **/
- public MBeanServerConnection
- getMBeanServerConnection() throws IOException {
- final MBeanServerConnection inner =
- source.getMBeanServerConnection();
- final MBeanServerConnection cached = getCached(inner);
- if (cached != null) return cached;
- final MBeanServerConnection wrapper = wrap(inner);
- return putCached(inner,wrapper);
- }
-
- public MBeanServerConnection
- getMBeanServerConnection(Subject delegationSubject)
- throws IOException {
- final MBeanServerConnection wrapped =
- source.getMBeanServerConnection(delegationSubject);
- synchronized (this) {
- final MBeanServerConnection cached = getCached(wrapped);
- if (cached != null) return cached;
- final MBeanServerConnection wrapper =
- wrapWithSubject(wrapped,delegationSubject);
- return putCached(wrapped,wrapper);
- }
- }
-
- public void removeConnectionNotificationListener(
- NotificationListener listener)
- throws ListenerNotFoundException {
- source.removeConnectionNotificationListener(listener);
- }
-
- public void removeConnectionNotificationListener(
- NotificationListener l, NotificationFilter f,
- Object handback) throws ListenerNotFoundException {
- source.removeConnectionNotificationListener(l,f,handback);
- }
-
- /**
- * This is the method that subclass will redefine. This method
- * is called by {@code this.getMBeanServerConnection()}.
- * {@code inner} is the connection returned by
- * {@code source.getMBeanServerConnection()}.
- **/
- protected MBeanServerConnection wrap(MBeanServerConnection inner)
- throws IOException {
- return inner;
- }
-
- /**
- * Subclass may also want to redefine this method.
- * By default it calls wrap(inner). This method
- * is called by {@code this.getMBeanServerConnection(Subject)}.
- * {@code inner} is the connection returned by
- * {@code source.getMBeanServerConnection(Subject)}.
- **/
- protected MBeanServerConnection wrapWithSubject(
- MBeanServerConnection inner, Subject delegationSubject)
- throws IOException {
- return wrap(inner);
- }
-
- @Override
- public String toString() {
- if (source instanceof JMXAddressable) {
- final JMXServiceURL address =
- ((JMXAddressable)source).getAddress();
- if (address != null)
- return address.toString();
- }
- return source.toString();
- }
-
- }
-
-
- /**
- * The name space connector can do 'cd'
- **/
- static class JMXNamespaceConnector extends JMXCachingConnector {
-
- // private static final long serialVersionUID = -4813611540843020867L;
-
- private final String toDir;
- private final boolean closeable;
-
- public JMXNamespaceConnector(JMXConnector source, String toDir,
- boolean closeable) {
- super(source);
- this.toDir = toDir;
- this.closeable = closeable;
- }
-
- @Override
- public void close() throws IOException {
- if (!closeable)
- throw new UnsupportedOperationException("close");
- else super.close();
- }
-
- @Override
- protected MBeanServerConnection wrap(MBeanServerConnection wrapped)
- throws IOException {
- if (LOG.isLoggable(Level.FINER))
- LOG.finer("Creating name space proxy connection for source: "+
- "namespace="+toDir);
- return JMXNamespaces.narrowToNamespace(wrapped,toDir);
- }
-
- @Override
- public String toString() {
- return "JMXNamespaces.narrowToNamespace("+
- super.toString()+
- ", \""+toDir+"\")";
- }
-
- }
-
- static class JMXEventConnector extends JMXCachingConnector {
-
- // private static final long serialVersionUID = 4742659236340242785L;
-
- JMXEventConnector(JMXConnector wrapped) {
- super(wrapped);
- }
-
- @Override
- protected MBeanServerConnection wrap(MBeanServerConnection inner)
- throws IOException {
- return EventClient.getEventClientConnection(inner);
- }
-
-
- @Override
- public String toString() {
- return "EventClient.withEventClient("+super.toString()+")";
- }
- }
-
- static class JMXAddressableEventConnector extends JMXEventConnector
- implements JMXAddressable {
-
- // private static final long serialVersionUID = -9128520234812124712L;
-
- JMXAddressableEventConnector(JMXConnector wrapped) {
- super(wrapped);
- }
-
- public JMXServiceURL getAddress() {
- return ((JMXAddressable)source).getAddress();
- }
- }
-
- /**
- * Creates a connector whose MBeamServerConnection will point to the
- * given sub name space inside the source connector.
- * @see JMXNamespace
- **/
- public static JMXConnector cd(final JMXConnector source,
- final String toNamespace,
- final boolean closeable)
- throws IOException {
-
- checkNonNull(source, "JMXConnector");
-
- if (toNamespace == null || toNamespace.equals(""))
- return source;
-
- return new JMXNamespaceConnector(source,toNamespace,closeable);
- }
-
-
- /**
- * Returns a JMX Connector that will use an {@link EventClient}
- * to subscribe for notifications. If the server doesn't have
- * an {@link EventClientDelegateMBean}, then the connector will
- * use the legacy notification mechanism instead.
- *
- * @param source The underlying JMX Connector wrapped by the returned
- * connector.
- * @return A JMX Connector that will uses an {@link EventClient}, if
- * available.
- * @see EventClient#getEventClientConnection(MBeanServerConnection)
- */
- public static JMXConnector withEventClient(final JMXConnector source) {
- checkNonNull(source, "JMXConnector");
- if (source instanceof JMXAddressable)
- return new JMXAddressableEventConnector(source);
- else
- return new JMXEventConnector(source);
- }
-
- public static <T> T checkNonNull(T parameter, String name) {
- if (parameter == null)
- throw new IllegalArgumentException(name+" must not be null");
- return parameter;
- }
-
-
-}
diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java b/jdk/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java
index 3c7065c..7d66816 100644
--- a/jdk/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java
+++ b/jdk/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java
@@ -49,11 +49,6 @@
final int tlen;
final boolean identity;
-
- public ObjectNameRouter(String targetDirName) {
- this(targetDirName,null);
- }
-
/** Creates a new instance of ObjectNameRouter */
public ObjectNameRouter(final String remove, final String add) {
this.targetPrefix = (remove==null?"":remove);
@@ -186,6 +181,4 @@
b.append(NAMESPACE_SEPARATOR);
return b.toString();
}
-
-
}
diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java
index 443c80f..b09bc84 100644
--- a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java
+++ b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java
@@ -31,7 +31,6 @@
import java.util.logging.Logger;
import javax.management.MBeanServerConnection;
-import javax.management.namespace.JMXNamespaces;
/**
@@ -61,18 +60,10 @@
* Creates a new instance of RoutingConnectionProxy
*/
public RoutingConnectionProxy(MBeanServerConnection source,
- String sourceDir) {
- this(source,sourceDir,"",false);
- }
-
- /**
- * Creates a new instance of RoutingConnectionProxy
- */
- public RoutingConnectionProxy(MBeanServerConnection source,
String sourceDir,
String targetDir,
- boolean forwardsContext) {
- super(source,sourceDir,targetDir,forwardsContext);
+ boolean probe) {
+ super(source, sourceDir, targetDir, probe);
if (LOG.isLoggable(Level.FINER))
LOG.finer("RoutingConnectionProxy for " + getSourceNamespace() +
@@ -85,15 +76,13 @@
final String sourceNs = getSourceNamespace();
String wrapped = String.valueOf(source());
if ("".equals(targetNs)) {
- if (forwardsContext)
- wrapped = "ClientContext.withDynamicContext("+wrapped+")";
return "JMXNamespaces.narrowToNamespace("+
wrapped+", \""+
sourceNs+"\")";
}
return this.getClass().getSimpleName()+"("+wrapped+", \""+
sourceNs+"\", \""+
- targetNs+"\", "+forwardsContext+")";
+ targetNs+"\")";
}
static final RoutingProxyFactory
@@ -102,22 +91,16 @@
<MBeanServerConnection,RoutingConnectionProxy>() {
public RoutingConnectionProxy newInstance(MBeanServerConnection source,
- String sourcePath, String targetPath,
- boolean forwardsContext) {
+ String sourcePath, String targetPath, boolean probe) {
return new RoutingConnectionProxy(source,sourcePath,
- targetPath,forwardsContext);
- }
-
- public RoutingConnectionProxy newInstance(
- MBeanServerConnection source, String sourcePath) {
- return new RoutingConnectionProxy(source,sourcePath);
+ targetPath, probe);
}
};
- public static MBeanServerConnection cd(MBeanServerConnection source,
- String sourcePath) {
+ public static MBeanServerConnection cd(
+ MBeanServerConnection source, String sourcePath, boolean probe) {
return RoutingProxy.cd(RoutingConnectionProxy.class, FACTORY,
- source, sourcePath);
+ source, sourcePath, probe);
}
}
diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java
index aa35c5b..12d4b4c 100644
--- a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java
+++ b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java
@@ -30,6 +30,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanRegistrationException;
@@ -90,17 +91,9 @@
// targetNs=<encoded-context> // context must be removed from object name
// sourceNs="" // nothing to add...
//
-// RoutingProxies can also be used on the client side to implement
-// "withClientContext" operations. In that case, the boolean parameter
-// 'forwards context' is set to true, targetNs is "", and sourceNS may
-// also be "". When forwardsContext is true, the RoutingProxy dynamically
-// creates an ObjectNameRouter for each operation - in order to dynamically add
-// the context attached to the thread to the routing ObjectName. This is
-// performed in the getObjectNameRouter() method.
-//
// Finally, in order to avoid too many layers of wrapping,
// RoutingConnectionProxy and RoutingServerProxy can be created through a
-// factory method that can concatenate namespace pathes in order to
+// factory method that can concatenate namespace paths in order to
// return a single RoutingProxy - rather than wrapping a RoutingProxy inside
// another RoutingProxy. See RoutingConnectionProxy.cd and
// RoutingServerProxy.cd
@@ -146,25 +139,27 @@
private final T source;
// The name space we're narrowing to (usually some name space in
- // the source MBeanServerConnection
+ // the source MBeanServerConnection), e.g. "a" for the namespace
+ // "a//". This is empty in the case of ClientContext described above.
private final String sourceNs;
- // The name space we pretend to be mounted in (usually "")
+ // The name space we pretend to be mounted in. This is empty except
+ // in the case of ClientContext described above (where it will be
+ // something like "jmx.context//foo=bar".
private final String targetNs;
// The name of the JMXNamespace that handles the source name space
private final ObjectName handlerName;
private final ObjectNameRouter router;
- final boolean forwardsContext;
private volatile String defaultDomain = null;
/**
* Creates a new instance of RoutingProxy
*/
protected RoutingProxy(T source,
- String sourceNs,
- String targetNs,
- boolean forwardsContext) {
+ String sourceNs,
+ String targetNs,
+ boolean probe) {
if (source == null) throw new IllegalArgumentException("null");
this.sourceNs = JMXNamespaces.normalizeNamespaceName(sourceNs);
@@ -177,13 +172,17 @@
// System.err.println("sourceNs: "+sourceNs);
this.handlerName =
JMXNamespaces.getNamespaceObjectName(this.sourceNs);
- try {
- // System.err.println("handlerName: "+handlerName);
- if (!source.isRegistered(handlerName))
- throw new IllegalArgumentException(sourceNs +
- ": no such name space");
- } catch (IOException x) {
- throw new IllegalArgumentException("source stale: "+x,x);
+ if (probe) {
+ try {
+ if (!source.isRegistered(handlerName)) {
+ InstanceNotFoundException infe =
+ new InstanceNotFoundException(handlerName);
+ throw new IllegalArgumentException(sourceNs +
+ ": no such name space", infe);
+ }
+ } catch (IOException x) {
+ throw new IllegalArgumentException("source stale: "+x,x);
+ }
}
}
this.source = source;
@@ -191,7 +190,6 @@
JMXNamespaces.normalizeNamespaceName(targetNs));
this.router =
new ObjectNameRouter(this.targetNs,this.sourceNs);
- this.forwardsContext = forwardsContext;
if (LOG.isLoggable(Level.FINER))
LOG.finer("RoutingProxy for " + this.sourceNs + " created");
@@ -200,14 +198,6 @@
@Override
public T source() { return source; }
- ObjectNameRouter getObjectNameRouter() {
-// TODO: uncomment this when contexts are added
-// if (forwardsContext)
-// return ObjectNameRouter.wrapWithContext(router);
-// else
- return router;
- }
-
@Override
public ObjectName toSource(ObjectName targetName)
throws MalformedObjectNameException {
@@ -222,8 +212,7 @@
if (defaultDomain != null)
targetName = targetName.withDomain(defaultDomain);
}
- final ObjectNameRouter r = getObjectNameRouter();
- return r.toSourceContext(targetName,true);
+ return router.toSourceContext(targetName,true);
}
@Override
@@ -243,8 +232,7 @@
public ObjectName toTarget(ObjectName sourceName)
throws MalformedObjectNameException {
if (sourceName == null) return null;
- final ObjectNameRouter r = getObjectNameRouter();
- return r.toTargetContext(sourceName,false);
+ return router.toTargetContext(sourceName,false);
}
private Object getAttributeFromHandler(String attributeName)
@@ -357,11 +345,8 @@
// instance.
static interface RoutingProxyFactory<T extends MBeanServerConnection,
R extends RoutingProxy<T>> {
- R newInstance(T source,
- String sourcePath, String targetPath,
- boolean forwardsContext);
- R newInstance(T source,
- String sourcePath);
+ public R newInstance(
+ T source, String sourcePath, String targetPath, boolean probe);
}
// Performs a narrowDownToNamespace operation.
@@ -377,7 +362,7 @@
static <T extends MBeanServerConnection, R extends RoutingProxy<T>>
R cd(Class<R> routingProxyClass,
RoutingProxyFactory<T,R> factory,
- T source, String sourcePath) {
+ T source, String sourcePath, boolean probe) {
if (source == null) throw new IllegalArgumentException("null");
if (source.getClass().equals(routingProxyClass)) {
// cast is OK here, but findbugs complains unless we use class.cast
@@ -400,14 +385,13 @@
final String path =
JMXNamespaces.concat(other.getSourceNamespace(),
sourcePath);
- return factory.newInstance(other.source(),path,"",
- other.forwardsContext);
+ return factory.newInstance(other.source(), path, "", probe);
}
// Note: we could do possibly something here - but it would involve
// removing part of targetDir, and possibly adding
// something to sourcePath.
// Too complex to bother! => simply default to stacking...
}
- return factory.newInstance(source,sourcePath);
+ return factory.newInstance(source, sourcePath, "", probe);
}
}
diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java
index f58e398..a11b0ec 100644
--- a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java
+++ b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java
@@ -54,7 +54,6 @@
import javax.management.QueryExp;
import javax.management.ReflectionException;
import javax.management.loading.ClassLoaderRepository;
-import javax.management.namespace.JMXNamespaces;
/**
* A RoutingServerProxy is an MBeanServer proxy that proxies a
@@ -76,19 +75,11 @@
extends RoutingProxy<MBeanServer>
implements MBeanServer {
- /**
- * Creates a new instance of RoutingServerProxy
- */
- public RoutingServerProxy(MBeanServer source,
- String sourceNs) {
- this(source,sourceNs,"",false);
- }
-
public RoutingServerProxy(MBeanServer source,
String sourceNs,
String targetNs,
- boolean forwardsContext) {
- super(source,sourceNs,targetNs,forwardsContext);
+ boolean probe) {
+ super(source, sourceNs, targetNs, probe);
}
/**
@@ -571,20 +562,15 @@
FACTORY = new RoutingProxyFactory<MBeanServer,RoutingServerProxy>() {
public RoutingServerProxy newInstance(MBeanServer source,
- String sourcePath, String targetPath,
- boolean forwardsContext) {
- return new RoutingServerProxy(source,sourcePath,
- targetPath,forwardsContext);
- }
-
- public RoutingServerProxy newInstance(
- MBeanServer source, String sourcePath) {
- return new RoutingServerProxy(source,sourcePath);
+ String sourcePath, String targetPath, boolean probe) {
+ return new RoutingServerProxy(
+ source, sourcePath, targetPath, probe);
}
};
- public static MBeanServer cd(MBeanServer source, String sourcePath) {
+ public static MBeanServer cd(
+ MBeanServer source, String sourcePath, boolean probe) {
return RoutingProxy.cd(RoutingServerProxy.class, FACTORY,
- source, sourcePath);
+ source, sourcePath, probe);
}
}
diff --git a/jdk/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java b/jdk/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java
index b660898..d02da69 100644
--- a/jdk/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java
+++ b/jdk/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java
@@ -430,13 +430,11 @@
* The {@code EventClient} is created lazily, when it is needed
* for the first time. If null, a default factory will be used
* (see {@link #createEventClient}).
- * @return the
+ * @return the MBeanServerConnection.
**/
public static MBeanServerConnection getEventConnectionFor(
MBeanServerConnection connection,
Callable<EventClient> eventClientFactory) {
- // if c already uses an EventClient no need to create a new one.
- //
if (connection instanceof EventClientFactory
&& eventClientFactory != null)
throw new IllegalArgumentException("connection already uses EventClient");
diff --git a/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java b/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java
index 8b34a2c..0e92d30 100644
--- a/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java
+++ b/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/HttpsURLConnectionOldImpl.java
@@ -497,6 +497,10 @@
delegate.setFixedLengthStreamingMode(contentLength);
}
+ public void setFixedLengthStreamingMode(long contentLength) {
+ delegate.setFixedLengthStreamingMode(contentLength);
+ }
+
public void setChunkedStreamingMode (int chunklen) {
delegate.setChunkedStreamingMode(chunklen);
}
diff --git a/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java b/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java
index 7562f58..55972ee 100644
--- a/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java
+++ b/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java
@@ -86,6 +86,8 @@
* the principal name from the configuration is used. In the
* case where the principal property is not set and the principal
* entry also does not exist, the user is prompted for the name.
+ * When this property of entry is set, and <code>useTicketCache</code>
+ * is set to true, only TGT belonging to this principal is used.
*
* <p> The following is a list of configuration options supported
* for <code>Krb5LoginModule</code>:
@@ -101,18 +103,19 @@
* to false if you do not want this module to use the ticket cache.
* (Default is False).
* This module will
- * search for the tickect
+ * search for the ticket
* cache in the following locations:
- * For Windows 2000, it will use Local Security Authority (LSA) API
- * to get the TGT. On Solaris and Linux
+ * On Solaris and Linux
* it will look for the ticket cache in /tmp/krb5cc_<code>uid</code>
* where the uid is numeric user
* identifier. If the ticket cache is
- * not available in either of the above locations, or if we are on a
- * different Windows platform, it will look for the cache as
+ * not available in the above location, or if we are on a
+ * Windows platform, it will look for the cache as
* {user.home}{file.separator}krb5cc_{user.name}.
* You can override the ticket cache location by using
- * <code>ticketCache</code>
+ * <code>ticketCache</code>.
+ * For Windows, if a ticket cannot be retrieved from the file ticket cache,
+ * it will use Local Security Authority (LSA) API to get the TGT.
* <P>
* <dt><b><code>ticketCache</code></b>:</dt>
* <dd>Set this to the name of the ticket
@@ -129,20 +132,20 @@
* <dt><b><code>doNotPrompt</code></b>:</dt>
* <dd>Set this to true if you do not want to be
* prompted for the password
- * if credentials can
- * not be obtained from the cache or keytab.(Default is false)
- * If set to true authentication will fail if credentials can
- * not be obtained from the cache or keytab.</dd>
+ * if credentials can not be obtained from the cache, the keytab,
+ * or through shared state.(Default is false)
+ * If set to true, credential must be obtained through cache, keytab,
+ * or shared state. Otherwise, authentication will fail.</dd>
* <P>
* <dt><b><code>useKeyTab</code></b>:</dt>
* <dd>Set this to true if you
* want the module to get the principal's key from the
* the keytab.(default value is False)
- * If <code>keyatb</code>
+ * If <code>keytab</code>
* is not set then
* the module will locate the keytab from the
- * Kerberos configuration file.</dd>
- * If it is not specifed in the Kerberos configuration file
+ * Kerberos configuration file.
+ * If it is not specified in the Kerberos configuration file
* then it will look for the file
* <code>{user.home}{file.separator}</code>krb5.keytab.</dd>
* <P>
@@ -210,20 +213,34 @@
* exist for the username and password in the shared
* state, or if authentication fails.
*
- * clearPass if, true, this <code>LoginModule</code> clears the
- * username and password stored in the module's shared
- * state after both phases of authentication
- * (login and commit) have completed.
+ * clearPass if, true, this LoginModule clears the
+ * username and password stored in the module's shared
+ * state after both phases of authentication
+ * (login and commit) have completed.
* </pre>
+ * <p>If the principal system property or key is already provided, the value of
+ * "javax.security.auth.login.name" in the shared state is ignored.
+ * <p>When multiple mechanisms to retrieve a ticket or key is provided, the
+ * preference order looks like this:
+ * <ol>
+ * <li>ticket cache
+ * <li>keytab
+ * <li>shared state
+ * <li>user prompt
+ * </ol>
+ * <p>Note that if any step fails, it will fallback to the next step.
+ * There's only one exception, it the shared state step fails and
+ * <code>useFirstPass</code>=true, no user prompt is made.
* <p>Examples of some configuration values for Krb5LoginModule in
* JAAS config file and the results are:
* <ul>
* <p> <code>doNotPrompt</code>=true;
* </ul>
- * <p> This is an illegal combination since <code>useTicketCache</code>
- * is not set and the user can not be prompted for the password.
+ * <p> This is an illegal combination since none of <code>useTicketCache</code>,
+ * <code>useKeyTab</code>, <code>useFirstPass</code> and <code>tryFirstPass</code>
+ * is set and the user can not be prompted for the password.
*<ul>
- * <p> <code>ticketCache</code> = < filename >;
+ * <p> <code>ticketCache</code> = <filename>;
*</ul>
* <p> This is an illegal combination since <code>useTicketCache</code>
* is not set to true and the ticketCache is set. A configuration error
@@ -240,9 +257,9 @@
*</ul>
* <p> This is an illegal combination since <code>storeKey</code> is set to
* true but the key can not be obtained either by prompting the user or from
- * the keytab.A configuration error will occur.
+ * the keytab, or from the shared state. A configuration error will occur.
* <ul>
- * <p> <code>keyTab</code> = < filename > <code>doNotPrompt</code>=true ;
+ * <p> <code>keyTab</code> = <filename> <code>doNotPrompt</code>=true ;
* </ul>
* <p>This is an illegal combination since useKeyTab is not set to true and
* the keyTab is set. A configuration error will occur.
@@ -260,7 +277,7 @@
* with the principal and TGT. If the TGT is not available,
* do not prompt the user, instead fail the authentication.
* <ul>
- * <p><code>principal</code>=< name ><code>useTicketCache</code> = true
+ * <p><code>principal</code>=<name><code>useTicketCache</code> = true
* <code>doNotPrompt</code>=true;
*</ul>
* <p> Get the TGT from the default cache for the principal and populate the
@@ -269,9 +286,9 @@
* authentication will fail.
* <ul>
* <p> <code>useTicketCache</code> = true
- * <code>ticketCache</code>=< file name ><code>useKeyTab</code> = true
- * <code> keyTab</code>=< keytab filename >
- * <code>principal</code> = < principal name >
+ * <code>ticketCache</code>=<file name><code>useKeyTab</code> = true
+ * <code> keyTab</code>=<keytab filename>
+ * <code>principal</code> = <principal name>
* <code>doNotPrompt</code>=true;
*</ul>
* <p> Search the cache for the principal's TGT. If it is not available
@@ -281,7 +298,7 @@
* If the key is not available or valid then authentication will fail.
* <ul>
* <p><code>useTicketCache</code> = true
- * <code>ticketCache</code>=< file name >
+ * <code>ticketCache</code>=<file name>
*</ul>
* <p> The TGT will be obtained from the cache specified.
* The Kerberos principal name used will be the principal name in
@@ -292,8 +309,8 @@
* The Subject will be populated with the TGT.
*<ul>
* <p> <code>useKeyTab</code> = true
- * <code>keyTab</code>=< keytab filename >
- * <code>principal</code>= < principal name >
+ * <code>keyTab</code>=<keytab filename>
+ * <code>principal</code>= <principal name>
* <code>storeKey</code>=true;
*</ul>
* <p> The key for the principal will be retrieved from the keytab.
@@ -303,7 +320,7 @@
* password entered.
* <ul>
* <p> <code>useKeyTab</code> = true
- * <code>keyTab</code>=< keytabname >
+ * <code>keyTab</code>=<keytabname>
* <code>storeKey</code>=true
* <code>doNotPrompt</code>=true;
*</ul>
@@ -316,21 +333,23 @@
* Subject's private credentials set. Otherwise the authentication will
* fail.
*<ul>
- * <p><code>useKeyTab</code> = true
- * <code>keyTab</code>=< file name > <code>storeKey</code>=true
- * <code>principal</code>= < principal name >
+ * <p>
* <code>useTicketCache</code>=true
- * <code>ticketCache</code>=< file name >;
+ * <code>ticketCache</code>=<file name>;
+ * <code>useKeyTab</code> = true
+ * <code>keyTab</code>=<file name> <code>storeKey</code>=true
+ * <code>principal</code>= <principal name>
*</ul>
- * <p>The principal's key will be retrieved from the keytab and added
- * to the <code>Subject</code>'s private credentials. If the key
- * is not available, the
- * user will be prompted for the password; the key derived from the password
- * will be added to the Subject's private credentials set. The
- * client's TGT will be retrieved from the ticket cache and added to the
+ * <p>
+ * The client's TGT will be retrieved from the ticket cache and added to the
* <code>Subject</code>'s private credentials. If the TGT is not available
- * in the ticket cache, it will be obtained using the authentication
+ * in the ticket cache, or the TGT's client name does not match the principal
+ * name, Java will use a secret key to obtain the TGT using the authentication
* exchange and added to the Subject's private credentials.
+ * This secret key will be first retrieved from the keytab. If the key
+ * is not available, the user will be prompted for the password. In either
+ * case, the key derived from the password will be added to the
+ * Subject's private credentials set.
* <ul>
* <p><code>isInitiator</code> = false
*</ul>
@@ -856,11 +875,13 @@
}
private void validateConfiguration() throws LoginException {
- if (doNotPrompt && !useTicketCache && !useKeyTab)
+ if (doNotPrompt && !useTicketCache && !useKeyTab
+ && !tryFirstPass && !useFirstPass)
throw new LoginException
("Configuration Error"
+ " - either doNotPrompt should be "
- + " false or useTicketCache/useKeyTab "
+ + " false or at least one of useTicketCache, "
+ + " useKeyTab, tryFirstPass and useFirstPass"
+ " should be true");
if (ticketCacheName != null && !useTicketCache)
throw new LoginException
@@ -872,11 +893,12 @@
throw new LoginException
("Configuration Error - useKeyTab should be set to true "
+ "to use the keytab" + keyTabName);
- if (storeKey && doNotPrompt && !useKeyTab)
+ if (storeKey && doNotPrompt && !useKeyTab
+ && !tryFirstPass && !useFirstPass)
throw new LoginException
- ("Configuration Error - either doNotPrompt "
- + "should be set to false or "
- + "useKeyTab must be set to true for storeKey option");
+ ("Configuration Error - either doNotPrompt should be set to "
+ + " false or at least one of tryFirstPass, useFirstPass "
+ + "or useKeyTab must be set to true for storeKey option");
if (renewTGT && !useTicketCache)
throw new LoginException
("Configuration Error"
diff --git a/jdk/src/share/classes/java/net/HttpURLConnection.java b/jdk/src/share/classes/java/net/HttpURLConnection.java
index eb21c7f..f35c3ef 100644
--- a/jdk/src/share/classes/java/net/HttpURLConnection.java
+++ b/jdk/src/share/classes/java/net/HttpURLConnection.java
@@ -73,11 +73,24 @@
* The fixed content-length when using fixed-length streaming mode.
* A value of <code>-1</code> means fixed-length streaming mode is disabled
* for output.
+ *
+ * <P> <B>NOTE:</B> {@link #fixedContentLengthLong} is recommended instead
+ * of this field, as it allows larger content lengths to be set.
+ *
* @since 1.5
*/
protected int fixedContentLength = -1;
/**
+ * The fixed content-length when using fixed-length streaming mode.
+ * A value of {@code -1} means fixed-length streaming mode is disabled
+ * for output.
+ *
+ * @since 1.7
+ */
+ protected long fixedContentLengthLong = -1;
+
+ /**
* Returns the key for the <code>n</code><sup>th</sup> header field.
* Some implementations may treat the <code>0</code><sup>th</sup>
* header field as special, i.e. as the status line returned by the HTTP
@@ -109,6 +122,9 @@
* This exception can be queried for the details of the error.
* <p>
* This method must be called before the URLConnection is connected.
+ * <p>
+ * <B>NOTE:</B> {@link #setFixedLengthStreamingMode(long)} is recommended
+ * instead of this method as it allows larger content lengths to be set.
*
* @param contentLength The number of bytes which will be written
* to the OutputStream.
@@ -135,6 +151,52 @@
fixedContentLength = contentLength;
}
+ /**
+ * This method is used to enable streaming of a HTTP request body
+ * without internal buffering, when the content length is known in
+ * advance.
+ *
+ * <P> An exception will be thrown if the application attempts to write
+ * more data than the indicated content-length, or if the application
+ * closes the OutputStream before writing the indicated amount.
+ *
+ * <P> When output streaming is enabled, authentication and redirection
+ * cannot be handled automatically. A {@linkplain HttpRetryException} will
+ * be thrown when reading the response if authentication or redirection
+ * are required. This exception can be queried for the details of the
+ * error.
+ *
+ * <P> This method must be called before the URLConnection is connected.
+ *
+ * <P> The content length set by invoking this method takes precedence
+ * over any value set by {@link #setFixedLengthStreamingMode(int)}.
+ *
+ * @param contentLength
+ * The number of bytes which will be written to the OutputStream.
+ *
+ * @throws IllegalStateException
+ * if URLConnection is already connected or if a different
+ * streaming mode is already enabled.
+ *
+ * @throws IllegalArgumentException
+ * if a content length less than zero is specified.
+ *
+ * @since 1.7
+ */
+ public void setFixedLengthStreamingMode(long contentLength) {
+ if (connected) {
+ throw new IllegalStateException("Already connected");
+ }
+ if (chunkLength != -1) {
+ throw new IllegalStateException(
+ "Chunked encoding streaming mode set");
+ }
+ if (contentLength < 0) {
+ throw new IllegalArgumentException("invalid content length");
+ }
+ fixedContentLengthLong = contentLength;
+ }
+
/* Default chunk size (including chunk header) if not specified;
* we want to keep this in sync with the one defined in
* sun.net.www.http.ChunkedOutputStream
@@ -170,7 +232,7 @@
if (connected) {
throw new IllegalStateException ("Can't set streaming mode: already connected");
}
- if (fixedContentLength != -1) {
+ if (fixedContentLength != -1 || fixedContentLengthLong != -1) {
throw new IllegalStateException ("Fixed length streaming mode set");
}
chunkLength = chunklen <=0? DEFAULT_CHUNK_SIZE : chunklen;
diff --git a/jdk/src/share/classes/java/security/cert/CertPathValidatorException.java b/jdk/src/share/classes/java/security/cert/CertPathValidatorException.java
index 8a04aef..c1ca1d2 100644
--- a/jdk/src/share/classes/java/security/cert/CertPathValidatorException.java
+++ b/jdk/src/share/classes/java/security/cert/CertPathValidatorException.java
@@ -113,7 +113,7 @@
* permitted, and indicates that the cause is nonexistent or unknown.)
*/
public CertPathValidatorException(Throwable cause) {
- this(null, cause);
+ this((cause == null ? null : cause.toString()), cause);
}
/**
diff --git a/jdk/src/share/classes/javax/management/AttributeList.java b/jdk/src/share/classes/javax/management/AttributeList.java
index 1ce3004..a629d57 100644
--- a/jdk/src/share/classes/javax/management/AttributeList.java
+++ b/jdk/src/share/classes/javax/management/AttributeList.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,17 +27,23 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
/**
- * Represents a list of values for attributes of an MBean. The methods
- * used for the insertion of {@link javax.management.Attribute
- * Attribute} objects in the <CODE>AttributeList</CODE> overrides the
- * corresponding methods in the superclass
- * <CODE>ArrayList</CODE>. This is needed in order to insure that the
- * objects contained in the <CODE>AttributeList</CODE> are only
- * <CODE>Attribute</CODE> objects. This avoids getting an exception
- * when retrieving elements from the <CODE>AttributeList</CODE>.
+ * <p>Represents a list of values for attributes of an MBean. See the
+ * {@link MBeanServerConnection#getAttributes getAttributes} and
+ * {@link MBeanServerConnection#setAttributes setAttributes} methods of
+ * {@link MBeanServer} and {@link MBeanServerConnection}.</p>
+ *
+ * <p id="type-safe">For compatibility reasons, it is possible, though
+ * highly discouraged, to add objects to an {@code AttributeList} that are
+ * not instances of {@code Attribute}. However, an {@code AttributeList}
+ * can be made <em>type-safe</em>, which means that an attempt to add
+ * an object that is not an {@code Attribute} will produce an {@code
+ * IllegalArgumentException}. An {@code AttributeList} becomes type-safe
+ * when the method {@link #asList()} is called on it.</p>
*
* @since 1.5
*/
@@ -58,8 +64,8 @@
*/
public class AttributeList extends ArrayList<Object> {
- private transient boolean typeSafe;
- private transient boolean tainted;
+ private transient volatile boolean typeSafe;
+ private transient volatile boolean tainted;
/* Serial version */
private static final long serialVersionUID = -4077085769279709076L;
@@ -124,7 +130,7 @@
// Check for non-Attribute objects
//
- checkTypeSafe(list);
+ adding(list);
// Build the List<Attribute>
//
@@ -132,6 +138,56 @@
}
/**
+ * <p>Constructs an {@code AttributeList} containing the elements of
+ * the {@code Map} specified, in the order in which they appear in the
+ * {@code Map}'s {@link Map#entrySet entrySet}. For each <em>{@code
+ * key}</em> and <em>{@code value}</em> in the {@code Map}, the constructed
+ * {@code AttributeList} will contain {@link Attribute#Attribute
+ * Attribute(<em>key</em>, <em>value</em>)}.</p>
+ *
+ * @param map the {@code Map} defining the elements of the new
+ * {@code AttributeList}.
+ */
+ public AttributeList(Map<String, ?> map) {
+ for (Map.Entry<String, ?> entry : map.entrySet())
+ add(new Attribute(entry.getKey(), entry.getValue()));
+ typeSafe = true;
+ }
+
+ /**
+ * <p>Return a {@code Map} that is a snapshot of the values in this
+ * {@code AttributeList}. Each key in the {@code Map} is the {@linkplain
+ * Attribute#getName() name} of an {@code Attribute} in the list, and each
+ * value is the corresponding {@linkplain Attribute#getValue() value} of
+ * that {@code Attribute}. The {@code AttributeList} and the {@code Map}
+ * are unrelated after the call, that is, changes to one do not affect the
+ * other.</p>
+ *
+ * <p>If the {@code AttributeList} contains more than one {@code Attribute}
+ * with the same name, then the {@code Map} will contain an entry
+ * for that name where the value is that of the last of those {@code
+ * Attribute}s.</p>
+ *
+ * @return the new {@code Map}.
+ *
+ * @throws IllegalArgumentException if this {@code AttributeList} contains
+ * an element that is not an {@code Attribute}.
+ */
+ public Map<String, Object> toMap() {
+ Map<String, Object> map = new LinkedHashMap<String, Object>();
+
+ // We can't call adding(this) because we're not necessarily typeSafe
+ if (tainted)
+ throw new IllegalArgumentException("AttributeList contains non-Attribute");
+
+ for (Object x : this) {
+ Attribute a = (Attribute) x;
+ map.put(a.getName(), a.getValue());
+ }
+ return map;
+ }
+
+ /**
* Return a view of this list as a {@code List<Attribute>}.
* Changes to the returned value are reflected by changes
* to the original {@code AttributeList} and vice versa.
@@ -154,11 +210,9 @@
*/
@SuppressWarnings("unchecked")
public List<Attribute> asList() {
- if (!typeSafe) {
- if (tainted)
- checkTypeSafe(this);
- typeSafe = true;
- }
+ typeSafe = true;
+ if (tainted)
+ adding((Collection<?>) this); // will throw IllegalArgumentException
return (List<Attribute>) (List<?>) this;
}
@@ -175,7 +229,7 @@
* Inserts the attribute specified as an element at the position specified.
* Elements with an index greater than or equal to the current position are
* shifted up. If the index is out of range (index < 0 || index >
- * size() a RuntimeOperationsException should be raised, wrapping the
+ * size()) a RuntimeOperationsException should be raised, wrapping the
* java.lang.IndexOutOfBoundsException thrown.
*
* @param object The <CODE>Attribute</CODE> object to be inserted.
@@ -245,8 +299,7 @@
public boolean addAll(int index, AttributeList list) {
try {
return super.addAll(index, list);
- }
- catch (IndexOutOfBoundsException e) {
+ } catch (IndexOutOfBoundsException e) {
throw new RuntimeOperationsException(e,
"The specified index is out of range");
}
@@ -258,96 +311,77 @@
* been called on this instance.
*/
+ /**
+ * {@inheritDoc}
+ * @throws IllegalArgumentException if this {@code AttributeList} is
+ * <a href="#type-safe">type-safe</a> and {@code element} is not an
+ * {@code Attribute}.
+ */
@Override
- public boolean add(Object o) {
- if (!tainted)
- tainted = isTainted(o);
- if (typeSafe)
- checkTypeSafe(o);
- return super.add(o);
+ public boolean add(Object element) {
+ adding(element);
+ return super.add(element);
}
+ /**
+ * {@inheritDoc}
+ * @throws IllegalArgumentException if this {@code AttributeList} is
+ * <a href="#type-safe">type-safe</a> and {@code element} is not an
+ * {@code Attribute}.
+ */
@Override
public void add(int index, Object element) {
- if (!tainted)
- tainted = isTainted(element);
- if (typeSafe)
- checkTypeSafe(element);
+ adding(element);
super.add(index, element);
}
+ /**
+ * {@inheritDoc}
+ * @throws IllegalArgumentException if this {@code AttributeList} is
+ * <a href="#type-safe">type-safe</a> and {@code c} contains an
+ * element that is not an {@code Attribute}.
+ */
@Override
public boolean addAll(Collection<?> c) {
- if (!tainted)
- tainted = isTainted(c);
- if (typeSafe)
- checkTypeSafe(c);
+ adding(c);
return super.addAll(c);
}
+ /**
+ * {@inheritDoc}
+ * @throws IllegalArgumentException if this {@code AttributeList} is
+ * <a href="#type-safe">type-safe</a> and {@code c} contains an
+ * element that is not an {@code Attribute}.
+ */
@Override
public boolean addAll(int index, Collection<?> c) {
- if (!tainted)
- tainted = isTainted(c);
- if (typeSafe)
- checkTypeSafe(c);
+ adding(c);
return super.addAll(index, c);
}
+ /**
+ * {@inheritDoc}
+ * @throws IllegalArgumentException if this {@code AttributeList} is
+ * <a href="#type-safe">type-safe</a> and {@code element} is not an
+ * {@code Attribute}.
+ */
@Override
public Object set(int index, Object element) {
- if (!tainted)
- tainted = isTainted(element);
- if (typeSafe)
- checkTypeSafe(element);
+ adding(element);
return super.set(index, element);
}
- /**
- * IllegalArgumentException if o is a non-Attribute object.
- */
- private static void checkTypeSafe(Object o) {
- try {
- o = (Attribute) o;
- } catch (ClassCastException e) {
- throw new IllegalArgumentException(e);
- }
+ private void adding(Object x) {
+ if (x == null || x instanceof Attribute)
+ return;
+ if (typeSafe)
+ throw new IllegalArgumentException("Not an Attribute: " + x);
+ else
+ tainted = true;
}
- /**
- * IllegalArgumentException if c contains any non-Attribute objects.
- */
- private static void checkTypeSafe(Collection<?> c) {
- try {
- Attribute a;
- for (Object o : c)
- a = (Attribute) o;
- } catch (ClassCastException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- /**
- * Returns true if o is a non-Attribute object.
- */
- private static boolean isTainted(Object o) {
- try {
- checkTypeSafe(o);
- } catch (IllegalArgumentException e) {
- return true;
- }
- return false;
- }
-
- /**
- * Returns true if c contains any non-Attribute objects.
- */
- private static boolean isTainted(Collection<?> c) {
- try {
- checkTypeSafe(c);
- } catch (IllegalArgumentException e) {
- return true;
- }
- return false;
+ private void adding(Collection<?> c) {
+ for (Object x : c)
+ adding(x);
}
}
diff --git a/jdk/src/share/classes/javax/management/ClientContext.java b/jdk/src/share/classes/javax/management/ClientContext.java
new file mode 100644
index 0000000..bddde7c
--- /dev/null
+++ b/jdk/src/share/classes/javax/management/ClientContext.java
@@ -0,0 +1,1091 @@
+/*
+ * 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 com.sun.jmx.interceptor.SingleMBeanForwarder;
+import com.sun.jmx.namespace.RoutingConnectionProxy;
+import com.sun.jmx.namespace.RoutingProxy;
+import com.sun.jmx.namespace.RoutingServerProxy;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+import java.util.concurrent.Callable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
+import javax.management.namespace.JMXNamespaces;
+import javax.management.namespace.JMXNamespace;
+import javax.management.namespace.JMXNamespaceMBean;
+import javax.management.namespace.MBeanServerSupport;
+import javax.management.remote.IdentityMBeanServerForwarder;
+import javax.management.remote.MBeanServerForwarder;
+
+/**
+ * <p>Methods to communicate a client context to MBeans. A context is
+ * a {@literal Map<String, String>} that is provided by the client and
+ * that an MBean can consult using the {@link #getContext()} method.
+ * The context is set on a per-thread basis and can be consulted by any
+ * code that the target MBean calls within the thread.</p>
+ *
+ * <p>One common usage of client context is to communicate the client's
+ * {@link Locale} to MBeans. For example, if an MBean has a String attribute
+ * {@code LastProblemDescription}, the value of that attribute could be
+ * a description of the last problem encountered by the MBean, translated
+ * into the client's locale. Different clients accessing this attribute
+ * from different locales would each see the appropriate version for their
+ * locale.</p>
+ *
+ * <p>The locale case is sufficiently important that it has a special
+ * shorthand, the {@link #getLocale()} method. This method calls
+ * <code>{@link #getContext()}.get({@link #LOCALE_KEY})</code> and converts the
+ * resultant String into a Locale object.</p>
+ *
+ * <p>Here is what an MBean with a localized {@code LastProblemDescription}
+ * attribute might look like:</p>
+ *
+ * <pre>
+ * public class LocaleSensitive implements LocaleSensitiveMBean {
+ * ...
+ * public String getLastProblemDescription() {
+ * Locale loc = {@link #getLocale() ClientContext.getLocale()};
+ * ResourceBundle rb = ResourceBundle.getBundle("MyResources", loc);
+ * String resourceKey = getLastProblemResourceKey();
+ * return rb.getString(resourceKey);
+ * }
+ * ...
+ * }
+ * </pre>
+ *
+ * <p>Here is how a client can communicate its locale to the target
+ * MBean:</p>
+ *
+ * <pre>
+ * JMXConnector connector = JMXConnectorFactory.connect(url);
+ * MBeanServerConnection connection = connector.getMBeanServerConnection();
+ * <b>MBeanServerConnection localizedConnection =
+ * {@link #withLocale(MBeanServerConnection, Locale)
+ * ClientContext.withLocale}(connection, Locale.getDefault());</b>
+ * String problem = localizedConnection.getAttribute(
+ * objectName, "LastProblemDescription");
+ * </pre>
+ *
+ * <p>In the more general case where the client wants to communicate context
+ * other than the locale, it can use {@link #withContext(MBeanServerConnection,
+ * String, String) withContext} instead of {@code withLocale}, and the target
+ * MBean can retrieve the context using {@link #getContext()}.</p>
+ *
+ *
+ * <h3 id="remote-use">Remote use of contexts</h3>
+ *
+ * <p>The various {@code with*} methods, for example {@link
+ * #withLocale(javax.management.MBeanServer, java.util.Locale) withLocale},
+ * transmit the context of each request by encoding it in the ObjectName of
+ * the request. For example, if a client creates a connection in the
+ * French locale like this...</p>
+ *
+ * <pre>
+ * MBeanServerConnection mbsc = ...;
+ * Locale french = new Locale("fr");
+ * MBeanServerConnection localizedConnection = ClientContext.withLocale(mbsc, french);
+ * </pre>
+ *
+ * <p>...or, equivalently, like this...</p>
+ *
+ * <pre>
+ * MBeanServerConnection localizedConnection =
+ * ClientContext.withContext(mbsc, {@link #LOCALE_KEY "jmx.locale"}, "fr");
+ * </pre>
+ *
+ * <p>...then the context associates {@code "jmx.locale"} with {@code "fr"}
+ * and a request such as<br>
+ * {@code localizedConnection.getAttribute("java.lang:type=Runtime", "Name")}<br>
+ * is translated into<br>
+ * {@code mbsc.getAttribute("jmx.context//jmx.locale=fr//java.lang:Runtime", "Name")}.<br>
+ * A special {@linkplain javax.management.namespace namespace} {@code jmx.context//}
+ * extracts the context from the string {@code jmx.locale=fr} and establishes
+ * it in the thread that will do<br>
+ * {@code getAttribute("java.lang:Runtime", "Name")}.</p>
+ *
+ * <p>The details of how contexts are encoded into ObjectNames are explained
+ * in the {@link #encode encode} method.</p>
+ *
+ * <p>The namespace {@code jmx.context//} just mentioned is only needed by
+ * remote clients, since local clients can set the context directly using
+ * {@link #doWithContext doWithContext}. Accordingly, this namespace is not
+ * present by default in the {@code MBeanServer}. Instead, it is
+ * <em>simulated</em> by the standard RMI connector using a special
+ * {@link MBeanServerForwarder}. If you are using this connector, you do not
+ * need to do anything special. Other connectors may or may not simulate this
+ * namespace in the same way. If the connector server returns true from the
+ * method {@link
+ * javax.management.remote.JMXConnectorServer#supportsSystemMBeanServerForwarder()
+ * supportsSystemMBeanServerForwarder} then it does simulate the namespace.
+ * If you are using another connector, or if you want to be able to use the
+ * {@code with*} methods locally, then you can install the {@code
+ * MBeanServerForwarder} yourself as described in the method {@link
+ * #newContextForwarder newContextForwarder}.</p>
+ */
+public class ClientContext {
+ /**
+ * <p>The context key for the client locale. The string associated with
+ * this key is an encoded locale such as {@code en_US} which could be
+ * returned by {@link Locale#toString()}.</p>
+ */
+ public static final String LOCALE_KEY = "jmx.locale";
+
+ private static final Logger LOG =
+ Logger.getLogger("javax.management.context");
+
+ /**
+ * <p>The namespace that implements contexts, {@value}.</p>
+ */
+ public static final String
+ NAMESPACE = "jmx.context";
+ private static final String NAMESPACE_PLUS_SEP =
+ NAMESPACE + NAMESPACE_SEPARATOR;
+ static final ObjectName CLIENT_CONTEXT_NAMESPACE_HANDLER =
+ ObjectName.valueOf(NAMESPACE_PLUS_SEP + ":" +
+ JMXNamespace.TYPE_ASSIGNMENT);
+ private static final ObjectName NAMESPACE_HANDLER_WITHOUT_NAMESPACE =
+ ObjectName.valueOf(":" + JMXNamespace.TYPE_ASSIGNMENT);
+
+ private static final ThreadLocal<Map<String, String>> contextThreadLocal =
+ new InheritableThreadLocal<Map<String, String>>() {
+ @Override
+ protected Map<String, String> initialValue() {
+ return Collections.emptyMap();
+ }
+ };
+
+ /** There are no instances of this class. */
+ private ClientContext() {
+ }
+
+ /**
+ * <p>Get the client context associated with the current thread.
+ *
+ * @return the client context associated with the current thread.
+ * This may be an empty Map, but it cannot be null. The returned
+ * Map cannot be modified.
+ */
+ public static Map<String, String> getContext() {
+ return Collections.unmodifiableMap(contextThreadLocal.get());
+ }
+
+ /**
+ * <p>Get the client locale associated with the current thread.
+ * If the client context includes the {@value #LOCALE_KEY} key
+ * then the returned value is the Locale encoded in that key.
+ * Otherwise the returned value is the {@linkplain Locale#getDefault()
+ * default locale}.
+ *
+ * @return the client locale.
+ */
+ public static Locale getLocale() {
+ String localeS = getContext().get(LOCALE_KEY);
+ if (localeS == null)
+ return Locale.getDefault();
+ // Parse the locale string. Why isn't there a method in Locale for this?
+ String language, country, variant;
+ int ui = localeS.indexOf('_');
+ if (ui < 0) {
+ language = localeS;
+ country = variant = "";
+ } else {
+ language = localeS.substring(0, ui);
+ localeS = localeS.substring(ui + 1);
+ ui = localeS.indexOf('_');
+ if (ui < 0) {
+ country = localeS;
+ variant = "";
+ } else {
+ country = localeS.substring(0, ui);
+ variant = localeS.substring(ui + 1);
+ }
+ }
+ return new Locale(language, country, variant);
+ }
+
+ /**
+ * <p>Execute the given {@code task} with the client context set to
+ * the given Map. This Map will be the result of {@link #getContext()}
+ * within the {@code task}.</p>
+ *
+ * <p>The {@code task} may include nested calls to {@code doWithContext}.
+ * The value returned by {@link #getContext} at any point is the Map
+ * provided to the most recent {@code doWithContext} (in the current thread)
+ * that has not yet returned.</p>
+ *
+ * <p>The {@link #getContext()} method returns the same value immediately
+ * after a call to this method as immediately before. In other words,
+ * {@code doWithContext} only affects the context during the execution of
+ * the {@code task}.</p>
+ *
+ * <p>As an example, suppose you want to get an attribute with whatever
+ * context has already been set, plus the locale set to "fr". You could
+ * write this:</p>
+ *
+ * <pre>
+ * {@code Map<String, String>} context =
+ * new {@code HashMap<String, String>}(ClientContext.getContext());
+ * context.put(ClientContext.LOCALE_KEY, "fr");
+ * String lastProblemDescription =
+ * ClientContext.doWithContext(context, new {@code Callable<String>}() {
+ * public String call() {
+ * return (String) mbeanServer.getAttribute(mbean, "LastProblemDescription");
+ * }
+ * });
+ * </pre>
+ *
+ * @param <T> the type of value that the task will return. This type
+ * parameter is usually inferred from the type of the {@code task}
+ * parameter. For example, if {@code task} is a {@code Callable<String>}
+ * then {@code T} is {@code String}. If the task does not return a value,
+ * use a {@code Callable<Void>} and return null from its
+ * {@link Callable#call call} method.
+ * @param context the context to use while executing {@code task}.
+ * @param task the task to run with the {@code key}={@code value}
+ * binding.
+ * @return the result of {@link Callable#call() task.call()}.
+ * @throws IllegalArgumentException if either parameter is null, or
+ * if any key in {@code context} is null or empty, or if any value
+ * in {@code context} is null.
+ * @throws Exception If {@link Callable#call() task.call()} throws an
+ * exception, {@code doWithContext} throws the same exception.
+ */
+ public static <T> T doWithContext(Map<String, String> context, Callable<T> task)
+ throws Exception {
+ if (context == null || task == null)
+ throw new IllegalArgumentException("Null parameter");
+ Map<String, String> contextCopy = new TreeMap<String, String>(context);
+ validateContext(contextCopy);
+ Map<String, String> oldContextMap = contextThreadLocal.get();
+ try {
+ contextThreadLocal.set(contextCopy);
+ return task.call();
+ } finally {
+ contextThreadLocal.set(oldContextMap);
+ }
+ }
+
+ private static void validateContext(Map<String, String> context) {
+ for (Map.Entry<String, String> entry : context.entrySet()) {
+ // If the user passes a raw Map rather than a Map<String, String>,
+ // entries could contain objects other than Strings. If so,
+ // we'll get a ClassCastException here.
+ String key = entry.getKey();
+ String value = entry.getValue();
+ if (key == null || value == null)
+ throw new IllegalArgumentException("Null key or value in context");
+ if (key.equals(""))
+ throw new IllegalArgumentException("Empty key in context");
+ }
+ }
+
+ /**
+ * <p>Return an MBeanServer object that is equivalent to the given
+ * MBeanServer object except that operations on MBeans run with
+ * the given Locale in their {@linkplain #getContext() thread context}.
+ * Note that this will only work if the given MBeanServer supports
+ * contexts, as described <a href="#remote-use">above</a>.</p>
+ *
+ * <p>This method is equivalent to {@link #withContext(MBeanServer,
+ * String, String) withContext}<code>(mbs, {@value LOCALE_KEY},
+ * locale.toString())</code>.</p>
+ *
+ * @throws IllegalArgumentException if either parameter is null, or if
+ * {@code mbs} does not support contexts. In the second case only,
+ * the cause of the {@code IllegalArgumentException} will be an {@link
+ * InstanceNotFoundException}.
+ */
+ public static MBeanServer withLocale(MBeanServer mbs, Locale locale) {
+ return withLocale(mbs, MBeanServer.class, locale);
+ }
+
+ /**
+ * <p>Return an MBeanServerConnection object that is equivalent to the given
+ * MBeanServerConnection object except that operations on MBeans run with
+ * the given Locale in their {@linkplain #getContext() thread context}.
+ * Note that this will only work if the given MBeanServerConnection supports
+ * contexts, as described <a href="#remote-use">above</a>.</p>
+ *
+ * <p>This method is equivalent to {@link #withContext(MBeanServerConnection,
+ * String, String) withContext}<code>(mbs, {@value LOCALE_KEY},
+ * locale.toString())</code>.</p>
+ *
+ * @throws IllegalArgumentException if either parameter is null, or if
+ * the communication with {@code mbsc} fails, or if {@code mbsc} does not
+ * support contexts. If the communication with {@code mbsc} fails, the
+ * {@linkplain Throwable#getCause() cause} of this exception will be an
+ * {@code IOException}. If {@code mbsc} does not support contexts, the
+ * cause will be an {@link InstanceNotFoundException}.
+ */
+ public static MBeanServerConnection withLocale(
+ MBeanServerConnection mbsc, Locale locale) {
+ return withLocale(mbsc, MBeanServerConnection.class, locale);
+ }
+
+ private static <T extends MBeanServerConnection> T withLocale(
+ T mbsc, Class<T> mbscClass, Locale locale) {
+ if (locale == null)
+ throw new IllegalArgumentException("Null locale");
+ return withContext(mbsc, mbscClass, LOCALE_KEY, locale.toString());
+ }
+
+ /**
+ * <p>Return an MBeanServer object that is equivalent to the given
+ * MBeanServer object except that operations on MBeans run with
+ * the given key bound to the given value in their {@linkplain
+ * #getContext() thread context}.
+ * Note that this will only work if the given MBeanServer supports
+ * contexts, as described <a href="#remote-use">above</a>.</p>
+ *
+ * @param mbs the original MBeanServer.
+ * @param key the key to bind in the context of MBean operations
+ * in the returned MBeanServer object.
+ * @param value the value to bind to the key in the context of MBean
+ * operations in the returned MBeanServer object.
+ * @throws IllegalArgumentException if any parameter is null, or
+ * if {@code key} is the empty string, or if {@code mbs} does not support
+ * contexts. In the last case only, the cause of the {@code
+ * IllegalArgumentException} will be an {@link InstanceNotFoundException}.
+ */
+ public static MBeanServer withContext(
+ MBeanServer mbs, String key, String value) {
+ return withContext(mbs, MBeanServer.class, key, value);
+ }
+
+ /**
+ * <p>Return an MBeanServerConnection object that is equivalent to the given
+ * MBeanServerConnection object except that operations on MBeans run with
+ * the given key bound to the given value in their {@linkplain
+ * #getContext() thread context}.
+ * Note that this will only work if the given MBeanServerConnection supports
+ * contexts, as described <a href="#remote-use">above</a>.</p>
+ *
+ * @param mbsc the original MBeanServerConnection.
+ * @param key the key to bind in the context of MBean operations
+ * in the returned MBeanServerConnection object.
+ * @param value the value to bind to the key in the context of MBean
+ * operations in the returned MBeanServerConnection object.
+ * @throws IllegalArgumentException if any parameter is null, or
+ * if {@code key} is the empty string, or if the communication with {@code
+ * mbsc} fails, or if {@code mbsc} does not support contexts. If
+ * the communication with {@code mbsc} fails, the {@linkplain
+ * Throwable#getCause() cause} of this exception will be an {@code
+ * IOException}. If {@code mbsc} does not support contexts, the cause will
+ * be an {@link InstanceNotFoundException}.
+ */
+ public static MBeanServerConnection withContext(
+ MBeanServerConnection mbsc, String key, String value) {
+ return withContext(mbsc, MBeanServerConnection.class, key, value);
+ }
+
+
+ /**
+ * <p>Returns an MBeanServerConnection object that is equivalent to the
+ * given MBeanServerConnection object except that remote operations on
+ * MBeans run with the context that has been established by the client
+ * using {@link #doWithContext doWithContext}. Note that this will
+ * only work if the remote system supports contexts, as described <a
+ * href="#remote-use">above</a>.</p>
+ *
+ * <p>For example, suppose the remote system does support contexts, and you
+ * have created a {@code JMXConnector} like this:</p>
+ *
+ * <pre>
+ * JMXServiceURL url = ...;
+ * JMXConnector client = JMXConnectorFactory.connect(url);
+ * MBeanServerConnection mbsc = client.getMBeanServerConnection();
+ * <b>mbsc = ClientContext.withDynamicContext(mbsc);</b>
+ * </pre>
+ *
+ * <p>Then if you do this...</p>
+ *
+ * <pre>
+ * MBeanInfo mbi = ClientContext.doWithContext(
+ * Collections.singletonMap(ClientContext.LOCALE_KEY, "fr"),
+ * new {@code Callable<MBeanInfo>}() {
+ * public MBeanInfo call() {
+ * return mbsc.getMBeanInfo(objectName);
+ * }
+ * });
+ * </pre>
+ *
+ * <p>...then the context with the locale set to "fr" will be in place
+ * when the {@code getMBeanInfo} is executed on the remote MBean Server.</p>
+ *
+ * @param mbsc the original MBeanServerConnection.
+ *
+ * @throws IllegalArgumentException if the {@code mbsc} parameter is null,
+ * or if the communication with {@code mbsc} fails, or if {@code mbsc}
+ * does not support contexts. If the communication with {@code mbsc}
+ * fails, the {@linkplain Throwable#getCause() cause} of this exception
+ * will be an {@code IOException}. If {@code mbsc} does not support
+ * contexts, the cause will be an {@link InstanceNotFoundException}.
+ */
+ public static MBeanServerConnection withDynamicContext(
+ MBeanServerConnection mbsc) {
+ // Probe mbsc to get the right exception if it's incommunicado or
+ // doesn't support namespaces.
+ JMXNamespaces.narrowToNamespace(mbsc, NAMESPACE);
+ return (MBeanServerConnection) Proxy.newProxyInstance(
+ MBeanServerConnection.class.getClassLoader(),
+ new Class<?>[] {MBeanServerConnection.class},
+ new DynamicContextIH(mbsc));
+ }
+
+ private static class DynamicContextIH implements InvocationHandler {
+ private final MBeanServerConnection mbsc;
+
+ public DynamicContextIH(MBeanServerConnection mbsc) {
+ this.mbsc = mbsc;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ MBeanServerConnection dynMBSC = withContext(
+ mbsc, MBeanServerConnection.class, getContext(), false);
+ try {
+ return method.invoke(dynMBSC, args);
+ } catch (InvocationTargetException e) {
+ throw e.getCause();
+ }
+ }
+ }
+
+ private static <T extends MBeanServerConnection> T withContext(
+ T mbsc, Class<T> mbscClass, String key, String value) {
+ return withContext(
+ mbsc, mbscClass, Collections.singletonMap(key, value), true);
+ }
+
+ private static <T extends MBeanServerConnection> T withContext(
+ T mbsc, Class<T> mbscClass, Map<String, String> context,
+ boolean probe) {
+ if (mbsc == null || context == null)
+ throw new IllegalArgumentException("Null parameter");
+ if (context.isEmpty())
+ return mbsc;
+ validateContext(context);
+ Map<String, String> contextMap = null;
+ if (mbsc.getClass() == RoutingServerProxy.class ||
+ mbsc.getClass() == RoutingProxy.class) {
+ RoutingProxy<?> nsp = (RoutingProxy<?>) mbsc;
+ String where = nsp.getSourceNamespace();
+ if (where.startsWith(NAMESPACE_PLUS_SEP)) {
+ /* Try to merge the existing context namespace with the
+ * new one. If it doesn't work, we fall back to just
+ * prefixing jmx.context//key=value, which
+ * might lead to a name like jmx.c//k1=v1//jmx.c//k2=v2//d:k=v.
+ */
+ String encodedContext =
+ where.substring(NAMESPACE_PLUS_SEP.length());
+ if (encodedContext.indexOf(NAMESPACE_SEPARATOR) < 0) {
+ contextMap = stringToMapOrNull(encodedContext);
+ if (contextMap != null) {
+ contextMap.putAll(context);
+ mbsc = mbscClass.cast(nsp.source());
+ }
+ }
+ }
+ }
+ if (contextMap == null)
+ contextMap = context;
+ String contextDir = NAMESPACE_PLUS_SEP + mapToString(contextMap);
+ if (mbscClass == MBeanServer.class) {
+ return mbscClass.cast(RoutingServerProxy.cd(
+ (MBeanServer) mbsc, contextDir, probe));
+ } else if (mbscClass == MBeanServerConnection.class) {
+ return mbscClass.cast(RoutingConnectionProxy.cd(
+ mbsc, contextDir, probe));
+ } else
+ throw new AssertionError("Bad MBSC: " + mbscClass);
+ }
+
+ /**
+ * <p>Returns an encoded context prefix for ObjectNames.
+ * If the given context is empty, {@code ""} is returned.
+ * Otherwise, this method returns a string of the form
+ * {@code "jmx.context//key=value;key=value;..."}.
+ * For example, if the context has keys {@code "jmx.locale"}
+ * and {@code "xid"} with respective values {@code "fr"}
+ * and {@code "1234"}, this method will return
+ * {@code "jmx.context//jmx.locale=fr;xid=1234"} or
+ * {@code "jmx.context//xid=1234;jmx.locale=fr"}.</p>
+ *
+ * <p>Each key and each value in the encoded string is subject to
+ * encoding as if by the method {@link URLEncoder#encode(String, String)}
+ * with a character encoding of {@code "UTF-8"}, but with the additional
+ * encoding of any {@code *} character as {@code "%2A"}. This ensures
+ * that keys and values can contain any character. Without encoding,
+ * characters such as {@code =} and {@code :} would pose problems.</p>
+ *
+ * @param context the context to encode.
+ *
+ * @return the context in encoded form.
+ *
+ * @throws IllegalArgumentException if the {@code context} parameter
+ * is null or if it contains a null key or value.
+ **/
+ public static String encode(Map<String, String> context) {
+ if (context == null)
+ throw new IllegalArgumentException("Null context");
+ if (context.isEmpty())
+ return "";
+ StringBuilder sb = new StringBuilder();
+ for (Map.Entry<String, String> entry : context.entrySet()) {
+ String key = entry.getKey();
+ String value = entry.getValue();
+ if (key == null || value == null)
+ throw new IllegalArgumentException("Null key or value");
+ if (sb.length() > 0)
+ sb.append(";");
+ sb.append(encode(key)).append("=").append(encode(value));
+ }
+ sb.insert(0, NAMESPACE_PLUS_SEP);
+ return sb.toString();
+ }
+
+ /**
+ * <p>Create a new {@link MBeanServerForwarder} that applies the context
+ * received from a client to the current thread. A client using
+ * one of the various {@code with*} methods (for example {@link
+ * #withContext(MBeanServerConnection, String, String) withContext}) will
+ * encode that context into the {@code ObjectName} of each
+ * {@code MBeanServer} request. The object returned by this method
+ * decodes the context from that {@code ObjectName} and applies it
+ * as described for {@link #doWithContext doWithContext} while performing
+ * the {@code MBeanServer} request using the {@code ObjectName} without
+ * the encoded context.</p>
+ *
+ * <p>This forwarder can be used in a number of ways:</p>
+ *
+ * <ul>
+ * <li>
+ * <p>To add context decoding to a local {@code MBeanServer}, you can
+ * write:</p>
+ * <pre>
+ * MBeanServer mbs = {@link
+ * java.lang.management.ManagementFactory#getPlatformMBeanServer()
+ * ManagementFactory.getPlatformMBeanServer()}; // for example
+ * mbs = ClientContext.newContextForwarder(mbs, null);
+ * </pre>
+ *
+ * <li>
+ * <p>To add context decoding to a {@linkplain
+ * javax.management.remote.JMXConnectorServer connector server}:</p>
+ * <pre>
+ * JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(...);
+ * MBeanServer nextMBS = cs.getMBeanServer();
+ * MBeanServerForwarder mbsf = ClientContext.newContextForwarder(nextMBS, null);
+ * cs.{@link
+ * javax.management.remote.JMXConnectorServer#setMBeanServerForwarder
+ * setMBeanServerForwarder}(mbsf);
+ * </pre>
+ *
+ * <li>
+ * <p>For connectors, such as the standard RMI connector, that support
+ * a {@linkplain
+ * javax.management.remote.JMXConnectorServer#getSystemMBeanServerForwarder
+ * system chain} of {@code MBeanServerForwarder}s, this forwarder will
+ * be installed in that chain by default. See
+ * {@link javax.management.remote.JMXConnectorServer#CONTEXT_FORWARDER
+ * JMXConnectorServer.CONTEXT_FORWARDER}.
+ * </p>
+ *
+ * </ul>
+ *
+ * @param nextMBS the next {@code MBeanServer} in the chain of
+ * forwarders, which might be another {@code MBeanServerForwarder} or
+ * a plain {@code MBeanServer}. This is the object to which {@code
+ * MBeanServer} requests that do not include a context are sent. It
+ * will be the value of {@link MBeanServerForwarder#getMBeanServer()
+ * getMBeanServer()} on the returned object, and can be changed with {@link
+ * MBeanServerForwarder#setMBeanServer setMBeanServer}. It can be null but
+ * must be set to a non-null value before any {@code MBeanServer} requests
+ * arrive.
+ *
+ * @param loopMBS the {@code MBeanServer} to which requests that contain
+ * an encoded context should be sent once the context has been decoded.
+ * For example, if the request is {@link MBeanServer#getAttribute
+ * getAttribute}{@code ("jmx.context//jmx.locale=fr//java.lang:type=Runtime",
+ * "Name")}, then the {@linkplain #getContext() context} of the thread
+ * executing that request will have {@code "jmx.locale"} set to {@code "fr"}
+ * while executing {@code loopMBS.getAttribute("java.lang:type=Runtime",
+ * "Name")}. If this parameter is null, then these requests will be
+ * sent to the newly-created {@code MBeanServerForwarder}. Usually
+ * the parameter will either be null or will be the result of {@link
+ * javax.management.remote.JMXConnectorServer#getSystemMBeanServerForwarder
+ * getSystemMBeanServerForwarder()} for the connector server in which
+ * this forwarder will be installed.
+ *
+ * @return a new {@code MBeanServerForwarder} that decodes client context
+ * from {@code ObjectName}s.
+ */
+ /*
+ * What we're building here is confusing enough to need a diagram.
+ * The MBSF that we return is actually the composition of two forwarders:
+ * the first one simulates the existence of the MBean
+ * jmx.context//:type=JMXNamespace, and the second one simulates the
+ * existence of the namespace jmx.context//. Furthermore, that namespace
+ * loops back to the composed forwarder, so that something like
+ * jmx.context//foo=bar//jmxcontext//baz=buh will work. And the loopback
+ * goes through yet another forwarder, which simulates the existence of
+ * (e.g.) jmx.context//foo=bar//:type=JMXNamespace, which is needed
+ * notably so that narrowToNamespace will work.
+ *
+ * | +--------------------------------------------------+
+ * v v |
+ * +----------------+ |
+ * | Handler MBSF |->accesses to jmx.context//:type=JMXNamespace |
+ * +----------------+ (handled completely here) +-------------------+
+ * | | 2nd Handler MBSF |
+ * v +-------------------+
+ * +----------------+ ^
+ * | Namespace MBSF |->accesses to jmx.context//**-------------------+
+ * +----------------+ (after attaching context to thread)
+ * |
+ * v accesses to anything else
+ *
+ * And finally, we need to ensure that from the outside the composed object
+ * looks like a single forwarder, so that its get/setMBeanServer methods
+ * will do the expected thing. That's what the anonymous subclass is for.
+ */
+ public static MBeanServerForwarder newContextForwarder(
+ MBeanServer nextMBS, MBeanServer loopMBS) {
+ final MBeanServerForwarder mbsWrapper =
+ new IdentityMBeanServerForwarder(nextMBS);
+ DynamicMBean handlerMBean = new StandardMBean(
+ new JMXNamespace(mbsWrapper), JMXNamespaceMBean.class, false);
+ SingleMBeanForwarder handlerForwarder = new SingleMBeanForwarder(
+ CLIENT_CONTEXT_NAMESPACE_HANDLER, handlerMBean, true) {
+ @Override
+ public MBeanServer getMBeanServer() {
+ return ((MBeanServerForwarder) super.getMBeanServer()).getMBeanServer();
+ }
+
+ @Override
+ public void setMBeanServer(MBeanServer mbs1) {
+ MBeanServerForwarder mbsf1 = (MBeanServerForwarder)
+ super.getMBeanServer();
+ if (mbsf1 != null)
+ mbsf1.setMBeanServer(mbs1);
+ else
+ super.setMBeanServer(mbs1);
+ mbsWrapper.setMBeanServer(mbs1);
+ }
+ };
+ if (loopMBS == null)
+ loopMBS = handlerForwarder;
+ ContextInvocationHandler contextIH =
+ new ContextInvocationHandler(nextMBS, loopMBS);
+ MBeanServerForwarder contextForwarder = newForwarderProxy(contextIH);
+ handlerForwarder.setMBeanServer(contextForwarder);
+ return handlerForwarder;
+ }
+
+ /**
+ * <p>Create a new {@link MBeanServerForwarder} that localizes
+ * descriptions in {@code MBeanInfo} instances returned by
+ * {@link MBeanServer#getMBeanInfo getMBeanInfo}. The {@code
+ * MBeanServerForwarder} returned by this method passes all {@code
+ * MBeanServer} methods through unchanged to the supplied object, {@code
+ * mbs}, with the exception of {@code getMBeanInfo}. To handle {@code
+ * getMBeanInfo(objectName)}, it calls {@code mbs.getMBeanInfo(objectName)}
+ * to get an {@code MBeanInfo}, {@code mbi}; it calls {@link
+ * MBeanServer#getClassLoaderFor mbs.getClassLoaderFor(objectName)} to
+ * get a {@code ClassLoader}, {@code cl}; and it calls {@link
+ * #getLocale} to get a {@code Locale}, {@code locale}. The order
+ * of these three calls is not specified. Then the result is {@code
+ * mbi.localizeDescriptions(locale, loader)}.</p>
+ *
+ * <p>This forwarder can be used in a number of ways:</p>
+ *
+ * <ul>
+ * <li>
+ * <p>To add description localization to a local {@code MBeanServer}, you
+ * can write:</p>
+ *
+ * <pre>
+ * MBeanServer mbs = {@link
+ * java.lang.management.ManagementFactory#getPlatformMBeanServer()
+ * ManagementFactory.getPlatformMBeanServer()}; // for example
+ * mbs = ClientContext.newLocalizeMBeanInfoForwarder(mbs);
+ * </pre>
+ *
+ * <li>
+ * <p>To add description localization to a {@linkplain
+ * javax.management.remote.JMXConnectorServer connector server}, you will
+ * need to add both a {@linkplain #newContextForwarder context forwarder}
+ * and a localization forwarder, for example like this:</p>
+ *
+ * <pre>
+ * JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(...);
+ * MBeanServer nextMBS = cs.getMBeanServer();
+ * MBeanServerForwarder localizeMBSF =
+ * ClientContext.newLocalizeMBeanInfoForwarder(nextMBS);
+ * MBeanServerForwarder contextMBSF =
+ * ClientContext.newContextForwarder(localizeMBSF, null);
+ * cs.{@link
+ * javax.management.remote.JMXConnectorServer#setMBeanServerForwarder
+ * setMBeanServerForwarder}(contextMBSF);
+ * </pre>
+ *
+ * <p>Notice that the context forwarder must run before the localization
+ * forwarder, so that the locale is correctly established when the latter
+ * runs. So the {@code nextMBS} parameter of the context forwarder must
+ * be the localization forwarder, and not vice versa.</p>
+ *
+ * <li>
+ * <p>For connectors, such as the standard RMI connector, that support
+ * a {@linkplain
+ * javax.management.remote.JMXConnectorServer#getSystemMBeanServerForwarder
+ * system chain} of {@code MBeanServerForwarder}s, the context forwarder and
+ * the localization forwarder will be installed in that chain, in the right
+ * order, if you include
+ * {@link
+ * javax.management.remote.JMXConnectorServer#LOCALIZE_MBEAN_INFO_FORWARDER
+ * LOCALIZE_MBEAN_INFO_FORWARDER} in the environment {@code Map} with
+ * the value {@code "true"}, for example like this:</p>
+ * </p>
+ * <pre>
+ * MBeanServer mbs = ...;
+ * JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://...");
+ * {@code Map<String, Object>} env = new {@code HashMap<String, Object>}();
+ * env.put(JMXConnectorServer.LOCALIZE_MBEAN_INFO_FORWARDER, "true");
+ * JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(
+ * url, env, mbs);
+ * </pre>
+ *
+ * </ul>
+ *
+ * @param mbs the next {@code MBeanServer} in the chain of
+ * forwarders, which might be another {@code MBeanServerForwarder}
+ * or a plain {@code MBeanServer}. It will be the value of
+ * {@link MBeanServerForwarder#getMBeanServer() getMBeanServer()}
+ * on the returned object, and can be changed with {@link
+ * MBeanServerForwarder#setMBeanServer setMBeanServer}. It can be null but
+ * must be set to a non-null value before any {@code MBeanServer} requests
+ * arrive.
+ *
+ * @return a new {@code MBeanServerForwarder} that localizes descriptions
+ * in the result of {@code getMBeanInfo}.
+ */
+ public static MBeanServerForwarder newLocalizeMBeanInfoForwarder(
+ MBeanServer mbs) {
+ return new IdentityMBeanServerForwarder(mbs) {
+ @Override
+ public MBeanInfo getMBeanInfo(ObjectName name)
+ throws InstanceNotFoundException, IntrospectionException,
+ ReflectionException {
+ MBeanInfo mbi = super.getMBeanInfo(name);
+ Locale locale = getLocale();
+ ClassLoader loader = getClassLoaderFor(name);
+ return mbi.localizeDescriptions(locale, loader);
+ }
+ };
+ }
+
+ private static MBeanServerForwarder newForwarderProxy(InvocationHandler ih) {
+ return (MBeanServerForwarder) Proxy.newProxyInstance(
+ MBeanServerForwarder.class.getClassLoader(),
+ new Class<?>[] {MBeanServerForwarder.class},
+ ih);
+ }
+
+ // A proxy connection that will strip the 'contextDir' at input (routing),
+ // and put it back at output (createMBean / registerMBean / query* /
+ // getObjectInstance). Usually RoutingProxy / RoutingServerProxy are used
+ // the other way round (they are used for 'cd' - where they need to add
+ // something at input and remove it at output).
+ // For 'cd' operations we create RoutingProxys with a non empty sourceDir,
+ // and a possibly non-empty targetDir. This is the only case where we use
+ // RoutingProxies with an empty sourceDir (sourceDir is what we add at input
+ // and remove at output, targetDir is what we remove at input and add at
+ // output.
+ //
+ // Note that using a transient ContextRoutingConnection
+ // is possible only because RoutingProxys don't rewrite
+ // notifications sources - otherwise we would have to
+ // keep the ContextRoutingConnection - just to preserve
+ // the 'wrapping listeners'
+ //
+ private static final class ContextRoutingConnection
+ extends RoutingServerProxy {
+ public ContextRoutingConnection(MBeanServer source,
+ String contextDir) {
+ super(source, "", contextDir, false);
+ }
+
+ // Not really needed - but this is safer and more optimized.
+ // See RoutingProxy for more details.
+ //
+ @Override
+ public Integer getMBeanCount() {
+ return source().getMBeanCount();
+ }
+
+ // Not really needed - but this is safer and more optimized.
+ // See RoutingProxy for more details.
+ //
+ @Override
+ public String[] getDomains() {
+ return source().getDomains();
+ }
+
+ // Not really needed - but this is safer and more optimized.
+ // See RoutingProxy for more details.
+ //
+ @Override
+ public String getDefaultDomain() {
+ return source().getDefaultDomain();
+ }
+
+ }
+
+ private static class ContextInvocationHandler implements InvocationHandler {
+ /*
+ * MBeanServer requests that don't include jmx.context//foo=bar//
+ * are forwarded to forwardMBS, which is the unadorned MBeanServer
+ * that knows nothing about the context namespace.
+ * MBeanServer requests that do include this prefix will
+ * usually (depending on the value of the loopMBS parameter to
+ * newContextForwarder) loop back to the combined MBeanServerForwarder
+ * that first implements
+ * jmx.context//:type=JMXNamespace and then implements
+ * jmx.context//foo=bar//. The reason is that it is valid
+ * to have jmx.context//foo=bar//jmx.context//baz=buh//, although
+ * usually that will be combined into jmx.context//foo=bar;baz=buh//.
+ *
+ * Before forwarding to loopMBS, we must check for :type=JMXNamespace
+ * so that jmx.context//foo=bar//:type=JMXNamespace will exist. Its
+ * existence is partial because it must remain "invisible": it should
+ * not show up in queryNames or getMBeanCount even though it does
+ * accept getAttribute and isRegistered and all other methods that
+ * reference a single MBean.
+ */
+ private MBeanServer forwardMBS;
+ private final MBeanServer loopMBS;
+ private static final MBeanServer emptyMBS = new MBeanServerSupport() {
+ @Override
+ public DynamicMBean getDynamicMBeanFor(ObjectName name)
+ throws InstanceNotFoundException {
+ throw new InstanceNotFoundException(name.toString());
+ }
+
+ @Override
+ protected Set<ObjectName> getNames() {
+ return Collections.emptySet();
+ }
+ };
+
+ ContextInvocationHandler(MBeanServer forwardMBS, MBeanServer loopMBS) {
+ this.forwardMBS = forwardMBS;
+ DynamicMBean handlerMBean = new StandardMBean(
+ new JMXNamespace(loopMBS), JMXNamespaceMBean.class, false);
+ MBeanServerForwarder handlerMBS = new SingleMBeanForwarder(
+ NAMESPACE_HANDLER_WITHOUT_NAMESPACE, handlerMBean, false);
+ handlerMBS.setMBeanServer(loopMBS);
+ this.loopMBS = handlerMBS;
+ }
+
+ public Object invoke(Object proxy, final Method method, final Object[] args)
+ throws Throwable {
+ String methodName = method.getName();
+ Class<?>[] paramTypes = method.getParameterTypes();
+
+ // If this is a method from MBeanServerForwarder, handle it here.
+ // There are only two such methods: getMBeanServer() and
+ // setMBeanServer(mbs).
+ if (methodName.equals("getMBeanServer"))
+ return forwardMBS;
+ else if (methodName.equals("setMBeanServer")) {
+ this.forwardMBS = (MBeanServer) args[0];
+ return null;
+ }
+
+ // It is a method from MBeanServer.
+ // Find the first parameter whose declared type is ObjectName,
+ // and see if it is in the context namespace. If so we need to
+ // trigger the logic for that namespace. If not, we simply
+ // forward to the next MBeanServer in the chain. This logic
+ // depends on the fact that if a method in the MBeanServer interface
+ // has a "routing" ObjectName parameter, it is always the first
+ // parameter of that type. Conversely, if a method has an
+ // ObjectName parameter, then it makes sense to "route" that
+ // method. Except for deserialize and instantiate, but if we
+ // recognize a context namespace in those methods' ObjectName
+ // parameters it is pretty harmless.
+ int objectNameI = -1;
+ for (int i = 0; i < paramTypes.length; i++) {
+ if (paramTypes[i] == ObjectName.class) {
+ objectNameI = i;
+ break;
+ }
+ }
+
+ if (objectNameI < 0)
+ return invoke(method, forwardMBS, args);
+
+ ObjectName target = (ObjectName) args[objectNameI];
+ if (target == null ||
+ !target.getDomain().startsWith(NAMESPACE_PLUS_SEP))
+ return invoke(method, forwardMBS, args);
+
+ String domain = target.getDomain().substring(NAMESPACE_PLUS_SEP.length());
+
+ // The method routes through the (simulated) context namespace.
+ // Decode the context after it, e.g. jmx.context//jmx.locale=fr//...
+ // If there is no context part, we can throw an exception,
+ // because a forwarder has already handled the unique MBean
+ // jmx.context//:type=JMXNamespace.
+ int sep = domain.indexOf(NAMESPACE_SEPARATOR);
+ if (sep < 0)
+ return invoke(method, emptyMBS, args); // throw exception
+ final String encodedContext = domain.substring(0, sep);
+
+ if (method.getName().startsWith("query") &&
+ (encodedContext.contains("*") || encodedContext.contains("?"))) {
+ // Queries like jmx.context//*//d:k=v return
+ // an empty set, consistent with "real" namespaces.
+ return Collections.EMPTY_SET;
+ }
+
+ Map<String, String> ctx = new TreeMap<String, String>(getContext());
+ ctx.putAll(stringToMap(encodedContext));
+
+ return doWithContext(ctx, new Callable<Object>() {
+ public Object call() throws Exception {
+ // Create a proxy connection that will strip
+ // "jmx.context//" + encodedContext + "//" on input,
+ // and put it back on output.
+ //
+ // Note that using a transient ContextRoutingConnection
+ // is possible only because it doesn't rewrite
+ // notification sources - otherwise we would have to
+ // keep the ContextRoutingConnection - just to preserve
+ // the 'wrapping listeners'
+ //
+ String namespace = NAMESPACE_PLUS_SEP + encodedContext;
+ final ContextRoutingConnection route =
+ new ContextRoutingConnection(loopMBS, namespace);
+
+ if (LOG.isLoggable(Level.FINE))
+ LOG.fine("context="+encodedContext);
+ if (LOG.isLoggable(Level.FINER))
+ LOG.finer(method.getName()+""+
+ ((args==null)?"()":(""+Arrays.asList(args))));
+
+ return invoke(method, route, args);
+ }
+ });
+ }
+
+ private static Object invoke(Method method, Object target, Object[] args)
+ throws Exception {
+ try {
+ return method.invoke(target, args);
+ } catch (InvocationTargetException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof Error)
+ throw (Error) cause;
+ throw (Exception) cause;
+ }
+ }
+ }
+
+ private static String mapToString(Map<String, String> map) {
+ StringBuilder sb = new StringBuilder();
+ for (Map.Entry<String, String> entry : map.entrySet()) {
+ String key = encode(entry.getKey());
+ String value = encode(entry.getValue());
+ if (sb.length() > 0)
+ sb.append(";");
+ sb.append(key).append("=").append(value);
+ }
+ return sb.toString();
+ }
+
+ private static Map<String, String> stringToMap(String encodedContext) {
+ Map<String, String> map = stringToMapOrNull(encodedContext);
+ if (map == null) {
+ throw new IllegalArgumentException(
+ "Invalid encoded context: " + encodedContext);
+ }
+ return map;
+ }
+
+ private static Map<String, String> stringToMapOrNull(String encodedContext) {
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ StringTokenizer stok = new StringTokenizer(encodedContext, ";");
+ while (stok.hasMoreTokens()) {
+ String tok = stok.nextToken();
+ int eq = tok.indexOf('=');
+ if (eq < 0)
+ return null;
+ String key = decode(tok.substring(0, eq));
+ if (key.equals(""))
+ return null;
+ String value = decode(tok.substring(eq + 1));
+ map.put(key, value);
+ }
+ return map;
+ }
+
+ private static String encode(String s) {
+ try {
+ s = URLEncoder.encode(s, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e); // Should not happen
+ }
+ return s.replace("*", "%2A");
+ // The * character is left intact in URL encodings, but for us it
+ // is special (an ObjectName wildcard) so we must map it.
+ // We are assuming that URLDecoder will decode it the same way as any
+ // other hex escape.
+ }
+
+ private static String decode(String s) {
+ try {
+ return URLDecoder.decode(s, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/jdk/src/share/classes/javax/management/Descriptor.java b/jdk/src/share/classes/javax/management/Descriptor.java
index a74fb11..b9c98f4 100644
--- a/jdk/src/share/classes/javax/management/Descriptor.java
+++ b/jdk/src/share/classes/javax/management/Descriptor.java
@@ -35,8 +35,8 @@
// Javadoc imports:
import java.lang.management.MemoryUsage;
import java.util.Arrays;
+import java.util.Locale;
import java.util.ResourceBundle;
-
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.MXBeanMappingFactory;
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
@@ -118,19 +118,22 @@
* deprecation, for example {@code "1.3 Replaced by the Capacity
* attribute"}.</td>
*
- * <tr id="descriptionResourceBundleBaseName">
- * <td>descriptionResource<br>BundleBaseName</td><td>String</td><td>Any</td>
+ * <tr><td id="descriptionResourceBundleBaseName"><i>descriptionResource<br>
+ * BundleBaseName</i></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"}.</td>
+ * {@code "com.example.myapp.MBeanResources"}. See
+ * {@link MBeanInfo#localizeDescriptions MBeanInfo.localizeDescriptions}.</td>
*
- * <tr id="descriptionResourceKey">
- * <td>descriptionResourceKey</td><td>String</td><td>Any</td>
+ * <tr><td id="descriptionResourceKey"><i>descriptionResourceKey</i></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.</td>
+ * this can be used to find a localized version of the description.
+ * See {@link MBeanInfo#localizeDescriptions MBeanInfo.localizeDescriptions}.
+ * </td>
*
* <tr><td>enabled</td><td>String</td>
* <td>MBeanAttributeInfo<br>MBeanNotificationInfo<br>MBeanOperationInfo</td>
@@ -157,11 +160,11 @@
* href="MBeanInfo.html#info-changed">{@code "jmx.mbean.info.changed"}</a>
* notification.</td>
*
- * <tr><td>infoTimeout</td><td>String<br>Long</td><td>MBeanInfo</td>
+ * <tr id="infoTimeout"><td>infoTimeout</td><td>String<br>Long</td><td>MBeanInfo</td>
*
- * <td id="infoTimeout">The time in milli-seconds that the MBeanInfo can
- * reasonably be expected to be unchanged. The value can be a {@code Long}
- * or a decimal string. This provides a hint from a DynamicMBean or any
+ * <td>The time in milli-seconds that the MBeanInfo can reasonably be
+ * expected to be unchanged. The value can be a {@code Long} or a
+ * decimal string. This provides a hint from a DynamicMBean or any
* MBean that does not define {@code immutableInfo} as {@code true}
* that the MBeanInfo is not likely to change within this period and
* therefore can be cached. When this field is missing or has the
@@ -185,6 +188,13 @@
* <td>Legal values for an attribute or parameter. See
* {@link javax.management.openmbean}.</td>
*
+ * <tr id="locale"><td><i>locale</i></td>
+ * <td>String</td><td>Any</td>
+ *
+ * <td>The {@linkplain Locale locale} of the description in this
+ * {@code MBeanInfo}, {@code MBeanAttributeInfo}, etc, as returned
+ * by {@link Locale#toString()}.</td>
+ *
* <tr id="maxValue"><td><i>maxValue</i><td>Object</td>
* <td>MBeanAttributeInfo<br>MBeanParameterInfo</td>
*
diff --git a/jdk/src/share/classes/javax/management/JMX.java b/jdk/src/share/classes/javax/management/JMX.java
index ac7468d..60b9605 100644
--- a/jdk/src/share/classes/javax/management/JMX.java
+++ b/jdk/src/share/classes/javax/management/JMX.java
@@ -30,6 +30,7 @@
import com.sun.jmx.remote.util.ClassLogger;
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
+import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
@@ -37,6 +38,7 @@
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.TreeMap;
+import javax.management.namespace.JMXNamespaces;
import javax.management.openmbean.MXBeanMappingFactory;
/**
@@ -60,6 +62,21 @@
*/
public static final String DEFAULT_VALUE_FIELD = "defaultValue";
+ /**
+ * The name of the <a
+ * href="Descriptor.html#descriptionResourceBundleBaseName">{@code
+ * descriptionResourceBundleBaseName}</a> field.
+ */
+ public static final String DESCRIPTION_RESOURCE_BUNDLE_BASE_NAME_FIELD =
+ "descriptionResourceBundleBaseName";
+
+ /**
+ * The name of the <a href="Descriptor.html#descriptionResourceKey">{@code
+ * descriptionResourceKey}</a> field.
+ */
+ public static final String DESCRIPTION_RESOURCE_KEY_FIELD =
+ "descriptionResourceKey";
+
/**
* The name of the <a href="Descriptor.html#immutableInfo">{@code
* immutableInfo}</a> field.
@@ -79,6 +96,12 @@
public static final String LEGAL_VALUES_FIELD = "legalValues";
/**
+ * The name of the <a href="Descriptor.html#locale">{@code locale}</a>
+ * field.
+ */
+ public static final String LOCALE_FIELD = "locale";
+
+ /**
* The name of the <a href="Descriptor.html#maxValue">{@code
* maxValue}</a> field.
*/
@@ -120,13 +143,12 @@
* <p>Options to apply to an MBean proxy or to an instance of {@link
* StandardMBean}.</p>
*
- * <p>For example, to specify a custom {@link MXBeanMappingFactory}
- * for a {@code StandardMBean}, you might write this:</p>
+ * <p>For example, to specify the "wrapped object visible" option for a
+ * {@code StandardMBean}, you might write this:</p>
*
* <pre>
- * MXBeanMappingFactory factory = new MyMXBeanMappingFactory();
- * JMX.MBeanOptions opts = new JMX.MBeanOptions();
- * opts.setMXBeanMappingFactory(factory);
+ * StandardMBean.Options opts = new StandardMBean.Options();
+ * opts.setWrappedObjectVisible(true);
* StandardMBean mbean = new StandardMBean(impl, intf, opts);
* </pre>
*
@@ -808,4 +830,80 @@
((DynamicWrapperMBean) mbean).getWrappedObject() : mbean;
return (MBeanInjector.injectsSendNotification(resource));
}
+
+ /**
+ * <p>Return the version of the JMX specification that a (possibly remote)
+ * MBean Server is using. The JMX specification described in this
+ * documentation is version 2.0. The earlier versions that might be
+ * reported by this method are 1.0, 1.1, 1.2, and 1.4. (There is no 1.3.)
+ * All of these versions and all future versions can be compared using
+ * {@link String#compareTo(String)}. So, for example, to tell if
+ * {@code mbsc} is running at least version 2.0 you can write:</p>
+ *
+ * <pre>
+ * String version = JMX.getSpecificationVersion(mbsc, null);
+ * boolean atLeast2dot0 = (version.compareTo("2.0") >= 0);
+ * </pre>
+ *
+ * <p>A remote MBean Server might be running an earlier version of the
+ * JMX API, and in that case <a href="package-summary.html#interop">certain
+ * features</a> might not be available in it.</p>
+ *
+ * <p>The version of the MBean Server {@code mbsc} is not necessarily
+ * the version of all namespaces within that MBean Server, for example
+ * if some of them use {@link javax.management.namespace.JMXRemoteNamespace
+ * JMXRemoteNamespace}. To determine the version of the namespace
+ * that a particular MBean is in, give its name as the {@code mbeanName}
+ * parameter.</p>
+ *
+ * @param mbsc a connection to an MBean Server.
+ *
+ * @param mbeanName the name of an MBean within that MBean Server, or null.
+ * If non-null, the namespace of this name, as determined by
+ * {@link JMXNamespaces#getContainingNamespace
+ * JMXNamespaces.getContainingNamespace}, is the one whose specification
+ * version will be returned.
+ *
+ * @return the JMX specification version reported by that MBean Server.
+ *
+ * @throws IllegalArgumentException if {@code mbsc} is null, or if
+ * {@code mbeanName} includes a wildcard character ({@code *} or {@code ?})
+ * in its namespace.
+ *
+ * @throws IOException if the version cannot be obtained, either because
+ * there is a communication problem or because the remote MBean Server
+ * does not have the appropriate {@linkplain
+ * MBeanServerDelegateMBean#getSpecificationVersion() attribute}.
+ *
+ * @see <a href="package-summary.html#interop">Interoperability between
+ * versions of the JMX specification</a>
+ * @see MBeanServerDelegateMBean#getSpecificationVersion
+ */
+ public static String getSpecificationVersion(
+ MBeanServerConnection mbsc, ObjectName mbeanName)
+ throws IOException {
+ if (mbsc == null)
+ throw new IllegalArgumentException("Null MBeanServerConnection");
+
+ String namespace;
+ if (mbeanName == null)
+ namespace = "";
+ else
+ namespace = JMXNamespaces.getContainingNamespace(mbeanName);
+ if (namespace.contains("*") || namespace.contains("?")) {
+ throw new IllegalArgumentException(
+ "ObjectName contains namespace wildcard: " + mbeanName);
+ }
+
+ try {
+ if (namespace.length() > 0)
+ mbsc = JMXNamespaces.narrowToNamespace(mbsc, namespace);
+ return (String) mbsc.getAttribute(
+ MBeanServerDelegate.DELEGATE_NAME, "SpecificationVersion");
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ }
}
diff --git a/jdk/src/share/classes/javax/management/MBeanInfo.java b/jdk/src/share/classes/javax/management/MBeanInfo.java
index 3561e3c..49973c6 100644
--- a/jdk/src/share/classes/javax/management/MBeanInfo.java
+++ b/jdk/src/share/classes/javax/management/MBeanInfo.java
@@ -25,6 +25,7 @@
package javax.management;
+import com.sun.jmx.mbeanserver.Util;
import java.io.IOException;
import java.io.StreamCorruptedException;
import java.io.Serializable;
@@ -37,6 +38,12 @@
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import static javax.management.ImmutableDescriptor.nonNullDescriptor;
/**
@@ -290,6 +297,7 @@
* <p>Since this class is immutable, the clone method is chiefly of
* interest to subclasses.</p>
*/
+ @Override
public Object clone () {
try {
return super.clone() ;
@@ -474,6 +482,7 @@
return (Descriptor) nonNullDescriptor(descriptor).clone();
}
+ @Override
public String toString() {
return
getClass().getName() + "[" +
@@ -505,6 +514,7 @@
* @return true if and only if <code>o</code> is an MBeanInfo that is equal
* to this one according to the rules above.
*/
+ @Override
public boolean equals(Object o) {
if (o == this)
return true;
@@ -524,6 +534,7 @@
Arrays.equals(p.fastGetNotifications(), fastGetNotifications()));
}
+ @Override
public int hashCode() {
/* Since computing the hashCode is quite expensive, we cache it.
If by some terrible misfortune the computed value is 0, the
@@ -747,4 +758,377 @@
throw new StreamCorruptedException("Got unexpected byte.");
}
}
+
+ /**
+ * <p>Return an {@code MBeanInfo} object that is the same as this one
+ * except that its descriptions are localized in the given locale.
+ * This means the text returned by {@link MBeanInfo#getDescription}
+ * (the description of the MBean itself), and the text returned by the
+ * {@link MBeanFeatureInfo#getDescription getDescription()} method
+ * for every {@linkplain MBeanAttributeInfo attribute}, {@linkplain
+ * MBeanOperationInfo operation}, {@linkplain MBeanConstructorInfo
+ * constructor}, and {@linkplain MBeanNotificationInfo notification}
+ * contained in the {@code MBeanInfo}.</p>
+ *
+ * <p>Here is how the description {@code this.getDescription()} is
+ * localized.</p>
+ *
+ * <p>First, if the {@linkplain #getDescriptor() descriptor}
+ * of this {@code MBeanInfo} contains a field <code><a
+ * href="Descriptor.html#locale">"locale"</a></code>, and the value of
+ * the field is the same as {@code locale.toString()}, then this {@code
+ * MBeanInfo} is returned. Otherwise, localization proceeds as follows,
+ * and the {@code "locale"} field in the returned {@code MBeanInfo} will
+ * be {@code locale.toString()}.
+ *
+ * <p>A <em>{@code className}</em> is determined. If this
+ * {@code MBeanInfo} contains a descriptor with the field
+ * <a href="Descriptor.html#interfaceClassName">{@code
+ * "interfaceClassName"}</a>, then the value of that field is the
+ * {@code className}. Otherwise, it is {@link #getClassName()}.
+ * Everything before the last period (.) in the {@code className} is
+ * the <em>{@code package}</em>, and everything after is the <em>{@code
+ * simpleClassName}</em>. (If there is no period, then the {@code package}
+ * is empty and the {@code simpleClassName} is the same as the {@code
+ * className}.)</p>
+ *
+ * <p>A <em>{@code resourceKey}</em> is determined. If this {@code
+ * MBeanInfo} contains a {@linkplain MBeanInfo#getDescriptor() descriptor}
+ * with a field {@link JMX#DESCRIPTION_RESOURCE_KEY_FIELD
+ * "descriptionResourceKey"}, the value of the field is
+ * the {@code resourceKey}. Otherwise, the {@code resourceKey} is {@code
+ * simpleClassName + ".mbean"}.</p>
+ *
+ * <p>A <em>{@code resourceBundleBaseName}</em> is determined. If
+ * this {@code MBeanInfo} contains a descriptor with a field {@link
+ * JMX#DESCRIPTION_RESOURCE_BUNDLE_BASE_NAME_FIELD
+ * "descriptionResourceBundleBaseName"}, the value of the field
+ * is the {@code resourceBundleBaseName}. Otherwise, the {@code
+ * resourceBundleBaseName} is {@code package + ".MBeanDescriptions"}.
+ *
+ * <p>Then, a {@link java.util.ResourceBundle ResourceBundle} is
+ * determined, using<br> {@link java.util.ResourceBundle#getBundle(String,
+ * Locale, ClassLoader) ResourceBundle.getBundle(resourceBundleBaseName,
+ * locale, loader)}. If this succeeds, and if {@link
+ * java.util.ResourceBundle#getString(String) getString(resourceKey)}
+ * returns a string, then that string is the localized description.
+ * Otherwise, the original description is unchanged.</p>
+ *
+ * <p>A localized description for an {@code MBeanAttributeInfo} is
+ * obtained similarly. The default {@code resourceBundleBaseName}
+ * is the same as above. The default description and the
+ * descriptor fields {@code "descriptionResourceKey"} and {@code
+ * "descriptionResourceBundleBaseName"} come from the {@code
+ * MBeanAttributeInfo} rather than the {@code MBeanInfo}. If the
+ * attribute's {@linkplain MBeanFeatureInfo#getName() name} is {@code
+ * Foo} then its default {@code resourceKey} is {@code simpleClassName +
+ * ".attribute.Foo"}.</p>
+ *
+ * <p>Similar rules apply for operations, constructors, and notifications.
+ * If the name of the operation, constructor, or notification is {@code
+ * Foo} then the default {@code resourceKey} is respectively {@code
+ * simpleClassName + ".operation.Foo"}, {@code simpleClassName +
+ * ".constructor.Foo"}, or {@code simpleClassName + ".notification.Foo"}.
+ * If two operations or constructors have the same name (overloading) then
+ * they have the same default {@code resourceKey}; if different localized
+ * descriptions are needed then a non-default key must be supplied using
+ * {@code "descriptionResourceKey"}.</p>
+ *
+ * <p>Similar rules also apply for descriptions of parameters ({@link
+ * MBeanParameterInfo}). The default {@code resourceKey} for a parameter
+ * whose {@linkplain MBeanFeatureInfo#getName() name} is {@code
+ * Bar} in an operation or constructor called {@code Foo} is {@code
+ * simpleClassName + ".operation.Foo.Bar"} or {@code simpleClassName +
+ * ".constructor.Foo.Bar"} respectively.</p>
+ *
+ * <h4>Example</h4>
+ *
+ * <p>Suppose you have an MBean defined by these two Java source files:</p>
+ *
+ * <pre>
+ * // ConfigurationMBean.java
+ * package com.example;
+ * public interface ConfigurationMBean {
+ * public String getName();
+ * public void save(String fileName);
+ * }
+ *
+ * // Configuration.java
+ * package com.example;
+ * public class Configuration implements ConfigurationMBean {
+ * public Configuration(String defaultName) {
+ * ...
+ * }
+ * ...
+ * }
+ * </pre>
+ *
+ * <p>Then you could define the default descriptions for the MBean, by
+ * including a resource bundle called {@code com/example/MBeanDescriptions}
+ * with the compiled classes. Most often this is done by creating a file
+ * {@code MBeanDescriptions.properties} in the same directory as {@code
+ * ConfigurationMBean.java}. Make sure that this file is copied into the
+ * same place as the compiled classes; in typical build environments that
+ * will be true by default.</p>
+ *
+ * <p>The file {@code com/example/MBeanDescriptions.properties} might
+ * look like this:</p>
+ *
+ * <pre>
+ * # Description of the MBean
+ * ConfigurationMBean.mbean = Configuration manager
+ *
+ * # Description of the Name attribute
+ * ConfigurationMBean.attribute.Name = The name of the configuration
+ *
+ * # Description of the save operation
+ * ConfigurationMBean.operation.save = Save the configuration to a file
+ *
+ * # Description of the parameter to the save operation.
+ * # Parameter names from the original Java source are not available,
+ * # so the default names are p1, p2, etc. If the names were available,
+ * # this would be ConfigurationMBean.operation.save.fileName
+ * ConfigurationMBean.operation.save.p1 = The name of the file
+ *
+ * # Description of the constructor. The default name of a constructor is
+ * # its fully-qualified class name.
+ * ConfigurationMBean.constructor.com.example.Configuration = <!--
+ * -->Constructor with name of default file
+ * # Description of the constructor parameter.
+ * ConfigurationMBean.constructor.com.example.Configuration.p1 = <!--
+ * -->Name of the default file
+ * </pre>
+ *
+ * <p>Starting with this file, you could create descriptions for the French
+ * locale by creating {@code com/example/MBeanDescriptions_fr.properties}.
+ * The keys in this file are the same as before but the text has been
+ * translated:
+ *
+ * <pre>
+ * ConfigurationMBean.mbean = Gestionnaire de configuration
+ *
+ * ConfigurationMBean.attribute.Name = Le nom de la configuration
+ *
+ * ConfigurationMBean.operation.save = Sauvegarder la configuration <!--
+ * -->dans un fichier
+ *
+ * ConfigurationMBean.operation.save.p1 = Le nom du fichier
+ *
+ * ConfigurationMBean.constructor.com.example.Configuration = <!--
+ * -->Constructeur avec nom du fichier par défaut
+ * ConfigurationMBean.constructor.com.example.Configuration.p1 = <!--
+ * -->Nom du fichier par défaut
+ * </pre>
+ *
+ * <p>The descriptions in {@code MBeanDescriptions.properties} and
+ * {@code MBeanDescriptions_fr.properties} will only be consulted if
+ * {@code localizeDescriptions} is called, perhaps because the
+ * MBean Server has been wrapped by {@link
+ * ClientContext#newLocalizeMBeanInfoForwarder} or because the
+ * connector server has been created with the {@link
+ * javax.management.remote.JMXConnectorServer#LOCALIZE_MBEAN_INFO_FORWARDER
+ * LOCALIZE_MBEAN_INFO_FORWARDER} option. If you want descriptions
+ * even when there is no localization step, then you should consider
+ * using {@link Description @Description} annotations. Annotations
+ * provide descriptions by default but are overridden if {@code
+ * localizeDescriptions} is called.</p>
+ *
+ * @param locale the target locale for descriptions. Cannot be null.
+ *
+ * @param loader the {@code ClassLoader} to use for looking up resource
+ * bundles.
+ *
+ * @return an {@code MBeanInfo} with descriptions appropriately localized.
+ *
+ * @throws NullPointerException if {@code locale} is null.
+ */
+ public MBeanInfo localizeDescriptions(Locale locale, ClassLoader loader) {
+ if (locale == null)
+ throw new NullPointerException("locale");
+ Descriptor d = getDescriptor();
+ String mbiLocaleString = (String) d.getFieldValue(JMX.LOCALE_FIELD);
+ if (locale.toString().equals(mbiLocaleString))
+ return this;
+ return new Rewriter(this, locale, loader).getMBeanInfo();
+ }
+
+ private static class Rewriter {
+ private final MBeanInfo mbi;
+ private final ClassLoader loader;
+ private final Locale locale;
+ private final String packageName;
+ private final String simpleClassNamePlusDot;
+ private ResourceBundle defaultBundle;
+ private boolean defaultBundleLoaded;
+
+ // ResourceBundle.getBundle throws NullPointerException
+ // if the loader is null, even though that is perfectly
+ // valid and means the bootstrap loader. So we work
+ // around with a ClassLoader that is equivalent to the
+ // bootstrap loader but is not null.
+ private static final ClassLoader bootstrapLoader =
+ new ClassLoader(null) {};
+
+ Rewriter(MBeanInfo mbi, Locale locale, ClassLoader loader) {
+ this.mbi = mbi;
+ this.locale = locale;
+ if (loader == null)
+ loader = bootstrapLoader;
+ this.loader = loader;
+
+ String intfName = (String)
+ mbi.getDescriptor().getFieldValue("interfaceClassName");
+ if (intfName == null)
+ intfName = mbi.getClassName();
+ int lastDot = intfName.lastIndexOf('.');
+ this.packageName = intfName.substring(0, lastDot + 1);
+ this.simpleClassNamePlusDot = intfName.substring(lastDot + 1) + ".";
+ // Inner classes show up as Outer$Inner so won't match the dot.
+ // When there is no dot, lastDot is -1,
+ // packageName is empty, and simpleClassNamePlusDot is intfName.
+ }
+
+ MBeanInfo getMBeanInfo() {
+ MBeanAttributeInfo[] mbais =
+ rewrite(mbi.getAttributes(), "attribute.");
+ MBeanOperationInfo[] mbois =
+ rewrite(mbi.getOperations(), "operation.");
+ MBeanConstructorInfo[] mbcis =
+ rewrite(mbi.getConstructors(), "constructor.");
+ MBeanNotificationInfo[] mbnis =
+ rewrite(mbi.getNotifications(), "notification.");
+ Descriptor d = mbi.getDescriptor();
+ d = changeLocale(d);
+ String description = getDescription(d, "mbean", "");
+ if (description == null)
+ description = mbi.getDescription();
+ return new MBeanInfo(
+ mbi.getClassName(), description,
+ mbais, mbcis, mbois, mbnis, d);
+ }
+
+ private Descriptor changeLocale(Descriptor d) {
+ if (d.getFieldValue(JMX.LOCALE_FIELD) != null) {
+ Map<String, Object> map = new HashMap<String, Object>();
+ for (String field : d.getFieldNames())
+ map.put(field, d.getFieldValue(field));
+ map.remove(JMX.LOCALE_FIELD);
+ d = new ImmutableDescriptor(map);
+ }
+ return ImmutableDescriptor.union(
+ d, new ImmutableDescriptor(JMX.LOCALE_FIELD + "=" + locale));
+ }
+
+ private String getDescription(
+ Descriptor d, String defaultPrefix, String defaultSuffix) {
+ ResourceBundle bundle = bundleFromDescriptor(d);
+ if (bundle == null)
+ return null;
+ String key =
+ (String) d.getFieldValue(JMX.DESCRIPTION_RESOURCE_KEY_FIELD);
+ if (key == null)
+ key = simpleClassNamePlusDot + defaultPrefix + defaultSuffix;
+ return descriptionFromResource(bundle, key);
+ }
+
+ private <T extends MBeanFeatureInfo> T[] rewrite(
+ T[] features, String resourcePrefix) {
+ for (int i = 0; i < features.length; i++) {
+ T feature = features[i];
+ Descriptor d = feature.getDescriptor();
+ String description =
+ getDescription(d, resourcePrefix, feature.getName());
+ if (description != null &&
+ !description.equals(feature.getDescription())) {
+ features[i] = setDescription(feature, description);
+ }
+ }
+ return features;
+ }
+
+ private <T extends MBeanFeatureInfo> T setDescription(
+ T feature, String description) {
+
+ Object newf;
+ String name = feature.getName();
+ Descriptor d = feature.getDescriptor();
+
+ if (feature instanceof MBeanAttributeInfo) {
+ MBeanAttributeInfo mbai = (MBeanAttributeInfo) feature;
+ newf = new MBeanAttributeInfo(
+ name, mbai.getType(), description,
+ mbai.isReadable(), mbai.isWritable(), mbai.isIs(),
+ d);
+ } else if (feature instanceof MBeanOperationInfo) {
+ MBeanOperationInfo mboi = (MBeanOperationInfo) feature;
+ MBeanParameterInfo[] sig = rewrite(
+ mboi.getSignature(), "operation." + name + ".");
+ newf = new MBeanOperationInfo(
+ name, description, sig,
+ mboi.getReturnType(), mboi.getImpact(), d);
+ } else if (feature instanceof MBeanConstructorInfo) {
+ MBeanConstructorInfo mbci = (MBeanConstructorInfo) feature;
+ MBeanParameterInfo[] sig = rewrite(
+ mbci.getSignature(), "constructor." + name + ".");
+ newf = new MBeanConstructorInfo(
+ name, description, sig, d);
+ } else if (feature instanceof MBeanNotificationInfo) {
+ MBeanNotificationInfo mbni = (MBeanNotificationInfo) feature;
+ newf = new MBeanNotificationInfo(
+ mbni.getNotifTypes(), name, description, d);
+ } else if (feature instanceof MBeanParameterInfo) {
+ MBeanParameterInfo mbpi = (MBeanParameterInfo) feature;
+ newf = new MBeanParameterInfo(
+ name, mbpi.getType(), description, d);
+ } else {
+ logger().log(Level.FINE, "Unknown feature type: " +
+ feature.getClass());
+ newf = feature;
+ }
+
+ return Util.<T>cast(newf);
+ }
+
+ private ResourceBundle bundleFromDescriptor(Descriptor d) {
+ String bundleName = (String) d.getFieldValue(
+ JMX.DESCRIPTION_RESOURCE_BUNDLE_BASE_NAME_FIELD);
+
+ if (bundleName != null)
+ return getBundle(bundleName);
+
+ if (defaultBundleLoaded)
+ return defaultBundle;
+
+ bundleName = packageName + "MBeanDescriptions";
+ defaultBundle = getBundle(bundleName);
+ defaultBundleLoaded = true;
+ return defaultBundle;
+ }
+
+ private String descriptionFromResource(
+ ResourceBundle bundle, String key) {
+ try {
+ return bundle.getString(key);
+ } catch (MissingResourceException e) {
+ logger().log(Level.FINEST, "No resource for " + key, e);
+ } catch (Exception e) {
+ logger().log(Level.FINE, "Bad resource for " + key, e);
+ }
+ return null;
+ }
+
+ private ResourceBundle getBundle(String name) {
+ try {
+ return ResourceBundle.getBundle(name, locale, loader);
+ } catch (Exception e) {
+ logger().log(Level.FINE,
+ "Could not load ResourceBundle " + name, e);
+ return null;
+ }
+ }
+
+ private Logger logger() {
+ return Logger.getLogger("javax.management.locale");
+ }
+ }
}
diff --git a/jdk/src/share/classes/javax/management/MBeanServerConnection.java b/jdk/src/share/classes/javax/management/MBeanServerConnection.java
index 16ce58b..fadebc1 100644
--- a/jdk/src/share/classes/javax/management/MBeanServerConnection.java
+++ b/jdk/src/share/classes/javax/management/MBeanServerConnection.java
@@ -532,8 +532,30 @@
/**
- * Enables the values of several attributes of a named MBean. The MBean
- * is identified by its object name.
+ * <p>Retrieves the values of several attributes of a named MBean. The MBean
+ * is identified by its object name.</p>
+ *
+ * <p>If one or more attributes cannot be retrieved for some reason, they
+ * will be omitted from the returned {@code AttributeList}. The caller
+ * should check that the list is the same size as the {@code attributes}
+ * array. To discover what problem prevented a given attribute from being
+ * retrieved, call {@link #getAttribute getAttribute} for that attribute.</p>
+ *
+ * <p>Here is an example of calling this method and checking that it
+ * succeeded in retrieving all the requested attributes:</p>
+ *
+ * <pre>
+ * String[] attrNames = ...;
+ * AttributeList list = mbeanServerConnection.getAttributes(objectName, attrNames);
+ * if (list.size() == attrNames.length)
+ * System.out.println("All attributes were retrieved successfully");
+ * else {
+ * {@code List<String>} missing = new {@code ArrayList<String>}(<!--
+ * -->{@link java.util.Arrays#asList Arrays.asList}(attrNames));
+ * missing.removeAll(list.toMap().keySet());
+ * System.out.println("Did not retrieve: " + missing);
+ * }
+ * </pre>
*
* @param name The object name of the MBean from which the
* attributes are retrieved.
@@ -557,6 +579,7 @@
throws InstanceNotFoundException, ReflectionException,
IOException;
+
/**
* Sets the value of a specific attribute of a named MBean. The MBean
* is identified by its object name.
@@ -592,10 +615,36 @@
ReflectionException, IOException;
-
/**
- * Sets the values of several attributes of a named MBean. The MBean is
- * identified by its object name.
+ * <p>Sets the values of several attributes of a named MBean. The MBean is
+ * identified by its object name.</p>
+ *
+ * <p>If one or more attributes cannot be set for some reason, they will be
+ * omitted from the returned {@code AttributeList}. The caller should check
+ * that the input {@code AttributeList} is the same size as the output one.
+ * To discover what problem prevented a given attribute from being retrieved,
+ * it will usually be possible to call {@link #setAttribute setAttribute}
+ * for that attribute, although this is not guaranteed to work. (For
+ * example, the values of two attributes may have been rejected because
+ * they were inconsistent with each other. Setting one of them alone might
+ * be allowed.)<p>
+ *
+ * <p>Here is an example of calling this method and checking that it
+ * succeeded in setting all the requested attributes:</p>
+ *
+ * <pre>
+ * AttributeList inputAttrs = ...;
+ * AttributeList outputAttrs = mbeanServerConnection.setAttributes(<!--
+ * -->objectName, inputAttrs);
+ * if (inputAttrs.size() == outputAttrs.size())
+ * System.out.println("All attributes were set successfully");
+ * else {
+ * {@code List<String>} missing = new {@code ArrayList<String>}(<!--
+ * -->inputAttrs.toMap().keySet());
+ * missing.removeAll(outputAttrs.toMap().keySet());
+ * System.out.println("Did not set: " + missing);
+ * }
+ * </pre>
*
* @param name The object name of the MBean within which the
* attributes are to be set.
@@ -622,7 +671,39 @@
throws InstanceNotFoundException, ReflectionException, IOException;
/**
- * Invokes an operation on an MBean.
+ * <p>Invokes an operation on an MBean.</p>
+ *
+ * <p>Because of the need for a {@code signature} to differentiate
+ * possibly-overloaded operations, it is much simpler to invoke operations
+ * through an {@linkplain JMX#newMBeanProxy(MBeanServerConnection, ObjectName,
+ * Class) MBean proxy} where possible. For example, suppose you have a
+ * Standard MBean interface like this:</p>
+ *
+ * <pre>
+ * public interface FooMBean {
+ * public int countMatches(String[] patterns, boolean ignoreCase);
+ * }
+ * </pre>
+ *
+ * <p>The {@code countMatches} operation can be invoked as follows:</p>
+ *
+ * <pre>
+ * String[] myPatterns = ...;
+ * int count = (Integer) mbeanServerConnection.invoke(
+ * objectName,
+ * "countMatches",
+ * new Object[] {myPatterns, true},
+ * new String[] {String[].class.getName(), boolean.class.getName()});
+ * </pre>
+ *
+ * <p>Alternatively, it can be invoked through a proxy as follows:</p>
+ *
+ * <pre>
+ * String[] myPatterns = ...;
+ * FooMBean fooProxy = JMX.newMBeanProxy(
+ * mbeanServerConnection, objectName, FooMBean.class);
+ * int count = fooProxy.countMatches(myPatterns, true);
+ * </pre>
*
* @param name The object name of the MBean on which the method is
* to be invoked.
@@ -630,7 +711,8 @@
* @param params An array containing the parameters to be set when
* the operation is invoked
* @param signature An array containing the signature of the
- * operation. The class objects will be loaded using the same
+ * operation, an array of class names in the format returned by
+ * {@link Class#getName()}. The class objects will be loaded using the same
* class loader as the one used for loading the MBean on which the
* operation was invoked.
*
diff --git a/jdk/src/share/classes/javax/management/MBeanServerNotification.java b/jdk/src/share/classes/javax/management/MBeanServerNotification.java
index 723d2d4..d19c73a 100644
--- a/jdk/src/share/classes/javax/management/MBeanServerNotification.java
+++ b/jdk/src/share/classes/javax/management/MBeanServerNotification.java
@@ -27,15 +27,70 @@
/**
- * Represents a notification emitted by the MBean server through the MBeanServerDelegate MBean.
+ * Represents a notification emitted by the MBean Server through the MBeanServerDelegate MBean.
* The MBean Server emits the following types of notifications: MBean registration, MBean
- * de-registration.
+ * unregistration.
* <P>
- * To receive to MBeanServerNotifications, you need to be declared as listener to
- * the {@link javax.management.MBeanServerDelegate javax.management.MBeanServerDelegate} MBean
- * that represents the MBeanServer. The ObjectName of the MBeanServerDelegate is:
+ * To receive MBeanServerNotifications, you need to register a listener with
+ * the {@link MBeanServerDelegate MBeanServerDelegate} MBean
+ * that represents the MBeanServer. The ObjectName of the MBeanServerDelegate is
+ * {@link MBeanServerDelegate#DELEGATE_NAME}, which is
* <CODE>JMImplementation:type=MBeanServerDelegate</CODE>.
*
+ * <p>The following code prints a message every time an MBean is registered
+ * or unregistered in the MBean Server {@code mbeanServer}:</p>
+ *
+ * <pre>
+ * private static final NotificationListener printListener = new NotificationListener() {
+ * public void handleNotification(Notification n, Object handback) {
+ * if (!(n instanceof MBeanServerNotification)) {
+ * System.out.println("Ignored notification of class " + n.getClass().getName());
+ * return;
+ * }
+ * MBeanServerNotification mbsn = (MBeanServerNotification) n;
+ * String what;
+ * if (n.getType().equals(MBeanServerNotification.REGISTRATION_NOTIFICATION))
+ * what = "MBean registered";
+ * else if (n.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION))
+ * what = "MBean unregistered";
+ * else
+ * what = "Unknown type " + n.getType();
+ * System.out.println("Received MBean Server notification: " + what + ": " +
+ * mbsn.getMBeanName());
+ * };
+ *
+ * ...
+ * mbeanServer.addNotificationListener(
+ * MBeanServerDelegate.DELEGATE_NAME, printListener, null, null);
+ * </pre>
+ *
+ * <p>The following code prints a message every time an MBean is registered
+ * or unregistered in the MBean Server {@code mbeanServer}:</p>
+ *
+ * <pre>
+ * private static final NotificationListener printListener = new NotificationListener() {
+ * public void handleNotification(Notification n, Object handback) {
+ * if (!(n instanceof MBeanServerNotification)) {
+ * System.out.println("Ignored notification of class " + n.getClass().getName());
+ * return;
+ * }
+ * MBeanServerNotification mbsn = (MBeanServerNotification) n;
+ * String what;
+ * if (n.getType().equals(MBeanServerNotification.REGISTRATION_NOTIFICATION))
+ * what = "MBean registered";
+ * else if (n.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION))
+ * what = "MBean unregistered";
+ * else
+ * what = "Unknown type " + n.getType();
+ * System.out.println("Received MBean Server notification: " + what + ": " +
+ * mbsn.getMBeanName());
+ * };
+ *
+ * ...
+ * mbeanServer.addNotificationListener(
+ * MBeanServerDelegate.DELEGATE_NAME, printListener, null, null);
+ * </pre>
+ *
* @since 1.5
*/
public class MBeanServerNotification extends Notification {
diff --git a/jdk/src/share/classes/javax/management/Notification.java b/jdk/src/share/classes/javax/management/Notification.java
index 07fc19b..de07ec4 100644
--- a/jdk/src/share/classes/javax/management/Notification.java
+++ b/jdk/src/share/classes/javax/management/Notification.java
@@ -54,7 +54,7 @@
* @since 1.5
*/
@SuppressWarnings("serial") // serialVersionUID is not constant
-public class Notification extends EventObject {
+public class Notification extends EventObject implements Cloneable {
// Serialization compatibility stuff:
// Two serial forms are supported in this class. The selected form depends
@@ -244,6 +244,26 @@
}
/**
+ * <p>Creates and returns a copy of this object. The copy is created as
+ * described for {@link Object#clone()}. This means, first, that the
+ * class of the object will be the same as the class of this object, and,
+ * second, that the copy is a "shallow copy". Fields of this notification
+ * are not themselves copied. In particular, the {@linkplain
+ * #getUserData user data} of the copy is the same object as the
+ * original.</p>
+ *
+ * @return a copy of this object.
+ */
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ /**
* Sets the source.
*
* @param source the new source for this object.
@@ -285,8 +305,10 @@
/**
* Get the notification type.
*
- * @return The notification type. It's a string expressed in a dot notation similar
- * to Java properties. An example of a notification type is network.alarm.router .
+ * @return The notification type. It's a string expressed in a dot notation
+ * similar to Java properties. It is recommended that the notification type
+ * should follow the reverse-domain-name convention used by Java package
+ * names. An example of a notification type is com.example.alarm.router.
*/
public String getType() {
return type ;
@@ -317,15 +339,26 @@
/**
* Get the notification message.
*
- * @return The message string of this notification object. It contains in a string,
- * which could be the explanation of the notification for displaying to a user
+ * @return The message string of this notification object.
*
+ * @see #setMessage
*/
public String getMessage() {
return message ;
}
/**
+ * Set the notification message.
+ *
+ * @param message the new notification message.
+ *
+ * @see #getMessage
+ */
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ /**
* Get the user data.
*
* @return The user data object. It is used for whatever data
@@ -355,6 +388,7 @@
*
* @return A String representation of this notification.
*/
+ @Override
public String toString() {
return super.toString()+"[type="+type+"][message="+message+"]";
}
diff --git a/jdk/src/share/classes/javax/management/QueryNotificationFilter.java b/jdk/src/share/classes/javax/management/QueryNotificationFilter.java
index 7d1990f..5d7e781 100644
--- a/jdk/src/share/classes/javax/management/QueryNotificationFilter.java
+++ b/jdk/src/share/classes/javax/management/QueryNotificationFilter.java
@@ -26,7 +26,6 @@
package javax.management;
import com.sun.jmx.mbeanserver.NotificationMBeanSupport;
-import com.sun.jmx.mbeanserver.Util;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -43,6 +42,11 @@
* on both the client and the server in the remote case, so using this class
* instead is recommended where possible.</p>
*
+ * <p>Because this class was introduced in version 2.0 of the JMX API,
+ * it may not be present on a remote JMX agent that is running an earlier
+ * version. The method {@link JMX#getSpecificationVersion
+ * JMX.getSpecificationVersion} can be used to determine the remote version.</p>
+ *
* <p>This class uses the {@linkplain Query Query API} to specify the
* filtering logic. For example, to select only notifications where the
* {@linkplain Notification#getType() type} is {@code "com.example.mytype"},
diff --git a/jdk/src/share/classes/javax/management/event/EventClient.java b/jdk/src/share/classes/javax/management/event/EventClient.java
index 96c4017..a2f6bc6 100644
--- a/jdk/src/share/classes/javax/management/event/EventClient.java
+++ b/jdk/src/share/classes/javax/management/event/EventClient.java
@@ -29,7 +29,6 @@
import com.sun.jmx.event.LeaseRenewer;
import com.sun.jmx.event.ReceiverBuffer;
import com.sun.jmx.event.RepeatedSingletonJob;
-import com.sun.jmx.namespace.JMXNamespaceUtils;
import com.sun.jmx.mbeanserver.PerThreadGroupPool;
import com.sun.jmx.remote.util.ClassLogger;
@@ -58,7 +57,6 @@
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;
-import javax.management.remote.JMXConnector;
import javax.management.remote.NotificationResult;
import javax.management.remote.TargetedNotification;
@@ -129,11 +127,12 @@
public static final String NOTIFS_LOST = "jmx.event.service.notifs.lost";
/**
- * The default lease time, {@value}, in milliseconds.
+ * The default lease time that EventClient instances will request, in
+ * milliseconds. This value is {@value}.
*
* @see EventClientDelegateMBean#lease
*/
- public static final long DEFAULT_LEASE_TIMEOUT = 300000;
+ public static final long DEFAULT_REQUESTED_LEASE_TIME = 300000;
/**
* <p>Constructs a default {@code EventClient} object.</p>
@@ -173,7 +172,7 @@
*/
public EventClient(EventClientDelegateMBean delegate)
throws IOException {
- this(delegate, null, null, null, DEFAULT_LEASE_TIMEOUT);
+ this(delegate, null, null, null, DEFAULT_REQUESTED_LEASE_TIME);
}
/**
@@ -196,7 +195,7 @@
* If {@code null}, a default scheduler will be used.
* @param requestedLeaseTime The lease time used to keep this client alive
* in the {@link EventClientDelegateMBean}. A value of zero is equivalent
- * to the {@linkplain #DEFAULT_LEASE_TIMEOUT default value}.
+ * to the {@linkplain #DEFAULT_REQUESTED_LEASE_TIME default value}.
*
* @throws IllegalArgumentException If {@code delegate} is null.
* @throws IOException If an I/O error occurs when communicating with the
@@ -213,7 +212,7 @@
}
if (requestedLeaseTime == 0)
- requestedLeaseTime = DEFAULT_LEASE_TIMEOUT;
+ requestedLeaseTime = DEFAULT_REQUESTED_LEASE_TIME;
else if (requestedLeaseTime < 0) {
throw new IllegalArgumentException(
"Negative lease time: " + requestedLeaseTime);
@@ -269,7 +268,13 @@
new ScheduledThreadPoolExecutor(20, daemonThreadFactory);
executor.setKeepAliveTime(1, TimeUnit.SECONDS);
executor.allowCoreThreadTimeOut(true);
- executor.setRemoveOnCancelPolicy(true);
+ if (setRemoveOnCancelPolicy != null) {
+ try {
+ setRemoveOnCancelPolicy.invoke(executor, true);
+ } catch (Exception e) {
+ logger.trace("setRemoveOnCancelPolicy", e);
+ }
+ }
// By default, a ScheduledThreadPoolExecutor will keep jobs
// in its queue even after they have been cancelled. They
// will only be removed when their scheduled time arrives.
@@ -277,12 +282,25 @@
// this EventClient, this can lead to a moderately large number
// of objects remaining referenced until the renewal time
// arrives. Hence the above call, which removes the job from
- // the queue as soon as it is cancelled.
+ // the queue as soon as it is cancelled. Since the call is
+ // new with JDK 7, we invoke it via reflection to make it
+ // easier to use this code on JDK 6.
return executor;
}
};
return leaseRenewerThreadPool.getThreadPoolExecutor(create);
+ }
+ private static final Method setRemoveOnCancelPolicy;
+ static {
+ Method m;
+ try {
+ m = ScheduledThreadPoolExecutor.class.getMethod(
+ "setRemoveOnCancelPolicy", boolean.class);
+ } catch (Exception e) {
+ m = null;
+ }
+ setRemoveOnCancelPolicy = m;
}
/**
@@ -1042,7 +1060,7 @@
final public EventClient call() throws Exception {
EventClientDelegateMBean ecd = EventClientDelegate.getProxy(conn);
return new EventClient(ecd, eventRelay, null, null,
- DEFAULT_LEASE_TIMEOUT);
+ DEFAULT_REQUESTED_LEASE_TIME);
}
};
@@ -1080,24 +1098,6 @@
return clientId;
}
- /**
- * Returns a JMX Connector that will use an {@link EventClient}
- * to subscribe for notifications. If the server doesn't have
- * an {@link EventClientDelegateMBean}, then the connector will
- * use the legacy notification mechanism instead.
- *
- * @param wrapped The underlying JMX Connector wrapped by the returned
- * connector.
- *
- * @return A JMX Connector that will uses an {@link EventClient}, if
- * available.
- *
- * @see EventClient#getEventClientConnection(MBeanServerConnection)
- */
- public static JMXConnector withEventClient(final JMXConnector wrapped) {
- return JMXNamespaceUtils.withEventClient(wrapped);
- }
-
private static final PerThreadGroupPool<ScheduledThreadPoolExecutor>
leaseRenewerThreadPool = PerThreadGroupPool.make();
}
diff --git a/jdk/src/share/classes/javax/management/event/EventClientDelegate.java b/jdk/src/share/classes/javax/management/event/EventClientDelegate.java
index 13329ea..8eeeeb1 100644
--- a/jdk/src/share/classes/javax/management/event/EventClientDelegate.java
+++ b/jdk/src/share/classes/javax/management/event/EventClientDelegate.java
@@ -149,6 +149,7 @@
// of a setMBeanServer on some other forwarder later in the chain.
private static class Forwarder extends SingleMBeanForwarder {
+ private MBeanServer loopMBS;
private static class UnsupportedInvocationHandler
implements InvocationHandler {
@@ -173,7 +174,11 @@
private volatile boolean madeECD;
Forwarder() {
- super(OBJECT_NAME, makeUnsupportedECD());
+ super(OBJECT_NAME, makeUnsupportedECD(), true);
+ }
+
+ synchronized void setLoopMBS(MBeanServer loopMBS) {
+ this.loopMBS = loopMBS;
}
@Override
@@ -186,7 +191,7 @@
AccessController.doPrivileged(
new PrivilegedAction<EventClientDelegate>() {
public EventClientDelegate run() {
- return getEventClientDelegate(Forwarder.this);
+ return getEventClientDelegate(loopMBS);
}
});
DynamicMBean mbean = new StandardMBean(
@@ -208,11 +213,46 @@
* that are targeted for that MBean and handles them itself. All other
* requests are forwarded to the next element in the forwarder chain.</p>
*
+ * @param nextMBS the next {@code MBeanServer} in the chain of forwarders,
+ * which might be another {@code MBeanServerForwarder} or a plain {@code
+ * MBeanServer}. This is the object to which {@code MBeanServer} requests
+ * that do not concern the {@code EventClientDelegateMBean} are sent.
+ * It will be the value of {@link MBeanServerForwarder#getMBeanServer()
+ * getMBeanServer()} on the returned object, and can be changed with {@link
+ * MBeanServerForwarder#setMBeanServer setMBeanServer}. It can be null but
+ * must be set to a non-null value before any {@code MBeanServer} requests
+ * arrive.
+ *
+ * @param loopMBS the {@code MBeanServer} to which requests from the
+ * {@code EventClientDelegateMBean} should be sent. For example,
+ * when you invoke the {@link EventClientDelegateMBean#addListener
+ * addListener} operation on the {@code EventClientDelegateMBean}, it will
+ * result in a call to {@link
+ * MBeanServer#addNotificationListener(ObjectName, NotificationListener,
+ * NotificationFilter, Object) addNotificationListener} on this object.
+ * If this parameter is null, then these requests will be sent to the
+ * newly-created {@code MBeanServerForwarder}. Usually the parameter will
+ * either be null or will be the result of {@link
+ * javax.management.remote.JMXConnectorServer#getSystemMBeanServerForwarder()
+ * getSystemMBeanServerForwarder()} for the connector server in which
+ * this forwarder will be installed.
+ *
* @return a new {@code MBeanServerForwarder} that simulates the existence
* of an {@code EventClientDelegateMBean}.
+ *
+ * @see javax.management.remote.JMXConnectorServer#installStandardForwarders
*/
- public static MBeanServerForwarder newForwarder() {
- return new Forwarder();
+ public static MBeanServerForwarder newForwarder(
+ MBeanServer nextMBS, MBeanServer loopMBS) {
+ Forwarder mbsf = new Forwarder();
+ // We must setLoopMBS before setMBeanServer, because when we
+ // setMBeanServer that will call getEventClientDelegate(loopMBS).
+ if (loopMBS == null)
+ loopMBS = mbsf;
+ mbsf.setLoopMBS(loopMBS);
+ if (nextMBS != null)
+ mbsf.setMBeanServer(nextMBS);
+ return mbsf;
}
/**
@@ -437,10 +477,9 @@
// private classes
// ------------------------------------
private class ClientInfo {
- String clientId;
- EventBuffer buffer;
- NotificationListener clientListener;
- Map<Integer, AddedListener> listenerInfoMap =
+ final String clientId;
+ final NotificationListener clientListener;
+ final Map<Integer, AddedListener> listenerInfoMap =
new HashMap<Integer, AddedListener>();
ClientInfo(String clientId, EventForwarder forwarder) {
@@ -703,7 +742,8 @@
clientInfo = clientInfoMap.get(clientId);
if (clientInfo == null) {
- throw new EventClientNotFoundException("The client is not found.");
+ throw new EventClientNotFoundException(
+ "Client not found (id " + clientId + ")");
}
return clientInfo;
diff --git a/jdk/src/share/classes/javax/management/event/EventClientDelegateMBean.java b/jdk/src/share/classes/javax/management/event/EventClientDelegateMBean.java
index a9718a9..e6030b6 100644
--- a/jdk/src/share/classes/javax/management/event/EventClientDelegateMBean.java
+++ b/jdk/src/share/classes/javax/management/event/EventClientDelegateMBean.java
@@ -51,7 +51,8 @@
* and the MBean Server, that will intercept accesses to the Event Client
* Delegate MBean and treat them as the real MBean would. This forwarder is
* inserted by default with the standard RMI Connector Server, and can also
- * be created explicitly using {@link EventClientDelegate#newForwarder()}.
+ * be created explicitly using {@link EventClientDelegate#newForwarder
+ * EventClientDelegate.newForwarder}.
*
* <li><p>A variant on the above is to replace the MBean Server that is
* used locally with a forwarder as described above. Since
@@ -61,9 +62,7 @@
*
* <pre>
* MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); // or whatever
- * MBeanServerForwarder mbsf = EventClientDelegate.newForwarder();
- * mbsf.setMBeanServer(mbs);
- * mbs = mbsf;
+ * mbs = EventClientDelegate.newForwarder(mbs, null);
* // now use mbs just as you did before, but it will have an EventClientDelegate
* </pre>
*
diff --git a/jdk/src/share/classes/javax/management/event/EventRelay.java b/jdk/src/share/classes/javax/management/event/EventRelay.java
index d723bb0..d106a16 100644
--- a/jdk/src/share/classes/javax/management/event/EventRelay.java
+++ b/jdk/src/share/classes/javax/management/event/EventRelay.java
@@ -27,7 +27,6 @@
import java.io.IOException;
import java.util.concurrent.Executors; // for javadoc
-import java.util.concurrent.ScheduledFuture;
/**
* This interface is used to specify a way to receive
diff --git a/jdk/src/share/classes/javax/management/event/package-info.java b/jdk/src/share/classes/javax/management/event/package-info.java
index c4c7dbe..728b095 100644
--- a/jdk/src/share/classes/javax/management/event/package-info.java
+++ b/jdk/src/share/classes/javax/management/event/package-info.java
@@ -83,8 +83,8 @@
* javax.management.event.EventClientDelegateMBean EventClientDelegateMBean}
* must be registered in the MBean Server, or the connector server must
* be configured to simulate the existence of this MBean, for example
- * using {@link javax.management.event.EventClientDelegate#newForwarder()
- * EventClientDelegate.newForwarder()}. The standard RMI connector is so
+ * using {@link javax.management.event.EventClientDelegate#newForwarder
+ * EventClientDelegate.newForwarder}. The standard RMI connector is so
* configured by default. The {@code EventClientDelegateMBean} documentation
* has further details.</p>
*
diff --git a/jdk/src/share/classes/javax/management/monitor/CounterMonitor.java b/jdk/src/share/classes/javax/management/monitor/CounterMonitor.java
index b592b17..b27e57f 100644
--- a/jdk/src/share/classes/javax/management/monitor/CounterMonitor.java
+++ b/jdk/src/share/classes/javax/management/monitor/CounterMonitor.java
@@ -265,6 +265,7 @@
* @return The derived gauge of the specified object.
*
*/
+ @Override
public synchronized Number getDerivedGauge(ObjectName object) {
return (Number) super.getDerivedGauge(object);
}
@@ -280,6 +281,7 @@
* @return The derived gauge timestamp of the specified object.
*
*/
+ @Override
public synchronized long getDerivedGaugeTimeStamp(ObjectName object) {
return super.getDerivedGaugeTimeStamp(object);
}
@@ -595,6 +597,7 @@
* name of the Java class of the notification and the notification
* types sent by the counter monitor.
*/
+ @Override
public MBeanNotificationInfo[] getNotificationInfo() {
return notifsInfo;
}
diff --git a/jdk/src/share/classes/javax/management/monitor/GaugeMonitor.java b/jdk/src/share/classes/javax/management/monitor/GaugeMonitor.java
index 7077f38..ab71f10 100644
--- a/jdk/src/share/classes/javax/management/monitor/GaugeMonitor.java
+++ b/jdk/src/share/classes/javax/management/monitor/GaugeMonitor.java
@@ -258,6 +258,7 @@
* @return The derived gauge of the specified object.
*
*/
+ @Override
public synchronized Number getDerivedGauge(ObjectName object) {
return (Number) super.getDerivedGauge(object);
}
@@ -273,6 +274,7 @@
* @return The derived gauge timestamp of the specified object.
*
*/
+ @Override
public synchronized long getDerivedGaugeTimeStamp(ObjectName object) {
return super.getDerivedGaugeTimeStamp(object);
}
@@ -477,6 +479,7 @@
* name of the Java class of the notification and the notification
* types sent by the gauge monitor.
*/
+ @Override
public MBeanNotificationInfo[] getNotificationInfo() {
return notifsInfo;
}
diff --git a/jdk/src/share/classes/javax/management/monitor/Monitor.java b/jdk/src/share/classes/javax/management/monitor/Monitor.java
index 0329a33..fb3e1a4 100644
--- a/jdk/src/share/classes/javax/management/monitor/Monitor.java
+++ b/jdk/src/share/classes/javax/management/monitor/Monitor.java
@@ -34,7 +34,6 @@
import java.security.PrivilegedAction;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
@@ -517,7 +516,7 @@
//
ObservedObject o = createObservedObject(object);
o.setAlreadyNotified(RESET_FLAGS_ALREADY_NOTIFIED);
- o.setDerivedGauge(null);
+ o.setDerivedGauge(INTEGER_ZERO);
o.setDerivedGaugeTimeStamp(System.currentTimeMillis());
observedObjects.add(o);
diff --git a/jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java b/jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java
index 429a9d4..f19dfa5 100644
--- a/jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java
+++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java
@@ -26,21 +26,19 @@
package javax.management.namespace;
import com.sun.jmx.defaults.JmxProperties;
-import com.sun.jmx.namespace.JMXNamespaceUtils;
import com.sun.jmx.namespace.ObjectNameRouter;
import com.sun.jmx.namespace.serial.RewritingProcessor;
import com.sun.jmx.namespace.RoutingConnectionProxy;
import com.sun.jmx.namespace.RoutingServerProxy;
-import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
-import javax.management.remote.JMXConnector;
/**
* Static constants and utility methods to help work with
@@ -69,23 +67,6 @@
/**
- * Returns a connector connected to a sub name space exposed through
- * the parent connector.
- * @param parent the parent connector.
- * @param namespace the {@linkplain javax.management.namespace name space}
- * to which the returned connector is
- * connected.
- * @return A connector connected to a sub name space exposed through
- * the parent connector.
- **/
- public static JMXConnector narrowToNamespace(final JMXConnector parent,
- final String namespace)
- throws IOException {
-
- return JMXNamespaceUtils.cd(parent,namespace,true);
- }
-
- /**
* Creates a new {@code MBeanServerConnection} proxy on a
* {@linkplain javax.management.namespace sub name space}
* of the given parent.
@@ -96,15 +77,18 @@
* name space} in which to narrow.
* @return A new {@code MBeanServerConnection} proxy that shows the content
* of that name space.
- * @throws IllegalArgumentException if the name space does not exist, or
- * if a proxy for that name space cannot be created.
+ * @throws IllegalArgumentException if either argument is null,
+ * or the name space does not exist, or if a proxy for that name space
+ * cannot be created. The {@linkplain Throwable#getCause() cause} of
+ * this exception will be an {@link InstanceNotFoundException} if and only
+ * if the name space is found not to exist.
*/
public static MBeanServerConnection narrowToNamespace(
MBeanServerConnection parent,
String namespace) {
if (LOG.isLoggable(Level.FINER))
LOG.finer("Making MBeanServerConnection for: " +namespace);
- return RoutingConnectionProxy.cd(parent,namespace);
+ return RoutingConnectionProxy.cd(parent, namespace, true);
}
/**
@@ -120,13 +104,15 @@
* of that name space.
* @throws IllegalArgumentException if either argument is null,
* or the name space does not exist, or if a proxy for that name space
- * cannot be created.
+ * cannot be created. The {@linkplain Throwable#getCause() cause} of
+ * this exception will be an {@link InstanceNotFoundException} if and only
+ * if the name space is found not to exist.
*/
public static MBeanServer narrowToNamespace(MBeanServer parent,
String namespace) {
if (LOG.isLoggable(Level.FINER))
- LOG.finer("Making NamespaceServerProxy for: " +namespace);
- return RoutingServerProxy.cd(parent,namespace);
+ LOG.finer("Making MBeanServer for: " +namespace);
+ return RoutingServerProxy.cd(parent, namespace, true);
}
/**
@@ -266,7 +252,7 @@
ObjectNameRouter.normalizeNamespacePath(namespace,false,
true,false);
try {
- // We could use Util.newObjectName here - but throwing an
+ // We could use ObjectName.valueOf here - but throwing an
// IllegalArgumentException that contains just the supplied
// namespace instead of the whole ObjectName seems preferable.
return ObjectName.getInstance(sourcePath+
diff --git a/jdk/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java b/jdk/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java
index 6958f57..1c4d29b 100644
--- a/jdk/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java
+++ b/jdk/src/share/classes/javax/management/namespace/JMXRemoteNamespace.java
@@ -27,10 +27,10 @@
import com.sun.jmx.defaults.JmxProperties;
import com.sun.jmx.mbeanserver.Util;
-import com.sun.jmx.namespace.JMXNamespaceUtils;
import com.sun.jmx.remote.util.EnvHelp;
import java.io.IOException;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
@@ -39,6 +39,7 @@
import javax.management.AttributeChangeNotification;
+import javax.management.ClientContext;
import javax.management.InstanceNotFoundException;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanNotificationInfo;
@@ -220,17 +221,26 @@
initParentOnce(this);
// URL must not be null.
- this.jmxURL = JMXNamespaceUtils.checkNonNull(sourceURL,"url");
+ if (sourceURL == null)
+ throw new IllegalArgumentException("Null URL");
+ this.jmxURL = sourceURL;
this.broadcaster =
new NotificationBroadcasterSupport(connectNotification);
// handles options
- this.optionsMap = JMXNamespaceUtils.unmodifiableMap(optionsMap);
+ this.optionsMap = unmodifiableMap(optionsMap);
// handles (dis)connection events
this.listener = new ConnectionListener();
}
+ // returns un unmodifiable view of a map.
+ private static <K,V> Map<K,V> unmodifiableMap(Map<K,V> aMap) {
+ if (aMap == null || aMap.isEmpty())
+ return Collections.emptyMap();
+ return Collections.unmodifiableMap(aMap);
+ }
+
/**
* Returns the {@code JMXServiceURL} that is (or will be) used to
* connect to the remote name space. <p>
@@ -483,106 +493,171 @@
}
}
- JMXConnector connect(JMXServiceURL url, Map<String,?> env)
+ private JMXConnector connect(JMXServiceURL url, Map<String,?> env)
throws IOException {
- final JMXConnector c = newJMXConnector(jmxURL, env);
+ final JMXConnector c = newJMXConnector(url, env);
c.connect(env);
return c;
}
/**
- * Creates a new JMXConnector with the specified {@code url} and
- * {@code env} options map.
- * <p>
- * This method first calls {@link JMXConnectorFactory#newJMXConnector
- * JMXConnectorFactory.newJMXConnector(jmxURL, env)} to obtain a new
- * JMX connector, and returns that.
- * </p>
- * <p>
- * A subclass of {@link JMXRemoteNamespace} can provide an implementation
- * that connects to a sub namespace of the remote server by subclassing
- * this class in the following way:
- * <pre>
- * class JMXRemoteSubNamespace extends JMXRemoteNamespace {
- * private final String subnamespace;
- * JMXRemoteSubNamespace(JMXServiceURL url,
- * Map{@code <String,?>} env, String subnamespace) {
- * super(url,options);
- * this.subnamespace = subnamespace;
- * }
- * protected JMXConnector newJMXConnector(JMXServiceURL url,
- * Map<String,?> env) throws IOException {
- * final JMXConnector inner = super.newJMXConnector(url,env);
- * return {@link JMXNamespaces#narrowToNamespace(JMXConnector,String)
- * JMXNamespaces.narrowToNamespace(inner,subnamespace)};
- * }
- * }
- * </pre>
- * </p>
- * <p>
- * Some connectors, like the JMXMP connector server defined by the
- * version 1.2 of the JMX API may not have been upgraded to use the
- * new {@linkplain javax.management.event Event Service} defined in this
- * version of the JMX API.
- * <p>
- * In that case, and if the remote server to which this JMXRemoteNamespace
- * connects also contains namespaces, it may be necessary to configure
- * explicitly an {@linkplain
- * javax.management.event.EventClientDelegate#newForwarder()
- * Event Client Forwarder} on the remote server side, and to force the use
- * of an {@link EventClient} on this client side.
- * <br>
- * A subclass of {@link JMXRemoteNamespace} can provide an implementation
- * of {@code newJMXConnector} that will force notification subscriptions
- * to flow through an {@link EventClient} over a legacy protocol by
- * overriding this method in the following way:
- * </p>
- * <pre>
- * class JMXRemoteEventClientNamespace extends JMXRemoteNamespace {
- * JMXRemoteSubNamespaceConnector(JMXServiceURL url,
- * Map<String,?> env) {
- * super(url,options);
- * }
- * protected JMXConnector newJMXConnector(JMXServiceURL url,
- * Map<String,?> env) throws IOException {
- * final JMXConnector inner = super.newJMXConnector(url,env);
- * return {@link EventClient#withEventClient(
- * JMXConnector) EventClient.withEventClient(inner)};
- * }
- * }
- * </pre>
- * <p>
- * Note that the remote server also needs to provide an {@link
- * javax.management.event.EventClientDelegateMBean}: only configuring
- * the client side (this object) is not enough.<br>
- * In summary, this technique should be used if the remote server
- * supports JMX namespaces, but uses a JMX Connector Server whose
- * implementation does not transparently use the new Event Service
- * (as would be the case with the JMXMPConnectorServer implementation
- * from the reference implementation of the JMX Remote API 1.0
- * specification).
- * </p>
+ * <p>Creates a new JMXConnector with the specified {@code url} and
+ * {@code env} options map. The default implementation of this method
+ * returns {@link JMXConnectorFactory#newJMXConnector
+ * JMXConnectorFactory.newJMXConnector(jmxURL, env)}. Subclasses can
+ * override this method to customize behavior.</p>
+ *
* @param url The JMXServiceURL of the remote server.
- * @param optionsMap An unmodifiable options map that will be passed to the
+ * @param optionsMap An options map that will be passed to the
* {@link JMXConnectorFactory} when {@linkplain
* JMXConnectorFactory#newJMXConnector creating} the
* {@link JMXConnector} that can connect to the remote source
* MBean Server.
- * @return An unconnected JMXConnector to use to connect to the remote
- * server
- * @throws java.io.IOException if the connector could not be created.
+ * @return A JMXConnector to use to connect to the remote server
+ * @throws IOException if the connector could not be created.
* @see JMXConnectorFactory#newJMXConnector(javax.management.remote.JMXServiceURL, java.util.Map)
* @see #JMXRemoteNamespace
*/
protected JMXConnector newJMXConnector(JMXServiceURL url,
Map<String,?> optionsMap) throws IOException {
- final JMXConnector c =
- JMXConnectorFactory.newJMXConnector(jmxURL, optionsMap);
-// TODO: uncomment this when contexts are added
-// return ClientContext.withDynamicContext(c);
- return c;
+ return JMXConnectorFactory.newJMXConnector(jmxURL, optionsMap);
}
+ /**
+ * <p>Called when a new connection is established using {@link #connect}
+ * so that subclasses can customize the connection. The default
+ * implementation of this method effectively does the following:</p>
+ *
+ * <pre>
+ * MBeanServerConnection mbsc = {@link JMXConnector#getMBeanServerConnection()
+ * jmxc.getMBeanServerConnection()};
+ * try {
+ * return {@link ClientContext#withDynamicContext
+ * ClientContext.withDynamicContext(mbsc)};
+ * } catch (IllegalArgumentException e) {
+ * return mbsc;
+ * }
+ * </pre>
+ *
+ * <p>In other words, it arranges for the client context to be forwarded
+ * to the remote MBean Server if the remote MBean Server supports contexts;
+ * otherwise it ignores the client context.</p>
+ *
+ * <h4>Example: connecting to a remote namespace</h4>
+ *
+ * <p>A subclass that wanted to narrow into a namespace of
+ * the remote MBeanServer might look like this:</p>
+ *
+ * <pre>
+ * class JMXRemoteSubNamespace extends JMXRemoteNamespace {
+ * private final String subnamespace;
+ *
+ * JMXRemoteSubNamespace(
+ * JMXServiceURL url, Map{@code <String, ?>} env, String subnamespace) {
+ * super(url, env);
+ * this.subnamespace = subnamespace;
+ * }
+ *
+ * {@code @Override}
+ * protected MBeanServerConnection getMBeanServerConnection(
+ * JMXConnector jmxc) throws IOException {
+ * MBeanServerConnection mbsc = super.getMBeanServerConnection(jmxc);
+ * return {@link JMXNamespaces#narrowToNamespace(MBeanServerConnection,String)
+ * JMXNamespaces.narrowToNamespace(mbsc, subnamespace)};
+ * }
+ * }
+ * </pre>
+ *
+ * <h4>Example: using the Event Service for notifications</h4>
+ *
+ * <p>Some connectors may have been designed to work with an earlier
+ * version of the JMX API, and may not have been upgraded to use
+ * the {@linkplain javax.management.event Event Service} defined in
+ * this version of the JMX API. In that case, and if the remote
+ * server to which this JMXRemoteNamespace connects also contains
+ * namespaces, it may be necessary to configure explicitly an {@linkplain
+ * javax.management.event.EventClientDelegate#newForwarder Event Client
+ * Forwarder} on the remote server side, and to force the use of an {@link
+ * EventClient} on this client side.</p>
+ *
+ * <p>A subclass of {@link JMXRemoteNamespace} can provide an
+ * implementation of {@code getMBeanServerConnection} that will force
+ * notification subscriptions to flow through an {@link EventClient} over
+ * a legacy protocol. It can do so by overriding this method in the
+ * following way:</p>
+ *
+ * <pre>
+ * class JMXRemoteEventClientNamespace extends JMXRemoteNamespace {
+ * JMXRemoteEventClientNamespace(JMXServiceURL url, {@code Map<String,?>} env) {
+ * super(url, env);
+ * }
+ *
+ * {@code @Override}
+ * protected MBeanServerConnection getMBeanServerConnection(JMXConnector jmxc)
+ * throws IOException {
+ * MBeanServerConnection mbsc = super.getMBeanServerConnection(jmxc);
+ * return EventClient.getEventClientConnection(mbsc);
+ * }
+ * }
+ * </pre>
+ *
+ * <p>
+ * Note that the remote server also needs to provide an {@link
+ * javax.management.event.EventClientDelegateMBean}: configuring only
+ * the client side (this object) is not enough.</p>
+ *
+ * <p>In summary, this technique should be used if the remote server
+ * supports JMX namespaces, but uses a JMX Connector Server whose
+ * implementation does not transparently use the new Event Service
+ * (as would be the case with the JMXMPConnectorServer implementation
+ * from the reference implementation of the JMX Remote API 1.0
+ * specification).</p>
+ *
+ * @param jmxc the newly-created {@code JMXConnector}.
+ *
+ * @return an {@code MBeanServerConnection} connected to the remote
+ * MBeanServer.
+ *
+ * @throws IOException if the connection cannot be made. If this method
+ * throws {@code IOException} then the calling {@link #connect()} method
+ * will also fail with an {@code IOException}.
+ *
+ * @see #connect
+ */
+ protected MBeanServerConnection getMBeanServerConnection(JMXConnector jmxc)
+ throws IOException {
+ final MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
+ try {
+ return ClientContext.withDynamicContext(mbsc);
+ } catch (IllegalArgumentException e) {
+ LOG.log(Level.FINER, "ClientContext.withDynamicContext", e);
+ return mbsc;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The sequence of events when this method is called includes,
+ * effectively, the following code:</p>
+ *
+ * <pre>
+ * JMXServiceURL url = {@link #getJMXServiceURL getJMXServiceURL}();
+ * JMXConnector jmxc = {@link #newJMXConnector newJMXConnector}(url, env);
+ * jmxc.connect();
+ * MBeanServerConnection mbsc = {@link #getMBeanServerConnection(JMXConnector)
+ * getMBeanServerConnection}(jmxc);
+ * </pre>
+ *
+ * <p>Here, {@code env} is a {@code Map} containing the entries from the
+ * {@code optionsMap} that was passed to the {@linkplain #JMXRemoteNamespace
+ * constructor} or to the {@link #newJMXRemoteNamespace newJMXRemoteNamespace}
+ * factory method.</p>
+ *
+ * <p>Subclasses can customize connection behavior by overriding the
+ * {@code getJMXServiceURL}, {@code newJMXConnector}, or
+ * {@code getMBeanServerConnection} methods.</p>
+ */
public void connect() throws IOException {
LOG.fine("connecting...");
final Map<String,Object> env =
@@ -590,7 +665,7 @@
try {
// XXX: We should probably document this...
// This allows to specify a loader name - which will be
- // retrieved from the paret MBeanServer.
+ // retrieved from the parent MBeanServer.
defaultClassLoader =
EnvHelp.resolveServerClassLoader(env,getMBeanServer());
} catch (InstanceNotFoundException x) {
@@ -604,7 +679,7 @@
final JMXConnector aconn = connect(url,env);
final MBeanServerConnection msc;
try {
- msc = aconn.getMBeanServerConnection();
+ msc = getMBeanServerConnection(aconn);
aconn.addConnectionNotificationListener(listener,null,aconn);
} catch (IOException io) {
close(aconn);
diff --git a/jdk/src/share/classes/javax/management/openmbean/CompositeDataSupport.java b/jdk/src/share/classes/javax/management/openmbean/CompositeDataSupport.java
index 4ef93b4..bd7c77a 100644
--- a/jdk/src/share/classes/javax/management/openmbean/CompositeDataSupport.java
+++ b/jdk/src/share/classes/javax/management/openmbean/CompositeDataSupport.java
@@ -33,12 +33,14 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
// jmx import
+import java.util.TreeSet;
//
@@ -60,16 +62,15 @@
* respective values.
* A {@link SortedMap} is used for faster retrieval of elements.
*/
- private SortedMap<String, Object> contents = new TreeMap<String, Object>();
+ private final SortedMap<String, Object> contents;
/**
* @serial The <i>composite type </i> of this <i>composite data</i> instance.
*/
- private CompositeType compositeType;
+ private final CompositeType compositeType;
/**
- * <p>
- * Constructs a <tt>CompositeDataSupport</tt> instance with the specified
+ * <p>Constructs a <tt>CompositeDataSupport</tt> instance with the specified
* <tt>compositeType</tt>, whose item values
* are specified by <tt>itemValues[]</tt>, in the same order as in
* <tt>itemNames[]</tt>.
@@ -79,103 +80,67 @@
* The items contained in this <tt>CompositeDataSupport</tt> instance are
* internally stored in a <tt>TreeMap</tt>,
* thus sorted in ascending lexicographic order of their names, for faster
- * retrieval of individual item values.
- * <p>
- * The constructor checks that all the constraints listed below for each
+ * retrieval of individual item values.</p>
+ *
+ * <p>The constructor checks that all the constraints listed below for each
* parameter are satisfied,
- * and throws the appropriate exception if they are not.
- * <p>
- * @param compositeType the <i>composite type </i> of this <i>composite
- * data</i> instance;
- * must not be null.
- * <p>
- * @param itemNames <tt>itemNames</tt> must list, in any order, all the
- * item names defined in <tt>compositeType</tt>;
- * the order in which the names are listed, is used to
- * match values in <tt>itemValues[]</tt>;
- * must not be null or empty.
- * <p>
- * @param itemValues the values of the items, listed in the same order as
- * their respective names in <tt>itemNames</tt>;
- * each item value can be null, but if it is non-null it must be
- * a valid value for the open type defined in <tt>compositeType</tt> for the corresponding item;
- * must be of the same size as <tt>itemNames</tt>; must not be null or empty.
- * <p>
- * @throws IllegalArgumentException <tt>compositeType</tt> is null, or <tt>itemNames[]</tt> or <tt>itemValues[]</tt> is null or empty,
- * or one of the elements in <tt>itemNames[]</tt> is a null or empty string,
- * or <tt>itemNames[]</tt> and <tt>itemValues[]</tt> are not of the same size.
- * <p>
- * @throws OpenDataException <tt>itemNames[]</tt> or <tt>itemValues[]</tt>'s size differs from
- * the number of items defined in <tt>compositeType</tt>,
- * or one of the elements in <tt>itemNames[]</tt> does not exist as an item name defined in <tt>compositeType</tt>,
- * or one of the elements in <tt>itemValues[]</tt> is not a valid value for the corresponding item
- * as defined in <tt>compositeType</tt>.
- * <p>
+ * and throws the appropriate exception if they are not.</p>
+ *
+ * @param compositeType the <i>composite type </i> of this <i>composite
+ * data</i> instance; must not be null.
+ *
+ * @param itemNames <tt>itemNames</tt> must list, in any order, all the
+ * item names defined in <tt>compositeType</tt>; the order in which the
+ * names are listed, is used to match values in <tt>itemValues[]</tt>; must
+ * not be null.
+ *
+ * @param itemValues the values of the items, listed in the same order as
+ * their respective names in <tt>itemNames</tt>; each item value can be
+ * null, but if it is non-null it must be a valid value for the open type
+ * defined in <tt>compositeType</tt> for the corresponding item; must be of
+ * the same size as <tt>itemNames</tt>; must not be null.
+ *
+ * @throws IllegalArgumentException <tt>compositeType</tt> is null, or
+ * <tt>itemNames[]</tt> or <tt>itemValues[]</tt> is null or empty, or one
+ * of the elements in <tt>itemNames[]</tt> is a null or empty string, or
+ * <tt>itemNames[]</tt> and <tt>itemValues[]</tt> are not of the same size.
+ *
+ * @throws OpenDataException <tt>itemNames[]</tt> or
+ * <tt>itemValues[]</tt>'s size differs from the number of items defined in
+ * <tt>compositeType</tt>, or one of the elements in <tt>itemNames[]</tt>
+ * does not exist as an item name defined in <tt>compositeType</tt>, or one
+ * of the elements in <tt>itemValues[]</tt> is not a valid value for the
+ * corresponding item as defined in <tt>compositeType</tt>.
*/
- public CompositeDataSupport(CompositeType compositeType, String[] itemNames, Object[] itemValues)
- throws OpenDataException {
+ public CompositeDataSupport(
+ CompositeType compositeType, String[] itemNames, Object[] itemValues)
+ throws OpenDataException {
+ this(makeMap(itemNames, itemValues), compositeType);
+ }
- // Check compositeType is not null
- //
- if (compositeType == null) {
- throw new IllegalArgumentException("Argument compositeType cannot be null.");
- }
+ private static SortedMap<String, Object> makeMap(
+ String[] itemNames, Object[] itemValues)
+ throws OpenDataException {
- // item names defined in compositeType:
- Set<String> namesSet = compositeType.keySet();
-
- // Check the array itemNames is not null or empty (length!=0) and
- // that there is no null element or empty string in it
- //
- checkForNullElement(itemNames, "itemNames");
- checkForEmptyString(itemNames, "itemNames");
-
- // Check the array itemValues is not null or empty (length!=0)
- // (NOTE: we allow null values as array elements)
- //
- if ( (itemValues == null) || (itemValues.length == 0) ) {
- throw new IllegalArgumentException("Argument itemValues[] cannot be null or empty.");
- }
-
- // Check that the sizes of the 2 arrays itemNames and itemValues are the same
- //
+ if (itemNames == null || itemValues == null)
+ throw new IllegalArgumentException("Null itemNames or itemValues");
if (itemNames.length != itemValues.length) {
- throw new IllegalArgumentException("Array arguments itemNames[] and itemValues[] "+
- "should be of same length (got "+ itemNames.length +
- " and "+ itemValues.length +").");
+ throw new IllegalArgumentException(
+ "Different lengths: itemNames[" + itemNames.length +
+ "], itemValues[" + itemValues.length + "]");
}
- // Check the size of the 2 arrays is equal to the number of items defined in compositeType
- //
- if (itemNames.length != namesSet.size()) {
- throw new OpenDataException("The size of array arguments itemNames[] and itemValues[] should be equal to the number of items defined"+
- " in argument compositeType (found "+ itemNames.length +" elements in itemNames[] and itemValues[],"+
- " expecting "+ namesSet.size() +" elements according to compositeType.");
+ SortedMap<String, Object> map = new TreeMap<String, Object>();
+ for (int i = 0; i < itemNames.length; i++) {
+ String name = itemNames[i];
+ if (name == null || name.equals(""))
+ throw new IllegalArgumentException("Null or empty item name");
+ if (map.containsKey(name))
+ throw new OpenDataException("Duplicate item name " + name);
+ map.put(itemNames[i], itemValues[i]);
}
- // Check parameter itemNames[] contains all names defined in the compositeType of this instance
- //
- if ( ! Arrays.asList(itemNames).containsAll(namesSet) ) {
- throw new OpenDataException("Argument itemNames[] does not contain all names defined in the compositeType of this instance.");
- }
-
- // Check each element of itemValues[], if not null, is of the open type defined for the corresponding item
- //
- OpenType<?> itemType;
- for (int i=0; i<itemValues.length; i++) {
- itemType = compositeType.getType(itemNames[i]);
- if ( (itemValues[i] != null) && (! itemType.isValue(itemValues[i])) ) {
- throw new OpenDataException("Argument's element itemValues["+ i +"]=\""+ itemValues[i] +"\" is not a valid value for"+
- " this item (itemName="+ itemNames[i] +",itemType="+ itemType +").");
- }
- }
-
- // Initialize internal fields: compositeType and contents
- //
- this.compositeType = compositeType;
- for (int i=0; i<itemNames.length; i++) {
- this.contents.put(itemNames[i], itemValues[i]);
- }
+ return map;
}
/**
@@ -184,64 +149,99 @@
* are given by the mappings in the map <tt>items</tt>.
* This constructor converts the keys to a string array and the values to an object array and calls
* <tt>CompositeDataSupport(javax.management.openmbean.CompositeType, java.lang.String[], java.lang.Object[])</tt>.
- * <p>
+ *
* @param compositeType the <i>composite type </i> of this <i>composite data</i> instance;
* must not be null.
- * <p>
* @param items the mappings of all the item names to their values;
* <tt>items</tt> must contain all the item names defined in <tt>compositeType</tt>;
- * must not be null or empty.
- * <p>
- * @throws IllegalArgumentException <tt>compositeType</tt> is null, or <tt>items</tt> is null or empty,
- * or one of the keys in <tt>items</tt> is a null or empty string,
- * or one of the values in <tt>items</tt> is null.
- * <p>
- * @throws OpenDataException <tt>items</tt>' size differs from the number of items defined in <tt>compositeType</tt>,
- * or one of the keys in <tt>items</tt> does not exist as an item name defined in <tt>compositeType</tt>,
- * or one of the values in <tt>items</tt> is not a valid value for the corresponding item
- * as defined in <tt>compositeType</tt>.
- * <p>
- * @throws ArrayStoreException one or more keys in <tt>items</tt> is not of the class <tt>java.lang.String</tt>.
- * <p>
+ * must not be null.
+ *
+ * @throws IllegalArgumentException <tt>compositeType</tt> is null, or
+ * <tt>items</tt> is null, or one of the keys in <tt>items</tt> is a null
+ * or empty string.
+ * @throws OpenDataException <tt>items</tt>' size differs from the
+ * number of items defined in <tt>compositeType</tt>, or one of the
+ * keys in <tt>items</tt> does not exist as an item name defined in
+ * <tt>compositeType</tt>, or one of the values in <tt>items</tt>
+ * is not a valid value for the corresponding item as defined in
+ * <tt>compositeType</tt>.
+ * @throws ArrayStoreException one or more keys in <tt>items</tt> is not of
+ * the class <tt>java.lang.String</tt>.
+ *
+ * @see #toMap
*/
public CompositeDataSupport(CompositeType compositeType,
Map<String,?> items)
throws OpenDataException {
+ this(makeMap(items), compositeType);
+ }
+ private static SortedMap<String, Object> makeMap(Map<String, ?> items) {
+ if (items == null)
+ throw new IllegalArgumentException("Null items map");
+ if (items.containsKey(null) || items.containsKey(""))
+ throw new IllegalArgumentException("Null or empty item name");
- // Let the other constructor do the job, as the call to another constructor must be the first call
+ SortedMap<String, Object> map = new TreeMap<String, Object>();
+ for (Object key : items.keySet()) {
+ if (!(key instanceof String)) {
+ throw new ArrayStoreException("Item name is not string: " + key);
+ // This can happen because of erasure. The particular
+ // exception is a historical artifact - an implementation
+ // detail that leaked into the API.
+ }
+ map.put((String) key, items.get(key));
+ }
+ return map;
+ }
+
+ private CompositeDataSupport(
+ SortedMap<String, Object> items, CompositeType compositeType)
+ throws OpenDataException {
+
+ // Check compositeType is not null
//
- this( compositeType,
- (items==null ? null : items.keySet().toArray(new String[items.size()])), // may raise an ArrayStoreException
- (items==null ? null : items.values().toArray()) );
- }
-
- /**
- *
- */
- private static void checkForNullElement(Object[] arg, String argName) {
- if ( (arg == null) || (arg.length == 0) ) {
- throw new IllegalArgumentException(
- "Argument "+ argName +"[] cannot be null or empty.");
+ if (compositeType == null) {
+ throw new IllegalArgumentException("Argument compositeType cannot be null.");
}
- for (int i=0; i<arg.length; i++) {
- if (arg[i] == null) {
- throw new IllegalArgumentException(
- "Argument's element "+ argName +"["+ i +"] cannot be null.");
+
+ // item names defined in compositeType:
+ Set<String> namesFromType = compositeType.keySet();
+ Set<String> namesFromItems = items.keySet();
+
+ // This is just a comparison, but we do it this way for a better
+ // exception message.
+ if (!namesFromType.equals(namesFromItems)) {
+ Set<String> extraFromType = new TreeSet<String>(namesFromType);
+ extraFromType.removeAll(namesFromItems);
+ Set<String> extraFromItems = new TreeSet<String>(namesFromItems);
+ extraFromItems.removeAll(namesFromType);
+ if (!extraFromType.isEmpty() || !extraFromItems.isEmpty()) {
+ throw new OpenDataException(
+ "Item names do not match CompositeType: " +
+ "names in items but not in CompositeType: " + extraFromItems +
+ "; names in CompositeType but not in items: " + extraFromType);
}
}
- }
- /**
- *
- */
- private static void checkForEmptyString(String[] arg, String argName) {
- for (int i=0; i<arg.length; i++) {
- if (arg[i].trim().equals("")) {
- throw new IllegalArgumentException(
- "Argument's element "+ argName +"["+ i +"] cannot be an empty string.");
+ // Check each value, if not null, is of the open type defined for the
+ // corresponding item
+ for (String name : namesFromType) {
+ Object value = items.get(name);
+ if (value != null) {
+ OpenType<?> itemType = compositeType.getType(name);
+ if (!itemType.isValue(value)) {
+ throw new OpenDataException(
+ "Argument value of wrong type for item " + name +
+ ": value " + value + ", type " + itemType);
+ }
}
}
+
+ // Initialize internal fields: compositeType and contents
+ //
+ this.compositeType = compositeType;
+ this.contents = items;
}
/**
@@ -329,6 +329,54 @@
}
/**
+ * <p>Returns a Map representing the contents of the given CompositeData.
+ * Each item in the CompositeData is represented by an entry in the map,
+ * where the name and value of the item are the key and value of the entry.
+ * The returned value is modifiable but modifications to it have no effect
+ * on the original CompositeData.</p>
+ *
+ * <p>For example, if you have a CompositeData {@code cd1} and you want
+ * to produce another CompositeData {@code cd2} which is the same except
+ * that the value of its {@code id} item has been changed to 253, you
+ * could write:</p>
+ *
+ * <pre>
+ * CompositeData cd1 = ...;
+ * {@code Map<String, Object>} map = CompositeDataSupport.toMap(cd1);
+ * assert(map.get("id") instanceof Integer);
+ * map.put("id", 253);
+ * CompositeData cd2 = {@link #CompositeDataSupport(CompositeType, Map)
+ * new CompositeDataSupport}(cd1.getCompositeType(), map);
+ * </pre>
+ *
+ * <p>Logically, this method would be a method in the {@link CompositeData}
+ * interface, but cannot be for compatibility reasons.</p>
+ *
+ * @param cd the CompositeData to convert to a Map.
+ *
+ * @return a Map that is a copy of the contents of {@code cd}.
+ *
+ * @throws IllegalArgumentException if {@code cd} is null.
+ *
+ * @see #CompositeDataSupport(CompositeType, Map)
+ */
+ public static Map<String, Object> toMap(CompositeData cd) {
+ if (cd == null)
+ throw new IllegalArgumentException("Null argument");
+
+ // If we really wanted, we could check whether cd is a
+ // CompositeDataSupport and return a copy of cd.contents if so,
+ // but I don't think that would be substantially faster.
+ Map<String, Object> map = new LinkedHashMap<String, Object>();
+ CompositeType ct = cd.getCompositeType();
+ for (String key : ct.keySet()) {
+ Object value = cd.get(key);
+ map.put(key, value);
+ }
+ return map;
+ }
+
+ /**
* Compares the specified <var>obj</var> parameter with this
* <code>CompositeDataSupport</code> instance for equality.
* <p>
diff --git a/jdk/src/share/classes/javax/management/package.html b/jdk/src/share/classes/javax/management/package.html
index 14027d6..372c30ef 100644
--- a/jdk/src/share/classes/javax/management/package.html
+++ b/jdk/src/share/classes/javax/management/package.html
@@ -1,7 +1,7 @@
<html>
-<head>
-<title>javax.management package</title>
-<!--
+ <head>
+ <title>javax.management package</title>
+ <!--
Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -24,37 +24,37 @@
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.
--->
-</head>
-<body bgcolor="white">
- <p>Provides the core classes for the Java Management Extensions.</p>
+ -->
+ </head>
+ <body bgcolor="white">
+ <p>Provides the core classes for the Java Management Extensions.</p>
- <p>The Java Management Extensions
- (JMX<sup><font size="-1">TM</font></sup>) API is a standard
- API for management and monitoring. Typical uses include:</p>
+ <p>The Java Management Extensions
+ (JMX<sup><font size="-1">TM</font></sup>) API is a standard
+ API for management and monitoring. Typical uses include:</p>
- <ul>
- <li>consulting and changing application configuration</li>
+ <ul>
+ <li>consulting and changing application configuration</li>
- <li>accumulating statistics about application behavior and
- making them available</li>
+ <li>accumulating statistics about application behavior and
+ making them available</li>
- <li>notifying of state changes and erroneous conditions.</li>
- </ul>
+ <li>notifying of state changes and erroneous conditions.</li>
+ </ul>
- <p>The JMX API can also be used as part of a solution for
- managing systems, networks, and so on.</p>
+ <p>The JMX API can also be used as part of a solution for
+ managing systems, networks, and so on.</p>
- <p>The API includes remote access, so a remote management
- program can interact with a running application for these
- purposes.</p>
+ <p>The API includes remote access, so a remote management
+ program can interact with a running application for these
+ purposes.</p>
- <h2>MBeans</h2>
+ <h2>MBeans</h2>
- <p>The fundamental notion of the JMX API is the <em>MBean</em>.
- An MBean is a named <em>managed object</em> representing a
- resource. It has a <em>management interface</em> consisting
- of:</p>
+ <p>The fundamental notion of the JMX API is the <em>MBean</em>.
+ An MBean is a named <em>managed object</em> representing a
+ resource. It has a <em>management interface</em> consisting
+ of:</p>
<ul>
<li>named and typed attributes that can be read and/or
@@ -92,40 +92,40 @@
<pre>
public interface ConfigurationMBean {
- public int getCacheSize();
- public void setCacheSize(int size);
- public long getLastChangedTime();
- public void save();
+ public int getCacheSize();
+ public void setCacheSize(int size);
+ public long getLastChangedTime();
+ public void save();
}
- </pre>
+ </pre>
- <p>The methods <code>getCacheSize</code> and
- <code>setCacheSize</code> define a read-write attribute of
- type <code>int</code> called <code>CacheSize</code> (with an
- initial capital, unlike the JavaBeans convention).</p>
+ <p>The methods <code>getCacheSize</code> and
+ <code>setCacheSize</code> define a read-write attribute of
+ type <code>int</code> called <code>CacheSize</code> (with an
+ initial capital, unlike the JavaBeans convention).</p>
- <p>The method <code>getLastChangedTime</code> defines an
- attribute of type <code>long</code> called
- <code>LastChangedTime</code>. This is a read-only attribute,
- since there is no method <code>setLastChangedTime</code>.</p>
+ <p>The method <code>getLastChangedTime</code> defines an
+ attribute of type <code>long</code> called
+ <code>LastChangedTime</code>. This is a read-only attribute,
+ since there is no method <code>setLastChangedTime</code>.</p>
- <p>The method <code>save</code> defines an operation called
- <code>save</code>. It is not an attribute, since its name
- does not begin with <code>get</code>, <code>set</code>, or
- <code>is</code>.</p>
+ <p>The method <code>save</code> defines an operation called
+ <code>save</code>. It is not an attribute, since its name
+ does not begin with <code>get</code>, <code>set</code>, or
+ <code>is</code>.</p>
- <p>The exact naming patterns for Standard MBeans are detailed in
- the <a href="#spec">JMX Specification</a>.</p>
+ <p>The exact naming patterns for Standard MBeans are detailed in
+ the <a href="#spec">JMX Specification</a>.</p>
- <p>There are two ways to make a Java object that is an MBean
- with this management interface. One is for the object to be
- of a class that has exactly the same name as the Java
- interface but without the <code>MBean</code> suffix. So in
- the example the object would be of the class
- <code>Configuration</code>, in the same Java package as
- <code>ConfigurationMBean</code>. The second way is to use the
- {@link javax.management.StandardMBean StandardMBean}
- class.</p>
+ <p>There are two ways to make a Java object that is an MBean
+ with this management interface. One is for the object to be
+ of a class that has exactly the same name as the Java
+ interface but without the <code>MBean</code> suffix. So in
+ the example the object would be of the class
+ <code>Configuration</code>, in the same Java package as
+ <code>ConfigurationMBean</code>. The second way is to use the
+ {@link javax.management.StandardMBean StandardMBean}
+ class.</p>
<h3 id="stdannot">Defining Standard MBeans with annotations</h3>
@@ -272,37 +272,37 @@
<pre>
int cacheSize = mbs.getAttribute(name, "CacheSize");
{@link javax.management.Attribute Attribute} newCacheSize =
- new Attribute("CacheSize", new Integer(2000));
+ new Attribute("CacheSize", new Integer(2000));
mbs.setAttribute(name, newCacheSize);
mbs.invoke(name, "save", new Object[0], new Class[0]);
- </pre>
+ </pre>
<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>
+ <pre>
ConfigurationMBean conf =
{@link javax.management.JMX#newMBeanProxy
JMX.newMBeanProxy}(mbs, name, ConfigurationMBean.class);
int cacheSize = conf.getCacheSize();
conf.setCacheSize(2000);
conf.save();
- </pre>
+ </pre>
- <p>Using an MBean proxy is just a convenience. The second
- example ends up calling the same <code>MBeanServer</code>
- operations as the first one.</p>
+ <p>Using an MBean proxy is just a convenience. The second
+ example ends up calling the same <code>MBeanServer</code>
+ operations as the first one.</p>
- <p>An MBean Server can be queried for MBeans whose names match
- certain patterns and/or whose attributes meet certain
- constraints. Name patterns are constructed using the {@link
- javax.management.ObjectName ObjectName} class and constraints
- are constructed using the {@link javax.management.Query Query}
- class. The methods {@link
- javax.management.MBeanServer#queryNames queryNames} and {@link
- javax.management.MBeanServer#queryMBeans queryMBeans} then
- perform the query.</p>
+ <p>An MBean Server can be queried for MBeans whose names match
+ certain patterns and/or whose attributes meet certain
+ constraints. Name patterns are constructed using the {@link
+ javax.management.ObjectName ObjectName} class and constraints
+ are constructed using the {@link javax.management.Query Query}
+ class. The methods {@link
+ javax.management.MBeanServer#queryNames queryNames} and {@link
+ javax.management.MBeanServer#queryMBeans queryMBeans} then
+ perform the query.</p>
<h3>MBean lifecycle and resource injection</h3>
@@ -407,6 +407,92 @@
So for example an SNMP GET operation might result in a
<code>getAttribute</code> on the MBean Server.</p>
+ <h3 id="interop">Interoperability between versions of the JMX
+ specification</h3>
+
+ <p>When a client connects to a server using the JMX Remote
+ API, it is possible that they do not have the same version
+ of the JMX specification. The version of the JMX
+ specification described here is version 2.0. Previous
+ versions were 1.0, 1.1, 1.2, and 1.4. (There was no 1.3.)
+ The standard JMX Remote API is defined to work with version
+ 1.2 onwards, so in standards-based deployment the only
+ interoperability questions that arise concern version 1.2
+ onwards.</p>
+
+ <p>Every version of the JMX specification continues to
+ implement the features of previous versions. So when the
+ client is running an earlier version than the server, there
+ should not be any interoperability concerns. The only
+ exception is the unlikely one where a pre-2.0 client used
+ the string {@code //} in the domain part of an {@link
+ javax.management.ObjectName ObjectName}.</p>
+
+ <p>When the client is running a later version than the server,
+ certain newer features may not be available, as detailed in
+ the next sections. The method {@link
+ javax.management.JMX#getSpecificationVersion
+ JMX.getSpecificationVersion} can be used to determine the
+ server version to check if required features are
+ available.</p>
+
+ <h4 id="interop-1.4">If the remote MBean Server is 1.4</h4>
+
+ <ul>
+
+ <li><p>You cannot use {@link
+ javax.management.QueryNotificationFilter
+ QueryNotificationFilter} in {@link
+ javax.management.MBeanServerConnection#addNotificationListener
+ addNotificationListener} since this class did not exist
+ in 1.4.</p>
+
+ <li><p>In an attribute in a query, you cannot access values
+ inside complex types using dot syntax, for example
+ {@link javax.management.Query#attr Query.attr}{@code
+ ("HeapMemoryUsage.used")}.</p>
+
+ <li><p>The packages {@link javax.management.event} and
+ {@link javax.management.namespace} did not exist in 1.4,
+ so you cannot remotely create instances of the MBeans
+ they define.</p>
+
+ <li><p>Even if the remote MBean Server is 2.0, you cannot in
+ general suppose that {@link
+ javax.management.event.EventClient EventClient} or
+ {@link javax.management.ClientContext ClientContext}
+ will work there without first checking. If the remote
+ MBean Server is 1.4 then those checks will return false.
+ An attempt to use these features without checking will
+ fail in the same way as for a remote 2.0 that is not
+ configured to support them.</p>
+ </ul>
+
+ <h4 id="interop-1.2">If the remote MBean Server is 1.2</h4>
+
+ <p><b>In addition to the above</b>,</p>
+
+ <ul>
+
+ <li><p>You cannot use wildcards in a key property of an
+ {@link javax.management.ObjectName ObjectName}, for
+ example {@code domain:type=Foo,name=*}. Wildcards that
+ match whole properties are still allowed, for example
+ {@code *:*} or {@code *:type=Foo,*}.</p>
+
+ <li><p>You cannot use {@link
+ javax.management.Query#isInstanceOf Query.isInstanceOf}
+ in a query.</p>
+
+ <li><p>You cannot use dot syntax such as {@code
+ HeapMemoryUsage.used} in the {@linkplain
+ javax.management.monitor.Monitor#setObservedAttribute
+ observed attribute} of a monitor, as described in the
+ documentation for the {@link javax.management.monitor}
+ package.</p>
+
+ </ul>
+
<p id="spec">
@see <a href="{@docRoot}/../technotes/guides/jmx/index.html">
Java SE 6 Platform documentation on JMX technology</a>
diff --git a/jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java b/jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java
index 051d8b3..77f700c 100644
--- a/jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorFactory.java
@@ -322,10 +322,12 @@
JMXConnectorProvider.class;
final String protocol = serviceURL.getProtocol();
final String providerClassName = "ClientProvider";
+ final JMXServiceURL providerURL = serviceURL;
- JMXConnectorProvider provider =
- getProvider(serviceURL, envcopy, providerClassName,
- targetInterface, loader);
+ JMXConnectorProvider provider = getProvider(providerURL, envcopy,
+ providerClassName,
+ targetInterface,
+ loader);
IOException exception = null;
if (provider == null) {
@@ -336,7 +338,7 @@
if (loader != null) {
try {
JMXConnector connection =
- getConnectorAsService(loader, serviceURL, envcopy);
+ getConnectorAsService(loader, providerURL, envcopy);
if (connection != null)
return connection;
} catch (JMXProviderException e) {
@@ -345,8 +347,7 @@
exception = e;
}
}
- provider =
- getProvider(protocol, PROTOCOL_PROVIDER_DEFAULT_PACKAGE,
+ provider = getProvider(protocol, PROTOCOL_PROVIDER_DEFAULT_PACKAGE,
JMXConnectorFactory.class.getClassLoader(),
providerClassName, targetInterface);
}
@@ -448,9 +449,10 @@
getProviderIterator(JMXConnectorProvider.class, loader);
JMXConnector connection;
IOException exception = null;
- while(providers.hasNext()) {
+ while (providers.hasNext()) {
+ JMXConnectorProvider provider = providers.next();
try {
- connection = providers.next().newJMXConnector(url, map);
+ connection = provider.newJMXConnector(url, map);
return connection;
} catch (JMXProviderException e) {
throw e;
@@ -553,4 +555,5 @@
private static String protocol2package(String protocol) {
return protocol.replace('+', '.').replace('-', '_');
}
+
}
diff --git a/jdk/src/share/classes/javax/management/remote/JMXConnectorServer.java b/jdk/src/share/classes/javax/management/remote/JMXConnectorServer.java
index 88348ff5..c9b4721 100644
--- a/jdk/src/share/classes/javax/management/remote/JMXConnectorServer.java
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorServer.java
@@ -33,6 +33,7 @@
import java.util.Map;
import java.util.NoSuchElementException;
+import javax.management.ClientContext;
import javax.management.MBeanInfo; // for javadoc
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanRegistration;
@@ -103,6 +104,56 @@
/**
* <p>Name of the attribute that specifies whether this connector
+ * server allows clients to communicate a context with each request.
+ * The value associated with this attribute, if any, must be a string
+ * that is equal to {@code "true"} or {@code "false"}, ignoring case.
+ * If it is {@code "true"}, then the connector server will simulate
+ * a namespace {@code jmx.context//}, as described in
+ * {@link ClientContext#newContextForwarder}. This namespace is needed
+ * for {@link ClientContext#withContext ClientContext.withContext} to
+ * function correctly.</p>
+ *
+ * <p>Not all connector servers will understand this attribute, but the
+ * standard {@linkplain javax.management.remote.rmi.RMIConnectorServer
+ * RMI Connector Server} does. For a connector server that understands
+ * this attribute, the default value is {@code "true"}.</p>
+ *
+ * @since 1.7
+ */
+ public static final String CONTEXT_FORWARDER =
+ "jmx.remote.context.forwarder";
+
+ /**
+ * <p>Name of the attribute that specifies whether this connector server
+ * localizes the descriptions in the {@link MBeanInfo} object returned by
+ * {@link MBeanServer#getMBeanInfo MBeanServer.getMBeanInfo}, based on the
+ * locale communicated by the client.</p>
+ *
+ * <p>The value associated with this attribute, if any, must be a string
+ * that is equal to {@code "true"} or {@code "false"}, ignoring case.
+ * If it is {@code "true"}, then the connector server will localize
+ * {@code MBeanInfo} descriptions as specified in {@link
+ * ClientContext#newLocalizeMBeanInfoForwarder}.</p>
+ *
+ * <p>Not all connector servers will understand this attribute, but the
+ * standard {@linkplain javax.management.remote.rmi.RMIConnectorServer
+ * RMI Connector Server} does. For a connector server that understands
+ * this attribute, the default value is {@code "false"}.</p>
+ *
+ * <p>Because localization requires the client to be able to communicate
+ * its locale, it does not make sense to specify this attribute as
+ * {@code "true"} if {@link #CONTEXT_FORWARDER} is not also {@code "true"}.
+ * For a connector server that understands these attributes, specifying
+ * this inconsistent combination will result in an {@link
+ * IllegalArgumentException}.</p>
+ *
+ * @since 1.7
+ */
+ public static final String LOCALIZE_MBEAN_INFO_FORWARDER =
+ "jmx.remote.localize.mbean.info";
+
+ /**
+ * <p>Name of the attribute that specifies whether this connector
* server simulates the existence of the {@link EventClientDelegate}
* MBean. The value associated with this attribute, if any, must
* be a string that is equal to {@code "true"} or {@code "false"},
@@ -155,7 +206,7 @@
* to, or null if it is not yet attached to an MBean server.
*
* @see #setMBeanServerForwarder
- * @see #getSystemMBeanServer
+ * @see #getSystemMBeanServerForwarder
*/
public synchronized MBeanServer getMBeanServer() {
return userMBeanServer;
@@ -176,30 +227,36 @@
* this method, the first occurrence in the chain of an object that is
* {@linkplain Object#equals equal} to {@code mbsf} will have been
* removed.</p>
+ *
* @param mbsf the forwarder to remove
+ *
* @throws NoSuchElementException if there is no occurrence of {@code mbsf}
* in the chain.
- * @throws IllegalArgumentException if {@code mbsf} is null.
+ * @throws IllegalArgumentException if {@code mbsf} is null or is the
+ * {@linkplain #getSystemMBeanServerForwarder() system forwarder}.
+ *
+ * @since 1.7
*/
public synchronized void removeMBeanServerForwarder(MBeanServerForwarder mbsf) {
if (mbsf == null)
throw new IllegalArgumentException("Invalid null argument: mbsf");
+ if (systemMBeanServerForwarder.equals(mbsf))
+ throw new IllegalArgumentException("Cannot remove system forwarder");
- MBeanServerForwarder prev = null;
- MBeanServer curr = systemMBeanServer;
- while (curr instanceof MBeanServerForwarder && !mbsf.equals(curr)) {
- prev = (MBeanServerForwarder) curr;
+ MBeanServerForwarder prev = systemMBeanServerForwarder;
+ MBeanServer curr;
+ while (true) {
curr = prev.getMBeanServer();
+ if (mbsf.equals(curr))
+ break;
+ if (curr instanceof MBeanServerForwarder)
+ prev = (MBeanServerForwarder) curr;
+ else
+ throw new NoSuchElementException("MBeanServerForwarder not in chain");
}
- if (!(curr instanceof MBeanServerForwarder))
- throw new NoSuchElementException("MBeanServerForwarder not in chain");
- MBeanServerForwarder deleted = (MBeanServerForwarder) curr;
- MBeanServer next = deleted.getMBeanServer();
- if (prev != null)
- prev.setMBeanServer(next);
- if (systemMBeanServer == deleted)
- systemMBeanServer = next;
- if (userMBeanServer == deleted)
+ MBeanServer next = mbsf.getMBeanServer();
+ prev.setMBeanServer(next);
+ if (userMBeanServer == mbsf)
userMBeanServer = next;
}
@@ -209,66 +266,63 @@
* the systemMBeanServer and userMBeanServer field declarations.
*/
private void insertUserMBeanServer(MBeanServer mbs) {
- MBeanServerForwarder lastSystemMBSF = null;
- for (MBeanServer mbsi = systemMBeanServer;
- mbsi != userMBeanServer;
- mbsi = lastSystemMBSF.getMBeanServer()) {
+ MBeanServerForwarder lastSystemMBSF = systemMBeanServerForwarder;
+ while (true) {
+ MBeanServer mbsi = lastSystemMBSF.getMBeanServer();
+ if (mbsi == userMBeanServer)
+ break;
lastSystemMBSF = (MBeanServerForwarder) mbsi;
}
userMBeanServer = mbs;
- if (lastSystemMBSF == null)
- systemMBeanServer = mbs;
- else
- lastSystemMBSF.setMBeanServer(mbs);
+ lastSystemMBSF.setMBeanServer(mbs);
}
/**
* <p>Returns the first item in the chain of system and then user
- * forwarders. In the simplest case, a {@code JMXConnectorServer}
- * is connected directly to an {@code MBeanServer}. But there can
- * also be a chain of {@link MBeanServerForwarder}s between the two.
- * This chain consists of two sub-chains: first the <em>system chain</em>
- * and then the <em>user chain</em>. Incoming requests are given to the
- * first forwarder in the system chain. Each forwarder can handle
- * a request itself, or more usually forward it to the next forwarder,
- * perhaps with some extra behavior such as logging or security
- * checking before or after the forwarding. The last forwarder in
- * the system chain is followed by the first forwarder in the user
- * chain.</p>
+ * forwarders. There is a chain of {@link MBeanServerForwarder}s between
+ * a {@code JMXConnectorServer} and its {@code MBeanServer}. This chain
+ * consists of two sub-chains: first the <em>system chain</em> and then
+ * the <em>user chain</em>. Incoming requests are given to the first
+ * forwarder in the system chain. Each forwarder can handle a request
+ * itself, or more usually forward it to the next forwarder, perhaps with
+ * some extra behavior such as logging or security checking before or after
+ * the forwarding. The last forwarder in the system chain is followed by
+ * the first forwarder in the user chain.</p>
*
- * <p>The <em>system chain</em> is usually
- * defined by a connector server based on the environment Map;
- * see {@link JMXConnectorServerFactory#newJMXConnectorServer}. Allowing the
- * connector server to define its forwarders in this way ensures that
- * they are in the correct order - some forwarders need to be inserted
- * before others for correct behavior. It is possible to modify the
- * system chain, for example using {@link #setSystemMBeanServerForwarder} or
- * {@link #removeMBeanServerForwarder}, but in that case the system
- * chain is no longer guaranteed to be correct.</p>
+ * <p>The object returned by this method is the first forwarder in the
+ * system chain. For a given {@code JMXConnectorServer}, this method
+ * always returns the same object, which simply forwards every request
+ * to the next object in the chain.</p>
+ *
+ * <p>Not all connector servers support a system chain of forwarders,
+ * although the standard {@linkplain
+ * javax.management.remote.rmi.RMIConnectorServer RMI connector
+ * server} does. For those that do not, this method will throw {@code
+ * UnsupportedOperationException}. All
+ * connector servers do support a user chain of forwarders.</p>
+ *
+ * <p>The <em>system chain</em> is usually defined by a
+ * connector server based on the environment Map; see {@link
+ * JMXConnectorServerFactory#newJMXConnectorServer
+ * JMXConnectorServerFactory.newJMXConnectorServer}. Allowing
+ * the connector server to define its forwarders in this way
+ * ensures that they are in the correct order - some forwarders
+ * need to be inserted before others for correct behavior. It is
+ * possible to modify the system chain, for example using {@code
+ * connectorServer.getSystemMBeanServerForwarder().setMBeanServer(mbsf)} or
+ * {@link #removeMBeanServerForwarder removeMBeanServerForwarder}, but in
+ * that case the system chain is no longer guaranteed to be correct.</p>
*
* <p>The <em>user chain</em> is defined by calling {@link
- * #setMBeanServerForwarder} to insert forwarders at the head of the user
- * chain.</p>
- *
- * <p>If there are no forwarders in either chain, then both
- * {@link #getMBeanServer()} and {@code getSystemMBeanServer()} will
- * return the {@code MBeanServer} for this connector server. If there
- * are forwarders in the user chain but not the system chain, then
- * both methods will return the first forwarder in the user chain.
- * If there are forwarders in the system chain but not the user chain,
- * then {@code getSystemMBeanServer()} will return the first forwarder
- * in the system chain, and {@code getMBeanServer()} will return the
- * {@code MBeanServer} for this connector server. Finally, if there
- * are forwarders in each chain then {@code getSystemMBeanServer()}
- * will return the first forwarder in the system chain, and {@code
- * getMBeanServer()} will return the first forwarder in the user chain.</p>
+ * #setMBeanServerForwarder setMBeanServerForwarder} to insert forwarders
+ * at the head of the user chain.</p>
*
* <p>This code illustrates how the chains can be traversed:</p>
*
* <pre>
* JMXConnectorServer cs;
* System.out.println("system chain:");
- * MBeanServer mbs = cs.getSystemMBeanServer();
+ * MBeanServer mbs = cs.getSystemMBeanServerForwarder();
* while (true) {
* if (mbs == cs.getMBeanServer())
* System.out.println("user chain:");
@@ -281,65 +335,40 @@
* System.out.println("--MBean Server");
* </pre>
*
+ * <h4>Note for connector server implementors</h4>
+ *
+ * <p>Existing connector server implementations can be updated to support
+ * a system chain of forwarders as follows:</p>
+ *
+ * <ul>
+ * <li><p>Override the {@link #supportsSystemMBeanServerForwarder()}
+ * method so that it returns true.</p>
+ *
+ * <li><p>Call {@link #installStandardForwarders} from the constructor of
+ * the connector server.</p>
+ *
+ * <li><p>Direct incoming requests to the result of {@link
+ * #getSystemMBeanServerForwarder()} instead of the result of {@link
+ * #getMBeanServer()}.</p>
+ * </ul>
+ *
* @return the first item in the system chain of forwarders.
*
- * @see #setSystemMBeanServerForwarder
+ * @throws UnsupportedOperationException if {@link
+ * #supportsSystemMBeanServerForwarder} returns false.
+ *
+ * @see #supportsSystemMBeanServerForwarder
+ * @see #setMBeanServerForwarder
+ *
+ * @since 1.7
*/
- public synchronized MBeanServer getSystemMBeanServer() {
- return systemMBeanServer;
- }
-
- /**
- * <p>Inserts an object that intercepts requests for the MBean server
- * that arrive through this connector server. This object will be
- * supplied as the <code>MBeanServer</code> for any new connection
- * created by this connector server. Existing connections are
- * unaffected.</p>
- *
- * <p>This method can be called more than once with different
- * {@link MBeanServerForwarder} objects. The result is a chain
- * of forwarders. The last forwarder added is the first in the chain.</p>
- *
- * <p>This method modifies the system chain of {@link MBeanServerForwarder}s.
- * Usually user code should change the user chain instead, via
- * {@link #setMBeanServerForwarder}.</p>
- *
- * <p>Not all connector servers support a system chain of forwarders.
- * Calling this method on a connector server that does not will produce an
- * {@link UnsupportedOperationException}.</p>
- *
- * <p>Suppose {@code mbs} is the result of {@link #getSystemMBeanServer()}
- * before calling this method. If {@code mbs} is not null, then
- * {@code mbsf.setMBeanServer(mbs)} will be called. If doing so
- * produces an exception, this method throws the same exception without
- * any other effect. If {@code mbs} is null, or if the call to
- * {@code mbsf.setMBeanServer(mbs)} succeeds, then this method will
- * return normally and {@code getSystemMBeanServer()} will then return
- * {@code mbsf}.</p>
- *
- * <p>The result of {@link #getMBeanServer()} is unchanged by this method.</p>
- *
- * @param mbsf the new <code>MBeanServerForwarder</code>.
- *
- * @throws IllegalArgumentException if the call to {@link
- * MBeanServerForwarder#setMBeanServer mbsf.setMBeanServer} fails
- * with <code>IllegalArgumentException</code>, or if
- * <code>mbsf</code> is null.
- *
- * @throws UnsupportedOperationException if
- * {@link #supportsSystemMBeanServerForwarder} returns false.
- *
- * @see #getSystemMBeanServer()
- */
- public synchronized void setSystemMBeanServerForwarder(
- MBeanServerForwarder mbsf) {
- if (mbsf == null)
- throw new IllegalArgumentException("Invalid null argument: mbsf");
- mustSupportSystemMBSF();
-
- if (systemMBeanServer != null)
- mbsf.setMBeanServer(systemMBeanServer);
- systemMBeanServer = mbsf;
+ public MBeanServerForwarder getSystemMBeanServerForwarder() {
+ if (!supportsSystemMBeanServerForwarder()) {
+ throw new UnsupportedOperationException(
+ "System MBeanServerForwarder not supported by this " +
+ "connector server");
+ }
+ return systemMBeanServerForwarder;
}
/**
@@ -350,19 +379,13 @@
*
* @return true if this connector server supports the system chain of
* forwarders.
+ *
+ * @since 1.7
*/
public boolean supportsSystemMBeanServerForwarder() {
return false;
}
- private void mustSupportSystemMBSF() {
- if (!supportsSystemMBeanServerForwarder()) {
- throw new UnsupportedOperationException(
- "System MBeanServerForwarder not supported by this " +
- "connector server");
- }
- }
-
/**
* <p>Install {@link MBeanServerForwarder}s in the system chain
* based on the attributes in the given {@code Map}. A connector
@@ -374,34 +397,90 @@
* <ul>
*
* <li>If {@link #EVENT_CLIENT_DELEGATE_FORWARDER} is absent, or is
- * present with the value {@code "true"}, then a forwarder with the
- * functionality of {@link EventClientDelegate#newForwarder} is inserted
- * at the start of the system chain.</li>
+ * present with the value {@code "true"}, then a forwarder
+ * equivalent to {@link EventClientDelegate#newForwarder
+ * EventClientDelegate.newForwarder}{@code (sysMBSF.getMBeanServer(),
+ * sysMBSF)} is inserted at the start of the system chain,
+ * where {@code sysMBSF} is the object returned by {@link
+ * #getSystemMBeanServerForwarder()}. </li>
+ *
+ * <li>If {@link #LOCALIZE_MBEAN_INFO_FORWARDER} is present with the
+ * value {@code "true"}, then a forwarder equivalent to
+ * {@link ClientContext#newLocalizeMBeanInfoForwarder
+ * ClientContext.newLocalizeMBeanInfoForwarder}{@code
+ * (sysMBSF.getMBeanServer())} is inserted at the start of the system
+ * chain.</li>
+ *
+ * <li>If {@link #CONTEXT_FORWARDER} is absent, or is present with
+ * the value {@code "true"}, then a forwarder equivalent to
+ * {@link ClientContext#newContextForwarder
+ * ClientContext.newContextForwarder}{@code (sysMSBF.getMBeanServer(),
+ * sysMBSF)} is inserted at the tart of the system chain.</li>
*
* </ul>
*
- * <p>For {@code EVENT_CLIENT_DELEGATE_FORWARDER}, if the
- * attribute is absent from the {@code Map} and a system property
- * of the same name is defined, then the value of the system
- * property is used as if it were in the {@code Map}.
+ * <p>For {@code EVENT_CLIENT_DELEGATE_FORWARDER} and {@code
+ * CONTEXT_FORWARDER}, if the attribute is absent from the {@code
+ * Map} and a system property of the same name is defined, then
+ * the value of the system property is used as if it were in the
+ * {@code Map}.
+ *
+ * <p>Since each forwarder is inserted at the start of the chain,
+ * the final order of the forwarders is the <b>reverse</b> of the order
+ * above. This is important, because the {@code
+ * LOCALIZE_MBEAN_INFO_FORWARDER} can only work if the {@code
+ * CONTEXT_FORWARDER} has already installed the remote client's locale
+ * in the {@linkplain ClientContext#getContext context} of the current
+ * thread.</p>
*
* <p>Attributes in {@code env} that are not listed above are ignored
* by this method.</p>
*
* @throws UnsupportedOperationException if {@link
* #supportsSystemMBeanServerForwarder} is false.
+ *
+ * @throws IllegalArgumentException if the relevant attributes in {@code env} are
+ * inconsistent, for example if {@link #LOCALIZE_MBEAN_INFO_FORWARDER} is
+ * {@code "true"} but {@link #CONTEXT_FORWARDER} is {@code "false"}; or
+ * if one of the attributes has an illegal value.
+ *
+ * @since 1.7
*/
protected void installStandardForwarders(Map<String, ?> env) {
- mustSupportSystemMBSF();
+ MBeanServerForwarder sysMBSF = getSystemMBeanServerForwarder();
// Remember that forwarders must be added in reverse order!
boolean ecd = EnvHelp.computeBooleanFromString(
env, EVENT_CLIENT_DELEGATE_FORWARDER, false, true);
+ boolean localize = EnvHelp.computeBooleanFromString(
+ env, LOCALIZE_MBEAN_INFO_FORWARDER, false, false);
+ boolean context = EnvHelp.computeBooleanFromString(
+ env, CONTEXT_FORWARDER, false, true);
+
+ if (localize && !context) {
+ throw new IllegalArgumentException(
+ "Inconsistent environment parameters: " +
+ LOCALIZE_MBEAN_INFO_FORWARDER + "=\"true\" requires " +
+ CONTEXT_FORWARDER + "=\"true\"");
+ }
if (ecd) {
- MBeanServerForwarder mbsf = EventClientDelegate.newForwarder();
- setSystemMBeanServerForwarder(mbsf);
+ MBeanServerForwarder mbsf = EventClientDelegate.newForwarder(
+ sysMBSF.getMBeanServer(), sysMBSF);
+ sysMBSF.setMBeanServer(mbsf);
+ }
+
+ if (localize) {
+ MBeanServerForwarder mbsf = ClientContext.newLocalizeMBeanInfoForwarder(
+ sysMBSF.getMBeanServer());
+ sysMBSF.setMBeanServer(mbsf);
+ }
+
+ if (context) {
+ MBeanServerForwarder mbsf = ClientContext.newContextForwarder(
+ sysMBSF.getMBeanServer(), sysMBSF);
+ sysMBSF.setMBeanServer(mbsf);
}
}
@@ -473,6 +552,7 @@
*
* @return the array of possible notifications.
*/
+ @Override
public MBeanNotificationInfo[] getNotificationInfo() {
final String[] types = {
JMXConnectionNotification.OPENED,
@@ -684,30 +764,29 @@
* Fields describing the chains of forwarders (MBeanServerForwarders).
* In the general case, the forwarders look something like this:
*
- * systemMBeanServer userMBeanServer
- * | |
- * v v
- * mbsf1 -> mbsf2 -> mbsf3 -> mbsf4 -> mbsf5 -> mbs
+ * userMBeanServer
+ * |
+ * v
+ * systemMBeanServerForwarder -> mbsf2 -> mbsf3 -> mbsf4 -> mbsf5 -> mbs
*
* Here, each mbsfi is an MBeanServerForwarder, and the arrows
* illustrate its getMBeanServer() method. The last MBeanServerForwarder
* can point to an MBeanServer that is not instanceof MBeanServerForwarder,
* here mbs.
*
- * Initially, the chain can be empty if this JMXConnectorServer was
- * constructed without an MBeanServer. In this case, both systemMBS
- * and userMBS will be null. If there is initially an MBeanServer,
- * then both systemMBS and userMBS will point to it.
+ * The system chain is never empty because it always has at least
+ * systemMBeanServerForwarder. Initially, the user chain can be empty if
+ * this JMXConnectorServer was constructed without an MBeanServer. In
+ * this case, userMBS will be null. If there is initially an MBeanServer,
+ * userMBS will point to it.
*
- * Whenever userMBS is changed, the system chain must be updated. If there
- * are forwarders in the system chain (between systemMBS and userMBS in the
- * picture above), then the last one must point to the old value of userMBS
- * (possibly null). It must be updated to point to the new value. If there
- * are no forwarders in the system chain, then systemMBS must be updated to
- * the new value of userMBS. The invariant is that starting from systemMBS
- * and repeatedly calling MBSF.getMBeanServer() you will end up at
- * userMBS. The implication is that you will not see any MBeanServer
- * object on the way that is not also an MBeanServerForwarder.
+ * Whenever userMBS is changed, the system chain must be updated. Before
+ * the update, the last forwarder in the system chain points to the old
+ * value of userMBS (possibly null). It must be updated to point to
+ * the new value. The invariant is that starting from systemMBSF and
+ * repeatedly calling MBSF.getMBeanServer() you will end up at userMBS.
+ * The implication is that you will not see any MBeanServer object on the
+ * way that is not also an MBeanServerForwarder.
*
* The method insertUserMBeanServer contains the logic to change userMBS
* and adjust the system chain appropriately.
@@ -716,7 +795,7 @@
* MBeanServer, then userMBS becomes that MBeanServer, and the system
* chain must be updated as just described.
*
- * When systemMBS is updated, there is no effect on userMBS. The system
+ * When systemMBSF is updated, there is no effect on userMBS. The system
* chain may contain forwarders even though the user chain is empty
* (there is no MBeanServer). In that case an attempt to forward an
* incoming request through the chain will fall off the end and fail with a
@@ -726,7 +805,8 @@
private MBeanServer userMBeanServer;
- private MBeanServer systemMBeanServer;
+ private final MBeanServerForwarder systemMBeanServerForwarder =
+ new IdentityMBeanServerForwarder();
/**
* The name used to registered this server in an MBeanServer.
diff --git a/jdk/src/share/classes/javax/management/remote/JMXConnectorServerMBean.java b/jdk/src/share/classes/javax/management/remote/JMXConnectorServerMBean.java
index fb6f883..b784b87 100644
--- a/jdk/src/share/classes/javax/management/remote/JMXConnectorServerMBean.java
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorServerMBean.java
@@ -132,7 +132,7 @@
*
* <p>A connector server may support two chains of forwarders,
* a system chain and a user chain. See {@link
- * JMXConnectorServer#setSystemMBeanServerForwarder} for details.</p>
+ * JMXConnectorServer#getSystemMBeanServerForwarder} for details.</p>
*
* @param mbsf the new <code>MBeanServerForwarder</code>.
*
@@ -141,7 +141,7 @@
* with <code>IllegalArgumentException</code>. This includes the
* case where <code>mbsf</code> is null.
*
- * @see JMXConnectorServer#setSystemMBeanServerForwarder
+ * @see JMXConnectorServer#getSystemMBeanServerForwarder
*/
public void setMBeanServerForwarder(MBeanServerForwarder mbsf);
diff --git a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java
index 1f17143..5f1b8ac 100644
--- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java
@@ -134,14 +134,14 @@
public class RMIConnector implements JMXConnector, Serializable, JMXAddressable {
private static final ClassLogger logger =
- new ClassLogger("javax.management.remote.rmi", "RMIConnector");
+ new ClassLogger("javax.management.remote.rmi", "RMIConnector");
private static final long serialVersionUID = 817323035842634473L;
private RMIConnector(RMIServer rmiServer, JMXServiceURL address,
- Map<String, ?> environment) {
+ Map<String, ?> environment) {
if (rmiServer == null && address == null) throw new
- IllegalArgumentException("rmiServer and jmxServiceURL both null");
+ IllegalArgumentException("rmiServer and jmxServiceURL both null");
initTransients();
@@ -257,7 +257,7 @@
}
public synchronized void connect(Map<String,?> environment)
- throws IOException {
+ throws IOException {
final boolean tracing = logger.traceOn();
String idstr = (tracing?"["+this.toString()+"]":null);
@@ -274,8 +274,8 @@
if (tracing) logger.trace("connect",idstr + " connecting...");
final Map<String, Object> usemap =
- new HashMap<String, Object>((this.env==null) ?
- Collections.<String, Object>emptyMap() : this.env);
+ new HashMap<String, Object>((this.env==null) ?
+ Collections.<String, Object>emptyMap() : this.env);
if (environment != null) {
@@ -315,7 +315,7 @@
defaultClassLoader = EnvHelp.resolveClientClassLoader(usemap);
usemap.put(JMXConnectorFactory.DEFAULT_CLASS_LOADER,
- defaultClassLoader);
+ defaultClassLoader);
rmiNotifClient = new RMINotifClient(defaultClassLoader, usemap);
@@ -333,12 +333,12 @@
eventServiceEnabled = EnvHelp.eventServiceEnabled(env);
Notification connectedNotif =
- new JMXConnectionNotification(JMXConnectionNotification.OPENED,
- this,
- connectionId,
- clientNotifSeqNo++,
- "Successful connection",
- null);
+ new JMXConnectionNotification(JMXConnectionNotification.OPENED,
+ this,
+ connectionId,
+ clientNotifSeqNo++,
+ "Successful connection",
+ null);
sendNotification(connectedNotif);
// whether or not event service
@@ -363,7 +363,7 @@
if (terminated || !connected) {
if (logger.traceOn())
logger.trace("getConnectionId","["+this.toString()+
- "] not connected.");
+ "] not connected.");
throw new IOException("Not connected");
}
@@ -374,23 +374,23 @@
}
public synchronized MBeanServerConnection getMBeanServerConnection()
- throws IOException {
+ throws IOException {
return getMBeanServerConnection(null);
}
public synchronized MBeanServerConnection
- getMBeanServerConnection(Subject delegationSubject)
+ getMBeanServerConnection(Subject delegationSubject)
throws IOException {
if (terminated) {
if (logger.traceOn())
logger.trace("getMBeanServerConnection","[" + this.toString() +
- "] already closed.");
+ "] already closed.");
throw new IOException("Connection closed");
} else if (!connected) {
if (logger.traceOn())
logger.trace("getMBeanServerConnection","[" + this.toString() +
- "] is not connected.");
+ "] is not connected.");
throw new IOException("Not connected");
}
@@ -405,7 +405,7 @@
rmbsc, EventClientDelegateMBean.OBJECT_NAME,
EventClientDelegateMBean.class);
EventClient ec = new EventClient(ecd, null, defaultExecutor(), null,
- EventClient.DEFAULT_LEASE_TIMEOUT);
+ EventClient.DEFAULT_REQUESTED_LEASE_TIME);
rmbsc = EventConnection.Factory.make(rmbsc, ec);
ec.addEventClientListener(
@@ -433,17 +433,17 @@
}
public void
- addConnectionNotificationListener(NotificationListener listener,
- NotificationFilter filter,
- Object handback) {
+ addConnectionNotificationListener(NotificationListener listener,
+ NotificationFilter filter,
+ Object handback) {
if (listener == null)
throw new NullPointerException("listener");
connectionBroadcaster.addNotificationListener(listener, filter,
- handback);
+ handback);
}
public void
- removeConnectionNotificationListener(NotificationListener listener)
+ removeConnectionNotificationListener(NotificationListener listener)
throws ListenerNotFoundException {
if (listener == null)
throw new NullPointerException("listener");
@@ -451,14 +451,14 @@
}
public void
- removeConnectionNotificationListener(NotificationListener listener,
- NotificationFilter filter,
- Object handback)
+ removeConnectionNotificationListener(NotificationListener listener,
+ NotificationFilter filter,
+ Object handback)
throws ListenerNotFoundException {
if (listener == null)
throw new NullPointerException("listener");
connectionBroadcaster.removeNotificationListener(listener, filter,
- handback);
+ handback);
}
private void sendNotification(Notification n) {
@@ -526,11 +526,11 @@
try {
rmiNotifClient.terminate();
if (tracing) logger.trace("close",idstr +
- " RMI Notification client terminated.");
+ " RMI Notification client terminated.");
} catch (RuntimeException x) {
closeException = x;
if (tracing) logger.trace("close",idstr +
- " Failed to terminate RMI Notification client: " + x);
+ " Failed to terminate RMI Notification client: " + x);
if (debug) logger.debug("close",x);
}
}
@@ -544,7 +544,7 @@
} catch (IOException e) {
closeException = e;
if (tracing) logger.trace("close",idstr +
- " Failed to close RMIServer: " + e);
+ " Failed to close RMIServer: " + e);
if (debug) logger.debug("close",e);
}
}
@@ -559,12 +559,12 @@
if (savedConnectionId != null) {
Notification closedNotif =
- new JMXConnectionNotification(JMXConnectionNotification.CLOSED,
- this,
- savedConnectionId,
- clientNotifSeqNo++,
- "Client has been closed",
- null);
+ new JMXConnectionNotification(JMXConnectionNotification.CLOSED,
+ this,
+ savedConnectionId,
+ clientNotifSeqNo++,
+ "Client has been closed",
+ null);
sendNotification(closedNotif);
}
@@ -572,13 +572,13 @@
//
if (closeException != null) {
if (tracing) logger.trace("close",idstr + " failed to close: " +
- closeException);
+ closeException);
if (closeException instanceof IOException)
throw (IOException) closeException;
if (closeException instanceof RuntimeException)
throw (RuntimeException) closeException;
final IOException x =
- new IOException("Failed to close: " + closeException);
+ new IOException("Failed to close: " + closeException);
throw EnvHelp.initCause(x,closeException);
}
}
@@ -593,7 +593,7 @@
final boolean debug = logger.debugOn();
if (debug)
logger.debug("addListenerWithSubject",
- "(ObjectName,MarshalledObject,Subject)");
+ "(ObjectName,MarshalledObject,Subject)");
final ObjectName[] names = new ObjectName[] {name};
final MarshalledObject<NotificationFilter>[] filters =
@@ -603,11 +603,11 @@
};
final Integer[] listenerIDs =
- addListenersWithSubjects(names,filters,delegationSubjects,
- reconnect);
+ addListenersWithSubjects(names,filters,delegationSubjects,
+ reconnect);
if (debug) logger.debug("addListenerWithSubject","listenerID="
- + listenerIDs[0]);
+ + listenerIDs[0]);
return listenerIDs[0];
}
@@ -620,24 +620,24 @@
final boolean debug = logger.debugOn();
if (debug)
- logger.debug("addListenersWithSubjects",
- "(ObjectName[],MarshalledObject[],Subject[])");
+ logger.debug("addListenersWithSubjects",
+ "(ObjectName[],MarshalledObject[],Subject[])");
final ClassLoader old = pushDefaultClassLoader();
Integer[] listenerIDs = null;
try {
listenerIDs = connection.addNotificationListeners(names,
- filters,
- delegationSubjects);
+ filters,
+ delegationSubjects);
} catch (NoSuchObjectException noe) {
// maybe reconnect
if (reconnect) {
communicatorAdmin.gotIOException(noe);
listenerIDs = connection.addNotificationListeners(names,
- filters,
- delegationSubjects);
+ filters,
+ delegationSubjects);
} else {
throw noe;
}
@@ -671,65 +671,65 @@
}
public ObjectInstance createMBean(String className,
- ObjectName name)
+ ObjectName name)
throws ReflectionException,
- InstanceAlreadyExistsException,
- MBeanRegistrationException,
- MBeanException,
- NotCompliantMBeanException,
- IOException {
+ InstanceAlreadyExistsException,
+ MBeanRegistrationException,
+ MBeanException,
+ NotCompliantMBeanException,
+ IOException {
if (logger.debugOn())
logger.debug("createMBean(String,ObjectName)",
- "className=" + className + ", name=" +
- name);
+ "className=" + className + ", name=" +
+ name);
final ClassLoader old = pushDefaultClassLoader();
try {
return connection.createMBean(className,
- name,
- delegationSubject);
+ name,
+ delegationSubject);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
return connection.createMBean(className,
- name,
- delegationSubject);
+ name,
+ delegationSubject);
} finally {
popDefaultClassLoader(old);
}
}
public ObjectInstance createMBean(String className,
- ObjectName name,
- ObjectName loaderName)
- throws ReflectionException,
- InstanceAlreadyExistsException,
- MBeanRegistrationException,
- MBeanException,
- NotCompliantMBeanException,
- InstanceNotFoundException,
- IOException {
+ ObjectName name,
+ ObjectName loaderName)
+ throws ReflectionException,
+ InstanceAlreadyExistsException,
+ MBeanRegistrationException,
+ MBeanException,
+ NotCompliantMBeanException,
+ InstanceNotFoundException,
+ IOException {
if (logger.debugOn())
logger.debug("createMBean(String,ObjectName,ObjectName)",
- "className=" + className + ", name="
- + name + ", loaderName="
- + loaderName + ")");
+ "className=" + className + ", name="
+ + name + ", loaderName="
+ + loaderName + ")");
final ClassLoader old = pushDefaultClassLoader();
try {
return connection.createMBean(className,
- name,
- loaderName,
- delegationSubject);
+ name,
+ loaderName,
+ delegationSubject);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
return connection.createMBean(className,
- name,
- loaderName,
- delegationSubject);
+ name,
+ loaderName,
+ delegationSubject);
} finally {
popDefaultClassLoader(old);
@@ -737,90 +737,90 @@
}
public ObjectInstance createMBean(String className,
- ObjectName name,
- Object params[],
- String signature[])
+ ObjectName name,
+ Object params[],
+ String signature[])
throws ReflectionException,
- InstanceAlreadyExistsException,
- MBeanRegistrationException,
- MBeanException,
- NotCompliantMBeanException,
- IOException {
+ InstanceAlreadyExistsException,
+ MBeanRegistrationException,
+ MBeanException,
+ NotCompliantMBeanException,
+ IOException {
if (logger.debugOn())
- logger.debug("createMBean(String,ObjectName,Object[],String[])",
- "className=" + className + ", name="
- + name + ", params="
- + objects(params) + ", signature="
- + strings(signature));
+ logger.debug("createMBean(String,ObjectName,Object[],String[])",
+ "className=" + className + ", name="
+ + name + ", params="
+ + objects(params) + ", signature="
+ + strings(signature));
final MarshalledObject<Object[]> sParams =
new MarshalledObject<Object[]>(params);
final ClassLoader old = pushDefaultClassLoader();
try {
return connection.createMBean(className,
- name,
- sParams,
- signature,
- delegationSubject);
+ name,
+ sParams,
+ signature,
+ delegationSubject);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
return connection.createMBean(className,
- name,
- sParams,
- signature,
- delegationSubject);
+ name,
+ sParams,
+ signature,
+ delegationSubject);
} finally {
popDefaultClassLoader(old);
}
}
public ObjectInstance createMBean(String className,
- ObjectName name,
- ObjectName loaderName,
- Object params[],
- String signature[])
+ ObjectName name,
+ ObjectName loaderName,
+ Object params[],
+ String signature[])
throws ReflectionException,
- InstanceAlreadyExistsException,
- MBeanRegistrationException,
- MBeanException,
- NotCompliantMBeanException,
- InstanceNotFoundException,
- IOException {
+ InstanceAlreadyExistsException,
+ MBeanRegistrationException,
+ MBeanException,
+ NotCompliantMBeanException,
+ InstanceNotFoundException,
+ IOException {
if (logger.debugOn()) logger.debug(
- "createMBean(String,ObjectName,ObjectName,Object[],String[])",
- "className=" + className + ", name=" + name + ", loaderName="
- + loaderName + ", params=" + objects(params)
- + ", signature=" + strings(signature));
+ "createMBean(String,ObjectName,ObjectName,Object[],String[])",
+ "className=" + className + ", name=" + name + ", loaderName="
+ + loaderName + ", params=" + objects(params)
+ + ", signature=" + strings(signature));
final MarshalledObject<Object[]> sParams =
new MarshalledObject<Object[]>(params);
final ClassLoader old = pushDefaultClassLoader();
try {
return connection.createMBean(className,
- name,
- loaderName,
- sParams,
- signature,
- delegationSubject);
+ name,
+ loaderName,
+ sParams,
+ signature,
+ delegationSubject);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
return connection.createMBean(className,
- name,
- loaderName,
- sParams,
- signature,
- delegationSubject);
+ name,
+ loaderName,
+ sParams,
+ signature,
+ delegationSubject);
} finally {
popDefaultClassLoader(old);
}
}
public void unregisterMBean(ObjectName name)
- throws InstanceNotFoundException,
- MBeanRegistrationException,
- IOException {
+ throws InstanceNotFoundException,
+ MBeanRegistrationException,
+ IOException {
if (logger.debugOn())
logger.debug("unregisterMBean", "name=" + name);
@@ -837,8 +837,8 @@
}
public ObjectInstance getObjectInstance(ObjectName name)
- throws InstanceNotFoundException,
- IOException {
+ throws InstanceNotFoundException,
+ IOException {
if (logger.debugOn())
logger.debug("getObjectInstance", "name=" + name);
@@ -855,10 +855,10 @@
}
public Set<ObjectInstance> queryMBeans(ObjectName name,
- QueryExp query)
- throws IOException {
+ QueryExp query)
+ throws IOException {
if (logger.debugOn()) logger.debug("queryMBeans",
- "name=" + name + ", query=" + query);
+ "name=" + name + ", query=" + query);
final MarshalledObject<QueryExp> sQuery =
new MarshalledObject<QueryExp>(query);
@@ -875,10 +875,10 @@
}
public Set<ObjectName> queryNames(ObjectName name,
- QueryExp query)
+ QueryExp query)
throws IOException {
if (logger.debugOn()) logger.debug("queryNames",
- "name=" + name + ", query=" + query);
+ "name=" + name + ", query=" + query);
final MarshalledObject<QueryExp> sQuery =
new MarshalledObject<QueryExp>(query);
@@ -895,7 +895,7 @@
}
public boolean isRegistered(ObjectName name)
- throws IOException {
+ throws IOException {
if (logger.debugOn())
logger.debug("isRegistered", "name=" + name);
@@ -912,7 +912,7 @@
}
public Integer getMBeanCount()
- throws IOException {
+ throws IOException {
if (logger.debugOn()) logger.debug("getMBeanCount", "");
final ClassLoader old = pushDefaultClassLoader();
@@ -928,53 +928,53 @@
}
public Object getAttribute(ObjectName name,
- String attribute)
+ String attribute)
throws MBeanException,
- AttributeNotFoundException,
- InstanceNotFoundException,
- ReflectionException,
- IOException {
+ AttributeNotFoundException,
+ InstanceNotFoundException,
+ ReflectionException,
+ IOException {
if (logger.debugOn()) logger.debug("getAttribute",
- "name=" + name + ", attribute="
- + attribute);
+ "name=" + name + ", attribute="
+ + attribute);
final ClassLoader old = pushDefaultClassLoader();
try {
return connection.getAttribute(name,
- attribute,
- delegationSubject);
+ attribute,
+ delegationSubject);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
return connection.getAttribute(name,
- attribute,
- delegationSubject);
+ attribute,
+ delegationSubject);
} finally {
popDefaultClassLoader(old);
}
}
public AttributeList getAttributes(ObjectName name,
- String[] attributes)
+ String[] attributes)
throws InstanceNotFoundException,
- ReflectionException,
- IOException {
+ ReflectionException,
+ IOException {
if (logger.debugOn()) logger.debug("getAttributes",
- "name=" + name + ", attributes="
- + strings(attributes));
+ "name=" + name + ", attributes="
+ + strings(attributes));
final ClassLoader old = pushDefaultClassLoader();
try {
return connection.getAttributes(name,
- attributes,
- delegationSubject);
+ attributes,
+ delegationSubject);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
return connection.getAttributes(name,
- attributes,
- delegationSubject);
+ attributes,
+ delegationSubject);
} finally {
popDefaultClassLoader(old);
}
@@ -982,20 +982,20 @@
public void setAttribute(ObjectName name,
- Attribute attribute)
- throws InstanceNotFoundException,
- AttributeNotFoundException,
- InvalidAttributeValueException,
- MBeanException,
- ReflectionException,
- IOException {
+ Attribute attribute)
+ throws InstanceNotFoundException,
+ AttributeNotFoundException,
+ InvalidAttributeValueException,
+ MBeanException,
+ ReflectionException,
+ IOException {
if (logger.debugOn()) logger.debug("setAttribute",
- "name=" + name + ", attribute="
- + attribute);
+ "name=" + name + ", attribute="
+ + attribute);
final MarshalledObject<Attribute> sAttribute =
- new MarshalledObject<Attribute>(attribute);
+ new MarshalledObject<Attribute>(attribute);
final ClassLoader old = pushDefaultClassLoader();
try {
connection.setAttribute(name, sAttribute, delegationSubject);
@@ -1009,28 +1009,28 @@
}
public AttributeList setAttributes(ObjectName name,
- AttributeList attributes)
- throws InstanceNotFoundException,
- ReflectionException,
- IOException {
+ AttributeList attributes)
+ throws InstanceNotFoundException,
+ ReflectionException,
+ IOException {
if (logger.debugOn()) logger.debug("setAttributes",
- "name=" + name + ", attributes="
- + attributes);
+ "name=" + name + ", attributes="
+ + attributes);
final MarshalledObject<AttributeList> sAttributes =
- new MarshalledObject<AttributeList>(attributes);
+ new MarshalledObject<AttributeList>(attributes);
final ClassLoader old = pushDefaultClassLoader();
try {
return connection.setAttributes(name,
- sAttributes,
- delegationSubject);
+ sAttributes,
+ delegationSubject);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
return connection.setAttributes(name,
- sAttributes,
- delegationSubject);
+ sAttributes,
+ delegationSubject);
} finally {
popDefaultClassLoader(old);
}
@@ -1038,37 +1038,37 @@
public Object invoke(ObjectName name,
- String operationName,
- Object params[],
- String signature[])
+ String operationName,
+ Object params[],
+ String signature[])
throws InstanceNotFoundException,
- MBeanException,
- ReflectionException,
- IOException {
+ MBeanException,
+ ReflectionException,
+ IOException {
if (logger.debugOn()) logger.debug("invoke",
- "name=" + name
- + ", operationName=" + operationName
- + ", params=" + objects(params)
- + ", signature=" + strings(signature));
+ "name=" + name
+ + ", operationName=" + operationName
+ + ", params=" + objects(params)
+ + ", signature=" + strings(signature));
final MarshalledObject<Object[]> sParams =
new MarshalledObject<Object[]>(params);
final ClassLoader old = pushDefaultClassLoader();
try {
return connection.invoke(name,
- operationName,
- sParams,
- signature,
- delegationSubject);
+ operationName,
+ sParams,
+ signature,
+ delegationSubject);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
return connection.invoke(name,
- operationName,
- sParams,
- signature,
- delegationSubject);
+ operationName,
+ sParams,
+ signature,
+ delegationSubject);
} finally {
popDefaultClassLoader(old);
}
@@ -1076,7 +1076,7 @@
public String getDefaultDomain()
- throws IOException {
+ throws IOException {
if (logger.debugOn()) logger.debug("getDefaultDomain", "");
final ClassLoader old = pushDefaultClassLoader();
@@ -1107,10 +1107,10 @@
}
public MBeanInfo getMBeanInfo(ObjectName name)
- throws InstanceNotFoundException,
- IntrospectionException,
- ReflectionException,
- IOException {
+ throws InstanceNotFoundException,
+ IntrospectionException,
+ ReflectionException,
+ IOException {
if (logger.debugOn()) logger.debug("getMBeanInfo", "name=" + name);
final ClassLoader old = pushDefaultClassLoader();
@@ -1127,41 +1127,41 @@
public boolean isInstanceOf(ObjectName name,
- String className)
+ String className)
throws InstanceNotFoundException,
- IOException {
+ IOException {
if (logger.debugOn())
logger.debug("isInstanceOf", "name=" + name +
- ", className=" + className);
+ ", className=" + className);
final ClassLoader old = pushDefaultClassLoader();
try {
return connection.isInstanceOf(name,
- className,
- delegationSubject);
+ className,
+ delegationSubject);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
return connection.isInstanceOf(name,
- className,
- delegationSubject);
+ className,
+ delegationSubject);
} finally {
popDefaultClassLoader(old);
}
}
public void addNotificationListener(ObjectName name,
- ObjectName listener,
- NotificationFilter filter,
- Object handback)
+ ObjectName listener,
+ NotificationFilter filter,
+ Object handback)
throws InstanceNotFoundException,
- IOException {
+ IOException {
if (logger.debugOn())
logger.debug("addNotificationListener" +
- "(ObjectName,ObjectName,NotificationFilter,Object)",
- "name=" + name + ", listener=" + listener
- + ", filter=" + filter + ", handback=" + handback);
+ "(ObjectName,ObjectName,NotificationFilter,Object)",
+ "name=" + name + ", listener=" + listener
+ + ", filter=" + filter + ", handback=" + handback);
final MarshalledObject<NotificationFilter> sFilter =
new MarshalledObject<NotificationFilter>(filter);
@@ -1170,64 +1170,64 @@
final ClassLoader old = pushDefaultClassLoader();
try {
connection.addNotificationListener(name,
- listener,
- sFilter,
- sHandback,
- delegationSubject);
+ listener,
+ sFilter,
+ sHandback,
+ delegationSubject);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
connection.addNotificationListener(name,
- listener,
- sFilter,
- sHandback,
- delegationSubject);
+ listener,
+ sFilter,
+ sHandback,
+ delegationSubject);
} finally {
popDefaultClassLoader(old);
}
}
public void removeNotificationListener(ObjectName name,
- ObjectName listener)
+ ObjectName listener)
throws InstanceNotFoundException,
- ListenerNotFoundException,
- IOException {
+ ListenerNotFoundException,
+ IOException {
if (logger.debugOn()) logger.debug("removeNotificationListener" +
- "(ObjectName,ObjectName)",
- "name=" + name
- + ", listener=" + listener);
+ "(ObjectName,ObjectName)",
+ "name=" + name
+ + ", listener=" + listener);
final ClassLoader old = pushDefaultClassLoader();
try {
connection.removeNotificationListener(name,
- listener,
- delegationSubject);
+ listener,
+ delegationSubject);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
connection.removeNotificationListener(name,
- listener,
- delegationSubject);
+ listener,
+ delegationSubject);
} finally {
popDefaultClassLoader(old);
}
}
public void removeNotificationListener(ObjectName name,
- ObjectName listener,
- NotificationFilter filter,
- Object handback)
+ ObjectName listener,
+ NotificationFilter filter,
+ Object handback)
throws InstanceNotFoundException,
- ListenerNotFoundException,
- IOException {
+ ListenerNotFoundException,
+ IOException {
if (logger.debugOn())
logger.debug("removeNotificationListener" +
- "(ObjectName,ObjectName,NotificationFilter,Object)",
- "name=" + name
- + ", listener=" + listener
- + ", filter=" + filter
- + ", handback=" + handback);
+ "(ObjectName,ObjectName,NotificationFilter,Object)",
+ "name=" + name
+ + ", listener=" + listener
+ + ", filter=" + filter
+ + ", handback=" + handback);
final MarshalledObject<NotificationFilter> sFilter =
new MarshalledObject<NotificationFilter>(filter);
@@ -1236,18 +1236,18 @@
final ClassLoader old = pushDefaultClassLoader();
try {
connection.removeNotificationListener(name,
- listener,
- sFilter,
- sHandback,
- delegationSubject);
+ listener,
+ sFilter,
+ sHandback,
+ delegationSubject);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
connection.removeNotificationListener(name,
- listener,
- sFilter,
- sHandback,
- delegationSubject);
+ listener,
+ sFilter,
+ sHandback,
+ delegationSubject);
} finally {
popDefaultClassLoader(old);
}
@@ -1256,34 +1256,34 @@
// Specific Notification Handle ----------------------------------
public void addNotificationListener(ObjectName name,
- NotificationListener listener,
- NotificationFilter filter,
- Object handback)
+ NotificationListener listener,
+ NotificationFilter filter,
+ Object handback)
throws InstanceNotFoundException,
- IOException {
+ IOException {
final boolean debug = logger.debugOn();
if (debug)
logger.debug("addNotificationListener" +
- "(ObjectName,NotificationListener,"+
- "NotificationFilter,Object)",
- "name=" + name
- + ", listener=" + listener
- + ", filter=" + filter
- + ", handback=" + handback);
+ "(ObjectName,NotificationListener,"+
+ "NotificationFilter,Object)",
+ "name=" + name
+ + ", listener=" + listener
+ + ", filter=" + filter
+ + ", handback=" + handback);
final Integer listenerID =
- addListenerWithSubject(name,
- new MarshalledObject<NotificationFilter>(filter),
- delegationSubject,true);
+ addListenerWithSubject(name,
+ new MarshalledObject<NotificationFilter>(filter),
+ delegationSubject,true);
rmiNotifClient.addNotificationListener(listenerID, name, listener,
- filter, handback,
- delegationSubject);
+ filter, handback,
+ delegationSubject);
}
public void removeNotificationListener(ObjectName name,
- NotificationListener listener)
+ NotificationListener listener)
throws InstanceNotFoundException,
ListenerNotFoundException,
IOException {
@@ -1291,28 +1291,28 @@
final boolean debug = logger.debugOn();
if (debug) logger.debug("removeNotificationListener"+
- "(ObjectName,NotificationListener)",
- "name=" + name
- + ", listener=" + listener);
+ "(ObjectName,NotificationListener)",
+ "name=" + name
+ + ", listener=" + listener);
final Integer[] ret =
- rmiNotifClient.removeNotificationListener(name, listener);
+ rmiNotifClient.removeNotificationListener(name, listener);
if (debug) logger.debug("removeNotificationListener",
- "listenerIDs=" + objects(ret));
+ "listenerIDs=" + objects(ret));
final ClassLoader old = pushDefaultClassLoader();
try {
connection.removeNotificationListeners(name,
- ret,
- delegationSubject);
+ ret,
+ delegationSubject);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
connection.removeNotificationListeners(name,
- ret,
- delegationSubject);
+ ret,
+ delegationSubject);
} finally {
popDefaultClassLoader(old);
}
@@ -1320,41 +1320,41 @@
}
public void removeNotificationListener(ObjectName name,
- NotificationListener listener,
- NotificationFilter filter,
- Object handback)
- throws InstanceNotFoundException,
- ListenerNotFoundException,
- IOException {
+ NotificationListener listener,
+ NotificationFilter filter,
+ Object handback)
+ throws InstanceNotFoundException,
+ ListenerNotFoundException,
+ IOException {
final boolean debug = logger.debugOn();
if (debug)
logger.debug("removeNotificationListener"+
- "(ObjectName,NotificationListener,"+
- "NotificationFilter,Object)",
- "name=" + name
- + ", listener=" + listener
- + ", filter=" + filter
- + ", handback=" + handback);
+ "(ObjectName,NotificationListener,"+
+ "NotificationFilter,Object)",
+ "name=" + name
+ + ", listener=" + listener
+ + ", filter=" + filter
+ + ", handback=" + handback);
final Integer ret =
- rmiNotifClient.removeNotificationListener(name, listener,
- filter, handback);
+ rmiNotifClient.removeNotificationListener(name, listener,
+ filter, handback);
if (debug) logger.debug("removeNotificationListener",
- "listenerID=" + ret);
+ "listenerID=" + ret);
final ClassLoader old = pushDefaultClassLoader();
try {
connection.removeNotificationListeners(name,
- new Integer[] {ret},
- delegationSubject);
+ new Integer[] {ret},
+ delegationSubject);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
connection.removeNotificationListeners(name,
- new Integer[] {ret},
- delegationSubject);
+ new Integer[] {ret},
+ delegationSubject);
} finally {
popDefaultClassLoader(old);
}
@@ -1369,16 +1369,16 @@
}
protected NotificationResult fetchNotifs(long clientSequenceNumber,
- int maxNotifications,
- long timeout)
+ int maxNotifications,
+ long timeout)
throws IOException, ClassNotFoundException {
IOException org;
while (true) { // used for a successful re-connection
try {
return connection.fetchNotifications(clientSequenceNumber,
- maxNotifications,
- timeout);
+ maxNotifications,
+ timeout);
} catch (IOException ioe) {
org = ioe;
@@ -1417,7 +1417,7 @@
clear we can do much better. */
if (ume.detail instanceof WriteAbortedException) {
WriteAbortedException wae =
- (WriteAbortedException) ume.detail;
+ (WriteAbortedException) ume.detail;
if (wae.detail instanceof IOException)
throw (IOException) wae.detail;
}
@@ -1435,11 +1435,11 @@
}
protected Integer addListenerForMBeanRemovedNotif()
- throws IOException, InstanceNotFoundException {
+ throws IOException, InstanceNotFoundException {
NotificationFilterSupport clientFilter =
- new NotificationFilterSupport();
+ new NotificationFilterSupport();
clientFilter.enableType(
- MBeanServerNotification.UNREGISTRATION_NOTIFICATION);
+ MBeanServerNotification.UNREGISTRATION_NOTIFICATION);
MarshalledObject<NotificationFilter> sFilter =
new MarshalledObject<NotificationFilter>(clientFilter);
@@ -1451,36 +1451,36 @@
final Subject[] subjects = new Subject[] {null};
try {
listenerIDs =
- connection.addNotificationListeners(names,
- filters,
- subjects);
+ connection.addNotificationListeners(names,
+ filters,
+ subjects);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
listenerIDs =
- connection.addNotificationListeners(names,
- filters,
- subjects);
+ connection.addNotificationListeners(names,
+ filters,
+ subjects);
}
return listenerIDs[0];
}
protected void removeListenerForMBeanRemovedNotif(Integer id)
- throws IOException, InstanceNotFoundException,
- ListenerNotFoundException {
+ throws IOException, InstanceNotFoundException,
+ ListenerNotFoundException {
try {
connection.removeNotificationListeners(
- MBeanServerDelegate.DELEGATE_NAME,
- new Integer[] {id},
- null);
+ MBeanServerDelegate.DELEGATE_NAME,
+ new Integer[] {id},
+ null);
} catch (IOException ioe) {
communicatorAdmin.gotIOException(ioe);
connection.removeNotificationListeners(
- MBeanServerDelegate.DELEGATE_NAME,
- new Integer[] {id},
- null);
+ MBeanServerDelegate.DELEGATE_NAME,
+ new Integer[] {id},
+ null);
}
}
@@ -1530,7 +1530,7 @@
// we should close the connection,
// but send a failed notif at first
final Notification failedNotif =
- new JMXConnectionNotification(
+ new JMXConnectionNotification(
JMXConnectionNotification.FAILED,
this,
connectionId,
@@ -1559,7 +1559,7 @@
will throw a ServerException at client side which wraps this
UnmarshalException.
No failed notif here.
- */
+ */
Throwable tt = ((ServerException)ioe).detail;
if (tt instanceof IOException) {
@@ -1600,11 +1600,11 @@
for (i=0;i<len;i++) {
clis[i] = new ClientListenerInfo(ids[i],
- names[i],
- listeners[i],
- filters[i],
- handbacks[i],
- subjects[i]);
+ names[i],
+ listeners[i],
+ filters[i],
+ handbacks[i],
+ subjects[i]);
}
rmiNotifClient.postReconnection(clis);
@@ -1623,15 +1623,15 @@
false);
clis[j++] = new ClientListenerInfo(id,
- names[i],
- listeners[i],
- filters[i],
- handbacks[i],
- subjects[i]);
+ names[i],
+ listeners[i],
+ filters[i],
+ handbacks[i],
+ subjects[i]);
} catch (InstanceNotFoundException infe) {
logger.warning("reconnectNotificationListeners",
- "Can't reconnect listener for " +
- names[i]);
+ "Can't reconnect listener for " +
+ names[i]);
}
}
@@ -1647,7 +1647,7 @@
protected void checkConnection() throws IOException {
if (logger.debugOn())
logger.debug("RMIClientCommunicatorAdmin-checkConnection",
- "Calling the method getDefaultDomain.");
+ "Calling the method getDefaultDomain.");
connection.getDefaultDomain(null);
}
@@ -1677,12 +1677,12 @@
connectionId = getConnectionId();
Notification reconnectedNotif =
- new JMXConnectionNotification(JMXConnectionNotification.OPENED,
- this,
- connectionId,
- clientNotifSeqNo++,
- "Reconnected to server",
- null);
+ new JMXConnectionNotification(JMXConnectionNotification.OPENED,
+ this,
+ connectionId,
+ clientNotifSeqNo++,
+ "Reconnected to server",
+ null);
sendNotification(reconnectedNotif);
}
@@ -1692,7 +1692,7 @@
close();
} catch (IOException ioe) {
logger.warning("RMIClientCommunicatorAdmin-doStop",
- "Failed to call the method close():" + ioe);
+ "Failed to call the method close():" + ioe);
logger.debug("RMIClientCommunicatorAdmin-doStop",ioe);
}
}
@@ -1785,15 +1785,15 @@
final Object orb = environment.get(EnvHelp.DEFAULT_ORB);
if (orb != null && !(orb instanceof ORB))
throw new IllegalArgumentException(EnvHelp.DEFAULT_ORB +
- " must be an instance of org.omg.CORBA.ORB.");
+ " must be an instance of org.omg.CORBA.ORB.");
if (orb != null) return (ORB)orb;
}
final ORB orb =
- (RMIConnector.orb==null)?null:RMIConnector.orb.get();
+ (RMIConnector.orb==null)?null:RMIConnector.orb.get();
if (orb != null) return orb;
final ORB newOrb =
- ORB.init((String[])null, (Properties)null);
+ ORB.init((String[])null, (Properties)null);
RMIConnector.orb = new WeakReference<ORB>(newOrb);
return newOrb;
}
@@ -1810,11 +1810,11 @@
* @see #RMIConnector(RMIServer,Map)
**/
private void readObject(java.io.ObjectInputStream s)
- throws IOException, ClassNotFoundException {
+ throws IOException, ClassNotFoundException {
s.defaultReadObject();
if (rmiServer == null && jmxServiceURL == null) throw new
- InvalidObjectException("rmiServer and jmxServiceURL both null");
+ InvalidObjectException("rmiServer and jmxServiceURL both null");
initTransients();
}
@@ -1851,9 +1851,9 @@
* @see #RMIConnector(RMIServer,Map)
**/
private void writeObject(java.io.ObjectOutputStream s)
- throws IOException {
+ throws IOException {
if (rmiServer == null && jmxServiceURL == null) throw new
- InvalidObjectException("rmiServer and jmxServiceURL both null.");
+ InvalidObjectException("rmiServer and jmxServiceURL both null.");
connectStub(this.rmiServer,env);
s.defaultWriteObject();
}
@@ -1892,21 +1892,21 @@
//--------------------------------------------------------------------
private static void checkStub(Remote stub,
- Class<?> stubClass) {
+ Class<?> stubClass) {
// Check remote stub is from the expected class.
//
if (stub.getClass() != stubClass) {
if (!Proxy.isProxyClass(stub.getClass())) {
throw new SecurityException(
- "Expecting a " + stubClass.getName() + " stub!");
+ "Expecting a " + stubClass.getName() + " stub!");
} else {
InvocationHandler handler = Proxy.getInvocationHandler(stub);
if (handler.getClass() != RemoteObjectInvocationHandler.class)
throw new SecurityException(
- "Expecting a dynamic proxy instance with a " +
- RemoteObjectInvocationHandler.class.getName() +
- " invocation handler!");
+ "Expecting a dynamic proxy instance with a " +
+ RemoteObjectInvocationHandler.class.getName() +
+ " invocation handler!");
else
stub = (Remote) handler;
}
@@ -1918,8 +1918,8 @@
RemoteRef ref = ((RemoteObject)stub).getRef();
if (ref.getClass() != UnicastRef2.class)
throw new SecurityException(
- "Expecting a " + UnicastRef2.class.getName() +
- " remote reference in stub!");
+ "Expecting a " + UnicastRef2.class.getName() +
+ " remote reference in stub!");
// Check RMIClientSocketFactory in stub is from the expected class
// "javax.rmi.ssl.SslRMIClientSocketFactory".
@@ -1928,8 +1928,8 @@
RMIClientSocketFactory csf = liveRef.getClientSocketFactory();
if (csf == null || csf.getClass() != SslRMIClientSocketFactory.class)
throw new SecurityException(
- "Expecting a " + SslRMIClientSocketFactory.class.getName() +
- " RMI client socket factory in stub!");
+ "Expecting a " + SslRMIClientSocketFactory.class.getName() +
+ " RMI client socket factory in stub!");
}
//--------------------------------------------------------------------
@@ -1937,8 +1937,8 @@
//--------------------------------------------------------------------
private RMIServer findRMIServer(JMXServiceURL directoryURL,
- Map<String, Object> environment)
- throws NamingException, IOException {
+ Map<String, Object> environment)
+ throws NamingException, IOException {
final boolean isIiop = RMIConnectorServer.isIiopURL(directoryURL,true);
if (isIiop) {
// Make sure java.naming.corba.orb is in the Map.
@@ -1956,7 +1956,7 @@
return findRMIServerIIOP(path.substring(5,end), environment, isIiop);
else {
final String msg = "URL path must begin with /jndi/ or /stub/ " +
- "or /ior/: " + path;
+ "or /ior/: " + path;
throw new MalformedURLException(msg);
}
}
@@ -1975,8 +1975,8 @@
* @exception NamingException if the stub couldn't be found.
**/
private RMIServer findRMIServerJNDI(String jndiURL, Map<String, ?> env,
- boolean isIiop)
- throws NamingException {
+ boolean isIiop)
+ throws NamingException {
InitialContext ctx = new InitialContext(EnvHelp.mapToHashtable(env));
@@ -1997,11 +1997,11 @@
private static RMIServer narrowIIOPServer(Object objref) {
try {
return (RMIServer)
- PortableRemoteObject.narrow(objref, RMIServer.class);
+ PortableRemoteObject.narrow(objref, RMIServer.class);
} catch (ClassCastException e) {
if (logger.traceOn())
logger.trace("narrowIIOPServer","Failed to narrow objref=" +
- objref + ": " + e);
+ objref + ": " + e);
if (logger.debugOn()) logger.debug("narrowIIOPServer",e);
return null;
}
@@ -2010,7 +2010,7 @@
private RMIServer findRMIServerIIOP(String ior, Map<String, ?> env, boolean isIiop) {
// could forbid "rmi:" URL here -- but do we need to?
final ORB orb = (ORB)
- env.get(EnvHelp.DEFAULT_ORB);
+ env.get(EnvHelp.DEFAULT_ORB);
final Object stub = orb.string_to_object(ior);
return (RMIServer) PortableRemoteObject.narrow(stub, RMIServer.class);
}
@@ -2023,15 +2023,15 @@
serialized = base64ToByteArray(base64);
} catch (IllegalArgumentException e) {
throw new MalformedURLException("Bad BASE64 encoding: " +
- e.getMessage());
+ e.getMessage());
}
final ByteArrayInputStream bin = new ByteArrayInputStream(serialized);
final ClassLoader loader = EnvHelp.resolveClientClassLoader(env);
final ObjectInputStream oin =
- (loader == null) ?
- new ObjectInputStream(bin) :
- new ObjectInputStreamWithLoader(bin, loader);
+ (loader == null) ?
+ new ObjectInputStream(bin) :
+ new ObjectInputStreamWithLoader(bin, loader);
final Object stub;
try {
stub = oin.readObject();
@@ -2044,7 +2044,7 @@
private static final class ObjectInputStreamWithLoader
extends ObjectInputStream {
ObjectInputStreamWithLoader(InputStream in, ClassLoader cl)
- throws IOException {
+ throws IOException {
super(in);
this.loader = cl;
}
@@ -2127,40 +2127,40 @@
RMIServer.class.getName() + "Impl_Stub";
private static final Class<?> rmiServerImplStubClass;
private static final String rmiConnectionImplStubClassName =
- RMIConnection.class.getName() + "Impl_Stub";
+ RMIConnection.class.getName() + "Impl_Stub";
private static final Class<?> rmiConnectionImplStubClass;
private static final String pRefClassName =
"com.sun.jmx.remote.internal.PRef";
private static final Constructor<?> proxyRefConstructor;
static {
final String pRefByteCodeString =
- "\312\376\272\276\0\0\0.\0\27\12\0\5\0\15\11\0\4\0\16\13\0\17\0"+
- "\20\7\0\21\7\0\22\1\0\6<init>\1\0\36(Ljava/rmi/server/RemoteRef;"+
- ")V\1\0\4Code\1\0\6invoke\1\0S(Ljava/rmi/Remote;Ljava/lang/reflec"+
- "t/Method;[Ljava/lang/Object;J)Ljava/lang/Object;\1\0\12Exception"+
- "s\7\0\23\14\0\6\0\7\14\0\24\0\25\7\0\26\14\0\11\0\12\1\0\40com/"+
- "sun/jmx/remote/internal/PRef\1\0$com/sun/jmx/remote/internal/Pr"+
- "oxyRef\1\0\23java/lang/Exception\1\0\3ref\1\0\33Ljava/rmi/serve"+
- "r/RemoteRef;\1\0\31java/rmi/server/RemoteRef\0!\0\4\0\5\0\0\0\0"+
- "\0\2\0\1\0\6\0\7\0\1\0\10\0\0\0\22\0\2\0\2\0\0\0\6*+\267\0\1\261"+
- "\0\0\0\0\0\1\0\11\0\12\0\2\0\10\0\0\0\33\0\6\0\6\0\0\0\17*\264\0"+
- "\2+,-\26\4\271\0\3\6\0\260\0\0\0\0\0\13\0\0\0\4\0\1\0\14\0\0";
+ "\312\376\272\276\0\0\0.\0\27\12\0\5\0\15\11\0\4\0\16\13\0\17\0"+
+ "\20\7\0\21\7\0\22\1\0\6<init>\1\0\36(Ljava/rmi/server/RemoteRef;"+
+ ")V\1\0\4Code\1\0\6invoke\1\0S(Ljava/rmi/Remote;Ljava/lang/reflec"+
+ "t/Method;[Ljava/lang/Object;J)Ljava/lang/Object;\1\0\12Exception"+
+ "s\7\0\23\14\0\6\0\7\14\0\24\0\25\7\0\26\14\0\11\0\12\1\0\40com/"+
+ "sun/jmx/remote/internal/PRef\1\0$com/sun/jmx/remote/internal/Pr"+
+ "oxyRef\1\0\23java/lang/Exception\1\0\3ref\1\0\33Ljava/rmi/serve"+
+ "r/RemoteRef;\1\0\31java/rmi/server/RemoteRef\0!\0\4\0\5\0\0\0\0"+
+ "\0\2\0\1\0\6\0\7\0\1\0\10\0\0\0\22\0\2\0\2\0\0\0\6*+\267\0\1\261"+
+ "\0\0\0\0\0\1\0\11\0\12\0\2\0\10\0\0\0\33\0\6\0\6\0\0\0\17*\264\0"+
+ "\2+,-\26\4\271\0\3\6\0\260\0\0\0\0\0\13\0\0\0\4\0\1\0\14\0\0";
final byte[] pRefByteCode =
- NoCallStackClassLoader.stringToBytes(pRefByteCodeString);
+ NoCallStackClassLoader.stringToBytes(pRefByteCodeString);
PrivilegedExceptionAction<Constructor<?>> action =
new PrivilegedExceptionAction<Constructor<?>>() {
public Constructor<?> run() throws Exception {
Class thisClass = RMIConnector.class;
ClassLoader thisLoader = thisClass.getClassLoader();
ProtectionDomain thisProtectionDomain =
- thisClass.getProtectionDomain();
+ thisClass.getProtectionDomain();
String[] otherClassNames = {ProxyRef.class.getName()};
ClassLoader cl =
- new NoCallStackClassLoader(pRefClassName,
- pRefByteCode,
- otherClassNames,
- thisLoader,
- thisProtectionDomain);
+ new NoCallStackClassLoader(pRefClassName,
+ pRefByteCode,
+ otherClassNames,
+ thisLoader,
+ thisProtectionDomain);
Class<?> c = cl.loadClass(pRefClassName);
return c.getConstructor(RemoteRef.class);
}
@@ -2171,8 +2171,8 @@
serverStubClass = Class.forName(rmiServerImplStubClassName);
} catch (Exception e) {
logger.error("<clinit>",
- "Failed to instantiate " +
- rmiServerImplStubClassName + ": " + e);
+ "Failed to instantiate " +
+ rmiServerImplStubClassName + ": " + e);
logger.debug("<clinit>",e);
serverStubClass = null;
}
@@ -2185,8 +2185,8 @@
constr = (Constructor<?>) AccessController.doPrivileged(action);
} catch (Exception e) {
logger.error("<clinit>",
- "Failed to initialize proxy reference constructor "+
- "for " + rmiConnectionImplStubClassName + ": " + e);
+ "Failed to initialize proxy reference constructor "+
+ "for " + rmiConnectionImplStubClassName + ": " + e);
logger.debug("<clinit>",e);
stubClass = null;
constr = null;
@@ -2196,9 +2196,9 @@
}
private static RMIConnection shadowJrmpStub(RemoteObject stub)
- throws InstantiationException, IllegalAccessException,
- InvocationTargetException, ClassNotFoundException,
- NoSuchMethodException {
+ throws InstantiationException, IllegalAccessException,
+ InvocationTargetException, ClassNotFoundException,
+ NoSuchMethodException {
RemoteRef ref = stub.getRef();
RemoteRef proxyRef = (RemoteRef)
proxyRefConstructor.newInstance(new Object[] {ref});
@@ -2206,7 +2206,7 @@
rmiConnectionImplStubClass.getConstructor(RemoteRef.class);
Object[] args = {proxyRef};
RMIConnection proxyStub = (RMIConnection)
- rmiConnectionImplStubConstructor.newInstance(args);
+ rmiConnectionImplStubConstructor.newInstance(args);
return proxyStub;
}
@@ -2326,55 +2326,55 @@
*/
private static final String iiopConnectionStubClassName =
- "org.omg.stub.javax.management.remote.rmi._RMIConnection_Stub";
+ "org.omg.stub.javax.management.remote.rmi._RMIConnection_Stub";
private static final String proxyStubClassName =
- "com.sun.jmx.remote.internal.ProxyStub";
+ "com.sun.jmx.remote.internal.ProxyStub";
private static final String pInputStreamClassName =
"com.sun.jmx.remote.internal.PInputStream";
private static final Class<?> proxyStubClass;
static {
final String proxyStubByteCodeString =
- "\312\376\272\276\0\0\0.\0)\12\0\14\0\26\7\0\27\12\0\14\0\30\12"+
- "\0\2\0\31\7\0\32\12\0\5\0\33\12\0\5\0\34\12\0\5\0\35\12\0\2\0"+
- "\36\12\0\14\0\37\7\0\40\7\0!\1\0\6<init>\1\0\3()V\1\0\4Code\1"+
- "\0\7_invoke\1\0K(Lorg/omg/CORBA/portable/OutputStream;)Lorg/o"+
- "mg/CORBA/portable/InputStream;\1\0\12Exceptions\7\0\"\1\0\15_"+
- "releaseReply\1\0'(Lorg/omg/CORBA/portable/InputStream;)V\14\0"+
- "\15\0\16\1\0(com/sun/jmx/remote/internal/PInputStream\14\0\20"+
- "\0\21\14\0\15\0\25\1\0+org/omg/CORBA/portable/ApplicationExce"+
- "ption\14\0#\0$\14\0%\0&\14\0\15\0'\14\0(\0$\14\0\24\0\25\1\0%"+
- "com/sun/jmx/remote/internal/ProxyStub\1\0<org/omg/stub/javax/"+
- "management/remote/rmi/_RMIConnection_Stub\1\0)org/omg/CORBA/p"+
- "ortable/RemarshalException\1\0\16getInputStream\1\0&()Lorg/om"+
- "g/CORBA/portable/InputStream;\1\0\5getId\1\0\24()Ljava/lang/S"+
- "tring;\1\09(Ljava/lang/String;Lorg/omg/CORBA/portable/InputSt"+
- "ream;)V\1\0\25getProxiedInputStream\0!\0\13\0\14\0\0\0\0\0\3\0"+
- "\1\0\15\0\16\0\1\0\17\0\0\0\21\0\1\0\1\0\0\0\5*\267\0\1\261\0"+
- "\0\0\0\0\1\0\20\0\21\0\2\0\17\0\0\0;\0\4\0\4\0\0\0'\273\0\2Y*"+
- "+\267\0\3\267\0\4\260M\273\0\2Y,\266\0\6\267\0\4N\273\0\5Y,\266"+
- "\0\7-\267\0\10\277\0\1\0\0\0\14\0\15\0\5\0\0\0\22\0\0\0\6\0\2"+
- "\0\5\0\23\0\1\0\24\0\25\0\1\0\17\0\0\0\36\0\2\0\2\0\0\0\22+\306"+
- "\0\13+\300\0\2\266\0\11L*+\267\0\12\261\0\0\0\0\0\0";
+ "\312\376\272\276\0\0\0.\0)\12\0\14\0\26\7\0\27\12\0\14\0\30\12"+
+ "\0\2\0\31\7\0\32\12\0\5\0\33\12\0\5\0\34\12\0\5\0\35\12\0\2\0"+
+ "\36\12\0\14\0\37\7\0\40\7\0!\1\0\6<init>\1\0\3()V\1\0\4Code\1"+
+ "\0\7_invoke\1\0K(Lorg/omg/CORBA/portable/OutputStream;)Lorg/o"+
+ "mg/CORBA/portable/InputStream;\1\0\12Exceptions\7\0\"\1\0\15_"+
+ "releaseReply\1\0'(Lorg/omg/CORBA/portable/InputStream;)V\14\0"+
+ "\15\0\16\1\0(com/sun/jmx/remote/internal/PInputStream\14\0\20"+
+ "\0\21\14\0\15\0\25\1\0+org/omg/CORBA/portable/ApplicationExce"+
+ "ption\14\0#\0$\14\0%\0&\14\0\15\0'\14\0(\0$\14\0\24\0\25\1\0%"+
+ "com/sun/jmx/remote/internal/ProxyStub\1\0<org/omg/stub/javax/"+
+ "management/remote/rmi/_RMIConnection_Stub\1\0)org/omg/CORBA/p"+
+ "ortable/RemarshalException\1\0\16getInputStream\1\0&()Lorg/om"+
+ "g/CORBA/portable/InputStream;\1\0\5getId\1\0\24()Ljava/lang/S"+
+ "tring;\1\09(Ljava/lang/String;Lorg/omg/CORBA/portable/InputSt"+
+ "ream;)V\1\0\25getProxiedInputStream\0!\0\13\0\14\0\0\0\0\0\3\0"+
+ "\1\0\15\0\16\0\1\0\17\0\0\0\21\0\1\0\1\0\0\0\5*\267\0\1\261\0"+
+ "\0\0\0\0\1\0\20\0\21\0\2\0\17\0\0\0;\0\4\0\4\0\0\0'\273\0\2Y*"+
+ "+\267\0\3\267\0\4\260M\273\0\2Y,\266\0\6\267\0\4N\273\0\5Y,\266"+
+ "\0\7-\267\0\10\277\0\1\0\0\0\14\0\15\0\5\0\0\0\22\0\0\0\6\0\2"+
+ "\0\5\0\23\0\1\0\24\0\25\0\1\0\17\0\0\0\36\0\2\0\2\0\0\0\22+\306"+
+ "\0\13+\300\0\2\266\0\11L*+\267\0\12\261\0\0\0\0\0\0";
final String pInputStreamByteCodeString =
- "\312\376\272\276\0\0\0.\0\36\12\0\7\0\17\11\0\6\0\20\12\0\21\0"+
- "\22\12\0\6\0\23\12\0\24\0\25\7\0\26\7\0\27\1\0\6<init>\1\0'(L"+
- "org/omg/CORBA/portable/InputStream;)V\1\0\4Code\1\0\10read_an"+
- "y\1\0\25()Lorg/omg/CORBA/Any;\1\0\12read_value\1\0)(Ljava/lan"+
- "g/Class;)Ljava/io/Serializable;\14\0\10\0\11\14\0\30\0\31\7\0"+
- "\32\14\0\13\0\14\14\0\33\0\34\7\0\35\14\0\15\0\16\1\0(com/sun"+
- "/jmx/remote/internal/PInputStream\1\0,com/sun/jmx/remote/inte"+
- "rnal/ProxyInputStream\1\0\2in\1\0$Lorg/omg/CORBA/portable/Inp"+
- "utStream;\1\0\"org/omg/CORBA/portable/InputStream\1\0\6narrow"+
- "\1\0*()Lorg/omg/CORBA_2_3/portable/InputStream;\1\0&org/omg/C"+
- "ORBA_2_3/portable/InputStream\0!\0\6\0\7\0\0\0\0\0\3\0\1\0\10"+
- "\0\11\0\1\0\12\0\0\0\22\0\2\0\2\0\0\0\6*+\267\0\1\261\0\0\0\0"+
- "\0\1\0\13\0\14\0\1\0\12\0\0\0\24\0\1\0\1\0\0\0\10*\264\0\2\266"+
- "\0\3\260\0\0\0\0\0\1\0\15\0\16\0\1\0\12\0\0\0\25\0\2\0\2\0\0\0"+
- "\11*\266\0\4+\266\0\5\260\0\0\0\0\0\0";
+ "\312\376\272\276\0\0\0.\0\36\12\0\7\0\17\11\0\6\0\20\12\0\21\0"+
+ "\22\12\0\6\0\23\12\0\24\0\25\7\0\26\7\0\27\1\0\6<init>\1\0'(L"+
+ "org/omg/CORBA/portable/InputStream;)V\1\0\4Code\1\0\10read_an"+
+ "y\1\0\25()Lorg/omg/CORBA/Any;\1\0\12read_value\1\0)(Ljava/lan"+
+ "g/Class;)Ljava/io/Serializable;\14\0\10\0\11\14\0\30\0\31\7\0"+
+ "\32\14\0\13\0\14\14\0\33\0\34\7\0\35\14\0\15\0\16\1\0(com/sun"+
+ "/jmx/remote/internal/PInputStream\1\0,com/sun/jmx/remote/inte"+
+ "rnal/ProxyInputStream\1\0\2in\1\0$Lorg/omg/CORBA/portable/Inp"+
+ "utStream;\1\0\"org/omg/CORBA/portable/InputStream\1\0\6narrow"+
+ "\1\0*()Lorg/omg/CORBA_2_3/portable/InputStream;\1\0&org/omg/C"+
+ "ORBA_2_3/portable/InputStream\0!\0\6\0\7\0\0\0\0\0\3\0\1\0\10"+
+ "\0\11\0\1\0\12\0\0\0\22\0\2\0\2\0\0\0\6*+\267\0\1\261\0\0\0\0"+
+ "\0\1\0\13\0\14\0\1\0\12\0\0\0\24\0\1\0\1\0\0\0\10*\264\0\2\266"+
+ "\0\3\260\0\0\0\0\0\1\0\15\0\16\0\1\0\12\0\0\0\25\0\2\0\2\0\0\0"+
+ "\11*\266\0\4+\266\0\5\260\0\0\0\0\0\0";
final byte[] proxyStubByteCode =
- NoCallStackClassLoader.stringToBytes(proxyStubByteCodeString);
+ NoCallStackClassLoader.stringToBytes(proxyStubByteCodeString);
final byte[] pInputStreamByteCode =
- NoCallStackClassLoader.stringToBytes(pInputStreamByteCodeString);
+ NoCallStackClassLoader.stringToBytes(pInputStreamByteCodeString);
final String[] classNames={proxyStubClassName, pInputStreamClassName};
final byte[][] byteCodes = {proxyStubByteCode, pInputStreamByteCode};
final String[] otherClassNames = {
@@ -2388,13 +2388,13 @@
Class thisClass = RMIConnector.class;
ClassLoader thisLoader = thisClass.getClassLoader();
ProtectionDomain thisProtectionDomain =
- thisClass.getProtectionDomain();
+ thisClass.getProtectionDomain();
ClassLoader cl =
- new NoCallStackClassLoader(classNames,
- byteCodes,
- otherClassNames,
- thisLoader,
- thisProtectionDomain);
+ new NoCallStackClassLoader(classNames,
+ byteCodes,
+ otherClassNames,
+ thisLoader,
+ thisProtectionDomain);
return cl.loadClass(proxyStubClassName);
}
};
@@ -2403,7 +2403,7 @@
stubClass = AccessController.doPrivileged(action);
} catch (Exception e) {
logger.error("<clinit>",
- "Unexpected exception making shadow IIOP stub class: "+e);
+ "Unexpected exception making shadow IIOP stub class: "+e);
logger.debug("<clinit>",e);
stubClass = null;
}
@@ -2411,15 +2411,15 @@
}
private static RMIConnection shadowIiopStub(Stub stub)
- throws InstantiationException, IllegalAccessException {
+ throws InstantiationException, IllegalAccessException {
Stub proxyStub = (Stub) proxyStubClass.newInstance();
proxyStub._set_delegate(stub._get_delegate());
return (RMIConnection) proxyStub;
}
private static RMIConnection getConnection(RMIServer server,
- Object credentials,
- boolean checkStub)
+ Object credentials,
+ boolean checkStub)
throws IOException {
RMIConnection c = server.newClient(credentials);
if (checkStub) checkStub(c, rmiConnectionImplStubClass);
@@ -2429,14 +2429,14 @@
if (c.getClass().getName().equals(iiopConnectionStubClassName))
return shadowIiopStub((Stub) c);
logger.trace("getConnection",
- "Did not wrap " + c.getClass() + " to foil " +
- "stack search for classes: class loading semantics " +
- "may be incorrect");
+ "Did not wrap " + c.getClass() + " to foil " +
+ "stack search for classes: class loading semantics " +
+ "may be incorrect");
} catch (Exception e) {
logger.error("getConnection",
- "Could not wrap " + c.getClass() + " to foil " +
- "stack search for classes: class loading semantics " +
- "may be incorrect: " + e);
+ "Could not wrap " + c.getClass() + " to foil " +
+ "stack search for classes: class loading semantics " +
+ "may be incorrect: " + e);
logger.debug("getConnection",e);
// so just return the original stub, which will work for all
// but the most exotic class loading situations
@@ -2449,7 +2449,7 @@
int numGroups = sLen/4;
if (4*numGroups != sLen)
throw new IllegalArgumentException(
- "String length must be a multiple of four.");
+ "String length must be a multiple of four.");
int missingBytesInLastGroup = 0;
int numFullGroups = numGroups;
if (sLen != 0) {
@@ -2535,21 +2535,21 @@
final ClassLoader old = t.getContextClassLoader();
if (defaultClassLoader != null)
AccessController.doPrivileged(new PrivilegedAction<Void>() {
- public Void run() {
- t.setContextClassLoader(defaultClassLoader);
- return null;
- }
- });
- return old;
+ public Void run() {
+ t.setContextClassLoader(defaultClassLoader);
+ return null;
+ }
+ });
+ return old;
}
private void popDefaultClassLoader(final ClassLoader old) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
- public Void run() {
- Thread.currentThread().setContextClassLoader(old);
- return null;
- }
- });
+ public Void run() {
+ Thread.currentThread().setContextClassLoader(old);
+ return null;
+ }
+ });
}
//--------------------------------------------------------------------
diff --git a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java
index e56020b..9d38c7e 100644
--- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java
@@ -383,7 +383,7 @@
try {
if (tracing) logger.trace("start", "setting default class loader");
defaultClassLoader = EnvHelp.resolveServerClassLoader(
- attributes, getSystemMBeanServer());
+ attributes, getSystemMBeanServerForwarder());
} catch (InstanceNotFoundException infc) {
IllegalArgumentException x = new
IllegalArgumentException("ClassLoader not found: "+infc);
@@ -398,7 +398,7 @@
else
rmiServer = newServer();
- rmiServer.setMBeanServer(getSystemMBeanServer());
+ rmiServer.setMBeanServer(getSystemMBeanServerForwarder());
rmiServer.setDefaultClassLoader(defaultClassLoader);
rmiServer.setRMIConnectorServer(this);
rmiServer.export();
@@ -592,31 +592,6 @@
return Collections.unmodifiableMap(map);
}
- @Override
- public synchronized void setMBeanServerForwarder(MBeanServerForwarder mbsf) {
- MBeanServer oldSMBS = getSystemMBeanServer();
- super.setMBeanServerForwarder(mbsf);
- if (oldSMBS != getSystemMBeanServer())
- updateMBeanServer();
- // If the system chain of MBeanServerForwarders is not empty, then
- // there is no need to call rmiServerImpl.setMBeanServer, because
- // it is pointing to the head of the system chain and that has not
- // changed. (The *end* of the system chain will have been changed
- // to point to mbsf.)
- }
-
- private void updateMBeanServer() {
- if (rmiServerImpl != null)
- rmiServerImpl.setMBeanServer(getSystemMBeanServer());
- }
-
- @Override
- public synchronized void setSystemMBeanServerForwarder(
- MBeanServerForwarder mbsf) {
- super.setSystemMBeanServerForwarder(mbsf);
- updateMBeanServer();
- }
-
/**
* {@inheritDoc}
* @return true, since this connector server does support a system chain
@@ -631,16 +606,19 @@
here so that they are accessible to other classes in this package
even though they have protected access. */
+ @Override
protected void connectionOpened(String connectionId, String message,
Object userData) {
super.connectionOpened(connectionId, message, userData);
}
+ @Override
protected void connectionClosed(String connectionId, String message,
Object userData) {
super.connectionClosed(connectionId, message, userData);
}
+ @Override
protected void connectionFailed(String connectionId, String message,
Object userData) {
super.connectionFailed(connectionId, message, userData);
diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
index 5aec189..6f3250b 100644
--- a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
@@ -435,8 +435,14 @@
if (streaming()) {
if (chunkLength != -1) {
requests.set ("Transfer-Encoding", "chunked");
- } else {
- requests.set ("Content-Length", String.valueOf(fixedContentLength));
+ } else { /* fixed content length */
+ if (fixedContentLengthLong != -1) {
+ requests.set ("Content-Length",
+ String.valueOf(fixedContentLengthLong));
+ } else if (fixedContentLength != -1) {
+ requests.set ("Content-Length",
+ String.valueOf(fixedContentLength));
+ }
}
} else if (poster != null) {
/* add Content-Length & POST/PUT data */
@@ -871,11 +877,17 @@
ps = (PrintStream)http.getOutputStream();
if (streaming()) {
if (strOutputStream == null) {
- if (fixedContentLength != -1) {
- strOutputStream = new StreamingOutputStream (ps, fixedContentLength);
- } else if (chunkLength != -1) {
- strOutputStream =
- new StreamingOutputStream (new ChunkedOutputStream (ps, chunkLength), -1);
+ if (chunkLength != -1) { /* chunked */
+ strOutputStream = new StreamingOutputStream(
+ new ChunkedOutputStream(ps, chunkLength), -1L);
+ } else { /* must be fixed content length */
+ long length = 0L;
+ if (fixedContentLengthLong != -1) {
+ length = fixedContentLengthLong;
+ } else if (fixedContentLength != -1) {
+ length = fixedContentLength;
+ }
+ strOutputStream = new StreamingOutputStream(ps, length);
}
}
return strOutputStream;
@@ -895,7 +907,8 @@
}
private boolean streaming () {
- return (fixedContentLength != -1) || (chunkLength != -1);
+ return (fixedContentLength != -1) || (fixedContentLengthLong != -1) ||
+ (chunkLength != -1);
}
/*
@@ -2619,8 +2632,8 @@
class StreamingOutputStream extends FilterOutputStream {
- int expected;
- int written;
+ long expected;
+ long written;
boolean closed;
boolean error;
IOException errorExcp;
@@ -2631,10 +2644,10 @@
* In the 2nd case, we make sure the expected number of
* of bytes are actually written
*/
- StreamingOutputStream (OutputStream os, int expectedLength) {
+ StreamingOutputStream (OutputStream os, long expectedLength) {
super (os);
expected = expectedLength;
- written = 0;
+ written = 0L;
closed = false;
error = false;
}
@@ -2643,7 +2656,7 @@
public void write (int b) throws IOException {
checkError();
written ++;
- if (expected != -1 && written > expected) {
+ if (expected != -1L && written > expected) {
throw new IOException ("too many bytes written");
}
out.write (b);
@@ -2658,7 +2671,7 @@
public void write (byte[] b, int off, int len) throws IOException {
checkError();
written += len;
- if (expected != -1 && written > expected) {
+ if (expected != -1L && written > expected) {
out.close ();
throw new IOException ("too many bytes written");
}
@@ -2691,7 +2704,7 @@
return;
}
closed = true;
- if (expected != -1) {
+ if (expected != -1L) {
/* not chunked */
if (written != expected) {
error = true;
diff --git a/jdk/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java b/jdk/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java
index 55b1859..c2a3701 100644
--- a/jdk/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java
+++ b/jdk/src/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java
@@ -527,6 +527,10 @@
delegate.setFixedLengthStreamingMode(contentLength);
}
+ public void setFixedLengthStreamingMode(long contentLength) {
+ delegate.setFixedLengthStreamingMode(contentLength);
+ }
+
public void setChunkedStreamingMode (int chunklen) {
delegate.setChunkedStreamingMode(chunklen);
}
diff --git a/jdk/src/share/classes/sun/security/jgss/GSSContextImpl.java b/jdk/src/share/classes/sun/security/jgss/GSSContextImpl.java
index a506394..046f647 100644
--- a/jdk/src/share/classes/sun/security/jgss/GSSContextImpl.java
+++ b/jdk/src/share/classes/sun/security/jgss/GSSContextImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -284,7 +284,8 @@
ByteArrayOutputStream bos = new ByteArrayOutputStream(100);
acceptSecContext(new ByteArrayInputStream(inTok, offset, len),
bos);
- return bos.toByteArray();
+ byte[] out = bos.toByteArray();
+ return (out.length == 0) ? null : out;
}
public void acceptSecContext(InputStream inStream,
diff --git a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java
index 5ea5cd3..7185b0e 100644
--- a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java
+++ b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -413,13 +413,14 @@
// pull out the mechanism token
byte[] accept_token = targToken.getResponseToken();
if (accept_token == null) {
- // return wth failure
- throw new GSSException(errorCode, -1,
- "mechansim token from server is null");
+ if (!isMechContextEstablished()) {
+ // return with failure
+ throw new GSSException(errorCode, -1,
+ "mechanism token from server is null");
+ }
+ } else {
+ mechToken = GSS_initSecContext(accept_token);
}
-
- mechToken = GSS_initSecContext(accept_token);
-
// verify MIC
if (!GSSUtil.useMSInterop()) {
byte[] micToken = targToken.getMechListMIC();
@@ -428,7 +429,6 @@
"verification of MIC on MechList Failed!");
}
}
-
if (isMechContextEstablished()) {
state = STATE_DONE;
retVal = mechToken;
@@ -556,9 +556,6 @@
// get the token for mechanism
byte[] accept_token = GSS_acceptSecContext(mechToken);
- if (accept_token == null) {
- valid = false;
- }
// verify MIC
if (!GSSUtil.useMSInterop() && valid) {
diff --git a/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java b/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java
index 24d8837..e9afb29 100644
--- a/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java
+++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java
@@ -151,6 +151,10 @@
private SingleResponse singleResponse;
+ // Maximum clock skew in milliseconds (10 minutes) allowed when checking
+ // validity of OCSP responses
+ private static final long MAX_CLOCK_SKEW = 600000;
+
// an array of all of the CRLReasons (used in SingleResponse)
private static CRLReason[] values = CRLReason.values();
@@ -583,7 +587,9 @@
}
}
- Date now = new Date();
+ long now = System.currentTimeMillis();
+ Date nowPlusSkew = new Date(now + MAX_CLOCK_SKEW);
+ Date nowMinusSkew = new Date(now - MAX_CLOCK_SKEW);
if (DEBUG != null) {
String until = "";
if (nextUpdate != null) {
@@ -593,8 +599,8 @@
thisUpdate + until);
}
// Check that the test date is within the validity interval
- if ((thisUpdate != null && now.before(thisUpdate)) ||
- (nextUpdate != null && now.after(nextUpdate))) {
+ if ((thisUpdate != null && nowPlusSkew.before(thisUpdate)) ||
+ (nextUpdate != null && nowMinusSkew.after(nextUpdate))) {
if (DEBUG != null) {
DEBUG.println("Response is unreliable: its validity " +
diff --git a/jdk/src/share/classes/sun/security/ssl/BaseSSLSocketImpl.java b/jdk/src/share/classes/sun/security/ssl/BaseSSLSocketImpl.java
index 8ca8e76..a918b14 100644
--- a/jdk/src/share/classes/sun/security/ssl/BaseSSLSocketImpl.java
+++ b/jdk/src/share/classes/sun/security/ssl/BaseSSLSocketImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -256,10 +256,12 @@
// ignore
}
} finally {
- // we call close on the underlying socket anyway, but be
- // doubly sure all resources get released.
- // note that we don't need to worry about self, the GC
- // will finalize that separately
+ // We called close on the underlying socket above to
+ // make doubly sure all resources got released. We
+ // don't finalize self in the case of overlain sockets,
+ // that's a different object which the GC will finalize
+ // separately.
+
super.finalize();
}
}
diff --git a/jdk/src/share/classes/sun/security/ssl/HelloExtensions.java b/jdk/src/share/classes/sun/security/ssl/HelloExtensions.java
index 51080b5..2a21489 100644
--- a/jdk/src/share/classes/sun/security/ssl/HelloExtensions.java
+++ b/jdk/src/share/classes/sun/security/ssl/HelloExtensions.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2006-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
@@ -218,7 +218,10 @@
throws IOException {
super(type);
data = new byte[len];
- s.read(data);
+ // s.read() does not handle 0-length arrays.
+ if (len != 0) {
+ s.read(data);
+ }
}
int length() {
diff --git a/jdk/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java
index 88bab01..68037ca 100644
--- a/jdk/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java
+++ b/jdk/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -304,14 +304,18 @@
enabledCipherSuites, doClientAuth,
enableSessionCreation, enabledProtocols);
- ServerHandshaker handshaker = tmp.getServerHandshaker();
+ try {
+ ServerHandshaker handshaker = tmp.getServerHandshaker();
- for (Iterator t = enabledCipherSuites.iterator(); t.hasNext(); ) {
- CipherSuite suite = (CipherSuite)t.next();
- if (handshaker.trySetCipherSuite(suite)) {
- checkedEnabled = true;
- return;
+ for (Iterator t = enabledCipherSuites.iterator(); t.hasNext(); ) {
+ CipherSuite suite = (CipherSuite)t.next();
+ if (handshaker.trySetCipherSuite(suite)) {
+ checkedEnabled = true;
+ return;
+ }
}
+ } finally {
+ tmp.closeSocket();
}
//
diff --git a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java
index 66b6e6d..a270cdc 100644
--- a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java
+++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java
@@ -1012,6 +1012,22 @@
*/
ServerHandshaker getServerHandshaker() throws SSLException {
initHandshaker();
+
+ // The connection state would have been set to cs_HANDSHAKE during the
+ // handshaking initializing, however the caller may not have the
+ // the low level connection's established, which is not consistent with
+ // the HANDSHAKE state. As if it is unconnected, we need to reset the
+ // connection state to cs_START.
+ if (!isConnected()) {
+ connectionState = cs_START;
+ }
+
+ // Make sure that we get a ServerHandshaker.
+ // This should never happen.
+ if (!(handshaker instanceof ServerHandshaker)) {
+ throw new SSLProtocolException("unexpected handshaker instance");
+ }
+
return (ServerHandshaker)handshaker;
}
@@ -1273,7 +1289,8 @@
}
}
- private void closeSocket() throws IOException {
+ protected void closeSocket() throws IOException {
+
if ((debug != null) && Debug.isOn("ssl")) {
System.out.println(threadName() + ", called closeSocket()");
}
diff --git a/jdk/src/share/native/java/util/zip/zip_util.c b/jdk/src/share/native/java/util/zip/zip_util.c
index 5d518cf..3b00b95 100644
--- a/jdk/src/share/native/java/util/zip/zip_util.c
+++ b/jdk/src/share/native/java/util/zip/zip_util.c
@@ -273,8 +273,8 @@
/*
* Searches for end of central directory (END) header. The contents of
* the END header will be read and placed in endbuf. Returns the file
- * position of the END header, otherwise returns 0 if the END header
- * was not found or -1 if an error occurred.
+ * position of the END header, otherwise returns -1 if the END header
+ * was not found or an error occurred.
*/
static jlong
findEND(jzfile *zip, void *endbuf)
@@ -314,7 +314,7 @@
}
}
}
- return 0; /* END header not found */
+ return -1; /* END header not found */
}
/*
@@ -460,9 +460,8 @@
/*
* Reads zip file central directory. Returns the file position of first
- * CEN header, otherwise returns 0 if central directory not found or -1
- * if an error occurred. If zip->msg != NULL then the error was a zip
- * format error and zip->msg has the error text.
+ * CEN header, otherwise returns -1 if an error occured. If zip->msg != NULL
+ * then the error was a zip format error and zip->msg has the error text.
* Always pass in -1 for knownTotal; it's used for a recursive call.
*/
static jlong
@@ -488,9 +487,9 @@
/* Get position of END header */
if ((endpos = findEND(zip, endbuf)) == -1)
- return -1; /* system error */
+ return -1; /* no END header or system error */
- if (endpos == 0) return 0; /* END header not found */
+ if (endpos == 0) return 0; /* only END header present */
freeCEN(zip);
diff --git a/jdk/test/com/sun/net/httpserver/bugs/FixedLengthInputStream.java b/jdk/test/com/sun/net/httpserver/bugs/FixedLengthInputStream.java
index 76a71fc..d5cdfdf 100644
--- a/jdk/test/com/sun/net/httpserver/bugs/FixedLengthInputStream.java
+++ b/jdk/test/com/sun/net/httpserver/bugs/FixedLengthInputStream.java
@@ -23,7 +23,7 @@
/**
* @test
- * @bug 6756771
+ * @bug 6756771 6755625
* @summary com.sun.net.httpserver.HttpServer should handle POSTs larger than 2Gig
*/
@@ -44,34 +44,16 @@
{
static final long POST_SIZE = 4L * 1024L * 1024L * 1024L; // 4Gig
- /* Remove when CR 6755625 is fixed */
- static final String requestHeaders = ((new StringBuilder())
- .append("POST /flis/ HTTP/1.1\r\n")
- .append("User-Agent: Java/1.7.0\r\n")
- .append("Host: localhost\r\n")
- .append("Accept: text/html, image/gif, image/jpeg,")
- .append( " *; q=.2, */*; q=.2\r\n")
- .append("Content-Length: 4294967296\r\n\r\n")).toString();
-
void test(String[] args) throws IOException {
HttpServer httpServer = startHttpServer();
int port = httpServer.getAddress().getPort();
try {
- /* Uncomment & when CR 6755625 is fixed, remove socket code
URL url = new URL("http://localhost:" + port + "/flis/");
HttpURLConnection uc = (HttpURLConnection)url.openConnection();
uc.setDoOutput(true);
uc.setRequestMethod("POST");
uc.setFixedLengthStreamingMode(POST_SIZE);
OutputStream os = uc.getOutputStream();
- */
-
- Socket socket = new Socket("localhost", port);
- OutputStream os = socket.getOutputStream();
- PrintStream ps = new PrintStream(os);
- debug("Request: " + requestHeaders);
- ps.print(requestHeaders);
- ps.flush();
/* create a 32K byte array with data to POST */
int thirtyTwoK = 32 * 1024;
@@ -84,18 +66,12 @@
os.write(ba);
}
- /* Uncomment & when CR 6755625 is fixed, remove socket code
os.close();
InputStream is = uc.getInputStream();
while(is.read(ba) != -1);
is.close();
- */
- InputStream is = socket.getInputStream();
- is.read();
- socket.close();
-
- pass();
+ pass();
} finally {
httpServer.stop(0);
}
diff --git a/jdk/test/java/security/cert/CertPathValidatorException/GetMessage.java b/jdk/test/java/security/cert/CertPathValidatorException/GetMessage.java
new file mode 100644
index 0000000..dd51af7
--- /dev/null
+++ b/jdk/test/java/security/cert/CertPathValidatorException/GetMessage.java
@@ -0,0 +1,63 @@
+/*
+ * 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 6765046
+ * @summary check that getMessage(cause) returns cause.toString if cause != null
+ */
+
+import java.security.cert.CertPathValidatorException;
+
+public class GetMessage {
+ private static volatile boolean failed = false;
+ public static void main(String[] args) throws Exception {
+
+ Throwable[] causes = {
+ new Throwable(),
+ new Throwable("message"),
+ new Throwable("message", new Throwable()) };
+
+ for (Throwable cause: causes) {
+ CertPathValidatorException cpve =
+ new CertPathValidatorException(cause);
+
+ // from CertPathValidatorException(Throwable cause) spec:
+ // The detail message is set to (cause==null ? null : cause.toString() )
+ // (which typically contains the class and detail message of cause).
+ String expMsg = (cause == null ? null : cause.toString());
+ String actualMsg = cpve.getMessage();
+
+ boolean msgsEqual =
+ (expMsg == null ? actualMsg == null : expMsg.equals(actualMsg));
+ if (!msgsEqual) {
+ System.out.println("expected message:" + expMsg);
+ System.out.println("getMessage():" + actualMsg);
+ failed = true;
+ }
+ }
+ if (failed) {
+ throw new Exception("Some tests FAILED");
+ }
+ }
+}
diff --git a/jdk/test/java/util/zip/TestEmptyZip.java b/jdk/test/java/util/zip/TestEmptyZip.java
index d19dee4..f4ad29b 100644
--- a/jdk/test/java/util/zip/TestEmptyZip.java
+++ b/jdk/test/java/util/zip/TestEmptyZip.java
@@ -39,34 +39,23 @@
throw new Exception("failed to delete " + zipName);
}
- // Verify 0-length file cannot be read
f.createNewFile();
- ZipFile zf = null;
try {
- zf = new ZipFile(f);
- fail();
- } catch (Exception ex) {
- check(ex.getMessage().contains("zip file is empty"));
- } finally {
- if (zf != null) {
- zf.close();
- }
- }
+ // Verify 0-length file cannot be read
+ checkCannotRead(f);
- ZipInputStream zis = null;
- try {
- zis = new ZipInputStream(new FileInputStream(f));
- ZipEntry ze = zis.getNextEntry();
- check(ze == null);
- } catch (Exception ex) {
- unexpected(ex);
- } finally {
- if (zis != null) {
- zis.close();
+ // Verify non-zip file cannot be read
+ OutputStream out = new FileOutputStream(f);
+ try {
+ out.write("class Foo { }".getBytes());
+ } finally {
+ out.close();
}
- }
+ checkCannotRead(f);
- f.delete();
+ } finally {
+ f.delete();
+ }
// Verify 0-entries file can be written
write(f);
@@ -78,6 +67,29 @@
f.delete();
}
+ static void checkCannotRead(File f) throws IOException {
+ try {
+ new ZipFile(f).close();
+ fail();
+ } catch (ZipException ze) {
+ if (f.length() == 0) {
+ check(ze.getMessage().contains("zip file is empty"));
+ } else {
+ pass();
+ }
+ }
+ ZipInputStream zis = null;
+ try {
+ zis = new ZipInputStream(new FileInputStream(f));
+ ZipEntry ze = zis.getNextEntry();
+ check(ze == null);
+ } catch (IOException ex) {
+ unexpected(ex);
+ } finally {
+ if (zis != null) zis.close();
+ }
+ }
+
static void write(File f) throws Exception {
ZipOutputStream zos = null;
try {
diff --git a/jdk/test/javax/management/Introspector/AnnotationTest.java b/jdk/test/javax/management/Introspector/AnnotationTest.java
index e6d3c10..49ca0d3 100644
--- a/jdk/test/javax/management/Introspector/AnnotationTest.java
+++ b/jdk/test/javax/management/Introspector/AnnotationTest.java
@@ -39,7 +39,8 @@
/*
This test checks that annotations produce Descriptor entries as
- specified in javax.management.DescriptorKey. It does two things:
+ specified in javax.management.DescriptorKey and javax.management.DescriptorField.
+ It does the following:
- An annotation consisting of an int and a String, each with an
appropriate @DescriptorKey annotation, is placed on every program
@@ -61,6 +62,10 @@
The test checks that in each case the corresponding Descriptor
appears in the appropriate place inside the MBean's MBeanInfo.
+ - A @DescriptorFields annotation defining two fields is placed in the
+ same places and again the test checks that the two fields appear
+ in the corresponding MBean*Info objects.
+
- An annotation consisting of enough other types to ensure coverage
is placed on a getter. The test checks that the generated
MBeanAttributeInfo contains the corresponding Descriptor. The tested
@@ -78,12 +83,6 @@
public class AnnotationTest {
private static String failed = null;
-// @Retention(RetentionPolicy.RUNTIME) @Inherited
-// @Target(ElementType.METHOD)
-// public static @interface DescriptorKey {
-// String value();
-// }
-
@Retention(RetentionPolicy.RUNTIME)
public static @interface Pair {
@DescriptorKey("x")
@@ -112,11 +111,12 @@
boolean[] booleanArrayValue();
}
- /* We use the annotation @Pair(x = 3, y = "foo") everywhere, and this is
- the Descriptor that it should produce: */
+ /* We use the annotations @Pair(x = 3, y = "foo")
+ and @DescriptorFields({"foo=bar", "baz="}) everywhere, and this is
+ the Descriptor that they should produce: */
private static Descriptor expectedDescriptor =
- new ImmutableDescriptor(new String[] {"x", "y"},
- new Object[] {3, "foo"});
+ new ImmutableDescriptor(new String[] {"x", "y", "foo", "baz"},
+ new Object[] {3, "foo", "bar", ""});
private static Descriptor expectedFullDescriptor =
new ImmutableDescriptor(new String[] {
@@ -136,8 +136,10 @@
});
@Pair(x = 3, y = "foo")
+ @DescriptorFields({"foo=bar", "baz="})
public static interface ThingMBean {
@Pair(x = 3, y = "foo")
+ @DescriptorFields({"foo=bar", "baz="})
@Full(classValue=Full.class,
enumValue=RetentionPolicy.RUNTIME,
booleanValue=false,
@@ -149,32 +151,47 @@
int getReadOnly();
@Pair(x = 3, y = "foo")
+ @DescriptorFields({"foo=bar", "baz="})
void setWriteOnly(int x);
@Pair(x = 3, y = "foo")
+ @DescriptorFields({"foo=bar", "baz="})
int getReadWrite1();
void setReadWrite1(int x);
@Pair(x = 3, y = "foo")
+ @DescriptorFields({"foo=bar", "baz="})
int getReadWrite2();
@Pair(x = 3, y = "foo")
+ @DescriptorFields({"foo=bar", "baz="})
void setReadWrite2(int x);
int getReadWrite3();
@Pair(x = 3, y = "foo")
+ @DescriptorFields({"foo=bar", "baz="})
void setReadWrite3(int x);
@Pair(x = 3, y = "foo")
- int operation(@Pair(x = 3, y = "foo") int p1,
- @Pair(x = 3, y = "foo") int p2);
+ @DescriptorFields({"foo=bar", "baz="})
+ int operation(@Pair(x = 3, y = "foo")
+ @DescriptorFields({"foo=bar", "baz="})
+ int p1,
+ @Pair(x = 3, y = "foo")
+ @DescriptorFields({"foo=bar", "baz="})
+ int p2);
}
public static class Thing implements ThingMBean {
@Pair(x = 3, y = "foo")
+ @DescriptorFields({"foo=bar", "baz="})
public Thing() {}
@Pair(x = 3, y = "foo")
- public Thing(@Pair(x = 3, y = "foo") int p1) {}
+ @DescriptorFields({"foo=bar", "baz="})
+ public Thing(
+ @Pair(x = 3, y = "foo")
+ @DescriptorFields({"foo=bar", "baz="})
+ int p1) {}
public int getReadOnly() {return 0;}
@@ -193,14 +210,20 @@
}
@Pair(x = 3, y = "foo")
+ @DescriptorFields({"foo=bar", "baz="})
public static interface ThingMXBean extends ThingMBean {}
public static class ThingImpl implements ThingMXBean {
@Pair(x = 3, y = "foo")
+ @DescriptorFields({"foo=bar", "baz="})
public ThingImpl() {}
@Pair(x = 3, y = "foo")
- public ThingImpl(@Pair(x = 3, y = "foo") int p1) {}
+ @DescriptorFields({"foo=bar", "baz="})
+ public ThingImpl(
+ @Pair(x = 3, y = "foo")
+ @DescriptorFields({"foo=bar", "baz="})
+ int p1) {}
public int getReadOnly() {return 0;}
@@ -218,6 +241,79 @@
public int operation(int p1, int p2) {return 0;}
}
+ @Retention(RetentionPolicy.RUNTIME)
+ public static @interface DefaultTest {
+ @DescriptorKey(value = "string1", omitIfDefault = true)
+ String string1() default "";
+ @DescriptorKey(value = "string2", omitIfDefault = true)
+ String string2() default "tiddly pom";
+ @DescriptorKey(value = "int", omitIfDefault = true)
+ int intx() default 23;
+ @DescriptorKey(value = "intarray1", omitIfDefault = true)
+ int[] intArray1() default {};
+ @DescriptorKey(value = "intarray2", omitIfDefault = true)
+ int[] intArray2() default {1, 2};
+ @DescriptorKey(value = "stringarray1", omitIfDefault = true)
+ String[] stringArray1() default {};
+ @DescriptorKey(value = "stringarray2", omitIfDefault = true)
+ String[] stringArray2() default {"foo", "bar"};
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public static @interface Expect {
+ String[] value() default {};
+ }
+
+ public static interface DefaultMBean {
+ @DefaultTest
+ @Expect()
+ public void a();
+
+ @DefaultTest(string1="")
+ @Expect()
+ public void b();
+
+ @DefaultTest(string1="nondefault")
+ @Expect("string1=nondefault")
+ public void c();
+
+ @DefaultTest(string2="tiddly pom")
+ @Expect()
+ public void d();
+
+ @DefaultTest(intx=23)
+ @Expect()
+ public void e();
+
+ @DefaultTest(intx=34)
+ @Expect("int=34")
+ public void f();
+
+ @DefaultTest(intArray1={})
+ @Expect()
+ public void g();
+
+ @DefaultTest(intArray1={2,3})
+ @Expect("intarray1=[2, 3]")
+ public void h();
+
+ @DefaultTest(intArray2={})
+ @Expect("intarray2=[]")
+ public void i();
+
+ @DefaultTest(stringArray1={})
+ @Expect()
+ public void j();
+
+ @DefaultTest(stringArray1={"foo"})
+ @Expect("stringarray1=[foo]")
+ public void k();
+
+ @DefaultTest(stringArray2={})
+ @Expect("stringarray2=[]")
+ public void l();
+ }
+
public static void main(String[] args) throws Exception {
System.out.println("Testing that annotations are correctly " +
"reflected in Descriptor entries");
@@ -225,20 +321,62 @@
MBeanServer mbs =
java.lang.management.ManagementFactory.getPlatformMBeanServer();
ObjectName on = new ObjectName("a:b=c");
+
Thing thing = new Thing();
mbs.registerMBean(thing, on);
check(mbs, on);
mbs.unregisterMBean(on);
+
ThingImpl thingImpl = new ThingImpl();
mbs.registerMBean(thingImpl, on);
+ Descriptor d = mbs.getMBeanInfo(on).getDescriptor();
+ if (!d.getFieldValue("mxbean").equals("true")) {
+ System.out.println("NOT OK: expected MXBean");
+ failed = "Expected MXBean";
+ }
check(mbs, on);
+ System.out.println();
+ System.out.println("Testing that omitIfDefault works");
+ DefaultMBean defaultImpl = (DefaultMBean) Proxy.newProxyInstance(
+ DefaultMBean.class.getClassLoader(),
+ new Class<?>[] {DefaultMBean.class},
+ new InvocationHandler(){
+ public Object invoke(Object proxy, Method method, Object[] args) {
+ return null;
+ }
+ });
+ DynamicMBean mbean = new StandardMBean(defaultImpl, DefaultMBean.class);
+ MBeanOperationInfo[] ops = mbean.getMBeanInfo().getOperations();
+ for (MBeanOperationInfo op : ops) {
+ String name = op.getName();
+ Expect expect =
+ DefaultMBean.class.getMethod(name).getAnnotation(Expect.class);
+ Descriptor opd = op.getDescriptor();
+ List<String> fields = new ArrayList<String>();
+ for (String fieldName : opd.getFieldNames()) {
+ Object value = opd.getFieldValue(fieldName);
+ String s = Arrays.deepToString(new Object[] {value});
+ s = s.substring(1, s.length() - 1);
+ fields.add(fieldName + "=" + s);
+ }
+ Descriptor opds = new ImmutableDescriptor(fields.toArray(new String[0]));
+ Descriptor expd = new ImmutableDescriptor(expect.value());
+ if (opds.equals(expd))
+ System.out.println("OK: op " + name + ": " + opds);
+ else {
+ String failure = "Bad descriptor for op " + name + ": " +
+ "expected " + expd + ", got " + opds;
+ System.out.println("NOT OK: " + failure);
+ failed = failure;
+ }
+ }
+ System.out.println();
+
if (failed == null)
System.out.println("Test passed");
- else if (true)
- throw new Exception("TEST FAILED: " + failed);
else
- System.out.println("Test disabled until 6221321 implemented");
+ throw new Exception("TEST FAILED: " + failed);
}
private static void check(MBeanServer mbs, ObjectName on) throws Exception {
@@ -295,151 +433,4 @@
for (DescriptorRead x : xx)
check(x);
}
-
- public static class AnnotatedMBean extends StandardMBean {
- <T> AnnotatedMBean(T resource, Class<T> interfaceClass, boolean mx) {
- super(resource, interfaceClass, mx);
- }
-
- private static final String[] attrPrefixes = {"get", "set", "is"};
-
- protected void cacheMBeanInfo(MBeanInfo info) {
- MBeanAttributeInfo[] attrs = info.getAttributes();
- MBeanOperationInfo[] ops = info.getOperations();
-
- for (int i = 0; i < attrs.length; i++) {
- MBeanAttributeInfo attr = attrs[i];
- String name = attr.getName();
- Descriptor d = attr.getDescriptor();
- Method m;
- if ((m = getMethod("get" + name)) != null)
- d = ImmutableDescriptor.union(d, descriptorFor(m));
- if (attr.getType().equals("boolean") &&
- (m = getMethod("is" + name)) != null)
- d = ImmutableDescriptor.union(d, descriptorFor(m));
- if ((m = getMethod("set" + name, attr)) != null)
- d = ImmutableDescriptor.union(d, descriptorFor(m));
- if (!d.equals(attr.getDescriptor())) {
- attrs[i] =
- new MBeanAttributeInfo(name, attr.getType(),
- attr.getDescription(), attr.isReadable(),
- attr.isWritable(), attr.isIs(), d);
- }
- }
-
- for (int i = 0; i < ops.length; i++) {
- MBeanOperationInfo op = ops[i];
- String name = op.getName();
- Descriptor d = op.getDescriptor();
- MBeanParameterInfo[] params = op.getSignature();
- Method m = getMethod(name, params);
- if (m != null) {
- d = ImmutableDescriptor.union(d, descriptorFor(m));
- Annotation[][] annots = m.getParameterAnnotations();
- for (int pi = 0; pi < params.length; pi++) {
- MBeanParameterInfo param = params[pi];
- Descriptor pd =
- ImmutableDescriptor.union(param.getDescriptor(),
- descriptorFor(annots[pi]));
- params[pi] = new MBeanParameterInfo(param.getName(),
- param.getType(), param.getDescription(), pd);
- }
- op = new MBeanOperationInfo(op.getName(),
- op.getDescription(), params, op.getReturnType(),
- op.getImpact(), d);
- if (!ops[i].equals(op))
- ops[i] = op;
- }
- }
-
- Descriptor id = descriptorFor(getMBeanInterface());
- info = new MBeanInfo(info.getClassName(), info.getDescription(),
- attrs, info.getConstructors(), ops, info.getNotifications(),
- ImmutableDescriptor.union(id, info.getDescriptor()));
- super.cacheMBeanInfo(info);
- }
-
- private Descriptor descriptorFor(AnnotatedElement x) {
- Annotation[] annots = x.getAnnotations();
- return descriptorFor(annots);
- }
-
- private Descriptor descriptorFor(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 (Exception e) {
- // we don't expect this
- throw new RuntimeException(e);
- }
- Object oldValue = descriptorMap.put(name, value);
- if (oldValue != null && !oldValue.equals(value)) {
- final String msg =
- "Inconsistent values for descriptor field " +
- name + " from annotations: " + value + " :: " +
- oldValue;
- throw new IllegalArgumentException(msg);
- }
- }
- }
- }
- if (descriptorMap.isEmpty())
- return ImmutableDescriptor.EMPTY_DESCRIPTOR;
- else
- return new ImmutableDescriptor(descriptorMap);
- }
-
- private Method getMethod(String name, MBeanFeatureInfo... params) {
- Class<?> intf = getMBeanInterface();
- ClassLoader loader = intf.getClassLoader();
- Class[] classes = new Class[params.length];
- for (int i = 0; i < params.length; i++) {
- MBeanFeatureInfo param = params[i];
- Descriptor d = param.getDescriptor();
- String type = (String) d.getFieldValue("originalType");
- if (type == null) {
- if (param instanceof MBeanAttributeInfo)
- type = ((MBeanAttributeInfo) param).getType();
- else
- type = ((MBeanParameterInfo) param).getType();
- }
- Class<?> c = primitives.get(type);
- if (c == null) {
- try {
- c = Class.forName(type, false, loader);
- } catch (ClassNotFoundException e) {
- return null;
- }
- }
- classes[i] = c;
- }
- try {
- return intf.getMethod(name, classes);
- } catch (Exception e) {
- return null;
- }
- }
-
- private static final Map<String, Class<?>> primitives =
- new HashMap<String, Class<?>>();
- static {
- for (Class<?> c :
- new Class[] {boolean.class, byte.class, short.class,
- int.class, long.class, float.class,
- double.class, char.class, void.class}) {
- primitives.put(c.getName(), c);
- }
- }
- }
}
diff --git a/jdk/test/javax/management/MBeanServer/AttributeListMapTest.java b/jdk/test/javax/management/MBeanServer/AttributeListMapTest.java
new file mode 100644
index 0000000..94dd393
--- /dev/null
+++ b/jdk/test/javax/management/MBeanServer/AttributeListMapTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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 6336968
+ * @summary Test AttributeList.toMap
+ * @author Eamonn McManus
+ */
+
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+
+public class AttributeListMapTest {
+
+ private static String failure;
+
+ public static void main(String[] args) throws Exception {
+ AttributeList attrs = new AttributeList(Arrays.asList(
+ new Attribute("Str", "Five"),
+ new Attribute("Int", 5),
+ new Attribute("Flt", 5.0)));
+
+ Map<String, Object> map = attrs.toMap();
+ final Map<String, Object> expectMap = new HashMap<String, Object>();
+ for (Attribute attr : attrs.asList())
+ expectMap.put(attr.getName(), attr.getValue());
+ assertEquals("Initial map", expectMap, map);
+ assertEquals("Initial map size", 3, map.size());
+ assertEquals("Name set", expectMap.keySet(), map.keySet());
+ assertEquals("Values", new HashSet<Object>(expectMap.values()),
+ new HashSet<Object>(map.values()));
+ assertEquals("Entry set", expectMap.entrySet(), map.entrySet());
+
+ AttributeList attrs2 = new AttributeList(map);
+ assertEquals("AttributeList from Map", attrs, attrs2);
+ // This assumes that the Map conserves the order of the attributes,
+ // which is not specified but true because we use LinkedHashMap.
+
+ // Check that toMap fails if the list contains non-Attribute elements.
+ AttributeList attrs3 = new AttributeList(attrs);
+ attrs3.add("Hello"); // allowed but curious
+ try {
+ map = attrs3.toMap();
+ fail("toMap succeeded on list with non-Attribute elements");
+ } catch (Exception e) {
+ assertEquals("Exception for toMap with non-Atttribute elements",
+ IllegalArgumentException.class, e.getClass());
+ }
+
+ // Check that the Map does not reflect changes made to the list after
+ // the Map was obtained.
+ AttributeList attrs4 = new AttributeList(attrs);
+ map = attrs4.toMap();
+ attrs4.add(new Attribute("Big", new BigInteger("5")));
+ assertEquals("Map after adding element to list", expectMap, map);
+
+ // Check that if there is more than one Attribute with the same name
+ // then toMap() chooses the last of them.
+ AttributeList attrs5 = new AttributeList(attrs);
+ attrs5.add(new Attribute("Str", "Cinq"));
+ map = attrs5.toMap();
+ assertEquals("Size of Map for list with duplicate attribute name",
+ 3, map.size());
+ Object value = map.get("Str");
+ assertEquals("Value of Str in Map for list with two values for it",
+ "Cinq", value);
+
+ if (failure == null)
+ System.out.println("TEST PASSED");
+ else
+ throw new Exception("TEST FAILED: " + failure);
+ }
+
+ private static void assertEquals(String what, Object expect, Object actual) {
+ if (eq(expect, actual))
+ System.out.println("OK: " + what);
+ else
+ fail(what + ": expected " + expect + ", got " + actual);
+ }
+
+ private static boolean eq(Object x, Object y) {
+ return (x == null) ? (y == null) : x.equals(y);
+ }
+
+ private static void fail(String why) {
+ System.out.println("FAIL: " + why);
+ failure = why;
+ }
+}
diff --git a/jdk/test/javax/management/MBeanServer/AttributeListTypeSafeTest.java b/jdk/test/javax/management/MBeanServer/AttributeListTypeSafeTest.java
new file mode 100644
index 0000000..ed2fc96
--- /dev/null
+++ b/jdk/test/javax/management/MBeanServer/AttributeListTypeSafeTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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 6336968
+ * @summary Test adding non-Attribute values to an AttributeList.
+ * @author Eamonn McManus
+ */
+
+import java.util.Collections;
+import java.util.List;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+
+public class AttributeListTypeSafeTest {
+
+ private static String failure;
+
+ public static void main(String[] args) throws Exception {
+ // Test calling asList after adding non-Attribute by various means
+ for (Op op : Op.values()) {
+ AttributeList alist = new AttributeList();
+ alist.add(new Attribute("foo", "bar"));
+ doOp(alist, op);
+ String what = "asList() after calling " + op + " with non-Attribute";
+ try {
+ List<Attribute> lista = alist.asList();
+ fail(what + ": succeeded but should not have");
+ } catch (IllegalArgumentException e) {
+ System.out.println("OK: " + what + ": got IllegalArgumentException");
+ }
+ }
+
+ // Test adding non-Attribute by various means after calling asList
+ for (Op op : Op.values()) {
+ AttributeList alist = new AttributeList();
+ List<Attribute> lista = alist.asList();
+ lista.add(new Attribute("foo", "bar"));
+ String what = op + " with non-Attribute after calling asList()";
+ try {
+ doOp(alist, op);
+ fail(what + ": succeeded but should not have");
+ } catch (IllegalArgumentException e) {
+ System.out.println("OK: " + what + ": got IllegalArgumentException");
+ }
+ }
+
+ if (failure == null)
+ System.out.println("TEST PASSED");
+ else
+ throw new Exception("TEST FAILED: " + failure);
+ }
+
+ private static enum Op {
+ ADD("add(Object)"), ADD_AT("add(int, Object)"),
+ ADD_ALL("add(Collection)"), ADD_ALL_AT("add(int, Collection)"),
+ SET("set(int, Object)");
+
+ private Op(String what) {
+ this.what = what;
+ }
+
+ @Override
+ public String toString() {
+ return what;
+ }
+
+ private final String what;
+ }
+
+ private static void doOp(AttributeList alist, Op op) {
+ Object x = "oops";
+ switch (op) {
+ case ADD: alist.add(x); break;
+ case ADD_AT: alist.add(0, x); break;
+ case ADD_ALL: alist.add(Collections.singleton(x)); break;
+ case ADD_ALL_AT: alist.add(0, Collections.singleton(x)); break;
+ case SET: alist.set(0, x); break;
+ default: throw new AssertionError("Case not covered");
+ }
+ }
+
+ private static void fail(String why) {
+ System.out.println("FAIL: " + why);
+ failure = why;
+ }
+
+}
diff --git a/jdk/test/javax/management/context/ContextForwarderTest.java b/jdk/test/javax/management/context/ContextForwarderTest.java
new file mode 100644
index 0000000..d82acd3
--- /dev/null
+++ b/jdk/test/javax/management/context/ContextForwarderTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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 5072267
+ * @summary Test that a context forwarder can be created and then installed.
+ * @author Eamonn McManus
+ */
+
+/* The specific thing we're testing for is that the forwarder can be created
+ * with a null "next", and then installed with a real "next". An earlier
+ * defect meant that in this case the simulated jmx.context// namespace had a
+ * null handler that never changed.
+ */
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.management.ClientContext;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.MBeanServerForwarder;
+
+public class ContextForwarderTest {
+ private static String failure;
+
+ public static void main(String[] args) throws Exception {
+ MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+ JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
+ Map<String, String> env = new HashMap<String, String>();
+ env.put(JMXConnectorServer.CONTEXT_FORWARDER, "false");
+ JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(
+ url, env, mbs);
+ MBeanServerForwarder sysMBSF = cs.getSystemMBeanServerForwarder();
+ MBeanServerForwarder mbsf = ClientContext.newContextForwarder(mbs, sysMBSF);
+ sysMBSF.setMBeanServer(mbsf);
+
+ int localCount = mbs.getMBeanCount();
+
+ cs.start();
+ try {
+ JMXConnector cc = JMXConnectorFactory.connect(cs.getAddress());
+ MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+ mbsc = ClientContext.withContext(mbsc, "foo", "bar");
+ int contextCount = mbsc.getMBeanCount();
+ if (localCount + 1 != contextCount) {
+ fail("Local MBean count %d, context MBean count %d",
+ localCount, contextCount);
+ }
+ Set<ObjectName> localNames =
+ new TreeSet<ObjectName>(mbs.queryNames(null, null));
+ ObjectName contextNamespaceObjectName =
+ new ObjectName(ClientContext.NAMESPACE + "//:type=JMXNamespace");
+ if (!localNames.add(contextNamespaceObjectName))
+ fail("Local names already contained context namespace handler");
+ Set<ObjectName> contextNames = mbsc.queryNames(null, null);
+ if (!localNames.equals(contextNames)) {
+ fail("Name set differs locally and in context: " +
+ "local: %s; context: %s", localNames, contextNames);
+ }
+ } finally {
+ cs.stop();
+ }
+ if (failure != null)
+ throw new Exception("TEST FAILED: " + failure);
+ else
+ System.out.println("TEST PASSED");
+ }
+
+ private static void fail(String msg, Object... params) {
+ failure = String.format(msg, params);
+ System.out.println("FAIL: " + failure);
+ }
+}
diff --git a/jdk/test/javax/management/context/ContextTest.java b/jdk/test/javax/management/context/ContextTest.java
new file mode 100644
index 0000000..1fb293e
--- /dev/null
+++ b/jdk/test/javax/management/context/ContextTest.java
@@ -0,0 +1,534 @@
+/*
+ * 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 ContextTest
+ * @bug 5072267
+ * @summary Test client contexts.
+ * @author Eamonn McManus
+ * TODO: Try registering with a null name replaced by preRegister (for example
+ * from the MLet class) and see if it now works.
+ */
+
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.Callable;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.ClientContext;
+import javax.management.DynamicMBean;
+import javax.management.JMX;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerDelegate;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.StandardMBean;
+import javax.management.loading.MLet;
+import javax.management.namespace.JMXNamespace;
+
+import javax.management.remote.MBeanServerForwarder;
+import static java.util.Collections.emptyMap;
+import static java.util.Collections.singletonMap;
+
+public class ContextTest {
+ private static String failure;
+ private static final Map<String, String> emptyContext = emptyMap();
+
+ public static interface ShowContextMBean {
+ public Map<String, String> getContext();
+ public Map<String, String> getCreationContext();
+ public Set<String> getCalledOps();
+ public String getThing();
+ public void setThing(String x);
+ public int add(int x, int y);
+ }
+
+ public static class ShowContext
+ extends NotificationBroadcasterSupport
+ implements ShowContextMBean, MBeanRegistration {
+ private final Map<String, String> creationContext;
+ private final Set<String> calledOps = new HashSet<String>();
+
+ public ShowContext() {
+ creationContext = getContext();
+ }
+
+ public Map<String, String> getContext() {
+ return ClientContext.getContext();
+ }
+
+ public Map<String, String> getCreationContext() {
+ return creationContext;
+ }
+
+ public Set<String> getCalledOps() {
+ return calledOps;
+ }
+
+ public String getThing() {
+ return "x";
+ }
+
+ public void setThing(String x) {
+ }
+
+ public int add(int x, int y) {
+ return x + y;
+ }
+
+ public ObjectName preRegister(MBeanServer server, ObjectName name) {
+ assertEquals("preRegister context", creationContext, getContext());
+ calledOps.add("preRegister");
+ return name;
+ }
+
+ public void postRegister(Boolean registrationDone) {
+ assertEquals("postRegister context", creationContext, getContext());
+ calledOps.add("postRegister");
+ }
+
+ // The condition checked here is not guaranteed universally true,
+ // but is true every time we unregister an instance of this MBean
+ // in this test.
+ public void preDeregister() throws Exception {
+ assertEquals("preDeregister context", creationContext, getContext());
+ }
+
+ public void postDeregister() {
+ assertEquals("postDeregister context", creationContext, getContext());
+ }
+
+ // Same remark as for preDeregister
+ @Override
+ public MBeanNotificationInfo[] getNotificationInfo() {
+ calledOps.add("getNotificationInfo");
+ return super.getNotificationInfo();
+ }
+
+ @Override
+ public void addNotificationListener(
+ NotificationListener listener, NotificationFilter filter, Object handback) {
+ calledOps.add("addNotificationListener");
+ super.addNotificationListener(listener, filter, handback);
+ }
+
+ @Override
+ public void removeNotificationListener(
+ NotificationListener listener)
+ throws ListenerNotFoundException {
+ calledOps.add("removeNL1");
+ super.removeNotificationListener(listener);
+ }
+
+ @Override
+ public void removeNotificationListener(
+ NotificationListener listener, NotificationFilter filter, Object handback)
+ throws ListenerNotFoundException {
+ calledOps.add("removeNL3");
+ super.removeNotificationListener(listener, filter, handback);
+ }
+ }
+
+ private static class LogRecord {
+ final String op;
+ final Object[] params;
+ final Map<String, String> context;
+ LogRecord(String op, Object[] params, Map<String, String> context) {
+ this.op = op;
+ this.params = params;
+ this.context = context;
+ }
+
+ @Override
+ public String toString() {
+ return op + Arrays.deepToString(params) + " " + context;
+ }
+ }
+
+ /*
+ * InvocationHandler that forwards all methods to a contained object
+ * but also records each forwarded method. This allows us to check
+ * that the appropriate methods were called with the appropriate
+ * parameters. It's similar to what's typically available in
+ * Mock Object frameworks.
+ */
+ private static class LogIH implements InvocationHandler {
+ private final Object wrapped;
+ Queue<LogRecord> log = new LinkedList<LogRecord>();
+
+ LogIH(Object wrapped) {
+ this.wrapped = wrapped;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ if (method.getDeclaringClass() != Object.class) {
+ LogRecord lr =
+ new LogRecord(
+ method.getName(), args, ClientContext.getContext());
+ log.add(lr);
+ }
+ try {
+ return method.invoke(wrapped, args);
+ } catch (InvocationTargetException e) {
+ throw e.getCause();
+ }
+ }
+ }
+
+ private static <T> T newSnoop(Class<T> wrappedClass, LogIH logIH) {
+ return wrappedClass.cast(Proxy.newProxyInstance(
+ wrappedClass.getClassLoader(),
+ new Class<?>[] {wrappedClass},
+ logIH));
+ }
+
+ public static void main(String[] args) throws Exception {
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ System.out.println(mbs.queryNames(null, null));
+ ObjectName name = new ObjectName("a:b=c");
+ mbs.registerMBean(new ShowContext(), name);
+ final ShowContextMBean show =
+ JMX.newMBeanProxy(mbs, name, ShowContextMBean.class);
+
+ // Test local setting and getting within the MBeanServer
+
+ assertEquals("initial context", emptyContext, show.getContext());
+ ClientContext.doWithContext(singletonMap("foo", "bar"), new Callable<Void>() {
+ public Void call() {
+ assertEquals("context in doWithContext",
+ singletonMap("foo", "bar"), show.getContext());
+ return null;
+ }
+ });
+ assertEquals("initial context after doWithContext",
+ emptyContext, show.getContext());
+ String got = ClientContext.doWithContext(
+ singletonMap("foo", "baz"), new Callable<String>() {
+ public String call() {
+ return ClientContext.getContext().get("foo");
+ }
+ });
+ assertEquals("value extracted from context", "baz", got);
+
+ Map<String, String> combined = ClientContext.doWithContext(
+ singletonMap("foo", "baz"), new Callable<Map<String, String>>() {
+ public Map<String, String> call() throws Exception {
+ return ClientContext.doWithContext(
+ singletonMap("fred", "jim"),
+ new Callable<Map<String, String>>() {
+ public Map<String, String> call() {
+ return ClientContext.getContext();
+ }
+ });
+ }
+ });
+ assertEquals("nested doWithContext context",
+ singletonMap("fred", "jim"), combined);
+
+ final String ugh = "a!\u00c9//*=:\"% ";
+ ClientContext.doWithContext(singletonMap(ugh, ugh), new Callable<Void>() {
+ public Void call() {
+ assertEquals("context with tricky encoding",
+ singletonMap(ugh, ugh), show.getContext());
+ return null;
+ }
+ });
+ Map<String, String> ughMap = new TreeMap<String, String>();
+ ughMap.put(ugh, ugh);
+ ughMap.put("fred", "jim");
+ // Since this is a TreeMap and "fred" is greater than ugh (which begins
+ // with "a"), we will see the encoding of ugh first in the output string.
+ String encoded = ClientContext.encode(ughMap);
+ String expectedUghCoding = "a%21%C3%89%2F%2F%2A%3D%3A%22%25+";
+ String expectedUghMapCoding =
+ ClientContext.NAMESPACE + "//" + expectedUghCoding + "=" +
+ expectedUghCoding + ";fred=jim";
+ assertEquals("hairy context encoded as string",
+ expectedUghMapCoding, encoded);
+
+ // Wrap the MBeanServer with a context MBSF so we can test withContext.
+ // Also check the simulated namespace directly.
+
+ LogIH mbsIH = new LogIH(mbs);
+ MBeanServer snoopMBS = newSnoop(MBeanServer.class, mbsIH);
+ MBeanServerForwarder ctxMBS =
+ ClientContext.newContextForwarder(snoopMBS, null);
+
+ // The MBSF returned by ClientContext is actually a compound of two
+ // forwarders, but that is supposed to be hidden by changing the
+ // behaviour of get/setMBeanServer. Check that it is indeed so.
+ assertEquals("next MBS of context forwarder",
+ snoopMBS, ctxMBS.getMBeanServer());
+ // If the above assertion fails you may get a confusing message
+ // because the toString() of the two objects is likely to be the same
+ // so it will look as if they should be equal.
+ ctxMBS.setMBeanServer(null);
+ assertEquals("next MBS of context forwarder after setting it null",
+ null, ctxMBS.getMBeanServer());
+ ctxMBS.setMBeanServer(snoopMBS);
+
+ // The MBSF should look the same as the original MBeanServer except
+ // that it has the JMXNamespace for the simulated namespace.
+
+ Set<ObjectName> origNames = mbs.queryNames(null, null);
+ Set<ObjectName> mbsfNames = ctxMBS.queryNames(null, null);
+ assertEquals("number of MBeans returned by queryNames within forwarder",
+ origNames.size() + 1, mbsfNames.size());
+ assertEquals("MBeanCount within forwarder",
+ mbsfNames.size(), ctxMBS.getMBeanCount());
+ assertCalled(mbsIH, "queryNames", emptyContext);
+ assertCalled(mbsIH, "getMBeanCount", emptyContext);
+
+ ObjectName ctxNamespaceName = new ObjectName(
+ ClientContext.NAMESPACE + "//:" + JMXNamespace.TYPE_ASSIGNMENT);
+ origNames.add(ctxNamespaceName);
+ assertEquals("MBeans within forwarder", origNames, mbsfNames);
+ Set<String> domains = new HashSet<String>(Arrays.asList(ctxMBS.getDomains()));
+ assertEquals("domains include context namespace MBean",
+ true, domains.contains(ClientContext.NAMESPACE + "//"));
+ assertCalled(mbsIH, "getDomains", emptyContext);
+
+ // Now test ClientContext.withContext.
+
+ MBeanServer ughMBS = ClientContext.withContext(ctxMBS, ugh, ugh);
+
+ ShowContextMBean ughshow =
+ JMX.newMBeanProxy(ughMBS, name, ShowContextMBean.class);
+ Map<String, String> ughCtx = ughshow.getContext();
+ Map<String, String> ughExpect = singletonMap(ugh, ugh);
+ assertEquals("context seen by MBean accessed within namespace",
+ ughExpect, ughCtx);
+ assertCalled(mbsIH, "getAttribute", ughExpect, name, "Context");
+
+ MBeanServer cmbs = ClientContext.withContext(
+ ctxMBS, "mickey", "mouse");
+ ShowContextMBean cshow =
+ JMX.newMBeanProxy(cmbs, name, ShowContextMBean.class);
+ assertEquals("context seen by MBean accessed within namespace",
+ singletonMap("mickey", "mouse"), cshow.getContext());
+
+ MBeanServer ccmbs = ClientContext.withContext(
+ cmbs, "donald", "duck");
+ ShowContextMBean ccshow =
+ JMX.newMBeanProxy(ccmbs, name, ShowContextMBean.class);
+ Map<String, String> disney = new HashMap<String, String>();
+ disney.put("mickey", "mouse");
+ disney.put("donald", "duck");
+ assertEquals("context seen by MBean in nested namespace",
+ disney, ccshow.getContext());
+
+ // Test that all MBS ops produce reasonable results
+
+ ObjectName logger = new ObjectName("a:type=Logger");
+ DynamicMBean showMBean =
+ new StandardMBean(new ShowContext(), ShowContextMBean.class);
+ LogIH mbeanLogIH = new LogIH(showMBean);
+ DynamicMBean logMBean = newSnoop(DynamicMBean.class, mbeanLogIH);
+ ObjectInstance loggerOI = ccmbs.registerMBean(logMBean, logger);
+ assertEquals("ObjectName returned by createMBean",
+ logger, loggerOI.getObjectName());
+
+ // We get an getMBeanInfo call to determine the className in the
+ // ObjectInstance to return from registerMBean.
+ assertCalled(mbeanLogIH, "getMBeanInfo", disney);
+
+ ccmbs.getAttribute(logger, "Thing");
+ assertCalled(mbeanLogIH, "getAttribute", disney);
+
+ ccmbs.getAttributes(logger, new String[] {"Thing", "Context"});
+ assertCalled(mbeanLogIH, "getAttributes", disney);
+
+ ccmbs.setAttribute(logger, new Attribute("Thing", "bar"));
+ assertCalled(mbeanLogIH, "setAttribute", disney);
+
+ ccmbs.setAttributes(logger, new AttributeList(
+ Arrays.asList(new Attribute("Thing", "baz"))));
+ assertCalled(mbeanLogIH, "setAttributes", disney);
+
+ ccmbs.getMBeanInfo(logger);
+ assertCalled(mbeanLogIH, "getMBeanInfo", disney);
+
+ Set<ObjectName> names = ccmbs.queryNames(null, null);
+ Set<ObjectName> expectedNames = new HashSet<ObjectName>(
+ Collections.singleton(MBeanServerDelegate.DELEGATE_NAME));
+ assertEquals("context namespace query includes expected names",
+ true, names.containsAll(expectedNames));
+
+ Set<ObjectName> nsNames = ccmbs.queryNames(new ObjectName("*//:*"), null);
+ Set<ObjectName> expectedNsNames = new HashSet<ObjectName>(
+ Arrays.asList(
+ new ObjectName(ClientContext.NAMESPACE +
+ ObjectName.NAMESPACE_SEPARATOR + ":" +
+ JMXNamespace.TYPE_ASSIGNMENT)));
+ assertEquals("context namespace query includes namespace MBean",
+ true, nsNames.containsAll(expectedNsNames));
+
+
+
+ Set<ObjectInstance> insts = ccmbs.queryMBeans(
+ MBeanServerDelegate.DELEGATE_NAME, null);
+ assertEquals("size of set from MBeanServerDelegate query", 1, insts.size());
+ assertEquals("ObjectName from MBeanServerDelegate query",
+ MBeanServerDelegate.DELEGATE_NAME,
+ insts.iterator().next().getObjectName());
+
+ ObjectName createdName = new ObjectName("a:type=Created");
+ ObjectInstance createdOI =
+ ccmbs.createMBean(ShowContext.class.getName(), createdName);
+ assertEquals("class name from createMBean",
+ ShowContext.class.getName(), createdOI.getClassName());
+ assertEquals("ObjectName from createMBean",
+ createdName, createdOI.getObjectName());
+ assertEquals("context within createMBean",
+ disney, ccmbs.getAttribute(createdName, "CreationContext"));
+
+ NotificationListener nothingListener = new NotificationListener() {
+ public void handleNotification(Notification n, Object h) {}
+ };
+ ccmbs.addNotificationListener(createdName, nothingListener, null, null);
+ ccmbs.removeNotificationListener(createdName, nothingListener, null, null);
+ ccmbs.addNotificationListener(createdName, nothingListener, null, null);
+ ccmbs.removeNotificationListener(createdName, nothingListener);
+ Set<String> expectedOps = new HashSet<String>(Arrays.asList(
+ "preRegister", "postRegister", "addNotificationListener",
+ "removeNL1", "removeNL3", "getNotificationInfo"));
+ assertEquals("operations called on MBean",
+ expectedOps, ccmbs.getAttribute(createdName, "CalledOps"));
+
+ assertEquals("ClassLoader for MBean",
+ ShowContext.class.getClassLoader(),
+ ccmbs.getClassLoaderFor(createdName));
+
+ assertEquals("isRegistered", true, ccmbs.isRegistered(createdName));
+ assertEquals("isInstanceOf", true, ccmbs.isInstanceOf(createdName,
+ ShowContext.class.getName()));
+ assertEquals("isInstanceOf", false, ccmbs.isInstanceOf(createdName,
+ DynamicMBean.class.getName()));
+ ccmbs.unregisterMBean(createdName);
+ assertEquals("isRegistered after unregister",
+ false, ccmbs.isRegistered(createdName));
+
+ MLet mlet = new MLet();
+ ObjectName defaultMLetName = new ObjectName("DefaultDomain:type=MLet");
+
+ ccmbs.registerMBean(mlet, defaultMLetName);
+
+ assertEquals("getClassLoader", mlet, ccmbs.getClassLoader(defaultMLetName));
+
+ assertEquals("number of MBean operations", 0, mbeanLogIH.log.size());
+
+ // Test that contexts still work when we can't combine two encoded contexts.
+ // Here, we wrap cmbs (mickey=mouse) so that ccmbs2 (donald=duck) cannot
+ // see that it already contains a context and therefore cannot combine
+ // into mickey=mouse;donald=duck. We don't actually use the snoop
+ // capabilities of the returned object -- we just want an opaque
+ // MBeanServer wrapper
+ MBeanServer cmbs2 = newSnoop(MBeanServer.class, new LogIH(cmbs));
+ MBeanServer ccmbs2 = ClientContext.withContext(cmbs2, "donald", "duck");
+ assertEquals("context when combination is impossible",
+ disney, ccmbs2.getAttribute(name, "Context"));
+
+ // Test failure cases of ClientContext.encode
+ final List<Map<String, String>> badEncodeArgs =
+ Arrays.asList(
+ null,
+ Collections.<String,String>singletonMap(null, "foo"),
+ Collections.<String,String>singletonMap("foo", null));
+ for (Map<String, String> bad : badEncodeArgs) {
+ try {
+ String oops = ClientContext.encode(bad);
+ failed("ClientContext.encode(" + bad + ") should have failed: "
+ + oops);
+ } catch (Exception e) {
+ assertEquals("Exception for ClientContext.encode(" + bad + ")",
+ IllegalArgumentException.class, e.getClass());
+ }
+ }
+
+ // ADD NEW TESTS HERE ^^^
+
+ if (failure != null)
+ throw new Exception(failure);
+ }
+
+ private static void assertEquals(String what, Object x, Object y) {
+ if (!equal(x, y))
+ failed(what + ": expected " + string(x) + "; got " + string(y));
+ }
+
+ private static boolean equal(Object x, Object y) {
+ if (x == y)
+ return true;
+ if (x == null || y == null)
+ return false;
+ if (x.getClass().isArray())
+ return Arrays.deepEquals(new Object[] {x}, new Object[] {y});
+ return x.equals(y);
+ }
+
+ private static String string(Object x) {
+ String s = Arrays.deepToString(new Object[] {x});
+ return s.substring(1, s.length() - 1);
+ }
+
+ private static void assertCalled(
+ LogIH logIH, String op, Map<String, String> expectedContext) {
+ assertCalled(logIH, op, expectedContext, (Object[]) null);
+ }
+
+ private static void assertCalled(
+ LogIH logIH, String op, Map<String, String> expectedContext,
+ Object... params) {
+ LogRecord lr = logIH.log.remove();
+ assertEquals("called operation", op, lr.op);
+ if (params != null)
+ assertEquals("operation parameters", params, lr.params);
+ assertEquals("operation context", expectedContext, lr.context);
+ }
+
+ private static void failed(String why) {
+ failure = why;
+ new Throwable("FAILED: " + why).printStackTrace(System.out);
+ }
+}
diff --git a/jdk/test/javax/management/context/LocaleAwareBroadcasterTest.java b/jdk/test/javax/management/context/LocaleAwareBroadcasterTest.java
new file mode 100644
index 0000000..7963f9f
--- /dev/null
+++ b/jdk/test/javax/management/context/LocaleAwareBroadcasterTest.java
@@ -0,0 +1,328 @@
+/*
+ * 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 5072267
+ * @summary Test that an MBean can handle localized Notification messages.
+ * @author Eamonn McManus
+ */
+
+import java.util.Collections;
+import java.util.ListResourceBundle;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+import javax.management.ClientContext;
+import javax.management.JMX;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.SendNotification;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+public class LocaleAwareBroadcasterTest {
+ static final ObjectName mbeanName = ObjectName.valueOf("d:type=LocaleAware");
+
+ static final String
+ messageKey = "broken.window",
+ defaultMessage = "broken window",
+ frenchMessage = "fen\u00eatre bris\u00e9e",
+ irishMessage = "fuinneog briste";
+
+ public static class Bundle extends ListResourceBundle {
+ @Override
+ protected Object[][] getContents() {
+ return new Object[][] {
+ {messageKey, defaultMessage},
+ };
+ }
+ }
+
+ public static class Bundle_fr extends ListResourceBundle {
+ @Override
+ protected Object[][] getContents() {
+ return new Object[][] {
+ {messageKey, frenchMessage},
+ };
+ }
+ }
+
+ public static class Bundle_ga extends ListResourceBundle {
+ @Override
+ protected Object[][] getContents() {
+ return new Object[][] {
+ {messageKey, irishMessage},
+ };
+ }
+ }
+
+ static volatile String failure;
+
+ public static interface LocaleAwareMBean {
+ public void sendNotification(Notification n);
+ }
+
+ public static class LocaleAware
+ implements LocaleAwareMBean, NotificationEmitter, SendNotification {
+
+ private final ConcurrentMap<Locale, NotificationBroadcasterSupport>
+ localeToEmitter = newConcurrentMap();
+
+ public void sendNotification(Notification n) {
+ for (Map.Entry<Locale, NotificationBroadcasterSupport> entry :
+ localeToEmitter.entrySet()) {
+ Notification localizedNotif =
+ localizeNotification(n, entry.getKey());
+ entry.getValue().sendNotification(localizedNotif);
+ }
+ }
+
+ public void addNotificationListener(
+ NotificationListener listener,
+ NotificationFilter filter,
+ Object handback)
+ throws IllegalArgumentException {
+ Locale locale = ClientContext.getLocale();
+ NotificationBroadcasterSupport broadcaster;
+ broadcaster = localeToEmitter.get(locale);
+ if (broadcaster == null) {
+ broadcaster = new NotificationBroadcasterSupport();
+ NotificationBroadcasterSupport old =
+ localeToEmitter.putIfAbsent(locale, broadcaster);
+ if (old != null)
+ broadcaster = old;
+ }
+ broadcaster.addNotificationListener(listener, filter, handback);
+ }
+
+ public void removeNotificationListener(NotificationListener listener)
+ throws ListenerNotFoundException {
+ Locale locale = ClientContext.getLocale();
+ NotificationBroadcasterSupport broadcaster =
+ localeToEmitter.get(locale);
+ if (broadcaster == null)
+ throw new ListenerNotFoundException();
+ broadcaster.removeNotificationListener(listener);
+ }
+
+ public void removeNotificationListener(
+ NotificationListener listener,
+ NotificationFilter filter,
+ Object handback)
+ throws ListenerNotFoundException {
+ Locale locale = ClientContext.getLocale();
+ NotificationBroadcasterSupport broadcaster =
+ localeToEmitter.get(locale);
+ if (broadcaster == null)
+ throw new ListenerNotFoundException();
+ broadcaster.removeNotificationListener(listener, filter, handback);
+ }
+
+ public MBeanNotificationInfo[] getNotificationInfo() {
+ return new MBeanNotificationInfo[0];
+ }
+ }
+
+ // Localize notif using the convention that the message looks like
+ // [resourcebundlename:resourcekey]defaultmessage
+ // for example [foo.bar.Resources:unknown.problem]
+ static Notification localizeNotification(Notification n, Locale locale) {
+ String msg = n.getMessage();
+ if (!msg.startsWith("["))
+ return n;
+ int close = msg.indexOf(']');
+ if (close < 0)
+ throw new IllegalArgumentException("Bad notification message: " + msg);
+ int colon = msg.indexOf(':');
+ if (colon < 0 || colon > close)
+ throw new IllegalArgumentException("Bad notification message: " + msg);
+ String bundleName = msg.substring(1, colon);
+ String key = msg.substring(colon + 1, close);
+ ClassLoader loader = LocaleAwareBroadcasterTest.class.getClassLoader();
+ ResourceBundle bundle =
+ ResourceBundle.getBundle(bundleName, locale, loader);
+ try {
+ msg = bundle.getString(key);
+ } catch (MissingResourceException e) {
+ msg = msg.substring(close + 1);
+ }
+ n = (Notification) n.clone();
+ n.setMessage(msg);
+ return n;
+ }
+
+ public static void main(String[] args) throws Exception {
+ Locale.setDefault(new Locale("en"));
+ testLocal();
+ testRemote();
+ if (failure == null)
+ System.out.println("TEST PASSED");
+ else
+ throw new Exception("TEST FAILED: " + failure);
+ }
+
+ static interface AddListenerInLocale {
+ public void addListenerInLocale(
+ MBeanServerConnection mbsc,
+ NotificationListener listener,
+ Locale locale) throws Exception;
+ }
+
+ private static void testLocal() throws Exception {
+ System.out.println("Test local MBeanServer using doWithContext");
+ MBeanServer mbs = makeMBS();
+ AddListenerInLocale addListener = new AddListenerInLocale() {
+ public void addListenerInLocale(
+ final MBeanServerConnection mbsc,
+ final NotificationListener listener,
+ Locale locale) throws Exception {
+ Map<String, String> localeContext = Collections.singletonMap(
+ ClientContext.LOCALE_KEY, locale.toString());
+ ClientContext.doWithContext(
+ localeContext, new Callable<Void>() {
+ public Void call() throws Exception {
+ mbsc.addNotificationListener(
+ mbeanName, listener, null, null);
+ return null;
+ }
+ });
+ }
+ };
+ test(mbs, addListener);
+ }
+
+ private static void testRemote() throws Exception {
+ System.out.println("Test remote MBeanServer using withLocale");
+ MBeanServer mbs = makeMBS();
+ JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
+ JMXConnectorServer cs =
+ JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
+ cs.start();
+ JMXServiceURL addr = cs.getAddress();
+ JMXConnector cc = JMXConnectorFactory.connect(addr);
+ MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+ AddListenerInLocale addListenerInLocale = new AddListenerInLocale() {
+ public void addListenerInLocale(
+ MBeanServerConnection mbsc,
+ NotificationListener listener,
+ Locale locale) throws Exception {
+ mbsc = ClientContext.withLocale(mbsc, locale);
+ mbsc.addNotificationListener(mbeanName, listener, null, null);
+ }
+ };
+ try {
+ test(mbsc, addListenerInLocale);
+ } finally {
+ try {
+ cc.close();
+ } catch (Exception e) {}
+ cs.stop();
+ }
+ }
+
+ static class QueueListener implements NotificationListener {
+ final BlockingQueue<Notification> queue =
+ new ArrayBlockingQueue<Notification>(10);
+
+ public void handleNotification(Notification notification,
+ Object handback) {
+ queue.add(notification);
+ }
+ }
+
+ private static void test(
+ MBeanServerConnection mbsc, AddListenerInLocale addListener)
+ throws Exception {
+ QueueListener defaultListener = new QueueListener();
+ QueueListener frenchListener = new QueueListener();
+ QueueListener irishListener = new QueueListener();
+ mbsc.addNotificationListener(mbeanName, defaultListener, null, null);
+ addListener.addListenerInLocale(mbsc, frenchListener, new Locale("fr"));
+ addListener.addListenerInLocale(mbsc, irishListener, new Locale("ga"));
+
+ LocaleAwareMBean proxy =
+ JMX.newMBeanProxy(mbsc, mbeanName, LocaleAwareMBean.class);
+ String notifMsg = "[" + Bundle.class.getName() + ":" + messageKey + "]" +
+ "broken window (default message that should never be seen)";
+ Notification notif = new Notification(
+ "notif.type", mbeanName, 0L, notifMsg);
+ proxy.sendNotification(notif);
+
+ final Object[][] expected = {
+ {defaultListener, defaultMessage},
+ {frenchListener, frenchMessage},
+ {irishListener, irishMessage},
+ };
+ for (Object[] exp : expected) {
+ QueueListener ql = (QueueListener) exp[0];
+ String msg = (String) exp[1];
+ System.out.println("Checking: " + msg);
+ Notification n = ql.queue.poll(1, TimeUnit.SECONDS);
+ if (n == null)
+ fail("Did not receive expected notif: " + msg);
+ if (!n.getMessage().equals(msg)) {
+ fail("Received notif with wrong message: got " +
+ n.getMessage() + ", expected " + msg);
+ }
+ n = ql.queue.poll(2, TimeUnit.MILLISECONDS);
+ if (n != null)
+ fail("Received unexpected extra notif: " + n);
+ }
+ }
+
+ private static MBeanServer makeMBS() throws Exception {
+ MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+ LocaleAware aware = new LocaleAware();
+ mbs.registerMBean(aware, mbeanName);
+ return mbs;
+ }
+
+ static <K, V> ConcurrentMap<K, V> newConcurrentMap() {
+ return new ConcurrentHashMap<K, V>();
+ }
+
+ static void fail(String why) {
+ System.out.println("FAIL: " + why);
+ failure = why;
+ }
+}
diff --git a/jdk/test/javax/management/context/LocaleTest.java b/jdk/test/javax/management/context/LocaleTest.java
new file mode 100644
index 0000000..e5ea530
--- /dev/null
+++ b/jdk/test/javax/management/context/LocaleTest.java
@@ -0,0 +1,140 @@
+/*
+ * 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 LocaleTest.java
+ * @bug 5072267
+ * @summary Test client locales.
+ * @author Eamonn McManus
+ */
+
+import java.lang.management.ManagementFactory;
+import java.util.Collections;
+import java.util.ListResourceBundle;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.concurrent.Callable;
+import javax.management.ClientContext;
+import java.util.Arrays;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+public class LocaleTest {
+ private static String failure;
+
+ public static void main(String[] args) throws Exception {
+
+ // Test the translation String -> Locale
+
+ Locale[] locales = Locale.getAvailableLocales();
+ System.out.println("Testing String->Locale for " + locales.length +
+ " locales");
+ for (Locale loc : locales) {
+ Map<String, String> ctx = Collections.singletonMap(
+ ClientContext.LOCALE_KEY, loc.toString());
+ Locale loc2 = ClientContext.doWithContext(
+ ctx, new Callable<Locale>() {
+ public Locale call() {
+ return ClientContext.getLocale();
+ }
+ });
+ assertEquals(loc, loc2);
+ }
+
+ // Test that a locale-sensitive attribute works
+
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ mbs = ClientContext.newContextForwarder(mbs, null);
+ ObjectName name = new ObjectName("a:type=LocaleSensitive");
+ mbs.registerMBean(new LocaleSensitive(), name);
+ Locale.setDefault(Locale.US);
+
+ assertEquals("spectacular failure",
+ mbs.getAttribute(name, "LastProblemDescription"));
+
+ MBeanServer frmbs = ClientContext.withContext(
+ mbs, ClientContext.LOCALE_KEY, Locale.FRANCE.toString());
+ assertEquals("\u00e9chec r\u00e9tentissant",
+ frmbs.getAttribute(name, "LastProblemDescription"));
+
+ if (failure == null)
+ System.out.println("TEST PASSED");
+ else
+ throw new Exception("TEST FAILED: " + failure);
+ }
+
+ public static interface LocaleSensitiveMBean {
+ public String getLastProblemDescription();
+ }
+
+ public static class LocaleSensitive implements LocaleSensitiveMBean {
+ public String getLastProblemDescription() {
+ Locale loc = ClientContext.getLocale();
+ ResourceBundle rb = ResourceBundle.getBundle(
+ MyResources.class.getName(), loc);
+ return rb.getString("spectacular");
+ }
+ }
+
+ public static class MyResources extends ListResourceBundle {
+ protected Object[][] getContents() {
+ return new Object[][] {
+ {"spectacular", "spectacular failure"},
+ };
+ }
+ }
+
+ public static class MyResources_fr extends ListResourceBundle {
+ protected Object[][] getContents() {
+ return new Object[][] {
+ {"spectacular", "\u00e9chec r\u00e9tentissant"},
+ };
+ }
+ }
+
+ private static void assertEquals(Object x, Object y) {
+ if (!equal(x, y))
+ failed("expected " + string(x) + "; got " + string(y));
+ }
+
+ private static boolean equal(Object x, Object y) {
+ if (x == y)
+ return true;
+ if (x == null || y == null)
+ return false;
+ if (x.getClass().isArray())
+ return Arrays.deepEquals(new Object[] {x}, new Object[] {y});
+ return x.equals(y);
+ }
+
+ private static String string(Object x) {
+ String s = Arrays.deepToString(new Object[] {x});
+ return s.substring(1, s.length() - 1);
+ }
+
+ private static void failed(String why) {
+ failure = why;
+ new Throwable("FAILED: " + why).printStackTrace(System.out);
+ }
+}
diff --git a/jdk/test/javax/management/context/LocalizableTest.java b/jdk/test/javax/management/context/LocalizableTest.java
new file mode 100644
index 0000000..40a18af
--- /dev/null
+++ b/jdk/test/javax/management/context/LocalizableTest.java
@@ -0,0 +1,192 @@
+/*
+ * 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 LocalizableTest
+ * @bug 5072267 6635499
+ * @summary Test localizable MBeanInfo using LocalizableMBeanFactory.
+ * @author Eamonn McManus
+ */
+
+import java.lang.management.ManagementFactory;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import javax.management.ClientContext;
+import javax.management.Description;
+import javax.management.JMX;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanConstructorInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import localizable.MBeanDescriptions_fr;
+import localizable.Whatsit;
+
+import static localizable.WhatsitMBean.*;
+
+public class LocalizableTest {
+ // If you change the order of the array elements or their number then
+ // you must also change these constants.
+ private static final int
+ MBEAN = 0, ATTR = 1, OPER = 2, PARAM = 3, CONSTR = 4,
+ CONSTR_PARAM = 5;
+ private static final String[] englishDescriptions = {
+ englishMBeanDescription, englishAttrDescription, englishOperDescription,
+ englishParamDescription, englishConstrDescription,
+ englishConstrParamDescription,
+ };
+ private static final String[] defaultDescriptions = englishDescriptions.clone();
+ static {
+ defaultDescriptions[MBEAN] = defaultMBeanDescription;
+ }
+ private static final String[] frenchDescriptions = {
+ frenchMBeanDescription, frenchAttrDescription, frenchOperDescription,
+ frenchParamDescription, frenchConstrDescription,
+ frenchConstrParamDescription,
+ };
+
+ private static String failure;
+
+ @Description(unlocalizedMBeanDescription)
+ public static interface UnlocalizedMBean {}
+ public static class Unlocalized implements UnlocalizedMBean {}
+
+ public static void main(String[] args) throws Exception {
+ ResourceBundle frenchBundle = new MBeanDescriptions_fr();
+ // The purpose of the previous line is to force that class to be compiled
+ // when the test is run so it will be available for reflection.
+ // Yes, we could do this with a @build tag.
+
+ MBeanServer plainMBS = ManagementFactory.getPlatformMBeanServer();
+ MBeanServer unlocalizedMBS =
+ ClientContext.newContextForwarder(plainMBS, null);
+ MBeanServer localizedMBS =
+ ClientContext.newLocalizeMBeanInfoForwarder(plainMBS);
+ localizedMBS = ClientContext.newContextForwarder(localizedMBS, null);
+ ObjectName name = new ObjectName("a:b=c");
+
+ Whatsit whatsit = new Whatsit();
+ Object[][] locales = {
+ {null, englishDescriptions},
+ {"en", englishDescriptions},
+ {"fr", frenchDescriptions},
+ };
+
+ for (Object[] localePair : locales) {
+ String locale = (String) localePair[0];
+ String[] localizedDescriptions = (String[]) localePair[1];
+ System.out.println("===Testing locale " + locale + "===");
+ for (boolean localized : new boolean[] {false, true}) {
+ String[] descriptions = localized ?
+ localizedDescriptions : defaultDescriptions;
+ MBeanServer mbs = localized ? localizedMBS : unlocalizedMBS;
+ System.out.println("Testing MBean " + whatsit + " with " +
+ "localized=" + localized);
+ mbs.registerMBean(whatsit, name);
+ System.out.println(mbs.getMBeanInfo(name));
+ try {
+ test(mbs, name, locale, descriptions);
+ } catch (Exception e) {
+ fail("Caught exception: " + e);
+ } finally {
+ mbs.unregisterMBean(name);
+ }
+ }
+ }
+
+ System.out.println("===Testing unlocalizable MBean===");
+ Object mbean = new Unlocalized();
+ localizedMBS.registerMBean(mbean, name);
+ try {
+ MBeanInfo mbi = localizedMBS.getMBeanInfo(name);
+ assertEquals("MBean description", unlocalizedMBeanDescription,
+ mbi.getDescription());
+ } finally {
+ localizedMBS.unregisterMBean(name);
+ }
+
+ System.out.println("===Testing MBeanInfo.localizeDescriptions===");
+ plainMBS.registerMBean(whatsit, name);
+ MBeanInfo mbi = plainMBS.getMBeanInfo(name);
+ Locale french = new Locale("fr");
+ mbi = mbi.localizeDescriptions(french, whatsit.getClass().getClassLoader());
+ checkDescriptions(mbi, frenchDescriptions);
+
+ if (failure == null)
+ System.out.println("TEST PASSED");
+ else
+ throw new Exception("TEST FAILED: Last failure: " + failure);
+ }
+
+ private static void test(MBeanServer mbs, ObjectName name, String locale,
+ String[] expectedDescriptions)
+ throws Exception {
+ if (locale != null)
+ mbs = ClientContext.withLocale(mbs, new Locale(locale));
+ MBeanInfo mbi = mbs.getMBeanInfo(name);
+ checkDescriptions(mbi, expectedDescriptions);
+ }
+
+ private static void checkDescriptions(MBeanInfo mbi,
+ String[] expectedDescriptions) {
+ assertEquals("MBean description",
+ expectedDescriptions[MBEAN], mbi.getDescription());
+ MBeanAttributeInfo mbai = mbi.getAttributes()[0];
+ assertEquals("Attribute description",
+ expectedDescriptions[ATTR], mbai.getDescription());
+ MBeanOperationInfo mboi = mbi.getOperations()[0];
+ assertEquals("Operation description",
+ expectedDescriptions[OPER], mboi.getDescription());
+ MBeanParameterInfo mbpi = mboi.getSignature()[0];
+ assertEquals("Parameter description",
+ expectedDescriptions[PARAM], mbpi.getDescription());
+ MBeanConstructorInfo[] mbcis = mbi.getConstructors();
+ assertEquals("Number of constructors", 2, mbcis.length);
+ for (MBeanConstructorInfo mbci : mbcis) {
+ MBeanParameterInfo[] mbcpis = mbci.getSignature();
+ String constrName = mbcpis.length + "-arg constructor";
+ assertEquals(constrName + " description",
+ expectedDescriptions[CONSTR], mbci.getDescription());
+ if (mbcpis.length > 0) {
+ assertEquals(constrName + " parameter description",
+ expectedDescriptions[CONSTR_PARAM],
+ mbcpis[0].getDescription());
+ }
+ }
+ }
+
+ private static void assertEquals(String what, Object expect, Object actual) {
+ if (expect.equals(actual))
+ System.out.println("...OK: " + what + " = " + expect);
+ else
+ fail(what + " should be " + expect + ", was " + actual);
+ }
+
+ private static void fail(String why) {
+ System.out.println("FAIL: " + why);
+ failure = why;
+ }
+}
diff --git a/jdk/test/javax/management/context/RemoteContextTest.java b/jdk/test/javax/management/context/RemoteContextTest.java
new file mode 100644
index 0000000..56c7eab
--- /dev/null
+++ b/jdk/test/javax/management/context/RemoteContextTest.java
@@ -0,0 +1,496 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test RemoteContextTest.java
+ * @bug 5072267
+ * @summary Test client contexts with namespaces.
+ * @author Eamonn McManus, Daniel Fuchs
+ */
+
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.URLEncoder;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.ClientContext;
+import javax.management.DynamicMBean;
+import javax.management.JMX;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerDelegate;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.StandardMBean;
+import javax.management.loading.MLet;
+import javax.management.namespace.JMXNamespaces;
+import javax.management.namespace.JMXRemoteNamespace;
+import javax.management.namespace.JMXNamespace;
+
+import static java.util.Collections.singletonMap;
+import javax.management.MBeanServerFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+public class RemoteContextTest {
+ private static String failure;
+
+ public static interface ShowContextMBean {
+ public Map<String, String> getContext();
+ public Map<String, String> getCreationContext();
+ public Set<String> getCalledOps();
+ public String getThing();
+ public void setThing(String x);
+ public int add(int x, int y);
+ }
+
+ public static class ShowContext
+ extends NotificationBroadcasterSupport
+ implements ShowContextMBean, MBeanRegistration {
+ private final Map<String, String> creationContext;
+ private final Set<String> calledOps = new HashSet<String>();
+
+ public ShowContext() {
+ creationContext = getContext();
+ }
+
+ public Map<String, String> getContext() {
+ return ClientContext.getContext();
+ }
+
+ public Map<String, String> getCreationContext() {
+ return creationContext;
+ }
+
+ public Set<String> getCalledOps() {
+ return calledOps;
+ }
+
+ public String getThing() {
+ return "x";
+ }
+
+ public void setThing(String x) {
+ }
+
+ public int add(int x, int y) {
+ return x + y;
+ }
+
+ public ObjectName preRegister(MBeanServer server, ObjectName name) {
+ assertEquals(creationContext, getContext());
+ calledOps.add("preRegister");
+ return name;
+ }
+
+ public void postRegister(Boolean registrationDone) {
+ assertEquals(creationContext, getContext());
+ calledOps.add("postRegister");
+ }
+
+ // The condition checked here is not guaranteed universally true,
+ // but is true every time we unregister an instance of this MBean
+ // in this test.
+ public void preDeregister() throws Exception {
+ assertEquals(creationContext, getContext());
+ }
+
+ public void postDeregister() {
+ assertEquals(creationContext, getContext());
+ }
+
+ // Same remark as for preDeregister
+ @Override
+ public MBeanNotificationInfo[] getNotificationInfo() {
+ calledOps.add("getNotificationInfo");
+ return super.getNotificationInfo();
+ }
+
+ @Override
+ public void addNotificationListener(
+ NotificationListener listener, NotificationFilter filter, Object handback) {
+ calledOps.add("addNotificationListener");
+ super.addNotificationListener(listener, filter, handback);
+ }
+
+ @Override
+ public void removeNotificationListener(
+ NotificationListener listener)
+ throws ListenerNotFoundException {
+ calledOps.add("removeNL1");
+ super.removeNotificationListener(listener);
+ }
+
+ @Override
+ public void removeNotificationListener(
+ NotificationListener listener, NotificationFilter filter, Object handback)
+ throws ListenerNotFoundException {
+ calledOps.add("removeNL3");
+ super.removeNotificationListener(listener, filter, handback);
+ }
+ }
+
+ private static class LogRecord {
+ final String op;
+ final Object[] params;
+ final Map<String, String> context;
+ LogRecord(String op, Object[] params, Map<String, String> context) {
+ this.op = op;
+ this.params = params;
+ this.context = context;
+ }
+
+ @Override
+ public String toString() {
+ return op + Arrays.deepToString(params) + " " + context;
+ }
+ }
+
+ private static class LogIH implements InvocationHandler {
+ private final Object wrapped;
+ Queue<LogRecord> log = new LinkedList<LogRecord>();
+
+ LogIH(Object wrapped) {
+ this.wrapped = wrapped;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ if (method.getDeclaringClass() != Object.class) {
+ LogRecord lr =
+ new LogRecord(
+ method.getName(), args, ClientContext.getContext());
+ log.add(lr);
+ }
+ try {
+ return method.invoke(wrapped, args);
+ } catch (InvocationTargetException e) {
+ throw e.getCause();
+ }
+ }
+ }
+
+ private static <T> T newSnoop(Class<T> wrappedClass, LogIH logIH) {
+ return wrappedClass.cast(Proxy.newProxyInstance(
+ wrappedClass.getClassLoader(),
+ new Class<?>[] {wrappedClass},
+ logIH));
+ }
+
+ public static void main(String[] args) throws Exception {
+ final String subnamespace = "sub";
+ final ObjectName locname = new ObjectName("a:b=c");
+ final ObjectName name = JMXNamespaces.insertPath(subnamespace,locname);
+ final MBeanServer mbs = ClientContext.newContextForwarder(
+ ManagementFactory.getPlatformMBeanServer(), null);
+ final MBeanServer sub = ClientContext.newContextForwarder(
+ MBeanServerFactory.newMBeanServer(), null);
+ final JMXServiceURL anonym = new JMXServiceURL("rmi",null,0);
+ final Map<String, Object> env = Collections.emptyMap();
+ final Map<String, String> emptyContext = Collections.emptyMap();
+ final JMXConnectorServer srv =
+ JMXConnectorServerFactory.newJMXConnectorServer(anonym,env,sub);
+ sub.registerMBean(new ShowContext(), locname);
+
+ srv.start();
+
+ try {
+ JMXRemoteNamespace subns = JMXRemoteNamespace.
+ newJMXRemoteNamespace(srv.getAddress(),null);
+ mbs.registerMBean(subns, JMXNamespaces.getNamespaceObjectName("sub"));
+ mbs.invoke(JMXNamespaces.getNamespaceObjectName("sub"),
+ "connect", null,null);
+ final ShowContextMBean show =
+ JMX.newMBeanProxy(mbs, name, ShowContextMBean.class);
+
+ assertEquals(emptyContext, show.getContext());
+ ClientContext.doWithContext(singletonMap("foo", "bar"), new Callable<Void>() {
+ public Void call() {
+ assertEquals(singletonMap("foo", "bar"), show.getContext());
+ return null;
+ }
+ });
+ assertEquals(emptyContext, show.getContext());
+ String got = ClientContext.doWithContext(
+ singletonMap("foo", "baz"), new Callable<String>() {
+ public String call() {
+ return ClientContext.getContext().get("foo");
+ }
+ });
+ assertEquals("baz", got);
+
+ Map<String, String> combined = ClientContext.doWithContext(
+ singletonMap("foo", "baz"), new Callable<Map<String, String>>() {
+ public Map<String, String> call() throws Exception {
+ return ClientContext.doWithContext(
+ singletonMap("fred", "jim"),
+ new Callable<Map<String, String>>() {
+ public Map<String, String> call() {
+ return ClientContext.getContext();
+ }
+ });
+ }
+ });
+ assertEquals(singletonMap("fred", "jim"), combined);
+
+ final String ugh = "a!?//*=:\"% ";
+ ClientContext.doWithContext(singletonMap(ugh, ugh), new Callable<Void>() {
+ public Void call() {
+ assertEquals(Collections.singletonMap(ugh, ugh),
+ ClientContext.getContext());
+ return null;
+ }
+ });
+
+ // Basic withContext tests
+
+ LogIH mbsIH = new LogIH(mbs);
+ MBeanServer snoopMBS = newSnoop(MBeanServer.class, mbsIH);
+ MBeanServer ughMBS = ClientContext.withContext(snoopMBS, ugh, ugh);
+ // ughMBS is never referenced but we check that the withContext call
+ // included a call to snoopMBS.isRegistered.
+ String encodedUgh = URLEncoder.encode(ugh, "UTF-8").replace("*", "%2A");
+ ObjectName expectedName = new ObjectName(
+ ClientContext.NAMESPACE + ObjectName.NAMESPACE_SEPARATOR +
+ encodedUgh + "=" + encodedUgh +
+ ObjectName.NAMESPACE_SEPARATOR + ":" +
+ JMXNamespace.TYPE_ASSIGNMENT);
+ assertCalled(mbsIH, "isRegistered", new Object[] {expectedName},
+ emptyContext);
+
+ // Test withDynamicContext
+
+ MBeanServerConnection dynamicSnoop =
+ ClientContext.withDynamicContext(snoopMBS);
+ assertCalled(mbsIH, "isRegistered",
+ new Object[] {
+ JMXNamespaces.getNamespaceObjectName(ClientContext.NAMESPACE)
+ },
+ emptyContext);
+ final ShowContextMBean dynamicShow =
+ JMX.newMBeanProxy(dynamicSnoop, name, ShowContextMBean.class);
+ assertEquals(Collections.emptyMap(), dynamicShow.getContext());
+ assertCalled(mbsIH, "getAttribute", new Object[] {name, "Context"},
+ emptyContext);
+
+ Map<String, String> expectedDynamic =
+ Collections.singletonMap("gladstone", "gander");
+ Map<String, String> dynamic = ClientContext.doWithContext(
+ expectedDynamic,
+ new Callable<Map<String, String>>() {
+ public Map<String, String> call() throws Exception {
+ return dynamicShow.getContext();
+ }
+ });
+ assertEquals(expectedDynamic, dynamic);
+ ObjectName expectedDynamicName = new ObjectName(
+ ClientContext.encode(expectedDynamic) +
+ ObjectName.NAMESPACE_SEPARATOR + name);
+ assertCalled(mbsIH, "getAttribute",
+ new Object[] {expectedDynamicName, "Context"}, dynamic);
+
+ MBeanServer cmbs = ClientContext.withContext(
+ mbs, "mickey", "mouse");
+ ShowContextMBean cshow =
+ JMX.newMBeanProxy(cmbs, name, ShowContextMBean.class);
+ assertEquals(Collections.singletonMap("mickey", "mouse"), cshow.getContext());
+
+ MBeanServer ccmbs = ClientContext.withContext(
+ cmbs, "donald", "duck");
+ ShowContextMBean ccshow =
+ JMX.newMBeanProxy(ccmbs, name, ShowContextMBean.class);
+ Map<String, String> disney = new HashMap<String, String>();
+ disney.put("mickey", "mouse");
+ disney.put("donald", "duck");
+ assertEquals(disney, ccshow.getContext());
+
+ // Test that all MBS ops produce reasonable results
+
+ ObjectName logger = new ObjectName("a:type=Logger");
+ DynamicMBean showMBean =
+ new StandardMBean(new ShowContext(), ShowContextMBean.class);
+ LogIH mbeanLogIH = new LogIH(showMBean);
+ DynamicMBean logMBean = newSnoop(DynamicMBean.class, mbeanLogIH);
+ ObjectInstance loggerOI = ccmbs.registerMBean(logMBean, logger);
+ assertEquals(logger, loggerOI.getObjectName());
+
+ // We get a getMBeanInfo call to determine the className in the
+ // ObjectInstance to return from registerMBean.
+ assertCalled(mbeanLogIH, "getMBeanInfo", disney);
+
+ ccmbs.getAttribute(logger, "Thing");
+ assertCalled(mbeanLogIH, "getAttribute", disney);
+
+ ccmbs.getAttributes(logger, new String[] {"Thing", "Context"});
+ assertCalled(mbeanLogIH, "getAttributes", disney);
+
+ ccmbs.setAttribute(logger, new Attribute("Thing", "bar"));
+ assertCalled(mbeanLogIH, "setAttribute", disney);
+
+ ccmbs.setAttributes(logger, new AttributeList(
+ Arrays.asList(new Attribute("Thing", "baz"))));
+ assertCalled(mbeanLogIH, "setAttributes", disney);
+
+ ccmbs.getMBeanInfo(logger);
+ assertCalled(mbeanLogIH, "getMBeanInfo", disney);
+
+ Set<ObjectName> names = ccmbs.queryNames(null, null);
+ Set<ObjectName> expectedNames = new HashSet<ObjectName>(
+ Collections.singleton(MBeanServerDelegate.DELEGATE_NAME));
+ expectedNames.removeAll(names);
+ assertEquals(0, expectedNames.size());
+
+ Set<ObjectName> nsNames =
+ ccmbs.queryNames(new ObjectName("**?*?//:*"), null);
+ Set<ObjectName> expectedNsNames = new HashSet<ObjectName>(
+ Arrays.asList(
+ new ObjectName(ClientContext.NAMESPACE +
+ ObjectName.NAMESPACE_SEPARATOR + ":" +
+ JMXNamespace.TYPE_ASSIGNMENT)));
+ expectedNsNames.removeAll(nsNames);
+ assertEquals(0, expectedNsNames.size());
+
+ Set<ObjectInstance> insts = ccmbs.queryMBeans(
+ MBeanServerDelegate.DELEGATE_NAME, null);
+ assertEquals(1, insts.size());
+ assertEquals(MBeanServerDelegate.DELEGATE_NAME,
+ insts.iterator().next().getObjectName());
+
+ ObjectName createdName = new ObjectName("a:type=Created");
+ ObjectInstance createdOI =
+ ccmbs.createMBean(ShowContext.class.getName(), createdName);
+ assertEquals(ShowContext.class.getName(), createdOI.getClassName());
+ assertEquals(createdName, createdOI.getObjectName());
+ assertEquals(disney, ccmbs.getAttribute(createdName, "CreationContext"));
+
+ NotificationListener nothingListener = new NotificationListener() {
+ public void handleNotification(Notification n, Object h) {}
+ };
+ ccmbs.addNotificationListener(createdName, nothingListener, null, null);
+ ccmbs.removeNotificationListener(createdName, nothingListener, null, null);
+ ccmbs.addNotificationListener(createdName, nothingListener, null, null);
+ ccmbs.removeNotificationListener(createdName, nothingListener);
+ Set<String> expectedOps = new HashSet<String>(Arrays.asList(
+ "preRegister", "postRegister", "addNotificationListener",
+ "removeNL1", "removeNL3", "getNotificationInfo"));
+ assertEquals(expectedOps, ccmbs.getAttribute(createdName, "CalledOps"));
+
+ assertEquals(ShowContext.class.getClassLoader(),
+ ccmbs.getClassLoaderFor(createdName));
+
+ assertEquals(true, ccmbs.isRegistered(createdName));
+ assertEquals(true, ccmbs.isInstanceOf(createdName,
+ ShowContext.class.getName()));
+ assertEquals(false, ccmbs.isInstanceOf(createdName,
+ DynamicMBean.class.getName()));
+ ccmbs.unregisterMBean(createdName);
+ assertEquals(false, ccmbs.isRegistered(createdName));
+
+ MLet mlet = new MLet();
+ ObjectName defaultMLetName = new ObjectName("DefaultDomain:type=MLet");
+
+ ccmbs.registerMBean(mlet, defaultMLetName);
+
+ assertEquals(mlet, ccmbs.getClassLoader(defaultMLetName));
+
+ assertEquals(0, mbeanLogIH.log.size());
+
+ // Test that contexts still work when we can't combine two encoded contexts.
+ // Here, we wrap cmbs (mickey=mouse) so that ccmbs2 (donald=duck) cannot
+ // see that it already contains a context and therefore cannot combine
+ // into mickey=mouse;donald=duck. We don't actually use the snoop
+ // capabilities of the returned object -- we just want an opaque
+ // MBeanServer wrapper
+ MBeanServer cmbs2 = newSnoop(MBeanServer.class, new LogIH(cmbs));
+ MBeanServer ccmbs2 = ClientContext.withContext(cmbs2, "donald", "duck");
+ assertEquals(disney, ccmbs2.getAttribute(name, "Context"));
+
+ // ADD NEW TESTS HERE ^^^
+
+ if (failure != null)
+ throw new Exception(failure);
+ } finally {
+ srv.stop();
+ }
+ }
+
+ private static void assertEquals(Object x, Object y) {
+ if (!equal(x, y))
+ failed("expected " + string(x) + "; got " + string(y));
+ }
+
+ private static boolean equal(Object x, Object y) {
+ if (x == y)
+ return true;
+ if (x == null || y == null)
+ return false;
+ if (x.getClass().isArray())
+ return Arrays.deepEquals(new Object[] {x}, new Object[] {y});
+ return x.equals(y);
+ }
+
+ private static String string(Object x) {
+ String s = Arrays.deepToString(new Object[] {x});
+ return s.substring(1, s.length() - 1);
+ }
+
+ private static void assertCalled(
+ LogIH logIH, String op, Map<String, String> expectedContext) {
+ assertCalled(logIH, op, null, expectedContext);
+ }
+
+ private static void assertCalled(
+ LogIH logIH, String op, Object[] params,
+ Map<String, String> expectedContext) {
+ LogRecord lr = logIH.log.remove();
+ assertEquals(op, lr.op);
+ if (params != null)
+ assertEquals(params, lr.params);
+ assertEquals(expectedContext, lr.context);
+ }
+
+ private static void failed(String why) {
+ failure = why;
+ new Throwable("FAILED: " + why).printStackTrace(System.out);
+ }
+}
diff --git a/jdk/test/javax/management/context/localizable/MBeanDescriptions.properties b/jdk/test/javax/management/context/localizable/MBeanDescriptions.properties
new file mode 100644
index 0000000..4722c5b
--- /dev/null
+++ b/jdk/test/javax/management/context/localizable/MBeanDescriptions.properties
@@ -0,0 +1,9 @@
+# This is the default description ResourceBundle for MBeans in this package.
+# Resources here override the descriptions specified with @Description
+# but only when localization is happening and when there is not a more
+# specific resource for the description (for example from MBeanDescriptions_fr).
+
+WhatsitMBean.mbean = A whatsit
+# This must be the same as WhatsitMBean.englishMBeanDescription for the
+# purposes of this test.
+
diff --git a/jdk/test/javax/management/context/localizable/MBeanDescriptions_fr.java b/jdk/test/javax/management/context/localizable/MBeanDescriptions_fr.java
new file mode 100644
index 0000000..9e9cfa2
--- /dev/null
+++ b/jdk/test/javax/management/context/localizable/MBeanDescriptions_fr.java
@@ -0,0 +1,42 @@
+/*
+ * 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 localizable;
+
+import java.util.ListResourceBundle;
+import static localizable.WhatsitMBean.*;
+
+public class MBeanDescriptions_fr extends ListResourceBundle {
+ @Override
+ protected Object[][] getContents() {
+ String constrProp = "WhatsitMBean.constructor." + Whatsit.class.getName();
+ return new Object[][] {
+ {"WhatsitMBean.mbean", frenchMBeanDescription},
+ {"WhatsitMBean.attribute.Whatsit", frenchAttrDescription},
+ {"WhatsitMBean.operation.frob", frenchOperDescription},
+ {"WhatsitMBean.operation.frob.p1", frenchParamDescription},
+ {constrProp, frenchConstrDescription},
+ {constrProp + ".p1", frenchConstrParamDescription},
+ };
+ }
+}
diff --git a/jdk/test/javax/management/context/localizable/Whatsit.java b/jdk/test/javax/management/context/localizable/Whatsit.java
new file mode 100644
index 0000000..f140ad9
--- /dev/null
+++ b/jdk/test/javax/management/context/localizable/Whatsit.java
@@ -0,0 +1,59 @@
+/*
+ * 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 localizable;
+
+import javax.management.Description;
+
+public class Whatsit implements WhatsitMBean {
+ /**
+ * Attribute : NewAttribute0
+ */
+ private String newAttribute0;
+ @Description(englishConstrDescription)
+ public Whatsit() {}
+
+ @Description(englishConstrDescription)
+ public Whatsit(@Description(englishConstrParamDescription) int type) {}
+
+ public String getWhatsit() {
+ return "whatsit";
+ }
+
+ public void frob(String whatsit) {
+ }
+
+ /**
+ * Get Tiddly
+ */
+ public String getNewAttribute0() {
+ return newAttribute0;
+ }
+
+ /**
+ * Set Tiddly
+ */
+ public void setNewAttribute0(String value) {
+ newAttribute0 = value;
+ }
+}
diff --git a/jdk/test/javax/management/context/localizable/WhatsitMBean.java b/jdk/test/javax/management/context/localizable/WhatsitMBean.java
new file mode 100644
index 0000000..5bebc52
--- /dev/null
+++ b/jdk/test/javax/management/context/localizable/WhatsitMBean.java
@@ -0,0 +1,53 @@
+/*
+ * 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 localizable;
+
+import javax.management.Description;
+
+@Description(WhatsitMBean.defaultMBeanDescription)
+public interface WhatsitMBean {
+ public static final String
+ defaultMBeanDescription = "Default whatsit MBean description",
+ englishMBeanDescription = "A whatsit",
+ // Previous description appears in MBeanDescriptions.properties
+ // so it overrides the @Description when that file is used.
+ frenchMBeanDescription = "Un bidule",
+ englishAttrDescription = "The whatsit",
+ frenchAttrDescription = "Le bidule",
+ englishOperDescription = "Frob the whatsit",
+ frenchOperDescription = "Frober le bidule",
+ englishParamDescription = "The whatsit to frob",
+ frenchParamDescription = "Le bidule \u00e0 frober",
+ englishConstrDescription = "Make a whatsit",
+ frenchConstrDescription = "Fabriquer un bidule",
+ englishConstrParamDescription = "Type of whatsit to make",
+ frenchConstrParamDescription = "Type de bidule \u00e0 fabriquer",
+ unlocalizedMBeanDescription = "Unlocalized MBean";
+
+ @Description(englishAttrDescription)
+ public String getWhatsit();
+
+ @Description(englishOperDescription)
+ public void frob(@Description(englishParamDescription) String whatsit);
+}
diff --git a/jdk/test/javax/management/eventService/CustomForwarderTest.java b/jdk/test/javax/management/eventService/CustomForwarderTest.java
index c9c866a..4d7e302 100644
--- a/jdk/test/javax/management/eventService/CustomForwarderTest.java
+++ b/jdk/test/javax/management/eventService/CustomForwarderTest.java
@@ -200,8 +200,7 @@
public static void main(String[] args) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- MBeanServerForwarder mbsf = EventClientDelegate.newForwarder();
- mbsf.setMBeanServer(mbs);
+ MBeanServerForwarder mbsf = EventClientDelegate.newForwarder(mbs, null);
mbs = mbsf;
// for 1.5
diff --git a/jdk/test/javax/management/eventService/EventClientExecutorTest.java b/jdk/test/javax/management/eventService/EventClientExecutorTest.java
index 19d6afd..5201335 100644
--- a/jdk/test/javax/management/eventService/EventClientExecutorTest.java
+++ b/jdk/test/javax/management/eventService/EventClientExecutorTest.java
@@ -65,8 +65,7 @@
new NamedThreadFactory("LEASE"));
MBeanServer mbs = MBeanServerFactory.newMBeanServer();
- MBeanServerForwarder mbsf = EventClientDelegate.newForwarder();
- mbsf.setMBeanServer(mbs);
+ MBeanServerForwarder mbsf = EventClientDelegate.newForwarder(mbs, null);
mbs = mbsf;
EventClientDelegateMBean ecd = EventClientDelegate.getProxy(mbs);
diff --git a/jdk/test/javax/management/eventService/EventManagerTest.java b/jdk/test/javax/management/eventService/EventManagerTest.java
index 2717c0e..66e4e36 100644
--- a/jdk/test/javax/management/eventService/EventManagerTest.java
+++ b/jdk/test/javax/management/eventService/EventManagerTest.java
@@ -98,7 +98,7 @@
succeed &= test(new EventClient(ecd,
new RMIPushEventRelay(ecd),
null, null,
- EventClient.DEFAULT_LEASE_TIMEOUT));
+ EventClient.DEFAULT_REQUESTED_LEASE_TIME));
conn.close();
server.stop();
diff --git a/jdk/test/javax/management/eventService/ListenerTest.java b/jdk/test/javax/management/eventService/ListenerTest.java
index 7195736..c4c9113 100644
--- a/jdk/test/javax/management/eventService/ListenerTest.java
+++ b/jdk/test/javax/management/eventService/ListenerTest.java
@@ -99,7 +99,7 @@
succeed &= test(new EventClient(ecd,
new RMIPushEventRelay(ecd),
null, null,
- EventClient.DEFAULT_LEASE_TIMEOUT));
+ EventClient.DEFAULT_REQUESTED_LEASE_TIME));
conn.close();
server.stop();
diff --git a/jdk/test/javax/management/eventService/NotSerializableNotifTest.java b/jdk/test/javax/management/eventService/NotSerializableNotifTest.java
index 0bf0bc5..4185b4d 100644
--- a/jdk/test/javax/management/eventService/NotSerializableNotifTest.java
+++ b/jdk/test/javax/management/eventService/NotSerializableNotifTest.java
@@ -95,7 +95,7 @@
FetchingEventRelay.DEFAULT_MAX_NOTIFICATIONS,
null);
EventClient ec = new EventClient(ecd, eventRelay, null, null,
- EventClient.DEFAULT_LEASE_TIMEOUT);
+ EventClient.DEFAULT_REQUESTED_LEASE_TIME);
// add listener from the client side
Listener listener = new Listener();
diff --git a/jdk/test/javax/management/eventService/UsingEventService.java b/jdk/test/javax/management/eventService/UsingEventService.java
index 3d768ed..b46ffe3 100644
--- a/jdk/test/javax/management/eventService/UsingEventService.java
+++ b/jdk/test/javax/management/eventService/UsingEventService.java
@@ -1,4 +1,27 @@
/*
+ * 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 UsingEventService.java 1.10 08/01/22
* @bug 5108776
* @summary Basic test for EventManager.
diff --git a/jdk/test/javax/management/monitor/DerivedGaugeMonitorTest.java b/jdk/test/javax/management/monitor/DerivedGaugeMonitorTest.java
new file mode 100644
index 0000000..dca66e0
--- /dev/null
+++ b/jdk/test/javax/management/monitor/DerivedGaugeMonitorTest.java
@@ -0,0 +1,270 @@
+/*
+ * 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 6683213
+ * @summary Test that the initial derived gauge is (Integer)0
+ * @author Daniel Fuchs
+ * @run clean DerivedGaugeMonitorTest
+ * @run build DerivedGaugeMonitorTest
+ * @run main DerivedGaugeMonitorTest
+ */
+
+import java.io.Serializable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+import javax.management.monitor.CounterMonitor;
+import javax.management.monitor.GaugeMonitor;
+
+public class DerivedGaugeMonitorTest {
+
+ public static interface Things {
+ public long getALong();
+ public int getAnInt();
+ public double getADouble();
+ public short getAShort();
+ public byte getAByte();
+ public float getAFloat();
+ }
+ public static interface MyMBean extends Things {
+ public Things getAThing();
+ }
+
+ public static class MyThings implements Things, Serializable {
+ private static final long serialVersionUID = -4333982919572564126L;
+
+ private volatile long along = 0;
+ private volatile int anint = 0;
+ private volatile short ashort = 0;
+ private volatile byte abyte = 0;
+ private volatile float afloat = 0;
+ private volatile double adouble = 0;
+
+ private volatile transient boolean mutable;
+
+ public MyThings() {
+ this(false);
+ }
+
+ protected MyThings(boolean mutable) {
+ this.mutable=mutable;
+ }
+
+ public long getALong() {
+ return mutable?along++:along;
+ }
+
+ public int getAnInt() {
+ return mutable?anint++:anint;
+ }
+
+ public double getADouble() {
+ return mutable?adouble++:adouble;
+ }
+
+ public short getAShort() {
+ return mutable?ashort++:ashort;
+ }
+
+ public byte getAByte() {
+ return mutable?abyte++:abyte;
+ }
+
+ public float getAFloat() {
+ return mutable?afloat++:afloat;
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ final MyThings other = (MyThings)super.clone();
+ other.mutable=false;
+ return other;
+ }
+ }
+
+ public static class My implements MyMBean {
+
+ public final CountDownLatch cdl = new CountDownLatch(6);
+
+ private final MyThings things = new MyThings(true);
+ private volatile int count = 0;
+
+ public Things getAThing() {
+ count++;
+ cdl.countDown();
+ try {
+ return (Things) things.clone();
+ } catch (CloneNotSupportedException ex) {
+ return null;
+ }
+ }
+
+ public long getALong() {
+ count++;
+ cdl.countDown();
+ return things.getALong();
+ }
+
+ public int getAnInt() {
+ count++;
+ cdl.countDown();
+ return things.getAnInt();
+ }
+
+ public double getADouble() {
+ count++;
+ cdl.countDown();
+ return things.getADouble();
+ }
+
+ public short getAShort() {
+ count++;
+ cdl.countDown();
+ return things.getAShort();
+ }
+
+ public byte getAByte() {
+ count++;
+ cdl.countDown();
+ return things.getAByte();
+ }
+
+ public float getAFloat() {
+ count++;
+ cdl.countDown();
+ return things.getAFloat();
+ }
+
+ }
+
+
+ public static String[] attributes = {
+ "AByte","AShort","AnInt","ALong","AFloat","ADouble"
+ };
+ public static String[] things = {
+ "AThing.AByte","AThing.AShort","AThing.AnInt","AThing.ALong",
+ "AThing.AFloat","AThing.ADouble"
+ };
+
+ public static void check(String attr, MBeanServer server, ObjectName mon,
+ ObjectName mbean) throws Exception {
+ final Object obj = server.getAttribute(mon, "DerivedGauge");
+ check(attr,server,mon,mbean,obj);
+ }
+
+ public static void check(String attr, MBeanServer server, ObjectName mon,
+ ObjectName mbean, Object obj) throws Exception {
+ if (obj == null)
+ throw new Exception("Derived gauge for: " + attr +
+ " ["+mon+", "+mbean+"] is null!");
+ if (!Integer.valueOf(0).equals(obj))
+ throw new Exception("Derived gauge for: " + attr +
+ " ["+mon+", "+mbean+"] is "+obj);
+ }
+
+ public static void check(String attr, MBeanServer server, ObjectName mon,
+ ObjectName mbean, long start) throws Exception {
+ final Object obj = server.getAttribute(mon, "DerivedGauge");
+ final long now = System.currentTimeMillis();
+ final long gran = (Long)server.getAttribute(mon, "GranularityPeriod");
+ if (now > start +2*gran) {
+ throw new Exception(attr+": Can't verify test case: " +
+ "granularity period expired!");
+ }
+ check(attr,server,mon,mbean,obj);
+ }
+
+ public static void test(String attr) throws Exception {
+ System.err.println("Testing "+ attr);
+ final MBeanServer server = MBeanServerFactory.createMBeanServer();
+ final ObjectName mbean = new ObjectName("ugly:type=cr.p");
+ final My my = new My();
+ final GaugeMonitor mon2 = new GaugeMonitor();
+ final ObjectName mon2n = new ObjectName("mon1:type=GaugeMonitor");
+ final CounterMonitor mon1 = new CounterMonitor();
+ final ObjectName mon1n = new ObjectName("mon2:type=CounterMonitor");
+
+ server.registerMBean(my, mbean);
+ server.registerMBean(mon1, mon1n);
+ server.registerMBean(mon2, mon2n);
+
+ mon1.addObservedObject(mbean);
+ mon1.setGranularityPeriod(60000); // 60 sec...
+ mon1.setObservedAttribute(attr);
+ mon1.setDifferenceMode(true);
+ check(attr,server,mon1n,mbean);
+
+ mon2.addObservedObject(mbean);
+ mon2.setGranularityPeriod(60000); // 60 sec...
+ mon2.setObservedAttribute(attr);
+ mon2.setDifferenceMode(true);
+ check(attr,server,mon2n,mbean);
+
+ final long approxStart = System.currentTimeMillis();
+ mon1.start();
+ mon2.start();
+
+ try {
+ check(attr,server,mon1n,mbean,approxStart);
+ check(attr,server,mon2n,mbean,approxStart);
+ check(attr,server,mon1n,mbean,approxStart);
+ check(attr,server,mon2n,mbean,approxStart);
+
+
+ mon1.setGranularityPeriod(5);
+ mon2.setGranularityPeriod(5);
+
+ my.cdl.await(1000, TimeUnit.MILLISECONDS);
+ if (my.cdl.getCount() > 0)
+ throw new Exception(attr+": Count down not reached!");
+
+ // just check that we don't get an exception now...
+ System.err.println(attr+": [" + mon1n+
+ "] DerivedGauge is now "+
+ server.getAttribute(mon1n, "DerivedGauge"));
+ System.err.println(attr+": [" + mon2n+
+ "] DerivedGauge is now "+
+ server.getAttribute(mon2n, "DerivedGauge"));
+ } finally {
+ try {mon1.stop();} catch (Exception x) {}
+ try {mon2.stop();} catch (Exception x) {}
+ }
+ }
+
+
+
+
+ public static void main(String[] args) throws Exception {
+ for (String attr:attributes) {
+ test(attr);
+ }
+ for (String attr:things) {
+ test(attr);
+ }
+ }
+
+}
diff --git a/jdk/test/javax/management/namespace/EventWithNamespaceControlTest.java b/jdk/test/javax/management/namespace/EventWithNamespaceControlTest.java
index 1e39011..9bfa986 100644
--- a/jdk/test/javax/management/namespace/EventWithNamespaceControlTest.java
+++ b/jdk/test/javax/management/namespace/EventWithNamespaceControlTest.java
@@ -85,6 +85,7 @@
}
}
+ @Override
public Map<String, ?> getServerMap() {
Map<String, ?> retValue = Collections.emptyMap();
return retValue;
diff --git a/jdk/test/javax/management/namespace/JMXNamespaceSecurityTest.java b/jdk/test/javax/management/namespace/JMXNamespaceSecurityTest.java
index 213ffbf..ec201db 100644
--- a/jdk/test/javax/management/namespace/JMXNamespaceSecurityTest.java
+++ b/jdk/test/javax/management/namespace/JMXNamespaceSecurityTest.java
@@ -51,6 +51,7 @@
import javax.management.namespace.JMXNamespace;
import javax.management.namespace.JMXNamespaces;
import javax.management.remote.JMXConnectorServer;
+import javax.management.ClientContext;
/**
*
diff --git a/jdk/test/javax/management/namespace/JMXNamespaceViewTest.java b/jdk/test/javax/management/namespace/JMXNamespaceViewTest.java
index e134968..4764f53 100644
--- a/jdk/test/javax/management/namespace/JMXNamespaceViewTest.java
+++ b/jdk/test/javax/management/namespace/JMXNamespaceViewTest.java
@@ -42,6 +42,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import javax.management.ClientContext;
import javax.management.JMException;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
@@ -62,11 +63,6 @@
*/
public class JMXNamespaceViewTest {
- // TODO: Remove this when contexts are added.
- public static class ClientContext {
- public final static String NAMESPACE = "jmx.context";
- }
-
/**
* Describe the configuration of a namespace
*/
diff --git a/jdk/test/javax/management/namespace/JMXRemoteTargetNamespace.java b/jdk/test/javax/management/namespace/JMXRemoteTargetNamespace.java
index 3d83844..633e930 100644
--- a/jdk/test/javax/management/namespace/JMXRemoteTargetNamespace.java
+++ b/jdk/test/javax/management/namespace/JMXRemoteTargetNamespace.java
@@ -68,13 +68,7 @@
public JMXRemoteTargetNamespace(JMXServiceURL sourceURL,
Map<String,?> optionsMap, String sourceNamespace) {
- this(sourceURL,optionsMap,sourceNamespace,false);
- }
-
- public JMXRemoteTargetNamespace(JMXServiceURL sourceURL,
- Map<String,?> optionsMap, String sourceNamespace,
- boolean createEventClient) {
- super(sourceURL,optionsMap);
+ super(sourceURL, optionsMap);
this.sourceNamespace = sourceNamespace;
this.createEventClient = createEventClient(optionsMap);
}
@@ -92,14 +86,14 @@
}
@Override
- protected JMXConnector newJMXConnector(JMXServiceURL url,
- Map<String, ?> env) throws IOException {
- JMXConnector sup = super.newJMXConnector(url, env);
- if (sourceNamespace == null || "".equals(sourceNamespace))
- return sup;
+ protected MBeanServerConnection getMBeanServerConnection(JMXConnector jmxc)
+ throws IOException {
+ MBeanServerConnection mbsc = super.getMBeanServerConnection(jmxc);
+ if (sourceNamespace != null && sourceNamespace.length() > 0)
+ mbsc = JMXNamespaces.narrowToNamespace(mbsc, sourceNamespace);
if (createEventClient)
- sup = EventClient.withEventClient(sup);
- return JMXNamespaces.narrowToNamespace(sup, sourceNamespace);
+ mbsc = EventClient.getEventClientConnection(mbsc);
+ return mbsc;
}
diff --git a/jdk/test/javax/management/namespace/NamespaceNotificationsTest.java b/jdk/test/javax/management/namespace/NamespaceNotificationsTest.java
index 9c5a1a0..0545a36 100644
--- a/jdk/test/javax/management/namespace/NamespaceNotificationsTest.java
+++ b/jdk/test/javax/management/namespace/NamespaceNotificationsTest.java
@@ -206,18 +206,10 @@
aconn.addNotificationListener(deep,listener,null,deep);
- final JMXServiceURL urlx = new JMXServiceURL(url1.toString());
- System.out.println("conn: "+urlx);
- final JMXConnector jc2 = JMXNamespaces.narrowToNamespace(
- JMXConnectorFactory.connect(urlx),"server1//server1");
- final JMXConnector jc3 = JMXNamespaces.narrowToNamespace(jc2,"server3");
- jc3.connect();
- System.out.println("JC#3: " +
- ((jc3 instanceof JMXAddressable)?
- ((JMXAddressable)jc3).getAddress():
- jc3.toString()));
- final MBeanServerConnection bconn =
- jc3.getMBeanServerConnection();
+ MBeanServerConnection iconn =
+ JMXNamespaces.narrowToNamespace(aconn, "server1//server1");
+ MBeanServerConnection bconn =
+ JMXNamespaces.narrowToNamespace(aconn, "server3");
final ObjectName shallow =
new ObjectName("bush:"+
deep.getKeyPropertyListString());
diff --git a/jdk/test/javax/management/namespace/NullDomainObjectNameTest.java b/jdk/test/javax/management/namespace/NullDomainObjectNameTest.java
index 3251d38..6b1ad51 100644
--- a/jdk/test/javax/management/namespace/NullDomainObjectNameTest.java
+++ b/jdk/test/javax/management/namespace/NullDomainObjectNameTest.java
@@ -155,7 +155,7 @@
// namespace.
//
RoutingServerProxy proxy =
- new RoutingServerProxy(sub, "", "faked", false);
+ new RoutingServerProxy(sub, "", "faked", true);
// These should fail because the ObjectName doesn't start
// with "faked//"
diff --git a/jdk/test/javax/management/namespace/NullObjectNameTest.java b/jdk/test/javax/management/namespace/NullObjectNameTest.java
index 156e766..0e645dc 100644
--- a/jdk/test/javax/management/namespace/NullObjectNameTest.java
+++ b/jdk/test/javax/management/namespace/NullObjectNameTest.java
@@ -162,7 +162,7 @@
// this case.
//
RoutingServerProxy proxy =
- new RoutingServerProxy(sub,"","faked",false);
+ new RoutingServerProxy(sub, "", "faked", true);
final ObjectInstance moi3 =
proxy.registerMBean(new MyWombat(),null);
System.out.println(moi3.getObjectName().toString()+
diff --git a/jdk/test/javax/management/openmbean/CompositeDataStringTest.java b/jdk/test/javax/management/openmbean/CompositeDataStringTest.java
index 286bfd1..7a64e52 100644
--- a/jdk/test/javax/management/openmbean/CompositeDataStringTest.java
+++ b/jdk/test/javax/management/openmbean/CompositeDataStringTest.java
@@ -21,19 +21,19 @@
* have any questions.
*/
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-
/*
* @test
* @bug 6610174
* @summary Test that CompositeDataSupport.toString() represents arrays correctly
* @author Eamonn McManus
*/
+
import javax.management.openmbean.ArrayType;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
public class CompositeDataStringTest {
public static void main(String[] args) throws Exception {
diff --git a/jdk/test/javax/management/openmbean/CompositeDataToMapTest.java b/jdk/test/javax/management/openmbean/CompositeDataToMapTest.java
new file mode 100644
index 0000000..30641b7
--- /dev/null
+++ b/jdk/test/javax/management/openmbean/CompositeDataToMapTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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 6750472 6752563
+ * @summary Test CompositeDataSupport.toMap.
+ * @author Eamonn McManus
+ * @run main/othervm -ea CompositeDataToMapTest
+ */
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+
+public class CompositeDataToMapTest {
+ private static class IdentityInvocationHandler implements InvocationHandler {
+ private final Object wrapped;
+
+ public IdentityInvocationHandler(Object wrapped) {
+ this.wrapped = wrapped;
+ }
+
+ public Object invoke(Object proxy, Method m, Object[] args)
+ throws Throwable {
+ try {
+ return m.invoke(wrapped, args);
+ } catch (InvocationTargetException e) {
+ throw e.getCause();
+ }
+ }
+ }
+
+ private static <T> T wrap(T x, Class<T> intf) {
+ InvocationHandler ih = new IdentityInvocationHandler(x);
+ return intf.cast(Proxy.newProxyInstance(
+ intf.getClassLoader(), new Class<?>[] {intf}, ih));
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (!CompositeDataToMapTest.class.desiredAssertionStatus())
+ throw new AssertionError("Must be run with -ea");
+
+ CompositeType emptyCT = new CompositeType(
+ "empty", "empty", new String[0], new String[0], new OpenType<?>[0]);
+ CompositeData emptyCD = new CompositeDataSupport(
+ emptyCT, Collections.<String, Object>emptyMap());
+ assert CompositeDataSupport.toMap(emptyCD).isEmpty() :
+ "Empty CD produces empty Map";
+
+ CompositeData emptyCD2 = new CompositeDataSupport(
+ emptyCT, new String[0], new Object[0]);
+ assert emptyCD.equals(emptyCD2) : "Empty CD can be constructed two ways";
+
+ CompositeType namedNumberCT = new CompositeType(
+ "NamedNumber", "NamedNumber",
+ new String[] {"name", "number"},
+ new String[] {"name", "number"},
+ new OpenType<?>[] {SimpleType.STRING, SimpleType.INTEGER});
+ Map<String, Object> namedNumberMap = new HashMap<String, Object>();
+ namedNumberMap.put("name", "Deich");
+ namedNumberMap.put("number", 10);
+ CompositeData namedNumberCD = new CompositeDataSupport(
+ namedNumberCT, namedNumberMap);
+ assert CompositeDataSupport.toMap(namedNumberCD).equals(namedNumberMap) :
+ "Map survives passage through CompositeData";
+
+ namedNumberCD = wrap(namedNumberCD, CompositeData.class);
+ assert CompositeDataSupport.toMap(namedNumberCD).equals(namedNumberMap) :
+ "Map survives passage through wrapped CompositeData";
+
+ namedNumberMap = CompositeDataSupport.toMap(namedNumberCD);
+ namedNumberMap.put("name", "Ceathar");
+ namedNumberMap.put("number", 4);
+ namedNumberCD = new CompositeDataSupport(namedNumberCT, namedNumberMap);
+ assert CompositeDataSupport.toMap(namedNumberCD).equals(namedNumberMap) :
+ "Modified Map survives passage through CompositeData";
+
+ try {
+ namedNumberMap = CompositeDataSupport.toMap(null);
+ assert false : "Null toMap arg provokes exception";
+ } catch (Exception e) {
+ assert e instanceof IllegalArgumentException :
+ "Exception for null toMap arg is IllegalArgumentException";
+ }
+ }
+}
diff --git a/jdk/test/javax/management/remote/mandatory/connectorServer/ForwarderChainTest.java b/jdk/test/javax/management/remote/mandatory/connectorServer/ForwarderChainTest.java
index b6c6d87..e1dcbcb 100644
--- a/jdk/test/javax/management/remote/mandatory/connectorServer/ForwarderChainTest.java
+++ b/jdk/test/javax/management/remote/mandatory/connectorServer/ForwarderChainTest.java
@@ -86,16 +86,20 @@
test(cs, mbs);
System.out.println("===Remove any leftover forwarders===");
- while (cs.getSystemMBeanServer() instanceof MBeanServerForwarder) {
- MBeanServerForwarder mbsf =
- (MBeanServerForwarder) cs.getSystemMBeanServer();
- cs.removeMBeanServerForwarder(mbsf);
+ MBeanServerForwarder systemMBSF = cs.getSystemMBeanServerForwarder();
+ // Real code would just do systemMBSF.setMBeanServer(mbs).
+ while (true) {
+ MBeanServer xmbs = systemMBSF.getMBeanServer();
+ if (!(xmbs instanceof MBeanServerForwarder))
+ break;
+ cs.removeMBeanServerForwarder((MBeanServerForwarder) xmbs);
}
expectChain(cs, "U", mbs);
System.out.println("===Ensure forwarders are called===");
cs.setMBeanServerForwarder(forwarders[0]);
- cs.setSystemMBeanServerForwarder(forwarders[1]);
+ systemMBSF.setMBeanServer(forwarders[1]);
+ forwarders[1].setMBeanServer(forwarders[0]);
expectChain(cs, "1U0", mbs);
cs.start();
if (forwarders[0].defaultDomainCount != 0 ||
@@ -125,8 +129,8 @@
private static void test(JMXConnectorServer cs, MBeanServer end) {
// A newly-created connector server might have system forwarders,
// so get rid of those.
- while (cs.getSystemMBeanServer() != cs.getMBeanServer())
- cs.removeMBeanServerForwarder((MBeanServerForwarder) cs.getSystemMBeanServer());
+ MBeanServerForwarder systemMBSF = cs.getSystemMBeanServerForwarder();
+ systemMBSF.setMBeanServer(cs.getMBeanServer());
expectChain(cs, "U", end);
@@ -139,7 +143,8 @@
expectChain(cs, "U10", end);
System.out.println("Add a system forwarder");
- cs.setSystemMBeanServerForwarder(forwarders[2]);
+ forwarders[2].setMBeanServer(systemMBSF.getMBeanServer());
+ systemMBSF.setMBeanServer(forwarders[2]);
expectChain(cs, "2U10", end);
System.out.println("Add another user forwarder");
@@ -147,7 +152,8 @@
expectChain(cs, "2U310", end);
System.out.println("Add another system forwarder");
- cs.setSystemMBeanServerForwarder(forwarders[4]);
+ forwarders[4].setMBeanServer(systemMBSF.getMBeanServer());
+ systemMBSF.setMBeanServer(forwarders[4]);
expectChain(cs, "42U310", end);
System.out.println("Remove the first user forwarder");
@@ -215,9 +221,8 @@
}
case 2: { // add it to the system chain
System.out.println("Add " + c + " to system chain");
- if (cs.getSystemMBeanServer() == null)
- mbsf.setMBeanServer(null);
- cs.setSystemMBeanServerForwarder(mbsf);
+ mbsf.setMBeanServer(systemMBSF.getMBeanServer());
+ systemMBSF.setMBeanServer(mbsf);
chain = c + chain;
break;
}
@@ -240,7 +245,7 @@
private static void expectChain(
JMXConnectorServer cs, String chain, MBeanServer end) {
System.out.println("...expected chain: " + chain);
- MBeanServer curr = cs.getSystemMBeanServer();
+ MBeanServer curr = cs.getSystemMBeanServerForwarder().getMBeanServer();
int i = 0;
while (i < chain.length()) {
char c = chain.charAt(i);
diff --git a/jdk/test/javax/management/remote/mandatory/connectorServer/StandardForwardersTest.java b/jdk/test/javax/management/remote/mandatory/connectorServer/StandardForwardersTest.java
index d2d5e37..25efde9 100644
--- a/jdk/test/javax/management/remote/mandatory/connectorServer/StandardForwardersTest.java
+++ b/jdk/test/javax/management/remote/mandatory/connectorServer/StandardForwardersTest.java
@@ -26,6 +26,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import javax.management.ClientContext;
import javax.management.MBeanServer;
import javax.management.event.EventClientDelegate;
import javax.management.remote.JMXConnectorServer;
@@ -62,13 +63,23 @@
public static void main(String[] args) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ MBeanServerForwarder ctxFwd = ClientContext.newContextForwarder(mbs, null);
+ Forwarder ctx = new Forwarder(
+ JMXConnectorServer.CONTEXT_FORWARDER, true, ctxFwd.getClass());
+
+ MBeanServerForwarder locFwd =
+ ClientContext.newLocalizeMBeanInfoForwarder(mbs);
+ Forwarder loc = new Forwarder(
+ JMXConnectorServer.LOCALIZE_MBEAN_INFO_FORWARDER, false,
+ locFwd.getClass());
+
MBeanServerForwarder ecdFwd =
- EventClientDelegate.newForwarder();
+ EventClientDelegate.newForwarder(mbs, null);
Forwarder ecd = new Forwarder(
JMXConnectorServer.EVENT_CLIENT_DELEGATE_FORWARDER, true,
ecdFwd.getClass());
- Forwarder[] forwarders = {ecd};
+ Forwarder[] forwarders = {ctx, loc, ecd};
// Now go through every combination of forwarders. Each forwarder
// may be explicitly enabled, explicitly disabled, or left to its
@@ -154,9 +165,11 @@
}
MBeanServer stop = cs.getMBeanServer();
List<Class<?>> foundClasses = new ArrayList<Class<?>>();
- for (MBeanServer mbs = cs.getSystemMBeanServer(); mbs != stop;
- mbs = ((MBeanServerForwarder) mbs).getMBeanServer())
+ for (MBeanServer mbs = cs.getSystemMBeanServerForwarder().getMBeanServer();
+ mbs != stop;
+ mbs = ((MBeanServerForwarder) mbs).getMBeanServer()) {
foundClasses.add(mbs.getClass());
+ }
if (!expectedClasses.equals(foundClasses)) {
fail("Incorrect forwarder chain: expected " + expectedClasses +
"; found " + foundClasses);
@@ -165,9 +178,12 @@
// env is consistent if either (a) localizer is not enabled or (b)
// localizer is enabled and context is enabled.
- // Neither of those is present in this codebase so env is always consistent.
private static boolean isConsistent(Map<String, String> env) {
- return true;
+ String ctxS = env.get(JMXConnectorServer.CONTEXT_FORWARDER);
+ boolean ctx = (ctxS == null) ? true : Boolean.parseBoolean(ctxS);
+ String locS = env.get(JMXConnectorServer.LOCALIZE_MBEAN_INFO_FORWARDER);
+ boolean loc = (locS == null) ? false : Boolean.parseBoolean(locS);
+ return !loc || ctx;
}
private static void fail(String why) {
diff --git a/jdk/test/javax/management/remote/mandatory/provider/ProviderTest.java b/jdk/test/javax/management/remote/mandatory/provider/ProviderTest.java
index 0c7e906..90aa130 100644
--- a/jdk/test/javax/management/remote/mandatory/provider/ProviderTest.java
+++ b/jdk/test/javax/management/remote/mandatory/provider/ProviderTest.java
@@ -46,6 +46,8 @@
/*
* Tests jar services provider are called
*/
+import provider.JMXConnectorProviderImpl;
+import provider.JMXConnectorServerProviderImpl;
public class ProviderTest {
public static void main(String[] args) throws Exception {
System.out.println("Starting ProviderTest");
@@ -56,8 +58,14 @@
dotest(url, mbs);
- if(!provider.JMXConnectorProviderImpl.called() ||
- !provider.JMXConnectorServerProviderImpl.called()) {
+ boolean clientCalled = provider.JMXConnectorProviderImpl.called();
+ boolean serverCalled = provider.JMXConnectorServerProviderImpl.called();
+ boolean ok = clientCalled && serverCalled;
+ if (!ok) {
+ if (!clientCalled)
+ System.out.println("Client provider not called");
+ if (!serverCalled)
+ System.out.println("Server provider not called");
System.out.println("Test Failed");
System.exit(1);
}
diff --git a/jdk/test/javax/management/remote/mandatory/subjectDelegation/SimpleStandard.java b/jdk/test/javax/management/remote/mandatory/subjectDelegation/SimpleStandard.java
index 1a0e1df..d0d7598 100644
--- a/jdk/test/javax/management/remote/mandatory/subjectDelegation/SimpleStandard.java
+++ b/jdk/test/javax/management/remote/mandatory/subjectDelegation/SimpleStandard.java
@@ -75,7 +75,7 @@
* @return the current value of the "State" attribute.
*/
public String getState() {
- checkSubject();
+ checkSubject("getState");
return state;
}
@@ -85,7 +85,7 @@
* @param <VAR>s</VAR> the new value of the "State" attribute.
*/
public void setState(String s) {
- checkSubject();
+ checkSubject("setState");
state = s;
nbChanges++;
}
@@ -97,7 +97,7 @@
* @return the current value of the "NbChanges" attribute.
*/
public int getNbChanges() {
- checkSubject();
+ checkSubject("getNbChanges");
return nbChanges;
}
@@ -106,7 +106,7 @@
* attributes of the "SimpleStandard" standard MBean.
*/
public void reset() {
- checkSubject();
+ checkSubject("reset");
AttributeChangeNotification acn =
new AttributeChangeNotification(this,
0,
@@ -149,18 +149,18 @@
* Check that the principal contained in the Subject is of
* type JMXPrincipal and refers to the principalName identity.
*/
- private void checkSubject() {
+ private void checkSubject(String op) {
AccessControlContext acc = AccessController.getContext();
Subject subject = Subject.getSubject(acc);
Set principals = subject.getPrincipals();
Principal principal = (Principal) principals.iterator().next();
if (!(principal instanceof JMXPrincipal))
- throw new SecurityException("Authenticated subject contains " +
+ throw new SecurityException(op+": Authenticated subject contains " +
"invalid principal type = " +
principal.getClass().getName());
String identity = principal.getName();
if (!identity.equals(principalName))
- throw new SecurityException("Authenticated subject contains " +
+ throw new SecurityException(op+": Authenticated subject contains " +
"invalid principal name = " + identity);
}
diff --git a/jdk/test/javax/management/remote/mandatory/version/JMXSpecVersionTest.java b/jdk/test/javax/management/remote/mandatory/version/JMXSpecVersionTest.java
new file mode 100644
index 0000000..6978269
--- /dev/null
+++ b/jdk/test/javax/management/remote/mandatory/version/JMXSpecVersionTest.java
@@ -0,0 +1,308 @@
+/*
+ * 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 6750008
+ * @summary Test JMX.getSpecificationVersion
+ * @author Eamonn McManus
+ */
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.ListIterator;
+import java.util.Set;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.DynamicMBean;
+import javax.management.InstanceNotFoundException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.JMX;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanServerDelegateMBean;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.StandardMBean;
+import javax.management.namespace.JMXNamespace;
+import javax.management.namespace.JMXNamespaces;
+import javax.management.namespace.MBeanServerSupport;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+public class JMXSpecVersionTest {
+ private static String failure;
+ private static final Object POISON_PILL = new Object();
+
+ private static class FakeDelegate implements DynamicMBean {
+ private final Object specVersion;
+ private final DynamicMBean delegate = new StandardMBean(
+ new MBeanServerDelegate(), MBeanServerDelegateMBean.class, false);
+
+ FakeDelegate(Object specVersion) {
+ this.specVersion = specVersion;
+ }
+
+ public Object getAttribute(String attribute)
+ throws AttributeNotFoundException, MBeanException,
+ ReflectionException {
+ if ("SpecificationVersion".equals(attribute)) {
+ if (specVersion == POISON_PILL)
+ throw new AttributeNotFoundException(attribute);
+ else
+ return specVersion;
+ } else
+ return delegate.getAttribute(attribute);
+ }
+
+ public void setAttribute(Attribute attribute)
+ throws AttributeNotFoundException, InvalidAttributeValueException,
+ MBeanException, ReflectionException {
+ delegate.setAttribute(attribute);
+ }
+
+ public AttributeList getAttributes(String[] attributes) {
+ AttributeList list = delegate.getAttributes(attributes);
+ for (ListIterator<Attribute> it = list.asList().listIterator();
+ it.hasNext(); ) {
+ Attribute attr = it.next();
+ if (attr.getName().equals("SpecificationVersion")) {
+ it.remove();
+ if (specVersion != POISON_PILL) {
+ attr = new Attribute(attr.getName(), specVersion);
+ it.add(attr);
+ }
+ }
+ }
+ return list;
+ }
+
+ public AttributeList setAttributes(AttributeList attributes) {
+ return delegate.setAttributes(attributes);
+ }
+
+ public Object invoke(String actionName, Object[] params,
+ String[] signature) throws MBeanException,
+ ReflectionException {
+ return delegate.invoke(actionName, params, signature);
+ }
+
+ public MBeanInfo getMBeanInfo() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ }
+
+ private static class MBeanServerWithVersion extends MBeanServerSupport {
+ private final DynamicMBean delegate;
+
+ public MBeanServerWithVersion(Object specVersion) {
+ this.delegate = new FakeDelegate(specVersion);
+ }
+
+ @Override
+ public DynamicMBean getDynamicMBeanFor(ObjectName name)
+ throws InstanceNotFoundException {
+ if (MBeanServerDelegate.DELEGATE_NAME.equals(name))
+ return delegate;
+ else
+ throw new InstanceNotFoundException(name);
+ }
+
+ @Override
+ protected Set<ObjectName> getNames() {
+ return Collections.singleton(MBeanServerDelegate.DELEGATE_NAME);
+ }
+ }
+
+ private static class EmptyMBeanServer extends MBeanServerSupport {
+ @Override
+ public DynamicMBean getDynamicMBeanFor(ObjectName name) throws InstanceNotFoundException {
+ throw new InstanceNotFoundException(name);
+ }
+
+ @Override
+ protected Set<ObjectName> getNames() {
+ return Collections.emptySet();
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+ JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///");
+ JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(
+ url, null, mbs);
+ cs.start();
+
+ String realVersion = (String) mbs.getAttribute(
+ MBeanServerDelegate.DELEGATE_NAME, "SpecificationVersion");
+ assertEquals("Reported local version",
+ realVersion, JMX.getSpecificationVersion(mbs, null));
+ assertEquals("Reported local version >= \"2.0\"",
+ true, (realVersion.compareTo("2.0") >= 0));
+
+ JMXConnector cc = JMXConnectorFactory.connect(cs.getAddress());
+ MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+ assertEquals("Reported remote version",
+ realVersion, JMX.getSpecificationVersion(mbsc, null));
+
+ cc.close();
+ try {
+ String brokenVersion = JMX.getSpecificationVersion(mbsc, null);
+ fail("JMX.getSpecificationVersion succeded over closed connection" +
+ " (returned " + brokenVersion + ")");
+ } catch (Exception e) {
+ assertEquals("Exception for closed connection",
+ IOException.class, e.getClass());
+ }
+
+ try {
+ String brokenVersion = JMX.getSpecificationVersion(
+ new EmptyMBeanServer(), null);
+ fail("JMX.getSpecificationVersion succeded with empty MBean Server" +
+ " (returned " + brokenVersion + ")");
+ } catch (Exception e) {
+ assertEquals("Exception for empty MBean Server",
+ IOException.class, e.getClass());
+ }
+
+ try {
+ String brokenVersion = JMX.getSpecificationVersion(null, null);
+ fail("JMX.getSpecificationVersion succeded with null MBean Server" +
+ " (returned " + brokenVersion + ")");
+ } catch (Exception e) {
+ assertEquals("Exception for null MBean Server",
+ IllegalArgumentException.class, e.getClass());
+ }
+
+ MBeanServer mbs1_2 = new MBeanServerWithVersion("1.2");
+ String version1_2 = JMX.getSpecificationVersion(mbs1_2, null);
+ assertEquals("Version for 1.2 MBean Server", "1.2", version1_2);
+
+ // It's completely nutty for an MBean Server to return null as the
+ // value of its spec version, and we don't actually say what happens
+ // in that case, but in fact we return the null to the caller.
+ MBeanServer mbs_null = new MBeanServerWithVersion(null);
+ String version_null = JMX.getSpecificationVersion(mbs_null, null);
+ assertEquals("Version for MBean Server that declares null spec version",
+ null, version_null);
+
+ try {
+ MBeanServer mbs1_2_float = new MBeanServerWithVersion(1.2f);
+ String version1_2_float =
+ JMX.getSpecificationVersion(mbs1_2_float, null);
+ fail("JMX.getSpecificationVersion succeeded with version 1.2f" +
+ " (returned " + version1_2_float + ")");
+ } catch (Exception e) {
+ assertEquals("Exception for non-string version (1.2f)",
+ IOException.class, e.getClass());
+ }
+
+ try {
+ MBeanServer mbs_missing = new MBeanServerWithVersion(POISON_PILL);
+ String version_missing =
+ JMX.getSpecificationVersion(mbs_missing, null);
+ fail("JMX.getSpecificationVersion succeeded with null version" +
+ " (returned " + version_missing + ")");
+ } catch (Exception e) {
+ assertEquals("Exception for missing version",
+ IOException.class, e.getClass());
+ }
+
+ ObjectName wildcardNamespaceName = new ObjectName("foo//*//bar//baz:k=v");
+ try {
+ String brokenVersion =
+ JMX.getSpecificationVersion(mbsc, wildcardNamespaceName);
+ fail("JMX.getSpecificationVersion succeeded with wildcard namespace" +
+ " (returned " + brokenVersion + ")");
+ } catch (Exception e) {
+ assertEquals("Exception for wildcard namespace",
+ IllegalArgumentException.class, e.getClass());
+ }
+
+ String sub1_2namespace = "blibby";
+ JMXNamespace sub1_2 = new JMXNamespace(mbs1_2);
+ ObjectName sub1_2name =
+ JMXNamespaces.getNamespaceObjectName(sub1_2namespace);
+ mbs.registerMBean(sub1_2, sub1_2name);
+ String sub1_2namespaceHandlerVersion =
+ JMX.getSpecificationVersion(mbs, sub1_2name);
+ assertEquals("Spec version of namespace handler",
+ realVersion, sub1_2namespaceHandlerVersion);
+ // The namespace handler is in the top-level namespace so its
+ // version should not be 1.2.
+
+ for (String nameInSub : new String[] {"*:*", "d:k=v"}) {
+ ObjectName subName = new ObjectName(sub1_2namespace + "//" + nameInSub);
+ String subVersion = JMX.getSpecificationVersion(mbs, subName);
+ assertEquals("Spec version in 1.2 namespace (" + nameInSub + ")",
+ "1.2", subVersion);
+ }
+
+ mbs.unregisterMBean(sub1_2name);
+ for (String noSuchNamespace : new String[] {
+ sub1_2namespace + "//*:*", sub1_2namespace + "//d:k=v",
+ }) {
+ try {
+ String brokenVersion = JMX.getSpecificationVersion(
+ mbs, new ObjectName(noSuchNamespace));
+ fail("JMX.getSpecificationVersion succeeded with missing " +
+ "namespace (" + noSuchNamespace + " -> " +
+ brokenVersion);
+ } catch (Exception e) {
+ assertEquals("Exception for missing namespace",
+ IOException.class, e.getClass());
+ }
+ }
+
+ if (failure != null)
+ throw new Exception("TEST FAILED: " + failure);
+ System.out.println("TEST PASSED");
+ }
+
+ private static void assertEquals(String what, Object expect, Object actual) {
+ if (equal(expect, actual))
+ System.out.println("OK: " + what + ": " + expect);
+ else
+ fail(what + ": expected " + expect + ", got " + actual);
+ }
+
+ private static boolean equal(Object x, Object y) {
+ if (x == null)
+ return (y == null);
+ else
+ return x.equals(y);
+ }
+
+ private static void fail(String why) {
+ System.out.println("FAILED: " + why);
+ failure = why;
+ }
+}
diff --git a/jdk/test/sun/security/krb5/auto/Context.java b/jdk/test/sun/security/krb5/auto/Context.java
index 9f52dad..2439aa2 100644
--- a/jdk/test/sun/security/krb5/auto/Context.java
+++ b/jdk/test/sun/security/krb5/auto/Context.java
@@ -109,13 +109,22 @@
out.s = new Subject();
Krb5LoginModule krb5 = new Krb5LoginModule();
Map<String, String> map = new HashMap<String, String>();
- map.put("tryFirstPass", "true");
+ Map<String, Object> shared = new HashMap<String, Object>();
+
+ if (pass != null) {
+ map.put("useFirstPass", "true");
+ shared.put("javax.security.auth.login.name", user);
+ shared.put("javax.security.auth.login.password", pass);
+ } else {
+ map.put("doNotPrompt", "true");
+ map.put("useTicketCache", "true");
+ if (user != null) {
+ map.put("principal", user);
+ }
+ }
if (storeKey) {
map.put("storeKey", "true");
}
- Map<String, Object> shared = new HashMap<String, Object>();
- shared.put("javax.security.auth.login.name", user);
- shared.put("javax.security.auth.login.password", pass);
krb5.initialize(out.s, null, shared, map);
krb5.login();
@@ -360,6 +369,10 @@
if (me.x.isEstablished()) {
me.f = true;
System.out.println(c.name + " side established");
+ if (input != null) {
+ throw new Exception("Context established but " +
+ "still receive token at " + c.name);
+ }
return null;
} else {
System.out.println(c.name + " call initSecContext");
@@ -374,6 +387,10 @@
if (me.x.isEstablished()) {
me.f = true;
System.out.println(s.name + " side established");
+ if (input != null) {
+ throw new Exception("Context established but " +
+ "still receive token at " + s.name);
+ }
return null;
} else {
System.out.println(s.name + " called acceptSecContext");
diff --git a/jdk/test/sun/security/krb5/auto/KDC.java b/jdk/test/sun/security/krb5/auto/KDC.java
index a875e09..3e6a779 100644
--- a/jdk/test/sun/security/krb5/auto/KDC.java
+++ b/jdk/test/sun/security/krb5/auto/KDC.java
@@ -32,6 +32,7 @@
import java.util.concurrent.*;
import sun.security.krb5.*;
import sun.security.krb5.internal.*;
+import sun.security.krb5.internal.ccache.CredentialsCache;
import sun.security.krb5.internal.crypto.KeyUsage;
import sun.security.krb5.internal.ktab.KeyTab;
import sun.security.util.DerInputStream;
@@ -765,7 +766,29 @@
DerOutputStream out = new DerOutputStream();
out.write(DerValue.createTag(DerValue.TAG_APPLICATION,
true, (byte)Krb5.KRB_AS_REP), asRep.asn1Encode());
- return out.toByteArray();
+ byte[] result = out.toByteArray();
+
+ // Added feature:
+ // Write the current issuing TGT into a ccache file specified
+ // by the system property below.
+ String ccache = System.getProperty("test.kdc.save.ccache");
+ if (ccache != null) {
+ asRep.encKDCRepPart = enc_part;
+ sun.security.krb5.internal.ccache.Credentials credentials =
+ new sun.security.krb5.internal.ccache.Credentials(asRep);
+ asReq.reqBody.cname.setRealm(getRealm());
+ CredentialsCache cache =
+ CredentialsCache.create(asReq.reqBody.cname, ccache);
+ if (cache == null) {
+ throw new IOException("Unable to create the cache file " +
+ ccache);
+ }
+ cache.update(credentials);
+ cache.save();
+ new File(ccache).deleteOnExit();
+ }
+
+ return result;
} catch (KrbException ke) {
ke.printStackTrace(System.out);
KRBError kerr = ke.getError();
diff --git a/jdk/test/sun/security/krb5/auto/LoginModuleOptions.java b/jdk/test/sun/security/krb5/auto/LoginModuleOptions.java
new file mode 100644
index 0000000..4c0dd73
--- /dev/null
+++ b/jdk/test/sun/security/krb5/auto/LoginModuleOptions.java
@@ -0,0 +1,184 @@
+/*
+ * 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 6765491
+ * @summary Krb5LoginModule a little too restrictive, and the doc is not clear.
+ */
+import com.sun.security.auth.module.Krb5LoginModule;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+public class LoginModuleOptions {
+
+ private static final String NAME = "javax.security.auth.login.name";
+ private static final String PWD = "javax.security.auth.login.password";
+
+ public static void main(String[] args) throws Exception {
+ OneKDC kdc = new OneKDC(null);
+ kdc.addPrincipal("foo", "bar".toCharArray());
+ kdc.writeKtab(OneKDC.KTAB); // rewrite to add foo
+
+ // All 4 works: keytab, shared state, callback, cache
+ login(null, "useKeyTab", "true", "principal", "dummy");
+ login(null, "tryFirstPass", "true", NAME, OneKDC.USER,
+ PWD, OneKDC.PASS);
+ System.setProperty("test.kdc.save.ccache", "krbcc");
+ login(new MyCallback(OneKDC.USER, OneKDC.PASS)); // save the cache
+ System.clearProperty("test.kdc.save.ccache");
+ login(null, "useTicketCache", "true", "ticketCache", "krbcc");
+
+ // Fallbacks
+ // 1. ccache -> keytab
+ login(null, "useTicketCache", "true", "ticketCache", "krbcc_non_exists",
+ "useKeyTab", "true", "principal", "dummy");
+ // 2. keytab -> shared
+ login(null, "useKeyTab", "true", "principal", "dummy",
+ "keyTab", "ktab_non_exist",
+ "tryFirstPass", "true", NAME, OneKDC.USER, PWD, OneKDC.PASS);
+ // 3. shared -> callback
+ // 3.1. useFirstPass, no callback
+ boolean failed = false;
+ try {
+ login(new MyCallback(OneKDC.USER, OneKDC.PASS),
+ "useFirstPass", "true",
+ NAME, OneKDC.USER, PWD, "haha".toCharArray());
+ } catch (Exception e) {
+ failed = true;
+ }
+ if (!failed) {
+ throw new Exception("useFirstPass should not fallback to callback");
+ }
+ // 3.2. tryFirstPass, has callback
+ login(new MyCallback(OneKDC.USER, OneKDC.PASS),
+ "tryFirstPass", "true",
+ NAME, OneKDC.USER, PWD, "haha".toCharArray());
+
+ // Preferences of type
+ // 1. ccache preferred to keytab
+ login(new MyCallback("foo", null),
+ "useTicketCache", "true", "ticketCache", "krbcc",
+ "useKeyTab", "true");
+ // 2. keytab preferred to shared. This test case is not exactly correct,
+ // because principal=dummy would shadow the PWD setting in the shared
+ // state. So by only looking at the final authentication user name
+ // (which is how this program does), there's no way to tell if keyTab
+ // is picked first, or shared is tried first but fallback to keytab.
+ login(null, "useKeyTab", "true", "principal", "dummy",
+ "tryFirstPass", "true", NAME, "foo", PWD, "bar".toCharArray());
+ // 3. shared preferred to callback
+ login(new MyCallback("foo", "bar".toCharArray()),
+ "tryFirstPass", "true", NAME, OneKDC.USER, PWD, OneKDC.PASS);
+
+ // Preferences of username
+ // 1. principal preferred to NAME (NAME can be wrong or missing)
+ login(null, "principal", OneKDC.USER,
+ "tryFirstPass", "true", NAME, "someone_else", PWD, OneKDC.PASS);
+ login(null, "principal", OneKDC.USER,
+ "tryFirstPass", "true", PWD, OneKDC.PASS);
+ // 2. NAME preferred to callback
+ login(new MyCallback("someone_else", OneKDC.PASS),
+ "principal", OneKDC.USER);
+ // 3. With tryFirstPass, NAME preferred to callback
+ login(new MyCallback("someone_else", null),
+ "tryFirstPass", "true", NAME, OneKDC.USER, PWD, OneKDC.PASS);
+ // 3.1. you must provide a NAME (when there's no principal)
+ failed = false;
+ try {
+ login(new MyCallback(OneKDC.USER, null),
+ "tryFirstPass", "true", PWD, OneKDC.PASS);
+ } catch (Exception e) {
+ failed = true;
+ }
+ if (!failed) {
+ throw new Exception("useFirstPass must provide a NAME");
+ }
+ // 3.2 Hybrid, you can use NAME as "", and provide it using callback.
+ // I don't think this is designed.
+ login(new MyCallback(OneKDC.USER, null),
+ "tryFirstPass", "true", NAME, "", PWD, OneKDC.PASS);
+
+ // Test for the bug fix: doNotPrompt can be true if tryFirstPass=true
+ login(null, "doNotPrompt", "true", "storeKey", "true",
+ "tryFirstPass", "true", NAME, OneKDC.USER, PWD, OneKDC.PASS);
+ }
+
+ static void login(CallbackHandler callback, Object... options)
+ throws Exception {
+ Krb5LoginModule krb5 = new Krb5LoginModule();
+ Subject subject = new Subject();
+ Map<String, String> map = new HashMap<String, String>();
+ Map<String, Object> shared = new HashMap<String, Object>();
+
+ int count = options.length / 2;
+ for (int i = 0; i < count; i++) {
+ String key = (String) options[2 * i];
+ Object value = options[2 * i + 1];
+ if (key.startsWith("javax")) {
+ shared.put(key, value);
+ } else {
+ map.put(key, (String) value);
+ }
+ }
+ krb5.initialize(subject, callback, shared, map);
+ krb5.login();
+ krb5.commit();
+ if (!subject.getPrincipals().iterator().next()
+ .getName().startsWith(OneKDC.USER)) {
+ throw new Exception("The authenticated is not " + OneKDC.USER);
+ }
+ }
+
+ static class MyCallback implements CallbackHandler {
+
+ private String name;
+ private char[] password;
+
+ public MyCallback(String name, char[] password) {
+ this.name = name;
+ this.password = password;
+ }
+
+ public void handle(Callback[] callbacks) {
+ for (Callback callback : callbacks) {
+ System.err.println(callback);
+ if (callback instanceof NameCallback) {
+ System.err.println("name is " + name);
+ ((NameCallback) callback).setName(name);
+ }
+ if (callback instanceof PasswordCallback) {
+ System.err.println("pass is " + new String(password));
+ ((PasswordCallback) callback).setPassword(password);
+ }
+ }
+ }
+ }
+}
diff --git a/jdk/test/sun/security/krb5/auto/NonMutualSpnego.java b/jdk/test/sun/security/krb5/auto/NonMutualSpnego.java
new file mode 100644
index 0000000..f2e7812
--- /dev/null
+++ b/jdk/test/sun/security/krb5/auto/NonMutualSpnego.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6733095
+ * @summary Failure when SPNEGO request non-Mutual
+ */
+
+import sun.security.jgss.GSSUtil;
+
+public class NonMutualSpnego {
+
+ public static void main(String[] args)
+ throws Exception {
+
+ // Create and start the KDC
+ new OneKDC(null).writeJAASConf();
+ new NonMutualSpnego().go();
+ }
+
+ void go() throws Exception {
+ Context c = Context.fromJAAS("client");
+ Context s = Context.fromJAAS("server");
+
+ c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_SPNEGO_MECH_OID);
+ c.x().requestMutualAuth(false);
+ s.startAsServer(GSSUtil.GSS_SPNEGO_MECH_OID);
+
+ Context.handshake(c, s);
+
+ Context.transmit("i say high --", c, s);
+ Context.transmit(" you say low", s, c);
+
+ c.dispose();
+ s.dispose();
+ }
+}
diff --git a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/EmptyExtensionData.java b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/EmptyExtensionData.java
new file mode 100644
index 0000000..3d86cc9
--- /dev/null
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/EmptyExtensionData.java
@@ -0,0 +1,196 @@
+/*
+ * 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 6728126
+ * @summary Parsing Extensions in Client Hello message is done in a wrong way
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+
+public class EmptyExtensionData {
+
+ private static boolean debug = false;
+
+ private static String pathToStores = "../../../../../../../etc";
+ private static String keyStoreFile = "keystore";
+ private static String trustStoreFile = "truststore";
+ private static String passwd = "passphrase";
+
+ private static String keyFilename =
+ System.getProperty("test.src", "./") + "/" + pathToStores +
+ "/" + keyStoreFile;
+ private static String trustFilename =
+ System.getProperty("test.src", "./") + "/" + pathToStores +
+ "/" + trustStoreFile;
+
+ private static void checkDone(SSLEngine ssle) throws Exception {
+ if (!ssle.isInboundDone()) {
+ throw new Exception("isInboundDone isn't done");
+ }
+ if (!ssle.isOutboundDone()) {
+ throw new Exception("isOutboundDone isn't done");
+ }
+ }
+
+ private static void runTest(SSLEngine ssle) throws Exception {
+ // a client hello message with an empty extension data
+ byte[] msg_clihello = {
+ (byte)0x16, (byte)0x03, (byte)0x01, (byte)0x00,
+ (byte)0x6f, (byte)0x01, (byte)0x00, (byte)0x00,
+ (byte)0x6b, (byte)0x03, (byte)0x01, (byte)0x48,
+ (byte)0x90, (byte)0x71, (byte)0xfc, (byte)0xf9,
+ (byte)0xa2, (byte)0x3a, (byte)0xd7, (byte)0xa8,
+ (byte)0x0b, (byte)0x25, (byte)0xf1, (byte)0x2b,
+ (byte)0x88, (byte)0x80, (byte)0x66, (byte)0xca,
+ (byte)0x07, (byte)0x78, (byte)0x2a, (byte)0x08,
+ (byte)0x9d, (byte)0x62, (byte)0x1d, (byte)0x89,
+ (byte)0xc9, (byte)0x1e, (byte)0x1f, (byte)0xe5,
+ (byte)0x92, (byte)0xfe, (byte)0x8d, (byte)0x00,
+ (byte)0x00, (byte)0x24, (byte)0x00, (byte)0x88,
+ (byte)0x00, (byte)0x87, (byte)0x00, (byte)0x39,
+ (byte)0x00, (byte)0x38, (byte)0x00, (byte)0x84,
+ (byte)0x00, (byte)0x35, (byte)0x00, (byte)0x45,
+ (byte)0x00, (byte)0x44, (byte)0x00, (byte)0x33,
+ (byte)0x00, (byte)0x32, (byte)0x00, (byte)0x41,
+ (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x05,
+ (byte)0x00, (byte)0x2f, (byte)0x00, (byte)0x16,
+ (byte)0x00, (byte)0x13, (byte)0xfe, (byte)0xff,
+ (byte)0x00, (byte)0x0a, (byte)0x01, (byte)0x00,
+ (byte)0x00, (byte)0x1e, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x16, (byte)0x00, (byte)0x14,
+ (byte)0x00, (byte)0x00, (byte)0x11, (byte)0x6a,
+ (byte)0x75, (byte)0x73, (byte)0x74, (byte)0x69,
+ (byte)0x6e, (byte)0x2e, (byte)0x75, (byte)0x6b,
+ (byte)0x2e, (byte)0x73, (byte)0x75, (byte)0x6e,
+ (byte)0x2e, (byte)0x63, (byte)0x6f, (byte)0x6d,
+ (byte)0x00, (byte)0x23, (byte)0x00, (byte)0x00
+ };
+ ByteBuffer bf_clihello = ByteBuffer.wrap(msg_clihello);
+
+ SSLSession session = ssle.getSession();
+ int appBufferMax = session.getApplicationBufferSize();
+ int netBufferMax = session.getPacketBufferSize();
+
+ ByteBuffer serverIn = ByteBuffer.allocate(appBufferMax + 50);
+ ByteBuffer serverOut = ByteBuffer.wrap("I'm Server".getBytes());
+ ByteBuffer sTOc = ByteBuffer.allocate(netBufferMax);
+
+ ssle.beginHandshake();
+
+ // unwrap the clientHello message.
+ SSLEngineResult result = ssle.unwrap(bf_clihello, serverIn);
+ System.out.println("server unwrap " + result);
+ runDelegatedTasks(result, ssle);
+
+ // one more step, ensure the clientHello message is parsed.
+ SSLEngineResult.HandshakeStatus status = ssle.getHandshakeStatus();
+ if ( status == HandshakeStatus.NEED_UNWRAP) {
+ result = ssle.unwrap(bf_clihello, serverIn);
+ System.out.println("server unwrap " + result);
+ runDelegatedTasks(result, ssle);
+ } else if ( status == HandshakeStatus.NEED_WRAP) {
+ result = ssle.wrap(serverOut, sTOc);
+ System.out.println("server wrap " + result);
+ runDelegatedTasks(result, ssle);
+ } else {
+ throw new Exception("unexpected handshake status " + status);
+ }
+
+ // enough, stop
+ }
+
+ /*
+ * If the result indicates that we have outstanding tasks to do,
+ * go ahead and run them in this thread.
+ */
+ private static void runDelegatedTasks(SSLEngineResult result,
+ SSLEngine engine) throws Exception {
+
+ if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+ Runnable runnable;
+ while ((runnable = engine.getDelegatedTask()) != null) {
+ log("\trunning delegated task...");
+ runnable.run();
+ }
+ HandshakeStatus hsStatus = engine.getHandshakeStatus();
+ if (hsStatus == HandshakeStatus.NEED_TASK) {
+ throw new Exception(
+ "handshake shouldn't need additional tasks");
+ }
+ log("\tnew HandshakeStatus: " + hsStatus);
+ }
+ }
+
+ public static void main(String args[]) throws Exception {
+
+ SSLEngine ssle = createSSLEngine(keyFilename, trustFilename);
+ runTest(ssle);
+
+ System.out.println("Test Passed.");
+ }
+
+ /*
+ * Create an initialized SSLContext to use for this test.
+ */
+ static private SSLEngine createSSLEngine(String keyFile, String trustFile)
+ throws Exception {
+
+ SSLEngine ssle;
+
+ KeyStore ks = KeyStore.getInstance("JKS");
+ KeyStore ts = KeyStore.getInstance("JKS");
+
+ char[] passphrase = "passphrase".toCharArray();
+
+ ks.load(new FileInputStream(keyFile), passphrase);
+ ts.load(new FileInputStream(trustFile), passphrase);
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+ kmf.init(ks, passphrase);
+
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+ tmf.init(ts);
+
+ SSLContext sslCtx = SSLContext.getInstance("TLS");
+
+ sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+ ssle = sslCtx.createSSLEngine();
+ ssle.setUseClientMode(false);
+
+ return ssle;
+ }
+
+
+ private static void log(String str) {
+ if (debug) {
+ System.out.println(str);
+ }
+ }
+}