Merge
This commit is contained in:
commit
1d59997abe
1
.hgtags
1
.hgtags
@ -14,3 +14,4 @@ d718a441936196b93d8bc9f084933af9a4c2a350 jdk7-b36
|
||||
c2036bf76829c03b99108fffab52e20910a9be4f jdk7-b37
|
||||
a2879b2837f5a4c87e9542efe69ef138194af8ff jdk7-b38
|
||||
126f365cec6c3c2c72de934fa1c64b5f082b55b5 jdk7-b39
|
||||
3c53424bbe3bb77e01b468b4b0140deec33e11fc jdk7-b40
|
||||
|
@ -14,3 +14,4 @@ bb1ef4ee3d2c8cbf43a37d372325a7952be590b9 jdk7-b33
|
||||
744554f5a3290e11c71cd2ddb1aff49e431f9ed0 jdk7-b37
|
||||
cc47a76899ed33a2c513cb688348244c9b5a1288 jdk7-b38
|
||||
ab523b49de1fc73fefe6855ce1e0349bdbd7af29 jdk7-b39
|
||||
44be42de6693063fb191989bf0e188de2fa51e7c jdk7-b40
|
||||
|
@ -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.
|
||||
|
@ -14,3 +14,4 @@ ef6af34d75a7b44e77083f1d4ee47631fa09d3b4 jdk7-b31
|
||||
59d5848bdedebe91cc2753acce78911bcb4a66db jdk7-b37
|
||||
08be802754b0296c91a7713b6d85a015dbcd5349 jdk7-b38
|
||||
55078b6661e286e90387d1d9950bd865f5cc436e jdk7-b39
|
||||
184e21992f47a8d730df1adc5b21a108f3125489 jdk7-b40
|
||||
|
@ -14,3 +14,4 @@ e91159f921a58af3698e6479ea1fc5818da66d09 jdk7-b36
|
||||
9ee9cf798b59e7d51f8c0a686959f313867a55d6 jdk7-b37
|
||||
d9bc824aa078573829bb66572af847e26e1bd12e jdk7-b38
|
||||
49ca90d77f34571b0757ebfcb8a7848ef2696b88 jdk7-b39
|
||||
81a0cbe3b28460ce836109934ece03db7afaf9cc jdk7-b40
|
||||
|
@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2008
|
||||
|
||||
HS_MAJOR_VER=14
|
||||
HS_MINOR_VER=0
|
||||
HS_BUILD_NUMBER=07
|
||||
HS_BUILD_NUMBER=08
|
||||
|
||||
JDK_MAJOR_VER=1
|
||||
JDK_MINOR_VER=7
|
||||
|
@ -200,29 +200,6 @@ BUILD_WIN_SA = 0
|
||||
checkSA::
|
||||
@echo Not building SA: ARCH = ia64
|
||||
|
||||
!elseif exist("$(MSVCDIR)\PlatformSDK\Include\dbgeng.h")
|
||||
# These don't have to be set because the default
|
||||
# setting of INCLUDE and LIB already contain the needed dirs.
|
||||
SA_INCLUDE =
|
||||
SA_LIB =
|
||||
|
||||
!elseif exist("$(SYSTEMROOT)\..\Program Files\Microsoft SDK\include\dbgeng.h")
|
||||
# These don't have to be set because the default
|
||||
# setting of INCLUDE and LIB already contain the needed dirs.
|
||||
SA_INCLUDE =
|
||||
SA_LIB =
|
||||
|
||||
!else
|
||||
checkSA::
|
||||
@echo .
|
||||
@echo ERROR: Can't build SA because dbgeng.h does not exist here:
|
||||
@echo $(MSVCDIR)\PlatformSDK\Include\dbgeng.h
|
||||
@echo nor here:
|
||||
@echo $(SYSTEMROOT)\..\Program Files\Microsoft SDK\include\dbgeng.h
|
||||
@echo You must use Vis. Studio .Net 2003 on Win 32, and you must
|
||||
@echo have the Microsoft SDK installed on Win amd64.
|
||||
@echo You can disable building of SA by specifying BUILD_WIN_SA = 0
|
||||
@echo . && false
|
||||
!endif # ! "$(BUILD_WIN_SA)" != "1"
|
||||
|
||||
#########################################################################
|
||||
|
@ -119,7 +119,7 @@ endif
|
||||
# we want to release it. If we build it here,
|
||||
# the SDK makefiles will copy it over and put it into
|
||||
# the created image.
|
||||
BUILD_WIN_SA = 0
|
||||
BUILD_WIN_SA = 1
|
||||
ifneq ($(ALT_BUILD_WIN_SA),)
|
||||
BUILD_WIN_SA = $(ALT_BUILD_WIN_SA)
|
||||
endif
|
||||
|
@ -49,6 +49,9 @@ SA_PROPERTIES = $(SA_CLASSDIR)\sa.properties
|
||||
|
||||
default:: $(GENERATED)\sa-jdi.jar
|
||||
|
||||
# Remove the space between $(SA_BUILD_VERSION_PROP) and > below as it adds a white space
|
||||
# at the end of SA version string and causes a version mismatch with the target VM version.
|
||||
|
||||
$(GENERATED)\sa-jdi.jar: $(AGENT_FILES1:/=\) $(AGENT_FILES2:/=\)
|
||||
@if not exist $(SA_CLASSDIR) mkdir $(SA_CLASSDIR)
|
||||
@echo ...Building sa-jdi.jar
|
||||
@ -56,15 +59,15 @@ $(GENERATED)\sa-jdi.jar: $(AGENT_FILES1:/=\) $(AGENT_FILES2:/=\)
|
||||
@$(COMPILE_JAVAC) -source 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -g -d $(SA_CLASSDIR) $(AGENT_FILES1:/=\)
|
||||
@$(COMPILE_JAVAC) -source 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -g -d $(SA_CLASSDIR) $(AGENT_FILES2:/=\)
|
||||
$(COMPILE_RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer
|
||||
$(QUIETLY) echo $(SA_BUILD_VERSION_PROP) > $(SA_PROPERTIES)
|
||||
$(RUN_JAR) cf $@ -C saclasses .
|
||||
$(RUN_JAR) uf $@ -C $(AGENT_SRC_DIR:/=\) META-INF\services\com.sun.jdi.connect.Connector
|
||||
$(QUIETLY) echo $(SA_BUILD_VERSION_PROP)> $(SA_PROPERTIES)
|
||||
$(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql/sa.js
|
||||
$(QUIETLY) cp $(AGENT_SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql
|
||||
$(QUIETLY) mkdir -p $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources
|
||||
$(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources/*
|
||||
$(QUIETLY) cp $(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/resources/*.png $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources/
|
||||
$(QUIETLY) cp -r $(AGENT_SRC_DIR)/images/* $(SA_CLASSDIR)/
|
||||
$(QUIETLY) rm -rf $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources
|
||||
$(QUIETLY) mkdir $(SA_CLASSDIR)\sun\jvm\hotspot\ui\resources
|
||||
$(QUIETLY) cp $(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/resources/*.png $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources
|
||||
$(QUIETLY) cp -r $(AGENT_SRC_DIR)/images/* $(SA_CLASSDIR)
|
||||
$(RUN_JAR) cf $@ -C saclasses .
|
||||
$(RUN_JAR) uf $@ -C $(AGENT_SRC_DIR:/=\) META-INF\services\com.sun.jdi.connect.Connector
|
||||
$(RUN_JAVAH) -classpath $(SA_CLASSDIR) -jni sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal
|
||||
$(RUN_JAVAH) -classpath $(SA_CLASSDIR) -jni sun.jvm.hotspot.debugger.x86.X86ThreadContext
|
||||
$(RUN_JAVAH) -classpath $(SA_CLASSDIR) -jni sun.jvm.hotspot.debugger.ia64.IA64ThreadContext
|
||||
@ -93,7 +96,7 @@ SA_LINK_FLAGS = bufferoverflowU.lib
|
||||
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)
|
||||
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)
|
||||
|
@ -2272,7 +2272,9 @@ void os::free_memory(char *addr, size_t bytes) {
|
||||
uncommit_memory(addr, bytes);
|
||||
}
|
||||
|
||||
void os::numa_make_global(char *addr, size_t bytes) { }
|
||||
void os::numa_make_global(char *addr, size_t bytes) {
|
||||
Linux::numa_interleave_memory(addr, bytes);
|
||||
}
|
||||
|
||||
void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) {
|
||||
Linux::numa_tonode_memory(addr, bytes, lgrp_hint);
|
||||
@ -2314,7 +2316,7 @@ char *os::scan_pages(char *start, char* end, page_info* page_expected, page_info
|
||||
extern "C" void numa_warn(int number, char *where, ...) { }
|
||||
extern "C" void numa_error(char *where) { }
|
||||
|
||||
void os::Linux::libnuma_init() {
|
||||
bool os::Linux::libnuma_init() {
|
||||
// sched_getcpu() should be in libc.
|
||||
set_sched_getcpu(CAST_TO_FN_PTR(sched_getcpu_func_t,
|
||||
dlsym(RTLD_DEFAULT, "sched_getcpu")));
|
||||
@ -2330,31 +2332,51 @@ void os::Linux::libnuma_init() {
|
||||
dlsym(handle, "numa_available")));
|
||||
set_numa_tonode_memory(CAST_TO_FN_PTR(numa_tonode_memory_func_t,
|
||||
dlsym(handle, "numa_tonode_memory")));
|
||||
set_numa_interleave_memory(CAST_TO_FN_PTR(numa_interleave_memory_func_t,
|
||||
dlsym(handle, "numa_interleave_memory")));
|
||||
|
||||
|
||||
if (numa_available() != -1) {
|
||||
set_numa_all_nodes((unsigned long*)dlsym(handle, "numa_all_nodes"));
|
||||
// Create a cpu -> node mapping
|
||||
_cpu_to_node = new (ResourceObj::C_HEAP) GrowableArray<int>(0, true);
|
||||
rebuild_cpu_to_node_map();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// rebuild_cpu_to_node_map() constructs a table mapping cpud id to node id.
|
||||
// The table is later used in get_node_by_cpu().
|
||||
void os::Linux::rebuild_cpu_to_node_map() {
|
||||
int cpu_num = os::active_processor_count();
|
||||
const size_t NCPUS = 32768; // Since the buffer size computation is very obscure
|
||||
// in libnuma (possible values are starting from 16,
|
||||
// and continuing up with every other power of 2, but less
|
||||
// than the maximum number of CPUs supported by kernel), and
|
||||
// is a subject to change (in libnuma version 2 the requirements
|
||||
// are more reasonable) we'll just hardcode the number they use
|
||||
// in the library.
|
||||
const size_t BitsPerCLong = sizeof(long) * CHAR_BIT;
|
||||
|
||||
size_t cpu_num = os::active_processor_count();
|
||||
size_t cpu_map_size = NCPUS / BitsPerCLong;
|
||||
size_t cpu_map_valid_size =
|
||||
MIN2((cpu_num + BitsPerCLong - 1) / BitsPerCLong, cpu_map_size);
|
||||
|
||||
cpu_to_node()->clear();
|
||||
cpu_to_node()->at_grow(cpu_num - 1);
|
||||
int node_num = numa_get_groups_num();
|
||||
int cpu_map_size = (cpu_num + BitsPerLong - 1) / BitsPerLong;
|
||||
size_t node_num = numa_get_groups_num();
|
||||
|
||||
unsigned long *cpu_map = NEW_C_HEAP_ARRAY(unsigned long, cpu_map_size);
|
||||
for (int i = 0; i < node_num; i++) {
|
||||
for (size_t i = 0; i < node_num; i++) {
|
||||
if (numa_node_to_cpus(i, cpu_map, cpu_map_size * sizeof(unsigned long)) != -1) {
|
||||
for (int j = 0; j < cpu_map_size; j++) {
|
||||
for (size_t j = 0; j < cpu_map_valid_size; j++) {
|
||||
if (cpu_map[j] != 0) {
|
||||
for (int k = 0; k < BitsPerLong; k++) {
|
||||
for (size_t k = 0; k < BitsPerCLong; k++) {
|
||||
if (cpu_map[j] & (1UL << k)) {
|
||||
cpu_to_node()->at_put(j * BitsPerLong + k, i);
|
||||
cpu_to_node()->at_put(j * BitsPerCLong + k, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2377,7 +2399,8 @@ os::Linux::numa_node_to_cpus_func_t os::Linux::_numa_node_to_cpus;
|
||||
os::Linux::numa_max_node_func_t os::Linux::_numa_max_node;
|
||||
os::Linux::numa_available_func_t os::Linux::_numa_available;
|
||||
os::Linux::numa_tonode_memory_func_t os::Linux::_numa_tonode_memory;
|
||||
|
||||
os::Linux::numa_interleave_memory_func_t os::Linux::_numa_interleave_memory;
|
||||
unsigned long* os::Linux::_numa_all_nodes;
|
||||
|
||||
bool os::uncommit_memory(char* addr, size_t size) {
|
||||
return ::mmap(addr, size,
|
||||
@ -3695,7 +3718,17 @@ jint os::init_2(void)
|
||||
}
|
||||
|
||||
if (UseNUMA) {
|
||||
Linux::libnuma_init();
|
||||
if (!Linux::libnuma_init()) {
|
||||
UseNUMA = false;
|
||||
} else {
|
||||
if ((Linux::numa_max_node() < 1)) {
|
||||
// There's only one node(they start from 0), disable NUMA.
|
||||
UseNUMA = false;
|
||||
}
|
||||
}
|
||||
if (!UseNUMA && ForceNUMA) {
|
||||
UseNUMA = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (MaxFDLimit) {
|
||||
|
@ -146,7 +146,7 @@ class Linux {
|
||||
static bool is_floating_stack() { return _is_floating_stack; }
|
||||
|
||||
static void libpthread_init();
|
||||
static void libnuma_init();
|
||||
static bool libnuma_init();
|
||||
|
||||
// Minimum stack size a thread can be created with (allowing
|
||||
// the VM to completely create the thread and enter user code)
|
||||
@ -240,20 +240,23 @@ private:
|
||||
typedef int (*numa_max_node_func_t)(void);
|
||||
typedef int (*numa_available_func_t)(void);
|
||||
typedef int (*numa_tonode_memory_func_t)(void *start, size_t size, int node);
|
||||
|
||||
typedef void (*numa_interleave_memory_func_t)(void *start, size_t size, unsigned long *nodemask);
|
||||
|
||||
static sched_getcpu_func_t _sched_getcpu;
|
||||
static numa_node_to_cpus_func_t _numa_node_to_cpus;
|
||||
static numa_max_node_func_t _numa_max_node;
|
||||
static numa_available_func_t _numa_available;
|
||||
static numa_tonode_memory_func_t _numa_tonode_memory;
|
||||
static numa_interleave_memory_func_t _numa_interleave_memory;
|
||||
static unsigned long* _numa_all_nodes;
|
||||
|
||||
static void set_sched_getcpu(sched_getcpu_func_t func) { _sched_getcpu = func; }
|
||||
static void set_numa_node_to_cpus(numa_node_to_cpus_func_t func) { _numa_node_to_cpus = func; }
|
||||
static void set_numa_max_node(numa_max_node_func_t func) { _numa_max_node = func; }
|
||||
static void set_numa_available(numa_available_func_t func) { _numa_available = func; }
|
||||
static void set_numa_tonode_memory(numa_tonode_memory_func_t func) { _numa_tonode_memory = func; }
|
||||
|
||||
static void set_numa_interleave_memory(numa_interleave_memory_func_t func) { _numa_interleave_memory = func; }
|
||||
static void set_numa_all_nodes(unsigned long* ptr) { _numa_all_nodes = ptr; }
|
||||
public:
|
||||
static int sched_getcpu() { return _sched_getcpu != NULL ? _sched_getcpu() : -1; }
|
||||
static int numa_node_to_cpus(int node, unsigned long *buffer, int bufferlen) {
|
||||
@ -264,6 +267,11 @@ public:
|
||||
static int numa_tonode_memory(void *start, size_t size, int node) {
|
||||
return _numa_tonode_memory != NULL ? _numa_tonode_memory(start, size, node) : -1;
|
||||
}
|
||||
static void numa_interleave_memory(void *start, size_t size) {
|
||||
if (_numa_interleave_memory != NULL && _numa_all_nodes != NULL) {
|
||||
_numa_interleave_memory(start, size, _numa_all_nodes);
|
||||
}
|
||||
}
|
||||
static int get_node_by_cpu(int cpu_id);
|
||||
};
|
||||
|
||||
|
@ -4638,7 +4638,7 @@ void os::Solaris::synchronization_init() {
|
||||
}
|
||||
}
|
||||
|
||||
void os::Solaris::liblgrp_init() {
|
||||
bool os::Solaris::liblgrp_init() {
|
||||
void *handle = dlopen("liblgrp.so.1", RTLD_LAZY);
|
||||
if (handle != NULL) {
|
||||
os::Solaris::set_lgrp_home(CAST_TO_FN_PTR(lgrp_home_func_t, dlsym(handle, "lgrp_home")));
|
||||
@ -4653,9 +4653,9 @@ void os::Solaris::liblgrp_init() {
|
||||
|
||||
lgrp_cookie_t c = lgrp_init(LGRP_VIEW_CALLER);
|
||||
set_lgrp_cookie(c);
|
||||
} else {
|
||||
warning("your OS does not support NUMA");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void os::Solaris::misc_sym_init() {
|
||||
@ -4824,9 +4824,25 @@ jint os::init_2(void) {
|
||||
vm_page_size()));
|
||||
|
||||
Solaris::libthread_init();
|
||||
|
||||
if (UseNUMA) {
|
||||
Solaris::liblgrp_init();
|
||||
if (!Solaris::liblgrp_init()) {
|
||||
UseNUMA = false;
|
||||
} else {
|
||||
size_t lgrp_limit = os::numa_get_groups_num();
|
||||
int *lgrp_ids = NEW_C_HEAP_ARRAY(int, lgrp_limit);
|
||||
size_t lgrp_num = os::numa_get_leaf_groups(lgrp_ids, lgrp_limit);
|
||||
FREE_C_HEAP_ARRAY(int, lgrp_ids);
|
||||
if (lgrp_num < 2) {
|
||||
// There's only one locality group, disable NUMA.
|
||||
UseNUMA = false;
|
||||
}
|
||||
}
|
||||
if (!UseNUMA && ForceNUMA) {
|
||||
UseNUMA = true;
|
||||
}
|
||||
}
|
||||
|
||||
Solaris::misc_sym_init();
|
||||
Solaris::signal_sets_init();
|
||||
Solaris::init_signal_mem();
|
||||
|
@ -176,7 +176,7 @@ class Solaris {
|
||||
public:
|
||||
static void libthread_init();
|
||||
static void synchronization_init();
|
||||
static void liblgrp_init();
|
||||
static bool liblgrp_init();
|
||||
// Load miscellaneous symbols.
|
||||
static void misc_sym_init();
|
||||
// This boolean allows users to forward their own non-matching signals
|
||||
|
@ -3347,6 +3347,10 @@ jint os::init_2(void) {
|
||||
// initialize thread priority policy
|
||||
prio_init();
|
||||
|
||||
if (UseNUMA && !ForceNUMA) {
|
||||
UseNUMA = false; // Currently unsupported.
|
||||
}
|
||||
|
||||
return JNI_OK;
|
||||
}
|
||||
|
||||
|
@ -676,21 +676,6 @@ GraphBuilder::ScopeData::ScopeData(ScopeData* parent)
|
||||
}
|
||||
|
||||
|
||||
void GraphBuilder::kill_field(ciField* field) {
|
||||
if (UseLocalValueNumbering) {
|
||||
vmap()->kill_field(field);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GraphBuilder::kill_array(Value value) {
|
||||
if (UseLocalValueNumbering) {
|
||||
vmap()->kill_array(value->type());
|
||||
}
|
||||
_memory->store_value(value);
|
||||
}
|
||||
|
||||
|
||||
void GraphBuilder::kill_all() {
|
||||
if (UseLocalValueNumbering) {
|
||||
vmap()->kill_all();
|
||||
@ -987,8 +972,8 @@ void GraphBuilder::store_indexed(BasicType type) {
|
||||
length = append(new ArrayLength(array, lock_stack()));
|
||||
}
|
||||
StoreIndexed* result = new StoreIndexed(array, index, length, type, value, lock_stack());
|
||||
kill_array(value); // invalidate all CSEs that are memory accesses of the same type
|
||||
append(result);
|
||||
_memory->store_value(value);
|
||||
}
|
||||
|
||||
|
||||
@ -1478,9 +1463,6 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
|
||||
case Bytecodes::_putstatic:
|
||||
{ Value val = pop(type);
|
||||
append(new StoreField(append(obj), offset, field, val, true, lock_stack(), state_copy, is_loaded, is_initialized));
|
||||
if (UseLocalValueNumbering) {
|
||||
vmap()->kill_field(field); // invalidate all CSEs that are memory accesses
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Bytecodes::_getfield :
|
||||
@ -1503,7 +1485,6 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
|
||||
if (is_loaded) store = _memory->store(store);
|
||||
if (store != NULL) {
|
||||
append(store);
|
||||
kill_field(field); // invalidate all CSEs that are accesses of this field
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1900,6 +1881,8 @@ Instruction* GraphBuilder::append_with_bci(Instruction* instr, int bci) {
|
||||
assert(i2->bci() != -1, "should already be linked");
|
||||
return i2;
|
||||
}
|
||||
ValueNumberingEffects vne(vmap());
|
||||
i1->visit(&vne);
|
||||
}
|
||||
|
||||
if (i1->as_Phi() == NULL && i1->as_Local() == NULL) {
|
||||
@ -1926,14 +1909,8 @@ Instruction* GraphBuilder::append_with_bci(Instruction* instr, int bci) {
|
||||
assert(_last == i1, "adjust code below");
|
||||
StateSplit* s = i1->as_StateSplit();
|
||||
if (s != NULL && i1->as_BlockEnd() == NULL) {
|
||||
// Continue CSE across certain intrinsics
|
||||
Intrinsic* intrinsic = s->as_Intrinsic();
|
||||
if (UseLocalValueNumbering) {
|
||||
if (intrinsic == NULL || !intrinsic->preserves_state()) {
|
||||
vmap()->kill_all(); // for now, hopefully we need this only for calls eventually
|
||||
}
|
||||
}
|
||||
if (EliminateFieldAccess) {
|
||||
Intrinsic* intrinsic = s->as_Intrinsic();
|
||||
if (s->as_Invoke() != NULL || (intrinsic && !intrinsic->preserves_state())) {
|
||||
_memory->kill();
|
||||
}
|
||||
|
@ -283,8 +283,6 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
|
||||
Dependencies* dependency_recorder() const; // = compilation()->dependencies()
|
||||
bool direct_compare(ciKlass* k);
|
||||
|
||||
void kill_field(ciField* field);
|
||||
void kill_array(Value value);
|
||||
void kill_all();
|
||||
|
||||
ValueStack* lock_stack();
|
||||
|
@ -133,53 +133,77 @@ class ValueNumberingVisitor: public InstructionVisitor {
|
||||
virtual void kill_array(ValueType* type) = 0;
|
||||
|
||||
// visitor functions
|
||||
void do_StoreField (StoreField* x) { kill_field(x->field()); };
|
||||
void do_StoreIndexed (StoreIndexed* x) { kill_array(x->type()); };
|
||||
void do_MonitorEnter (MonitorEnter* x) { kill_memory(); };
|
||||
void do_MonitorExit (MonitorExit* x) { kill_memory(); };
|
||||
void do_Invoke (Invoke* x) { kill_memory(); };
|
||||
void do_UnsafePutRaw (UnsafePutRaw* x) { kill_memory(); };
|
||||
void do_UnsafePutObject(UnsafePutObject* x) { kill_memory(); };
|
||||
void do_Intrinsic (Intrinsic* x) { if (!x->preserves_state()) kill_memory(); };
|
||||
void do_StoreField (StoreField* x) {
|
||||
if (!x->is_initialized()) {
|
||||
kill_memory();
|
||||
} else {
|
||||
kill_field(x->field());
|
||||
}
|
||||
}
|
||||
void do_StoreIndexed (StoreIndexed* x) { kill_array(x->type()); }
|
||||
void do_MonitorEnter (MonitorEnter* x) { kill_memory(); }
|
||||
void do_MonitorExit (MonitorExit* x) { kill_memory(); }
|
||||
void do_Invoke (Invoke* x) { kill_memory(); }
|
||||
void do_UnsafePutRaw (UnsafePutRaw* x) { kill_memory(); }
|
||||
void do_UnsafePutObject(UnsafePutObject* x) { kill_memory(); }
|
||||
void do_Intrinsic (Intrinsic* x) { if (!x->preserves_state()) kill_memory(); }
|
||||
|
||||
void do_Phi (Phi* x) { /* nothing to do */ };
|
||||
void do_Local (Local* x) { /* nothing to do */ };
|
||||
void do_Constant (Constant* x) { /* nothing to do */ };
|
||||
void do_LoadField (LoadField* x) { /* nothing to do */ };
|
||||
void do_ArrayLength (ArrayLength* x) { /* nothing to do */ };
|
||||
void do_LoadIndexed (LoadIndexed* x) { /* nothing to do */ };
|
||||
void do_NegateOp (NegateOp* x) { /* nothing to do */ };
|
||||
void do_ArithmeticOp (ArithmeticOp* x) { /* nothing to do */ };
|
||||
void do_ShiftOp (ShiftOp* x) { /* nothing to do */ };
|
||||
void do_LogicOp (LogicOp* x) { /* nothing to do */ };
|
||||
void do_CompareOp (CompareOp* x) { /* nothing to do */ };
|
||||
void do_IfOp (IfOp* x) { /* nothing to do */ };
|
||||
void do_Convert (Convert* x) { /* nothing to do */ };
|
||||
void do_NullCheck (NullCheck* x) { /* nothing to do */ };
|
||||
void do_NewInstance (NewInstance* x) { /* nothing to do */ };
|
||||
void do_NewTypeArray (NewTypeArray* x) { /* nothing to do */ };
|
||||
void do_NewObjectArray (NewObjectArray* x) { /* nothing to do */ };
|
||||
void do_NewMultiArray (NewMultiArray* x) { /* nothing to do */ };
|
||||
void do_CheckCast (CheckCast* x) { /* nothing to do */ };
|
||||
void do_InstanceOf (InstanceOf* x) { /* nothing to do */ };
|
||||
void do_BlockBegin (BlockBegin* x) { /* nothing to do */ };
|
||||
void do_Goto (Goto* x) { /* nothing to do */ };
|
||||
void do_If (If* x) { /* nothing to do */ };
|
||||
void do_IfInstanceOf (IfInstanceOf* x) { /* nothing to do */ };
|
||||
void do_TableSwitch (TableSwitch* x) { /* nothing to do */ };
|
||||
void do_LookupSwitch (LookupSwitch* x) { /* nothing to do */ };
|
||||
void do_Return (Return* x) { /* nothing to do */ };
|
||||
void do_Throw (Throw* x) { /* nothing to do */ };
|
||||
void do_Base (Base* x) { /* nothing to do */ };
|
||||
void do_OsrEntry (OsrEntry* x) { /* nothing to do */ };
|
||||
void do_ExceptionObject(ExceptionObject* x) { /* nothing to do */ };
|
||||
void do_RoundFP (RoundFP* x) { /* nothing to do */ };
|
||||
void do_UnsafeGetRaw (UnsafeGetRaw* x) { /* nothing to do */ };
|
||||
void do_UnsafeGetObject(UnsafeGetObject* x) { /* nothing to do */ };
|
||||
void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ };
|
||||
void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ };
|
||||
void do_ProfileCall (ProfileCall* x) { /* nothing to do */ };
|
||||
void do_ProfileCounter (ProfileCounter* x) { /* nothing to do */ };
|
||||
void do_Phi (Phi* x) { /* nothing to do */ }
|
||||
void do_Local (Local* x) { /* nothing to do */ }
|
||||
void do_Constant (Constant* x) { /* nothing to do */ }
|
||||
void do_LoadField (LoadField* x) {
|
||||
if (!x->is_initialized()) {
|
||||
kill_memory();
|
||||
}
|
||||
}
|
||||
void do_ArrayLength (ArrayLength* x) { /* nothing to do */ }
|
||||
void do_LoadIndexed (LoadIndexed* x) { /* nothing to do */ }
|
||||
void do_NegateOp (NegateOp* x) { /* nothing to do */ }
|
||||
void do_ArithmeticOp (ArithmeticOp* x) { /* nothing to do */ }
|
||||
void do_ShiftOp (ShiftOp* x) { /* nothing to do */ }
|
||||
void do_LogicOp (LogicOp* x) { /* nothing to do */ }
|
||||
void do_CompareOp (CompareOp* x) { /* nothing to do */ }
|
||||
void do_IfOp (IfOp* x) { /* nothing to do */ }
|
||||
void do_Convert (Convert* x) { /* nothing to do */ }
|
||||
void do_NullCheck (NullCheck* x) { /* nothing to do */ }
|
||||
void do_NewInstance (NewInstance* x) { /* nothing to do */ }
|
||||
void do_NewTypeArray (NewTypeArray* x) { /* nothing to do */ }
|
||||
void do_NewObjectArray (NewObjectArray* x) { /* nothing to do */ }
|
||||
void do_NewMultiArray (NewMultiArray* x) { /* nothing to do */ }
|
||||
void do_CheckCast (CheckCast* x) { /* nothing to do */ }
|
||||
void do_InstanceOf (InstanceOf* x) { /* nothing to do */ }
|
||||
void do_BlockBegin (BlockBegin* x) { /* nothing to do */ }
|
||||
void do_Goto (Goto* x) { /* nothing to do */ }
|
||||
void do_If (If* x) { /* nothing to do */ }
|
||||
void do_IfInstanceOf (IfInstanceOf* x) { /* nothing to do */ }
|
||||
void do_TableSwitch (TableSwitch* x) { /* nothing to do */ }
|
||||
void do_LookupSwitch (LookupSwitch* x) { /* nothing to do */ }
|
||||
void do_Return (Return* x) { /* nothing to do */ }
|
||||
void do_Throw (Throw* x) { /* nothing to do */ }
|
||||
void do_Base (Base* x) { /* nothing to do */ }
|
||||
void do_OsrEntry (OsrEntry* x) { /* nothing to do */ }
|
||||
void do_ExceptionObject(ExceptionObject* x) { /* nothing to do */ }
|
||||
void do_RoundFP (RoundFP* x) { /* nothing to do */ }
|
||||
void do_UnsafeGetRaw (UnsafeGetRaw* x) { /* nothing to do */ }
|
||||
void do_UnsafeGetObject(UnsafeGetObject* x) { /* nothing to do */ }
|
||||
void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ }
|
||||
void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ }
|
||||
void do_ProfileCall (ProfileCall* x) { /* nothing to do */ }
|
||||
void do_ProfileCounter (ProfileCounter* x) { /* nothing to do */ }
|
||||
};
|
||||
|
||||
|
||||
class ValueNumberingEffects: public ValueNumberingVisitor {
|
||||
private:
|
||||
ValueMap* _map;
|
||||
|
||||
public:
|
||||
// implementation for abstract methods of ValueNumberingVisitor
|
||||
void kill_memory() { _map->kill_memory(); }
|
||||
void kill_field(ciField* field) { _map->kill_field(field); }
|
||||
void kill_array(ValueType* type) { _map->kill_array(type); }
|
||||
|
||||
ValueNumberingEffects(ValueMap* map): _map(map) {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -325,24 +325,30 @@ class Par_PushOrMarkClosure: public OopClosure {
|
||||
// For objects in CMS generation, this closure marks
|
||||
// given objects (transitively) as being reachable/live.
|
||||
// This is currently used during the (weak) reference object
|
||||
// processing phase of the CMS final checkpoint step.
|
||||
// processing phase of the CMS final checkpoint step, as
|
||||
// well as during the concurrent precleaning of the discovered
|
||||
// reference lists.
|
||||
class CMSKeepAliveClosure: public OopClosure {
|
||||
private:
|
||||
CMSCollector* _collector;
|
||||
const MemRegion _span;
|
||||
CMSMarkStack* _mark_stack;
|
||||
CMSBitMap* _bit_map;
|
||||
bool _concurrent_precleaning;
|
||||
protected:
|
||||
DO_OOP_WORK_DEFN
|
||||
public:
|
||||
CMSKeepAliveClosure(CMSCollector* collector, MemRegion span,
|
||||
CMSBitMap* bit_map, CMSMarkStack* mark_stack):
|
||||
CMSBitMap* bit_map, CMSMarkStack* mark_stack,
|
||||
bool cpc):
|
||||
_collector(collector),
|
||||
_span(span),
|
||||
_bit_map(bit_map),
|
||||
_mark_stack(mark_stack) {
|
||||
_mark_stack(mark_stack),
|
||||
_concurrent_precleaning(cpc) {
|
||||
assert(!_span.is_empty(), "Empty span could spell trouble");
|
||||
}
|
||||
bool concurrent_precleaning() const { return _concurrent_precleaning; }
|
||||
virtual void do_oop(oop* p);
|
||||
virtual void do_oop(narrowOop* p);
|
||||
inline void do_oop_nv(oop* p) { CMSKeepAliveClosure::do_oop_work(p); }
|
||||
|
@ -538,6 +538,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||
_survivor_chunk_capacity(0), // -- ditto --
|
||||
_survivor_chunk_index(0), // -- ditto --
|
||||
_ser_pmc_preclean_ovflw(0),
|
||||
_ser_kac_preclean_ovflw(0),
|
||||
_ser_pmc_remark_ovflw(0),
|
||||
_par_pmc_remark_ovflw(0),
|
||||
_ser_kac_ovflw(0),
|
||||
@ -1960,6 +1961,7 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
|
||||
|
||||
ref_processor()->set_enqueuing_is_done(false);
|
||||
ref_processor()->enable_discovery();
|
||||
ref_processor()->setup_policy(clear_all_soft_refs);
|
||||
// If an asynchronous collection finishes, the _modUnionTable is
|
||||
// all clear. If we are assuming the collection from an asynchronous
|
||||
// collection, clear the _modUnionTable.
|
||||
@ -2383,6 +2385,9 @@ void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) {
|
||||
Universe::verify(true);
|
||||
}
|
||||
|
||||
// Snapshot the soft reference policy to be used in this collection cycle.
|
||||
ref_processor()->setup_policy(clear_all_soft_refs);
|
||||
|
||||
bool init_mark_was_synchronous = false; // until proven otherwise
|
||||
while (_collectorState != Idling) {
|
||||
if (TraceCMSState) {
|
||||
@ -4388,10 +4393,10 @@ size_t CMSCollector::preclean_work(bool clean_refs, bool clean_survivor) {
|
||||
CMSPrecleanRefsYieldClosure yield_cl(this);
|
||||
assert(rp->span().equals(_span), "Spans should be equal");
|
||||
CMSKeepAliveClosure keep_alive(this, _span, &_markBitMap,
|
||||
&_markStack);
|
||||
&_markStack, true /* preclean */);
|
||||
CMSDrainMarkingStackClosure complete_trace(this,
|
||||
_span, &_markBitMap, &_markStack,
|
||||
&keep_alive);
|
||||
_span, &_markBitMap, &_markStack,
|
||||
&keep_alive, true /* preclean */);
|
||||
|
||||
// We don't want this step to interfere with a young
|
||||
// collection because we don't want to take CPU
|
||||
@ -4590,11 +4595,11 @@ size_t CMSCollector::preclean_mod_union_table(
|
||||
if (!dirtyRegion.is_empty()) {
|
||||
assert(numDirtyCards > 0, "consistency check");
|
||||
HeapWord* stop_point = NULL;
|
||||
stopTimer();
|
||||
CMSTokenSyncWithLocks ts(true, gen->freelistLock(),
|
||||
bitMapLock());
|
||||
startTimer();
|
||||
{
|
||||
stopTimer();
|
||||
CMSTokenSyncWithLocks ts(true, gen->freelistLock(),
|
||||
bitMapLock());
|
||||
startTimer();
|
||||
verify_work_stacks_empty();
|
||||
verify_overflow_empty();
|
||||
sample_eden();
|
||||
@ -4611,10 +4616,6 @@ size_t CMSCollector::preclean_mod_union_table(
|
||||
assert((CMSPermGenPrecleaningEnabled && (gen == _permGen)) ||
|
||||
(_collectorState == AbortablePreclean && should_abort_preclean()),
|
||||
"Unparsable objects should only be in perm gen.");
|
||||
|
||||
stopTimer();
|
||||
CMSTokenSyncWithLocks ts(true, bitMapLock());
|
||||
startTimer();
|
||||
_modUnionTable.mark_range(MemRegion(stop_point, dirtyRegion.end()));
|
||||
if (should_abort_preclean()) {
|
||||
break; // out of preclean loop
|
||||
@ -4852,17 +4853,19 @@ void CMSCollector::checkpointRootsFinalWork(bool asynch,
|
||||
// recurrence of that condition.
|
||||
assert(_markStack.isEmpty(), "No grey objects");
|
||||
size_t ser_ovflw = _ser_pmc_remark_ovflw + _ser_pmc_preclean_ovflw +
|
||||
_ser_kac_ovflw;
|
||||
_ser_kac_ovflw + _ser_kac_preclean_ovflw;
|
||||
if (ser_ovflw > 0) {
|
||||
if (PrintCMSStatistics != 0) {
|
||||
gclog_or_tty->print_cr("Marking stack overflow (benign) "
|
||||
"(pmc_pc="SIZE_FORMAT", pmc_rm="SIZE_FORMAT", kac="SIZE_FORMAT")",
|
||||
"(pmc_pc="SIZE_FORMAT", pmc_rm="SIZE_FORMAT", kac="SIZE_FORMAT
|
||||
", kac_preclean="SIZE_FORMAT")",
|
||||
_ser_pmc_preclean_ovflw, _ser_pmc_remark_ovflw,
|
||||
_ser_kac_ovflw);
|
||||
_ser_kac_ovflw, _ser_kac_preclean_ovflw);
|
||||
}
|
||||
_markStack.expand();
|
||||
_ser_pmc_remark_ovflw = 0;
|
||||
_ser_pmc_preclean_ovflw = 0;
|
||||
_ser_kac_preclean_ovflw = 0;
|
||||
_ser_kac_ovflw = 0;
|
||||
}
|
||||
if (_par_pmc_remark_ovflw > 0 || _par_kac_ovflw > 0) {
|
||||
@ -5675,40 +5678,29 @@ void CMSCollector::refProcessingWork(bool asynch, bool clear_all_soft_refs) {
|
||||
|
||||
ResourceMark rm;
|
||||
HandleMark hm;
|
||||
ReferencePolicy* soft_ref_policy;
|
||||
|
||||
assert(!ref_processor()->enqueuing_is_done(), "Enqueuing should not be complete");
|
||||
// Process weak references.
|
||||
if (clear_all_soft_refs) {
|
||||
soft_ref_policy = new AlwaysClearPolicy();
|
||||
} else {
|
||||
#ifdef COMPILER2
|
||||
soft_ref_policy = new LRUMaxHeapPolicy();
|
||||
#else
|
||||
soft_ref_policy = new LRUCurrentHeapPolicy();
|
||||
#endif // COMPILER2
|
||||
}
|
||||
verify_work_stacks_empty();
|
||||
|
||||
ReferenceProcessor* rp = ref_processor();
|
||||
assert(rp->span().equals(_span), "Spans should be equal");
|
||||
assert(!rp->enqueuing_is_done(), "Enqueuing should not be complete");
|
||||
// Process weak references.
|
||||
rp->setup_policy(clear_all_soft_refs);
|
||||
verify_work_stacks_empty();
|
||||
|
||||
CMSKeepAliveClosure cmsKeepAliveClosure(this, _span, &_markBitMap,
|
||||
&_markStack);
|
||||
&_markStack, false /* !preclean */);
|
||||
CMSDrainMarkingStackClosure cmsDrainMarkingStackClosure(this,
|
||||
_span, &_markBitMap, &_markStack,
|
||||
&cmsKeepAliveClosure);
|
||||
&cmsKeepAliveClosure, false /* !preclean */);
|
||||
{
|
||||
TraceTime t("weak refs processing", PrintGCDetails, false, gclog_or_tty);
|
||||
if (rp->processing_is_mt()) {
|
||||
CMSRefProcTaskExecutor task_executor(*this);
|
||||
rp->process_discovered_references(soft_ref_policy,
|
||||
&_is_alive_closure,
|
||||
rp->process_discovered_references(&_is_alive_closure,
|
||||
&cmsKeepAliveClosure,
|
||||
&cmsDrainMarkingStackClosure,
|
||||
&task_executor);
|
||||
} else {
|
||||
rp->process_discovered_references(soft_ref_policy,
|
||||
&_is_alive_closure,
|
||||
rp->process_discovered_references(&_is_alive_closure,
|
||||
&cmsKeepAliveClosure,
|
||||
&cmsDrainMarkingStackClosure,
|
||||
NULL);
|
||||
@ -6163,8 +6155,8 @@ void CMSCollector::verify_ok_to_terminate() const {
|
||||
#endif
|
||||
|
||||
size_t CMSCollector::block_size_using_printezis_bits(HeapWord* addr) const {
|
||||
assert(_markBitMap.isMarked(addr) && _markBitMap.isMarked(addr + 1),
|
||||
"missing Printezis mark?");
|
||||
assert(_markBitMap.isMarked(addr) && _markBitMap.isMarked(addr + 1),
|
||||
"missing Printezis mark?");
|
||||
HeapWord* nextOneAddr = _markBitMap.getNextMarkedWordAddress(addr + 2);
|
||||
size_t size = pointer_delta(nextOneAddr + 1, addr);
|
||||
assert(size == CompactibleFreeListSpace::adjustObjectSize(size),
|
||||
@ -8302,8 +8294,29 @@ void CMSKeepAliveClosure::do_oop(oop obj) {
|
||||
}
|
||||
)
|
||||
if (simulate_overflow || !_mark_stack->push(obj)) {
|
||||
_collector->push_on_overflow_list(obj);
|
||||
_collector->_ser_kac_ovflw++;
|
||||
if (_concurrent_precleaning) {
|
||||
// We dirty the overflown object and let the remark
|
||||
// phase deal with it.
|
||||
assert(_collector->overflow_list_is_empty(), "Error");
|
||||
// In the case of object arrays, we need to dirty all of
|
||||
// the cards that the object spans. No locking or atomics
|
||||
// are needed since no one else can be mutating the mod union
|
||||
// table.
|
||||
if (obj->is_objArray()) {
|
||||
size_t sz = obj->size();
|
||||
HeapWord* end_card_addr =
|
||||
(HeapWord*)round_to((intptr_t)(addr+sz), CardTableModRefBS::card_size);
|
||||
MemRegion redirty_range = MemRegion(addr, end_card_addr);
|
||||
assert(!redirty_range.is_empty(), "Arithmetical tautology");
|
||||
_collector->_modUnionTable.mark_range(redirty_range);
|
||||
} else {
|
||||
_collector->_modUnionTable.mark(addr);
|
||||
}
|
||||
_collector->_ser_kac_preclean_ovflw++;
|
||||
} else {
|
||||
_collector->push_on_overflow_list(obj);
|
||||
_collector->_ser_kac_ovflw++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8400,6 +8413,8 @@ const char* CMSExpansionCause::to_string(CMSExpansionCause::Cause cause) {
|
||||
void CMSDrainMarkingStackClosure::do_void() {
|
||||
// the max number to take from overflow list at a time
|
||||
const size_t num = _mark_stack->capacity()/4;
|
||||
assert(!_concurrent_precleaning || _collector->overflow_list_is_empty(),
|
||||
"Overflow list should be NULL during concurrent phases");
|
||||
while (!_mark_stack->isEmpty() ||
|
||||
// if stack is empty, check the overflow list
|
||||
_collector->take_from_overflow_list(num, _mark_stack)) {
|
||||
|
@ -592,6 +592,7 @@ class CMSCollector: public CHeapObj {
|
||||
size_t _ser_pmc_preclean_ovflw;
|
||||
size_t _ser_pmc_remark_ovflw;
|
||||
size_t _par_pmc_remark_ovflw;
|
||||
size_t _ser_kac_preclean_ovflw;
|
||||
size_t _ser_kac_ovflw;
|
||||
size_t _par_kac_ovflw;
|
||||
NOT_PRODUCT(size_t _num_par_pushes;)
|
||||
@ -1749,21 +1750,30 @@ class SweepClosure: public BlkClosureCareful {
|
||||
// work-routine/closure used to complete transitive
|
||||
// marking of objects as live after a certain point
|
||||
// in which an initial set has been completely accumulated.
|
||||
// This closure is currently used both during the final
|
||||
// remark stop-world phase, as well as during the concurrent
|
||||
// precleaning of the discovered reference lists.
|
||||
class CMSDrainMarkingStackClosure: public VoidClosure {
|
||||
CMSCollector* _collector;
|
||||
MemRegion _span;
|
||||
CMSMarkStack* _mark_stack;
|
||||
CMSBitMap* _bit_map;
|
||||
CMSKeepAliveClosure* _keep_alive;
|
||||
bool _concurrent_precleaning;
|
||||
public:
|
||||
CMSDrainMarkingStackClosure(CMSCollector* collector, MemRegion span,
|
||||
CMSBitMap* bit_map, CMSMarkStack* mark_stack,
|
||||
CMSKeepAliveClosure* keep_alive):
|
||||
CMSKeepAliveClosure* keep_alive,
|
||||
bool cpc):
|
||||
_collector(collector),
|
||||
_span(span),
|
||||
_bit_map(bit_map),
|
||||
_mark_stack(mark_stack),
|
||||
_keep_alive(keep_alive) { }
|
||||
_keep_alive(keep_alive),
|
||||
_concurrent_precleaning(cpc) {
|
||||
assert(_concurrent_precleaning == _keep_alive->concurrent_precleaning(),
|
||||
"Mismatch");
|
||||
}
|
||||
|
||||
void do_void();
|
||||
};
|
||||
|
@ -811,6 +811,7 @@ void ConcurrentMark::checkpointRootsInitialPost() {
|
||||
ReferenceProcessor* rp = g1h->ref_processor();
|
||||
rp->verify_no_references_recorded();
|
||||
rp->enable_discovery(); // enable ("weak") refs discovery
|
||||
rp->setup_policy(false); // snapshot the soft ref policy to be used in this cycle
|
||||
|
||||
SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
|
||||
satb_mq_set.set_process_completed_threshold(G1SATBProcessCompletedThreshold);
|
||||
@ -1829,32 +1830,21 @@ class G1CMDrainMarkingStackClosure: public VoidClosure {
|
||||
void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
|
||||
ResourceMark rm;
|
||||
HandleMark hm;
|
||||
ReferencePolicy* soft_ref_policy;
|
||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
||||
ReferenceProcessor* rp = g1h->ref_processor();
|
||||
|
||||
// Process weak references.
|
||||
if (clear_all_soft_refs) {
|
||||
soft_ref_policy = new AlwaysClearPolicy();
|
||||
} else {
|
||||
#ifdef COMPILER2
|
||||
soft_ref_policy = new LRUMaxHeapPolicy();
|
||||
#else
|
||||
soft_ref_policy = new LRUCurrentHeapPolicy();
|
||||
#endif
|
||||
}
|
||||
rp->setup_policy(clear_all_soft_refs);
|
||||
assert(_markStack.isEmpty(), "mark stack should be empty");
|
||||
|
||||
G1CollectedHeap* g1 = G1CollectedHeap::heap();
|
||||
G1CMIsAliveClosure g1IsAliveClosure(g1);
|
||||
|
||||
G1CMKeepAliveClosure g1KeepAliveClosure(g1, this, nextMarkBitMap());
|
||||
G1CMIsAliveClosure g1IsAliveClosure (g1h);
|
||||
G1CMKeepAliveClosure g1KeepAliveClosure(g1h, this, nextMarkBitMap());
|
||||
G1CMDrainMarkingStackClosure
|
||||
g1DrainMarkingStackClosure(nextMarkBitMap(), &_markStack,
|
||||
&g1KeepAliveClosure);
|
||||
|
||||
// XXXYYY Also: copy the parallel ref processing code from CMS.
|
||||
ReferenceProcessor* rp = g1->ref_processor();
|
||||
rp->process_discovered_references(soft_ref_policy,
|
||||
&g1IsAliveClosure,
|
||||
rp->process_discovered_references(&g1IsAliveClosure,
|
||||
&g1KeepAliveClosure,
|
||||
&g1DrainMarkingStackClosure,
|
||||
NULL);
|
||||
|
@ -891,6 +891,7 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs,
|
||||
ReferenceProcessorIsAliveMutator rp_is_alive_null(ref_processor(), NULL);
|
||||
|
||||
ref_processor()->enable_discovery();
|
||||
ref_processor()->setup_policy(clear_all_soft_refs);
|
||||
|
||||
// Do collection work
|
||||
{
|
||||
@ -2463,7 +2464,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) {
|
||||
|
||||
COMPILER2_PRESENT(DerivedPointerTable::clear());
|
||||
|
||||
// We want to turn off ref discovere, if necessary, and turn it back on
|
||||
// We want to turn off ref discovery, if necessary, and turn it back on
|
||||
// on again later if we do.
|
||||
bool was_enabled = ref_processor()->discovery_enabled();
|
||||
if (was_enabled) ref_processor()->disable_discovery();
|
||||
|
@ -33,8 +33,9 @@ void G1MarkSweep::invoke_at_safepoint(ReferenceProcessor* rp,
|
||||
|
||||
// hook up weak ref data so it can be used during Mark-Sweep
|
||||
assert(GenMarkSweep::ref_processor() == NULL, "no stomping");
|
||||
GenMarkSweep::_ref_processor = rp;
|
||||
assert(rp != NULL, "should be non-NULL");
|
||||
GenMarkSweep::_ref_processor = rp;
|
||||
rp->setup_policy(clear_all_softrefs);
|
||||
|
||||
// When collecting the permanent generation methodOops may be moving,
|
||||
// so we either have to flush all bcp data or convert it into bci.
|
||||
@ -121,23 +122,12 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading,
|
||||
&GenMarkSweep::follow_root_closure);
|
||||
|
||||
// Process reference objects found during marking
|
||||
ReferencePolicy *soft_ref_policy;
|
||||
if (clear_all_softrefs) {
|
||||
soft_ref_policy = new AlwaysClearPolicy();
|
||||
} else {
|
||||
#ifdef COMPILER2
|
||||
soft_ref_policy = new LRUMaxHeapPolicy();
|
||||
#else
|
||||
soft_ref_policy = new LRUCurrentHeapPolicy();
|
||||
#endif
|
||||
}
|
||||
assert(soft_ref_policy != NULL,"No soft reference policy");
|
||||
GenMarkSweep::ref_processor()->process_discovered_references(
|
||||
soft_ref_policy,
|
||||
&GenMarkSweep::is_alive,
|
||||
&GenMarkSweep::keep_alive,
|
||||
&GenMarkSweep::follow_stack_closure,
|
||||
NULL);
|
||||
ReferenceProcessor* rp = GenMarkSweep::ref_processor();
|
||||
rp->setup_policy(clear_all_softrefs);
|
||||
rp->process_discovered_references(&GenMarkSweep::is_alive,
|
||||
&GenMarkSweep::keep_alive,
|
||||
&GenMarkSweep::follow_stack_closure,
|
||||
NULL);
|
||||
|
||||
// Follow system dictionary roots and unload classes
|
||||
bool purged_class = SystemDictionary::do_unloading(&GenMarkSweep::is_alive);
|
||||
|
@ -759,17 +759,12 @@ void ParNewGeneration::collect(bool full,
|
||||
thread_state_set.steals(),
|
||||
thread_state_set.pops()+thread_state_set.steals());
|
||||
}
|
||||
assert(thread_state_set.pushes() == thread_state_set.pops() + thread_state_set.steals(),
|
||||
assert(thread_state_set.pushes() == thread_state_set.pops()
|
||||
+ thread_state_set.steals(),
|
||||
"Or else the queues are leaky.");
|
||||
|
||||
// For now, process discovered weak refs sequentially.
|
||||
#ifdef COMPILER2
|
||||
ReferencePolicy *soft_ref_policy = new LRUMaxHeapPolicy();
|
||||
#else
|
||||
ReferencePolicy *soft_ref_policy = new LRUCurrentHeapPolicy();
|
||||
#endif // COMPILER2
|
||||
|
||||
// Process (weak) reference objects found during scavenge.
|
||||
ReferenceProcessor* rp = ref_processor();
|
||||
IsAliveClosure is_alive(this);
|
||||
ScanWeakRefClosure scan_weak_ref(this);
|
||||
KeepAliveClosure keep_alive(&scan_weak_ref);
|
||||
@ -778,18 +773,17 @@ void ParNewGeneration::collect(bool full,
|
||||
set_promo_failure_scan_stack_closure(&scan_without_gc_barrier);
|
||||
EvacuateFollowersClosureGeneral evacuate_followers(gch, _level,
|
||||
&scan_without_gc_barrier, &scan_with_gc_barrier);
|
||||
if (ref_processor()->processing_is_mt()) {
|
||||
rp->setup_policy(clear_all_soft_refs);
|
||||
if (rp->processing_is_mt()) {
|
||||
ParNewRefProcTaskExecutor task_executor(*this, thread_state_set);
|
||||
ref_processor()->process_discovered_references(
|
||||
soft_ref_policy, &is_alive, &keep_alive, &evacuate_followers,
|
||||
&task_executor);
|
||||
rp->process_discovered_references(&is_alive, &keep_alive,
|
||||
&evacuate_followers, &task_executor);
|
||||
} else {
|
||||
thread_state_set.flush();
|
||||
gch->set_par_threads(0); // 0 ==> non-parallel.
|
||||
gch->save_marks();
|
||||
ref_processor()->process_discovered_references(
|
||||
soft_ref_policy, &is_alive, &keep_alive, &evacuate_followers,
|
||||
NULL);
|
||||
rp->process_discovered_references(&is_alive, &keep_alive,
|
||||
&evacuate_followers, NULL);
|
||||
}
|
||||
if (!promotion_failed()) {
|
||||
// Swap the survivor spaces.
|
||||
@ -851,14 +845,14 @@ void ParNewGeneration::collect(bool full,
|
||||
|
||||
SpecializationStats::print();
|
||||
|
||||
ref_processor()->set_enqueuing_is_done(true);
|
||||
if (ref_processor()->processing_is_mt()) {
|
||||
rp->set_enqueuing_is_done(true);
|
||||
if (rp->processing_is_mt()) {
|
||||
ParNewRefProcTaskExecutor task_executor(*this, thread_state_set);
|
||||
ref_processor()->enqueue_discovered_references(&task_executor);
|
||||
rp->enqueue_discovered_references(&task_executor);
|
||||
} else {
|
||||
ref_processor()->enqueue_discovered_references(NULL);
|
||||
rp->enqueue_discovered_references(NULL);
|
||||
}
|
||||
ref_processor()->verify_no_references_recorded();
|
||||
rp->verify_no_references_recorded();
|
||||
}
|
||||
|
||||
static int sum;
|
||||
@ -1211,7 +1205,7 @@ ParNewGeneration::take_from_overflow_list(ParScanThreadState* par_scan_state) {
|
||||
int n = 0;
|
||||
while (cur != NULL) {
|
||||
oop obj_to_push = cur->forwardee();
|
||||
oop next = oop(cur->klass());
|
||||
oop next = oop(cur->klass_or_null());
|
||||
cur->set_klass(obj_to_push->klass());
|
||||
if (par_scan_state->should_be_partially_scanned(obj_to_push, cur)) {
|
||||
obj_to_push = cur;
|
||||
|
@ -172,6 +172,7 @@ void PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
|
||||
COMPILER2_PRESENT(DerivedPointerTable::clear());
|
||||
|
||||
ref_processor()->enable_discovery();
|
||||
ref_processor()->setup_policy(clear_all_softrefs);
|
||||
|
||||
mark_sweep_phase1(clear_all_softrefs);
|
||||
|
||||
@ -517,20 +518,9 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
|
||||
|
||||
// Process reference objects found during marking
|
||||
{
|
||||
ReferencePolicy *soft_ref_policy;
|
||||
if (clear_all_softrefs) {
|
||||
soft_ref_policy = new AlwaysClearPolicy();
|
||||
} else {
|
||||
#ifdef COMPILER2
|
||||
soft_ref_policy = new LRUMaxHeapPolicy();
|
||||
#else
|
||||
soft_ref_policy = new LRUCurrentHeapPolicy();
|
||||
#endif // COMPILER2
|
||||
}
|
||||
assert(soft_ref_policy != NULL,"No soft reference policy");
|
||||
ref_processor()->setup_policy(clear_all_softrefs);
|
||||
ref_processor()->process_discovered_references(
|
||||
soft_ref_policy, is_alive_closure(), mark_and_push_closure(),
|
||||
follow_stack_closure(), NULL);
|
||||
is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL);
|
||||
}
|
||||
|
||||
// Follow system dictionary roots and unload classes
|
||||
|
@ -1578,6 +1578,7 @@ void PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
|
||||
COMPILER2_PRESENT(DerivedPointerTable::clear());
|
||||
|
||||
ref_processor()->enable_discovery();
|
||||
ref_processor()->setup_policy(maximum_heap_compaction);
|
||||
|
||||
bool marked_for_unloading = false;
|
||||
|
||||
@ -1894,26 +1895,14 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm,
|
||||
// Process reference objects found during marking
|
||||
{
|
||||
TraceTime tm_r("reference processing", print_phases(), true, gclog_or_tty);
|
||||
ReferencePolicy *soft_ref_policy;
|
||||
if (maximum_heap_compaction) {
|
||||
soft_ref_policy = new AlwaysClearPolicy();
|
||||
} else {
|
||||
#ifdef COMPILER2
|
||||
soft_ref_policy = new LRUMaxHeapPolicy();
|
||||
#else
|
||||
soft_ref_policy = new LRUCurrentHeapPolicy();
|
||||
#endif // COMPILER2
|
||||
}
|
||||
assert(soft_ref_policy != NULL, "No soft reference policy");
|
||||
if (ref_processor()->processing_is_mt()) {
|
||||
RefProcTaskExecutor task_executor;
|
||||
ref_processor()->process_discovered_references(
|
||||
soft_ref_policy, is_alive_closure(), &mark_and_push_closure,
|
||||
&follow_stack_closure, &task_executor);
|
||||
is_alive_closure(), &mark_and_push_closure, &follow_stack_closure,
|
||||
&task_executor);
|
||||
} else {
|
||||
ref_processor()->process_discovered_references(
|
||||
soft_ref_policy, is_alive_closure(), &mark_and_push_closure,
|
||||
&follow_stack_closure, NULL);
|
||||
is_alive_closure(), &mark_and_push_closure, &follow_stack_closure, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -330,6 +330,7 @@ bool PSScavenge::invoke_no_policy() {
|
||||
COMPILER2_PRESENT(DerivedPointerTable::clear());
|
||||
|
||||
reference_processor()->enable_discovery();
|
||||
reference_processor()->setup_policy(false);
|
||||
|
||||
// We track how much was promoted to the next generation for
|
||||
// the AdaptiveSizePolicy.
|
||||
@ -394,24 +395,16 @@ bool PSScavenge::invoke_no_policy() {
|
||||
|
||||
// Process reference objects discovered during scavenge
|
||||
{
|
||||
#ifdef COMPILER2
|
||||
ReferencePolicy *soft_ref_policy = new LRUMaxHeapPolicy();
|
||||
#else
|
||||
ReferencePolicy *soft_ref_policy = new LRUCurrentHeapPolicy();
|
||||
#endif // COMPILER2
|
||||
|
||||
reference_processor()->setup_policy(false); // not always_clear
|
||||
PSKeepAliveClosure keep_alive(promotion_manager);
|
||||
PSEvacuateFollowersClosure evac_followers(promotion_manager);
|
||||
assert(soft_ref_policy != NULL,"No soft reference policy");
|
||||
if (reference_processor()->processing_is_mt()) {
|
||||
PSRefProcTaskExecutor task_executor;
|
||||
reference_processor()->process_discovered_references(
|
||||
soft_ref_policy, &_is_alive_closure, &keep_alive, &evac_followers,
|
||||
&task_executor);
|
||||
&_is_alive_closure, &keep_alive, &evac_followers, &task_executor);
|
||||
} else {
|
||||
reference_processor()->process_discovered_references(
|
||||
soft_ref_policy, &_is_alive_closure, &keep_alive, &evac_followers,
|
||||
NULL);
|
||||
&_is_alive_closure, &keep_alive, &evac_followers, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -414,9 +414,20 @@ size_t MutableNUMASpace::adaptive_chunk_size(int i, size_t limit) {
|
||||
if (limit > 0) {
|
||||
limit = round_down(limit, page_size());
|
||||
if (chunk_size > current_chunk_size(i)) {
|
||||
chunk_size = MIN2((off_t)chunk_size, (off_t)current_chunk_size(i) + (off_t)limit);
|
||||
size_t upper_bound = pages_available * page_size();
|
||||
if (upper_bound > limit &&
|
||||
current_chunk_size(i) < upper_bound - limit) {
|
||||
// The resulting upper bound should not exceed the available
|
||||
// amount of memory (pages_available * page_size()).
|
||||
upper_bound = current_chunk_size(i) + limit;
|
||||
}
|
||||
chunk_size = MIN2(chunk_size, upper_bound);
|
||||
} else {
|
||||
chunk_size = MAX2((off_t)chunk_size, (off_t)current_chunk_size(i) - (off_t)limit);
|
||||
size_t lower_bound = page_size();
|
||||
if (current_chunk_size(i) > limit) { // lower_bound shouldn't underflow.
|
||||
lower_bound = current_chunk_size(i) - limit;
|
||||
}
|
||||
chunk_size = MAX2(chunk_size, lower_bound);
|
||||
}
|
||||
}
|
||||
assert(chunk_size <= pages_available * page_size(), "Chunk size out of range");
|
||||
|
@ -3435,6 +3435,7 @@ referenceProcessor.cpp referenceProcessor.hpp
|
||||
referenceProcessor.cpp systemDictionary.hpp
|
||||
|
||||
referenceProcessor.hpp instanceRefKlass.hpp
|
||||
referenceProcessor.hpp referencePolicy.hpp
|
||||
|
||||
reflection.cpp arguments.hpp
|
||||
reflection.cpp handles.inline.hpp
|
||||
|
@ -540,14 +540,6 @@ void DefNewGeneration::collect(bool full,
|
||||
assert(gch->no_allocs_since_save_marks(0),
|
||||
"save marks have not been newly set.");
|
||||
|
||||
// Weak refs.
|
||||
// FIXME: Are these storage leaks, or are they resource objects?
|
||||
#ifdef COMPILER2
|
||||
ReferencePolicy *soft_ref_policy = new LRUMaxHeapPolicy();
|
||||
#else
|
||||
ReferencePolicy *soft_ref_policy = new LRUCurrentHeapPolicy();
|
||||
#endif // COMPILER2
|
||||
|
||||
// Not very pretty.
|
||||
CollectorPolicy* cp = gch->collector_policy();
|
||||
|
||||
@ -574,8 +566,10 @@ void DefNewGeneration::collect(bool full,
|
||||
evacuate_followers.do_void();
|
||||
|
||||
FastKeepAliveClosure keep_alive(this, &scan_weak_ref);
|
||||
ref_processor()->process_discovered_references(
|
||||
soft_ref_policy, &is_alive, &keep_alive, &evacuate_followers, NULL);
|
||||
ReferenceProcessor* rp = ref_processor();
|
||||
rp->setup_policy(clear_all_soft_refs);
|
||||
rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers,
|
||||
NULL);
|
||||
if (!promotion_failed()) {
|
||||
// Swap the survivor spaces.
|
||||
eden()->clear(SpaceDecorator::Mangle);
|
||||
|
@ -525,8 +525,9 @@ void GenCollectedHeap::do_collection(bool full,
|
||||
if (rp->discovery_is_atomic()) {
|
||||
rp->verify_no_references_recorded();
|
||||
rp->enable_discovery();
|
||||
rp->setup_policy(clear_all_soft_refs);
|
||||
} else {
|
||||
// collect() will enable discovery as appropriate
|
||||
// collect() below will enable discovery as appropriate
|
||||
}
|
||||
_gens[i]->collect(full, clear_all_soft_refs, size, is_tlab);
|
||||
if (!rp->enqueuing_is_done()) {
|
||||
|
@ -31,8 +31,9 @@ void GenMarkSweep::invoke_at_safepoint(int level, ReferenceProcessor* rp,
|
||||
|
||||
// hook up weak ref data so it can be used during Mark-Sweep
|
||||
assert(ref_processor() == NULL, "no stomping");
|
||||
_ref_processor = rp;
|
||||
assert(rp != NULL, "should be non-NULL");
|
||||
_ref_processor = rp;
|
||||
rp->setup_policy(clear_all_softrefs);
|
||||
|
||||
TraceTime t1("Full GC", PrintGC && !PrintGCDetails, true, gclog_or_tty);
|
||||
|
||||
@ -245,20 +246,9 @@ void GenMarkSweep::mark_sweep_phase1(int level,
|
||||
|
||||
// Process reference objects found during marking
|
||||
{
|
||||
ReferencePolicy *soft_ref_policy;
|
||||
if (clear_all_softrefs) {
|
||||
soft_ref_policy = new AlwaysClearPolicy();
|
||||
} else {
|
||||
#ifdef COMPILER2
|
||||
soft_ref_policy = new LRUMaxHeapPolicy();
|
||||
#else
|
||||
soft_ref_policy = new LRUCurrentHeapPolicy();
|
||||
#endif // COMPILER2
|
||||
}
|
||||
assert(soft_ref_policy != NULL,"No soft reference policy");
|
||||
ref_processor()->setup_policy(clear_all_softrefs);
|
||||
ref_processor()->process_discovered_references(
|
||||
soft_ref_policy, &is_alive, &keep_alive,
|
||||
&follow_stack_closure, NULL);
|
||||
&is_alive, &keep_alive, &follow_stack_closure, NULL);
|
||||
}
|
||||
|
||||
// Follow system dictionary roots and unload classes
|
||||
|
@ -26,6 +26,11 @@
|
||||
# include "incls/_referencePolicy.cpp.incl"
|
||||
|
||||
LRUCurrentHeapPolicy::LRUCurrentHeapPolicy() {
|
||||
setup();
|
||||
}
|
||||
|
||||
// Capture state (of-the-VM) information needed to evaluate the policy
|
||||
void LRUCurrentHeapPolicy::setup() {
|
||||
_max_interval = (Universe::get_heap_free_at_last_gc() / M) * SoftRefLRUPolicyMSPerMB;
|
||||
assert(_max_interval >= 0,"Sanity check");
|
||||
}
|
||||
@ -47,6 +52,11 @@ bool LRUCurrentHeapPolicy::should_clear_reference(oop p) {
|
||||
/////////////////////// MaxHeap //////////////////////
|
||||
|
||||
LRUMaxHeapPolicy::LRUMaxHeapPolicy() {
|
||||
setup();
|
||||
}
|
||||
|
||||
// Capture state (of-the-VM) information needed to evaluate the policy
|
||||
void LRUMaxHeapPolicy::setup() {
|
||||
size_t max_heap = MaxHeapSize;
|
||||
max_heap -= Universe::get_heap_used_at_last_gc();
|
||||
max_heap /= M;
|
||||
|
@ -26,9 +26,11 @@
|
||||
// should be cleared.
|
||||
|
||||
|
||||
class ReferencePolicy : public ResourceObj {
|
||||
class ReferencePolicy : public CHeapObj {
|
||||
public:
|
||||
virtual bool should_clear_reference(oop p) { ShouldNotReachHere(); return true; }
|
||||
// Capture state (of-the-VM) information needed to evaluate the policy
|
||||
virtual void setup() { /* do nothing */ }
|
||||
};
|
||||
|
||||
class NeverClearPolicy : public ReferencePolicy {
|
||||
@ -48,6 +50,8 @@ class LRUCurrentHeapPolicy : public ReferencePolicy {
|
||||
public:
|
||||
LRUCurrentHeapPolicy();
|
||||
|
||||
// Capture state (of-the-VM) information needed to evaluate the policy
|
||||
void setup();
|
||||
bool should_clear_reference(oop p);
|
||||
};
|
||||
|
||||
@ -58,5 +62,7 @@ class LRUMaxHeapPolicy : public ReferencePolicy {
|
||||
public:
|
||||
LRUMaxHeapPolicy();
|
||||
|
||||
// Capture state (of-the-VM) information needed to evaluate the policy
|
||||
void setup();
|
||||
bool should_clear_reference(oop p);
|
||||
};
|
||||
|
@ -25,6 +25,11 @@
|
||||
# include "incls/_precompiled.incl"
|
||||
# include "incls/_referenceProcessor.cpp.incl"
|
||||
|
||||
ReferencePolicy* ReferenceProcessor::_always_clear_soft_ref_policy = NULL;
|
||||
ReferencePolicy* ReferenceProcessor::_default_soft_ref_policy = NULL;
|
||||
oop ReferenceProcessor::_sentinelRef = NULL;
|
||||
const int subclasses_of_ref = REF_PHANTOM - REF_OTHER;
|
||||
|
||||
// List of discovered references.
|
||||
class DiscoveredList {
|
||||
public:
|
||||
@ -47,7 +52,9 @@ public:
|
||||
}
|
||||
bool empty() const { return head() == ReferenceProcessor::sentinel_ref(); }
|
||||
size_t length() { return _len; }
|
||||
void set_length(size_t len) { _len = len; }
|
||||
void set_length(size_t len) { _len = len; }
|
||||
void inc_length(size_t inc) { _len += inc; assert(_len > 0, "Error"); }
|
||||
void dec_length(size_t dec) { _len -= dec; }
|
||||
private:
|
||||
// Set value depending on UseCompressedOops. This could be a template class
|
||||
// but then we have to fix all the instantiations and declarations that use this class.
|
||||
@ -56,10 +63,6 @@ private:
|
||||
size_t _len;
|
||||
};
|
||||
|
||||
oop ReferenceProcessor::_sentinelRef = NULL;
|
||||
|
||||
const int subclasses_of_ref = REF_PHANTOM - REF_OTHER;
|
||||
|
||||
void referenceProcessor_init() {
|
||||
ReferenceProcessor::init_statics();
|
||||
}
|
||||
@ -80,6 +83,12 @@ void ReferenceProcessor::init_statics() {
|
||||
}
|
||||
assert(_sentinelRef != NULL && _sentinelRef->is_oop(),
|
||||
"Just constructed it!");
|
||||
_always_clear_soft_ref_policy = new AlwaysClearPolicy();
|
||||
_default_soft_ref_policy = new COMPILER2_PRESENT(LRUMaxHeapPolicy())
|
||||
NOT_COMPILER2(LRUCurrentHeapPolicy());
|
||||
if (_always_clear_soft_ref_policy == NULL || _default_soft_ref_policy == NULL) {
|
||||
vm_exit_during_initialization("Could not allocate reference policy object");
|
||||
}
|
||||
guarantee(RefDiscoveryPolicy == ReferenceBasedDiscovery ||
|
||||
RefDiscoveryPolicy == ReferentBasedDiscovery,
|
||||
"Unrecongnized RefDiscoveryPolicy");
|
||||
@ -106,6 +115,7 @@ ReferenceProcessor::create_ref_processor(MemRegion span,
|
||||
vm_exit_during_initialization("Could not allocate ReferenceProcessor object");
|
||||
}
|
||||
rp->set_is_alive_non_header(is_alive_non_header);
|
||||
rp->setup_policy(false /* default soft ref policy */);
|
||||
return rp;
|
||||
}
|
||||
|
||||
@ -192,7 +202,6 @@ void ReferenceProcessor::update_soft_ref_master_clock() {
|
||||
}
|
||||
|
||||
void ReferenceProcessor::process_discovered_references(
|
||||
ReferencePolicy* policy,
|
||||
BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc,
|
||||
@ -207,7 +216,7 @@ void ReferenceProcessor::process_discovered_references(
|
||||
// Soft references
|
||||
{
|
||||
TraceTime tt("SoftReference", trace_time, false, gclog_or_tty);
|
||||
process_discovered_reflist(_discoveredSoftRefs, policy, true,
|
||||
process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,
|
||||
is_alive, keep_alive, complete_gc, task_executor);
|
||||
}
|
||||
|
||||
@ -436,13 +445,13 @@ public:
|
||||
// The "allow_null_referent" argument tells us to allow for the possibility
|
||||
// of a NULL referent in the discovered Reference object. This typically
|
||||
// happens in the case of concurrent collectors that may have done the
|
||||
// discovery concurrently or interleaved with mutator execution.
|
||||
// discovery concurrently, or interleaved, with mutator execution.
|
||||
inline void load_ptrs(DEBUG_ONLY(bool allow_null_referent));
|
||||
|
||||
// Move to the next discovered reference.
|
||||
inline void next();
|
||||
|
||||
// Remove the current reference from the list and move to the next.
|
||||
// Remove the current reference from the list
|
||||
inline void remove();
|
||||
|
||||
// Make the Reference object active again.
|
||||
@ -476,7 +485,6 @@ public:
|
||||
inline size_t removed() const { return _removed; }
|
||||
)
|
||||
|
||||
private:
|
||||
inline void move_to_next();
|
||||
|
||||
private:
|
||||
@ -553,7 +561,7 @@ inline void DiscoveredListIterator::remove() {
|
||||
oopDesc::store_heap_oop((oop*)_prev_next, _next);
|
||||
}
|
||||
NOT_PRODUCT(_removed++);
|
||||
move_to_next();
|
||||
_refs_list.dec_length(1);
|
||||
}
|
||||
|
||||
inline void DiscoveredListIterator::move_to_next() {
|
||||
@ -591,12 +599,13 @@ ReferenceProcessor::process_phase1(DiscoveredList& refs_list,
|
||||
gclog_or_tty->print_cr("Dropping reference (" INTPTR_FORMAT ": %s" ") by policy",
|
||||
iter.obj(), iter.obj()->blueprint()->internal_name());
|
||||
}
|
||||
// Remove Reference object from list
|
||||
iter.remove();
|
||||
// Make the Reference object active again
|
||||
iter.make_active();
|
||||
// keep the referent around
|
||||
iter.make_referent_alive();
|
||||
// Remove Reference object from list
|
||||
iter.remove();
|
||||
iter.move_to_next();
|
||||
} else {
|
||||
iter.next();
|
||||
}
|
||||
@ -629,12 +638,13 @@ ReferenceProcessor::pp2_work(DiscoveredList& refs_list,
|
||||
iter.obj(), iter.obj()->blueprint()->internal_name());
|
||||
}
|
||||
// The referent is reachable after all.
|
||||
// Remove Reference object from list.
|
||||
iter.remove();
|
||||
// Update the referent pointer as necessary: Note that this
|
||||
// should not entail any recursive marking because the
|
||||
// referent must already have been traversed.
|
||||
iter.make_referent_alive();
|
||||
// Remove Reference object from list
|
||||
iter.remove();
|
||||
iter.move_to_next();
|
||||
} else {
|
||||
iter.next();
|
||||
}
|
||||
@ -670,6 +680,7 @@ ReferenceProcessor::pp2_work_concurrent_discovery(DiscoveredList& refs_list,
|
||||
} else {
|
||||
keep_alive->do_oop((oop*)next_addr);
|
||||
}
|
||||
iter.move_to_next();
|
||||
} else {
|
||||
iter.next();
|
||||
}
|
||||
@ -832,9 +843,9 @@ void ReferenceProcessor::balance_queues(DiscoveredList ref_lists[])
|
||||
}
|
||||
java_lang_ref_Reference::set_discovered(move_tail, ref_lists[to_idx].head());
|
||||
ref_lists[to_idx].set_head(move_head);
|
||||
ref_lists[to_idx].set_length(ref_lists[to_idx].length() + refs_to_move);
|
||||
ref_lists[to_idx].inc_length(refs_to_move);
|
||||
ref_lists[from_idx].set_head(new_head);
|
||||
ref_lists[from_idx].set_length(ref_lists[from_idx].length() - refs_to_move);
|
||||
ref_lists[from_idx].dec_length(refs_to_move);
|
||||
} else {
|
||||
++to_idx;
|
||||
}
|
||||
@ -923,7 +934,6 @@ void ReferenceProcessor::clean_up_discovered_references() {
|
||||
void ReferenceProcessor::clean_up_discovered_reflist(DiscoveredList& refs_list) {
|
||||
assert(!discovery_is_atomic(), "Else why call this method?");
|
||||
DiscoveredListIterator iter(refs_list, NULL, NULL);
|
||||
size_t length = refs_list.length();
|
||||
while (iter.has_next()) {
|
||||
iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */));
|
||||
oop next = java_lang_ref_Reference::next(iter.obj());
|
||||
@ -941,12 +951,11 @@ void ReferenceProcessor::clean_up_discovered_reflist(DiscoveredList& refs_list)
|
||||
)
|
||||
// Remove Reference object from list
|
||||
iter.remove();
|
||||
--length;
|
||||
iter.move_to_next();
|
||||
} else {
|
||||
iter.next();
|
||||
}
|
||||
}
|
||||
refs_list.set_length(length);
|
||||
NOT_PRODUCT(
|
||||
if (PrintGCDetails && TraceReferenceGC) {
|
||||
gclog_or_tty->print(
|
||||
@ -1024,7 +1033,7 @@ ReferenceProcessor::add_to_discovered_list_mt(DiscoveredList& refs_list,
|
||||
// We have separate lists for enqueueing so no synchronization
|
||||
// is necessary.
|
||||
refs_list.set_head(obj);
|
||||
refs_list.set_length(refs_list.length() + 1);
|
||||
refs_list.inc_length(1);
|
||||
if (_discovered_list_needs_barrier) {
|
||||
_bs->write_ref_field((void*)discovered_addr, current_head); guarantee(false, "Needs to be fixed: YSR");
|
||||
}
|
||||
@ -1090,15 +1099,28 @@ bool ReferenceProcessor::discover_reference(oop obj, ReferenceType rt) {
|
||||
// reachable.
|
||||
if (is_alive_non_header() != NULL) {
|
||||
oop referent = java_lang_ref_Reference::referent(obj);
|
||||
// We'd like to assert the following:
|
||||
// assert(referent != NULL, "Refs with null referents already filtered");
|
||||
// However, since this code may be executed concurrently with
|
||||
// mutators, which can clear() the referent, it is not
|
||||
// guaranteed that the referent is non-NULL.
|
||||
// In the case of non-concurrent discovery, the last
|
||||
// disjunct below should hold. It may not hold in the
|
||||
// case of concurrent discovery because mutators may
|
||||
// concurrently clear() a Reference.
|
||||
assert(UseConcMarkSweepGC || UseG1GC || referent != NULL,
|
||||
"Refs with null referents already filtered");
|
||||
if (is_alive_non_header()->do_object_b(referent)) {
|
||||
return false; // referent is reachable
|
||||
}
|
||||
}
|
||||
if (rt == REF_SOFT) {
|
||||
// For soft refs we can decide now if these are not
|
||||
// current candidates for clearing, in which case we
|
||||
// can mark through them now, rather than delaying that
|
||||
// to the reference-processing phase. Since all current
|
||||
// time-stamp policies advance the soft-ref clock only
|
||||
// at a major collection cycle, this is always currently
|
||||
// accurate.
|
||||
if (!_current_soft_ref_policy->should_clear_reference(obj)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
HeapWord* const discovered_addr = java_lang_ref_Reference::discovered_addr(obj);
|
||||
const oop discovered = java_lang_ref_Reference::discovered(obj);
|
||||
@ -1168,7 +1190,7 @@ bool ReferenceProcessor::discover_reference(oop obj, ReferenceType rt) {
|
||||
_bs->write_ref_field((oop*)discovered_addr, current_head);
|
||||
}
|
||||
list->set_head(obj);
|
||||
list->set_length(list->length() + 1);
|
||||
list->inc_length(1);
|
||||
}
|
||||
|
||||
// In the MT discovery case, it is currently possible to see
|
||||
@ -1209,45 +1231,48 @@ void ReferenceProcessor::preclean_discovered_references(
|
||||
TraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC,
|
||||
false, gclog_or_tty);
|
||||
for (int i = 0; i < _num_q; i++) {
|
||||
if (yield->should_return()) {
|
||||
return;
|
||||
}
|
||||
preclean_discovered_reflist(_discoveredSoftRefs[i], is_alive,
|
||||
keep_alive, complete_gc, yield);
|
||||
}
|
||||
}
|
||||
if (yield->should_return()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Weak references
|
||||
{
|
||||
TraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC,
|
||||
false, gclog_or_tty);
|
||||
for (int i = 0; i < _num_q; i++) {
|
||||
if (yield->should_return()) {
|
||||
return;
|
||||
}
|
||||
preclean_discovered_reflist(_discoveredWeakRefs[i], is_alive,
|
||||
keep_alive, complete_gc, yield);
|
||||
}
|
||||
}
|
||||
if (yield->should_return()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Final references
|
||||
{
|
||||
TraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC,
|
||||
false, gclog_or_tty);
|
||||
for (int i = 0; i < _num_q; i++) {
|
||||
if (yield->should_return()) {
|
||||
return;
|
||||
}
|
||||
preclean_discovered_reflist(_discoveredFinalRefs[i], is_alive,
|
||||
keep_alive, complete_gc, yield);
|
||||
}
|
||||
}
|
||||
if (yield->should_return()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Phantom references
|
||||
{
|
||||
TraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC,
|
||||
false, gclog_or_tty);
|
||||
for (int i = 0; i < _num_q; i++) {
|
||||
if (yield->should_return()) {
|
||||
return;
|
||||
}
|
||||
preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive,
|
||||
keep_alive, complete_gc, yield);
|
||||
}
|
||||
@ -1256,9 +1281,12 @@ void ReferenceProcessor::preclean_discovered_references(
|
||||
|
||||
// Walk the given discovered ref list, and remove all reference objects
|
||||
// whose referents are still alive, whose referents are NULL or which
|
||||
// are not active (have a non-NULL next field). NOTE: For this to work
|
||||
// correctly, refs discovery can not be happening concurrently with this
|
||||
// step.
|
||||
// are not active (have a non-NULL next field). NOTE: When we are
|
||||
// thus precleaning the ref lists (which happens single-threaded today),
|
||||
// we do not disable refs discovery to honour the correct semantics of
|
||||
// java.lang.Reference. As a result, we need to be careful below
|
||||
// that ref removal steps interleave safely with ref discovery steps
|
||||
// (in this thread).
|
||||
void
|
||||
ReferenceProcessor::preclean_discovered_reflist(DiscoveredList& refs_list,
|
||||
BoolObjectClosure* is_alive,
|
||||
@ -1266,7 +1294,6 @@ ReferenceProcessor::preclean_discovered_reflist(DiscoveredList& refs_list,
|
||||
VoidClosure* complete_gc,
|
||||
YieldClosure* yield) {
|
||||
DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
|
||||
size_t length = refs_list.length();
|
||||
while (iter.has_next()) {
|
||||
iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */));
|
||||
oop obj = iter.obj();
|
||||
@ -1281,7 +1308,6 @@ ReferenceProcessor::preclean_discovered_reflist(DiscoveredList& refs_list,
|
||||
}
|
||||
// Remove Reference object from list
|
||||
iter.remove();
|
||||
--length;
|
||||
// Keep alive its cohort.
|
||||
iter.make_referent_alive();
|
||||
if (UseCompressedOops) {
|
||||
@ -1291,12 +1317,11 @@ ReferenceProcessor::preclean_discovered_reflist(DiscoveredList& refs_list,
|
||||
oop* next_addr = (oop*)java_lang_ref_Reference::next_addr(obj);
|
||||
keep_alive->do_oop(next_addr);
|
||||
}
|
||||
iter.move_to_next();
|
||||
} else {
|
||||
iter.next();
|
||||
}
|
||||
}
|
||||
refs_list.set_length(length);
|
||||
|
||||
// Close the reachable set
|
||||
complete_gc->do_void();
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
// ReferenceProcessor class encapsulates the per-"collector" processing
|
||||
// of "weak" references for GC. The interface is useful for supporting
|
||||
// of java.lang.Reference objects for GC. The interface is useful for supporting
|
||||
// a generational abstraction, in particular when there are multiple
|
||||
// generations that are being independently collected -- possibly
|
||||
// concurrently and/or incrementally. Note, however, that the
|
||||
@ -75,6 +75,14 @@ class ReferenceProcessor : public CHeapObj {
|
||||
// all collectors but the CMS collector).
|
||||
BoolObjectClosure* _is_alive_non_header;
|
||||
|
||||
// Soft ref clearing policies
|
||||
// . the default policy
|
||||
static ReferencePolicy* _default_soft_ref_policy;
|
||||
// . the "clear all" policy
|
||||
static ReferencePolicy* _always_clear_soft_ref_policy;
|
||||
// . the current policy below is either one of the above
|
||||
ReferencePolicy* _current_soft_ref_policy;
|
||||
|
||||
// The discovered ref lists themselves
|
||||
|
||||
// The MT'ness degree of the queues below
|
||||
@ -90,6 +98,12 @@ class ReferenceProcessor : public CHeapObj {
|
||||
DiscoveredList* discovered_soft_refs() { return _discoveredSoftRefs; }
|
||||
static oop sentinel_ref() { return _sentinelRef; }
|
||||
static oop* adr_sentinel_ref() { return &_sentinelRef; }
|
||||
ReferencePolicy* setup_policy(bool always_clear) {
|
||||
_current_soft_ref_policy = always_clear ?
|
||||
_always_clear_soft_ref_policy : _default_soft_ref_policy;
|
||||
_current_soft_ref_policy->setup(); // snapshot the policy threshold
|
||||
return _current_soft_ref_policy;
|
||||
}
|
||||
|
||||
public:
|
||||
// Process references with a certain reachability level.
|
||||
@ -297,8 +311,7 @@ class ReferenceProcessor : public CHeapObj {
|
||||
bool discover_reference(oop obj, ReferenceType rt);
|
||||
|
||||
// Process references found during GC (called by the garbage collector)
|
||||
void process_discovered_references(ReferencePolicy* policy,
|
||||
BoolObjectClosure* is_alive,
|
||||
void process_discovered_references(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
VoidClosure* complete_gc,
|
||||
AbstractRefProcTaskExecutor* task_executor);
|
||||
|
@ -96,7 +96,7 @@ bool Universe::_bootstrapping = false;
|
||||
bool Universe::_fully_initialized = false;
|
||||
|
||||
size_t Universe::_heap_capacity_at_last_gc;
|
||||
size_t Universe::_heap_used_at_last_gc;
|
||||
size_t Universe::_heap_used_at_last_gc = 0;
|
||||
|
||||
CollectedHeap* Universe::_collectedHeap = NULL;
|
||||
address Universe::_heap_base = NULL;
|
||||
|
@ -92,7 +92,7 @@ inline void oopDesc::set_klass_to_list_ptr(oop k) {
|
||||
// This is only to be used during GC, for from-space objects, so no
|
||||
// barrier is needed.
|
||||
if (UseCompressedOops) {
|
||||
_metadata._compressed_klass = encode_heap_oop_not_null(k);
|
||||
_metadata._compressed_klass = encode_heap_oop(k); // may be null (parnew overflow handling)
|
||||
} else {
|
||||
_metadata._klass = (klassOop)k;
|
||||
}
|
||||
|
@ -395,7 +395,13 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st)
|
||||
OptoReg::regname(OptoReg::c_frame_pointer),
|
||||
regalloc->reg2offset(box_reg));
|
||||
}
|
||||
format_helper( regalloc, st, obj, "MON-OBJ[", i, &scobjs );
|
||||
const char* obj_msg = "MON-OBJ[";
|
||||
if (EliminateLocks) {
|
||||
while( !box->is_BoxLock() ) box = box->in(1);
|
||||
if (box->as_BoxLock()->is_eliminated())
|
||||
obj_msg = "MON-OBJ(LOCK ELIMINATED)[";
|
||||
}
|
||||
format_helper( regalloc, st, obj, obj_msg, i, &scobjs );
|
||||
}
|
||||
|
||||
for (i = 0; i < (uint)scobjs.length(); i++) {
|
||||
@ -908,8 +914,9 @@ void SafePointNode::push_monitor(const FastLockNode *lock) {
|
||||
add_req(lock->box_node());
|
||||
add_req(lock->obj_node());
|
||||
} else {
|
||||
add_req(NULL);
|
||||
add_req(NULL);
|
||||
Node* top = Compile::current()->top();
|
||||
add_req(top);
|
||||
add_req(top);
|
||||
}
|
||||
jvms()->set_scloff(nextmon+MonitorEdges);
|
||||
jvms()->set_endoff(req());
|
||||
@ -1382,7 +1389,7 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
//
|
||||
// If we are locking an unescaped object, the lock/unlock is unnecessary
|
||||
//
|
||||
ConnectionGraph *cgr = Compile::current()->congraph();
|
||||
ConnectionGraph *cgr = phase->C->congraph();
|
||||
PointsToNode::EscapeState es = PointsToNode::GlobalEscape;
|
||||
if (cgr != NULL)
|
||||
es = cgr->escape_state(obj_node(), phase);
|
||||
@ -1450,6 +1457,7 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
|
||||
// Mark it eliminated to update any counters
|
||||
lock->set_eliminated();
|
||||
lock->set_coarsened();
|
||||
}
|
||||
} else if (result != NULL && ctrl->is_Region() &&
|
||||
iter->_worklist.member(ctrl)) {
|
||||
@ -1484,7 +1492,7 @@ Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
//
|
||||
// If we are unlocking an unescaped object, the lock/unlock is unnecessary.
|
||||
//
|
||||
ConnectionGraph *cgr = Compile::current()->congraph();
|
||||
ConnectionGraph *cgr = phase->C->congraph();
|
||||
PointsToNode::EscapeState es = PointsToNode::GlobalEscape;
|
||||
if (cgr != NULL)
|
||||
es = cgr->escape_state(obj_node(), phase);
|
||||
|
@ -780,7 +780,8 @@ public:
|
||||
//------------------------------AbstractLockNode-----------------------------------
|
||||
class AbstractLockNode: public CallNode {
|
||||
private:
|
||||
bool _eliminate; // indicates this lock can be safely eliminated
|
||||
bool _eliminate; // indicates this lock can be safely eliminated
|
||||
bool _coarsened; // indicates this lock was coarsened
|
||||
#ifndef PRODUCT
|
||||
NamedCounter* _counter;
|
||||
#endif
|
||||
@ -801,6 +802,7 @@ protected:
|
||||
public:
|
||||
AbstractLockNode(const TypeFunc *tf)
|
||||
: CallNode(tf, NULL, TypeRawPtr::BOTTOM),
|
||||
_coarsened(false),
|
||||
_eliminate(false)
|
||||
{
|
||||
#ifndef PRODUCT
|
||||
@ -819,6 +821,9 @@ public:
|
||||
// mark node as eliminated and update the counter if there is one
|
||||
void set_eliminated();
|
||||
|
||||
bool is_coarsened() { return _coarsened; }
|
||||
void set_coarsened() { _coarsened = true; }
|
||||
|
||||
// locking does not modify its arguments
|
||||
virtual bool may_modify(const TypePtr *addr_t, PhaseTransform *phase){ return false;}
|
||||
|
||||
|
@ -1532,11 +1532,6 @@ void Compile::Optimize() {
|
||||
|
||||
if (failing()) return;
|
||||
|
||||
// get rid of the connection graph since it's information is not
|
||||
// updated by optimizations
|
||||
_congraph = NULL;
|
||||
|
||||
|
||||
// Loop transforms on the ideal graph. Range Check Elimination,
|
||||
// peeling, unrolling, etc.
|
||||
|
||||
|
@ -199,7 +199,8 @@ PointsToNode::EscapeState ConnectionGraph::escape_state(Node *n, PhaseTransform
|
||||
es = ptnode_adr(idx)->escape_state();
|
||||
|
||||
// if we have already computed a value, return it
|
||||
if (es != PointsToNode::UnknownEscape)
|
||||
if (es != PointsToNode::UnknownEscape &&
|
||||
ptnode_adr(idx)->node_type() == PointsToNode::JavaObject)
|
||||
return es;
|
||||
|
||||
// PointsTo() calls n->uncast() which can return a new ideal node.
|
||||
|
@ -44,10 +44,15 @@ BoxLockNode::BoxLockNode( int slot ) : Node( Compile::current()->root() ),
|
||||
_inmask.Insert(reg);
|
||||
}
|
||||
|
||||
//-----------------------------hash--------------------------------------------
|
||||
uint BoxLockNode::hash() const {
|
||||
return Node::hash() + _slot + (_is_eliminated ? Compile::current()->fixed_slots() : 0);
|
||||
}
|
||||
|
||||
//------------------------------cmp--------------------------------------------
|
||||
uint BoxLockNode::cmp( const Node &n ) const {
|
||||
const BoxLockNode &bn = (const BoxLockNode &)n;
|
||||
return bn._slot == _slot;
|
||||
return bn._slot == _slot && bn._is_eliminated == _is_eliminated;
|
||||
}
|
||||
|
||||
OptoReg::Name BoxLockNode::stack_slot(Node* box_node) {
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
virtual const RegMask &in_RegMask(uint) const;
|
||||
virtual const RegMask &out_RegMask() const;
|
||||
virtual uint size_of() const;
|
||||
virtual uint hash() const { return Node::hash() + _slot; }
|
||||
virtual uint hash() const;
|
||||
virtual uint cmp( const Node &n ) const;
|
||||
virtual const class Type *bottom_type() const { return TypeRawPtr::BOTTOM; }
|
||||
virtual uint ideal_reg() const { return Op_RegP; }
|
||||
|
@ -59,7 +59,7 @@ void PhaseMacroExpand::copy_call_debug_info(CallNode *oldcall, CallNode * newcal
|
||||
for (uint i = old_dbg_start; i < oldcall->req(); i++) {
|
||||
Node* old_in = oldcall->in(i);
|
||||
// Clone old SafePointScalarObjectNodes, adjusting their field contents.
|
||||
if (old_in->is_SafePointScalarObject()) {
|
||||
if (old_in != NULL && old_in->is_SafePointScalarObject()) {
|
||||
SafePointScalarObjectNode* old_sosn = old_in->as_SafePointScalarObject();
|
||||
uint old_unique = C->unique();
|
||||
Node* new_in = old_sosn->clone(jvms_adj, sosn_map);
|
||||
@ -1509,21 +1509,63 @@ bool PhaseMacroExpand::eliminate_locking_node(AbstractLockNode *alock) {
|
||||
if (!alock->is_eliminated()) {
|
||||
return false;
|
||||
}
|
||||
// Mark the box lock as eliminated if all correspondent locks are eliminated
|
||||
// to construct correct debug info.
|
||||
BoxLockNode* box = alock->box_node()->as_BoxLock();
|
||||
if (!box->is_eliminated()) {
|
||||
bool eliminate = true;
|
||||
for (DUIterator_Fast imax, i = box->fast_outs(imax); i < imax; i++) {
|
||||
Node *lck = box->fast_out(i);
|
||||
if (lck->is_Lock() && !lck->as_AbstractLock()->is_eliminated()) {
|
||||
eliminate = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (eliminate)
|
||||
box->set_eliminated();
|
||||
}
|
||||
if (alock->is_Lock() && !alock->is_coarsened()) {
|
||||
// Create new "eliminated" BoxLock node and use it
|
||||
// in monitor debug info for the same object.
|
||||
BoxLockNode* oldbox = alock->box_node()->as_BoxLock();
|
||||
Node* obj = alock->obj_node();
|
||||
if (!oldbox->is_eliminated()) {
|
||||
BoxLockNode* newbox = oldbox->clone()->as_BoxLock();
|
||||
newbox->set_eliminated();
|
||||
transform_later(newbox);
|
||||
// Replace old box node with new box for all users
|
||||
// of the same object.
|
||||
for (uint i = 0; i < oldbox->outcnt();) {
|
||||
|
||||
bool next_edge = true;
|
||||
Node* u = oldbox->raw_out(i);
|
||||
if (u == alock) {
|
||||
i++;
|
||||
continue; // It will be removed below
|
||||
}
|
||||
if (u->is_Lock() &&
|
||||
u->as_Lock()->obj_node() == obj &&
|
||||
// oldbox could be referenced in debug info also
|
||||
u->as_Lock()->box_node() == oldbox) {
|
||||
assert(u->as_Lock()->is_eliminated(), "sanity");
|
||||
_igvn.hash_delete(u);
|
||||
u->set_req(TypeFunc::Parms + 1, newbox);
|
||||
next_edge = false;
|
||||
#ifdef ASSERT
|
||||
} else if (u->is_Unlock() && u->as_Unlock()->obj_node() == obj) {
|
||||
assert(u->as_Unlock()->is_eliminated(), "sanity");
|
||||
#endif
|
||||
}
|
||||
// Replace old box in monitor debug info.
|
||||
if (u->is_SafePoint() && u->as_SafePoint()->jvms()) {
|
||||
SafePointNode* sfn = u->as_SafePoint();
|
||||
JVMState* youngest_jvms = sfn->jvms();
|
||||
int max_depth = youngest_jvms->depth();
|
||||
for (int depth = 1; depth <= max_depth; depth++) {
|
||||
JVMState* jvms = youngest_jvms->of_depth(depth);
|
||||
int num_mon = jvms->nof_monitors();
|
||||
// Loop over monitors
|
||||
for (int idx = 0; idx < num_mon; idx++) {
|
||||
Node* obj_node = sfn->monitor_obj(jvms, idx);
|
||||
Node* box_node = sfn->monitor_box(jvms, idx);
|
||||
if (box_node == oldbox && obj_node == obj) {
|
||||
int j = jvms->monitor_box_offset(idx);
|
||||
_igvn.hash_delete(u);
|
||||
u->set_req(j, newbox);
|
||||
next_edge = false;
|
||||
}
|
||||
} // for (int idx = 0;
|
||||
} // for (int depth = 1;
|
||||
} // if (u->is_SafePoint()
|
||||
if (next_edge) i++;
|
||||
} // for (uint i = 0; i < oldbox->outcnt();)
|
||||
} // if (!oldbox->is_eliminated())
|
||||
} // if (alock->is_Lock() && !lock->is_coarsened())
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (PrintEliminateLocks) {
|
||||
@ -1562,6 +1604,15 @@ bool PhaseMacroExpand::eliminate_locking_node(AbstractLockNode *alock) {
|
||||
_igvn.subsume_node(ctrlproj, fallthroughproj);
|
||||
_igvn.hash_delete(memproj);
|
||||
_igvn.subsume_node(memproj, memproj_fallthrough);
|
||||
|
||||
// Delete FastLock node also if this Lock node is unique user
|
||||
// (a loop peeling may clone a Lock node).
|
||||
Node* flock = alock->as_Lock()->fastlock_node();
|
||||
if (flock->outcnt() == 1) {
|
||||
assert(flock->unique_out() == alock, "sanity");
|
||||
_igvn.hash_delete(flock);
|
||||
_igvn.subsume_node(flock, top());
|
||||
}
|
||||
}
|
||||
|
||||
// Seach for MemBarRelease node and delete it also.
|
||||
@ -1887,8 +1938,28 @@ void PhaseMacroExpand::expand_unlock_node(UnlockNode *unlock) {
|
||||
bool PhaseMacroExpand::expand_macro_nodes() {
|
||||
if (C->macro_count() == 0)
|
||||
return false;
|
||||
// attempt to eliminate allocations
|
||||
// First, attempt to eliminate locks
|
||||
bool progress = true;
|
||||
while (progress) {
|
||||
progress = false;
|
||||
for (int i = C->macro_count(); i > 0; i--) {
|
||||
Node * n = C->macro_node(i-1);
|
||||
bool success = false;
|
||||
debug_only(int old_macro_count = C->macro_count(););
|
||||
if (n->is_AbstractLock()) {
|
||||
success = eliminate_locking_node(n->as_AbstractLock());
|
||||
} else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) {
|
||||
_igvn.add_users_to_worklist(n);
|
||||
_igvn.hash_delete(n);
|
||||
_igvn.subsume_node(n, n->in(1));
|
||||
success = true;
|
||||
}
|
||||
assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");
|
||||
progress = progress || success;
|
||||
}
|
||||
}
|
||||
// Next, attempt to eliminate allocations
|
||||
progress = true;
|
||||
while (progress) {
|
||||
progress = false;
|
||||
for (int i = C->macro_count(); i > 0; i--) {
|
||||
@ -1902,17 +1973,10 @@ bool PhaseMacroExpand::expand_macro_nodes() {
|
||||
break;
|
||||
case Node::Class_Lock:
|
||||
case Node::Class_Unlock:
|
||||
success = eliminate_locking_node(n->as_AbstractLock());
|
||||
assert(!n->as_AbstractLock()->is_eliminated(), "sanity");
|
||||
break;
|
||||
default:
|
||||
if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) {
|
||||
_igvn.add_users_to_worklist(n);
|
||||
_igvn.hash_delete(n);
|
||||
_igvn.subsume_node(n, n->in(1));
|
||||
success = true;
|
||||
} else {
|
||||
assert(false, "unknown node type in macro list");
|
||||
}
|
||||
assert(false, "unknown node type in macro list");
|
||||
}
|
||||
assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");
|
||||
progress = progress || success;
|
||||
|
@ -849,10 +849,8 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) {
|
||||
// Loop over monitors and insert into array
|
||||
for(idx = 0; idx < num_mon; idx++) {
|
||||
// Grab the node that defines this monitor
|
||||
Node* box_node;
|
||||
Node* obj_node;
|
||||
box_node = sfn->monitor_box(jvms, idx);
|
||||
obj_node = sfn->monitor_obj(jvms, idx);
|
||||
Node* box_node = sfn->monitor_box(jvms, idx);
|
||||
Node* obj_node = sfn->monitor_obj(jvms, idx);
|
||||
|
||||
// Create ScopeValue for object
|
||||
ScopeValue *scval = NULL;
|
||||
@ -890,6 +888,7 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) {
|
||||
|
||||
OptoReg::Name box_reg = BoxLockNode::stack_slot(box_node);
|
||||
Location basic_lock = Location::new_stk_loc(Location::normal,_regalloc->reg2offset(box_reg));
|
||||
while( !box_node->is_BoxLock() ) box_node = box_node->in(1);
|
||||
monarray->append(new MonitorValue(scval, basic_lock, box_node->as_BoxLock()->is_eliminated()));
|
||||
}
|
||||
|
||||
|
@ -342,6 +342,9 @@ class CommandLineFlags {
|
||||
product(bool, UseNUMA, false, \
|
||||
"Use NUMA if available") \
|
||||
\
|
||||
product(bool, ForceNUMA, false, \
|
||||
"Force NUMA optimizations on single-node/UMA systems") \
|
||||
\
|
||||
product(intx, NUMAChunkResizeWeight, 20, \
|
||||
"Percentage (0-100) used to weight the current sample when " \
|
||||
"computing exponentially decaying average for " \
|
||||
@ -1474,7 +1477,7 @@ class CommandLineFlags {
|
||||
"CMSPrecleanNumerator:CMSPrecleanDenominator yields convergence" \
|
||||
" ratio") \
|
||||
\
|
||||
product(bool, CMSPrecleanRefLists1, false, \
|
||||
product(bool, CMSPrecleanRefLists1, true, \
|
||||
"Preclean ref lists during (initial) preclean phase") \
|
||||
\
|
||||
product(bool, CMSPrecleanRefLists2, false, \
|
||||
|
@ -65,8 +65,10 @@
|
||||
// COMPILER2 variant
|
||||
#ifdef COMPILER2
|
||||
#define COMPILER2_PRESENT(code) code
|
||||
#define NOT_COMPILER2(code)
|
||||
#else // COMPILER2
|
||||
#define COMPILER2_PRESENT(code)
|
||||
#define NOT_COMPILER2(code) code
|
||||
#endif // COMPILER2
|
||||
|
||||
|
||||
|
55
hotspot/test/compiler/6756768/Test6756768.java
Normal file
55
hotspot/test/compiler/6756768/Test6756768.java
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 6756768
|
||||
* @summary C1 generates invalid code
|
||||
*
|
||||
* @run main/othervm -Xcomp Test6756768
|
||||
*/
|
||||
|
||||
class Test6756768a
|
||||
{
|
||||
static boolean var_1 = true;
|
||||
}
|
||||
|
||||
final class Test6756768b
|
||||
{
|
||||
static boolean var_24 = false;
|
||||
static int var_25 = 0;
|
||||
|
||||
static boolean var_temp1 = Test6756768a.var_1 = false;
|
||||
}
|
||||
|
||||
public final class Test6756768 extends Test6756768a
|
||||
{
|
||||
final static int var = var_1 ^ (Test6756768b.var_24 ? var_1 : var_1) ? Test6756768b.var_25 : 1;
|
||||
|
||||
static public void main(String[] args) {
|
||||
if (var != 0) {
|
||||
throw new InternalError("var = " + var);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
55
hotspot/test/compiler/6756768/Test6756768_2.java
Normal file
55
hotspot/test/compiler/6756768/Test6756768_2.java
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 6756768
|
||||
* @summary C1 generates invalid code
|
||||
*
|
||||
* @run main/othervm -Xcomp Test6756768_2
|
||||
*/
|
||||
|
||||
class Test6756768_2a {
|
||||
static int var = ++Test6756768_2.var;
|
||||
}
|
||||
|
||||
public class Test6756768_2 {
|
||||
static int var = 1;
|
||||
|
||||
static Object d2 = null;
|
||||
|
||||
static void test_static_field() {
|
||||
int v = var;
|
||||
int v2 = Test6756768_2a.var;
|
||||
int v3 = var;
|
||||
var = v3;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
var = 1;
|
||||
test_static_field();
|
||||
if (var != 2) {
|
||||
throw new InternalError();
|
||||
}
|
||||
}
|
||||
}
|
67
hotspot/test/compiler/6775880/Test.java
Normal file
67
hotspot/test/compiler/6775880/Test.java
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 6775880
|
||||
* @summary EA +DeoptimizeALot: assert(mon_info->owner()->is_locked(),"object must be locked now")
|
||||
* @compile -source 1.4 -target 1.4 Test.java
|
||||
* @run main/othervm -server -Xbatch -XX:+DoEscapeAnalysis -XX:+DeoptimizeALot -XX:CompileCommand=exclude,java.lang.AbstractStringBuilder::append Test
|
||||
*/
|
||||
|
||||
public class Test {
|
||||
|
||||
int cnt;
|
||||
int b[];
|
||||
String s;
|
||||
|
||||
String test() {
|
||||
String res="";
|
||||
for (int i=0; i < cnt; i++) {
|
||||
if (i != 0) {
|
||||
res = res +".";
|
||||
}
|
||||
res = res + b[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Test t = new Test();
|
||||
t.cnt = 3;
|
||||
t.b = new int[3];
|
||||
t.b[0] = 0;
|
||||
t.b[1] = 1;
|
||||
t.b[2] = 2;
|
||||
int j=0;
|
||||
t.s = "";
|
||||
for (int i=0; i<10001; i++) {
|
||||
t.s = "c";
|
||||
t.s = t.test();
|
||||
}
|
||||
System.out.println("After s=" + t.s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,3 +14,4 @@ c84ca638db42a8b6b227b4e3b63bca192c5ca634 jdk7-b36
|
||||
af49591bc486d82aa04b832257de0d18adc9af52 jdk7-b37
|
||||
e9f750f0a3a00413a7b77028b2ecdabb7129ae32 jdk7-b38
|
||||
831b80be6cea8e7d7da197ccdac5fd4c701a5033 jdk7-b39
|
||||
54946f466e2c047c44c903f1bec400b685c2508e jdk7-b40
|
||||
|
@ -14,3 +14,4 @@ f60187f44a0d62906a5e2f6bd0989b5b24c1ca1e jdk7-b36
|
||||
a2a6f9edf761934faf59ea60d7fe7178371302cd jdk7-b37
|
||||
9ce439969184c753a9ba3caf8ed277b05230f2e5 jdk7-b38
|
||||
077bc9b1b035a409a76bd5366f73ed9dd9846934 jdk7-b39
|
||||
70a6ac6dd737fe45c2fadb57646195b2b4fe269d jdk7-b40
|
||||
|
@ -14,3 +14,4 @@ cf4894b78ceb966326e93bf221db0c2d14d59218 jdk7-b35
|
||||
14f50aee4989b75934d385c56a83da0c23d2f68b jdk7-b37
|
||||
cc5f810b5af8a3a83b0df5a29d9e24d7a0ff8086 jdk7-b38
|
||||
4e51997582effa006dde5c6d8b8820b2045b9c7f jdk7-b39
|
||||
2201dad60231a3c3e0346e3a0250d69ca3b71fd4 jdk7-b40
|
||||
|
@ -69,9 +69,9 @@ public class ServiceName {
|
||||
/**
|
||||
* 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.
|
||||
|
@ -41,7 +41,7 @@ public class EventParams {
|
||||
|
||||
@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);
|
||||
|
@ -29,6 +29,7 @@ import com.sun.jmx.remote.util.ClassLogger;
|
||||
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 @@ public class LeaseManager {
|
||||
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");
|
||||
|
@ -55,9 +55,19 @@ import javax.management.namespace.JMXNamespaces;
|
||||
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 @@ public class SingleMBeanForwarder extends IdentityMBeanServerForwarder {
|
||||
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 @@ public class SingleMBeanForwarder extends IdentityMBeanServerForwarder {
|
||||
|
||||
@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 @@ public class SingleMBeanForwarder extends IdentityMBeanServerForwarder {
|
||||
@Override
|
||||
public Integer getMBeanCount() {
|
||||
Integer count = super.getMBeanCount();
|
||||
if (!super.isRegistered(mbeanName))
|
||||
if (visible && !super.isRegistered(mbeanName))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
@ -284,7 +306,7 @@ public class SingleMBeanForwarder extends IdentityMBeanServerForwarder {
|
||||
*/
|
||||
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 @@ public class SingleMBeanForwarder extends IdentityMBeanServerForwarder {
|
||||
@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 @@ public class SingleMBeanForwarder extends IdentityMBeanServerForwarder {
|
||||
@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;
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ public final class JmxMBeanServer
|
||||
* {@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 @@ public final class JmxMBeanServer
|
||||
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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -49,11 +49,6 @@ public class ObjectNameRouter {
|
||||
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 @@ public class ObjectNameRouter {
|
||||
b.append(NAMESPACE_SEPARATOR);
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -31,7 +31,6 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.namespace.JMXNamespaces;
|
||||
|
||||
|
||||
/**
|
||||
@ -57,22 +56,14 @@ public class RoutingConnectionProxy
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of RoutingConnectionProxy
|
||||
*/
|
||||
public RoutingConnectionProxy(MBeanServerConnection source,
|
||||
String sourceDir) {
|
||||
this(source,sourceDir,"",false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of RoutingConnectionProxy
|
||||
*/
|
||||
public RoutingConnectionProxy(MBeanServerConnection source,
|
||||
String sourceDir,
|
||||
String targetDir,
|
||||
boolean forwardsContext) {
|
||||
super(source,sourceDir,targetDir,forwardsContext);
|
||||
boolean probe) {
|
||||
super(source, sourceDir, targetDir, probe);
|
||||
|
||||
if (LOG.isLoggable(Level.FINER))
|
||||
LOG.finer("RoutingConnectionProxy for " + getSourceNamespace() +
|
||||
@ -85,15 +76,13 @@ public class RoutingConnectionProxy
|
||||
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 @@ public class RoutingConnectionProxy
|
||||
<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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import java.io.IOException;
|
||||
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 @@ import javax.management.namespace.JMXNamespaces;
|
||||
// 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 @@ public abstract class RoutingProxy<T extends MBeanServerConnection>
|
||||
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 @@ public abstract class RoutingProxy<T extends MBeanServerConnection>
|
||||
// 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 @@ public abstract class RoutingProxy<T extends MBeanServerConnection>
|
||||
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 @@ public abstract class RoutingProxy<T extends MBeanServerConnection>
|
||||
@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 @@ public abstract class RoutingProxy<T extends MBeanServerConnection>
|
||||
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 abstract class RoutingProxy<T extends MBeanServerConnection>
|
||||
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 @@ public abstract class RoutingProxy<T extends MBeanServerConnection>
|
||||
// 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 @@ public abstract class RoutingProxy<T extends MBeanServerConnection>
|
||||
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 @@ public abstract class RoutingProxy<T extends MBeanServerConnection>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,6 @@ import javax.management.OperationsException;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.loading.ClassLoaderRepository;
|
||||
import javax.management.namespace.JMXNamespaces;
|
||||
|
||||
/**
|
||||
* A RoutingServerProxy is an MBeanServer proxy that proxies a
|
||||
@ -76,19 +75,11 @@ public class RoutingServerProxy
|
||||
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 @@ public class RoutingServerProxy
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -430,13 +430,11 @@ public class EventClientConnection implements InvocationHandler,
|
||||
* 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");
|
||||
|
@ -497,6 +497,10 @@ public class HttpsURLConnectionOldImpl
|
||||
delegate.setFixedLengthStreamingMode(contentLength);
|
||||
}
|
||||
|
||||
public void setFixedLengthStreamingMode(long contentLength) {
|
||||
delegate.setFixedLengthStreamingMode(contentLength);
|
||||
}
|
||||
|
||||
public void setChunkedStreamingMode (int chunklen) {
|
||||
delegate.setChunkedStreamingMode(chunklen);
|
||||
}
|
||||
|
@ -86,6 +86,8 @@ import sun.misc.HexDumpEncoder;
|
||||
* 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 @@ import sun.misc.HexDumpEncoder;
|
||||
* 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 @@ import sun.misc.HexDumpEncoder;
|
||||
* <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 @@ import sun.misc.HexDumpEncoder;
|
||||
* 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 @@ import sun.misc.HexDumpEncoder;
|
||||
*</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 @@ import sun.misc.HexDumpEncoder;
|
||||
* 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 @@ import sun.misc.HexDumpEncoder;
|
||||
* 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 @@ import sun.misc.HexDumpEncoder;
|
||||
* 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 @@ import sun.misc.HexDumpEncoder;
|
||||
* 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 @@ import sun.misc.HexDumpEncoder;
|
||||
* 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 @@ import sun.misc.HexDumpEncoder;
|
||||
* 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 @@ public class Krb5LoginModule implements LoginModule {
|
||||
}
|
||||
|
||||
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 @@ public class Krb5LoginModule implements LoginModule {
|
||||
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"
|
||||
|
@ -73,10 +73,23 @@ abstract public class HttpURLConnection extends URLConnection {
|
||||
* 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>
|
||||
@ -109,6 +122,9 @@ abstract public class HttpURLConnection extends URLConnection {
|
||||
* 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 @@ abstract public class HttpURLConnection extends URLConnection {
|
||||
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 @@ abstract public class HttpURLConnection extends URLConnection {
|
||||
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;
|
||||
|
@ -113,7 +113,7 @@ public class CertPathValidatorException extends GeneralSecurityException {
|
||||
* permitted, and indicates that the cause is nonexistent or unknown.)
|
||||
*/
|
||||
public CertPathValidatorException(Throwable cause) {
|
||||
this(null, cause);
|
||||
this((cause == null ? null : cause.toString()), cause);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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 @@ package javax.management;
|
||||
|
||||
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 @@ import java.util.List;
|
||||
*/
|
||||
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,13 +130,63 @@ public class AttributeList extends ArrayList<Object> {
|
||||
|
||||
// Check for non-Attribute objects
|
||||
//
|
||||
checkTypeSafe(list);
|
||||
adding(list);
|
||||
|
||||
// Build the List<Attribute>
|
||||
//
|
||||
super.addAll(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* <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
|
||||
@ -154,11 +210,9 @@ public class AttributeList extends ArrayList<Object> {
|
||||
*/
|
||||
@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 @@ public class AttributeList extends ArrayList<Object> {
|
||||
* 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 class AttributeList extends ArrayList<Object> {
|
||||
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 @@ public class AttributeList extends ArrayList<Object> {
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
1091
jdk/src/share/classes/javax/management/ClientContext.java
Normal file
1091
jdk/src/share/classes/javax/management/ClientContext.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -35,8 +35,8 @@ import java.io.Serializable;
|
||||
// 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 @@ import javax.management.openmbean.OpenType;
|
||||
* 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 @@ import javax.management.openmbean.OpenType;
|
||||
* 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 @@ import javax.management.openmbean.OpenType;
|
||||
* <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>
|
||||
*
|
||||
|
@ -30,6 +30,7 @@ import com.sun.jmx.mbeanserver.MBeanInjector;
|
||||
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.Method;
|
||||
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 class JMX {
|
||||
*/
|
||||
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.
|
||||
@ -78,6 +95,12 @@ public class JMX {
|
||||
*/
|
||||
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 @@ public class JMX {
|
||||
* <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 @@ public class JMX {
|
||||
((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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.util.WeakHashMap;
|
||||
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 @@ public class MBeanInfo implements Cloneable, Serializable, DescriptorRead {
|
||||
* <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 @@ public class MBeanInfo implements Cloneable, Serializable, DescriptorRead {
|
||||
return (Descriptor) nonNullDescriptor(descriptor).clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return
|
||||
getClass().getName() + "[" +
|
||||
@ -505,6 +514,7 @@ public class MBeanInfo implements Cloneable, Serializable, DescriptorRead {
|
||||
* @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 @@ public class MBeanInfo implements Cloneable, Serializable, DescriptorRead {
|
||||
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 @@ public class MBeanInfo implements Cloneable, Serializable, DescriptorRead {
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -532,8 +532,30 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
|
||||
|
||||
/**
|
||||
* 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 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
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 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
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 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
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 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
* @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.
|
||||
*
|
||||
|
@ -27,15 +27,70 @@ package javax.management;
|
||||
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
@ -54,7 +54,7 @@ import com.sun.jmx.mbeanserver.GetPropertyAction;
|
||||
* @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
|
||||
@ -243,6 +243,26 @@ public class Notification extends EventObject {
|
||||
this.message = message ;
|
||||
}
|
||||
|
||||
/**
|
||||
* <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.
|
||||
*
|
||||
@ -285,8 +305,10 @@ public class Notification extends EventObject {
|
||||
/**
|
||||
* 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,14 +339,25 @@ public class Notification extends EventObject {
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@ -355,6 +388,7 @@ public class Notification extends EventObject {
|
||||
*
|
||||
* @return A String representation of this notification.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString()+"[type="+type+"][message="+message+"]";
|
||||
}
|
||||
|
@ -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 @@ import java.util.Set;
|
||||
* 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"},
|
||||
|
@ -29,7 +29,6 @@ import com.sun.jmx.event.DaemonThreadFactory;
|
||||
import com.sun.jmx.event.LeaseRenewer;
|
||||
import com.sun.jmx.event.ReceiverBuffer;
|
||||
import com.sun.jmx.event.RepeatedSingletonJob;
|
||||
import com.sun.jmx.namespace.JMXNamespaceUtils;
|
||||
import com.sun.jmx.mbeanserver.PerThreadGroupPool;
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
|
||||
@ -58,7 +57,6 @@ import javax.management.NotificationBroadcasterSupport;
|
||||
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 class EventClient implements EventConsumer, NotificationManager {
|
||||
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 class EventClient implements EventConsumer, NotificationManager {
|
||||
*/
|
||||
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 @@ public class EventClient implements EventConsumer, NotificationManager {
|
||||
* 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 @@ public class EventClient implements EventConsumer, NotificationManager {
|
||||
}
|
||||
|
||||
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 @@ public class EventClient implements EventConsumer, NotificationManager {
|
||||
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 @@ public class EventClient implements EventConsumer, NotificationManager {
|
||||
// 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 @@ public class EventClient implements EventConsumer, NotificationManager {
|
||||
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 @@ public class EventClient implements EventConsumer, NotificationManager {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JMX Connector that will use an {@link EventClient}
|
||||
* to subscribe for notifications. If the server doesn't have
|
||||
* an {@link EventClientDelegateMBean}, then the connector will
|
||||
* use the legacy notification mechanism instead.
|
||||
*
|
||||
* @param wrapped The underlying JMX Connector wrapped by the returned
|
||||
* connector.
|
||||
*
|
||||
* @return A JMX Connector that will uses an {@link EventClient}, if
|
||||
* available.
|
||||
*
|
||||
* @see EventClient#getEventClientConnection(MBeanServerConnection)
|
||||
*/
|
||||
public static JMXConnector withEventClient(final JMXConnector wrapped) {
|
||||
return JMXNamespaceUtils.withEventClient(wrapped);
|
||||
}
|
||||
|
||||
private static final PerThreadGroupPool<ScheduledThreadPoolExecutor>
|
||||
leaseRenewerThreadPool = PerThreadGroupPool.make();
|
||||
}
|
||||
|
@ -149,6 +149,7 @@ public class EventClientDelegate implements EventClientDelegateMBean {
|
||||
// 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 @@ public class EventClientDelegate implements EventClientDelegateMBean {
|
||||
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 @@ public class EventClientDelegate implements EventClientDelegateMBean {
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedAction<EventClientDelegate>() {
|
||||
public EventClientDelegate run() {
|
||||
return getEventClientDelegate(Forwarder.this);
|
||||
return getEventClientDelegate(loopMBS);
|
||||
}
|
||||
});
|
||||
DynamicMBean mbean = new StandardMBean(
|
||||
@ -208,11 +213,46 @@ public class EventClientDelegate implements EventClientDelegateMBean {
|
||||
* 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 @@ public class EventClientDelegate implements EventClientDelegateMBean {
|
||||
// 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 @@ public class EventClientDelegate implements EventClientDelegateMBean {
|
||||
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;
|
||||
|
@ -51,7 +51,8 @@ import javax.management.remote.NotificationResult;
|
||||
* 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 @@ import javax.management.remote.NotificationResult;
|
||||
*
|
||||
* <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>
|
||||
*
|
||||
|
@ -27,7 +27,6 @@ package javax.management.event;
|
||||
|
||||
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
|
||||
|
@ -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>
|
||||
*
|
||||
|
@ -265,6 +265,7 @@ public class CounterMonitor extends Monitor implements CounterMonitorMBean {
|
||||
* @return The derived gauge of the specified object.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public synchronized Number getDerivedGauge(ObjectName object) {
|
||||
return (Number) super.getDerivedGauge(object);
|
||||
}
|
||||
@ -280,6 +281,7 @@ public class CounterMonitor extends Monitor implements CounterMonitorMBean {
|
||||
* @return The derived gauge timestamp of the specified object.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public synchronized long getDerivedGaugeTimeStamp(ObjectName object) {
|
||||
return super.getDerivedGaugeTimeStamp(object);
|
||||
}
|
||||
@ -595,6 +597,7 @@ public class CounterMonitor extends Monitor implements CounterMonitorMBean {
|
||||
* name of the Java class of the notification and the notification
|
||||
* types sent by the counter monitor.
|
||||
*/
|
||||
@Override
|
||||
public MBeanNotificationInfo[] getNotificationInfo() {
|
||||
return notifsInfo;
|
||||
}
|
||||
|
@ -258,6 +258,7 @@ public class GaugeMonitor extends Monitor implements GaugeMonitorMBean {
|
||||
* @return The derived gauge of the specified object.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public synchronized Number getDerivedGauge(ObjectName object) {
|
||||
return (Number) super.getDerivedGauge(object);
|
||||
}
|
||||
@ -273,6 +274,7 @@ public class GaugeMonitor extends Monitor implements GaugeMonitorMBean {
|
||||
* @return The derived gauge timestamp of the specified object.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public synchronized long getDerivedGaugeTimeStamp(ObjectName object) {
|
||||
return super.getDerivedGaugeTimeStamp(object);
|
||||
}
|
||||
@ -477,6 +479,7 @@ public class GaugeMonitor extends Monitor implements GaugeMonitorMBean {
|
||||
* name of the Java class of the notification and the notification
|
||||
* types sent by the gauge monitor.
|
||||
*/
|
||||
@Override
|
||||
public MBeanNotificationInfo[] getNotificationInfo() {
|
||||
return notifsInfo;
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ import java.security.AccessController;
|
||||
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 @@ public abstract class Monitor
|
||||
//
|
||||
ObservedObject o = createObservedObject(object);
|
||||
o.setAlreadyNotified(RESET_FLAGS_ALREADY_NOTIFIED);
|
||||
o.setDerivedGauge(null);
|
||||
o.setDerivedGauge(INTEGER_ZERO);
|
||||
o.setDerivedGaugeTimeStamp(System.currentTimeMillis());
|
||||
observedObjects.add(o);
|
||||
|
||||
|
@ -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
|
||||
@ -68,23 +66,6 @@ public class JMXNamespaces {
|
||||
NAMESPACE_SEPARATOR.length();
|
||||
|
||||
|
||||
/**
|
||||
* Returns a connector connected to a sub name space exposed through
|
||||
* the parent connector.
|
||||
* @param parent the parent connector.
|
||||
* @param namespace the {@linkplain javax.management.namespace name space}
|
||||
* to which the returned connector is
|
||||
* connected.
|
||||
* @return A connector connected to a sub name space exposed through
|
||||
* the parent connector.
|
||||
**/
|
||||
public static JMXConnector narrowToNamespace(final JMXConnector parent,
|
||||
final String namespace)
|
||||
throws IOException {
|
||||
|
||||
return JMXNamespaceUtils.cd(parent,namespace,true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code MBeanServerConnection} proxy on a
|
||||
* {@linkplain javax.management.namespace sub name space}
|
||||
@ -96,15 +77,18 @@ public class JMXNamespaces {
|
||||
* 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 @@ public class JMXNamespaces {
|
||||
* 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 @@ public class JMXNamespaces {
|
||||
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+
|
||||
|
@ -27,10 +27,10 @@ package javax.management.namespace;
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import com.sun.jmx.namespace.JMXNamespaceUtils;
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
@ -39,6 +39,7 @@ import java.util.logging.Logger;
|
||||
|
||||
import javax.management.AttributeChangeNotification;
|
||||
|
||||
import javax.management.ClientContext;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
@ -220,17 +221,26 @@ public class JMXRemoteNamespace
|
||||
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 @@ public class JMXRemoteNamespace
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class JMXRemoteNamespace
|
||||
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 @@ public class JMXRemoteNamespace
|
||||
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);
|
||||
|
@ -33,12 +33,14 @@ import java.io.Serializable;
|
||||
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 @@ public class CompositeDataSupport
|
||||
* 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 @@ public class CompositeDataSupport
|
||||
* 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 @@ public class CompositeDataSupport
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -328,6 +328,54 @@ public class CompositeDataSupport
|
||||
return Collections.unmodifiableCollection(contents.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* <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.
|
||||
|
@ -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 @@ 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.
|
||||
-->
|
||||
</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 @@ have any questions.
|
||||
|
||||
<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 @@ have any questions.
|
||||
<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 @@ have any questions.
|
||||
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>
|
||||
|
@ -322,10 +322,12 @@ public class JMXConnectorFactory {
|
||||
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 @@ public class JMXConnectorFactory {
|
||||
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 @@ public class JMXConnectorFactory {
|
||||
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 @@ public class JMXConnectorFactory {
|
||||
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 @@ public class JMXConnectorFactory {
|
||||
private static String protocol2package(String protocol) {
|
||||
return protocol.replace('+', '.').replace('-', '_');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ import java.util.List;
|
||||
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;
|
||||
@ -101,6 +102,56 @@ public abstract class JMXConnectorServer
|
||||
public static final String DELEGATE_TO_EVENT_SERVICE =
|
||||
"jmx.remote.delegate.event.service";
|
||||
|
||||
/**
|
||||
* <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}
|
||||
@ -155,7 +206,7 @@ public abstract class JMXConnectorServer
|
||||
* 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 @@ public abstract class JMXConnectorServer
|
||||
* 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 @@ public abstract class JMXConnectorServer
|
||||
* 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 @@ public abstract class JMXConnectorServer
|
||||
* 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 @@ public abstract class JMXConnectorServer
|
||||
*
|
||||
* @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 @@ public abstract class JMXConnectorServer
|
||||
* <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 @@ public abstract class JMXConnectorServer
|
||||
*
|
||||
* @return the array of possible notifications.
|
||||
*/
|
||||
@Override
|
||||
public MBeanNotificationInfo[] getNotificationInfo() {
|
||||
final String[] types = {
|
||||
JMXConnectionNotification.OPENED,
|
||||
@ -684,30 +764,29 @@ public abstract class JMXConnectorServer
|
||||
* 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 @@ public abstract class JMXConnectorServer
|
||||
* 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 @@ public abstract class JMXConnectorServer
|
||||
|
||||
private MBeanServer userMBeanServer;
|
||||
|
||||
private MBeanServer systemMBeanServer;
|
||||
private final MBeanServerForwarder systemMBeanServerForwarder =
|
||||
new IdentityMBeanServerForwarder();
|
||||
|
||||
/**
|
||||
* The name used to registered this server in an MBeanServer.
|
||||
|
@ -132,7 +132,7 @@ public interface JMXConnectorServerMBean {
|
||||
*
|
||||
* <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 @@ public interface JMXConnectorServerMBean {
|
||||
* 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);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -383,7 +383,7 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
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 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
else
|
||||
rmiServer = newServer();
|
||||
|
||||
rmiServer.setMBeanServer(getSystemMBeanServer());
|
||||
rmiServer.setMBeanServer(getSystemMBeanServerForwarder());
|
||||
rmiServer.setDefaultClassLoader(defaultClassLoader);
|
||||
rmiServer.setRMIConnectorServer(this);
|
||||
rmiServer.export();
|
||||
@ -592,31 +592,6 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
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 @@ public class RMIConnectorServer extends JMXConnectorServer {
|
||||
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);
|
||||
|
@ -435,8 +435,14 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
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 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
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 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
}
|
||||
|
||||
private boolean streaming () {
|
||||
return (fixedContentLength != -1) || (chunkLength != -1);
|
||||
return (fixedContentLength != -1) || (fixedContentLengthLong != -1) ||
|
||||
(chunkLength != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2619,8 +2632,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
|
||||
class StreamingOutputStream extends FilterOutputStream {
|
||||
|
||||
int expected;
|
||||
int written;
|
||||
long expected;
|
||||
long written;
|
||||
boolean closed;
|
||||
boolean error;
|
||||
IOException errorExcp;
|
||||
@ -2631,10 +2644,10 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
* 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 class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
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 class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
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 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
if (expected != -1) {
|
||||
if (expected != -1L) {
|
||||
/* not chunked */
|
||||
if (written != expected) {
|
||||
error = true;
|
||||
|
@ -527,6 +527,10 @@ public class HttpsURLConnectionImpl
|
||||
delegate.setFixedLengthStreamingMode(contentLength);
|
||||
}
|
||||
|
||||
public void setFixedLengthStreamingMode(long contentLength) {
|
||||
delegate.setFixedLengthStreamingMode(contentLength);
|
||||
}
|
||||
|
||||
public void setChunkedStreamingMode (int chunklen) {
|
||||
delegate.setChunkedStreamingMode(chunklen);
|
||||
}
|
||||
|
@ -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 @@ class GSSContextImpl implements GSSContext {
|
||||
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,
|
||||
|
@ -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 @@ public class SpNegoContext implements GSSContextSpi {
|
||||
// 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 @@ public class SpNegoContext implements GSSContextSpi {
|
||||
"verification of MIC on MechList Failed!");
|
||||
}
|
||||
}
|
||||
|
||||
if (isMechContextEstablished()) {
|
||||
state = STATE_DONE;
|
||||
retVal = mechToken;
|
||||
@ -556,9 +556,6 @@ public class SpNegoContext implements GSSContextSpi {
|
||||
|
||||
// get the token for mechanism
|
||||
byte[] accept_token = GSS_acceptSecContext(mechToken);
|
||||
if (accept_token == null) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
// verify MIC
|
||||
if (!GSSUtil.useMSInterop() && valid) {
|
||||
|
@ -151,6 +151,10 @@ class OCSPResponse {
|
||||
|
||||
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 @@ class OCSPResponse {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ class OCSPResponse {
|
||||
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 " +
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user