Merge
This commit is contained in:
commit
62c247e129
@ -50,3 +50,4 @@ e1b972ff53cd58f825791f8ed9b2deffd16e768c jdk7-b68
|
||||
3ac6dcf7823205546fbbc3d4ea59f37358d0b0d4 jdk7-b73
|
||||
2c88089b6e1c053597418099a14232182c387edc jdk7-b74
|
||||
d1516b9f23954b29b8e76e6f4efc467c08c78133 jdk7-b75
|
||||
c8b63075403d53a208104a8a6ea5072c1cb66aab jdk7-b76
|
||||
|
@ -50,3 +50,4 @@ a94714c550658fd6741793ef036cb9625dc2ab1a jdk7-b72
|
||||
faf94d94786b621f8e13cbcc941ca69c6d967c3f jdk7-b73
|
||||
f4b900403d6e4b0af51447bd13bbe23fe3a1dac7 jdk7-b74
|
||||
d8dd291a362acb656026a9c0a9da48501505a1e7 jdk7-b75
|
||||
9174bb32e934965288121f75394874eeb1fcb649 jdk7-b76
|
||||
|
@ -50,3 +50,4 @@ b3f3240135f0c10b9f2481c174b81b7fcf0daa60 jdk7-b71
|
||||
f708138c9aca4b389872838fe6773872fce3609e jdk7-b73
|
||||
eacb36e30327e7ae33baa068e82ddccbd91eaae2 jdk7-b74
|
||||
8885b22565077236a927e824ef450742e434a230 jdk7-b75
|
||||
8fb602395be0f7d5af4e7e93b7df2d960faf9d17 jdk7-b76
|
||||
|
@ -165,6 +165,9 @@ ifeq ($(SYSTEM_UNAME), Linux)
|
||||
sparc*) \
|
||||
echo sparc \
|
||||
;; \
|
||||
arm*) \
|
||||
echo arm \
|
||||
;; \
|
||||
*) \
|
||||
echo $(mach) \
|
||||
;; \
|
||||
|
@ -160,10 +160,8 @@ CORE_PKGS = \
|
||||
javax.lang.model.type \
|
||||
javax.lang.model.util \
|
||||
javax.management \
|
||||
javax.management.event \
|
||||
javax.management.loading \
|
||||
javax.management.monitor \
|
||||
javax.management.namespace \
|
||||
javax.management.relation \
|
||||
javax.management.openmbean \
|
||||
javax.management.timer \
|
||||
|
@ -251,6 +251,7 @@ JAVA_JAVA_java = \
|
||||
java/util/IdentityHashMap.java \
|
||||
java/util/EnumMap.java \
|
||||
java/util/Arrays.java \
|
||||
java/util/DualPivotQuicksort.java \
|
||||
java/util/TimSort.java \
|
||||
java/util/ComparableTimSort.java \
|
||||
java/util/ConcurrentModificationException.java \
|
||||
|
@ -83,7 +83,7 @@ endif
|
||||
#
|
||||
# Find platform specific native code
|
||||
#
|
||||
vpath %.c $(PLATFORM_SRC)/native/sun/net/dns $(PLATFORM_SRC)/native/sun/net/www/protocol/http $(PLATFORM_SRC)/native/sun/net/spi
|
||||
vpath %.c $(PLATFORM_SRC)/native/sun/net/dns $(PLATFORM_SRC)/native/sun/net/www/protocol/http/ntlm $(PLATFORM_SRC)/native/sun/net/spi
|
||||
|
||||
#
|
||||
# Include rules
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
# Copyright 2006-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,8 +34,8 @@ solaris_i586_5.10,\
|
||||
solaris_x64_5.10,\
|
||||
linux_i586_2.6,\
|
||||
linux_x64_2.6,\
|
||||
windows_i586,\
|
||||
windows_x64
|
||||
windows_i586_5.0,\
|
||||
windows_x64_5.2
|
||||
|
||||
# The different build flavors we want
|
||||
jprt.build.flavors=product,fastdebug
|
||||
@ -51,21 +51,37 @@ jprt.run.flavor.c2.option=-server
|
||||
jprt.solaris_sparcv9.build.platform.match32=solaris_sparc_5.10
|
||||
jprt.solaris_x64.build.platform.match32=solaris_i586_5.10
|
||||
|
||||
# Standard list of jprt test targets for this workspace
|
||||
# Standard test target for everybody
|
||||
jprt.test.targets=*-*-*-jvm98
|
||||
jprt.regression.test.targets= \
|
||||
*-product-*-java/lang, \
|
||||
*-product-*-java/security, \
|
||||
*-product-*-java/text, \
|
||||
*-product-*-java/util
|
||||
|
||||
#jprt.regression.test.targets= \
|
||||
# *-product-*-java/awt, \
|
||||
# *-product-*-java/beans, \
|
||||
# *-product-*-java/io, \
|
||||
# *-product-*-java/net, \
|
||||
# *-product-*-java/nio, \
|
||||
# *-product-*-java/rmi, \
|
||||
# Test targets in test/Makefile (some longer running tests only test c2)
|
||||
jprt.make.rule.test.targets= \
|
||||
*-product-*-jdk_beans1, \
|
||||
*-product-*-jdk_beans2, \
|
||||
*-product-*-jdk_beans3, \
|
||||
*-product-*-jdk_io, \
|
||||
*-product-*-jdk_lang, \
|
||||
*-product-*-jdk_management1, \
|
||||
*-product-*-jdk_management2, \
|
||||
*-product-*-jdk_math, \
|
||||
*-product-*-jdk_misc, \
|
||||
*-product-*-jdk_net, \
|
||||
*-product-*-jdk_nio1, \
|
||||
*-product-*-jdk_nio2, \
|
||||
*-product-*-jdk_nio3, \
|
||||
*-product-*-jdk_security1, \
|
||||
*-product-*-jdk_security2, \
|
||||
*-product-*-jdk_security3, \
|
||||
*-product-*-jdk_text, \
|
||||
*-product-*-jdk_tools1, \
|
||||
*-product-*-jdk_tools2, \
|
||||
*-product-*-jdk_util
|
||||
|
||||
# Some of these are crashing Xvfb or windows manager, need dedicated DISPLAY per test batch
|
||||
jprt2.make.rule.test.targets= \
|
||||
*-product-*-jdk_awt, \
|
||||
*-product-*-jdk_rmi, \
|
||||
*-product-*-jdk_swing, \
|
||||
|
||||
# Directories needed to build
|
||||
jprt.bundle.exclude.src.dirs=build
|
||||
|
@ -53,7 +53,6 @@ SUNWprivate_1.1 {
|
||||
Java_sun_awt_image_GifImageDecoder_initIDs;
|
||||
Java_sun_awt_image_GifImageDecoder_parseImage;
|
||||
Java_sun_awt_image_ImageRepresentation_initIDs;
|
||||
Java_sun_awt_image_ImageRepresentation_setBytePixels;
|
||||
Java_sun_awt_image_ImageRepresentation_setDiffICM;
|
||||
Java_sun_awt_image_ImageRepresentation_setICMpixels;
|
||||
Java_sun_awt_image_ImagingLib_convolveBI;
|
||||
|
@ -55,7 +55,6 @@ SUNWprivate_1.1 {
|
||||
Java_sun_awt_image_GifImageDecoder_parseImage;
|
||||
Java_sun_awt_image_Image_initIDs;
|
||||
Java_sun_awt_image_ImageRepresentation_initIDs;
|
||||
Java_sun_awt_image_ImageRepresentation_setBytePixels;
|
||||
Java_sun_awt_image_ImageRepresentation_setDiffICM;
|
||||
Java_sun_awt_image_ImageRepresentation_setICMpixels;
|
||||
Java_sun_awt_image_ImagingLib_convolveBI;
|
||||
|
@ -21,4 +21,4 @@
|
||||
# CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
# have any questions.
|
||||
#
|
||||
tzdata2009l
|
||||
tzdata2009r
|
||||
|
@ -102,15 +102,38 @@ Rule ChileAQ 2000 max - Mar Sun>=9 3:00u 0 -
|
||||
# Davis, Vestfold Hills, -6835+07759, since 1957-01-13
|
||||
# (except 1964-11 - 1969-02)
|
||||
# Mawson, Holme Bay, -6736+06253, since 1954-02-13
|
||||
|
||||
# From Steffen Thorsen (2009-03-11):
|
||||
# Three Australian stations in Antarctica have changed their time zone:
|
||||
# Casey moved from UTC+8 to UTC+11
|
||||
# Davis moved from UTC+7 to UTC+5
|
||||
# Mawson moved from UTC+6 to UTC+5
|
||||
# The changes occurred on 2009-10-18 at 02:00 (local times).
|
||||
#
|
||||
# Government source: (Australian Antarctic Division)
|
||||
# <a href="http://www.aad.gov.au/default.asp?casid=37079">
|
||||
# http://www.aad.gov.au/default.asp?casid=37079
|
||||
# </a>
|
||||
#
|
||||
# We have more background information here:
|
||||
# <a href="http://www.timeanddate.com/news/time/antarctica-new-times.html">
|
||||
# http://www.timeanddate.com/news/time/antarctica-new-times.html
|
||||
# </a>
|
||||
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Antarctica/Casey 0 - zzz 1969
|
||||
8:00 - WST # Western (Aus) Standard Time
|
||||
8:00 - WST 2009 Oct 18 2:00
|
||||
# Western (Aus) Standard Time
|
||||
11:00 - CAST # Casey Time
|
||||
Zone Antarctica/Davis 0 - zzz 1957 Jan 13
|
||||
7:00 - DAVT 1964 Nov # Davis Time
|
||||
0 - zzz 1969 Feb
|
||||
7:00 - DAVT
|
||||
7:00 - DAVT 2009 Oct 18 2:0
|
||||
5:00 - DAVT
|
||||
Zone Antarctica/Mawson 0 - zzz 1954 Feb 13
|
||||
6:00 - MAWT # Mawson Time
|
||||
6:00 - MAWT 2009 Oct 18 2:00
|
||||
# Mawson Time
|
||||
5:00 - MAWT
|
||||
# References:
|
||||
# <a href="http://www.antdiv.gov.au/aad/exop/sfo/casey/casey_aws.html">
|
||||
# Casey Weather (1998-02-26)
|
||||
|
@ -21,7 +21,6 @@
|
||||
# CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
# have any questions.
|
||||
#
|
||||
# <pre>
|
||||
# This file is in the public domain, so clarified as of
|
||||
# 2009-05-17 by Arthur David Olson.
|
||||
|
||||
@ -194,11 +193,30 @@ Zone Asia/Bahrain 3:22:20 - LMT 1920 # Al Manamah
|
||||
#
|
||||
# No DST end date has been announced yet.
|
||||
|
||||
# From Arthur David Olson (2009-07-11):
|
||||
# Arbitrarily end DST at the end of 2009 so that a POSIX-sytle time zone string
|
||||
# can appear in the Dhaka binary file and for the benefit of old glibc
|
||||
# reimplementations of the time zone software that mishandle permanent DST.
|
||||
# A change will be required once the end date is known.
|
||||
# From Alexander Krivenyshev (2009-09-25):
|
||||
# Bangladesh won't go back to Standard Time from October 1, 2009,
|
||||
# instead it will continue DST measure till the cabinet makes a fresh decision.
|
||||
#
|
||||
# Following report by same newspaper-"The Daily Star Friday":
|
||||
# "DST change awaits cabinet decision-Clock won't go back by 1-hr from Oct 1"
|
||||
# <a href="http://www.thedailystar.net/newDesign/news-details.php?nid=107021">
|
||||
# http://www.thedailystar.net/newDesign/news-details.php?nid=107021
|
||||
# </a>
|
||||
# or
|
||||
# <a href="http://www.worldtimezone.com/dst_news/dst_news_bangladesh04.html">
|
||||
# http://www.worldtimezone.com/dst_news/dst_news_bangladesh04.html
|
||||
# </a>
|
||||
|
||||
# From Steffen Thorsen (2009-10-13):
|
||||
# IANS (Indo-Asian News Service) now reports:
|
||||
# Bangladesh has decided that the clock advanced by an hour to make
|
||||
# maximum use of daylight hours as an energy saving measure would
|
||||
# "continue for an indefinite period."
|
||||
#
|
||||
# One of many places where it is published:
|
||||
# <a href="http://www.thaindian.com/newsportal/business/bangladesh-to-continue-indefinitely-with-advanced-time_100259987.html">
|
||||
# http://www.thaindian.com/newsportal/business/bangladesh-to-continue-indefinitely-with-advanced-time_100259987.html
|
||||
# </a>
|
||||
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Asia/Dhaka 6:01:40 - LMT 1890
|
||||
@ -208,8 +226,7 @@ Zone Asia/Dhaka 6:01:40 - LMT 1890
|
||||
6:30 - BURT 1951 Sep 30
|
||||
6:00 - DACT 1971 Mar 26 # Dacca Time
|
||||
6:00 - BDT 2009 Jun 19 23:00 # Bangladesh Time
|
||||
6:00 1:00 BDST 2010
|
||||
6:00 - BDT
|
||||
6:00 1:00 BDST
|
||||
|
||||
# Bhutan
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
@ -373,14 +390,84 @@ Zone Asia/Kashgar 5:03:56 - LMT 1928 # or Kashi or Kaxgar
|
||||
5:00 - KAST 1980 May
|
||||
8:00 PRC C%sT
|
||||
|
||||
|
||||
# From Lee Yiu Chung (2009-10-24):
|
||||
# I found there are some mistakes for the historial DST rule for Hong
|
||||
# Kong. Accoring to the DST record from Hong Kong Observatory (actually,
|
||||
# it is not [an] observatory, but the official meteorological agency of HK,
|
||||
# and also serves as the official timing agency), there are some missing
|
||||
# and incorrect rules. Although the exact switch over time is missing, I
|
||||
# think 3:30 is correct. The official DST record for Hong Kong can be
|
||||
# obtained from
|
||||
# <a href="http://www.hko.gov.hk/gts/time/Summertime.htm">
|
||||
# http://www.hko.gov.hk/gts/time/Summertime.htm
|
||||
# </a>.
|
||||
|
||||
# From Arthur David Olson (2009-10-28):
|
||||
# Here are the dates given at
|
||||
# <a href="http://www.hko.gov.hk/gts/time/Summertime.htm">
|
||||
# http://www.hko.gov.hk/gts/time/Summertime.htm
|
||||
# </a>
|
||||
# as of 2009-10-28:
|
||||
# Year Period
|
||||
# 1941 1 Apr to 30 Sep
|
||||
# 1942 Whole year
|
||||
# 1943 Whole year
|
||||
# 1944 Whole year
|
||||
# 1945 Whole year
|
||||
# 1946 20 Apr to 1 Dec
|
||||
# 1947 13 Apr to 30 Dec
|
||||
# 1948 2 May to 31 Oct
|
||||
# 1949 3 Apr to 30 Oct
|
||||
# 1950 2 Apr to 29 Oct
|
||||
# 1951 1 Apr to 28 Oct
|
||||
# 1952 6 Apr to 25 Oct
|
||||
# 1953 5 Apr to 1 Nov
|
||||
# 1954 21 Mar to 31 Oct
|
||||
# 1955 20 Mar to 6 Nov
|
||||
# 1956 18 Mar to 4 Nov
|
||||
# 1957 24 Mar to 3 Nov
|
||||
# 1958 23 Mar to 2 Nov
|
||||
# 1959 22 Mar to 1 Nov
|
||||
# 1960 20 Mar to 6 Nov
|
||||
# 1961 19 Mar to 5 Nov
|
||||
# 1962 18 Mar to 4 Nov
|
||||
# 1963 24 Mar to 3 Nov
|
||||
# 1964 22 Mar to 1 Nov
|
||||
# 1965 18 Apr to 17 Oct
|
||||
# 1966 17 Apr to 16 Oct
|
||||
# 1967 16 Apr to 22 Oct
|
||||
# 1968 21 Apr to 20 Oct
|
||||
# 1969 20 Apr to 19 Oct
|
||||
# 1970 19 Apr to 18 Oct
|
||||
# 1971 18 Apr to 17 Oct
|
||||
# 1972 16 Apr to 22 Oct
|
||||
# 1973 22 Apr to 21 Oct
|
||||
# 1973/74 30 Dec 73 to 20 Oct 74
|
||||
# 1975 20 Apr to 19 Oct
|
||||
# 1976 18 Apr to 17 Oct
|
||||
# 1977 Nil
|
||||
# 1978 Nil
|
||||
# 1979 13 May to 21 Oct
|
||||
# 1980 to Now Nil
|
||||
# The page does not give start or end times of day.
|
||||
# The page does not give a start date for 1942.
|
||||
# The page does not givw an end date for 1945.
|
||||
# The Japanese occupation of Hong Kong began on 1941-12-25.
|
||||
# The Japanese surrender of Hong Kong was signed 1945-09-15.
|
||||
# For lack of anything better, use start of those days as the transition times.
|
||||
|
||||
# Hong Kong (Xianggang)
|
||||
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
Rule HK 1941 only - Apr 1 3:30 1:00 S
|
||||
Rule HK 1941 only - Sep 30 3:30 0 -
|
||||
Rule HK 1946 only - Apr 20 3:30 1:00 S
|
||||
Rule HK 1946 only - Dec 1 3:30 0 -
|
||||
Rule HK 1947 only - Apr 13 3:30 1:00 S
|
||||
Rule HK 1947 only - Dec 30 3:30 0 -
|
||||
Rule HK 1948 only - May 2 3:30 1:00 S
|
||||
Rule HK 1948 1952 - Oct lastSun 3:30 0 -
|
||||
Rule HK 1948 1951 - Oct lastSun 3:30 0 -
|
||||
Rule HK 1952 only - Oct 25 3:30 0 -
|
||||
Rule HK 1949 1953 - Apr Sun>=1 3:30 1:00 S
|
||||
Rule HK 1953 only - Nov 1 3:30 0 -
|
||||
Rule HK 1954 1964 - Mar Sun>=18 3:30 1:00 S
|
||||
@ -388,13 +475,15 @@ Rule HK 1954 only - Oct 31 3:30 0 -
|
||||
Rule HK 1955 1964 - Nov Sun>=1 3:30 0 -
|
||||
Rule HK 1965 1977 - Apr Sun>=16 3:30 1:00 S
|
||||
Rule HK 1965 1977 - Oct Sun>=16 3:30 0 -
|
||||
Rule HK 1979 1980 - May Sun>=8 3:30 1:00 S
|
||||
Rule HK 1979 1980 - Oct Sun>=16 3:30 0 -
|
||||
Rule HK 1973 only - Dec 30 3:30 1:00 S
|
||||
Rule HK 1979 only - May Sun>=8 3:30 1:00 S
|
||||
Rule HK 1979 only - Oct Sun>=16 3:30 0 -
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Asia/Hong_Kong 7:36:36 - LMT 1904 Oct 30
|
||||
8:00 HK HK%sT 1941 Dec 25
|
||||
9:00 - JST 1945 Sep 15
|
||||
8:00 HK HK%sT
|
||||
|
||||
|
||||
###############################################################################
|
||||
|
||||
# Taiwan
|
||||
@ -1696,16 +1785,66 @@ Zone Asia/Muscat 3:54:20 - LMT 1920
|
||||
# advance clocks in the country by one hour from April 15 to
|
||||
# conserve energy"
|
||||
|
||||
# From Arthur David Olson (2009-04-10):
|
||||
# Assume for now that Pakistan will end DST in 2009 as it did in 2008.
|
||||
# From Steffen Thorsen (2009-09-17):
|
||||
# "The News International," Pakistan reports that: "The Federal
|
||||
# Government has decided to restore the previous time by moving the
|
||||
# clocks backward by one hour from October 1. A formal announcement to
|
||||
# this effect will be made after the Prime Minister grants approval in
|
||||
# this regard."
|
||||
# <a href="http://www.thenews.com.pk/updates.asp?id=87168">
|
||||
# http://www.thenews.com.pk/updates.asp?id=87168
|
||||
# </a>
|
||||
|
||||
# From Alexander Krivenyshev (2009-09-28):
|
||||
# According to Associated Press Of Pakistan, it is confirmed that
|
||||
# Pakistan clocks across the country would be turned back by an hour from October
|
||||
# 1, 2009.
|
||||
#
|
||||
# "Clocks to go back one hour from 1 Oct"
|
||||
# <a href="http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=86715&Itemid=2">
|
||||
# http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=86715&Itemid=2
|
||||
# </a>
|
||||
# or
|
||||
# <a href="http://www.worldtimezone.com/dst_news/dst_news_pakistan07.htm">
|
||||
# http://www.worldtimezone.com/dst_news/dst_news_pakistan07.htm
|
||||
# </a>
|
||||
|
||||
# From Steffen Thorsen (2009-09-29):
|
||||
# Alexander Krivenyshev wrote:
|
||||
# > According to Associated Press Of Pakistan, it is confirmed that
|
||||
# > Pakistan clocks across the country would be turned back by an hour from October
|
||||
# > 1, 2009.
|
||||
#
|
||||
# Now they seem to have changed their mind, November 1 is the new date:
|
||||
# <a href="http://www.thenews.com.pk/top_story_detail.asp?Id=24742">
|
||||
# http://www.thenews.com.pk/top_story_detail.asp?Id=24742
|
||||
# </a>
|
||||
# "The country's clocks will be reversed by one hour on November 1.
|
||||
# Officials of Federal Ministry for Interior told this to Geo News on
|
||||
# Monday."
|
||||
#
|
||||
# And more importantly, it seems that these dates will be kept every year:
|
||||
# "It has now been decided that clocks will be wound forward by one hour
|
||||
# on April 15 and reversed by an hour on November 1 every year without
|
||||
# obtaining prior approval, the officials added."
|
||||
#
|
||||
# We have confirmed this year's end date with both with the Ministry of
|
||||
# Water and Power and the Pakistan Electric Power Company:
|
||||
# <a href="http://www.timeanddate.com/news/time/pakistan-ends-dst09.html">
|
||||
# http://www.timeanddate.com/news/time/pakistan-ends-dst09.html
|
||||
# </a>
|
||||
|
||||
# From Christoph Goehre (2009-10-01):
|
||||
# [T]he German Consulate General in Karachi reported me today that Pakistan
|
||||
# will go back to standard time on 1st of November.
|
||||
|
||||
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
Rule Pakistan 2002 only - Apr Sun>=2 0:01 1:00 S
|
||||
Rule Pakistan 2002 only - Oct Sun>=2 0:01 0 -
|
||||
Rule Pakistan 2008 only - Jun 1 0:00 1:00 S
|
||||
Rule Pakistan 2008 only - Nov 1 0:00 0 -
|
||||
Rule Pakistan 2009 only - Apr 15 0:00 1:00 S
|
||||
Rule Pakistan 2009 only - Nov 1 0:00 0 -
|
||||
Rule Pakistan 2009 max - Apr 15 0:00 1:00 S
|
||||
Rule Pakistan 2009 max - Nov 1 0:00 0 -
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Asia/Karachi 4:28:12 - LMT 1907
|
||||
5:30 - IST 1942 Sep
|
||||
@ -1858,6 +1997,42 @@ Zone Asia/Karachi 4:28:12 - LMT 1907
|
||||
# http://www.worldtimezone.com/dst_news/dst_news_westbank01.html
|
||||
# </a>
|
||||
|
||||
# From Steffen Thorsen (2009-08-31):
|
||||
# Palestine's Council of Ministers announced that they will revert back to
|
||||
# winter time on Friday, 2009-09-04.
|
||||
#
|
||||
# One news source:
|
||||
# <a href="http://www.safa.ps/ara/?action=showdetail&seid=4158">
|
||||
# http://www.safa.ps/ara/?action=showdetail&seid=4158
|
||||
# </a>
|
||||
# (Palestinian press agency, Arabic),
|
||||
# Google translate: "Decided that the Palestinian government in Ramallah
|
||||
# headed by Salam Fayyad, the start of work in time for the winter of
|
||||
# 2009, starting on Friday approved the fourth delay Sept. clock sixty
|
||||
# minutes per hour as of Friday morning."
|
||||
#
|
||||
# We are not sure if Gaza will do the same, last year they had a different
|
||||
# end date, we will keep this page updated:
|
||||
# <a href="http://www.timeanddate.com/news/time/westbank-gaza-dst-2009.html">
|
||||
# http://www.timeanddate.com/news/time/westbank-gaza-dst-2009.html
|
||||
# </a>
|
||||
|
||||
# From Alexander Krivenyshev (2009-09-02):
|
||||
# Seems that Gaza Strip will go back to Winter Time same date as West Bank.
|
||||
#
|
||||
# According to Palestinian Ministry Of Interior, West Bank and Gaza Strip plan
|
||||
# to change time back to Standard time on September 4, 2009.
|
||||
#
|
||||
# "Winter time unite the West Bank and Gaza"
|
||||
# (from Palestinian National Authority):
|
||||
# <a href="http://www.moi.gov.ps/en/?page=633167343250594025&nid=11505
|
||||
# http://www.moi.gov.ps/en/?page=633167343250594025&nid=11505
|
||||
# </a>
|
||||
# or
|
||||
# <a href="http://www.worldtimezone.com/dst_news/dst_news_gazastrip02.html>
|
||||
# http://www.worldtimezone.com/dst_news/dst_news_gazastrip02.html
|
||||
# </a>
|
||||
|
||||
# The rules for Egypt are stolen from the `africa' file.
|
||||
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
|
||||
Rule EgyptAsia 1957 only - May 10 0:00 1:00 S
|
||||
@ -1876,7 +2051,7 @@ Rule Palestine 2006 only - Sep 22 0:00 0 -
|
||||
Rule Palestine 2007 only - Sep Thu>=8 2:00 0 -
|
||||
Rule Palestine 2008 only - Aug lastFri 2:00 0 -
|
||||
Rule Palestine 2009 max - Mar lastFri 0:00 1:00 S
|
||||
Rule Palestine 2009 max - Sep lastMon 2:00 0 -
|
||||
Rule Palestine 2009 max - Sep Fri>=1 2:00 0 -
|
||||
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Asia/Gaza 2:17:52 - LMT 1900 Oct
|
||||
@ -2154,9 +2329,23 @@ Rule Syria 2007 only - Nov Fri>=1 0:00 0 -
|
||||
# http://www.timeanddate.com/news/time/syria-dst-starts-march-27-2009.html
|
||||
# </a>
|
||||
|
||||
# From Steffen Thorsen (2009-10-27):
|
||||
# The Syrian Arab News Network on 2009-09-29 reported that Syria will
|
||||
# revert back to winter (standard) time on midnight between Thursday
|
||||
# 2009-10-29 and Friday 2009-10-30:
|
||||
# <a href="http://www.sana.sy/ara/2/2009/09/29/247012.htm">
|
||||
# http://www.sana.sy/ara/2/2009/09/29/247012.htm (Arabic)
|
||||
# </a>
|
||||
|
||||
# From Arthur David Olson (2009-10-28):
|
||||
# We'll see if future DST switching times turn out to be end of the last
|
||||
# Thursday of the month or the start of the last Friday of the month or
|
||||
# something else. For now, use the start of the last Friday.
|
||||
|
||||
Rule Syria 2008 only - Apr Fri>=1 0:00 1:00 S
|
||||
Rule Syria 2008 max - Nov 1 0:00 0 -
|
||||
Rule Syria 2008 only - Nov 1 0:00 0 -
|
||||
Rule Syria 2009 max - Mar lastFri 0:00 1:00 S
|
||||
Rule Syria 2009 max - Oct lastFri 0:00 0 -
|
||||
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
Zone Asia/Damascus 2:25:12 - LMT 1920 # Dimashq
|
||||
|
@ -465,10 +465,56 @@ Zone Pacific/Pago_Pago 12:37:12 - LMT 1879 Jul 5
|
||||
# http://www.worldtimezone.com/dst_news/dst_news_samoa01.html
|
||||
# </a>
|
||||
|
||||
# From Steffen Thorsen (2009-08-27):
|
||||
# Samoa's parliament passed the Daylight Saving Bill 2009, and will start
|
||||
# daylight saving time on the first Sunday of October 2009 and end on the
|
||||
# last Sunday of March 2010. We hope that the full text will be published
|
||||
# soon, but we believe that the bill is only valid for 2009-2010. Samoa's
|
||||
# Daylight Saving Act 2009 will be enforced as soon as the Head of State
|
||||
# executes a proclamation publicizing this Act.
|
||||
#
|
||||
# Some background information here, which will be updated once we have
|
||||
# more details:
|
||||
# <a href="http://www.timeanddate.com/news/time/samoa-dst-plan-2009.html">
|
||||
# http://www.timeanddate.com/news/time/samoa-dst-plan-2009.html
|
||||
# </a>
|
||||
|
||||
# From Alexander Krivenyshev (2009-10-03):
|
||||
# First, my deepest condolences to people of Samoa islands and all families and
|
||||
# loved ones around the world who lost their lives in the earthquake and tsunami.
|
||||
#
|
||||
# Considering the recent devastation on Samoa by earthquake and tsunami and that
|
||||
# many government offices/ ministers are closed- not sure if "Daylight Saving
|
||||
# Bill 2009" will be implemented in next few days- on October 4, 2009.
|
||||
#
|
||||
# Here is reply from Consulate-General of Samoa in New Zealand
|
||||
# ---------------------------
|
||||
# Consul General
|
||||
# consulgeneral@samoaconsulate.org.nz
|
||||
#
|
||||
# Talofa Alexander,
|
||||
#
|
||||
# Thank you for your sympathy for our country but at this time we have not
|
||||
# been informed about the Daylight Savings Time Change. Most Ministries in
|
||||
# Apia are closed or relocating due to weather concerns.
|
||||
#
|
||||
# When we do find out if they are still proceeding with the time change we
|
||||
# will advise you soonest.
|
||||
#
|
||||
# Kind Regards,
|
||||
# Lana
|
||||
# for: Consul General
|
||||
|
||||
# From Steffen Thorsen (2009-10-05):
|
||||
# We have called a hotel in Samoa and asked about local time there - they
|
||||
# are still on standard time.
|
||||
|
||||
Zone Pacific/Apia 12:33:04 - LMT 1879 Jul 5
|
||||
-11:26:56 - LMT 1911
|
||||
-11:30 - SAMT 1950 # Samoa Time
|
||||
-11:00 - WST # Samoa Time
|
||||
-11:00 - WST 2009 Oct 4
|
||||
-11:00 1:00 WSDT 2010 Mar 28
|
||||
-11:00 - WST
|
||||
|
||||
# Solomon Is
|
||||
# excludes Bougainville, for which see Papua New Guinea
|
||||
|
@ -2094,9 +2094,43 @@ Zone Asia/Novosibirsk 5:31:40 - LMT 1919 Dec 14 6:00
|
||||
6:00 Russia NOV%sT 1992 Jan 19 2:00s
|
||||
7:00 Russia NOV%sT 1993 May 23 # say Shanks & P.
|
||||
6:00 Russia NOV%sT
|
||||
|
||||
# From Alexander Krivenyshev (2009-10-13):
|
||||
# Kemerovo oblast' (Kemerovo region) in Russia will change current time zone on
|
||||
# March 28, 2010:
|
||||
# from current Russia Zone 6 - Krasnoyarsk Time Zone (KRA) UTC +0700
|
||||
# to Russia Zone 5 - Novosibirsk Time Zone (NOV) UTC +0600
|
||||
#
|
||||
# This is according to Government of Russia decree # 740, on September
|
||||
# 14, 2009 "Application in the territory of the Kemerovo region the Fifth
|
||||
# time zone." ("Russia Zone 5" or old "USSR Zone 5" is GMT +0600)
|
||||
#
|
||||
# Russian Government web site (Russian language)
|
||||
# <a href="http://www.government.ru/content/governmentactivity/rfgovernmentdecisions/archiv">
|
||||
# http://www.government.ru/content/governmentactivity/rfgovernmentdecisions/archive/2009/09/14/991633.htm
|
||||
# </a>
|
||||
# or Russian-English translation by WorldTimeZone.com with reference
|
||||
# map to local region and new Russia Time Zone map after March 28, 2010
|
||||
# <a href="http://www.worldtimezone.com/dst_news/dst_news_russia03.html">
|
||||
# http://www.worldtimezone.com/dst_news/dst_news_russia03.html
|
||||
# </a>
|
||||
#
|
||||
# Thus, when Russia will switch to DST on the night of March 28, 2010
|
||||
# Kemerovo region (Kemerovo oblast') will not change the clock.
|
||||
#
|
||||
# As a result, Kemerovo oblast' will be in the same time zone as
|
||||
# Novosibirsk, Omsk, Tomsk, Barnaul and Altai Republic.
|
||||
|
||||
Zone Asia/Novokuznetsk 5:48:48 - NMT 1920 Jan 6
|
||||
6:00 - KRAT 1930 Jun 21 # Krasnoyarsk Time
|
||||
7:00 Russia KRA%sT 1991 Mar 31 2:00s
|
||||
6:00 Russia KRA%sT 1992 Jan 19 2:00s
|
||||
7:00 Russia KRA%sT 2010 Mar 28 2:00s
|
||||
6:00 Russia NOV%sT # Novosibirsk/Novokuznetsk Time
|
||||
|
||||
#
|
||||
# From Oscar van Vlijmen (2001-08-25): [This region consists of]
|
||||
# Kemerovskaya oblast', Krasnoyarskij kraj,
|
||||
# Krasnoyarskij kraj,
|
||||
# Tajmyrskij (Dolgano-Nenetskij) avtonomnyj okrug,
|
||||
# Respublika Tuva, Respublika Khakasiya, Evenkijskij avtonomnyj okrug.
|
||||
Zone Asia/Krasnoyarsk 6:11:20 - LMT 1920 Jan 6
|
||||
|
@ -237,9 +237,23 @@ Rule Arg 2000 only - Mar 3 0:00 0 -
|
||||
# http://www.jujuy.gov.ar/index2/partes_prensa/18_10_08/235-181008.doc
|
||||
# </a>
|
||||
|
||||
# From fullinet (2009-10-18):
|
||||
# As announced in
|
||||
# <a hef="http://www.argentina.gob.ar/argentina/portal/paginas.dhtml?pagina=356">
|
||||
# http://www.argentina.gob.ar/argentina/portal/paginas.dhtml?pagina=356
|
||||
# </a>
|
||||
# (an official .gob.ar) under title: "Sin Cambio de Hora" (english: "No hour change")
|
||||
#
|
||||
# "Por el momento, el Gobierno Nacional resolvio no modificar la hora
|
||||
# oficial, decision que estaba en estudio para su implementacion el
|
||||
# domingo 18 de octubre. Desde el Ministerio de Planificacion se anuncio
|
||||
# que la Argentina hoy, en estas condiciones meteorologicas, no necesita
|
||||
# la modificacion del huso horario, ya que 2009 nos encuentra con
|
||||
# crecimiento en la produccion y distribucion energetica."
|
||||
|
||||
Rule Arg 2007 only - Dec 30 0:00 1:00 S
|
||||
Rule Arg 2008 max - Mar Sun>=15 0:00 0 -
|
||||
Rule Arg 2008 max - Oct Sun>=15 0:00 1:00 S
|
||||
Rule Arg 2008 2009 - Mar Sun>=15 0:00 0 -
|
||||
Rule Arg 2008 only - Oct Sun>=15 0:00 1:00 S
|
||||
|
||||
# From Mariano Absatz (2004-05-21):
|
||||
# Today it was officially published that the Province of Mendoza is changing
|
||||
@ -411,15 +425,40 @@ Rule Arg 2008 max - Oct Sun>=15 0:00 1:00 S
|
||||
# during 2009, this timezone change will run from 00:00 the third Sunday
|
||||
# in March until 24:00 of the second Saturday in October.
|
||||
|
||||
# From Arthur David Olson (2009-03-16):
|
||||
# The unofficial claim at
|
||||
# <a href="http://www.timeanddate.com/news/time/san-luis-new-time-zone.html">
|
||||
# http://www.timeanddate.com/news/time/san-luis-new-time-zone.html
|
||||
# </a>
|
||||
# is that "The province will most likely follow the next daylight saving schedule,
|
||||
# which is planned for the second Sunday in October."
|
||||
|
||||
# From Mariano Absatz (2009-10-16):
|
||||
# ...the Province of San Luis is a case in itself.
|
||||
#
|
||||
# The Law at
|
||||
# <a href="http://www.diputadossanluis.gov.ar/diputadosasp/paginas/verNorma.asp?NormaID=276>"
|
||||
# http://www.diputadossanluis.gov.ar/diputadosasp/paginas/verNorma.asp?NormaID=276
|
||||
# </a>
|
||||
# is ambiguous because establishes a calendar from the 2nd Sunday in
|
||||
# October at 0:00 thru the 2nd Saturday in March at 24:00 and the
|
||||
# complement of that starting on the 2nd Sunday of March at 0:00 and
|
||||
# ending on the 2nd Saturday of March at 24:00.
|
||||
#
|
||||
# This clearly breaks every time the 1st of March or October is a Sunday.
|
||||
#
|
||||
# IMHO, the "spirit of the Law" is to make the changes at 0:00 on the 2nd
|
||||
# Sunday of October and March.
|
||||
#
|
||||
# The problem is that the changes in the rest of the Provinces that did
|
||||
# change in 2007/2008, were made according to the Federal Law and Decrees
|
||||
# that did so on the 3rd Sunday of October and March.
|
||||
#
|
||||
# In fact, San Luis actually switched from UTC-4 to UTC-3 last Sunday
|
||||
# (October 11th) at 0:00.
|
||||
#
|
||||
# So I guess a new set of rules, besides "Arg", must be made and the last
|
||||
# America/Argentina/San_Luis entries should change to use these...
|
||||
#
|
||||
# I'm enclosing a patch that does what I say... regretfully, the San Luis
|
||||
# timezone must be called "WART/WARST" even when most of the time (like,
|
||||
# right now) WARST == ART... that is, since last Sunday, all the country
|
||||
# is using UTC-3, but in my patch, San Luis calls it "WARST" and the rest
|
||||
# of the country calls it "ART".
|
||||
# ...
|
||||
|
||||
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
|
||||
#
|
||||
# Buenos Aires (BA), Capital Federal (CF),
|
||||
@ -552,6 +591,10 @@ Zone America/Argentina/Mendoza -4:35:16 - LMT 1894 Oct 31
|
||||
-3:00 - ART
|
||||
#
|
||||
# San Luis (SL)
|
||||
|
||||
Rule SanLuis 2008 max - Mar Sun>=8 0:00 0 -
|
||||
Rule SanLuis 2007 max - Oct Sun>=8 0:00 1:00 S
|
||||
|
||||
Zone America/Argentina/San_Luis -4:25:24 - LMT 1894 Oct 31
|
||||
-4:16:48 - CMT 1920 May
|
||||
-4:00 - ART 1930 Dec
|
||||
@ -566,8 +609,7 @@ Zone America/Argentina/San_Luis -4:25:24 - LMT 1894 Oct 31
|
||||
-3:00 - ART 2004 May 31
|
||||
-4:00 - WART 2004 Jul 25
|
||||
-3:00 Arg AR%sT 2008 Jan 21
|
||||
-3:00 - ART 2009 Mar 15
|
||||
-4:00 Arg WAR%sT
|
||||
-4:00 SanLuis WAR%sT
|
||||
#
|
||||
# Santa Cruz (SC)
|
||||
Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 Oct 31
|
||||
|
@ -352,6 +352,7 @@ RU +5312+05009 Europe/Samara Moscow+01 - Samara, Udmurtia
|
||||
RU +5651+06036 Asia/Yekaterinburg Moscow+02 - Urals
|
||||
RU +5500+07324 Asia/Omsk Moscow+03 - west Siberia
|
||||
RU +5502+08255 Asia/Novosibirsk Moscow+03 - Novosibirsk
|
||||
RU +5345+08707 Asia/Novokuznetsk Moscow+03 - Novokuznetsk
|
||||
RU +5601+09250 Asia/Krasnoyarsk Moscow+04 - Yenisei River
|
||||
RU +5216+10420 Asia/Irkutsk Moscow+05 - Lake Baikal
|
||||
RU +6200+12940 Asia/Yakutsk Moscow+06 - Lena River
|
||||
|
@ -45,8 +45,14 @@ FILES_java = \
|
||||
sun/net/dns/ResolverConfiguration.java \
|
||||
sun/net/dns/ResolverConfigurationImpl.java \
|
||||
sun/net/ftp/FtpClient.java \
|
||||
sun/net/ftp/FtpClientProvider.java \
|
||||
sun/net/ftp/FtpDirEntry.java \
|
||||
sun/net/ftp/FtpReplyCode.java \
|
||||
sun/net/ftp/FtpDirParser.java \
|
||||
sun/net/ftp/FtpLoginException.java \
|
||||
sun/net/ftp/FtpProtocolException.java \
|
||||
sun/net/ftp/impl/FtpClient.java \
|
||||
sun/net/ftp/impl/DefaultFtpClientProvider.java \
|
||||
sun/net/spi/DefaultProxySelector.java \
|
||||
sun/net/spi/nameservice/NameServiceDescriptor.java \
|
||||
sun/net/spi/nameservice/NameService.java \
|
||||
@ -79,7 +85,6 @@ FILES_java = \
|
||||
sun/net/www/http/Hurryable.java \
|
||||
sun/net/www/protocol/http/Handler.java \
|
||||
sun/net/www/protocol/http/HttpURLConnection.java \
|
||||
sun/net/www/protocol/http/HttpLogFormatter.java \
|
||||
sun/net/www/protocol/http/HttpAuthenticator.java \
|
||||
sun/net/www/protocol/http/AuthenticationHeader.java \
|
||||
sun/net/www/protocol/http/AuthenticationInfo.java \
|
||||
@ -89,11 +94,13 @@ FILES_java = \
|
||||
sun/net/www/protocol/http/AuthScheme.java \
|
||||
sun/net/www/protocol/http/BasicAuthentication.java \
|
||||
sun/net/www/protocol/http/DigestAuthentication.java \
|
||||
sun/net/www/protocol/http/NTLMAuthentication.java \
|
||||
sun/net/www/protocol/http/NTLMAuthenticationProxy.java \
|
||||
sun/net/www/protocol/http/NegotiateAuthentication.java \
|
||||
sun/net/www/protocol/http/NegotiatorImpl.java \
|
||||
sun/net/www/protocol/http/NegotiateCallbackHandler.java \
|
||||
sun/net/www/protocol/http/Negotiator.java \
|
||||
sun/net/www/protocol/http/ntlm/NTLMAuthentication.java \
|
||||
sun/net/www/protocol/http/spnego/NegotiatorImpl.java \
|
||||
sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java \
|
||||
sun/net/www/protocol/http/logging/HttpLogFormatter.java \
|
||||
sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java \
|
||||
sun/net/www/protocol/https/HttpsClient.java \
|
||||
sun/net/www/protocol/https/DefaultHostnameVerifier.java \
|
||||
@ -128,7 +135,7 @@ FILES_java = \
|
||||
sun/net/idn/StringPrep.java
|
||||
|
||||
ifeq ($(PLATFORM), windows)
|
||||
FILES_java += sun/net/www/protocol/http/NTLMAuthSequence.java
|
||||
FILES_java += sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), solaris)
|
||||
|
@ -39,6 +39,7 @@ AUTO_FILES_JAVA_DIRS = \
|
||||
sun/security/provider \
|
||||
sun/security/rsa \
|
||||
sun/security/ssl \
|
||||
sun/security/ssl/krb5 \
|
||||
sun/security/timestamp \
|
||||
sun/security/validator \
|
||||
sun/security/x509 \
|
||||
|
@ -62,6 +62,8 @@ import javax.imageio.event.IIOReadWarningListener;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.StringTokenizer;
|
||||
@ -502,12 +504,18 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
|
||||
iis.reset();
|
||||
|
||||
try {
|
||||
if (metadata.colorSpace == PROFILE_LINKED)
|
||||
if (metadata.colorSpace == PROFILE_LINKED &&
|
||||
isLinkedProfileAllowed() &&
|
||||
!isUncOrDevicePath(profile))
|
||||
{
|
||||
String path = new String(profile, "windows-1252");
|
||||
|
||||
colorSpace =
|
||||
new ICC_ColorSpace(ICC_Profile.getInstance(new String(profile)));
|
||||
else
|
||||
new ICC_ColorSpace(ICC_Profile.getInstance(path));
|
||||
} else {
|
||||
colorSpace =
|
||||
new ICC_ColorSpace(ICC_Profile.getInstance(profile));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
||||
}
|
||||
@ -1745,4 +1753,69 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
|
||||
public void sequenceStarted(ImageReader src, int minIndex) {}
|
||||
public void readAborted(ImageReader src) {}
|
||||
}
|
||||
|
||||
private static Boolean isLinkedProfileDisabled = null;
|
||||
|
||||
private static boolean isLinkedProfileAllowed() {
|
||||
if (isLinkedProfileDisabled == null) {
|
||||
PrivilegedAction<Boolean> a = new PrivilegedAction<Boolean>() {
|
||||
public Boolean run() {
|
||||
return Boolean.getBoolean("sun.imageio.plugins.bmp.disableLinkedProfiles");
|
||||
}
|
||||
};
|
||||
isLinkedProfileDisabled = AccessController.doPrivileged(a);
|
||||
}
|
||||
return !isLinkedProfileDisabled;
|
||||
}
|
||||
|
||||
private static Boolean isWindowsPlatform = null;
|
||||
|
||||
/**
|
||||
* Verifies whether the byte array contans a unc path.
|
||||
* Non-UNC path examples:
|
||||
* c:\path\to\file - simple notation
|
||||
* \\?\c:\path\to\file - long notation
|
||||
*
|
||||
* UNC path examples:
|
||||
* \\server\share - a UNC path in simple notation
|
||||
* \\?\UNC\server\share - a UNC path in long notation
|
||||
* \\.\some\device - a path to device.
|
||||
*/
|
||||
private static boolean isUncOrDevicePath(byte[] p) {
|
||||
if (isWindowsPlatform == null) {
|
||||
PrivilegedAction<Boolean> a = new PrivilegedAction<Boolean>() {
|
||||
public Boolean run() {
|
||||
String osname = System.getProperty("os.name");
|
||||
return (osname != null &&
|
||||
osname.toLowerCase().startsWith("win"));
|
||||
}
|
||||
};
|
||||
isWindowsPlatform = AccessController.doPrivileged(a);
|
||||
}
|
||||
|
||||
if (!isWindowsPlatform) {
|
||||
/* no need for the check on platforms except windows */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* normalize prefix of the path */
|
||||
if (p[0] == '/') p[0] = '\\';
|
||||
if (p[1] == '/') p[1] = '\\';
|
||||
if (p[3] == '/') p[3] = '\\';
|
||||
|
||||
|
||||
if ((p[0] == '\\') && (p[1] == '\\')) {
|
||||
if ((p[2] == '?') && (p[3] == '\\')) {
|
||||
// long path: whether unc or local
|
||||
return ((p[4] == 'U' || p[4] == 'u') &&
|
||||
(p[5] == 'N' || p[5] == 'n') &&
|
||||
(p[6] == 'C' || p[6] == 'c'));
|
||||
} else {
|
||||
// device path or short unc notation
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
package com.sun.java.swing.plaf.motif;
|
||||
|
||||
import sun.awt.AppContext;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.plaf.basic.*;
|
||||
@ -46,16 +48,23 @@ import javax.swing.plaf.*;
|
||||
*/
|
||||
public class MotifButtonUI extends BasicButtonUI {
|
||||
|
||||
private final static MotifButtonUI motifButtonUI = new MotifButtonUI();
|
||||
|
||||
protected Color selectColor;
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
private static final Object MOTIF_BUTTON_UI_KEY = new Object();
|
||||
|
||||
// ********************************
|
||||
// Create PLAF
|
||||
// ********************************
|
||||
public static ComponentUI createUI(JComponent c){
|
||||
public static ComponentUI createUI(JComponent c) {
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
MotifButtonUI motifButtonUI =
|
||||
(MotifButtonUI) appContext.get(MOTIF_BUTTON_UI_KEY);
|
||||
if (motifButtonUI == null) {
|
||||
motifButtonUI = new MotifButtonUI();
|
||||
appContext.put(MOTIF_BUTTON_UI_KEY, motifButtonUI);
|
||||
}
|
||||
return motifButtonUI;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
package com.sun.java.swing.plaf.motif;
|
||||
|
||||
import sun.awt.AppContext;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import javax.swing.plaf.*;
|
||||
@ -45,7 +47,7 @@ import java.awt.*;
|
||||
*/
|
||||
public class MotifCheckBoxUI extends MotifRadioButtonUI {
|
||||
|
||||
private static final MotifCheckBoxUI motifCheckBoxUI = new MotifCheckBoxUI();
|
||||
private static final Object MOTIF_CHECK_BOX_UI_KEY = new Object();
|
||||
|
||||
private final static String propertyPrefix = "CheckBox" + ".";
|
||||
|
||||
@ -55,7 +57,14 @@ public class MotifCheckBoxUI extends MotifRadioButtonUI {
|
||||
// ********************************
|
||||
// Create PLAF
|
||||
// ********************************
|
||||
public static ComponentUI createUI(JComponent c){
|
||||
public static ComponentUI createUI(JComponent c) {
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
MotifCheckBoxUI motifCheckBoxUI =
|
||||
(MotifCheckBoxUI) appContext.get(MOTIF_CHECK_BOX_UI_KEY);
|
||||
if (motifCheckBoxUI == null) {
|
||||
motifCheckBoxUI = new MotifCheckBoxUI();
|
||||
appContext.put(MOTIF_CHECK_BOX_UI_KEY, motifCheckBoxUI);
|
||||
}
|
||||
return motifCheckBoxUI;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
package com.sun.java.swing.plaf.motif;
|
||||
|
||||
import sun.awt.AppContext;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.plaf.basic.BasicLabelUI;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
@ -44,9 +46,16 @@ import javax.swing.plaf.ComponentUI;
|
||||
*/
|
||||
public class MotifLabelUI extends BasicLabelUI
|
||||
{
|
||||
static MotifLabelUI sharedInstance = new MotifLabelUI();
|
||||
private static final Object MOTIF_LABEL_UI_KEY = new Object();
|
||||
|
||||
public static ComponentUI createUI(JComponent c) {
|
||||
return sharedInstance;
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
MotifLabelUI motifLabelUI =
|
||||
(MotifLabelUI) appContext.get(MOTIF_LABEL_UI_KEY);
|
||||
if (motifLabelUI == null) {
|
||||
motifLabelUI = new MotifLabelUI();
|
||||
appContext.put(MOTIF_LABEL_UI_KEY, motifLabelUI);
|
||||
}
|
||||
return motifLabelUI;
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
package com.sun.java.swing.plaf.motif;
|
||||
|
||||
import sun.awt.AppContext;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.plaf.basic.BasicRadioButtonUI;
|
||||
@ -47,7 +49,7 @@ import java.awt.*;
|
||||
*/
|
||||
public class MotifRadioButtonUI extends BasicRadioButtonUI {
|
||||
|
||||
private static final MotifRadioButtonUI motifRadioButtonUI = new MotifRadioButtonUI();
|
||||
private static final Object MOTIF_RADIO_BUTTON_UI_KEY = new Object();
|
||||
|
||||
protected Color focusColor;
|
||||
|
||||
@ -57,6 +59,13 @@ public class MotifRadioButtonUI extends BasicRadioButtonUI {
|
||||
// Create PLAF
|
||||
// ********************************
|
||||
public static ComponentUI createUI(JComponent c) {
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
MotifRadioButtonUI motifRadioButtonUI =
|
||||
(MotifRadioButtonUI) appContext.get(MOTIF_RADIO_BUTTON_UI_KEY);
|
||||
if (motifRadioButtonUI == null) {
|
||||
motifRadioButtonUI = new MotifRadioButtonUI();
|
||||
appContext.put(MOTIF_RADIO_BUTTON_UI_KEY, motifRadioButtonUI);
|
||||
}
|
||||
return motifRadioButtonUI;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
package com.sun.java.swing.plaf.motif;
|
||||
|
||||
import sun.awt.AppContext;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
@ -48,7 +50,7 @@ import javax.swing.plaf.basic.*;
|
||||
*/
|
||||
public class MotifToggleButtonUI extends BasicToggleButtonUI
|
||||
{
|
||||
private final static MotifToggleButtonUI motifToggleButtonUI = new MotifToggleButtonUI();
|
||||
private static final Object MOTIF_TOGGLE_BUTTON_UI_KEY = new Object();
|
||||
|
||||
protected Color selectColor;
|
||||
|
||||
@ -58,6 +60,13 @@ public class MotifToggleButtonUI extends BasicToggleButtonUI
|
||||
// Create PLAF
|
||||
// ********************************
|
||||
public static ComponentUI createUI(JComponent b) {
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
MotifToggleButtonUI motifToggleButtonUI =
|
||||
(MotifToggleButtonUI) appContext.get(MOTIF_TOGGLE_BUTTON_UI_KEY);
|
||||
if (motifToggleButtonUI == null) {
|
||||
motifToggleButtonUI = new MotifToggleButtonUI();
|
||||
appContext.put(MOTIF_TOGGLE_BUTTON_UI_KEY, motifToggleButtonUI);
|
||||
}
|
||||
return motifToggleButtonUI;
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@ import java.awt.*;
|
||||
import static com.sun.java.swing.plaf.windows.TMSchema.*;
|
||||
import static com.sun.java.swing.plaf.windows.TMSchema.Part.*;
|
||||
import static com.sun.java.swing.plaf.windows.XPStyle.Skin;
|
||||
import sun.awt.AppContext;
|
||||
|
||||
|
||||
/**
|
||||
@ -52,8 +53,6 @@ import static com.sun.java.swing.plaf.windows.XPStyle.Skin;
|
||||
*/
|
||||
public class WindowsButtonUI extends BasicButtonUI
|
||||
{
|
||||
private final static WindowsButtonUI windowsButtonUI = new WindowsButtonUI();
|
||||
|
||||
protected int dashedRectGapX;
|
||||
protected int dashedRectGapY;
|
||||
protected int dashedRectGapWidth;
|
||||
@ -63,11 +62,19 @@ public class WindowsButtonUI extends BasicButtonUI
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
private static final Object WINDOWS_BUTTON_UI_KEY = new Object();
|
||||
|
||||
// ********************************
|
||||
// Create PLAF
|
||||
// ********************************
|
||||
public static ComponentUI createUI(JComponent c){
|
||||
public static ComponentUI createUI(JComponent c) {
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
WindowsButtonUI windowsButtonUI =
|
||||
(WindowsButtonUI) appContext.get(WINDOWS_BUTTON_UI_KEY);
|
||||
if (windowsButtonUI == null) {
|
||||
windowsButtonUI = new WindowsButtonUI();
|
||||
appContext.put(WINDOWS_BUTTON_UI_KEY, windowsButtonUI);
|
||||
}
|
||||
return windowsButtonUI;
|
||||
}
|
||||
|
||||
@ -151,7 +158,7 @@ public class WindowsButtonUI extends BasicButtonUI
|
||||
* allocating them in each paint call substantially reduced the time
|
||||
* it took paint to run. Obviously, this method can't be re-entered.
|
||||
*/
|
||||
private static Rectangle viewRect = new Rectangle();
|
||||
private Rectangle viewRect = new Rectangle();
|
||||
|
||||
public void paint(Graphics g, JComponent c) {
|
||||
if (XPStyle.getXP() != null) {
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
package com.sun.java.swing.plaf.windows;
|
||||
|
||||
import sun.awt.AppContext;
|
||||
|
||||
import javax.swing.plaf.basic.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.plaf.*;
|
||||
@ -49,7 +51,7 @@ public class WindowsCheckBoxUI extends WindowsRadioButtonUI
|
||||
// of BasicCheckBoxUI because we want to pick up all the
|
||||
// painting changes made in MetalRadioButtonUI.
|
||||
|
||||
private static final WindowsCheckBoxUI windowsCheckBoxUI = new WindowsCheckBoxUI();
|
||||
private static final Object WINDOWS_CHECK_BOX_UI_KEY = new Object();
|
||||
|
||||
private final static String propertyPrefix = "CheckBox" + ".";
|
||||
|
||||
@ -59,6 +61,13 @@ public class WindowsCheckBoxUI extends WindowsRadioButtonUI
|
||||
// Create PLAF
|
||||
// ********************************
|
||||
public static ComponentUI createUI(JComponent c) {
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
WindowsCheckBoxUI windowsCheckBoxUI =
|
||||
(WindowsCheckBoxUI) appContext.get(WINDOWS_CHECK_BOX_UI_KEY);
|
||||
if (windowsCheckBoxUI == null) {
|
||||
windowsCheckBoxUI = new WindowsCheckBoxUI();
|
||||
appContext.put(WINDOWS_CHECK_BOX_UI_KEY, windowsCheckBoxUI);
|
||||
}
|
||||
return windowsCheckBoxUI;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,8 @@
|
||||
package com.sun.java.swing.plaf.windows;
|
||||
|
||||
import sun.swing.SwingUtilities2;
|
||||
import sun.awt.AppContext;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
|
||||
@ -51,12 +53,19 @@ import javax.swing.plaf.basic.BasicLabelUI;
|
||||
*/
|
||||
public class WindowsLabelUI extends BasicLabelUI {
|
||||
|
||||
private final static WindowsLabelUI windowsLabelUI = new WindowsLabelUI();
|
||||
private static final Object WINDOWS_LABEL_UI_KEY = new Object();
|
||||
|
||||
// ********************************
|
||||
// Create PLAF
|
||||
// ********************************
|
||||
public static ComponentUI createUI(JComponent c){
|
||||
public static ComponentUI createUI(JComponent c) {
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
WindowsLabelUI windowsLabelUI =
|
||||
(WindowsLabelUI) appContext.get(WINDOWS_LABEL_UI_KEY);
|
||||
if (windowsLabelUI == null) {
|
||||
windowsLabelUI = new WindowsLabelUI();
|
||||
appContext.put(WINDOWS_LABEL_UI_KEY, windowsLabelUI);
|
||||
}
|
||||
return windowsLabelUI;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
package com.sun.java.swing.plaf.windows;
|
||||
|
||||
import sun.awt.AppContext;
|
||||
|
||||
import javax.swing.plaf.basic.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.plaf.*;
|
||||
@ -44,7 +46,7 @@ import java.awt.*;
|
||||
*/
|
||||
public class WindowsRadioButtonUI extends BasicRadioButtonUI
|
||||
{
|
||||
private static final WindowsRadioButtonUI windowsRadioButtonUI = new WindowsRadioButtonUI();
|
||||
private static final Object WINDOWS_RADIO_BUTTON_UI_KEY = new Object();
|
||||
|
||||
protected int dashedRectGapX;
|
||||
protected int dashedRectGapY;
|
||||
@ -59,6 +61,13 @@ public class WindowsRadioButtonUI extends BasicRadioButtonUI
|
||||
// Create PLAF
|
||||
// ********************************
|
||||
public static ComponentUI createUI(JComponent c) {
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
WindowsRadioButtonUI windowsRadioButtonUI =
|
||||
(WindowsRadioButtonUI) appContext.get(WINDOWS_RADIO_BUTTON_UI_KEY);
|
||||
if (windowsRadioButtonUI == null) {
|
||||
windowsRadioButtonUI = new WindowsRadioButtonUI();
|
||||
appContext.put(WINDOWS_RADIO_BUTTON_UI_KEY, windowsRadioButtonUI);
|
||||
}
|
||||
return windowsRadioButtonUI;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
package com.sun.java.swing.plaf.windows;
|
||||
|
||||
import sun.awt.AppContext;
|
||||
|
||||
import javax.swing.plaf.basic.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.plaf.*;
|
||||
@ -49,18 +51,25 @@ import java.beans.PropertyChangeEvent;
|
||||
*/
|
||||
public class WindowsToggleButtonUI extends BasicToggleButtonUI
|
||||
{
|
||||
protected static int dashedRectGapX;
|
||||
protected static int dashedRectGapY;
|
||||
protected static int dashedRectGapWidth;
|
||||
protected static int dashedRectGapHeight;
|
||||
protected int dashedRectGapX;
|
||||
protected int dashedRectGapY;
|
||||
protected int dashedRectGapWidth;
|
||||
protected int dashedRectGapHeight;
|
||||
|
||||
protected Color focusColor;
|
||||
|
||||
private final static WindowsToggleButtonUI windowsToggleButtonUI = new WindowsToggleButtonUI();
|
||||
private static final Object WINDOWS_TOGGLE_BUTTON_UI_KEY = new Object();
|
||||
|
||||
private boolean defaults_initialized = false;
|
||||
|
||||
public static ComponentUI createUI(JComponent b) {
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
WindowsToggleButtonUI windowsToggleButtonUI =
|
||||
(WindowsToggleButtonUI) appContext.get(WINDOWS_TOGGLE_BUTTON_UI_KEY);
|
||||
if (windowsToggleButtonUI == null) {
|
||||
windowsToggleButtonUI = new WindowsToggleButtonUI();
|
||||
appContext.put(WINDOWS_TOGGLE_BUTTON_UI_KEY, windowsToggleButtonUI);
|
||||
}
|
||||
return windowsToggleButtonUI;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -176,18 +176,6 @@ public class JmxProperties {
|
||||
public static final String RELATION_LOGGER_NAME =
|
||||
"javax.management.relation";
|
||||
|
||||
/**
|
||||
* Logger name for Namespaces.
|
||||
*/
|
||||
public static final String NAMESPACE_LOGGER_NAME =
|
||||
"javax.management.namespace";
|
||||
|
||||
/**
|
||||
* Logger name for Namespaces.
|
||||
*/
|
||||
public static final Logger NAMESPACE_LOGGER =
|
||||
Logger.getLogger(NAMESPACE_LOGGER_NAME);
|
||||
|
||||
/**
|
||||
* Logger for Relation Service.
|
||||
*/
|
||||
|
@ -69,9 +69,9 @@ public class ServiceName {
|
||||
/**
|
||||
* The version of the JMX specification implemented by this product.
|
||||
* <BR>
|
||||
* The value is <CODE>2.0</CODE>.
|
||||
* The value is <CODE>1.4</CODE>.
|
||||
*/
|
||||
public static final String JMX_SPEC_VERSION = "2.0";
|
||||
public static final String JMX_SPEC_VERSION = "1.4";
|
||||
|
||||
/**
|
||||
* The vendor of the JMX specification implemented by this product.
|
||||
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.event;
|
||||
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class DaemonThreadFactory implements ThreadFactory {
|
||||
public DaemonThreadFactory(String nameTemplate) {
|
||||
this(nameTemplate, null);
|
||||
}
|
||||
|
||||
// nameTemplate should be a format with %d in it, which will be replaced
|
||||
// by a sequence number of threads created by this factory.
|
||||
public DaemonThreadFactory(String nameTemplate, ThreadGroup threadGroup) {
|
||||
if (logger.debugOn()) {
|
||||
logger.debug("DaemonThreadFactory",
|
||||
"Construct a new daemon factory: "+nameTemplate);
|
||||
}
|
||||
|
||||
if (threadGroup == null) {
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
threadGroup = (s != null) ? s.getThreadGroup() :
|
||||
Thread.currentThread().getThreadGroup();
|
||||
}
|
||||
|
||||
this.nameTemplate = nameTemplate;
|
||||
this.threadGroup = threadGroup;
|
||||
}
|
||||
|
||||
public Thread newThread(Runnable r) {
|
||||
final String name =
|
||||
String.format(nameTemplate, threadNumber.getAndIncrement());
|
||||
Thread t = new Thread(threadGroup, r, name, 0);
|
||||
t.setDaemon(true);
|
||||
if (t.getPriority() != Thread.NORM_PRIORITY)
|
||||
t.setPriority(Thread.NORM_PRIORITY);
|
||||
|
||||
if (logger.debugOn()) {
|
||||
logger.debug("newThread",
|
||||
"Create a new daemon thread with the name "+t.getName());
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
private final String nameTemplate;
|
||||
private final ThreadGroup threadGroup;
|
||||
private final AtomicInteger threadNumber = new AtomicInteger(1);
|
||||
|
||||
private static final ClassLogger logger =
|
||||
new ClassLogger("com.sun.jmx.event", "DaemonThreadFactory");
|
||||
}
|
@ -1,252 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.event;
|
||||
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.management.remote.NotificationResult;
|
||||
import javax.management.remote.TargetedNotification;
|
||||
|
||||
public class EventBuffer {
|
||||
|
||||
public EventBuffer() {
|
||||
this(Integer.MAX_VALUE, null);
|
||||
}
|
||||
|
||||
public EventBuffer(int capacity) {
|
||||
this(capacity, new ArrayList<TargetedNotification>());
|
||||
}
|
||||
|
||||
public EventBuffer(int capacity, final List<TargetedNotification> list) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("EventBuffer", "New buffer with the capacity: "
|
||||
+capacity);
|
||||
}
|
||||
if (capacity < 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"The capacity must be bigger than 0");
|
||||
}
|
||||
|
||||
if (list == null) {
|
||||
throw new NullPointerException("Null list.");
|
||||
}
|
||||
|
||||
this.capacity = capacity;
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
public void add(TargetedNotification tn) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("add", "Add one notif.");
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
if (list.size() == capacity) { // have to throw one
|
||||
passed++;
|
||||
list.remove(0);
|
||||
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("add", "Over, remove the oldest one.");
|
||||
}
|
||||
}
|
||||
|
||||
list.add(tn);
|
||||
lock.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public void add(TargetedNotification[] tns) {
|
||||
if (tns == null || tns.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("add", "Add notifs: "+tns.length);
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
final int d = list.size() - capacity + tns.length;
|
||||
if (d > 0) { // have to throw
|
||||
passed += d;
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("add",
|
||||
"Over, remove the oldest: "+d);
|
||||
}
|
||||
if (tns.length <= capacity){
|
||||
list.subList(0, d).clear();
|
||||
} else {
|
||||
list.clear();
|
||||
TargetedNotification[] tmp =
|
||||
new TargetedNotification[capacity];
|
||||
System.arraycopy(tns, tns.length-capacity, tmp, 0, capacity);
|
||||
tns = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
Collections.addAll(list,tns);
|
||||
lock.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public NotificationResult fetchNotifications(long startSequenceNumber,
|
||||
long timeout,
|
||||
int maxNotifications) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("fetchNotifications",
|
||||
"Being called: "
|
||||
+startSequenceNumber+" "
|
||||
+timeout+" "+maxNotifications);
|
||||
}
|
||||
if (startSequenceNumber < 0 ||
|
||||
timeout < 0 ||
|
||||
maxNotifications < 0) {
|
||||
throw new IllegalArgumentException("Negative value.");
|
||||
}
|
||||
|
||||
TargetedNotification[] tns = new TargetedNotification[0];
|
||||
long earliest = startSequenceNumber < passed ?
|
||||
passed : startSequenceNumber;
|
||||
long next = earliest;
|
||||
|
||||
final long startTime = System.currentTimeMillis();
|
||||
long toWait = timeout;
|
||||
synchronized(lock) {
|
||||
int toSkip = (int)(startSequenceNumber - passed);
|
||||
|
||||
// skip those before startSequenceNumber.
|
||||
while (!closed && toSkip > 0) {
|
||||
toWait = timeout - (System.currentTimeMillis() - startTime);
|
||||
if (list.size() == 0) {
|
||||
if (toWait <= 0) {
|
||||
// the notification of startSequenceNumber
|
||||
// does not arrive yet.
|
||||
return new NotificationResult(startSequenceNumber,
|
||||
startSequenceNumber,
|
||||
new TargetedNotification[0]);
|
||||
}
|
||||
|
||||
waiting(toWait);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (toSkip <= list.size()) {
|
||||
list.subList(0, toSkip).clear();
|
||||
passed += toSkip;
|
||||
|
||||
break;
|
||||
} else {
|
||||
passed += list.size();
|
||||
toSkip -= list.size();
|
||||
|
||||
list.clear();
|
||||
}
|
||||
}
|
||||
|
||||
earliest = passed;
|
||||
|
||||
if (list.size() == 0) {
|
||||
toWait = timeout - (System.currentTimeMillis() - startTime);
|
||||
|
||||
waiting(toWait);
|
||||
}
|
||||
|
||||
if (list.size() == 0) {
|
||||
tns = new TargetedNotification[0];
|
||||
} else if (list.size() <= maxNotifications) {
|
||||
tns = list.toArray(new TargetedNotification[0]);
|
||||
} else {
|
||||
tns = new TargetedNotification[maxNotifications];
|
||||
for (int i=0; i<maxNotifications; i++) {
|
||||
tns[i] = list.get(i);
|
||||
}
|
||||
}
|
||||
|
||||
next = earliest + tns.length;
|
||||
}
|
||||
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("fetchNotifications",
|
||||
"Return: "+earliest+" "+next+" "+tns.length);
|
||||
}
|
||||
|
||||
return new NotificationResult(earliest, next, tns);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
public void addLost(long nb) {
|
||||
synchronized(lock) {
|
||||
passed += nb;
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("clear", "done");
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
list.clear();
|
||||
closed = true;
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------
|
||||
// private classes
|
||||
// -------------------------------------------
|
||||
private void waiting(long timeout) {
|
||||
final long startTime = System.currentTimeMillis();
|
||||
long toWait = timeout;
|
||||
synchronized(lock) {
|
||||
while (!closed && list.size() == 0 && toWait > 0) {
|
||||
try {
|
||||
lock.wait(toWait);
|
||||
|
||||
toWait = timeout - (System.currentTimeMillis() - startTime);
|
||||
} catch (InterruptedException ire) {
|
||||
logger.trace("waiting", ire);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final int capacity;
|
||||
private final List<TargetedNotification> list;
|
||||
private boolean closed;
|
||||
|
||||
private long passed = 0;
|
||||
private final int[] lock = new int[0];
|
||||
|
||||
private static final ClassLogger logger =
|
||||
new ClassLogger("javax.management.event", "EventBuffer");
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.event;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.event.EventClient;
|
||||
import javax.management.event.EventClientDelegate;
|
||||
import javax.management.event.EventConsumer;
|
||||
import javax.management.event.NotificationManager;
|
||||
|
||||
/**
|
||||
* Override the methods related to the notification to use the
|
||||
* Event service.
|
||||
*/
|
||||
public interface EventConnection extends MBeanServerConnection, EventConsumer {
|
||||
public EventClient getEventClient();
|
||||
|
||||
public static class Factory {
|
||||
public static EventConnection make(
|
||||
final MBeanServerConnection mbsc,
|
||||
final EventClient eventClient)
|
||||
throws IOException {
|
||||
if (!mbsc.isRegistered(EventClientDelegate.OBJECT_NAME)) {
|
||||
throw new IOException(
|
||||
"The server does not support the event service.");
|
||||
}
|
||||
InvocationHandler ih = new InvocationHandler() {
|
||||
public Object invoke(Object proxy, Method method, Object[] args)
|
||||
throws Throwable {
|
||||
Class<?> intf = method.getDeclaringClass();
|
||||
try {
|
||||
if (intf.isInstance(eventClient))
|
||||
return method.invoke(eventClient, args);
|
||||
else
|
||||
return method.invoke(mbsc, args);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
};
|
||||
// It is important to declare NotificationManager.class first
|
||||
// in the array below, so that the relevant addNL and removeNL
|
||||
// methods will show up with method.getDeclaringClass() as
|
||||
// being from that interface and not MBeanServerConnection.
|
||||
return (EventConnection) Proxy.newProxyInstance(
|
||||
NotificationManager.class.getClassLoader(),
|
||||
new Class<?>[] {
|
||||
NotificationManager.class, EventConnection.class,
|
||||
},
|
||||
ih);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.event;
|
||||
|
||||
import com.sun.jmx.mbeanserver.GetPropertyAction;
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.security.AccessController;
|
||||
import javax.management.event.EventClient;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author sjiang
|
||||
*/
|
||||
public class EventParams {
|
||||
public static final String DEFAULT_LEASE_TIMEOUT =
|
||||
"com.sun.event.lease.time";
|
||||
|
||||
|
||||
@SuppressWarnings("cast") // cast for jdk 1.5
|
||||
public static long getLeaseTimeout() {
|
||||
long timeout = EventClient.DEFAULT_REQUESTED_LEASE_TIME;
|
||||
try {
|
||||
final GetPropertyAction act =
|
||||
new GetPropertyAction(DEFAULT_LEASE_TIMEOUT);
|
||||
final String s = (String)AccessController.doPrivileged(act);
|
||||
if (s != null) {
|
||||
timeout = Long.parseLong(s);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
logger.fine("getLeaseTimeout", "exception getting property", e);
|
||||
}
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/** Creates a new instance of EventParams */
|
||||
private EventParams() {
|
||||
}
|
||||
|
||||
private static final ClassLogger logger =
|
||||
new ClassLogger("javax.management.event", "EventParams");
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.event;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* <p>Manage a renewable lease. The lease can be renewed indefinitely
|
||||
* but if the lease runs to its current expiry date without being renewed
|
||||
* then the expiry callback is invoked. If the lease has already expired
|
||||
* when renewal is attempted then the lease method returns zero.</p>
|
||||
* @author sjiang
|
||||
* @author emcmanus
|
||||
*/
|
||||
// The synchronization logic of this class is tricky to deal correctly with the
|
||||
// case where the lease expires at the same time as the |lease| or |stop| method
|
||||
// is called. If the lease is active then the field |scheduled| represents
|
||||
// the expiry task; otherwise |scheduled| is null. Renewing or stopping the
|
||||
// lease involves canceling this task and setting |scheduled| either to a new
|
||||
// task (to renew) or to null (to stop).
|
||||
//
|
||||
// Suppose the expiry task runs at the same time as the |lease| method is called.
|
||||
// If the task enters its synchronized block before the method starts, then
|
||||
// it will set |scheduled| to null and the method will return 0. If the method
|
||||
// starts before the task enters its synchronized block, then the method will
|
||||
// cancel the task which will see that when it later enters the block.
|
||||
// Similar reasoning applies to the |stop| method. It is not expected that
|
||||
// different threads will call |lease| or |stop| simultaneously, although the
|
||||
// logic should be correct then too.
|
||||
public class LeaseManager {
|
||||
public LeaseManager(Runnable callback) {
|
||||
this(callback, EventParams.getLeaseTimeout());
|
||||
}
|
||||
|
||||
public LeaseManager(Runnable callback, long timeout) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("LeaseManager", "new manager with lease: "+timeout);
|
||||
}
|
||||
if (callback == null) {
|
||||
throw new NullPointerException("Null callback.");
|
||||
}
|
||||
if (timeout <= 0)
|
||||
throw new IllegalArgumentException("Timeout must be positive: " + timeout);
|
||||
|
||||
this.callback = callback;
|
||||
schedule(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Renew the lease for the given time. The new time can be shorter
|
||||
* than the previous one, in which case the lease will expire earlier
|
||||
* than it would have.</p>
|
||||
*
|
||||
* <p>Calling this method after the lease has expired will return zero
|
||||
* immediately and have no other effect.</p>
|
||||
*
|
||||
* @param timeout the new lifetime. If zero, the lease
|
||||
* will expire immediately.
|
||||
*/
|
||||
public synchronized long lease(long timeout) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("lease", "new lease to: "+timeout);
|
||||
}
|
||||
|
||||
if (timeout < 0)
|
||||
throw new IllegalArgumentException("Negative lease: " + timeout);
|
||||
|
||||
if (scheduled == null)
|
||||
return 0L;
|
||||
|
||||
scheduled.cancel(false);
|
||||
|
||||
if (logger.traceOn())
|
||||
logger.trace("lease", "start lease: "+timeout);
|
||||
schedule(timeout);
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
private class Expire implements Runnable {
|
||||
ScheduledFuture<?> task;
|
||||
|
||||
public void run() {
|
||||
synchronized (LeaseManager.this) {
|
||||
if (task.isCancelled())
|
||||
return;
|
||||
scheduled = null;
|
||||
}
|
||||
callback.run();
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void schedule(long timeout) {
|
||||
Expire expire = new Expire();
|
||||
scheduled = executor.schedule(expire, timeout, TimeUnit.MILLISECONDS);
|
||||
expire.task = scheduled;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Cancel the lease without calling the expiry callback.</p>
|
||||
*/
|
||||
public synchronized void stop() {
|
||||
logger.trace("stop", "canceling lease");
|
||||
scheduled.cancel(false);
|
||||
scheduled = null;
|
||||
try {
|
||||
executor.shutdown();
|
||||
} catch (SecurityException e) {
|
||||
// OK: caller doesn't have RuntimePermission("modifyThread")
|
||||
// which is unlikely in reality but triggers a test failure otherwise
|
||||
logger.trace("stop", "exception from executor.shutdown", e);
|
||||
}
|
||||
}
|
||||
|
||||
private final Runnable callback;
|
||||
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, threadFactory);
|
||||
|
||||
private static final ClassLogger logger =
|
||||
new ClassLogger("javax.management.event", "LeaseManager");
|
||||
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.event;
|
||||
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author sjiang
|
||||
*/
|
||||
public class LeaseRenewer {
|
||||
public LeaseRenewer(ScheduledExecutorService scheduler, Callable<Long> doRenew) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("LeaseRenewer", "New LeaseRenewer.");
|
||||
}
|
||||
|
||||
if (doRenew == null) {
|
||||
throw new NullPointerException("Null job to call server.");
|
||||
}
|
||||
|
||||
this.doRenew = doRenew;
|
||||
nextRenewTime = System.currentTimeMillis();
|
||||
|
||||
this.scheduler = scheduler;
|
||||
future = this.scheduler.schedule(myRenew, 0, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("close", "Close the lease.");
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
if (closed) {
|
||||
return;
|
||||
} else {
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
future.cancel(false); // not interrupt if running
|
||||
} catch (Exception e) {
|
||||
// OK
|
||||
if (logger.debugOn()) {
|
||||
logger.debug("close", "Failed to cancel the leasing job.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean closed() {
|
||||
synchronized(lock) {
|
||||
return closed;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
// private
|
||||
// ------------------------------
|
||||
private final Runnable myRenew = new Runnable() {
|
||||
public void run() {
|
||||
synchronized(lock) {
|
||||
if (closed()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
long next = nextRenewTime - System.currentTimeMillis();
|
||||
if (next < MIN_MILLIS) {
|
||||
try {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("myRenew-run", "");
|
||||
}
|
||||
next = doRenew.call().longValue();
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.fine("myRenew-run", "Failed to renew lease", e);
|
||||
close();
|
||||
}
|
||||
|
||||
if (next > 0 && next < Long.MAX_VALUE) {
|
||||
next = next/2;
|
||||
next = (next < MIN_MILLIS) ? MIN_MILLIS : next;
|
||||
} else {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
nextRenewTime = System.currentTimeMillis() + next;
|
||||
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("myRenew-run", "Next leasing: "+next);
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
if (!closed) {
|
||||
future = scheduler.schedule(this, next, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final Callable<Long> doRenew;
|
||||
private ScheduledFuture<?> future;
|
||||
private boolean closed = false;
|
||||
private long nextRenewTime;
|
||||
|
||||
private final int[] lock = new int[0];
|
||||
|
||||
private final ScheduledExecutorService scheduler;
|
||||
|
||||
private static final long MIN_MILLIS = 50;
|
||||
|
||||
private static final ClassLogger logger =
|
||||
new ClassLogger("javax.management.event", "LeaseRenewer");
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.event;
|
||||
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.management.remote.NotificationResult;
|
||||
import javax.management.remote.TargetedNotification;
|
||||
|
||||
|
||||
public class ReceiverBuffer {
|
||||
public void addNotifs(NotificationResult nr) {
|
||||
if (nr == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
TargetedNotification[] tns = nr.getTargetedNotifications();
|
||||
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("addNotifs", "" + tns.length);
|
||||
}
|
||||
|
||||
long impliedStart = nr.getEarliestSequenceNumber();
|
||||
final long missed = impliedStart - start;
|
||||
start = nr.getNextSequenceNumber();
|
||||
|
||||
if (missed > 0) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("addNotifs",
|
||||
"lost: "+missed);
|
||||
}
|
||||
|
||||
lost += missed;
|
||||
}
|
||||
|
||||
Collections.addAll(notifList, nr.getTargetedNotifications());
|
||||
}
|
||||
|
||||
public TargetedNotification[] removeNotifs() {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("removeNotifs", String.valueOf(notifList.size()));
|
||||
}
|
||||
|
||||
if (notifList.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TargetedNotification[] ret = notifList.toArray(
|
||||
new TargetedNotification[]{});
|
||||
notifList.clear();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return notifList.size();
|
||||
}
|
||||
|
||||
public int removeLost() {
|
||||
int ret = lost;
|
||||
lost = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private List<TargetedNotification> notifList
|
||||
= new ArrayList<TargetedNotification>();
|
||||
private long start = 0;
|
||||
private int lost = 0;
|
||||
|
||||
private static final ClassLogger logger =
|
||||
new ClassLogger("javax.management.event", "ReceiverBuffer");
|
||||
}
|
@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.event;
|
||||
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
/**
|
||||
* <p>A task that is repeatedly run by an Executor. The task will be
|
||||
* repeated as long as the {@link #isSuspended()} method returns true. Once
|
||||
* that method returns false, the task is no longer executed until someone
|
||||
* calls {@link #resume()}.</p>
|
||||
* @author sjiang
|
||||
*/
|
||||
public abstract class RepeatedSingletonJob implements Runnable {
|
||||
public RepeatedSingletonJob(Executor executor) {
|
||||
if (executor == null) {
|
||||
throw new NullPointerException("Null executor!");
|
||||
}
|
||||
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
public boolean isWorking() {
|
||||
return working;
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
|
||||
synchronized(this) {
|
||||
if (!working) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("resume", "");
|
||||
}
|
||||
working = true;
|
||||
execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void task();
|
||||
public abstract boolean isSuspended();
|
||||
|
||||
public void run() {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("run", "execute the task");
|
||||
}
|
||||
try {
|
||||
task();
|
||||
} catch (Exception e) {
|
||||
// A correct task() implementation should not throw exceptions.
|
||||
// It may cause isSuspended() to start returning true, though.
|
||||
logger.trace("run", "failed to execute the task", e);
|
||||
}
|
||||
|
||||
synchronized(this) {
|
||||
if (!isSuspended()) {
|
||||
execute();
|
||||
} else {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("run", "suspend the task");
|
||||
}
|
||||
working = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void execute() {
|
||||
try {
|
||||
executor.execute(this);
|
||||
} catch (RejectedExecutionException e) {
|
||||
logger.warning(
|
||||
"execute",
|
||||
"Executor threw exception (" + this.getClass().getName() + ")",
|
||||
e);
|
||||
throw new RejectedExecutionException(
|
||||
"Executor.execute threw exception -" +
|
||||
"should not be possible", e);
|
||||
// User-supplied Executor should not be configured in a way that
|
||||
// might cause this exception, for example if it is shared between
|
||||
// several client objects and doesn't have capacity for one job
|
||||
// from each one. CR 6732037 will add text to the spec explaining
|
||||
// the problem. The rethrown exception will propagate either out
|
||||
// of resume() to user code, or out of run() to the Executor
|
||||
// (which will probably ignore it).
|
||||
}
|
||||
}
|
||||
|
||||
private boolean working = false;
|
||||
private final Executor executor;
|
||||
|
||||
private static final ClassLogger logger =
|
||||
new ClassLogger("javax.management.event", "RepeatedSingletonJob");
|
||||
}
|
@ -30,16 +30,15 @@ package com.sun.jmx.interceptor;
|
||||
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
|
||||
import com.sun.jmx.mbeanserver.DynamicMBean2;
|
||||
import com.sun.jmx.mbeanserver.Introspector;
|
||||
import com.sun.jmx.mbeanserver.MBeanInjector;
|
||||
import com.sun.jmx.mbeanserver.MBeanInstantiator;
|
||||
import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository;
|
||||
import com.sun.jmx.mbeanserver.NamedObject;
|
||||
import com.sun.jmx.mbeanserver.NotifySupport;
|
||||
import com.sun.jmx.mbeanserver.Repository;
|
||||
import com.sun.jmx.mbeanserver.Repository.RegistrationContext;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
@ -48,10 +47,7 @@ import java.security.PrivilegedAction;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.logging.Level;
|
||||
@ -61,7 +57,6 @@ import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.DynamicWrapperMBean;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.IntrospectionException;
|
||||
@ -70,7 +65,6 @@ import javax.management.JMRuntimeException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanPermission;
|
||||
import javax.management.MBeanRegistration;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
@ -81,19 +75,19 @@ import javax.management.MBeanTrustPermission;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationBroadcaster;
|
||||
import javax.management.NotificationBroadcasterSupport;
|
||||
import javax.management.NotificationEmitter;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.OperationsException;
|
||||
import javax.management.QueryEval;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.RuntimeErrorException;
|
||||
import javax.management.RuntimeMBeanException;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
import javax.management.namespace.JMXNamespace;
|
||||
import javax.management.loading.ClassLoaderRepository;
|
||||
|
||||
/**
|
||||
* This is the default class for MBean manipulation on the agent side. It
|
||||
@ -116,8 +110,7 @@ import javax.management.namespace.JMXNamespace;
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public class DefaultMBeanServerInterceptor
|
||||
extends MBeanServerInterceptorSupport {
|
||||
public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
|
||||
/** The MBeanInstantiator object used by the
|
||||
* DefaultMBeanServerInterceptor */
|
||||
@ -142,14 +135,9 @@ public class DefaultMBeanServerInterceptor
|
||||
new WeakHashMap<ListenerWrapper,
|
||||
WeakReference<ListenerWrapper>>();
|
||||
|
||||
private final NamespaceDispatchInterceptor dispatcher;
|
||||
|
||||
/** The default domain of the object names */
|
||||
private final String domain;
|
||||
|
||||
/** The mbeanServerName */
|
||||
private final String mbeanServerName;
|
||||
|
||||
/** The sequence number identifying the notifications sent */
|
||||
// Now sequence number is handled by MBeanServerDelegate.
|
||||
// private int sequenceNumber=0;
|
||||
@ -168,13 +156,11 @@ public class DefaultMBeanServerInterceptor
|
||||
* @param instantiator The MBeanInstantiator that will be used to
|
||||
* instantiate MBeans and take care of class loading issues.
|
||||
* @param repository The repository to use for this MBeanServer.
|
||||
* @param dispatcher The dispatcher used by this MBeanServer
|
||||
*/
|
||||
public DefaultMBeanServerInterceptor(MBeanServer outer,
|
||||
MBeanServerDelegate delegate,
|
||||
MBeanInstantiator instantiator,
|
||||
Repository repository,
|
||||
NamespaceDispatchInterceptor dispatcher) {
|
||||
Repository repository) {
|
||||
if (outer == null) throw new
|
||||
IllegalArgumentException("outer MBeanServer cannot be null");
|
||||
if (delegate == null) throw new
|
||||
@ -189,8 +175,6 @@ public class DefaultMBeanServerInterceptor
|
||||
this.instantiator = instantiator;
|
||||
this.repository = repository;
|
||||
this.domain = repository.getDefaultDomain();
|
||||
this.dispatcher = dispatcher;
|
||||
this.mbeanServerName = Util.getMBeanServerSecurityName(delegate);
|
||||
}
|
||||
|
||||
public ObjectInstance createMBean(String className, ObjectName name)
|
||||
@ -269,8 +253,8 @@ public class DefaultMBeanServerInterceptor
|
||||
name = nonDefaultDomain(name);
|
||||
}
|
||||
|
||||
checkMBeanPermission(mbeanServerName,className, null, null, "instantiate");
|
||||
checkMBeanPermission(mbeanServerName,className, null, name, "registerMBean");
|
||||
checkMBeanPermission(className, null, null, "instantiate");
|
||||
checkMBeanPermission(className, null, name, "registerMBean");
|
||||
|
||||
/* Load the appropriate class. */
|
||||
if (withDefaultLoaderRepository) {
|
||||
@ -334,7 +318,7 @@ public class DefaultMBeanServerInterceptor
|
||||
|
||||
final String infoClassName = getNewMBeanClassName(object);
|
||||
|
||||
checkMBeanPermission(mbeanServerName,infoClassName, null, name, "registerMBean");
|
||||
checkMBeanPermission(infoClassName, null, name, "registerMBean");
|
||||
checkMBeanTrustPermission(theClass);
|
||||
|
||||
return registerObject(infoClassName, object, name);
|
||||
@ -443,8 +427,7 @@ public class DefaultMBeanServerInterceptor
|
||||
DynamicMBean instance = getMBean(name);
|
||||
// may throw InstanceNotFoundException
|
||||
|
||||
checkMBeanPermission(mbeanServerName, instance, null, name,
|
||||
"unregisterMBean");
|
||||
checkMBeanPermission(instance, null, name, "unregisterMBean");
|
||||
|
||||
if (instance instanceof MBeanRegistration)
|
||||
preDeregisterInvoke((MBeanRegistration) instance);
|
||||
@ -478,8 +461,7 @@ public class DefaultMBeanServerInterceptor
|
||||
name = nonDefaultDomain(name);
|
||||
DynamicMBean instance = getMBean(name);
|
||||
|
||||
checkMBeanPermission(mbeanServerName,
|
||||
instance, null, name, "getObjectInstance");
|
||||
checkMBeanPermission(instance, null, name, "getObjectInstance");
|
||||
|
||||
final String className = getClassName(instance);
|
||||
|
||||
@ -491,7 +473,7 @@ public class DefaultMBeanServerInterceptor
|
||||
if (sm != null) {
|
||||
// Check if the caller has the right to invoke 'queryMBeans'
|
||||
//
|
||||
checkMBeanPermission(mbeanServerName,(String) null, null, null, "queryMBeans");
|
||||
checkMBeanPermission((String) null, null, null, "queryMBeans");
|
||||
|
||||
// Perform query without "query".
|
||||
//
|
||||
@ -504,7 +486,7 @@ public class DefaultMBeanServerInterceptor
|
||||
new HashSet<ObjectInstance>(list.size());
|
||||
for (ObjectInstance oi : list) {
|
||||
try {
|
||||
checkMBeanPermission(mbeanServerName,oi.getClassName(), null,
|
||||
checkMBeanPermission(oi.getClassName(), null,
|
||||
oi.getObjectName(), "queryMBeans");
|
||||
allowedList.add(oi);
|
||||
} catch (SecurityException e) {
|
||||
@ -537,7 +519,7 @@ public class DefaultMBeanServerInterceptor
|
||||
if (sm != null) {
|
||||
// Check if the caller has the right to invoke 'queryNames'
|
||||
//
|
||||
checkMBeanPermission(mbeanServerName,(String) null, null, null, "queryNames");
|
||||
checkMBeanPermission((String) null, null, null, "queryNames");
|
||||
|
||||
// Perform query without "query".
|
||||
//
|
||||
@ -550,7 +532,7 @@ public class DefaultMBeanServerInterceptor
|
||||
new HashSet<ObjectInstance>(list.size());
|
||||
for (ObjectInstance oi : list) {
|
||||
try {
|
||||
checkMBeanPermission(mbeanServerName, oi.getClassName(), null,
|
||||
checkMBeanPermission(oi.getClassName(), null,
|
||||
oi.getObjectName(), "queryNames");
|
||||
allowedList.add(oi);
|
||||
} catch (SecurityException e) {
|
||||
@ -602,7 +584,7 @@ public class DefaultMBeanServerInterceptor
|
||||
if (sm != null) {
|
||||
// Check if the caller has the right to invoke 'getDomains'
|
||||
//
|
||||
checkMBeanPermission(mbeanServerName, (String) null, null, null, "getDomains");
|
||||
checkMBeanPermission((String) null, null, null, "getDomains");
|
||||
|
||||
// Return domains
|
||||
//
|
||||
@ -614,8 +596,8 @@ public class DefaultMBeanServerInterceptor
|
||||
List<String> result = new ArrayList<String>(domains.length);
|
||||
for (int i = 0; i < domains.length; i++) {
|
||||
try {
|
||||
ObjectName dom = ObjectName.valueOf(domains[i] + ":x=x");
|
||||
checkMBeanPermission(mbeanServerName, (String) null, null, dom, "getDomains");
|
||||
ObjectName dom = Util.newObjectName(domains[i] + ":x=x");
|
||||
checkMBeanPermission((String) null, null, dom, "getDomains");
|
||||
result.add(domains[i]);
|
||||
} catch (SecurityException e) {
|
||||
// OK: Do not add this domain to the list
|
||||
@ -659,8 +641,7 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
|
||||
final DynamicMBean instance = getMBean(name);
|
||||
checkMBeanPermission(mbeanServerName, instance, attribute,
|
||||
name, "getAttribute");
|
||||
checkMBeanPermission(instance, attribute, name, "getAttribute");
|
||||
|
||||
try {
|
||||
return instance.getAttribute(attribute);
|
||||
@ -705,7 +686,7 @@ public class DefaultMBeanServerInterceptor
|
||||
|
||||
// Check if the caller has the right to invoke 'getAttribute'
|
||||
//
|
||||
checkMBeanPermission(mbeanServerName, classname, null, name, "getAttribute");
|
||||
checkMBeanPermission(classname, null, name, "getAttribute");
|
||||
|
||||
// Check if the caller has the right to invoke 'getAttribute'
|
||||
// on each specific attribute
|
||||
@ -714,8 +695,7 @@ public class DefaultMBeanServerInterceptor
|
||||
new ArrayList<String>(attributes.length);
|
||||
for (String attr : attributes) {
|
||||
try {
|
||||
checkMBeanPermission(mbeanServerName, classname, attr,
|
||||
name, "getAttribute");
|
||||
checkMBeanPermission(classname, attr, name, "getAttribute");
|
||||
allowedList.add(attr);
|
||||
} catch (SecurityException e) {
|
||||
// OK: Do not add this attribute to the list
|
||||
@ -760,8 +740,7 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
|
||||
DynamicMBean instance = getMBean(name);
|
||||
checkMBeanPermission(mbeanServerName, instance, attribute.getName(),
|
||||
name, "setAttribute");
|
||||
checkMBeanPermission(instance, attribute.getName(), name, "setAttribute");
|
||||
|
||||
try {
|
||||
instance.setAttribute(attribute);
|
||||
@ -803,7 +782,7 @@ public class DefaultMBeanServerInterceptor
|
||||
|
||||
// Check if the caller has the right to invoke 'setAttribute'
|
||||
//
|
||||
checkMBeanPermission(mbeanServerName, classname, null, name, "setAttribute");
|
||||
checkMBeanPermission(classname, null, name, "setAttribute");
|
||||
|
||||
// Check if the caller has the right to invoke 'setAttribute'
|
||||
// on each specific attribute
|
||||
@ -811,7 +790,7 @@ public class DefaultMBeanServerInterceptor
|
||||
allowedAttributes = new AttributeList(attributes.size());
|
||||
for (Attribute attribute : attributes.asList()) {
|
||||
try {
|
||||
checkMBeanPermission(mbeanServerName, classname, attribute.getName(),
|
||||
checkMBeanPermission(classname, attribute.getName(),
|
||||
name, "setAttribute");
|
||||
allowedAttributes.add(attribute);
|
||||
} catch (SecurityException e) {
|
||||
@ -835,8 +814,7 @@ public class DefaultMBeanServerInterceptor
|
||||
name = nonDefaultDomain(name);
|
||||
|
||||
DynamicMBean instance = getMBean(name);
|
||||
checkMBeanPermission(mbeanServerName, instance, operationName,
|
||||
name, "invoke");
|
||||
checkMBeanPermission(instance, operationName, name, "invoke");
|
||||
try {
|
||||
return instance.invoke(operationName, params, signature);
|
||||
} catch (Throwable t) {
|
||||
@ -919,12 +897,6 @@ public class DefaultMBeanServerInterceptor
|
||||
|
||||
DynamicMBean mbean = Introspector.makeDynamicMBean(object);
|
||||
|
||||
//Access the ObjectName template value only if the provided name is null
|
||||
if(name == null) {
|
||||
name = Introspector.templateToObjectName(mbean.getMBeanInfo().
|
||||
getDescriptor(), mbean);
|
||||
}
|
||||
|
||||
return registerDynamicMBean(classname, mbean, name);
|
||||
}
|
||||
|
||||
@ -953,8 +925,6 @@ public class DefaultMBeanServerInterceptor
|
||||
ResourceContext context = null;
|
||||
|
||||
try {
|
||||
mbean = injectResources(mbean, server, logicalName);
|
||||
|
||||
if (mbean instanceof DynamicMBean2) {
|
||||
try {
|
||||
((DynamicMBean2) mbean).preRegister2(server, logicalName);
|
||||
@ -973,8 +943,7 @@ public class DefaultMBeanServerInterceptor
|
||||
ObjectName.getInstance(nonDefaultDomain(logicalName));
|
||||
}
|
||||
|
||||
checkMBeanPermission(mbeanServerName, classname, null, logicalName,
|
||||
"registerMBean");
|
||||
checkMBeanPermission(classname, null, logicalName, "registerMBean");
|
||||
|
||||
if (logicalName == null) {
|
||||
final RuntimeException wrapped =
|
||||
@ -988,10 +957,9 @@ public class DefaultMBeanServerInterceptor
|
||||
// Register the MBean with the repository.
|
||||
// Returns the resource context that was used.
|
||||
// The returned context does nothing for regular MBeans.
|
||||
// For ClassLoader MBeans and JMXNamespace (and JMXDomain)
|
||||
// MBeans - the context makes it possible to register these
|
||||
// For ClassLoader MBeans the context makes it possible to register these
|
||||
// objects with the appropriate framework artifacts, such as
|
||||
// the CLR or the dispatcher, from within the repository lock.
|
||||
// the CLR, from within the repository lock.
|
||||
// In case of success, we also need to call context.done() at the
|
||||
// end of this method.
|
||||
//
|
||||
@ -1045,27 +1013,6 @@ public class DefaultMBeanServerInterceptor
|
||||
else return name;
|
||||
}
|
||||
|
||||
private static DynamicMBean injectResources(
|
||||
DynamicMBean mbean, MBeanServer mbs, ObjectName name)
|
||||
throws MBeanRegistrationException {
|
||||
try {
|
||||
Object resource = getResource(mbean);
|
||||
MBeanInjector.inject(resource, mbs, name);
|
||||
if (MBeanInjector.injectsSendNotification(resource)) {
|
||||
MBeanNotificationInfo[] mbnis =
|
||||
mbean.getMBeanInfo().getNotifications();
|
||||
NotificationBroadcasterSupport nbs =
|
||||
new NotificationBroadcasterSupport(mbnis);
|
||||
MBeanInjector.injectSendNotification(resource, nbs);
|
||||
mbean = NotifySupport.wrap(mbean, nbs);
|
||||
}
|
||||
return mbean;
|
||||
} catch (Throwable t) {
|
||||
throwMBeanRegistrationException(t, "injecting @Resources");
|
||||
return null; // not reached
|
||||
}
|
||||
}
|
||||
|
||||
private static void postRegister(
|
||||
ObjectName logicalName, DynamicMBean mbean,
|
||||
boolean registrationDone, boolean registerFailed) {
|
||||
@ -1151,19 +1098,12 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
|
||||
private static Object getResource(DynamicMBean mbean) {
|
||||
if (mbean instanceof DynamicWrapperMBean)
|
||||
return ((DynamicWrapperMBean) mbean).getWrappedObject();
|
||||
if (mbean instanceof DynamicMBean2)
|
||||
return ((DynamicMBean2) mbean).getResource();
|
||||
else
|
||||
return mbean;
|
||||
}
|
||||
|
||||
private static ClassLoader getResourceLoader(DynamicMBean mbean) {
|
||||
if (mbean instanceof DynamicWrapperMBean)
|
||||
return ((DynamicWrapperMBean) mbean).getWrappedClassLoader();
|
||||
else
|
||||
return mbean.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
private ObjectName nonDefaultDomain(ObjectName name) {
|
||||
if (name == null || name.getDomain().length() > 0)
|
||||
return name;
|
||||
@ -1177,7 +1117,7 @@ public class DefaultMBeanServerInterceptor
|
||||
if one is supplied where it shouldn't be). */
|
||||
final String completeName = domain + name;
|
||||
|
||||
return ObjectName.valueOf(completeName);
|
||||
return Util.newObjectName(completeName);
|
||||
}
|
||||
|
||||
public String getDefaultDomain() {
|
||||
@ -1243,8 +1183,7 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
|
||||
DynamicMBean instance = getMBean(name);
|
||||
checkMBeanPermission(mbeanServerName, instance, null,
|
||||
name, "addNotificationListener");
|
||||
checkMBeanPermission(instance, null, name, "addNotificationListener");
|
||||
|
||||
NotificationBroadcaster broadcaster =
|
||||
getNotificationBroadcaster(name, instance,
|
||||
@ -1381,8 +1320,7 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
|
||||
DynamicMBean instance = getMBean(name);
|
||||
checkMBeanPermission(mbeanServerName, instance, null, name,
|
||||
"removeNotificationListener");
|
||||
checkMBeanPermission(instance, null, name, "removeNotificationListener");
|
||||
|
||||
/* We could simplify the code by assigning broadcaster after
|
||||
assigning listenerWrapper, but that would change the error
|
||||
@ -1415,8 +1353,8 @@ public class DefaultMBeanServerInterceptor
|
||||
Class<T> reqClass) {
|
||||
if (reqClass.isInstance(instance))
|
||||
return reqClass.cast(instance);
|
||||
if (instance instanceof DynamicWrapperMBean)
|
||||
instance = ((DynamicWrapperMBean) instance).getWrappedObject();
|
||||
if (instance instanceof DynamicMBean2)
|
||||
instance = ((DynamicMBean2) instance).getResource();
|
||||
if (reqClass.isInstance(instance))
|
||||
return reqClass.cast(instance);
|
||||
final RuntimeException exc =
|
||||
@ -1452,7 +1390,7 @@ public class DefaultMBeanServerInterceptor
|
||||
throw new JMRuntimeException("MBean " + name +
|
||||
"has no MBeanInfo");
|
||||
|
||||
checkMBeanPermission(mbeanServerName, mbi.getClassName(), null, name, "getMBeanInfo");
|
||||
checkMBeanPermission(mbi.getClassName(), null, name, "getMBeanInfo");
|
||||
|
||||
return mbi;
|
||||
}
|
||||
@ -1461,8 +1399,7 @@ public class DefaultMBeanServerInterceptor
|
||||
throws InstanceNotFoundException {
|
||||
|
||||
final DynamicMBean instance = getMBean(name);
|
||||
checkMBeanPermission(mbeanServerName,
|
||||
instance, null, name, "isInstanceOf");
|
||||
checkMBeanPermission(instance, null, name, "isInstanceOf");
|
||||
|
||||
try {
|
||||
Object resource = getResource(instance);
|
||||
@ -1474,20 +1411,12 @@ public class DefaultMBeanServerInterceptor
|
||||
|
||||
if (resourceClassName.equals(className))
|
||||
return true;
|
||||
final ClassLoader cl = getResourceLoader(instance);
|
||||
final ClassLoader cl = resource.getClass().getClassLoader();
|
||||
|
||||
final Class<?> classNameClass = Class.forName(className, false, cl);
|
||||
if (classNameClass.isInstance(resource))
|
||||
return true;
|
||||
|
||||
// Ensure that isInstanceOf(NotificationEmitter) is true when
|
||||
// the MBean is a NotificationEmitter by virtue of a @Resource
|
||||
// annotation specifying a SendNotification resource.
|
||||
// This is a hack.
|
||||
if (instance instanceof NotificationBroadcaster &&
|
||||
classNameClass.isAssignableFrom(NotificationEmitter.class))
|
||||
return true;
|
||||
|
||||
final Class<?> resourceClass = Class.forName(resourceClassName, false, cl);
|
||||
return classNameClass.isAssignableFrom(resourceClass);
|
||||
} catch (Exception x) {
|
||||
@ -1513,9 +1442,8 @@ public class DefaultMBeanServerInterceptor
|
||||
throws InstanceNotFoundException {
|
||||
|
||||
DynamicMBean instance = getMBean(mbeanName);
|
||||
checkMBeanPermission(mbeanServerName, instance, null, mbeanName,
|
||||
"getClassLoaderFor");
|
||||
return getResourceLoader(instance);
|
||||
checkMBeanPermission(instance, null, mbeanName, "getClassLoaderFor");
|
||||
return getResource(instance).getClass().getClassLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1529,13 +1457,12 @@ public class DefaultMBeanServerInterceptor
|
||||
throws InstanceNotFoundException {
|
||||
|
||||
if (loaderName == null) {
|
||||
checkMBeanPermission(mbeanServerName, (String) null, null, null, "getClassLoader");
|
||||
checkMBeanPermission((String) null, null, null, "getClassLoader");
|
||||
return server.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
DynamicMBean instance = getMBean(loaderName);
|
||||
checkMBeanPermission(mbeanServerName, instance, null, loaderName,
|
||||
"getClassLoader");
|
||||
checkMBeanPermission(instance, null, loaderName, "getClassLoader");
|
||||
|
||||
Object resource = getResource(instance);
|
||||
|
||||
@ -1757,6 +1684,49 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
}
|
||||
|
||||
public Object instantiate(String className) throws ReflectionException,
|
||||
MBeanException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public Object instantiate(String className, ObjectName loaderName) throws ReflectionException,
|
||||
MBeanException,
|
||||
InstanceNotFoundException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public Object instantiate(String className, Object[] params,
|
||||
String[] signature) throws ReflectionException, MBeanException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public Object instantiate(String className, ObjectName loaderName,
|
||||
Object[] params, String[] signature) throws ReflectionException,
|
||||
MBeanException,
|
||||
InstanceNotFoundException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public ObjectInputStream deserialize(ObjectName name, byte[] data) throws InstanceNotFoundException,
|
||||
OperationsException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public ObjectInputStream deserialize(String className, byte[] data) throws OperationsException,
|
||||
ReflectionException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public ObjectInputStream deserialize(String className, ObjectName loaderName,
|
||||
byte[] data) throws InstanceNotFoundException, OperationsException,
|
||||
ReflectionException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public ClassLoaderRepository getClassLoaderRepository() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
private static class ListenerWrapper implements NotificationListener {
|
||||
ListenerWrapper(NotificationListener l, ObjectName name,
|
||||
Object mbean) {
|
||||
@ -1834,30 +1804,26 @@ public class DefaultMBeanServerInterceptor
|
||||
return mbean.getMBeanInfo().getClassName();
|
||||
}
|
||||
|
||||
private static void checkMBeanPermission(String mbeanServerName,
|
||||
DynamicMBean mbean,
|
||||
private static void checkMBeanPermission(DynamicMBean mbean,
|
||||
String member,
|
||||
ObjectName objectName,
|
||||
String actions) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMBeanPermission(mbeanServerName,
|
||||
safeGetClassName(mbean),
|
||||
checkMBeanPermission(safeGetClassName(mbean),
|
||||
member,
|
||||
objectName,
|
||||
actions);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkMBeanPermission(String mbeanServerName,
|
||||
String classname,
|
||||
private static void checkMBeanPermission(String classname,
|
||||
String member,
|
||||
ObjectName objectName,
|
||||
String actions) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
Permission perm = new MBeanPermission(mbeanServerName,
|
||||
classname,
|
||||
Permission perm = new MBeanPermission(classname,
|
||||
member,
|
||||
objectName,
|
||||
actions);
|
||||
@ -1923,12 +1889,6 @@ public class DefaultMBeanServerInterceptor
|
||||
throws InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException {
|
||||
|
||||
// this will throw an exception if the pair (resource, logicalName)
|
||||
// violates namespace conventions - for instance, if logicalName
|
||||
// ends with // but resource is not a JMXNamespace.
|
||||
//
|
||||
checkResourceObjectNameConstraints(resource, logicalName);
|
||||
|
||||
// Creates a registration context, if needed.
|
||||
//
|
||||
final ResourceContext context =
|
||||
@ -1995,56 +1955,6 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks that the ObjectName is legal with regards to the
|
||||
* type of the MBean resource.
|
||||
* If the MBean name is domain:type=JMXDomain, the
|
||||
* MBean must be a JMXDomain.
|
||||
* If the MBean name is namespace//:type=JMXNamespace, the
|
||||
* MBean must be a JMXNamespace.
|
||||
* If the MBean is a JMXDomain, its name
|
||||
* must be domain:type=JMXDomain.
|
||||
* If the MBean is a JMXNamespace, its name
|
||||
* must be namespace//:type=JMXNamespace.
|
||||
*/
|
||||
private void checkResourceObjectNameConstraints(Object resource,
|
||||
ObjectName logicalName)
|
||||
throws MBeanRegistrationException {
|
||||
try {
|
||||
dispatcher.checkLocallyRegistrable(resource, logicalName);
|
||||
} catch (Throwable x) {
|
||||
DefaultMBeanServerInterceptor.throwMBeanRegistrationException(x, "validating ObjectName");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a JMXNamespace with the dispatcher.
|
||||
* This method is called by the ResourceContext from within the
|
||||
* repository lock.
|
||||
* @param namespace The JMXNamespace
|
||||
* @param logicalName The JMXNamespaceMBean ObjectName
|
||||
* @param postQueue A queue that will be processed after postRegister.
|
||||
*/
|
||||
private void addJMXNamespace(JMXNamespace namespace,
|
||||
final ObjectName logicalName,
|
||||
final Queue<Runnable> postQueue) {
|
||||
dispatcher.addInterceptorFor(logicalName, namespace, postQueue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a JMXNamespace from the dispatcher.
|
||||
* This method is called by the ResourceContext from within the
|
||||
* repository lock.
|
||||
* @param namespace The JMXNamespace
|
||||
* @param logicalName The JMXNamespaceMBean ObjectName
|
||||
* @param postQueue A queue that will be processed after postDeregister.
|
||||
*/
|
||||
private void removeJMXNamespace(JMXNamespace namespace,
|
||||
final ObjectName logicalName,
|
||||
final Queue<Runnable> postQueue) {
|
||||
dispatcher.removeInterceptorFor(logicalName, namespace, postQueue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a ClassLoader with the CLR.
|
||||
* This method is called by the ResourceContext from within the
|
||||
@ -2099,51 +2009,6 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a ResourceContext for a JMXNamespace MBean.
|
||||
* The resource context makes it possible to add the JMXNamespace to
|
||||
* (ResourceContext.registering) or resp. remove the JMXNamespace from
|
||||
* (ResourceContext.unregistered) the NamespaceDispatchInterceptor
|
||||
* when the associated MBean is added to or resp. removed from the
|
||||
* repository.
|
||||
* Note: JMXDomains are special sub classes of JMXNamespaces and
|
||||
* are also handled by this object.
|
||||
*
|
||||
* @param namespace The JMXNamespace MBean being registered or
|
||||
* unregistered.
|
||||
* @param logicalName The name of the JMXNamespace MBean.
|
||||
* @return a ResourceContext that takes in charge the addition or removal
|
||||
* of the namespace to or from the NamespaceDispatchInterceptor.
|
||||
*/
|
||||
private ResourceContext createJMXNamespaceContext(
|
||||
final JMXNamespace namespace,
|
||||
final ObjectName logicalName) {
|
||||
final Queue<Runnable> doneTaskQueue = new LinkedList<Runnable>();
|
||||
return new ResourceContext() {
|
||||
|
||||
public void registering() {
|
||||
addJMXNamespace(namespace, logicalName, doneTaskQueue);
|
||||
}
|
||||
|
||||
public void unregistered() {
|
||||
removeJMXNamespace(namespace, logicalName,
|
||||
doneTaskQueue);
|
||||
}
|
||||
|
||||
public void done() {
|
||||
for (Runnable r : doneTaskQueue) {
|
||||
try {
|
||||
r.run();
|
||||
} catch (RuntimeException x) {
|
||||
MBEANSERVER_LOGGER.log(Level.FINE,
|
||||
"Failed to process post queue for "+
|
||||
logicalName, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ResourceContext for a ClassLoader MBean.
|
||||
* The resource context makes it possible to add the ClassLoader to
|
||||
@ -2180,8 +2045,7 @@ public class DefaultMBeanServerInterceptor
|
||||
* Creates a ResourceContext for the given resource.
|
||||
* If the resource does not need a ResourceContext, returns
|
||||
* ResourceContext.NONE.
|
||||
* At this time, only JMXNamespaces and ClassLoaders need a
|
||||
* ResourceContext.
|
||||
* At this time, only ClassLoaders need a ResourceContext.
|
||||
*
|
||||
* @param resource The resource being registered or unregistered.
|
||||
* @param logicalName The name of the associated MBean.
|
||||
@ -2189,10 +2053,6 @@ public class DefaultMBeanServerInterceptor
|
||||
*/
|
||||
private ResourceContext makeResourceContextFor(Object resource,
|
||||
ObjectName logicalName) {
|
||||
if (resource instanceof JMXNamespace) {
|
||||
return createJMXNamespaceContext((JMXNamespace) resource,
|
||||
logicalName);
|
||||
}
|
||||
if (resource instanceof ClassLoader) {
|
||||
return createClassLoaderContext((ClassLoader) resource,
|
||||
logicalName);
|
||||
|
@ -1,551 +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.interceptor;
|
||||
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.namespace.JMXNamespace;
|
||||
|
||||
/**
|
||||
* A dispatcher that dispatches to MBeanServers.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
//
|
||||
// This is the base class for implementing dispatchers. We have two concrete
|
||||
// dispatcher implementations:
|
||||
//
|
||||
// * A NamespaceDispatchInterceptor, which dispatch calls to existing
|
||||
// namespace interceptors
|
||||
// * A DomainDispatchInterceptor, which dispatch calls to existing domain
|
||||
// interceptors.
|
||||
//
|
||||
// With the JMX Namespaces feature, the JMX MBeanServer is now structured
|
||||
// as follows:
|
||||
//
|
||||
// The JMX MBeanServer delegates to a NamespaceDispatchInterceptor,
|
||||
// which either dispatches to a namespace, or delegates to the
|
||||
// DomainDispatchInterceptor (if the object name contained no namespace).
|
||||
// The DomainDispatchInterceptor in turn either dispatches to a domain (if
|
||||
// there is a JMXDomain for that domain) or delegates to the
|
||||
// DefaultMBeanServerInterceptor (if there is no JMXDomain for that
|
||||
// domain). This makes the following picture:
|
||||
//
|
||||
// JMX MBeanServer (outer shell)
|
||||
// |
|
||||
// |
|
||||
// NamespaceDispatchInterceptor
|
||||
// / \
|
||||
// no namespace in object name? \
|
||||
// / \
|
||||
// / dispatch to namespace
|
||||
// DomainDispatchInterceptor
|
||||
// / \
|
||||
// no JMXDomain for domain? \
|
||||
// / \
|
||||
// / dispatch to domain
|
||||
// DefaultMBeanServerInterceptor
|
||||
// /
|
||||
// invoke locally registered MBean
|
||||
//
|
||||
// The logic for maintaining a map of interceptors
|
||||
// and dispatching to impacted interceptor, is implemented in this
|
||||
// base class, which both NamespaceDispatchInterceptor and
|
||||
// DomainDispatchInterceptor extend.
|
||||
//
|
||||
public abstract class DispatchInterceptor
|
||||
<T extends MBeanServer, N extends JMXNamespace>
|
||||
extends MBeanServerInterceptorSupport {
|
||||
|
||||
/**
|
||||
* This is an abstraction which allows us to handle queryNames
|
||||
* and queryMBeans with the same algorithm. There are some subclasses
|
||||
* where we need to override both queryNames & queryMBeans to apply
|
||||
* the same transformation (usually aggregation of results when
|
||||
* several namespaces/domains are impacted) to both algorithms.
|
||||
* Usually the only thing that varies between the algorithm of
|
||||
* queryNames & the algorithm of queryMBean is the type of objects
|
||||
* in the returned Set. By using a QueryInvoker we can implement the
|
||||
* transformation only once and apply it to both queryNames &
|
||||
* queryMBeans.
|
||||
* @see QueryInterceptor below, and its subclass in
|
||||
* {@link DomainDispatcher}.
|
||||
**/
|
||||
static abstract class QueryInvoker<T> {
|
||||
abstract Set<T> query(MBeanServer mbs,
|
||||
ObjectName pattern, QueryExp query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to perform queryNames. A QueryInvoker that invokes
|
||||
* queryNames on an MBeanServer.
|
||||
**/
|
||||
final static QueryInvoker<ObjectName> queryNamesInvoker =
|
||||
new QueryInvoker<ObjectName>() {
|
||||
Set<ObjectName> query(MBeanServer mbs,
|
||||
ObjectName pattern, QueryExp query) {
|
||||
return mbs.queryNames(pattern,query);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to perform queryMBeans. A QueryInvoker that invokes
|
||||
* queryMBeans on an MBeanServer.
|
||||
**/
|
||||
final static QueryInvoker<ObjectInstance> queryMBeansInvoker =
|
||||
new QueryInvoker<ObjectInstance>() {
|
||||
Set<ObjectInstance> query(MBeanServer mbs,
|
||||
ObjectName pattern, QueryExp query) {
|
||||
return mbs.queryMBeans(pattern,query);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* We use this class to intercept queries.
|
||||
* There's a special case for JMXNamespace MBeans, because
|
||||
* "namespace//*:*" matches both "namespace//domain:k=v" and
|
||||
* "namespace//:type=JMXNamespace".
|
||||
* Therefore, queries may need to be forwarded to more than
|
||||
* on interceptor and the results aggregated...
|
||||
*/
|
||||
static class QueryInterceptor {
|
||||
final MBeanServer wrapped;
|
||||
QueryInterceptor(MBeanServer mbs) {
|
||||
wrapped = mbs;
|
||||
}
|
||||
<X> Set<X> query(ObjectName pattern, QueryExp query,
|
||||
QueryInvoker<X> invoker, MBeanServer server) {
|
||||
return invoker.query(server, pattern, query);
|
||||
}
|
||||
|
||||
public Set<ObjectName> queryNames(ObjectName pattern, QueryExp query) {
|
||||
return query(pattern,query,queryNamesInvoker,wrapped);
|
||||
}
|
||||
|
||||
public Set<ObjectInstance> queryMBeans(ObjectName pattern,
|
||||
QueryExp query) {
|
||||
return query(pattern,query,queryMBeansInvoker,wrapped);
|
||||
}
|
||||
}
|
||||
|
||||
// We don't need a ConcurrentHashMap here because getkeys() returns
|
||||
// an array of keys. Therefore there's no risk to have a
|
||||
// ConcurrentModificationException. We must however take into
|
||||
// account the fact that there can be no interceptor for
|
||||
// some of the returned keys if the map is being modified by
|
||||
// another thread, or by a callback within the same thread...
|
||||
// See getKeys() in this class and query() in DomainDispatcher.
|
||||
//
|
||||
private final Map<String,T> handlerMap =
|
||||
Collections.synchronizedMap(
|
||||
new HashMap<String,T>());
|
||||
|
||||
// The key at which an interceptor for accessing the named MBean can be
|
||||
// found in the handlerMap. Note: there doesn't need to be an interceptor
|
||||
// for that key in the Map.
|
||||
//
|
||||
abstract String getHandlerKey(ObjectName name);
|
||||
|
||||
// Returns an interceptor for that name, or null if there's no interceptor
|
||||
// for that name.
|
||||
abstract MBeanServer getInterceptorOrNullFor(ObjectName name);
|
||||
|
||||
// Returns a QueryInterceptor for that pattern.
|
||||
abstract QueryInterceptor getInterceptorForQuery(ObjectName pattern);
|
||||
|
||||
// Returns the ObjectName of the JMXNamespace (or JMXDomain) for that
|
||||
// key (a namespace or a domain name).
|
||||
abstract ObjectName getHandlerNameFor(String key);
|
||||
|
||||
// Creates an interceptor for the given key, name, JMXNamespace (or
|
||||
// JMXDomain). Note: this will be either a NamespaceInterceptor
|
||||
// wrapping a JMXNamespace, if this object is an instance of
|
||||
// NamespaceDispatchInterceptor, or a DomainInterceptor wrapping a
|
||||
// JMXDomain, if this object is an instance of DomainDispatchInterceptor.
|
||||
abstract T createInterceptorFor(String key, ObjectName name,
|
||||
N jmxNamespace, Queue<Runnable> postRegisterQueue);
|
||||
//
|
||||
// The next interceptor in the chain.
|
||||
//
|
||||
// For the NamespaceDispatchInterceptor, this the DomainDispatchInterceptor.
|
||||
// For the DomainDispatchInterceptor, this is the
|
||||
// DefaultMBeanServerInterceptor.
|
||||
//
|
||||
// The logic of when to invoke the next interceptor in the chain depends
|
||||
// on the logic of the concrete dispatcher class.
|
||||
//
|
||||
// For instance, the NamespaceDispatchInterceptor invokes the next
|
||||
// interceptor when the object name doesn't contain any namespace.
|
||||
//
|
||||
// On the other hand, the DomainDispatchInterceptor invokes the
|
||||
// next interceptor when there's no interceptor for the accessed domain.
|
||||
//
|
||||
abstract MBeanServer getNextInterceptor();
|
||||
|
||||
// hook for cleanup in subclasses.
|
||||
void interceptorReleased(T interceptor,
|
||||
Queue<Runnable> postDeregisterQueue) {
|
||||
// hook
|
||||
}
|
||||
|
||||
// Hook for subclasses.
|
||||
MBeanServer getInterceptorForCreate(ObjectName name)
|
||||
throws MBeanRegistrationException {
|
||||
final MBeanServer ns = getInterceptorOrNullFor(name);
|
||||
if (ns == null) // name cannot be null here.
|
||||
throw new MBeanRegistrationException(
|
||||
new IllegalArgumentException("No such MBean handler: " +
|
||||
getHandlerKey(name) + " for " +name));
|
||||
return ns;
|
||||
}
|
||||
|
||||
// Hook for subclasses.
|
||||
MBeanServer getInterceptorForInstance(ObjectName name)
|
||||
throws InstanceNotFoundException {
|
||||
final MBeanServer ns = getInterceptorOrNullFor(name);
|
||||
if (ns == null) // name cannot be null here.
|
||||
throw new InstanceNotFoundException(String.valueOf(name));
|
||||
return ns;
|
||||
}
|
||||
|
||||
// sanity checks
|
||||
void validateHandlerNameFor(String key, ObjectName name) {
|
||||
if (key == null || key.equals(""))
|
||||
throw new IllegalArgumentException("invalid key for "+name+": "+key);
|
||||
final ObjectName handlerName = getHandlerNameFor(key);
|
||||
if (!name.equals(handlerName))
|
||||
throw new IllegalArgumentException("bad handler name: "+name+
|
||||
". Should be: "+handlerName);
|
||||
}
|
||||
|
||||
// Called by the DefaultMBeanServerInterceptor when an instance
|
||||
// of JMXNamespace (or a subclass of it) is registered as an MBean.
|
||||
// This method is usually invoked from within the repository lock,
|
||||
// hence the necessity of the postRegisterQueue.
|
||||
public void addInterceptorFor(ObjectName name, N jmxNamespace,
|
||||
Queue<Runnable> postRegisterQueue) {
|
||||
final String key = getHandlerKey(name);
|
||||
validateHandlerNameFor(key,name);
|
||||
synchronized (handlerMap) {
|
||||
final T exists =
|
||||
handlerMap.get(key);
|
||||
if (exists != null)
|
||||
throw new IllegalArgumentException(key+
|
||||
": handler already exists");
|
||||
|
||||
final T ns = createInterceptorFor(key,name,jmxNamespace,
|
||||
postRegisterQueue);
|
||||
handlerMap.put(key,ns);
|
||||
}
|
||||
}
|
||||
|
||||
// Called by the DefaultMBeanServerInterceptor when an instance
|
||||
// of JMXNamespace (or a subclass of it) is deregistered.
|
||||
// This method is usually invoked from within the repository lock,
|
||||
// hence the necessity of the postDeregisterQueue.
|
||||
public void removeInterceptorFor(ObjectName name, N jmxNamespace,
|
||||
Queue<Runnable> postDeregisterQueue) {
|
||||
final String key = getHandlerKey(name);
|
||||
final T ns;
|
||||
synchronized(handlerMap) {
|
||||
ns = handlerMap.remove(key);
|
||||
}
|
||||
interceptorReleased(ns,postDeregisterQueue);
|
||||
}
|
||||
|
||||
// Get the interceptor for that key.
|
||||
T getInterceptor(String key) {
|
||||
synchronized (handlerMap) {
|
||||
return handlerMap.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
// We return an array of keys, which makes it possible to make
|
||||
// concurrent modifications of the handlerMap, provided that
|
||||
// the code which loops over the keys is prepared to handle null
|
||||
// interceptors.
|
||||
// See declaration of handlerMap above, and see also query() in
|
||||
// DomainDispatcher
|
||||
//
|
||||
public String[] getKeys() {
|
||||
synchronized (handlerMap) {
|
||||
final int size = handlerMap.size();
|
||||
return handlerMap.keySet().toArray(new String[size]);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ObjectInstance createMBean(String className, ObjectName name)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException {
|
||||
return getInterceptorForCreate(name).createMBean(className,name);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ObjectInstance createMBean(String className, ObjectName name,
|
||||
ObjectName loaderName)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, InstanceNotFoundException{
|
||||
return getInterceptorForCreate(name).createMBean(className,name,loaderName);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ObjectInstance createMBean(String className, ObjectName name,
|
||||
Object params[], String signature[])
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException{
|
||||
return getInterceptorForCreate(name).
|
||||
createMBean(className,name,params,signature);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ObjectInstance createMBean(String className, ObjectName name,
|
||||
ObjectName loaderName, Object params[],
|
||||
String signature[])
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, InstanceNotFoundException{
|
||||
return getInterceptorForCreate(name).createMBean(className,name,loaderName,
|
||||
params,signature);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ObjectInstance registerMBean(Object object, ObjectName name)
|
||||
throws InstanceAlreadyExistsException, MBeanRegistrationException,
|
||||
NotCompliantMBeanException {
|
||||
return getInterceptorForCreate(name).registerMBean(object,name);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final void unregisterMBean(ObjectName name)
|
||||
throws InstanceNotFoundException, MBeanRegistrationException {
|
||||
getInterceptorForInstance(name).unregisterMBean(name);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ObjectInstance getObjectInstance(ObjectName name)
|
||||
throws InstanceNotFoundException {
|
||||
return getInterceptorForInstance(name).getObjectInstance(name);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final Set<ObjectInstance> queryMBeans(ObjectName name,
|
||||
QueryExp query) {
|
||||
final QueryInterceptor queryInvoker =
|
||||
getInterceptorForQuery(name);
|
||||
if (queryInvoker == null) return Collections.emptySet();
|
||||
else return queryInvoker.queryMBeans(name,query);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
|
||||
final QueryInterceptor queryInvoker =
|
||||
getInterceptorForQuery(name);
|
||||
if (queryInvoker == null) return Collections.emptySet();
|
||||
else return queryInvoker.queryNames(name,query);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final boolean isRegistered(ObjectName name) {
|
||||
final MBeanServer mbs = getInterceptorOrNullFor(name);
|
||||
if (mbs == null) return false;
|
||||
else return mbs.isRegistered(name);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public Integer getMBeanCount() {
|
||||
return getNextInterceptor().getMBeanCount();
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final Object getAttribute(ObjectName name, String attribute)
|
||||
throws MBeanException, AttributeNotFoundException,
|
||||
InstanceNotFoundException, ReflectionException {
|
||||
return getInterceptorForInstance(name).getAttribute(name,attribute);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final AttributeList getAttributes(ObjectName name,
|
||||
String[] attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
return getInterceptorForInstance(name).getAttributes(name,attributes);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final void setAttribute(ObjectName name, Attribute attribute)
|
||||
throws InstanceNotFoundException, AttributeNotFoundException,
|
||||
InvalidAttributeValueException, MBeanException,
|
||||
ReflectionException {
|
||||
getInterceptorForInstance(name).setAttribute(name,attribute);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final AttributeList setAttributes(ObjectName name,
|
||||
AttributeList attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
return getInterceptorForInstance(name).setAttributes(name,attributes);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final Object invoke(ObjectName name, String operationName,
|
||||
Object params[], String signature[])
|
||||
throws InstanceNotFoundException, MBeanException,
|
||||
ReflectionException {
|
||||
return getInterceptorForInstance(name).invoke(name,operationName,params,
|
||||
signature);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public String getDefaultDomain() {
|
||||
return getNextInterceptor().getDefaultDomain();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of domains in which any MBean is currently
|
||||
* registered.
|
||||
*/
|
||||
public abstract String[] getDomains();
|
||||
|
||||
// From MBeanServer
|
||||
public final void addNotificationListener(ObjectName name,
|
||||
NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException {
|
||||
getInterceptorForInstance(name).
|
||||
addNotificationListener(name,listener,filter,
|
||||
handback);
|
||||
}
|
||||
|
||||
|
||||
// From MBeanServer
|
||||
public final void addNotificationListener(ObjectName name,
|
||||
ObjectName listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException {
|
||||
getInterceptorForInstance(name).
|
||||
addNotificationListener(name,listener,filter,
|
||||
handback);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final void removeNotificationListener(ObjectName name,
|
||||
ObjectName listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
getInterceptorForInstance(name).
|
||||
removeNotificationListener(name,listener);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final void removeNotificationListener(ObjectName name,
|
||||
ObjectName listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
getInterceptorForInstance(name).
|
||||
removeNotificationListener(name,listener,filter,
|
||||
handback);
|
||||
}
|
||||
|
||||
|
||||
// From MBeanServer
|
||||
public final void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
getInterceptorForInstance(name).
|
||||
removeNotificationListener(name,listener);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
getInterceptorForInstance(name).
|
||||
removeNotificationListener(name,listener,filter,
|
||||
handback);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final MBeanInfo getMBeanInfo(ObjectName name)
|
||||
throws InstanceNotFoundException, IntrospectionException,
|
||||
ReflectionException {
|
||||
return getInterceptorForInstance(name).getMBeanInfo(name);
|
||||
}
|
||||
|
||||
|
||||
// From MBeanServer
|
||||
public final boolean isInstanceOf(ObjectName name, String className)
|
||||
throws InstanceNotFoundException {
|
||||
return getInterceptorForInstance(name).isInstanceOf(name,className);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ClassLoader getClassLoaderFor(ObjectName mbeanName)
|
||||
throws InstanceNotFoundException {
|
||||
return getInterceptorForInstance(mbeanName).
|
||||
getClassLoaderFor(mbeanName);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ClassLoader getClassLoader(ObjectName loaderName)
|
||||
throws InstanceNotFoundException {
|
||||
return getInterceptorForInstance(loaderName).
|
||||
getClassLoader(loaderName);
|
||||
}
|
||||
|
||||
}
|
@ -1,350 +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.interceptor;
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import com.sun.jmx.mbeanserver.MBeanInstantiator;
|
||||
import com.sun.jmx.mbeanserver.Repository;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import com.sun.jmx.namespace.DomainInterceptor;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerDelegate;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.namespace.JMXDomain;
|
||||
import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
|
||||
|
||||
/**
|
||||
* A dispatcher that dispatch incoming MBeanServer requests to
|
||||
* DomainInterceptors.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
//
|
||||
// See comments in DispatchInterceptor.
|
||||
//
|
||||
class DomainDispatchInterceptor
|
||||
extends DispatchInterceptor<DomainInterceptor, JMXDomain> {
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
private static final ObjectName ALL_DOMAINS =
|
||||
JMXDomain.getDomainObjectName("*");
|
||||
|
||||
|
||||
/**
|
||||
* A QueryInterceptor that perform & aggregates queries spanning several
|
||||
* domains.
|
||||
*/
|
||||
final static class AggregatingQueryInterceptor extends QueryInterceptor {
|
||||
|
||||
private final DomainDispatchInterceptor parent;
|
||||
AggregatingQueryInterceptor(DomainDispatchInterceptor dispatcher) {
|
||||
super(dispatcher.nextInterceptor);
|
||||
parent = dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform queryNames or queryMBeans, depending on which QueryInvoker
|
||||
* is passed as argument. This is closures without closures.
|
||||
**/
|
||||
@Override
|
||||
<T> Set<T> query(ObjectName pattern, QueryExp query,
|
||||
QueryInvoker<T> invoker, MBeanServer localNamespace) {
|
||||
final Set<T> local = invoker.query(localNamespace, pattern, query);
|
||||
|
||||
// Add all matching MBeans from local namespace.
|
||||
final Set<T> res = Util.cloneSet(local);
|
||||
|
||||
if (pattern == null) pattern = ObjectName.WILDCARD;
|
||||
final boolean all = pattern.getDomain().equals("*");
|
||||
|
||||
final String domain = pattern.getDomain();
|
||||
|
||||
// If there's no domain pattern, just include the pattern's domain.
|
||||
// Otherwiae, loop over all virtual domains (parent.getKeys()).
|
||||
final String[] keys =
|
||||
(pattern.isDomainPattern() ?
|
||||
parent.getKeys() : new String[]{domain});
|
||||
|
||||
// Add all matching MBeans from each virtual domain
|
||||
//
|
||||
for (String key : keys) {
|
||||
// Only invoke those virtual domain which are selected
|
||||
// by the domain pattern
|
||||
//
|
||||
if (!all && !Util.isDomainSelected(key, domain))
|
||||
continue;
|
||||
|
||||
try {
|
||||
final MBeanServer mbs = parent.getInterceptor(key);
|
||||
|
||||
// mbs can be null if the interceptor was removed
|
||||
// concurrently...
|
||||
// See handlerMap and getKeys() in DispatchInterceptor
|
||||
//
|
||||
if (mbs == null) continue;
|
||||
|
||||
// If the domain is selected, we can replace the pattern
|
||||
// by the actual domain. This is safer if we want to avoid
|
||||
// a domain (which could be backed up by an MBeanServer) to
|
||||
// return names from outside the domain.
|
||||
// So instead of asking the domain handler for "foo" to
|
||||
// return all names which match "?o*:type=Bla,*" we're
|
||||
// going to ask it to return all names which match
|
||||
// "foo:type=Bla,*"
|
||||
//
|
||||
final ObjectName subPattern = pattern.withDomain(key);
|
||||
res.addAll(invoker.query(mbs, subPattern, query));
|
||||
} catch (Exception x) {
|
||||
LOG.finest("Ignoring exception " +
|
||||
"when attempting to query namespace "+key+": "+x);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
private final DefaultMBeanServerInterceptor nextInterceptor;
|
||||
private final String mbeanServerName;
|
||||
private final MBeanServerDelegate delegate;
|
||||
|
||||
/**
|
||||
* Creates a DomainDispatchInterceptor with the specified
|
||||
* repository instance.
|
||||
*
|
||||
* @param outer A pointer to the MBeanServer object that must be
|
||||
* passed to the MBeans when invoking their
|
||||
* {@link javax.management.MBeanRegistration} interface.
|
||||
* @param delegate A pointer to the MBeanServerDelegate associated
|
||||
* with the new MBeanServer. The new MBeanServer must register
|
||||
* this MBean in its MBean repository.
|
||||
* @param instantiator The MBeanInstantiator that will be used to
|
||||
* instantiate MBeans and take care of class loading issues.
|
||||
* @param repository The repository to use for this MBeanServer
|
||||
*/
|
||||
public DomainDispatchInterceptor(MBeanServer outer,
|
||||
MBeanServerDelegate delegate,
|
||||
MBeanInstantiator instantiator,
|
||||
Repository repository,
|
||||
NamespaceDispatchInterceptor namespaces) {
|
||||
nextInterceptor = new DefaultMBeanServerInterceptor(outer,
|
||||
delegate, instantiator,repository,namespaces);
|
||||
mbeanServerName = Util.getMBeanServerSecurityName(delegate);
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
final boolean isLocalHandlerNameFor(String domain,
|
||||
ObjectName handlerName) {
|
||||
if (domain == null) return true;
|
||||
return handlerName.getDomain().equals(domain) &&
|
||||
JMXDomain.TYPE_ASSIGNMENT.equals(
|
||||
handlerName.getKeyPropertyListString());
|
||||
}
|
||||
|
||||
@Override
|
||||
void validateHandlerNameFor(String key, ObjectName name) {
|
||||
super.validateHandlerNameFor(key,name);
|
||||
final String[] domains = nextInterceptor.getDomains();
|
||||
for (int i=0;i<domains.length;i++) {
|
||||
if (domains[i].equals(key))
|
||||
throw new IllegalArgumentException("domain "+key+
|
||||
" is not empty");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
final MBeanServer getInterceptorOrNullFor(ObjectName name) {
|
||||
|
||||
if (name == null) return nextInterceptor;
|
||||
|
||||
final String domain = name.getDomain();
|
||||
if (domain.endsWith(NAMESPACE_SEPARATOR))
|
||||
return nextInterceptor; // This can be a namespace handler.
|
||||
if (domain.contains(NAMESPACE_SEPARATOR))
|
||||
return null; // shouldn't reach here.
|
||||
if (isLocalHandlerNameFor(domain,name)) {
|
||||
// This is the name of a JMXDomain MBean. Return nextInterceptor.
|
||||
LOG.finer("dispatching to local namespace");
|
||||
return nextInterceptor;
|
||||
}
|
||||
|
||||
final DomainInterceptor ns = getInterceptor(domain);
|
||||
if (ns == null) {
|
||||
// no JMXDomain found for that domain - return nextInterceptor.
|
||||
if (LOG.isLoggable(Level.FINER)) {
|
||||
LOG.finer("dispatching to local namespace: " + domain);
|
||||
}
|
||||
return getNextInterceptor();
|
||||
}
|
||||
|
||||
if (LOG.isLoggable(Level.FINER)) {
|
||||
LOG.finer("dispatching to domain: " + domain);
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
|
||||
// This method returns true if the given pattern must be evaluated against
|
||||
// several interceptors. This happens when either:
|
||||
//
|
||||
// a) the pattern can select several domains (it's null, or it's a
|
||||
// domain pattern)
|
||||
// or b) it's not a domain pattern, but it might select the name of a
|
||||
// JMXDomain MBean in charge of that domain. Since the JMXDomain
|
||||
// MBean is located in the nextInterceptor, the pattern might need
|
||||
// to be evaluated on two interceptors.
|
||||
//
|
||||
// 1. When this method returns false, the query is evaluated on a single
|
||||
// interceptor:
|
||||
// The interceptor for pattern.getDomain(), if there is one,
|
||||
// or the next interceptor, if there is none.
|
||||
//
|
||||
// 2. When this method returns true, we loop over all the domain
|
||||
// interceptors:
|
||||
// in the list, and if the domain pattern matches the interceptor domain
|
||||
// we evaluate the query on that interceptor and aggregate the results.
|
||||
// Eventually we also evaluate the pattern against the next interceptor.
|
||||
//
|
||||
// See getInterceptorForQuery below.
|
||||
//
|
||||
private boolean multipleQuery(ObjectName pattern) {
|
||||
// case a) above
|
||||
if (pattern == null) return true;
|
||||
if (pattern.isDomainPattern()) return true;
|
||||
|
||||
// case b) above.
|
||||
//
|
||||
// This is a bit of a hack. If there's any chance that a JMXDomain
|
||||
// MBean name is selected by the given pattern then we must include
|
||||
// the local namespace in our search.
|
||||
//
|
||||
// Returning true will have this effect. see 2. above.
|
||||
//
|
||||
if (pattern.apply(ALL_DOMAINS.withDomain(pattern.getDomain())))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
final QueryInterceptor getInterceptorForQuery(ObjectName pattern) {
|
||||
|
||||
// Check if we need to aggregate.
|
||||
if (multipleQuery(pattern))
|
||||
return new AggregatingQueryInterceptor(this);
|
||||
|
||||
// We don't need to aggregate: do the "simple" thing...
|
||||
final String domain = pattern.getDomain();
|
||||
|
||||
// Do we have a virtual domain?
|
||||
final DomainInterceptor ns = getInterceptor(domain);
|
||||
if (ns != null) {
|
||||
if (LOG.isLoggable(Level.FINER))
|
||||
LOG.finer("dispatching to domain: " + domain);
|
||||
return new QueryInterceptor(ns);
|
||||
}
|
||||
|
||||
// We don't have a virtual domain. Send to local domains.
|
||||
if (LOG.isLoggable(Level.FINER))
|
||||
LOG.finer("dispatching to local namespace: " + domain);
|
||||
return new QueryInterceptor(nextInterceptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
final ObjectName getHandlerNameFor(String key) {
|
||||
return JMXDomain.getDomainObjectName(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
final public String getHandlerKey(ObjectName name) {
|
||||
return name.getDomain();
|
||||
}
|
||||
|
||||
@Override
|
||||
final DomainInterceptor createInterceptorFor(String key,
|
||||
ObjectName name, JMXDomain handler,
|
||||
Queue<Runnable> postRegisterQueue) {
|
||||
final DomainInterceptor ns =
|
||||
new DomainInterceptor(mbeanServerName,handler,key);
|
||||
ns.addPostRegisterTask(postRegisterQueue, delegate);
|
||||
if (LOG.isLoggable(Level.FINER)) {
|
||||
LOG.finer("DomainInterceptor created: "+ns);
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
|
||||
@Override
|
||||
final void interceptorReleased(DomainInterceptor interceptor,
|
||||
Queue<Runnable> postDeregisterQueue) {
|
||||
interceptor.addPostDeregisterTask(postDeregisterQueue, delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
final DefaultMBeanServerInterceptor getNextInterceptor() {
|
||||
return nextInterceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of domains in which any MBean is currently
|
||||
* registered.
|
||||
*/
|
||||
@Override
|
||||
public String[] getDomains() {
|
||||
// A JMXDomain is registered in its own domain.
|
||||
// Therefore, nextInterceptor.getDomains() contains all domains.
|
||||
// In addition, nextInterceptor will perform the necessary
|
||||
// MBeanPermission checks for getDomains().
|
||||
//
|
||||
return nextInterceptor.getDomains();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of MBeans registered in the MBean server.
|
||||
*/
|
||||
@Override
|
||||
public Integer getMBeanCount() {
|
||||
int count = getNextInterceptor().getMBeanCount();
|
||||
final String[] keys = getKeys();
|
||||
for (String key:keys) {
|
||||
final MBeanServer mbs = getInterceptor(key);
|
||||
if (mbs == null) continue;
|
||||
count += mbs.getMBeanCount();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
@ -1,127 +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.interceptor;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.OperationsException;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.loading.ClassLoaderRepository;
|
||||
|
||||
/**
|
||||
* An abstract class for MBeanServerInterceptorSupport.
|
||||
* Some methods in MBeanServerInterceptor should never be called.
|
||||
* This base class provides an implementation of these methods that simply
|
||||
* throw an {@link UnsupportedOperationException}.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public abstract class MBeanServerInterceptorSupport
|
||||
implements MBeanServerInterceptor {
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className)
|
||||
throws ReflectionException, MBeanException {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className, ObjectName loaderName)
|
||||
throws ReflectionException, MBeanException,
|
||||
InstanceNotFoundException {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className, Object[] params,
|
||||
String[] signature) throws ReflectionException, MBeanException {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className, ObjectName loaderName,
|
||||
Object[] params, String[] signature)
|
||||
throws ReflectionException, MBeanException,
|
||||
InstanceNotFoundException {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(ObjectName name, byte[] data)
|
||||
throws InstanceNotFoundException, OperationsException {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(String className, byte[] data)
|
||||
throws OperationsException, ReflectionException {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(String className,
|
||||
ObjectName loaderName, byte[] data)
|
||||
throws InstanceNotFoundException, OperationsException,
|
||||
ReflectionException {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public ClassLoaderRepository getClassLoaderRepository() {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
}
|
@ -1,297 +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.interceptor;
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import com.sun.jmx.mbeanserver.MBeanInstantiator;
|
||||
import com.sun.jmx.mbeanserver.Repository;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import com.sun.jmx.namespace.NamespaceInterceptor;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerDelegate;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
import javax.management.namespace.JMXDomain;
|
||||
import javax.management.namespace.JMXNamespace;
|
||||
import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
|
||||
|
||||
/**
|
||||
* A dispatcher that dispatches to NamespaceInterceptors.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public class NamespaceDispatchInterceptor
|
||||
extends DispatchInterceptor<NamespaceInterceptor, JMXNamespace> {
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
private static final int NAMESPACE_SEPARATOR_LENGTH =
|
||||
NAMESPACE_SEPARATOR.length();
|
||||
private static final ObjectName X3 = ObjectName.valueOf("x:x=x");
|
||||
|
||||
private final DomainDispatchInterceptor nextInterceptor;
|
||||
private final String serverName;
|
||||
|
||||
/**
|
||||
* Creates a NamespaceDispatchInterceptor with the specified
|
||||
* repository instance.
|
||||
* <p>Do not forget to call <code>initialize(outer,delegate)</code>
|
||||
* before using this object.
|
||||
*
|
||||
* @param outer A pointer to the MBeanServer object that must be
|
||||
* passed to the MBeans when invoking their
|
||||
* {@link javax.management.MBeanRegistration} interface.
|
||||
* @param delegate A pointer to the MBeanServerDelegate associated
|
||||
* with the new MBeanServer. The new MBeanServer must register
|
||||
* this MBean in its MBean repository.
|
||||
* @param instantiator The MBeanInstantiator that will be used to
|
||||
* instantiate MBeans and take care of class loading issues.
|
||||
* @param repository The repository to use for this MBeanServer
|
||||
*/
|
||||
public NamespaceDispatchInterceptor(MBeanServer outer,
|
||||
MBeanServerDelegate delegate,
|
||||
MBeanInstantiator instantiator,
|
||||
Repository repository) {
|
||||
nextInterceptor = new DomainDispatchInterceptor(outer,delegate,
|
||||
instantiator,repository,this);
|
||||
serverName = Util.getMBeanServerSecurityName(delegate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get first name space in ObjectName path. Ignore leading namespace
|
||||
* separators. Includes the trailing //.
|
||||
*
|
||||
* Examples:
|
||||
* <pre>
|
||||
* For ObjectName: Returns:
|
||||
* foo//bar//baz:x=x -> "foo//"
|
||||
* foo//:type=JMXNamespace -> "foo//"
|
||||
* foo//:x=x -> "foo//"
|
||||
* foo////:x=x -> "foo//"
|
||||
* //foo//bar//baz:x=x -> "//"
|
||||
* ////foo//bar//baz:x=x -> "//"
|
||||
* //:x=x -> "//"
|
||||
* foo:x=x -> ""
|
||||
* (null) -> ""
|
||||
* :x=x -> ""
|
||||
*
|
||||
* </pre>
|
||||
**/
|
||||
static String getFirstNamespaceWithSlash(ObjectName name) {
|
||||
if (name == null) return "";
|
||||
final String domain = name.getDomain();
|
||||
if (domain.equals("")) return "";
|
||||
|
||||
// go to next separator
|
||||
final int end = domain.indexOf(NAMESPACE_SEPARATOR);
|
||||
if (end == -1) return ""; // no namespace
|
||||
|
||||
// This is the first element in the namespace path.
|
||||
final String namespace =
|
||||
domain.substring(0,end+NAMESPACE_SEPARATOR_LENGTH);
|
||||
|
||||
return namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the DefaultMBeanServerInterceptor, just before adding an
|
||||
* MBean to the repository.
|
||||
*
|
||||
* @param resource the MBean to be registered.
|
||||
* @param logicalName the name of the MBean to be registered.
|
||||
*/
|
||||
final void checkLocallyRegistrable(Object resource,
|
||||
ObjectName logicalName) {
|
||||
if (!(resource instanceof JMXNamespace) &&
|
||||
logicalName.getDomain().contains(NAMESPACE_SEPARATOR))
|
||||
throw new IllegalArgumentException(String.valueOf(logicalName)+
|
||||
": Invalid ObjectName for an instance of " +
|
||||
resource.getClass().getName());
|
||||
}
|
||||
|
||||
// Removes the trailing //. namespaceWithSlash should be either
|
||||
// "" or a namespace path ending with //.
|
||||
//
|
||||
private final String getKeyFor(String namespaceWithSlash) {
|
||||
final int end = namespaceWithSlash.length() -
|
||||
NAMESPACE_SEPARATOR_LENGTH;
|
||||
if (end <= 0) return "";
|
||||
final String key = namespaceWithSlash.substring(0,end);
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
final MBeanServer getInterceptorOrNullFor(ObjectName name) {
|
||||
final String namespace = getFirstNamespaceWithSlash(name);
|
||||
|
||||
// Leading separators should trigger instance not found exception.
|
||||
// returning null here has this effect.
|
||||
//
|
||||
if (namespace.equals(NAMESPACE_SEPARATOR)) {
|
||||
LOG.finer("ObjectName starts with: "+namespace);
|
||||
return null;
|
||||
}
|
||||
|
||||
// namespace="" means that there was no namespace path in the
|
||||
// ObjectName. => delegate to the next interceptor (local MBS)
|
||||
// name.getDomain()=namespace means that we have an ObjectName of
|
||||
// the form blah//:x=x. This is either a JMXNamespace or a non
|
||||
// existent MBean. => delegate to the next interceptor (local MBS)
|
||||
if (namespace.equals("") || name.getDomain().equals(namespace)) {
|
||||
LOG.finer("dispatching to local name space");
|
||||
return nextInterceptor;
|
||||
}
|
||||
|
||||
// There was a namespace path in the ObjectName. Returns the
|
||||
// interceptor that handles it, or null if there is no such
|
||||
// interceptor.
|
||||
final String key = getKeyFor(namespace);
|
||||
final NamespaceInterceptor ns = getInterceptor(key);
|
||||
if (LOG.isLoggable(Level.FINER)) {
|
||||
if (ns != null) {
|
||||
LOG.finer("dispatching to name space: " + key);
|
||||
} else {
|
||||
LOG.finer("no handler for: " + key);
|
||||
}
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
|
||||
@Override
|
||||
final QueryInterceptor getInterceptorForQuery(ObjectName pattern) {
|
||||
final String namespace = getFirstNamespaceWithSlash(pattern);
|
||||
|
||||
// Leading separators should trigger instance not found exception.
|
||||
// returning null here has this effect.
|
||||
//
|
||||
if (namespace.equals(NAMESPACE_SEPARATOR)) {
|
||||
LOG.finer("ObjectName starts with: "+namespace);
|
||||
return null;
|
||||
}
|
||||
|
||||
// namespace="" means that there was no namespace path in the
|
||||
// ObjectName. => delegate to the next interceptor (local MBS)
|
||||
// name.getDomain()=namespace means that we have an ObjectName of
|
||||
// the form blah//:x=x. This is either a JMXNamespace or a non
|
||||
// existent MBean. => delegate to the next interceptor (local MBS)
|
||||
if (namespace.equals("") || pattern.getDomain().equals(namespace)) {
|
||||
LOG.finer("dispatching to local name space");
|
||||
return new QueryInterceptor(nextInterceptor);
|
||||
}
|
||||
|
||||
// This is a 'hack' to check whether the first namespace is a pattern.
|
||||
// We wan to throw RTOE wrapping IAE in that case
|
||||
if (X3.withDomain(namespace).isDomainPattern()) {
|
||||
throw new RuntimeOperationsException(
|
||||
new IllegalArgumentException("Pattern not allowed in namespace path"));
|
||||
}
|
||||
|
||||
// There was a namespace path in the ObjectName. Returns the
|
||||
// interceptor that handles it, or null if there is no such
|
||||
// interceptor.
|
||||
//
|
||||
final String key = getKeyFor(namespace);
|
||||
final NamespaceInterceptor ns = getInterceptor(key);
|
||||
if (LOG.isLoggable(Level.FINER)) {
|
||||
if (ns != null) {
|
||||
LOG.finer("dispatching to name space: " + key);
|
||||
} else {
|
||||
LOG.finer("no handler for: " + key);
|
||||
}
|
||||
}
|
||||
if (ns == null) return null;
|
||||
return new QueryInterceptor(ns);
|
||||
}
|
||||
|
||||
@Override
|
||||
final ObjectName getHandlerNameFor(String key) {
|
||||
return ObjectName.valueOf(key+NAMESPACE_SEPARATOR,
|
||||
"type", JMXNamespace.TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
final public String getHandlerKey(ObjectName name) {
|
||||
final String namespace = getFirstNamespaceWithSlash(name);
|
||||
// namespace is either "" or a namespace ending with //
|
||||
return getKeyFor(namespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
final NamespaceInterceptor createInterceptorFor(String key,
|
||||
ObjectName name, JMXNamespace handler,
|
||||
Queue<Runnable> postRegisterQueue) {
|
||||
final NamespaceInterceptor ns =
|
||||
new NamespaceInterceptor(serverName,handler,key);
|
||||
if (LOG.isLoggable(Level.FINER)) {
|
||||
LOG.finer("NamespaceInterceptor created: "+ns);
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
|
||||
@Override
|
||||
final DomainDispatchInterceptor getNextInterceptor() {
|
||||
return nextInterceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of domains in which any MBean is currently
|
||||
* registered.
|
||||
*/
|
||||
@Override
|
||||
public String[] getDomains() {
|
||||
return nextInterceptor.getDomains();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptorFor(ObjectName name, JMXNamespace handler,
|
||||
Queue<Runnable> postRegisterQueue) {
|
||||
if (handler instanceof JMXDomain)
|
||||
nextInterceptor.addInterceptorFor(name,
|
||||
(JMXDomain)handler,postRegisterQueue);
|
||||
else super.addInterceptorFor(name,handler,postRegisterQueue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeInterceptorFor(ObjectName name, JMXNamespace handler,
|
||||
Queue<Runnable> postDeregisterQueue) {
|
||||
if (handler instanceof JMXDomain)
|
||||
nextInterceptor.removeInterceptorFor(name,(JMXDomain)handler,
|
||||
postDeregisterQueue);
|
||||
else super.removeInterceptorFor(name,handler,postDeregisterQueue);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,442 +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.interceptor;
|
||||
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationEmitter;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.namespace.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() {
|
||||
|
||||
@Override
|
||||
public DynamicMBean getDynamicMBeanFor(ObjectName name)
|
||||
throws InstanceNotFoundException {
|
||||
if (mbeanName.equals(name)) {
|
||||
return mbean;
|
||||
} else {
|
||||
throw new InstanceNotFoundException(name.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<ObjectName> getNames() {
|
||||
return Collections.singleton(mbeanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationEmitter getNotificationEmitterFor(
|
||||
ObjectName name) {
|
||||
if (mbean instanceof NotificationEmitter)
|
||||
return (NotificationEmitter) mbean;
|
||||
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, boolean visible) {
|
||||
this.mbeanName = mbeanName;
|
||||
this.visible = visible;
|
||||
setSingleMBean(mbean);
|
||||
}
|
||||
|
||||
protected void setSingleMBean(DynamicMBean mbean) {
|
||||
this.mbean = mbean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotificationListener(ObjectName name, ObjectName listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.addNotificationListener(name, listener, filter, handback);
|
||||
else
|
||||
super.addNotificationListener(name, listener, filter, handback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotificationListener(ObjectName name,
|
||||
NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.addNotificationListener(name, listener, filter, handback);
|
||||
else
|
||||
super.addNotificationListener(name, listener, filter, handback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
ObjectName loaderName, Object[] params,
|
||||
String[] signature)
|
||||
throws ReflectionException,
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
MBeanException,
|
||||
NotCompliantMBeanException,
|
||||
InstanceNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
throw new InstanceAlreadyExistsException(mbeanName.toString());
|
||||
else
|
||||
return super.createMBean(className, name, loaderName, params, signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
Object[] params, String[] signature)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException {
|
||||
if (mbeanName.equals(name))
|
||||
throw new InstanceAlreadyExistsException(mbeanName.toString());
|
||||
return super.createMBean(className, name, params, signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
ObjectName loaderName)
|
||||
throws ReflectionException,
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
MBeanException,
|
||||
NotCompliantMBeanException,
|
||||
InstanceNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
throw new InstanceAlreadyExistsException(mbeanName.toString());
|
||||
return super.createMBean(className, name, loaderName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name)
|
||||
throws ReflectionException,
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
MBeanException,
|
||||
NotCompliantMBeanException {
|
||||
if (mbeanName.equals(name))
|
||||
throw new InstanceAlreadyExistsException(mbeanName.toString());
|
||||
return super.createMBean(className, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(ObjectName name, String attribute)
|
||||
throws MBeanException,
|
||||
AttributeNotFoundException,
|
||||
InstanceNotFoundException,
|
||||
ReflectionException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.getAttribute(name, attribute);
|
||||
else
|
||||
return super.getAttribute(name, attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeList getAttributes(ObjectName name, String[] attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.getAttributes(name, attributes);
|
||||
else
|
||||
return super.getAttributes(name, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader(ObjectName loaderName)
|
||||
throws InstanceNotFoundException {
|
||||
if (mbeanName.equals(loaderName))
|
||||
return mbeanMBS.getClassLoader(loaderName);
|
||||
else
|
||||
return super.getClassLoader(loaderName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoaderFor(ObjectName name)
|
||||
throws InstanceNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.getClassLoaderFor(name);
|
||||
else
|
||||
return super.getClassLoaderFor(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] 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()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMBeanCount() {
|
||||
Integer count = super.getMBeanCount();
|
||||
if (visible && !super.isRegistered(mbeanName))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MBeanInfo getMBeanInfo(ObjectName name)
|
||||
throws InstanceNotFoundException,
|
||||
IntrospectionException,
|
||||
ReflectionException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.getMBeanInfo(name);
|
||||
else
|
||||
return super.getMBeanInfo(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance getObjectInstance(ObjectName name)
|
||||
throws InstanceNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.getObjectInstance(name);
|
||||
else
|
||||
return super.getObjectInstance(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(ObjectName name, String operationName, Object[] params,
|
||||
String[] signature)
|
||||
throws InstanceNotFoundException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.invoke(name, operationName, params, signature);
|
||||
else
|
||||
return super.invoke(name, operationName, params, signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstanceOf(ObjectName name, String className)
|
||||
throws InstanceNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.isInstanceOf(name, className);
|
||||
else
|
||||
return super.isInstanceOf(name, className);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegistered(ObjectName name) {
|
||||
if (mbeanName.equals(name))
|
||||
return true;
|
||||
else
|
||||
return super.isRegistered(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a ugly hack. Although jmx.context//*:* matches jmx.context//:*
|
||||
* queryNames(jmx.context//*:*,null) must not return jmx.context//:*
|
||||
* @param pattern the pattern to match against. must not be null.
|
||||
* @return true if mbeanName can be included, false if it must not.
|
||||
*/
|
||||
private boolean applies(ObjectName pattern) {
|
||||
// we know pattern is not null.
|
||||
if (!visible || !pattern.apply(mbeanName))
|
||||
return false;
|
||||
|
||||
final String dompat = pattern.getDomain();
|
||||
if (!dompat.contains(JMXNamespaces.NAMESPACE_SEPARATOR))
|
||||
return true; // We already checked that patterns apply.
|
||||
|
||||
if (mbeanName.getDomain().endsWith(JMXNamespaces.NAMESPACE_SEPARATOR)) {
|
||||
// only matches if pattern ends with //
|
||||
return dompat.endsWith(JMXNamespaces.NAMESPACE_SEPARATOR);
|
||||
}
|
||||
|
||||
// should not come here, unless mbeanName contains a // in the
|
||||
// middle of its domain, which would be weird.
|
||||
// let query on mbeanMBS proceed and take care of that.
|
||||
//
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
|
||||
Set<ObjectInstance> names = super.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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
|
||||
Set<ObjectName> names = super.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;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ObjectInstance registerMBean(Object object, ObjectName name)
|
||||
throws InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
NotCompliantMBeanException {
|
||||
if (mbeanName.equals(name))
|
||||
throw new InstanceAlreadyExistsException(mbeanName.toString());
|
||||
else
|
||||
return super.registerMBean(object, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException,
|
||||
ListenerNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.removeNotificationListener(name, listener, filter, handback);
|
||||
else
|
||||
super.removeNotificationListener(name, listener, filter, handback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.removeNotificationListener(name, listener);
|
||||
else
|
||||
super.removeNotificationListener(name, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name, ObjectName listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException,
|
||||
ListenerNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.removeNotificationListener(name, listener, filter, handback);
|
||||
else
|
||||
super.removeNotificationListener(name, listener, filter, handback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name, ObjectName listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.removeNotificationListener(name, listener);
|
||||
else
|
||||
super.removeNotificationListener(name, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(ObjectName name, Attribute attribute)
|
||||
throws InstanceNotFoundException,
|
||||
AttributeNotFoundException,
|
||||
InvalidAttributeValueException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.setAttribute(name, attribute);
|
||||
else
|
||||
super.setAttribute(name, attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeList setAttributes(ObjectName name,
|
||||
AttributeList attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.setAttributes(name, attributes);
|
||||
else
|
||||
return super.setAttributes(name, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterMBean(ObjectName name)
|
||||
throws InstanceNotFoundException,
|
||||
MBeanRegistrationException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.unregisterMBean(name);
|
||||
else
|
||||
super.unregisterMBean(name);
|
||||
}
|
||||
}
|
@ -31,15 +31,13 @@ import java.lang.reflect.Type;
|
||||
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.openmbean.MXBeanMapping;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.OpenDataException;
|
||||
import javax.management.openmbean.OpenType;
|
||||
|
||||
final class ConvertingMethod {
|
||||
static ConvertingMethod from(Method m, MXBeanMappingFactory mappingFactory) {
|
||||
static ConvertingMethod from(Method m) {
|
||||
try {
|
||||
return new ConvertingMethod(m, mappingFactory);
|
||||
return new ConvertingMethod(m);
|
||||
} catch (OpenDataException ode) {
|
||||
final String msg = "Method " + m.getDeclaringClass().getName() +
|
||||
"." + m.getName() + " has parameter or return type that " +
|
||||
@ -53,7 +51,7 @@ final class ConvertingMethod {
|
||||
}
|
||||
|
||||
Descriptor getDescriptor() {
|
||||
return Introspector.descriptorForElement(method, false);
|
||||
return Introspector.descriptorForElement(method);
|
||||
}
|
||||
|
||||
Type getGenericReturnType() {
|
||||
@ -206,9 +204,9 @@ final class ConvertingMethod {
|
||||
return method.getDeclaringClass() + "." + method.getName();
|
||||
}
|
||||
|
||||
private ConvertingMethod(Method m, MXBeanMappingFactory mappingFactory)
|
||||
throws OpenDataException {
|
||||
private ConvertingMethod(Method m) throws OpenDataException {
|
||||
this.method = m;
|
||||
MXBeanMappingFactory mappingFactory = MXBeanMappingFactory.DEFAULT;
|
||||
returnMapping =
|
||||
mappingFactory.mappingForType(m.getGenericReturnType(), mappingFactory);
|
||||
Type[] params = m.getGenericParameterTypes();
|
||||
|
@ -28,8 +28,6 @@ package com.sun.jmx.mbeanserver;
|
||||
import static com.sun.jmx.mbeanserver.Util.*;
|
||||
import static com.sun.jmx.mbeanserver.MXBeanIntrospector.typeName;
|
||||
|
||||
import javax.management.openmbean.MXBeanMappingClass;
|
||||
|
||||
import static javax.management.openmbean.SimpleType.*;
|
||||
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
@ -69,8 +67,6 @@ import javax.management.openmbean.CompositeDataInvocationHandler;
|
||||
import javax.management.openmbean.CompositeDataSupport;
|
||||
import javax.management.openmbean.CompositeDataView;
|
||||
import javax.management.openmbean.CompositeType;
|
||||
import javax.management.openmbean.MXBeanMapping;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.OpenDataException;
|
||||
import javax.management.openmbean.OpenType;
|
||||
import javax.management.openmbean.SimpleType;
|
||||
@ -165,34 +161,29 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
private static final class Mappings
|
||||
extends WeakHashMap<Type, WeakReference<MXBeanMapping>> {}
|
||||
|
||||
private static final Map<MXBeanMappingFactory, Mappings> factoryMappings =
|
||||
new WeakHashMap<MXBeanMappingFactory, Mappings>();
|
||||
private static final Mappings mappings = new Mappings();
|
||||
|
||||
private static final Map<Type, MXBeanMapping> permanentMappings = newMap();
|
||||
/** Following List simply serves to keep a reference to predefined
|
||||
MXBeanMappings so they don't get garbage collected. */
|
||||
private static final List<MXBeanMapping> permanentMappings = newList();
|
||||
|
||||
private static synchronized MXBeanMapping getMapping(
|
||||
Type type, MXBeanMappingFactory factory) {
|
||||
Mappings mappings = factoryMappings.get(factory);
|
||||
if (mappings == null) {
|
||||
mappings = new Mappings();
|
||||
factoryMappings.put(factory, mappings);
|
||||
}
|
||||
private static synchronized MXBeanMapping getMapping(Type type) {
|
||||
WeakReference<MXBeanMapping> wr = mappings.get(type);
|
||||
return (wr == null) ? null : wr.get();
|
||||
}
|
||||
|
||||
private static synchronized void putMapping(
|
||||
Type type, MXBeanMapping mapping, MXBeanMappingFactory factory) {
|
||||
Mappings mappings = factoryMappings.get(factory);
|
||||
if (mappings == null) {
|
||||
mappings = new Mappings();
|
||||
factoryMappings.put(factory, mappings);
|
||||
}
|
||||
private static synchronized void putMapping(Type type, MXBeanMapping mapping) {
|
||||
WeakReference<MXBeanMapping> wr =
|
||||
new WeakReference<MXBeanMapping>(mapping);
|
||||
mappings.put(type, wr);
|
||||
}
|
||||
|
||||
private static synchronized void putPermanentMapping(
|
||||
Type type, MXBeanMapping mapping) {
|
||||
putMapping(type, mapping);
|
||||
permanentMappings.add(mapping);
|
||||
}
|
||||
|
||||
static {
|
||||
/* Set up the mappings for Java types that map to SimpleType. */
|
||||
|
||||
@ -213,7 +204,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
throw new Error(e);
|
||||
}
|
||||
final MXBeanMapping mapping = new IdentityMapping(c, t);
|
||||
permanentMappings.put(c, mapping);
|
||||
putPermanentMapping(c, mapping);
|
||||
|
||||
if (c.getName().startsWith("java.lang.")) {
|
||||
try {
|
||||
@ -221,7 +212,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
final Class<?> primitiveType = (Class<?>) typeField.get(null);
|
||||
final MXBeanMapping primitiveMapping =
|
||||
new IdentityMapping(primitiveType, t);
|
||||
permanentMappings.put(primitiveType, primitiveMapping);
|
||||
putPermanentMapping(primitiveType, primitiveMapping);
|
||||
if (primitiveType != void.class) {
|
||||
final Class<?> primitiveArrayType =
|
||||
Array.newInstance(primitiveType, 0).getClass();
|
||||
@ -230,8 +221,8 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
final MXBeanMapping primitiveArrayMapping =
|
||||
new IdentityMapping(primitiveArrayType,
|
||||
primitiveArrayOpenType);
|
||||
permanentMappings.put(primitiveArrayType,
|
||||
primitiveArrayMapping);
|
||||
putPermanentMapping(primitiveArrayType,
|
||||
primitiveArrayMapping);
|
||||
}
|
||||
} catch (NoSuchFieldException e) {
|
||||
// OK: must not be a primitive wrapper
|
||||
@ -255,7 +246,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
|
||||
MXBeanMapping mapping;
|
||||
|
||||
mapping = getMapping(objType, null);
|
||||
mapping = getMapping(objType);
|
||||
if (mapping != null)
|
||||
return mapping;
|
||||
|
||||
@ -268,7 +259,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
inProgress.remove(objType);
|
||||
}
|
||||
|
||||
putMapping(objType, mapping, factory);
|
||||
putMapping(objType, mapping);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
@ -278,14 +269,6 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
/* It's not yet worth formalizing these tests by having for example
|
||||
an array of factory classes, each of which says whether it
|
||||
recognizes the Type (Chain of Responsibility pattern). */
|
||||
MXBeanMapping mapping = permanentMappings.get(objType);
|
||||
if (mapping != null)
|
||||
return mapping;
|
||||
Class<?> erasure = erasure(objType);
|
||||
MXBeanMappingClass mappingClass =
|
||||
erasure.getAnnotation(MXBeanMappingClass.class);
|
||||
if (mappingClass != null)
|
||||
return makeAnnotationMapping(mappingClass, objType, factory);
|
||||
if (objType instanceof GenericArrayType) {
|
||||
Type componentType =
|
||||
((GenericArrayType) objType).getGenericComponentType();
|
||||
@ -313,51 +296,6 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
throw new OpenDataException("Cannot map type: " + objType);
|
||||
}
|
||||
|
||||
private static MXBeanMapping
|
||||
makeAnnotationMapping(MXBeanMappingClass mappingClass,
|
||||
Type objType,
|
||||
MXBeanMappingFactory factory)
|
||||
throws OpenDataException {
|
||||
Class<? extends MXBeanMapping> c = mappingClass.value();
|
||||
Constructor<? extends MXBeanMapping> cons;
|
||||
try {
|
||||
cons = c.getConstructor(Type.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
final String msg =
|
||||
"Annotation @" + MXBeanMappingClass.class.getName() +
|
||||
" must name a class with a public constructor that has a " +
|
||||
"single " + Type.class.getName() + " argument";
|
||||
OpenDataException ode = new OpenDataException(msg);
|
||||
ode.initCause(e);
|
||||
throw ode;
|
||||
}
|
||||
try {
|
||||
return cons.newInstance(objType);
|
||||
} catch (Exception e) {
|
||||
final String msg =
|
||||
"Could not construct a " + c.getName() + " for @" +
|
||||
MXBeanMappingClass.class.getName();
|
||||
OpenDataException ode = new OpenDataException(msg);
|
||||
ode.initCause(e);
|
||||
throw ode;
|
||||
}
|
||||
}
|
||||
|
||||
private static Class<?> erasure(Type t) {
|
||||
if (t instanceof Class<?>)
|
||||
return (Class<?>) t;
|
||||
if (t instanceof ParameterizedType)
|
||||
return erasure(((ParameterizedType) t).getRawType());
|
||||
/* Other cases: GenericArrayType, TypeVariable, WildcardType.
|
||||
* Returning the erasure of GenericArrayType is not necessary because
|
||||
* anyway we will be recursing on the element type, and we'll erase
|
||||
* then. Returning the erasure of the other two would mean returning
|
||||
* the type bound (e.g. Foo in <T extends Foo> or <? extends Foo>)
|
||||
* and since we don't treat this as Foo elsewhere we shouldn't here.
|
||||
*/
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
private static <T extends Enum<T>> MXBeanMapping
|
||||
makeEnumMapping(Class<?> enumClass, Class<T> fake) {
|
||||
return new EnumMapping<T>(Util.<Class<T>>cast(enumClass));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2005 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,7 +25,7 @@
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import javax.management.DynamicWrapperMBean;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
@ -35,7 +35,17 @@ import javax.management.ObjectName;
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface DynamicMBean2 extends DynamicWrapperMBean {
|
||||
public interface DynamicMBean2 extends DynamicMBean {
|
||||
/**
|
||||
* The resource corresponding to this MBean. This is the object whose
|
||||
* class name should be reflected by the MBean's
|
||||
* getMBeanInfo().getClassName() for example. For a "plain"
|
||||
* DynamicMBean it will be "this". For an MBean that wraps another
|
||||
* object, like javax.management.StandardMBean, it will be the wrapped
|
||||
* object.
|
||||
*/
|
||||
public Object getResource();
|
||||
|
||||
/**
|
||||
* The name of this MBean's class, as used by permission checks.
|
||||
* This is typically equal to getResource().getClass().getName().
|
||||
|
@ -25,14 +25,9 @@
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Proxy;
|
||||
@ -40,39 +35,21 @@ import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.Description;
|
||||
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.DescriptorFields;
|
||||
import javax.management.DescriptorKey;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.ImmutableDescriptor;
|
||||
import javax.management.MBean;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MXBean;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.JMX;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ObjectNameTemplate;
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* This class contains the methods for performing all the tests needed to verify
|
||||
@ -82,13 +59,7 @@ import javax.management.openmbean.MXBeanMappingFactory;
|
||||
*/
|
||||
public class Introspector {
|
||||
|
||||
/**
|
||||
* Pattern used to extract Attribute Names from ObjectNameTemplate Annotation
|
||||
* For example, in the following example, the Name attribute value is
|
||||
* retrieved : ":type=MyType, name={Name}"
|
||||
*/
|
||||
private static Pattern OBJECT_NAME_PATTERN_TEMPLATE =
|
||||
Pattern.compile("(\\{[^\\}]+\\})|(=\"\\{[^\\}]+\\}\")");
|
||||
|
||||
/*
|
||||
* ------------------------------------------
|
||||
* PRIVATE CONSTRUCTORS
|
||||
@ -164,10 +135,6 @@ public class Introspector {
|
||||
|
||||
public static void checkCompliance(Class<?> mbeanClass)
|
||||
throws NotCompliantMBeanException {
|
||||
|
||||
// Check that @Resource is used correctly (if it used).
|
||||
MBeanInjector.validate(mbeanClass);
|
||||
|
||||
// Is DynamicMBean?
|
||||
//
|
||||
if (DynamicMBean.class.isAssignableFrom(mbeanClass))
|
||||
@ -190,36 +157,16 @@ public class Introspector {
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
mxbeanException = e;
|
||||
}
|
||||
// Is @MBean or @MXBean class?
|
||||
// In fact we find @MBean or @MXBean as a hacky variant of
|
||||
// getStandardMBeanInterface or getMXBeanInterface. If we get here
|
||||
// then nothing worked.
|
||||
final String msg =
|
||||
"MBean class " + mbeanClass.getName() + " does not implement " +
|
||||
"DynamicMBean; does not follow the Standard MBean conventions (" +
|
||||
mbeanException.toString() + "); does not follow the MXBean conventions (" +
|
||||
mxbeanException.toString() + "); and does not have or inherit the @" +
|
||||
MBean.class.getSimpleName() + " or @" + MXBean.class.getSimpleName() +
|
||||
" annotation";
|
||||
"DynamicMBean, and neither follows the Standard MBean conventions (" +
|
||||
mbeanException.toString() + ") nor the MXBean conventions (" +
|
||||
mxbeanException.toString() + ")";
|
||||
throw new NotCompliantMBeanException(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Make a DynamicMBean out of the existing MBean object. The object
|
||||
* may already be a DynamicMBean, or it may be a Standard MBean or
|
||||
* MXBean, possibly defined using {@code @MBean} or {@code @MXBean}.</p>
|
||||
* @param mbean the object to convert to a DynamicMBean.
|
||||
* @param <T> a type parameter defined for implementation convenience
|
||||
* (which would have to be removed if this method were part of the public
|
||||
* API).
|
||||
* @return the converted DynamicMBean.
|
||||
* @throws NotCompliantMBeanException if {@code mbean} is not a compliant
|
||||
* MBean object, including the case where it is null.
|
||||
*/
|
||||
public static <T> DynamicMBean makeDynamicMBean(T mbean)
|
||||
throws NotCompliantMBeanException {
|
||||
if (mbean == null)
|
||||
throw new NotCompliantMBeanException("Null MBean object");
|
||||
throws NotCompliantMBeanException {
|
||||
if (mbean instanceof DynamicMBean)
|
||||
return (DynamicMBean) mbean;
|
||||
final Class<?> mbeanClass = mbean.getClass();
|
||||
@ -240,18 +187,8 @@ public class Introspector {
|
||||
// to be an MBean or an MXBean. We will call checkCompliance()
|
||||
// to generate the appropriate exception.
|
||||
}
|
||||
if (c != null) {
|
||||
MXBeanMappingFactory factory;
|
||||
try {
|
||||
factory = MXBeanMappingFactory.forInterface(c);
|
||||
} catch (IllegalArgumentException e) {
|
||||
NotCompliantMBeanException ncmbe =
|
||||
new NotCompliantMBeanException(e.getMessage());
|
||||
ncmbe.initCause(e);
|
||||
throw ncmbe;
|
||||
}
|
||||
return new MXBeanSupport(mbean, c, factory);
|
||||
}
|
||||
if (c != null)
|
||||
return new MXBeanSupport(mbean, c);
|
||||
checkCompliance(mbeanClass);
|
||||
throw new NotCompliantMBeanException("Not compliant"); // not reached
|
||||
}
|
||||
@ -280,10 +217,9 @@ public class Introspector {
|
||||
return testCompliance(baseClass, null);
|
||||
}
|
||||
|
||||
public static void testComplianceMXBeanInterface(Class<?> interfaceClass,
|
||||
MXBeanMappingFactory factory)
|
||||
public static void testComplianceMXBeanInterface(Class<?> interfaceClass)
|
||||
throws NotCompliantMBeanException {
|
||||
MXBeanIntrospector.getInstance(factory).getAnalyzer(interfaceClass);
|
||||
MXBeanIntrospector.getInstance().getAnalyzer(interfaceClass);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -352,8 +288,6 @@ public class Introspector {
|
||||
*/
|
||||
public static <T> Class<? super T> getStandardMBeanInterface(Class<T> baseClass)
|
||||
throws NotCompliantMBeanException {
|
||||
if (baseClass.isAnnotationPresent(MBean.class))
|
||||
return baseClass;
|
||||
Class<? super T> current = baseClass;
|
||||
Class<? super T> mbeanInterface = null;
|
||||
while (current != null) {
|
||||
@ -384,8 +318,6 @@ public class Introspector {
|
||||
*/
|
||||
public static <T> Class<? super T> getMXBeanInterface(Class<T> baseClass)
|
||||
throws NotCompliantMBeanException {
|
||||
if (hasMXBeanAnnotation(baseClass))
|
||||
return baseClass;
|
||||
try {
|
||||
return MXBeanSupport.findMXBeanInterface(baseClass);
|
||||
} catch (Exception e) {
|
||||
@ -393,61 +325,12 @@ public class Introspector {
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Class<? super T> getStandardOrMXBeanInterface(
|
||||
Class<T> baseClass, boolean mxbean)
|
||||
throws NotCompliantMBeanException {
|
||||
if (mxbean)
|
||||
return getMXBeanInterface(baseClass);
|
||||
else
|
||||
return getStandardMBeanInterface(baseClass);
|
||||
}
|
||||
|
||||
public static ObjectName templateToObjectName(Descriptor descriptor,
|
||||
DynamicMBean mbean)
|
||||
throws NotCompliantMBeanException {
|
||||
String template = (String)
|
||||
descriptor.getFieldValue(JMX.OBJECT_NAME_TEMPLATE);
|
||||
if(template == null) return null;
|
||||
try {
|
||||
Matcher m = OBJECT_NAME_PATTERN_TEMPLATE.matcher(template);
|
||||
while (m.find()){
|
||||
String grp = m.group();
|
||||
System.out.println("GROUP " + grp);
|
||||
String attributeName = null;
|
||||
boolean quote = false;
|
||||
if(grp.startsWith("=\"{")) {
|
||||
attributeName = grp.substring(3, grp.length() - 2);
|
||||
quote = true;
|
||||
} else
|
||||
attributeName = grp.substring(1, grp.length() - 1);
|
||||
|
||||
Object attributeValue = mbean.getAttribute(attributeName);
|
||||
String validValue = quote ?
|
||||
"=" + ObjectName.quote(attributeValue.toString()) :
|
||||
attributeValue.toString();
|
||||
template = template.replace(grp, validValue);
|
||||
}
|
||||
return new ObjectName(template);
|
||||
}catch(Exception ex) {
|
||||
NotCompliantMBeanException ncex = new
|
||||
NotCompliantMBeanException(ObjectNameTemplate.class.
|
||||
getSimpleName() + " annotation value [" + template + "] " +
|
||||
"is invalid. " + ex);
|
||||
ncex.initCause(ex);
|
||||
throw ncex;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------
|
||||
* PRIVATE METHODS
|
||||
* ------------------------------------------
|
||||
*/
|
||||
|
||||
static boolean hasMXBeanAnnotation(Class<?> c) {
|
||||
MXBean m = c.getAnnotation(MXBean.class);
|
||||
return (m != null && m.value());
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find the MBean interface corresponding to the class aName
|
||||
@ -469,77 +352,11 @@ public class Introspector {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String descriptionForElement(AnnotatedElement elmt) {
|
||||
if (elmt == null)
|
||||
return null;
|
||||
Description d = elmt.getAnnotation(Description.class);
|
||||
if (d == null)
|
||||
return null;
|
||||
return d.value();
|
||||
}
|
||||
|
||||
public static String descriptionForParameter(
|
||||
Annotation[] parameterAnnotations) {
|
||||
for (Annotation a : parameterAnnotations) {
|
||||
if (a instanceof Description)
|
||||
return ((Description) a).value();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String nameForParameter(
|
||||
Annotation[] parameterAnnotations) {
|
||||
for (Annotation a : parameterAnnotations) {
|
||||
Class<? extends Annotation> ac = a.annotationType();
|
||||
// You'd really have to go out of your way to have more than
|
||||
// one @Name annotation, so we don't check for that.
|
||||
if (ac.getSimpleName().equals("Name")) {
|
||||
try {
|
||||
Method value = ac.getMethod("value");
|
||||
if (value.getReturnType() == String.class &&
|
||||
value.getParameterTypes().length == 0) {
|
||||
return (String) value.invoke(a);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
MBEANSERVER_LOGGER.log(
|
||||
Level.WARNING,
|
||||
"Unexpected exception getting @" + ac.getName(),
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Descriptor descriptorForElement(final AnnotatedElement elmt,
|
||||
boolean isSetter) {
|
||||
public static Descriptor descriptorForElement(final AnnotatedElement elmt) {
|
||||
if (elmt == null)
|
||||
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
||||
final Annotation[] annots = elmt.getAnnotations();
|
||||
Descriptor descr = descriptorForAnnotations(annots);
|
||||
String[] exceptions = {};
|
||||
if(elmt instanceof Method)
|
||||
exceptions = getAllExceptions(((Method) elmt).getExceptionTypes());
|
||||
else
|
||||
if(elmt instanceof Constructor<?>)
|
||||
exceptions = getAllExceptions(((Constructor<?>) elmt).
|
||||
getExceptionTypes());
|
||||
|
||||
if(exceptions.length > 0 ) {
|
||||
String fieldName = isSetter ? JMX.SET_EXCEPTIONS_FIELD :
|
||||
JMX.EXCEPTIONS_FIELD;
|
||||
|
||||
String[] fieldNames = {fieldName};
|
||||
Object[] fieldValues = {exceptions};
|
||||
descr = ImmutableDescriptor.union(descr,
|
||||
new ImmutableDescriptor(fieldNames, fieldValues));
|
||||
}
|
||||
|
||||
return descr;
|
||||
}
|
||||
|
||||
public static Descriptor descriptorForAnnotation(Annotation annot) {
|
||||
return descriptorForAnnotations(new Annotation[] {annot});
|
||||
return descriptorForAnnotations(annots);
|
||||
}
|
||||
|
||||
public static Descriptor descriptorForAnnotations(Annotation[] annots) {
|
||||
@ -547,9 +364,36 @@ public class Introspector {
|
||||
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
||||
Map<String, Object> descriptorMap = new HashMap<String, Object>();
|
||||
for (Annotation a : annots) {
|
||||
if (a instanceof DescriptorFields)
|
||||
addDescriptorFieldsToMap(descriptorMap, (DescriptorFields) a);
|
||||
addAnnotationFieldsToMap(descriptorMap, a);
|
||||
Class<? extends Annotation> c = a.annotationType();
|
||||
Method[] elements = c.getMethods();
|
||||
for (Method element : elements) {
|
||||
DescriptorKey key = element.getAnnotation(DescriptorKey.class);
|
||||
if (key != null) {
|
||||
String name = key.value();
|
||||
Object value;
|
||||
try {
|
||||
value = element.invoke(a);
|
||||
} catch (RuntimeException e) {
|
||||
// we don't expect this - except for possibly
|
||||
// security exceptions?
|
||||
// RuntimeExceptions shouldn't be "UndeclaredThrowable".
|
||||
// anyway...
|
||||
//
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// we don't expect this
|
||||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
value = annotationToField(value);
|
||||
Object oldValue = descriptorMap.put(name, value);
|
||||
if (oldValue != null && !equals(oldValue, value)) {
|
||||
final String msg =
|
||||
"Inconsistent values for descriptor field " + name +
|
||||
" from annotations: " + value + " :: " + oldValue;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (descriptorMap.isEmpty())
|
||||
@ -558,76 +402,6 @@ public class Introspector {
|
||||
return new ImmutableDescriptor(descriptorMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Array of thrown excepions.
|
||||
* @param exceptions can be null;
|
||||
* @return An Array of Exception class names. Size is 0 if method is null.
|
||||
*/
|
||||
private static String[] getAllExceptions(Class<?>[] exceptions) {
|
||||
Set<String> set = new LinkedHashSet<String>();
|
||||
for(Class<?>ex : exceptions)
|
||||
set.add(ex.getName());
|
||||
|
||||
String[] arr = new String[set.size()];
|
||||
return set.toArray(arr);
|
||||
}
|
||||
|
||||
private static void addDescriptorFieldsToMap(
|
||||
Map<String, Object> descriptorMap, DescriptorFields df) {
|
||||
for (String field : df.value()) {
|
||||
int eq = field.indexOf('=');
|
||||
if (eq < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"@DescriptorFields string must contain '=': " +
|
||||
field);
|
||||
}
|
||||
String name = field.substring(0, eq);
|
||||
String value = field.substring(eq + 1);
|
||||
addToMap(descriptorMap, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addAnnotationFieldsToMap(
|
||||
Map<String, Object> descriptorMap, Annotation a) {
|
||||
Class<? extends Annotation> c = a.annotationType();
|
||||
Method[] elements = c.getMethods();
|
||||
for (Method element : elements) {
|
||||
DescriptorKey key = element.getAnnotation(DescriptorKey.class);
|
||||
if (key != null) {
|
||||
String name = key.value();
|
||||
Object value;
|
||||
try {
|
||||
value = element.invoke(a);
|
||||
} catch (RuntimeException e) {
|
||||
// we don't expect this - except for possibly
|
||||
// security exceptions?
|
||||
// RuntimeExceptions shouldn't be "UndeclaredThrowable".
|
||||
// anyway...
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// we don't expect this
|
||||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
if (!key.omitIfDefault() ||
|
||||
!equals(value, element.getDefaultValue())) {
|
||||
value = annotationToField(value);
|
||||
addToMap(descriptorMap, name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addToMap(
|
||||
Map<String, Object> descriptorMap, String name, Object value) {
|
||||
Object oldValue = descriptorMap.put(name, value);
|
||||
if (oldValue != null && !equals(oldValue, value)) {
|
||||
final String msg =
|
||||
"Inconsistent values for descriptor field " + name +
|
||||
" from annotations: " + value + " :: " + oldValue;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a NotCompliantMBeanException or a SecurityException.
|
||||
* @param notCompliant the class which was under examination
|
||||
|
@ -25,14 +25,14 @@
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import com.sun.jmx.interceptor.DefaultMBeanServerInterceptor;
|
||||
import com.sun.jmx.interceptor.MBeanServerInterceptor;
|
||||
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
|
||||
import com.sun.jmx.interceptor.NamespaceDispatchInterceptor;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import java.security.AccessController;
|
||||
import java.security.Permission;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
@ -108,8 +108,6 @@ public final class JmxMBeanServer
|
||||
/** The MBeanServerDelegate object representing the MBean Server */
|
||||
private final MBeanServerDelegate mBeanServerDelegateObject;
|
||||
|
||||
private final String mbeanServerName;
|
||||
|
||||
/**
|
||||
* <b>Package:</b> Creates an MBeanServer with the
|
||||
* specified default domain name, outer interface, and delegate.
|
||||
@ -241,10 +239,9 @@ public final class JmxMBeanServer
|
||||
|
||||
final Repository repository = new Repository(domain);
|
||||
this.mbsInterceptor =
|
||||
new NamespaceDispatchInterceptor(outer, delegate, instantiator,
|
||||
new DefaultMBeanServerInterceptor(outer, delegate, instantiator,
|
||||
repository);
|
||||
this.interceptorsEnabled = interceptors;
|
||||
this.mbeanServerName = Util.getMBeanServerSecurityName(delegate);
|
||||
initialize();
|
||||
}
|
||||
|
||||
@ -940,8 +937,7 @@ public final class JmxMBeanServer
|
||||
throws ReflectionException, MBeanException {
|
||||
|
||||
/* Permission check */
|
||||
checkMBeanPermission(mbeanServerName, className, null, null,
|
||||
"instantiate");
|
||||
checkMBeanPermission(className, null, null, "instantiate");
|
||||
|
||||
return instantiator.instantiate(className);
|
||||
}
|
||||
@ -978,8 +974,7 @@ public final class JmxMBeanServer
|
||||
InstanceNotFoundException {
|
||||
|
||||
/* Permission check */
|
||||
checkMBeanPermission(mbeanServerName, className, null,
|
||||
null, "instantiate");
|
||||
checkMBeanPermission(className, null, null, "instantiate");
|
||||
|
||||
ClassLoader myLoader = outerShell.getClass().getClassLoader();
|
||||
return instantiator.instantiate(className, loaderName, myLoader);
|
||||
@ -1017,8 +1012,7 @@ public final class JmxMBeanServer
|
||||
throws ReflectionException, MBeanException {
|
||||
|
||||
/* Permission check */
|
||||
checkMBeanPermission(mbeanServerName, className, null, null,
|
||||
"instantiate");
|
||||
checkMBeanPermission(className, null, null, "instantiate");
|
||||
|
||||
ClassLoader myLoader = outerShell.getClass().getClassLoader();
|
||||
return instantiator.instantiate(className, params, signature,
|
||||
@ -1061,8 +1055,7 @@ public final class JmxMBeanServer
|
||||
InstanceNotFoundException {
|
||||
|
||||
/* Permission check */
|
||||
checkMBeanPermission(mbeanServerName, className, null,
|
||||
null, "instantiate");
|
||||
checkMBeanPermission(className, null, null, "instantiate");
|
||||
|
||||
ClassLoader myLoader = outerShell.getClass().getClassLoader();
|
||||
return instantiator.instantiate(className,loaderName,params,signature,
|
||||
@ -1333,8 +1326,7 @@ public final class JmxMBeanServer
|
||||
**/
|
||||
public ClassLoaderRepository getClassLoaderRepository() {
|
||||
/* Permission check */
|
||||
checkMBeanPermission(mbeanServerName, null, null,
|
||||
null, "getClassLoaderRepository");
|
||||
checkMBeanPermission(null, null, null, "getClassLoaderRepository");
|
||||
return secureClr;
|
||||
}
|
||||
|
||||
@ -1487,16 +1479,14 @@ public final class JmxMBeanServer
|
||||
// SECURITY CHECKS
|
||||
//----------------
|
||||
|
||||
private static void checkMBeanPermission(String serverName,
|
||||
String classname,
|
||||
private static void checkMBeanPermission(String classname,
|
||||
String member,
|
||||
ObjectName objectName,
|
||||
String actions)
|
||||
throws SecurityException {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
Permission perm = new MBeanPermission(serverName,
|
||||
classname,
|
||||
Permission perm = new MBeanPermission(classname,
|
||||
member,
|
||||
objectName,
|
||||
actions);
|
||||
|
@ -33,10 +33,6 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.management.MBean;
|
||||
import javax.management.MXBean;
|
||||
import javax.management.ManagedAttribute;
|
||||
import javax.management.ManagedOperation;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
|
||||
/**
|
||||
@ -55,15 +51,15 @@ import javax.management.NotCompliantMBeanException;
|
||||
*/
|
||||
class MBeanAnalyzer<M> {
|
||||
|
||||
static interface MBeanVisitor<M, X extends Exception> {
|
||||
static interface MBeanVisitor<M> {
|
||||
public void visitAttribute(String attributeName,
|
||||
M getter,
|
||||
M setter) throws X;
|
||||
M setter);
|
||||
public void visitOperation(String operationName,
|
||||
M operation) throws X;
|
||||
M operation);
|
||||
}
|
||||
|
||||
<X extends Exception> void visit(MBeanVisitor<M, X> visitor) throws X {
|
||||
void visit(MBeanVisitor<M> visitor) {
|
||||
// visit attributes
|
||||
for (Map.Entry<String, AttrMethods<M>> entry : attrMap.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
@ -108,7 +104,10 @@ class MBeanAnalyzer<M> {
|
||||
private MBeanAnalyzer(Class<?> mbeanType,
|
||||
MBeanIntrospector<M> introspector)
|
||||
throws NotCompliantMBeanException {
|
||||
introspector.checkCompliance(mbeanType);
|
||||
if (!mbeanType.isInterface()) {
|
||||
throw new NotCompliantMBeanException("Not an interface: " +
|
||||
mbeanType.getName());
|
||||
}
|
||||
|
||||
try {
|
||||
initMaps(mbeanType, introspector);
|
||||
@ -129,26 +128,18 @@ class MBeanAnalyzer<M> {
|
||||
for (Method m : methods) {
|
||||
final String name = m.getName();
|
||||
final int nParams = m.getParameterTypes().length;
|
||||
final boolean managedOp = m.isAnnotationPresent(ManagedOperation.class);
|
||||
final boolean managedAttr = m.isAnnotationPresent(ManagedAttribute.class);
|
||||
if (managedOp && managedAttr) {
|
||||
throw new NotCompliantMBeanException("Method " + name +
|
||||
" has both @ManagedOperation and @ManagedAttribute");
|
||||
}
|
||||
|
||||
final M cm = introspector.mFrom(m);
|
||||
|
||||
String attrName = "";
|
||||
if (!managedOp) {
|
||||
if (name.startsWith("get"))
|
||||
attrName = name.substring(3);
|
||||
else if (name.startsWith("is")
|
||||
&& m.getReturnType() == boolean.class)
|
||||
attrName = name.substring(2);
|
||||
}
|
||||
if (name.startsWith("get"))
|
||||
attrName = name.substring(3);
|
||||
else if (name.startsWith("is")
|
||||
&& m.getReturnType() == boolean.class)
|
||||
attrName = name.substring(2);
|
||||
|
||||
if (attrName.length() != 0 && nParams == 0
|
||||
&& m.getReturnType() != void.class && !managedOp) {
|
||||
&& m.getReturnType() != void.class) {
|
||||
// It's a getter
|
||||
// Check we don't have both isX and getX
|
||||
AttrMethods<M> am = attrMap.get(attrName);
|
||||
@ -165,7 +156,7 @@ class MBeanAnalyzer<M> {
|
||||
attrMap.put(attrName, am);
|
||||
} else if (name.startsWith("set") && name.length() > 3
|
||||
&& nParams == 1 &&
|
||||
m.getReturnType() == void.class && !managedOp) {
|
||||
m.getReturnType() == void.class) {
|
||||
// It's a setter
|
||||
attrName = name.substring(3);
|
||||
AttrMethods<M> am = attrMap.get(attrName);
|
||||
@ -178,9 +169,6 @@ class MBeanAnalyzer<M> {
|
||||
}
|
||||
am.setter = cm;
|
||||
attrMap.put(attrName, am);
|
||||
} else if (managedAttr) {
|
||||
throw new NotCompliantMBeanException("Method " + name +
|
||||
" has @ManagedAttribute but is not a valid getter or setter");
|
||||
} else {
|
||||
// It's an operation
|
||||
List<M> cms = opMap.get(name);
|
||||
|
@ -1,295 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import javax.annotation.Resource;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import static com.sun.jmx.mbeanserver.Util.newMap;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.AccessController;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.management.SendNotification;
|
||||
|
||||
public class MBeanInjector {
|
||||
// There are no instances of this class
|
||||
private MBeanInjector() {
|
||||
}
|
||||
|
||||
private static Class<?>[] injectedClasses = {
|
||||
MBeanServer.class, ObjectName.class, SendNotification.class,
|
||||
};
|
||||
|
||||
public static void inject(Object mbean, MBeanServer mbs, ObjectName name)
|
||||
throws Exception {
|
||||
ClassInjector injector = injectorForClass(mbean.getClass());
|
||||
injector.inject(mbean, MBeanServer.class, mbs);
|
||||
injector.inject(mbean, ObjectName.class, name);
|
||||
}
|
||||
|
||||
public static boolean injectsSendNotification(Object mbean)
|
||||
throws NotCompliantMBeanException {
|
||||
ClassInjector injector = injectorForClass(mbean.getClass());
|
||||
return injector.injects(SendNotification.class);
|
||||
}
|
||||
|
||||
public static void injectSendNotification(Object mbean, SendNotification sn)
|
||||
throws Exception {
|
||||
ClassInjector injector = injectorForClass(mbean.getClass());
|
||||
injector.inject(mbean, SendNotification.class, sn);
|
||||
}
|
||||
|
||||
public static void validate(Class<?> c) throws NotCompliantMBeanException {
|
||||
injectorForClass(c);
|
||||
}
|
||||
|
||||
private static class ClassInjector {
|
||||
private Map<Class<?>, List<Field>> fields;
|
||||
private Map<Class<?>, List<Method>> methods;
|
||||
|
||||
ClassInjector(Class<?> c) throws NotCompliantMBeanException {
|
||||
fields = newMap();
|
||||
methods = newMap();
|
||||
|
||||
Class<?> sup = c.getSuperclass();
|
||||
ClassInjector supInjector;
|
||||
if (sup == null) {
|
||||
supInjector = null;
|
||||
} else {
|
||||
supInjector = injectorForClass(sup);
|
||||
fields.putAll(supInjector.fields);
|
||||
methods.putAll(supInjector.methods);
|
||||
}
|
||||
|
||||
addMembers(c);
|
||||
eliminateOverriddenMethods();
|
||||
|
||||
// If we haven't added any new fields or methods to what we
|
||||
// inherited, then we can share the parent's maps.
|
||||
if (supInjector != null) {
|
||||
if (fields.equals(supInjector.fields))
|
||||
fields = supInjector.fields;
|
||||
if (methods.equals(supInjector.methods))
|
||||
methods = supInjector.methods;
|
||||
}
|
||||
}
|
||||
|
||||
boolean injects(Class<?> c) {
|
||||
return (fields.get(c) != null || methods.get(c) != null);
|
||||
}
|
||||
|
||||
<T> void inject(Object instance, Class<T> type, T resource)
|
||||
throws Exception {
|
||||
List<Field> fs = fields.get(type);
|
||||
if (fs != null) {
|
||||
for (Field f : fs)
|
||||
f.set(instance, resource);
|
||||
}
|
||||
List<Method> ms = methods.get(type);
|
||||
if (ms != null) {
|
||||
for (Method m : ms) {
|
||||
try {
|
||||
m.invoke(instance, resource);
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof Error)
|
||||
throw (Error) cause;
|
||||
else
|
||||
throw (Exception) cause;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void eliminateOverriddenMethods() {
|
||||
/* Covariant overriding is unlikely, but it is possible that the
|
||||
* parent has a @Resource method that we override with another
|
||||
* @Resource method. We don't want to invoke both methods,
|
||||
* because polymorphism means we would actually invoke the same
|
||||
* method twice.
|
||||
*/
|
||||
for (Map.Entry<Class<?>, List<Method>> entry : methods.entrySet()) {
|
||||
List<Method> list = entry.getValue();
|
||||
list = MBeanAnalyzer.eliminateCovariantMethods(list);
|
||||
entry.setValue(list);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find Fields or Methods within the given Class that we can inject
|
||||
* resource references into. Suppose we want to know if a Field can get
|
||||
* a reference to an ObjectName. We'll accept fields like this:
|
||||
*
|
||||
* @Resource
|
||||
* private transient ObjectName name;
|
||||
*
|
||||
* or like this:
|
||||
*
|
||||
* @Resource(type = ObjectName.class)
|
||||
* private transient Object name;
|
||||
*
|
||||
* but not like this:
|
||||
*
|
||||
* @Resource
|
||||
* private transient Object name;
|
||||
*
|
||||
* (Plain @Resource is equivalent to @Resource(type = Object.class).)
|
||||
*
|
||||
* We don't want to inject into everything that might possibly accept
|
||||
* an ObjectName reference, because examples like the last one above
|
||||
* could also accept an MBeanServer reference or any other sort of
|
||||
* reference.
|
||||
*
|
||||
* So we accept a Field if it has a @Resource annotation and either
|
||||
* (a) its type is exactly ObjectName and its @Resource type is
|
||||
* compatible with ObjectName (e.g. it is Object); or
|
||||
* (b) its type is compatible with ObjectName and its @Resource type
|
||||
* is exactly ObjectName. Fields that meet these criteria will not
|
||||
* meet the same criteria with respect to other types such as MBeanServer.
|
||||
*
|
||||
* The same logic applies mutatis mutandis to Methods such as this:
|
||||
*
|
||||
* @Resource
|
||||
* private void setObjectName1(ObjectName name)
|
||||
* @Resource(type = Object.class)
|
||||
* private void setObjectName2(Object name)
|
||||
*/
|
||||
private void addMembers(final Class<?> c)
|
||||
throws NotCompliantMBeanException {
|
||||
AccessibleObject[][] memberArrays =
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedAction<AccessibleObject[][]>() {
|
||||
public AccessibleObject[][] run() {
|
||||
return new AccessibleObject[][] {
|
||||
c.getDeclaredFields(), c.getDeclaredMethods()
|
||||
};
|
||||
}
|
||||
});
|
||||
for (AccessibleObject[] members : memberArrays) {
|
||||
for (final AccessibleObject member : members) {
|
||||
Resource res = member.getAnnotation(Resource.class);
|
||||
if (res == null)
|
||||
continue;
|
||||
|
||||
final Field field;
|
||||
final Method method;
|
||||
final Class<?> memberType;
|
||||
final int modifiers;
|
||||
if (member instanceof Field) {
|
||||
field = (Field) member;
|
||||
memberType = field.getType();
|
||||
modifiers = field.getModifiers();
|
||||
method = null;
|
||||
} else {
|
||||
field = null;
|
||||
method = (Method) member;
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
if (paramTypes.length != 1) {
|
||||
throw new NotCompliantMBeanException(
|
||||
"@Resource method must have exactly 1 " +
|
||||
"parameter: " + method);
|
||||
}
|
||||
if (method.getReturnType() != void.class) {
|
||||
throw new NotCompliantMBeanException(
|
||||
"@Resource method must return void: " +
|
||||
method);
|
||||
}
|
||||
memberType = paramTypes[0];
|
||||
modifiers = method.getModifiers();
|
||||
}
|
||||
|
||||
if (Modifier.isStatic(modifiers)) {
|
||||
throw new NotCompliantMBeanException(
|
||||
"@Resource method or field cannot be static: " +
|
||||
member);
|
||||
}
|
||||
|
||||
for (Class<?> injectedClass : injectedClasses) {
|
||||
Class<?>[] types = {memberType, res.type()};
|
||||
boolean accept = false;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (types[i] == injectedClass &&
|
||||
types[1 - i].isAssignableFrom(injectedClass)) {
|
||||
accept = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (accept) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
member.setAccessible(true);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
addToMap(fields, injectedClass, field);
|
||||
addToMap(methods, injectedClass, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static <K, V> void addToMap(Map<K, List<V>> map, K key, V value) {
|
||||
if (value == null)
|
||||
return;
|
||||
List<V> list = map.get(key);
|
||||
if (list == null)
|
||||
list = Collections.singletonList(value);
|
||||
else {
|
||||
if (list.size() == 1)
|
||||
list = new ArrayList<V>(list);
|
||||
list.add(value);
|
||||
}
|
||||
map.put(key, list);
|
||||
}
|
||||
}
|
||||
|
||||
private static synchronized ClassInjector injectorForClass(Class<?> c)
|
||||
throws NotCompliantMBeanException {
|
||||
WeakReference<ClassInjector> wr = injectorMap.get(c);
|
||||
ClassInjector ci = (wr == null) ? null : wr.get();
|
||||
if (ci == null) {
|
||||
ci = new ClassInjector(c);
|
||||
injectorMap.put(c, new WeakReference<ClassInjector>(ci));
|
||||
}
|
||||
return ci;
|
||||
}
|
||||
|
||||
private static Map<Class<?>, WeakReference<ClassInjector>> injectorMap =
|
||||
new WeakHashMap<Class<?>, WeakReference<ClassInjector>>();
|
||||
}
|
@ -613,15 +613,6 @@ public class MBeanInstantiator {
|
||||
return clr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class of a primitive type.
|
||||
* @param name The type for which we the associated class.
|
||||
* @return the class, or null if name is not primitive.
|
||||
*/
|
||||
public static Class<?> primitiveType(String name) {
|
||||
return primitiveClasses.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a class with the specified loader, or with this object
|
||||
* class loader if the specified loader is null.
|
||||
|
@ -36,28 +36,20 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import javax.management.Description;
|
||||
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.ImmutableDescriptor;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.MBean;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanConstructorInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MXBean;
|
||||
import javax.management.ManagedAttribute;
|
||||
import javax.management.ManagedOperation;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationBroadcaster;
|
||||
import javax.management.NotificationInfo;
|
||||
import javax.management.NotificationInfos;
|
||||
import javax.management.ReflectionException;
|
||||
|
||||
/**
|
||||
@ -79,7 +71,7 @@ import javax.management.ReflectionException;
|
||||
* ancestor with ConvertingMethod. But that would mean an extra object
|
||||
* for every Method in every Standard MBean interface.
|
||||
*/
|
||||
public abstract class MBeanIntrospector<M> {
|
||||
abstract class MBeanIntrospector<M> {
|
||||
static final class PerInterfaceMap<M>
|
||||
extends WeakHashMap<Class<?>, WeakReference<PerInterface<M>>> {}
|
||||
|
||||
@ -159,27 +151,7 @@ public abstract class MBeanIntrospector<M> {
|
||||
* may be null.
|
||||
*/
|
||||
abstract MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
|
||||
M getter, M setter) throws IntrospectionException;
|
||||
|
||||
final String getAttributeDescription(
|
||||
String attributeName, String defaultDescription,
|
||||
Method getter, Method setter) throws IntrospectionException {
|
||||
String g = Introspector.descriptionForElement(getter);
|
||||
String s = Introspector.descriptionForElement(setter);
|
||||
if (g == null) {
|
||||
if (s == null)
|
||||
return defaultDescription;
|
||||
else
|
||||
return s;
|
||||
} else if (s == null || g.equals(s)) {
|
||||
return g;
|
||||
} else {
|
||||
throw new IntrospectionException(
|
||||
"Inconsistent @Description on getter and setter for " +
|
||||
"attribute " + attributeName);
|
||||
}
|
||||
}
|
||||
|
||||
M getter, M setter);
|
||||
/**
|
||||
* Construct an MBeanOperationInfo for the given operation based on
|
||||
* the M it was derived from.
|
||||
@ -200,37 +172,11 @@ public abstract class MBeanIntrospector<M> {
|
||||
*/
|
||||
abstract Descriptor getMBeanDescriptor(Class<?> resourceClass);
|
||||
|
||||
/**
|
||||
* Get any additional Descriptor entries for this introspector instance.
|
||||
* If there is a non-default MXBeanMappingFactory, it will appear in
|
||||
* this Descriptor.
|
||||
* @return Additional Descriptor entries, or an empty Descriptor if none.
|
||||
*/
|
||||
Descriptor getSpecificMBeanDescriptor() {
|
||||
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
||||
}
|
||||
|
||||
void checkCompliance(Class<?> mbeanType) throws NotCompliantMBeanException {
|
||||
if (!mbeanType.isInterface() &&
|
||||
!mbeanType.isAnnotationPresent(MBean.class) &&
|
||||
!Introspector.hasMXBeanAnnotation(mbeanType)) {
|
||||
throw new NotCompliantMBeanException("Not an interface and " +
|
||||
"does not have @" + MBean.class.getSimpleName() +
|
||||
" or @" + MXBean.class.getSimpleName() + " annotation: " +
|
||||
mbeanType.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the methods to be analyzed to build the MBean interface.
|
||||
*/
|
||||
List<Method> getMethods(final Class<?> mbeanType) throws Exception {
|
||||
if (mbeanType.isInterface())
|
||||
return Arrays.asList(mbeanType.getMethods());
|
||||
|
||||
final List<Method> methods = newList();
|
||||
getAnnotatedMethods(mbeanType, methods);
|
||||
return methods;
|
||||
return Arrays.asList(mbeanType.getMethods());
|
||||
}
|
||||
|
||||
final PerInterface<M> getPerInterface(Class<?> mbeanInterface)
|
||||
@ -265,14 +211,11 @@ public abstract class MBeanIntrospector<M> {
|
||||
* the MBeanInfo's Descriptor.
|
||||
*/
|
||||
private MBeanInfo makeInterfaceMBeanInfo(Class<?> mbeanInterface,
|
||||
MBeanAnalyzer<M> analyzer) throws IntrospectionException {
|
||||
MBeanAnalyzer<M> analyzer) {
|
||||
final MBeanInfoMaker maker = new MBeanInfoMaker();
|
||||
analyzer.visit(maker);
|
||||
final String defaultDescription =
|
||||
final String description =
|
||||
"Information on the management interface of the MBean";
|
||||
String description = Introspector.descriptionForElement(mbeanInterface);
|
||||
if (description == null)
|
||||
description = defaultDescription;
|
||||
return maker.makeMBeanInfo(mbeanInterface, description);
|
||||
}
|
||||
|
||||
@ -370,11 +313,11 @@ public abstract class MBeanIntrospector<M> {
|
||||
|
||||
/** A visitor that constructs the per-interface MBeanInfo. */
|
||||
private class MBeanInfoMaker
|
||||
implements MBeanAnalyzer.MBeanVisitor<M, IntrospectionException> {
|
||||
implements MBeanAnalyzer.MBeanVisitor<M> {
|
||||
|
||||
public void visitAttribute(String attributeName,
|
||||
M getter,
|
||||
M setter) throws IntrospectionException {
|
||||
M setter) {
|
||||
MBeanAttributeInfo mbai =
|
||||
getMBeanAttributeInfo(attributeName, getter, setter);
|
||||
|
||||
@ -403,7 +346,7 @@ public abstract class MBeanIntrospector<M> {
|
||||
new ImmutableDescriptor(interfaceClassName);
|
||||
final Descriptor mbeanDescriptor = getBasicMBeanDescriptor();
|
||||
final Descriptor annotatedDescriptor =
|
||||
Introspector.descriptorForElement(mbeanInterface, false);
|
||||
Introspector.descriptorForElement(mbeanInterface);
|
||||
final Descriptor descriptor =
|
||||
DescriptorCache.getInstance().union(
|
||||
classNameDescriptor,
|
||||
@ -442,32 +385,20 @@ public abstract class MBeanIntrospector<M> {
|
||||
* Return the MBeanInfo for the given resource, based on the given
|
||||
* per-interface data.
|
||||
*/
|
||||
final MBeanInfo getMBeanInfo(Object resource, PerInterface<M> perInterface)
|
||||
throws NotCompliantMBeanException {
|
||||
final MBeanInfo getMBeanInfo(Object resource, PerInterface<M> perInterface) {
|
||||
MBeanInfo mbi =
|
||||
getClassMBeanInfo(resource.getClass(), perInterface);
|
||||
MBeanNotificationInfo[] notifs;
|
||||
try {
|
||||
notifs = findNotifications(resource);
|
||||
} catch (RuntimeException e) {
|
||||
NotCompliantMBeanException x =
|
||||
new NotCompliantMBeanException(e.getMessage());
|
||||
x.initCause(e);
|
||||
throw x;
|
||||
}
|
||||
Descriptor d = getSpecificMBeanDescriptor();
|
||||
boolean anyNotifs = (notifs != null && notifs.length > 0);
|
||||
if (!anyNotifs && ImmutableDescriptor.EMPTY_DESCRIPTOR.equals(d))
|
||||
MBeanNotificationInfo[] notifs = findNotifications(resource);
|
||||
if (notifs == null || notifs.length == 0)
|
||||
return mbi;
|
||||
else {
|
||||
d = ImmutableDescriptor.union(d, mbi.getDescriptor());
|
||||
return new MBeanInfo(mbi.getClassName(),
|
||||
mbi.getDescription(),
|
||||
mbi.getAttributes(),
|
||||
mbi.getConstructors(),
|
||||
mbi.getOperations(),
|
||||
notifs,
|
||||
d);
|
||||
mbi.getDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
@ -507,145 +438,29 @@ public abstract class MBeanIntrospector<M> {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add to "methods" every public method that has the @ManagedAttribute
|
||||
* or @ManagedOperation annotation, in the given class or any of
|
||||
* its superclasses or superinterfaces.
|
||||
*
|
||||
* We always add superclass or superinterface methods first, so that
|
||||
* the stable sort used by eliminateCovariantMethods will put the
|
||||
* method from the most-derived class last. This means that we will
|
||||
* see the version of the @ManagedAttribute (or ...Operation) annotation
|
||||
* from that method, which might have a different description or whatever.
|
||||
*/
|
||||
public static void getAnnotatedMethods(Class<?> c, List<Method> methods)
|
||||
throws Exception {
|
||||
Class<?> sup = c.getSuperclass();
|
||||
if (sup != null)
|
||||
getAnnotatedMethods(sup, methods);
|
||||
Class<?>[] intfs = c.getInterfaces();
|
||||
for (Class<?> intf : intfs)
|
||||
getAnnotatedMethods(intf, methods);
|
||||
for (Method m : c.getMethods()) {
|
||||
// We are careful not to add m if it is inherited from a parent
|
||||
// class or interface, because duplicate methods lead to nasty
|
||||
// behaviour in eliminateCovariantMethods.
|
||||
if (m.getDeclaringClass() == c &&
|
||||
(m.isAnnotationPresent(ManagedAttribute.class) ||
|
||||
m.isAnnotationPresent(ManagedOperation.class)))
|
||||
methods.add(m);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the array of MBeanNotificationInfo for the given MBean object.
|
||||
* If the object implements NotificationBroadcaster and its
|
||||
* getNotificationInfo() method returns a non-empty array, then that
|
||||
* is the result. Otherwise, if the object has a @NotificationInfo
|
||||
* or @NotificationInfos annotation, then its contents form the result.
|
||||
* Otherwise, the result is null.
|
||||
*/
|
||||
static MBeanNotificationInfo[] findNotifications(Object moi) {
|
||||
if (moi instanceof NotificationBroadcaster) {
|
||||
MBeanNotificationInfo[] mbn =
|
||||
((NotificationBroadcaster) moi).getNotificationInfo();
|
||||
if (mbn != null && mbn.length > 0) {
|
||||
MBeanNotificationInfo[] result =
|
||||
new MBeanNotificationInfo[mbn.length];
|
||||
for (int i = 0; i < mbn.length; i++) {
|
||||
MBeanNotificationInfo ni = mbn[i];
|
||||
if (ni.getClass() != MBeanNotificationInfo.class)
|
||||
ni = (MBeanNotificationInfo) ni.clone();
|
||||
result[i] = ni;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
if (!MBeanInjector.injectsSendNotification(moi))
|
||||
return null;
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return findNotificationsFromAnnotations(moi.getClass());
|
||||
}
|
||||
|
||||
public static MBeanNotificationInfo[] findNotificationsFromAnnotations(
|
||||
Class<?> mbeanClass) {
|
||||
Class<?> c = getAnnotatedNotificationInfoClass(mbeanClass);
|
||||
if (c == null)
|
||||
if (!(moi instanceof NotificationBroadcaster))
|
||||
return null;
|
||||
NotificationInfo ni = c.getAnnotation(NotificationInfo.class);
|
||||
NotificationInfos nis = c.getAnnotation(NotificationInfos.class);
|
||||
List<NotificationInfo> list = newList();
|
||||
if (ni != null)
|
||||
list.add(ni);
|
||||
if (nis != null)
|
||||
list.addAll(Arrays.asList(nis.value()));
|
||||
if (list.isEmpty())
|
||||
MBeanNotificationInfo[] mbn =
|
||||
((NotificationBroadcaster) moi).getNotificationInfo();
|
||||
if (mbn == null)
|
||||
return null;
|
||||
List<MBeanNotificationInfo> mbnis = newList();
|
||||
for (NotificationInfo x : list) {
|
||||
// The Descriptor includes any fields explicitly specified by
|
||||
// x.descriptorFields(), plus any fields from the contained
|
||||
// @Description annotation.
|
||||
Descriptor d = new ImmutableDescriptor(x.descriptorFields());
|
||||
d = ImmutableDescriptor.union(
|
||||
d, Introspector.descriptorForAnnotation(x.description()));
|
||||
MBeanNotificationInfo mbni = new MBeanNotificationInfo(
|
||||
x.types(), x.notificationClass().getName(),
|
||||
x.description().value(), d);
|
||||
mbnis.add(mbni);
|
||||
}
|
||||
return mbnis.toArray(new MBeanNotificationInfo[mbnis.size()]);
|
||||
}
|
||||
|
||||
private static final Map<Class<?>, WeakReference<Class<?>>>
|
||||
annotatedNotificationInfoClasses = newWeakHashMap();
|
||||
|
||||
private static Class<?> getAnnotatedNotificationInfoClass(Class<?> baseClass) {
|
||||
synchronized (annotatedNotificationInfoClasses) {
|
||||
WeakReference<Class<?>> wr =
|
||||
annotatedNotificationInfoClasses.get(baseClass);
|
||||
if (wr != null)
|
||||
return wr.get();
|
||||
Class<?> c = null;
|
||||
if (baseClass.isAnnotationPresent(NotificationInfo.class) ||
|
||||
baseClass.isAnnotationPresent(NotificationInfos.class)) {
|
||||
c = baseClass;
|
||||
} else {
|
||||
Class<?>[] intfs = baseClass.getInterfaces();
|
||||
for (Class<?> intf : intfs) {
|
||||
Class<?> c1 = getAnnotatedNotificationInfoClass(intf);
|
||||
if (c1 != null) {
|
||||
if (c != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Class " + baseClass.getName() + " inherits " +
|
||||
"@NotificationInfo(s) from both " +
|
||||
c.getName() + " and " + c1.getName());
|
||||
}
|
||||
c = c1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Record the result of the search. If no @NotificationInfo(s)
|
||||
// were found, c is null, and we store a WeakReference(null).
|
||||
// This prevents us from having to search again and fail again.
|
||||
annotatedNotificationInfoClasses.put(baseClass,
|
||||
new WeakReference<Class<?>>(c));
|
||||
return c;
|
||||
MBeanNotificationInfo[] result =
|
||||
new MBeanNotificationInfo[mbn.length];
|
||||
for (int i = 0; i < mbn.length; i++) {
|
||||
MBeanNotificationInfo ni = mbn[i];
|
||||
if (ni.getClass() != MBeanNotificationInfo.class)
|
||||
ni = (MBeanNotificationInfo) ni.clone();
|
||||
result[i] = ni;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static MBeanConstructorInfo[] findConstructors(Class<?> c) {
|
||||
Constructor<?>[] cons = c.getConstructors();
|
||||
MBeanConstructorInfo[] mbc = new MBeanConstructorInfo[cons.length];
|
||||
for (int i = 0; i < cons.length; i++) {
|
||||
String descr = "Public constructor of the MBean";
|
||||
Description d = cons[i].getAnnotation(Description.class);
|
||||
if (d != null)
|
||||
descr = d.value();
|
||||
final String descr = "Public constructor of the MBean";
|
||||
mbc[i] = new MBeanConstructorInfo(descr, cons[i]);
|
||||
}
|
||||
return mbc;
|
||||
|
@ -37,7 +37,7 @@ import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import com.sun.jmx.mbeanserver.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* Base class for MBeans. There is one instance of this class for
|
||||
@ -121,8 +121,7 @@ import javax.management.openmbean.MXBeanMappingFactory;
|
||||
public abstract class MBeanSupport<M>
|
||||
implements DynamicMBean2, MBeanRegistration {
|
||||
|
||||
<T> MBeanSupport(T resource, Class<T> mbeanInterfaceType,
|
||||
MXBeanMappingFactory mappingFactory)
|
||||
<T> MBeanSupport(T resource, Class<T> mbeanInterfaceType)
|
||||
throws NotCompliantMBeanException {
|
||||
if (mbeanInterfaceType == null)
|
||||
throw new NotCompliantMBeanException("Null MBean interface");
|
||||
@ -133,14 +132,13 @@ public abstract class MBeanSupport<M>
|
||||
throw new NotCompliantMBeanException(msg);
|
||||
}
|
||||
this.resource = resource;
|
||||
MBeanIntrospector<M> introspector = getMBeanIntrospector(mappingFactory);
|
||||
MBeanIntrospector<M> introspector = getMBeanIntrospector();
|
||||
this.perInterface = introspector.getPerInterface(mbeanInterfaceType);
|
||||
this.mbeanInfo = introspector.getMBeanInfo(resource, perInterface);
|
||||
}
|
||||
|
||||
/** Return the appropriate introspector for this type of MBean. */
|
||||
abstract MBeanIntrospector<M>
|
||||
getMBeanIntrospector(MXBeanMappingFactory mappingFactory);
|
||||
abstract MBeanIntrospector<M> getMBeanIntrospector();
|
||||
|
||||
/**
|
||||
* Return a cookie for this MBean. This cookie will be passed to
|
||||
@ -262,14 +260,10 @@ public abstract class MBeanSupport<M>
|
||||
return resource.getClass().getName();
|
||||
}
|
||||
|
||||
public final Object getWrappedObject() {
|
||||
public final Object getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public final ClassLoader getWrappedClassLoader() {
|
||||
return resource.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
public final Class<?> getMBeanInterface() {
|
||||
return perInterface.getMBeanInterface();
|
||||
}
|
||||
|
@ -28,26 +28,18 @@ package com.sun.jmx.mbeanserver;
|
||||
import com.sun.jmx.mbeanserver.MBeanIntrospector.MBeanInfoMap;
|
||||
import com.sun.jmx.mbeanserver.MBeanIntrospector.PerInterfaceMap;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import javax.management.Description;
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.ImmutableDescriptor;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.JMX;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
import javax.management.ManagedOperation;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
|
||||
import javax.management.openmbean.OpenMBeanOperationInfoSupport;
|
||||
import javax.management.openmbean.OpenMBeanParameterInfo;
|
||||
@ -60,36 +52,10 @@ import javax.management.openmbean.OpenType;
|
||||
* @since 1.6
|
||||
*/
|
||||
class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
/* We keep one MXBeanIntrospector per MXBeanMappingFactory, since the results
|
||||
* of the introspection depend on the factory. The MXBeanIntrospector
|
||||
* has a reference back to the factory, so we wrap it in a WeakReference.
|
||||
* It will be strongly referenced by any MXBeanSupport instances using it;
|
||||
* if there are none then it is OK to gc it.
|
||||
*/
|
||||
private static final
|
||||
Map<MXBeanMappingFactory, WeakReference<MXBeanIntrospector>> map =
|
||||
new WeakHashMap<MXBeanMappingFactory, WeakReference<MXBeanIntrospector>>();
|
||||
private static final MXBeanIntrospector instance = new MXBeanIntrospector();
|
||||
|
||||
static MXBeanIntrospector getInstance(MXBeanMappingFactory factory) {
|
||||
if (factory == null)
|
||||
factory = MXBeanMappingFactory.DEFAULT;
|
||||
synchronized (map) {
|
||||
MXBeanIntrospector intro;
|
||||
WeakReference<MXBeanIntrospector> wr = map.get(factory);
|
||||
if (wr != null) {
|
||||
intro = wr.get();
|
||||
if (intro != null)
|
||||
return intro;
|
||||
}
|
||||
intro = new MXBeanIntrospector(factory);
|
||||
wr = new WeakReference<MXBeanIntrospector>(intro);
|
||||
map.put(factory, wr);
|
||||
return intro;
|
||||
}
|
||||
}
|
||||
|
||||
private MXBeanIntrospector(MXBeanMappingFactory factory) {
|
||||
this.mappingFactory = factory;
|
||||
static MXBeanIntrospector getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -115,7 +81,7 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
|
||||
@Override
|
||||
ConvertingMethod mFrom(Method m) {
|
||||
return ConvertingMethod.from(m, mappingFactory);
|
||||
return ConvertingMethod.from(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -176,17 +142,13 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
|
||||
@Override
|
||||
MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
|
||||
ConvertingMethod getter, ConvertingMethod setter)
|
||||
throws IntrospectionException {
|
||||
ConvertingMethod getter, ConvertingMethod setter) {
|
||||
|
||||
final boolean isReadable = (getter != null);
|
||||
final boolean isWritable = (setter != null);
|
||||
final boolean isIs = isReadable && getName(getter).startsWith("is");
|
||||
|
||||
final String description = getAttributeDescription(
|
||||
attributeName, attributeName,
|
||||
getter == null ? null : getter.getMethod(),
|
||||
setter == null ? null : setter.getMethod());
|
||||
final String description = attributeName;
|
||||
|
||||
final OpenType<?> openType;
|
||||
final Type originalType;
|
||||
@ -235,17 +197,13 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
MBeanOperationInfo getMBeanOperationInfo(String operationName,
|
||||
ConvertingMethod operation) {
|
||||
final Method method = operation.getMethod();
|
||||
String description = operationName;
|
||||
final String description = operationName;
|
||||
/* Ideally this would be an empty string, but
|
||||
OMBOperationInfo constructor forbids that. */
|
||||
Description d = method.getAnnotation(Description.class);
|
||||
if (d != null)
|
||||
description = d.value();
|
||||
OMBOperationInfo constructor forbids that. Also, we
|
||||
could consult an annotation to get a useful
|
||||
description. */
|
||||
|
||||
int impact = MBeanOperationInfo.UNKNOWN;
|
||||
ManagedOperation annot = method.getAnnotation(ManagedOperation.class);
|
||||
if (annot != null)
|
||||
impact = annot.impact().getCode();
|
||||
final int impact = MBeanOperationInfo.UNKNOWN;
|
||||
|
||||
final OpenType<?> returnType = operation.getOpenReturnType();
|
||||
final Type originalReturnType = operation.getGenericReturnType();
|
||||
@ -257,15 +215,8 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
boolean openParameterTypes = true;
|
||||
Annotation[][] annots = method.getParameterAnnotations();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
String paramName = Introspector.nameForParameter(annots[i]);
|
||||
if (paramName == null)
|
||||
paramName = "p" + i;
|
||||
|
||||
String paramDescription =
|
||||
Introspector.descriptionForParameter(annots[i]);
|
||||
if (paramDescription == null)
|
||||
paramDescription = paramName;
|
||||
|
||||
final String paramName = "p" + i;
|
||||
final String paramDescription = paramName;
|
||||
final OpenType<?> openType = paramTypes[i];
|
||||
final Type originalType = originalParamTypes[i];
|
||||
Descriptor descriptor =
|
||||
@ -292,7 +243,7 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
Descriptor descriptor =
|
||||
typeDescriptor(returnType, originalReturnType);
|
||||
descriptor = ImmutableDescriptor.union(descriptor,
|
||||
Introspector.descriptorForElement(method, false));
|
||||
Introspector.descriptorForElement(method));
|
||||
final MBeanOperationInfo oi;
|
||||
if (openReturnType && openParameterTypes) {
|
||||
/* If the return value and all the parameters can be faithfully
|
||||
@ -343,17 +294,6 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
Descriptor getSpecificMBeanDescriptor() {
|
||||
if (mappingFactory == MXBeanMappingFactory.DEFAULT)
|
||||
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
||||
else {
|
||||
return new ImmutableDescriptor(
|
||||
JMX.MXBEAN_MAPPING_FACTORY_CLASS_FIELD + "=" +
|
||||
mappingFactory.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static Descriptor typeDescriptor(OpenType<?> openType,
|
||||
Type originalType) {
|
||||
return new ImmutableDescriptor(
|
||||
@ -421,7 +361,5 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
private final PerInterfaceMap<ConvertingMethod>
|
||||
perInterfaceMap = new PerInterfaceMap<ConvertingMethod>();
|
||||
|
||||
private final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap();
|
||||
|
||||
private final MXBeanMappingFactory mappingFactory;
|
||||
private static final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap();
|
||||
}
|
||||
|
@ -25,8 +25,6 @@
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
import java.io.InvalidObjectException;
|
||||
import static com.sun.jmx.mbeanserver.Util.*;
|
||||
import java.util.Map;
|
||||
import java.lang.ref.WeakReference;
|
||||
@ -85,181 +83,87 @@ import javax.management.openmbean.OpenDataException;
|
||||
*
|
||||
* From the above, it is clear that the logic for getX on an MXBean is
|
||||
* the same as for setX on a proxy, and vice versa.
|
||||
*
|
||||
* The above describes the logic for "plain" MXBeanLookup, represented
|
||||
* by MXBeanLookup.Plain. When namespaces enter the picture, we see
|
||||
* MXBeanLookup.Prefix. Here, the idea is that the name of the ModuleMXBean
|
||||
* might be a//m:m=m. In this case, we don't accept a reference to
|
||||
* an MXBean object, since that would require different namespaces to know
|
||||
* each others' objects. We only accept proxies. Suppose you have a proxy
|
||||
* for a//m:m=m, call it moduleProxy, and you call
|
||||
* moduleProxy.setProduct(productProxy). Then if productProxy is for
|
||||
* a//p:p=p we should convert this to just p:p=p. If productProxy is for
|
||||
* a//b//p:p=p we should convert it to b//p:p=p. Conversely, if getProduct
|
||||
* returns an ObjectName like b//p:p=p then we should convert it into a proxy
|
||||
* for a//b//p:p=p.
|
||||
*/
|
||||
public abstract class MXBeanLookup {
|
||||
public class MXBeanLookup {
|
||||
private MXBeanLookup(MBeanServerConnection mbsc) {
|
||||
this.mbsc = mbsc;
|
||||
}
|
||||
|
||||
static MXBeanLookup lookupFor(MBeanServerConnection mbsc, String prefix) {
|
||||
if (prefix == null)
|
||||
return Plain.lookupFor(mbsc);
|
||||
else
|
||||
return new Prefix(mbsc, prefix);
|
||||
static MXBeanLookup lookupFor(MBeanServerConnection mbsc) {
|
||||
synchronized (mbscToLookup) {
|
||||
WeakReference<MXBeanLookup> weakLookup = mbscToLookup.get(mbsc);
|
||||
MXBeanLookup lookup = (weakLookup == null) ? null : weakLookup.get();
|
||||
if (lookup == null) {
|
||||
lookup = new MXBeanLookup(mbsc);
|
||||
mbscToLookup.put(mbsc, new WeakReference<MXBeanLookup>(lookup));
|
||||
}
|
||||
return lookup;
|
||||
}
|
||||
}
|
||||
|
||||
abstract <T> T objectNameToMXBean(ObjectName name, Class<T> type)
|
||||
throws InvalidObjectException;
|
||||
|
||||
abstract ObjectName mxbeanToObjectName(Object mxbean)
|
||||
throws OpenDataException;
|
||||
|
||||
static class Plain extends MXBeanLookup {
|
||||
Plain(MBeanServerConnection mbsc) {
|
||||
super(mbsc);
|
||||
synchronized <T> T objectNameToMXBean(ObjectName name, Class<T> type) {
|
||||
WeakReference<Object> wr = objectNameToProxy.get(name);
|
||||
if (wr != null) {
|
||||
Object proxy = wr.get();
|
||||
if (type.isInstance(proxy))
|
||||
return type.cast(proxy);
|
||||
}
|
||||
T proxy = JMX.newMXBeanProxy(mbsc, name, type);
|
||||
objectNameToProxy.put(name, new WeakReference<Object>(proxy));
|
||||
return proxy;
|
||||
}
|
||||
|
||||
static Plain lookupFor(MBeanServerConnection mbsc) {
|
||||
synchronized (mbscToLookup) {
|
||||
WeakReference<Plain> weakLookup = mbscToLookup.get(mbsc);
|
||||
Plain lookup = (weakLookup == null) ? null : weakLookup.get();
|
||||
if (lookup == null) {
|
||||
lookup = new Plain(mbsc);
|
||||
mbscToLookup.put(mbsc, new WeakReference<Plain>(lookup));
|
||||
}
|
||||
return lookup;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized <T> T objectNameToMXBean(ObjectName name, Class<T> type) {
|
||||
WeakReference<Object> wr = objectNameToProxy.get(name);
|
||||
if (wr != null) {
|
||||
Object proxy = wr.get();
|
||||
if (type.isInstance(proxy))
|
||||
return type.cast(proxy);
|
||||
}
|
||||
T proxy = JMX.newMXBeanProxy(mbsc, name, type);
|
||||
objectNameToProxy.put(name, new WeakReference<Object>(proxy));
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized ObjectName mxbeanToObjectName(Object mxbean)
|
||||
throws OpenDataException {
|
||||
String wrong;
|
||||
if (mxbean instanceof Proxy) {
|
||||
InvocationHandler ih = Proxy.getInvocationHandler(mxbean);
|
||||
if (ih instanceof MBeanServerInvocationHandler) {
|
||||
MBeanServerInvocationHandler mbsih =
|
||||
(MBeanServerInvocationHandler) ih;
|
||||
if (mbsih.getMBeanServerConnection().equals(mbsc))
|
||||
return mbsih.getObjectName();
|
||||
else
|
||||
wrong = "proxy for a different MBeanServer";
|
||||
} else
|
||||
wrong = "not a JMX proxy";
|
||||
} else {
|
||||
ObjectName name = mxbeanToObjectName.get(mxbean);
|
||||
if (name != null)
|
||||
return name;
|
||||
wrong = "not an MXBean registered in this MBeanServer";
|
||||
}
|
||||
String s = (mxbean == null) ?
|
||||
"null" : "object of type " + mxbean.getClass().getName();
|
||||
throw new OpenDataException(
|
||||
"Could not convert " + s + " to an ObjectName: " + wrong);
|
||||
// Message will be strange if mxbean is null but it is not
|
||||
// supposed to be.
|
||||
}
|
||||
|
||||
synchronized void addReference(ObjectName name, Object mxbean)
|
||||
throws InstanceAlreadyExistsException {
|
||||
ObjectName existing = mxbeanToObjectName.get(mxbean);
|
||||
if (existing != null) {
|
||||
String multiname = AccessController.doPrivileged(
|
||||
new GetPropertyAction("jmx.mxbean.multiname"));
|
||||
if (!"true".equalsIgnoreCase(multiname)) {
|
||||
throw new InstanceAlreadyExistsException(
|
||||
"MXBean already registered with name " + existing);
|
||||
}
|
||||
}
|
||||
mxbeanToObjectName.put(mxbean, name);
|
||||
}
|
||||
|
||||
synchronized boolean removeReference(ObjectName name, Object mxbean) {
|
||||
if (name.equals(mxbeanToObjectName.get(mxbean))) {
|
||||
mxbeanToObjectName.remove(mxbean);
|
||||
return true;
|
||||
synchronized ObjectName mxbeanToObjectName(Object mxbean)
|
||||
throws OpenDataException {
|
||||
String wrong;
|
||||
if (mxbean instanceof Proxy) {
|
||||
InvocationHandler ih = Proxy.getInvocationHandler(mxbean);
|
||||
if (ih instanceof MBeanServerInvocationHandler) {
|
||||
MBeanServerInvocationHandler mbsih =
|
||||
(MBeanServerInvocationHandler) ih;
|
||||
if (mbsih.getMBeanServerConnection().equals(mbsc))
|
||||
return mbsih.getObjectName();
|
||||
else
|
||||
wrong = "proxy for a different MBeanServer";
|
||||
} else
|
||||
return false;
|
||||
/* removeReference can be called when the above condition fails,
|
||||
* notably if you try to register the same MXBean twice.
|
||||
*/
|
||||
wrong = "not a JMX proxy";
|
||||
} else {
|
||||
ObjectName name = mxbeanToObjectName.get(mxbean);
|
||||
if (name != null)
|
||||
return name;
|
||||
wrong = "not an MXBean registered in this MBeanServer";
|
||||
}
|
||||
|
||||
private final WeakIdentityHashMap<Object, ObjectName>
|
||||
mxbeanToObjectName = WeakIdentityHashMap.make();
|
||||
private final Map<ObjectName, WeakReference<Object>>
|
||||
objectNameToProxy = newMap();
|
||||
private static WeakIdentityHashMap<MBeanServerConnection,
|
||||
WeakReference<Plain>>
|
||||
mbscToLookup = WeakIdentityHashMap.make();
|
||||
String s = (mxbean == null) ?
|
||||
"null" : "object of type " + mxbean.getClass().getName();
|
||||
throw new OpenDataException(
|
||||
"Could not convert " + s + " to an ObjectName: " + wrong);
|
||||
// Message will be strange if mxbean is null but it is not
|
||||
// supposed to be.
|
||||
}
|
||||
|
||||
private static class Prefix extends MXBeanLookup {
|
||||
private final String prefix;
|
||||
|
||||
Prefix(MBeanServerConnection mbsc, String prefix) {
|
||||
super(mbsc);
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
<T> T objectNameToMXBean(ObjectName name, Class<T> type)
|
||||
throws InvalidObjectException {
|
||||
String domain = prefix + name.getDomain();
|
||||
try {
|
||||
name = name.withDomain(domain);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw EnvHelp.initCause(
|
||||
new InvalidObjectException(e.getMessage()), e);
|
||||
synchronized void addReference(ObjectName name, Object mxbean)
|
||||
throws InstanceAlreadyExistsException {
|
||||
ObjectName existing = mxbeanToObjectName.get(mxbean);
|
||||
if (existing != null) {
|
||||
String multiname = AccessController.doPrivileged(
|
||||
new GetPropertyAction("jmx.mxbean.multiname"));
|
||||
if (!"true".equalsIgnoreCase(multiname)) {
|
||||
throw new InstanceAlreadyExistsException(
|
||||
"MXBean already registered with name " + existing);
|
||||
}
|
||||
return JMX.newMXBeanProxy(mbsc, name, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
ObjectName mxbeanToObjectName(Object mxbean)
|
||||
throws OpenDataException {
|
||||
ObjectName name = proxyToObjectName(mxbean);
|
||||
String domain = name.getDomain();
|
||||
if (!domain.startsWith(prefix)) {
|
||||
throw new OpenDataException(
|
||||
"Proxy's name does not start with " +
|
||||
prefix + ": " + name);
|
||||
}
|
||||
try {
|
||||
name = name.withDomain(domain.substring(prefix.length()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw EnvHelp.initCause(
|
||||
new OpenDataException(e.getMessage()), e);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
mxbeanToObjectName.put(mxbean, name);
|
||||
}
|
||||
|
||||
ObjectName proxyToObjectName(Object proxy) {
|
||||
InvocationHandler ih = Proxy.getInvocationHandler(proxy);
|
||||
if (ih instanceof MBeanServerInvocationHandler) {
|
||||
MBeanServerInvocationHandler mbsih =
|
||||
(MBeanServerInvocationHandler) ih;
|
||||
if (mbsih.getMBeanServerConnection().equals(mbsc))
|
||||
return mbsih.getObjectName();
|
||||
}
|
||||
return null;
|
||||
synchronized boolean removeReference(ObjectName name, Object mxbean) {
|
||||
if (name.equals(mxbeanToObjectName.get(mxbean))) {
|
||||
mxbeanToObjectName.remove(mxbean);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
/* removeReference can be called when the above condition fails,
|
||||
* notably if you try to register the same MXBean twice.
|
||||
*/
|
||||
}
|
||||
|
||||
static MXBeanLookup getLookup() {
|
||||
@ -273,5 +177,12 @@ public abstract class MXBeanLookup {
|
||||
private static final ThreadLocal<MXBeanLookup> currentLookup =
|
||||
new ThreadLocal<MXBeanLookup>();
|
||||
|
||||
final MBeanServerConnection mbsc;
|
||||
private final MBeanServerConnection mbsc;
|
||||
private final WeakIdentityHashMap<Object, ObjectName>
|
||||
mxbeanToObjectName = WeakIdentityHashMap.make();
|
||||
private final Map<ObjectName, WeakReference<Object>>
|
||||
objectNameToProxy = newMap();
|
||||
private static final WeakIdentityHashMap<MBeanServerConnection,
|
||||
WeakReference<MXBeanLookup>>
|
||||
mbscToLookup = WeakIdentityHashMap.make();
|
||||
}
|
||||
|
@ -23,10 +23,12 @@
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management.openmbean;
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.lang.reflect.Type;
|
||||
import javax.management.openmbean.OpenDataException;
|
||||
import javax.management.openmbean.OpenType;
|
||||
|
||||
/**
|
||||
* <p>A custom mapping between Java types and Open types for use in MXBeans.
|
||||
@ -166,12 +168,10 @@ public abstract class MXBeanMapping {
|
||||
if (javaType instanceof Class<?> && ((Class<?>) javaType).isPrimitive())
|
||||
return (Class<?>) javaType;
|
||||
try {
|
||||
String className = OpenType.validClassName(openType.getClassName());
|
||||
String className = openType.getClassName();
|
||||
return Class.forName(className, false, null);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e); // should not happen
|
||||
} catch (OpenDataException e) {
|
||||
throw new IllegalArgumentException("Bad OpenType: " + openType, e);
|
||||
}
|
||||
}
|
||||
|
@ -23,8 +23,10 @@
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management.openmbean;
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import javax.management.openmbean.*;
|
||||
import com.sun.jmx.mbeanserver.MXBeanMapping;
|
||||
import com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
@ -100,49 +102,6 @@ public abstract class MXBeanMappingFactory {
|
||||
public static final MXBeanMappingFactory DEFAULT =
|
||||
new DefaultMXBeanMappingFactory();
|
||||
|
||||
/**
|
||||
* <p>Determine the appropriate MXBeanMappingFactory to use for the given
|
||||
* MXBean interface, based on its annotations. If the interface has an
|
||||
* {@link MXBeanMappingFactoryClass @MXBeanMappingFactoryClass} annotation,
|
||||
* that is used to determine the MXBeanMappingFactory. Otherwise, if the
|
||||
* package containing the interface has such an annotation, that is used.
|
||||
* Otherwise the MXBeanMappingFactory is the {@linkplain #DEFAULT default}
|
||||
* one.</p>
|
||||
*
|
||||
* @param intf the MXBean interface for which to determine the
|
||||
* MXBeanMappingFactory.
|
||||
*
|
||||
* @return the MXBeanMappingFactory for the given MXBean interface.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code intf} is null, or if an
|
||||
* exception occurs while trying constructing an MXBeanMappingFactory
|
||||
* based on an annotation. In the second case, the exception will appear
|
||||
* in the {@linkplain Throwable#getCause() cause chain} of the
|
||||
* {@code IllegalArgumentException}.
|
||||
*/
|
||||
public static MXBeanMappingFactory forInterface(Class<?> intf) {
|
||||
if (intf == null)
|
||||
throw new IllegalArgumentException("Null interface");
|
||||
MXBeanMappingFactoryClass annot =
|
||||
intf.getAnnotation(MXBeanMappingFactoryClass.class);
|
||||
if (annot == null) {
|
||||
Package p = intf.getPackage();
|
||||
if (p != null)
|
||||
annot = p.getAnnotation(MXBeanMappingFactoryClass.class);
|
||||
}
|
||||
if (annot == null)
|
||||
return MXBeanMappingFactory.DEFAULT;
|
||||
Class<? extends MXBeanMappingFactory> factoryClass = annot.value();
|
||||
try {
|
||||
return annot.value().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not instantiate MXBeanMappingFactory " +
|
||||
factoryClass.getName() +
|
||||
" from @MXBeanMappingFactoryClass", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the mapping for the given Java type. Typically, a
|
||||
* mapping factory will return mappings for types it handles, and
|
@ -32,10 +32,8 @@ import java.util.Map;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
<p>Helper class for an {@link InvocationHandler} that forwards methods from an
|
||||
@ -47,7 +45,7 @@ import javax.management.openmbean.MXBeanMappingFactory;
|
||||
@since 1.6
|
||||
*/
|
||||
public class MXBeanProxy {
|
||||
public MXBeanProxy(Class<?> mxbeanInterface, MXBeanMappingFactory factory) {
|
||||
public MXBeanProxy(Class<?> mxbeanInterface) {
|
||||
|
||||
if (mxbeanInterface == null)
|
||||
throw new IllegalArgumentException("Null parameter");
|
||||
@ -55,7 +53,7 @@ public class MXBeanProxy {
|
||||
final MBeanAnalyzer<ConvertingMethod> analyzer;
|
||||
try {
|
||||
analyzer =
|
||||
MXBeanIntrospector.getInstance(factory).getAnalyzer(mxbeanInterface);
|
||||
MXBeanIntrospector.getInstance().getAnalyzer(mxbeanInterface);
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
@ -63,7 +61,7 @@ public class MXBeanProxy {
|
||||
}
|
||||
|
||||
private class Visitor
|
||||
implements MBeanAnalyzer.MBeanVisitor<ConvertingMethod, RuntimeException> {
|
||||
implements MBeanAnalyzer.MBeanVisitor<ConvertingMethod> {
|
||||
public void visitAttribute(String attributeName,
|
||||
ConvertingMethod getter,
|
||||
ConvertingMethod setter) {
|
||||
@ -161,8 +159,7 @@ public class MXBeanProxy {
|
||||
|
||||
Handler handler = handlerMap.get(method);
|
||||
ConvertingMethod cm = handler.getConvertingMethod();
|
||||
String prefix = extractPrefix(name);
|
||||
MXBeanLookup lookup = MXBeanLookup.lookupFor(mbsc, prefix);
|
||||
MXBeanLookup lookup = MXBeanLookup.lookupFor(mbsc);
|
||||
MXBeanLookup oldLookup = MXBeanLookup.getLookup();
|
||||
try {
|
||||
MXBeanLookup.setLookup(lookup);
|
||||
@ -174,17 +171,5 @@ public class MXBeanProxy {
|
||||
}
|
||||
}
|
||||
|
||||
private static String extractPrefix(ObjectName name)
|
||||
throws MalformedObjectNameException {
|
||||
String domain = name.getDomain();
|
||||
int slashslash = domain.lastIndexOf("//");
|
||||
if (slashslash > 0 && domain.charAt(slashslash - 1) == '/')
|
||||
slashslash--;
|
||||
if (slashslash >= 0)
|
||||
return domain.substring(0, slashslash + 2);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
private final Map<Method, Handler> handlerMap = newMap();
|
||||
}
|
||||
|
@ -35,7 +35,6 @@ import javax.management.JMX;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* Base class for MXBeans.
|
||||
@ -62,16 +61,14 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
||||
if it does not implement the class {@code mxbeanInterface} or if
|
||||
that class is not a valid MXBean interface.
|
||||
*/
|
||||
public <T> MXBeanSupport(T resource, Class<T> mxbeanInterface,
|
||||
MXBeanMappingFactory mappingFactory)
|
||||
public <T> MXBeanSupport(T resource, Class<T> mxbeanInterface)
|
||||
throws NotCompliantMBeanException {
|
||||
super(resource, mxbeanInterface, mappingFactory);
|
||||
super(resource, mxbeanInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
MBeanIntrospector<ConvertingMethod>
|
||||
getMBeanIntrospector(MXBeanMappingFactory mappingFactory) {
|
||||
return MXBeanIntrospector.getInstance(mappingFactory);
|
||||
MBeanIntrospector<ConvertingMethod> getMBeanIntrospector() {
|
||||
return MXBeanIntrospector.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -159,8 +156,8 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
||||
// eventually we could have some logic to supply a default name
|
||||
|
||||
synchronized (lock) {
|
||||
this.mxbeanLookup = MXBeanLookup.Plain.lookupFor(server);
|
||||
this.mxbeanLookup.addReference(name, getWrappedObject());
|
||||
this.mxbeanLookup = MXBeanLookup.lookupFor(server);
|
||||
this.mxbeanLookup.addReference(name, getResource());
|
||||
this.objectName = name;
|
||||
}
|
||||
}
|
||||
@ -169,19 +166,13 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
||||
public void unregister() {
|
||||
synchronized (lock) {
|
||||
if (mxbeanLookup != null) {
|
||||
if (mxbeanLookup.removeReference(objectName, getWrappedObject()))
|
||||
if (mxbeanLookup.removeReference(objectName, getResource()))
|
||||
objectName = null;
|
||||
}
|
||||
// XXX: need to revisit the whole register/unregister logic in
|
||||
// the face of wrapping. The mxbeanLookup!=null test is a hack.
|
||||
// If you wrap an MXBean in a MyWrapperMBean and register it,
|
||||
// the lookup table should contain the wrapped object. But that
|
||||
// implies that MyWrapperMBean calls register, which today it
|
||||
// can't within the public API.
|
||||
}
|
||||
}
|
||||
private final Object lock = new Object(); // for mxbeanLookup and objectName
|
||||
|
||||
private MXBeanLookup.Plain mxbeanLookup;
|
||||
private MXBeanLookup mxbeanLookup;
|
||||
private ObjectName objectName;
|
||||
}
|
||||
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.Notification;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* <p>A variant of {@code StandardMBeanSupport} where the only
|
||||
* methods included are public getters. This is used by
|
||||
* {@code QueryNotificationFilter} to pretend that a Notification is
|
||||
* an MBean so it can have a query evaluated on it. Standard queries
|
||||
* never set attributes or invoke methods but custom queries could and
|
||||
* we don't want to allow that. Also we don't want to fail if a
|
||||
* Notification happens to have inconsistent types in a pair of getX and
|
||||
* setX methods, and we want to include the Object.getClass() method.
|
||||
*/
|
||||
public class NotificationMBeanSupport extends StandardMBeanSupport {
|
||||
public <T extends Notification> NotificationMBeanSupport(T n)
|
||||
throws NotCompliantMBeanException {
|
||||
super(n, Util.<Class<T>>cast(n.getClass()));
|
||||
}
|
||||
|
||||
@Override
|
||||
MBeanIntrospector<Method> getMBeanIntrospector(MXBeanMappingFactory ignored) {
|
||||
return introspector;
|
||||
}
|
||||
|
||||
private static class Introspector extends StandardMBeanIntrospector {
|
||||
@Override
|
||||
void checkCompliance(Class<?> mbeanType) {}
|
||||
|
||||
@Override
|
||||
List<Method> getMethods(final Class<?> mbeanType)
|
||||
throws Exception {
|
||||
List<Method> methods = new ArrayList<Method>();
|
||||
for (Method m : mbeanType.getMethods()) {
|
||||
String name = m.getName();
|
||||
Class<?> ret = m.getReturnType();
|
||||
if (m.getParameterTypes().length == 0) {
|
||||
if ((name.startsWith("is") && name.length() > 2 &&
|
||||
ret == boolean.class) ||
|
||||
(name.startsWith("get") && name.length() > 3 &&
|
||||
ret != void.class)) {
|
||||
methods.add(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
||||
}
|
||||
private static final MBeanIntrospector<Method> introspector =
|
||||
new Introspector();
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.DynamicWrapperMBean;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanRegistration;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotificationBroadcasterSupport;
|
||||
import javax.management.NotificationEmitter;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ReflectionException;
|
||||
|
||||
/**
|
||||
* Create wrappers for DynamicMBean that implement NotificationEmitter
|
||||
* and SendNotification.
|
||||
*/
|
||||
public class NotifySupport
|
||||
implements DynamicMBean2, NotificationEmitter, MBeanRegistration {
|
||||
|
||||
private final DynamicMBean mbean;
|
||||
private final NotificationBroadcasterSupport nbs;
|
||||
|
||||
public static DynamicMBean wrap(
|
||||
DynamicMBean mbean, NotificationBroadcasterSupport nbs) {
|
||||
return new NotifySupport(mbean, nbs);
|
||||
}
|
||||
|
||||
private NotifySupport(DynamicMBean mbean, NotificationBroadcasterSupport nbs) {
|
||||
this.mbean = mbean;
|
||||
this.nbs = nbs;
|
||||
}
|
||||
|
||||
public static NotificationBroadcasterSupport getNB(DynamicMBean mbean) {
|
||||
if (mbean instanceof NotifySupport)
|
||||
return ((NotifySupport) mbean).nbs;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
if (mbean instanceof DynamicMBean2)
|
||||
return ((DynamicMBean2) mbean).getClassName();
|
||||
Object w = mbean;
|
||||
if (w instanceof DynamicWrapperMBean)
|
||||
w = ((DynamicWrapperMBean) w).getWrappedObject();
|
||||
return w.getClass().getName();
|
||||
}
|
||||
|
||||
public void preRegister2(MBeanServer mbs, ObjectName name) throws Exception {
|
||||
if (mbean instanceof DynamicMBean2)
|
||||
((DynamicMBean2) mbean).preRegister2(mbs, name);
|
||||
}
|
||||
|
||||
public void registerFailed() {
|
||||
if (mbean instanceof DynamicMBean2)
|
||||
((DynamicMBean2) mbean).registerFailed();
|
||||
}
|
||||
|
||||
public Object getWrappedObject() {
|
||||
if (mbean instanceof DynamicWrapperMBean)
|
||||
return ((DynamicWrapperMBean) mbean).getWrappedObject();
|
||||
else
|
||||
return mbean;
|
||||
}
|
||||
|
||||
public ClassLoader getWrappedClassLoader() {
|
||||
if (mbean instanceof DynamicWrapperMBean)
|
||||
return ((DynamicWrapperMBean) mbean).getWrappedClassLoader();
|
||||
else
|
||||
return mbean.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
public Object getAttribute(String attribute) throws AttributeNotFoundException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
return mbean.getAttribute(attribute);
|
||||
}
|
||||
|
||||
public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
|
||||
InvalidAttributeValueException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
mbean.setAttribute(attribute);
|
||||
}
|
||||
|
||||
public AttributeList setAttributes(AttributeList attributes) {
|
||||
return mbean.setAttributes(attributes);
|
||||
}
|
||||
|
||||
public Object invoke(String actionName, Object[] params, String[] signature)
|
||||
throws MBeanException, ReflectionException {
|
||||
return mbean.invoke(actionName, params, signature);
|
||||
}
|
||||
|
||||
public MBeanInfo getMBeanInfo() {
|
||||
return mbean.getMBeanInfo();
|
||||
}
|
||||
|
||||
public AttributeList getAttributes(String[] attributes) {
|
||||
return mbean.getAttributes(attributes);
|
||||
}
|
||||
|
||||
public void removeNotificationListener(NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback) throws ListenerNotFoundException {
|
||||
nbs.removeNotificationListener(listener, filter, handback);
|
||||
}
|
||||
|
||||
public void removeNotificationListener(NotificationListener listener)
|
||||
throws ListenerNotFoundException {
|
||||
nbs.removeNotificationListener(listener);
|
||||
}
|
||||
|
||||
public MBeanNotificationInfo[] getNotificationInfo() {
|
||||
return nbs.getNotificationInfo();
|
||||
}
|
||||
|
||||
public void addNotificationListener(NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback) {
|
||||
nbs.addNotificationListener(listener, filter, handback);
|
||||
}
|
||||
|
||||
public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
|
||||
if (mbr() != null)
|
||||
return mbr().preRegister(server, name);
|
||||
else
|
||||
return name;
|
||||
}
|
||||
|
||||
public void postRegister(Boolean registrationDone) {
|
||||
if (mbr() != null)
|
||||
mbr().postRegister(registrationDone);
|
||||
}
|
||||
|
||||
public void preDeregister() throws Exception {
|
||||
if (mbr() != null)
|
||||
mbr().preDeregister();
|
||||
}
|
||||
|
||||
public void postDeregister() {
|
||||
if (mbr() != null)
|
||||
mbr().postDeregister();
|
||||
}
|
||||
|
||||
private MBeanRegistration mbr() {
|
||||
if (mbean instanceof MBeanRegistration)
|
||||
return (MBeanRegistration) mbean;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -231,7 +231,7 @@ final class PerInterface<M> {
|
||||
/**
|
||||
* Visitor that sets up the method maps (operations, getters, setters).
|
||||
*/
|
||||
private class InitMaps implements MBeanAnalyzer.MBeanVisitor<M, RuntimeException> {
|
||||
private class InitMaps implements MBeanAnalyzer.MBeanVisitor<M> {
|
||||
public void visitAttribute(String attributeName,
|
||||
M getter,
|
||||
M setter) {
|
||||
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* <p>A factory for ThreadPoolExecutor objects that allows the same object to
|
||||
* be shared by all users of the factory that are in the same ThreadGroup.</p>
|
||||
*/
|
||||
// We return a ThreadPoolExecutor rather than the more general ExecutorService
|
||||
// because we need to be able to call allowCoreThreadTimeout so that threads in
|
||||
// the pool will eventually be destroyed when the pool is no longer in use.
|
||||
// Otherwise these threads would keep the ThreadGroup alive forever.
|
||||
public class PerThreadGroupPool<T extends ThreadPoolExecutor> {
|
||||
private final WeakIdentityHashMap<ThreadGroup, WeakReference<T>> map =
|
||||
WeakIdentityHashMap.make();
|
||||
|
||||
public static interface Create<T extends ThreadPoolExecutor> {
|
||||
public T createThreadPool(ThreadGroup group);
|
||||
}
|
||||
|
||||
private PerThreadGroupPool() {}
|
||||
|
||||
public static <T extends ThreadPoolExecutor> PerThreadGroupPool<T> make() {
|
||||
return new PerThreadGroupPool<T>();
|
||||
}
|
||||
|
||||
public synchronized T getThreadPoolExecutor(Create<T> create) {
|
||||
// Find out if there's already an existing executor for the calling
|
||||
// thread and reuse it. Otherwise, create a new one and store it in
|
||||
// the executors map. If there is a SecurityManager, the group of
|
||||
// System.getSecurityManager() is used, else the group of the calling
|
||||
// thread.
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
ThreadGroup group = (s != null) ? s.getThreadGroup() :
|
||||
Thread.currentThread().getThreadGroup();
|
||||
WeakReference<T> wr = map.get(group);
|
||||
T executor = (wr == null) ? null : wr.get();
|
||||
if (executor == null) {
|
||||
executor = create.createThreadPool(group);
|
||||
executor.allowCoreThreadTimeOut(true);
|
||||
map.put(group, new WeakReference<T>(executor));
|
||||
}
|
||||
return executor;
|
||||
}
|
||||
}
|
@ -396,7 +396,7 @@ public class Repository {
|
||||
|
||||
// Set domain to default if domain is empty and not already set
|
||||
if (dom.length() == 0)
|
||||
name = ObjectName.valueOf(domain + name.toString());
|
||||
name = Util.newObjectName(domain + name.toString());
|
||||
|
||||
// Do we have default domain ?
|
||||
if (dom == domain) { // ES: OK (dom & domain are interned)
|
||||
@ -573,7 +573,7 @@ public class Repository {
|
||||
// Pattern matching in the domain name (*, ?)
|
||||
final String dom2Match = name.getDomain();
|
||||
for (String dom : domainTb.keySet()) {
|
||||
if (Util.wildpathmatch(dom, dom2Match)) {
|
||||
if (Util.wildmatch(dom, dom2Match)) {
|
||||
final Map<String,NamedObject> moiTb = domainTb.get(dom);
|
||||
if (allNames)
|
||||
result.addAll(moiTb.values());
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2005 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -35,7 +35,6 @@ import javax.management.IntrospectionException;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.ManagedOperation;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationBroadcaster;
|
||||
import javax.management.NotificationBroadcasterSupport;
|
||||
@ -119,32 +118,22 @@ class StandardMBeanIntrospector extends MBeanIntrospector<Method> {
|
||||
|
||||
@Override
|
||||
MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
|
||||
Method getter, Method setter) throws IntrospectionException {
|
||||
Method getter, Method setter) {
|
||||
|
||||
String description = getAttributeDescription(
|
||||
attributeName, "Attribute exposed for management",
|
||||
getter, setter);
|
||||
return new MBeanAttributeInfo(attributeName, description,
|
||||
getter, setter);
|
||||
final String description = "Attribute exposed for management";
|
||||
try {
|
||||
return new MBeanAttributeInfo(attributeName, description,
|
||||
getter, setter);
|
||||
} catch (IntrospectionException e) {
|
||||
throw new RuntimeException(e); // should not happen
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
MBeanOperationInfo getMBeanOperationInfo(String operationName,
|
||||
Method operation) {
|
||||
final String defaultDescription = "Operation exposed for management";
|
||||
String description = Introspector.descriptionForElement(operation);
|
||||
if (description == null)
|
||||
description = defaultDescription;
|
||||
|
||||
int impact = MBeanOperationInfo.UNKNOWN;
|
||||
ManagedOperation annot = operation.getAnnotation(ManagedOperation.class);
|
||||
if (annot != null)
|
||||
impact = annot.impact().getCode();
|
||||
|
||||
MBeanOperationInfo mboi = new MBeanOperationInfo(description, operation);
|
||||
return new MBeanOperationInfo(
|
||||
mboi.getName(), mboi.getDescription(), mboi.getSignature(),
|
||||
mboi.getReturnType(), impact, mboi.getDescriptor());
|
||||
final String description = "Operation exposed for management";
|
||||
return new MBeanOperationInfo(description, operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -31,7 +31,6 @@ import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* Base class for Standard MBeans.
|
||||
@ -58,11 +57,11 @@ public class StandardMBeanSupport extends MBeanSupport<Method> {
|
||||
*/
|
||||
public <T> StandardMBeanSupport(T resource, Class<T> mbeanInterfaceType)
|
||||
throws NotCompliantMBeanException {
|
||||
super(resource, mbeanInterfaceType, (MXBeanMappingFactory) null);
|
||||
super(resource, mbeanInterfaceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
MBeanIntrospector<Method> getMBeanIntrospector(MXBeanMappingFactory ignored) {
|
||||
MBeanIntrospector<Method> getMBeanIntrospector() {
|
||||
return StandardMBeanIntrospector.getInstance();
|
||||
}
|
||||
|
||||
@ -84,14 +83,13 @@ public class StandardMBeanSupport extends MBeanSupport<Method> {
|
||||
@Override
|
||||
public MBeanInfo getMBeanInfo() {
|
||||
MBeanInfo mbi = super.getMBeanInfo();
|
||||
Class<?> resourceClass = getWrappedObject().getClass();
|
||||
if (!getMBeanInterface().isInterface() ||
|
||||
StandardMBeanIntrospector.isDefinitelyImmutableInfo(resourceClass))
|
||||
Class<?> resourceClass = getResource().getClass();
|
||||
if (StandardMBeanIntrospector.isDefinitelyImmutableInfo(resourceClass))
|
||||
return mbi;
|
||||
return new MBeanInfo(mbi.getClassName(), mbi.getDescription(),
|
||||
mbi.getAttributes(), mbi.getConstructors(),
|
||||
mbi.getOperations(),
|
||||
MBeanIntrospector.findNotifications(getWrappedObject()),
|
||||
MBeanIntrospector.findNotifications(getResource()),
|
||||
mbi.getDescriptor());
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,6 @@
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -40,25 +38,18 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.logging.Level;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerDelegate;
|
||||
import javax.management.MBeanServerFactory;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.loading.ClassLoaderRepository;
|
||||
import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
|
||||
|
||||
public class Util {
|
||||
private final static int NAMESPACE_SEPARATOR_LENGTH =
|
||||
NAMESPACE_SEPARATOR.length();
|
||||
public final static char[] ILLEGAL_MBEANSERVER_NAME_CHARS=";:*?".
|
||||
toCharArray();
|
||||
|
||||
public static ObjectName newObjectName(String string) {
|
||||
try {
|
||||
return new ObjectName(string);
|
||||
} catch (MalformedObjectNameException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static <K, V> Map<K, V> newMap() {
|
||||
return new HashMap<K, V>();
|
||||
@ -89,10 +80,6 @@ public class Util {
|
||||
return new LinkedHashMap<K, V>();
|
||||
}
|
||||
|
||||
static <K, V> WeakHashMap<K, V> newWeakHashMap() {
|
||||
return new WeakHashMap<K, V>();
|
||||
}
|
||||
|
||||
static <E> Set<E> newSet() {
|
||||
return new HashSet<E>();
|
||||
}
|
||||
@ -251,451 +238,4 @@ public class Util {
|
||||
public static boolean wildmatch(String str, String pat) {
|
||||
return wildmatch(str,pat,0,str.length(),0,pat.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a string against a pattern, as a name space path.
|
||||
* This is a special matching where * and ?? don't match //.
|
||||
* The string is split in sub-strings separated by //, and the
|
||||
* pattern is split in sub-patterns separated by //. Each sub-string
|
||||
* is matched against its corresponding sub-pattern.
|
||||
* so <elt-1>//<elt2>//...//<elt-n> matches <pat-1>//<pat-2>//...//<pat-q>
|
||||
* only if n==q and for ( i = 1 => n) elt-i matches pat-i.
|
||||
*
|
||||
* In addition, if we encounter a pattern element which is exactly
|
||||
* **, it can match any number of path-elements - but it must match at
|
||||
* least one element.
|
||||
* When we encounter such a meta-wildcard, we remember its position
|
||||
* and the position in the string path, and we advance both the pattern
|
||||
* and the string. Later, if we encounter a mismatch in pattern & string,
|
||||
* we rewind the position in pattern to just after the meta-wildcard,
|
||||
* and we backtrack the string to i+1 element after the position
|
||||
* we had when we first encountered the meta-wildcard, i being the
|
||||
* position when we last backtracked the string.
|
||||
*
|
||||
* The backtracking logic is an adaptation of the logic in wildmatch
|
||||
* above.
|
||||
* See test/javax/mangement/ObjectName/ApplyWildcardTest.java
|
||||
*
|
||||
* Note: this thing is called 'wild' - and that's for a reason ;-)
|
||||
**/
|
||||
public static boolean wildpathmatch(String str, String pat) {
|
||||
final int strlen = str.length();
|
||||
final int patlen = pat.length();
|
||||
int stri = 0;
|
||||
int pati = 0;
|
||||
|
||||
int starstri; // index for backtrack if "**" attempt fails
|
||||
int starpati; // index for backtrack if "**" attempt fails
|
||||
|
||||
starstri = starpati = -1;
|
||||
|
||||
while (true) {
|
||||
// System.out.println("pati="+pati+", stri="+stri);
|
||||
final int strend = str.indexOf(NAMESPACE_SEPARATOR, stri);
|
||||
final int patend = pat.indexOf(NAMESPACE_SEPARATOR, pati);
|
||||
|
||||
// no // remaining in either string or pattern: simple wildmatch
|
||||
// until end of string.
|
||||
if (strend == -1 && patend == -1) {
|
||||
// System.out.println("last sub pattern, last sub element...");
|
||||
// System.out.println("wildmatch("+str.substring(stri,strlen)+
|
||||
// ","+pat.substring(pati,patlen)+")");
|
||||
return wildmatch(str,pat,stri,strlen,pati,patlen);
|
||||
}
|
||||
|
||||
// no // remaining in string, but at least one remaining in
|
||||
// pattern
|
||||
// => no match
|
||||
if (strend == -1) {
|
||||
// System.out.println("pattern has more // than string...");
|
||||
return false;
|
||||
}
|
||||
|
||||
// strend is != -1, but patend might.
|
||||
// detect wildcard **
|
||||
if (patend == pati+2 && pat.charAt(pati)=='*' &&
|
||||
pat.charAt(pati+1)=='*') {
|
||||
// if we reach here we know that neither strend nor patend are
|
||||
// equals to -1.
|
||||
stri = strend + NAMESPACE_SEPARATOR_LENGTH;
|
||||
pati = patend + NAMESPACE_SEPARATOR_LENGTH;
|
||||
starpati = pati; // position just after **// in pattern
|
||||
starstri = stri; // we eat 1 element in string, and remember
|
||||
// the position for backtracking and eating
|
||||
// one more element if needed.
|
||||
// System.out.println("starpati="+pati);
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is a bit hacky: * can match // when // is at the end
|
||||
// of the string, so we include the // delimiter in the pattern
|
||||
// matching. Either we're in the middle of the path, so including
|
||||
// // both at the end of the pattern and at the end of the string
|
||||
// has no effect - match(*//,dfsd//) is equivalent to match(*,dfsd)
|
||||
// or we're at the end of the pattern path, in which case
|
||||
// including // at the end of the string will have the desired
|
||||
// effect (provided that we detect the end of matching correctly,
|
||||
// see further on).
|
||||
//
|
||||
final int endpat =
|
||||
((patend > -1)?patend+NAMESPACE_SEPARATOR_LENGTH:patlen);
|
||||
final int endstr =
|
||||
((strend > -1)?strend+NAMESPACE_SEPARATOR_LENGTH:strlen);
|
||||
|
||||
// if we reach the end of the pattern, or if elt-i & pat-i
|
||||
// don't match, we have a mismatch.
|
||||
|
||||
// Note: we know that strend != -1, therefore patend==-1
|
||||
// indicates a mismatch unless pattern can match
|
||||
// a // at the end, and strend+2=strlen.
|
||||
// System.out.println("wildmatch("+str.substring(stri,endstr)+","+
|
||||
// pat.substring(pati,endpat)+")");
|
||||
if (!wildmatch(str,pat,stri,endstr,pati,endpat)) {
|
||||
|
||||
// System.out.println("nomatch");
|
||||
// if we have a mismatch and didn't encounter any meta-wildcard,
|
||||
// we return false. String & pattern don't match.
|
||||
if (starpati < 0) return false;
|
||||
|
||||
// If we reach here, we had a meta-wildcard.
|
||||
// We need to backtrack to the wildcard, and make it eat an
|
||||
// additional string element.
|
||||
//
|
||||
stri = str.indexOf(NAMESPACE_SEPARATOR, starstri);
|
||||
// System.out.println("eating one additional element? "+stri);
|
||||
|
||||
// If there's no more elements to eat, string and pattern
|
||||
// don't match => return false.
|
||||
if (stri == -1) return false;
|
||||
|
||||
// Backtrack to where we were when we last matched against
|
||||
// the meta-wildcard, make it eat an additional path element,
|
||||
// remember the new positions, and continue from there...
|
||||
//
|
||||
stri = stri + NAMESPACE_SEPARATOR_LENGTH;
|
||||
starstri = stri;
|
||||
pati = starpati;
|
||||
// System.out.println("skiping to stri="+stri);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Here we know that strend > -1 but we can have patend == -1.
|
||||
//
|
||||
// So if we reach here, we know pat-i+//? has matched
|
||||
// elt-i+//
|
||||
//
|
||||
// If patend==-1, we know that there was no delimiter
|
||||
// at the end of the pattern, that we are at the last pattern,
|
||||
// and therefore that pat-i has matched elt-i+//
|
||||
//
|
||||
// In that case we can consider that we have a match only if
|
||||
// elt-i is also the last path element in the string, which is
|
||||
// equivalent to saying that strend+2==strlen.
|
||||
//
|
||||
if (patend == -1 && starpati == -1)
|
||||
return (strend+NAMESPACE_SEPARATOR_LENGTH==strlen);
|
||||
|
||||
// patend != -1, or starpati > -1 so there remains something
|
||||
// to match.
|
||||
|
||||
// go to next pair: elt-(i+1) pat-(i+1);
|
||||
stri = strend + NAMESPACE_SEPARATOR_LENGTH;
|
||||
pati = (patend==-1)?pati:(patend + NAMESPACE_SEPARATOR_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the ObjectName's {@code domain} is selected by the
|
||||
* given {@code pattern}.
|
||||
*/
|
||||
public static boolean isDomainSelected(String domain, String pattern) {
|
||||
if (domain == null || pattern == null)
|
||||
throw new IllegalArgumentException("null");
|
||||
return Util.wildpathmatch(domain,pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a set of ObjectName according to a given pattern.
|
||||
*
|
||||
* @param pattern the pattern that the returned names must match.
|
||||
* @param all the set of names to filter.
|
||||
* @return a set of ObjectName from which non matching names
|
||||
* have been removed.
|
||||
*/
|
||||
public static Set<ObjectName> filterMatchingNames(ObjectName pattern,
|
||||
Set<ObjectName> all) {
|
||||
// If no pattern, just return all names
|
||||
if (pattern == null
|
||||
|| all.isEmpty()
|
||||
|| ObjectName.WILDCARD.equals(pattern))
|
||||
return all;
|
||||
|
||||
// If there's a pattern, do the matching.
|
||||
final Set<ObjectName> res = equivalentEmptySet(all);
|
||||
for (ObjectName n : all) if (pattern.apply(n)) res.add(n);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Filters a set of ObjectInstance according to a given pattern.
|
||||
*
|
||||
* @param pattern the pattern that the returned names must match.
|
||||
* @param all the set of instances to filter.
|
||||
* @return a set of ObjectInstance from which non matching instances
|
||||
* have been removed.
|
||||
*/
|
||||
public static Set<ObjectInstance>
|
||||
filterMatchingInstances(ObjectName pattern,
|
||||
Set<ObjectInstance> all) {
|
||||
// If no pattern, just return all names
|
||||
if (pattern == null
|
||||
|| all.isEmpty()
|
||||
|| ObjectName.WILDCARD.equals(pattern))
|
||||
return all;
|
||||
|
||||
// If there's a pattern, do the matching.
|
||||
final Set<ObjectInstance> res = equivalentEmptySet(all);
|
||||
for (ObjectInstance n : all) {
|
||||
if (n == null) continue;
|
||||
if (pattern.apply(n.getObjectName()))
|
||||
res.add(n);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract ClassLoaderRepository that contains a single class loader.
|
||||
**/
|
||||
private final static class SingleClassLoaderRepository
|
||||
implements ClassLoaderRepository {
|
||||
private final ClassLoader singleLoader;
|
||||
|
||||
SingleClassLoaderRepository(ClassLoader loader) {
|
||||
this.singleLoader = loader;
|
||||
}
|
||||
|
||||
ClassLoader getSingleClassLoader() {
|
||||
return singleLoader;
|
||||
}
|
||||
|
||||
private Class<?> loadClass(String className, ClassLoader loader)
|
||||
throws ClassNotFoundException {
|
||||
return Class.forName(className, false, loader);
|
||||
}
|
||||
|
||||
public Class<?> loadClass(String className)
|
||||
throws ClassNotFoundException {
|
||||
return loadClass(className, getSingleClassLoader());
|
||||
}
|
||||
|
||||
public Class<?> loadClassWithout(ClassLoader exclude,
|
||||
String className) throws ClassNotFoundException {
|
||||
final ClassLoader loader = getSingleClassLoader();
|
||||
if (exclude != null && exclude.equals(loader))
|
||||
throw new ClassNotFoundException(className);
|
||||
return loadClass(className, loader);
|
||||
}
|
||||
|
||||
public Class<?> loadClassBefore(ClassLoader stop, String className)
|
||||
throws ClassNotFoundException {
|
||||
return loadClassWithout(stop, className);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ClassLoaderRepository that contains a single class loader.
|
||||
* @param loader the class loader contained in the returned repository.
|
||||
* @return a ClassLoaderRepository that contains the single loader.
|
||||
*/
|
||||
public static ClassLoaderRepository getSingleClassLoaderRepository(
|
||||
final ClassLoader loader) {
|
||||
return new SingleClassLoaderRepository(loader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the given MBeanServer that should be put in a
|
||||
* permission you need.
|
||||
* This corresponds to the
|
||||
* {@code *[;mbeanServerName=<mbeanServerName>[;*]]} property
|
||||
* embedded in the MBeanServerId attribute of the
|
||||
* server's {@link MBeanServerDelegate}.
|
||||
*
|
||||
* @param server The MBean server
|
||||
* @return the name of the MBeanServer, or "*" if the name couldn't be
|
||||
* obtained, or {@value MBeanServerFactory#DEFAULT_MBEANSERVER_NAME}
|
||||
* if there was no name.
|
||||
*/
|
||||
public static String getMBeanServerSecurityName(MBeanServer server) {
|
||||
final String notfound = "*";
|
||||
try {
|
||||
final String mbeanServerId = (String)
|
||||
server.getAttribute(MBeanServerDelegate.DELEGATE_NAME,
|
||||
"MBeanServerId");
|
||||
final String found = extractMBeanServerName(mbeanServerId);
|
||||
if (found.length()==0)
|
||||
return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME;
|
||||
return found;
|
||||
} catch (Exception x) {
|
||||
logshort("Failed to retrieve MBeanServerName for server, " +
|
||||
"using \"*\"",x);
|
||||
return notfound;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the MBeanServer embedded in the given
|
||||
* mbeanServerId. If the given mbeanServerId doesn't contain any name,
|
||||
* an empty String is returned.
|
||||
* The MBeanServerId is expected to be of the form:
|
||||
* {@code *[;mbeanServerName=<mbeanServerName>[;*]]}
|
||||
* @param mbeanServerId The MBean server ID
|
||||
* @return the name of the MBeanServer if found, or "" if the name was
|
||||
* not present in the mbeanServerId.
|
||||
*/
|
||||
public static String extractMBeanServerName(String mbeanServerId) {
|
||||
if (mbeanServerId==null) return "";
|
||||
final String beginMarker=";mbeanServerName=";
|
||||
final String endMarker=";";
|
||||
final int found = mbeanServerId.indexOf(beginMarker);
|
||||
if (found < 0) return "";
|
||||
final int start = found + beginMarker.length();
|
||||
final int stop = mbeanServerId.indexOf(endMarker, start);
|
||||
return mbeanServerId.substring(start,
|
||||
(stop < 0 ? mbeanServerId.length() : stop));
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the given mbeanServerName into the given mbeanServerId.
|
||||
* If mbeanServerName is null, empty, or equals to "-", the returned
|
||||
* mbeanServerId will not contain any mbeanServerName.
|
||||
* @param mbeanServerId The mbeanServerId in which to insert
|
||||
* mbeanServerName
|
||||
* @param mbeanServerName The mbeanServerName
|
||||
* @return an mbeanServerId containing the given mbeanServerName
|
||||
* @throws IllegalArgumentException if mbeanServerId already contains
|
||||
* a different name, or if the given mbeanServerName is not valid.
|
||||
*/
|
||||
public static String insertMBeanServerName(String mbeanServerId,
|
||||
String mbeanServerName) {
|
||||
final String found = extractMBeanServerName(mbeanServerId);
|
||||
if (found.length() > 0 &&
|
||||
found.equals(checkServerName(mbeanServerName)))
|
||||
return mbeanServerId;
|
||||
if (found.length() > 0 && !isMBeanServerNameUndefined(found))
|
||||
throw new IllegalArgumentException(
|
||||
"MBeanServerName already defined");
|
||||
if (isMBeanServerNameUndefined(mbeanServerName))
|
||||
return mbeanServerId;
|
||||
final String beginMarker=";mbeanServerName=";
|
||||
return mbeanServerId+beginMarker+checkServerName(mbeanServerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given mbeanServerName corresponds to an
|
||||
* undefined MBeanServerName.
|
||||
* The mbeanServerName is considered undefined if it is one of:
|
||||
* {@code null} or {@value MBeanServerFactory#DEFAULT_MBEANSERVER_NAME}.
|
||||
* @param mbeanServerName The mbeanServerName, as returned by
|
||||
* {@link #extractMBeanServerName(String)}.
|
||||
* @return true if the given name corresponds to one of the forms that
|
||||
* denotes an undefined MBeanServerName.
|
||||
*/
|
||||
public static boolean isMBeanServerNameUndefined(String mbeanServerName) {
|
||||
return mbeanServerName == null ||
|
||||
MBeanServerFactory.DEFAULT_MBEANSERVER_NAME.equals(mbeanServerName);
|
||||
}
|
||||
/**
|
||||
* Check that the provided mbeanServername is syntactically valid.
|
||||
* @param mbeanServerName An mbeanServerName, or {@code null}.
|
||||
* @return mbeanServerName, or {@value
|
||||
* MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if {@code mbeanServerName}
|
||||
* is {@code null}.
|
||||
* @throws IllegalArgumentException if mbeanServerName contains illegal
|
||||
* characters, or is empty, or is {@code "-"}.
|
||||
* Illegal characters are {@link #ILLEGAL_MBEANSERVER_NAME_CHARS}.
|
||||
*/
|
||||
public static String checkServerName(String mbeanServerName) {
|
||||
if ("".equals(mbeanServerName))
|
||||
throw new IllegalArgumentException(
|
||||
"\"\" is not a valid MBean server name");
|
||||
if ("-".equals(mbeanServerName))
|
||||
throw new IllegalArgumentException(
|
||||
"\"-\" is not a valid MBean server name");
|
||||
if (isMBeanServerNameUndefined(mbeanServerName))
|
||||
return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME;
|
||||
for (char c : ILLEGAL_MBEANSERVER_NAME_CHARS) {
|
||||
if (mbeanServerName.indexOf(c) >= 0)
|
||||
throw new IllegalArgumentException(
|
||||
"invalid character in MBeanServer name: "+c);
|
||||
}
|
||||
return mbeanServerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MBeanServer name that should be put in a permission you need.
|
||||
*
|
||||
* @param delegate The MBeanServerDelegate
|
||||
* @return The MBeanServer name - or {@value
|
||||
* MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if there was no name.
|
||||
*/
|
||||
public static String getMBeanServerSecurityName(
|
||||
MBeanServerDelegate delegate) {
|
||||
try {
|
||||
final String serverName = delegate.getMBeanServerName();
|
||||
if (isMBeanServerNameUndefined(serverName))
|
||||
return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME;
|
||||
return serverName;
|
||||
} catch (Exception x) {
|
||||
logshort("Failed to retrieve MBeanServerName from delegate, " +
|
||||
"using \"*\"",x);
|
||||
return "*";
|
||||
}
|
||||
}
|
||||
|
||||
// Log the exception and its causes without logging the stack trace.
|
||||
// Use with care - it is usually preferable to log the whole stack trace!
|
||||
// We don't want to log the whole stack trace here: logshort() is
|
||||
// called in those cases where the exception might not be abnormal.
|
||||
private static void logshort(String msg, Throwable t) {
|
||||
if (JmxProperties.MISC_LOGGER.isLoggable(Level.FINE)) {
|
||||
StringBuilder toprint = new StringBuilder(msg);
|
||||
do {
|
||||
toprint.append("\nCaused By: ").append(String.valueOf(t));
|
||||
} while ((t=t.getCause())!=null);
|
||||
JmxProperties.MISC_LOGGER.fine(toprint.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Set<T> cloneSet(Set<T> set) {
|
||||
if (set instanceof SortedSet<?>) {
|
||||
@SuppressWarnings("unchecked")
|
||||
SortedSet<T> sset = (SortedSet<T>) set;
|
||||
set = new TreeSet<T>(sset.comparator());
|
||||
set.addAll(sset);
|
||||
} else
|
||||
set = new HashSet<T>(set);
|
||||
return set;
|
||||
}
|
||||
|
||||
public static <T> Set<T> equivalentEmptySet(Set<T> set) {
|
||||
if (set instanceof SortedSet<?>) {
|
||||
@SuppressWarnings("unchecked")
|
||||
SortedSet<T> sset = (SortedSet<T>) set;
|
||||
set = new TreeSet<T>(sset.comparator());
|
||||
} else
|
||||
set = new HashSet<T>();
|
||||
return set;
|
||||
}
|
||||
|
||||
// This exception is used when wrapping a class that throws IOException
|
||||
// in a class that doesn't.
|
||||
// The typical example for this are JMXNamespaces, when the sub
|
||||
// MBeanServer can be remote.
|
||||
//
|
||||
public static RuntimeException newRuntimeIOException(IOException io) {
|
||||
final String msg = "Communication failed with underlying resource: "+
|
||||
io.getMessage();
|
||||
return new RuntimeException(msg,io);
|
||||
}
|
||||
}
|
||||
|
@ -1,463 +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 com.sun.jmx.mbeanserver.Util;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanPermission;
|
||||
import javax.management.MBeanServerDelegate;
|
||||
import javax.management.MBeanServerNotification;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.namespace.JMXDomain;
|
||||
|
||||
/**
|
||||
* A DomainInterceptor wraps a JMXDomain.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
|
||||
|
||||
// TODO: Ideally DomainInterceptor should be replaced by
|
||||
// something at Repository level.
|
||||
// The problem there will be that we may need to
|
||||
// reinstantiate the 'queryPerformedByRepos' boolean
|
||||
// [or we will need to wrap the repository in
|
||||
// a 'RepositoryInterceptor'?]
|
||||
// Also there's no real need for a DomainInterceptor to
|
||||
// extend RewritingMBeanServerConnection.
|
||||
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
private final String domainName;
|
||||
private volatile ObjectName ALL;
|
||||
private final String serverName;
|
||||
private volatile NotificationListener mbsListener;
|
||||
|
||||
private static class PatternNotificationFilter
|
||||
implements NotificationFilter {
|
||||
|
||||
final ObjectName pattern;
|
||||
public PatternNotificationFilter(ObjectName pattern) {
|
||||
this.pattern = pattern==null?ObjectName.WILDCARD:pattern;
|
||||
}
|
||||
|
||||
public boolean isNotificationEnabled(Notification notification) {
|
||||
if (!(notification instanceof MBeanServerNotification))
|
||||
return false;
|
||||
final MBeanServerNotification mbsn =
|
||||
(MBeanServerNotification) notification;
|
||||
if (pattern.apply(mbsn.getMBeanName()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static final long serialVersionUID = 7409950927025262111L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of NamespaceInterceptor
|
||||
*/
|
||||
public DomainInterceptor(String serverName,
|
||||
JMXDomain handler,
|
||||
String domainName) {
|
||||
super(handler);
|
||||
this.domainName = domainName;
|
||||
this.serverName = serverName;
|
||||
ALL = ObjectName.valueOf(domainName+":*");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getName()+"(parent="+serverName+
|
||||
", domain="+this.domainName+")";
|
||||
}
|
||||
|
||||
final void connectDelegate(final MBeanServerDelegate delegate)
|
||||
throws InstanceNotFoundException {
|
||||
final NotificationFilter filter =
|
||||
new PatternNotificationFilter(getPatternFor(null));
|
||||
synchronized (this) {
|
||||
if (mbsListener == null) {
|
||||
mbsListener = new NotificationListener() {
|
||||
public void handleNotification(Notification notification,
|
||||
Object handback) {
|
||||
if (filter.isNotificationEnabled(notification))
|
||||
delegate.sendNotification(notification);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
getHandlerInterceptorMBean().
|
||||
addMBeanServerNotificationListener(mbsListener, filter);
|
||||
}
|
||||
|
||||
final void disconnectDelegate()
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
final NotificationListener l;
|
||||
synchronized (this) {
|
||||
l = mbsListener;
|
||||
if (l == null) return;
|
||||
mbsListener = null;
|
||||
}
|
||||
getHandlerInterceptorMBean().removeMBeanServerNotificationListener(l);
|
||||
}
|
||||
|
||||
public final void addPostRegisterTask(Queue<Runnable> queue,
|
||||
final MBeanServerDelegate delegate) {
|
||||
if (queue == null)
|
||||
throw new IllegalArgumentException("task queue must not be null");
|
||||
final Runnable task1 = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
connectDelegate(delegate);
|
||||
} catch (Exception x) {
|
||||
throw new UnsupportedOperationException(
|
||||
"notification forwarding",x);
|
||||
}
|
||||
}
|
||||
};
|
||||
queue.add(task1);
|
||||
}
|
||||
|
||||
public final void addPostDeregisterTask(Queue<Runnable> queue,
|
||||
final MBeanServerDelegate delegate) {
|
||||
if (queue == null)
|
||||
throw new IllegalArgumentException("task queue must not be null");
|
||||
final Runnable task1 = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
disconnectDelegate();
|
||||
} catch (Exception x) {
|
||||
throw new UnsupportedOperationException(
|
||||
"notification forwarding",x);
|
||||
}
|
||||
}
|
||||
};
|
||||
queue.add(task1);
|
||||
}
|
||||
|
||||
// No name conversion for JMXDomains...
|
||||
// Throws IllegalArgumentException if targetName.getDomain() is not
|
||||
// in the domain handled.
|
||||
//
|
||||
@Override
|
||||
protected ObjectName toSource(ObjectName targetName) {
|
||||
if (targetName == null) return null;
|
||||
if (targetName.isDomainPattern()) return targetName;
|
||||
final String targetDomain = targetName.getDomain();
|
||||
|
||||
// TODO: revisit this. RuntimeOperationsException may be better?
|
||||
//
|
||||
if (!targetDomain.equals(domainName))
|
||||
throw new IllegalArgumentException(targetName.toString());
|
||||
return targetName;
|
||||
}
|
||||
|
||||
// No name conversion for JMXDomains...
|
||||
@Override
|
||||
protected ObjectName toTarget(ObjectName sourceName) {
|
||||
return sourceName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* No rewriting: always return sources - stripping instances for which
|
||||
* the caller doesn't have permissions.
|
||||
**/
|
||||
@Override
|
||||
Set<ObjectInstance> processOutputInstances(Set<ObjectInstance> sources) {
|
||||
if (sources == null || sources.isEmpty() || !checkOn())
|
||||
return sources;
|
||||
final Set<ObjectInstance> res = Util.equivalentEmptySet(sources);
|
||||
for (ObjectInstance o : sources) {
|
||||
if (checkQuery(o.getObjectName(), "queryMBeans"))
|
||||
res.add(o);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* No rewriting: always return sourceNames - stripping names for which
|
||||
* the caller doesn't have permissions.
|
||||
**/
|
||||
@Override
|
||||
Set<ObjectName> processOutputNames(Set<ObjectName> sourceNames) {
|
||||
if (sourceNames == null || sourceNames.isEmpty() || !checkOn())
|
||||
return sourceNames;
|
||||
final Set<ObjectName> res = Util.equivalentEmptySet(sourceNames);
|
||||
for (ObjectName o : sourceNames) {
|
||||
if (checkQuery(o, "queryNames"))
|
||||
res.add(o);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/** No rewriting: always return source **/
|
||||
@Override
|
||||
ObjectInstance processOutputInstance(ObjectInstance source) {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
|
||||
try {
|
||||
// We don't trust the wrapped JMXDomain...
|
||||
final ObjectName pattern = getPatternFor(name);
|
||||
final Set<ObjectName> res = super.queryNames(pattern,query);
|
||||
return Util.filterMatchingNames(pattern,res);
|
||||
} catch (Exception x) {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("Unexpected exception raised in queryNames: "+x);
|
||||
LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x);
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
// Compute a new pattern which is a sub pattern of 'name' but only selects
|
||||
// the MBeans in domain 'domainName'
|
||||
// When we reach here, it has been verified that 'name' matches our domain
|
||||
// name (done by DomainDispatchInterceptor)
|
||||
private ObjectName getPatternFor(final ObjectName name) {
|
||||
if (name == null) return ALL;
|
||||
if (name.getDomain().equals(domainName)) return name;
|
||||
return name.withDomain(domainName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
|
||||
try {
|
||||
// We don't trust the wrapped JMXDomain...
|
||||
final ObjectName pattern = getPatternFor(name);
|
||||
final Set<ObjectInstance> res = super.queryMBeans(pattern,query);
|
||||
return Util.filterMatchingInstances(pattern,res);
|
||||
} catch (Exception x) {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("Unexpected exception raised in queryNames: "+x);
|
||||
LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x);
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultDomain() {
|
||||
return domainName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDomains() {
|
||||
return new String[] {domainName};
|
||||
}
|
||||
|
||||
// We call getMBeanCount() on the namespace rather than on the
|
||||
// source server in order to avoid counting MBeans which are not
|
||||
// in the domain.
|
||||
@Override
|
||||
public Integer getMBeanCount() {
|
||||
return getHandlerInterceptorMBean().getMBeanCount();
|
||||
}
|
||||
|
||||
private boolean checkOn() {
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
return (sm != null);
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission checks.
|
||||
//
|
||||
@Override
|
||||
void check(ObjectName routingName, String member, String action) {
|
||||
if (!checkOn()) return;
|
||||
final String act = (action==null)?"-":action;
|
||||
if("queryMBeans".equals(act) || "queryNames".equals(act)) {
|
||||
// This is tricky. check with 3 parameters is called
|
||||
// by queryNames/queryMBeans before performing the query.
|
||||
// At this point we must check with no class name.
|
||||
// Therefore we pass a className of "-".
|
||||
// The filtering will be done later - processOutputNames and
|
||||
// processOutputInstance will call checkQuery.
|
||||
//
|
||||
check(routingName, "-", "-", act);
|
||||
} else {
|
||||
// This is also tricky:
|
||||
// passing null here will cause check to retrieve the classname,
|
||||
// if needed.
|
||||
check(routingName, null, member, act);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission checks.
|
||||
//
|
||||
@Override
|
||||
void checkCreate(ObjectName routingName, String className, String action) {
|
||||
if (!checkOn()) return;
|
||||
check(routingName,className,"-",action);
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission checks.
|
||||
//
|
||||
void check(ObjectName routingName, String className, String member,
|
||||
String action) {
|
||||
if (!checkOn()) return;
|
||||
final MBeanPermission perm;
|
||||
|
||||
final String act = (action==null)?"-":action;
|
||||
if ("getDomains".equals(act)) { // ES: OK
|
||||
perm = new MBeanPermission(serverName,"-",member,
|
||||
routingName,act);
|
||||
} else {
|
||||
final String clazz =
|
||||
(className==null)?getClassName(routingName):className;
|
||||
perm = new MBeanPermission(serverName,clazz,member,
|
||||
routingName,act);
|
||||
}
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkPermission(perm);
|
||||
}
|
||||
|
||||
String getClassName(ObjectName routingName) {
|
||||
if (routingName == null || routingName.isPattern()) return "-";
|
||||
try {
|
||||
return getHandlerInterceptorMBean().getSourceServer().
|
||||
getObjectInstance(routingName).getClassName();
|
||||
} catch (InstanceNotFoundException ex) {
|
||||
LOG.finest("Can't get class name for "+routingName+
|
||||
", using \"-\". Cause is: "+ex);
|
||||
return "-";
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for attributes...
|
||||
//
|
||||
@Override
|
||||
AttributeList checkAttributes(ObjectName routingName,
|
||||
AttributeList attributes, String action) {
|
||||
if (!checkOn()) return attributes;
|
||||
final String className = getClassName(routingName);
|
||||
check(routingName,className,"-",action);
|
||||
if (attributes == null || attributes.isEmpty()) return attributes;
|
||||
final AttributeList res = new AttributeList();
|
||||
for (Attribute at : attributes.asList()) {
|
||||
try {
|
||||
check(routingName,className,at.getName(),action);
|
||||
res.add(at);
|
||||
} catch (SecurityException x) { // DLS: OK
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for attributes...
|
||||
//
|
||||
@Override
|
||||
String[] checkAttributes(ObjectName routingName, String[] attributes,
|
||||
String action) {
|
||||
if (!checkOn()) return attributes;
|
||||
final String className = getClassName(routingName);
|
||||
check(routingName,className,"-",action);
|
||||
if (attributes == null || attributes.length==0) return attributes;
|
||||
final List<String> res = new ArrayList<String>(attributes.length);
|
||||
for (String at : attributes) {
|
||||
try {
|
||||
check(routingName,className,at,action);
|
||||
res.add(at);
|
||||
} catch (SecurityException x) { // DLS: OK
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return res.toArray(new String[res.size()]);
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for domains...
|
||||
//
|
||||
@Override
|
||||
String[] checkDomains(String[] domains, String action) {
|
||||
if (domains == null || domains.length==0 || !checkOn())
|
||||
return domains;
|
||||
int count=0;
|
||||
for (int i=0;i<domains.length;i++) {
|
||||
try {
|
||||
check(ObjectName.valueOf(domains[i]+":x=x"),"-",
|
||||
"-","getDomains");
|
||||
} catch (SecurityException x) { // DLS: OK
|
||||
count++;
|
||||
domains[i]=null;
|
||||
}
|
||||
}
|
||||
if (count == 0) return domains;
|
||||
final String[] res = new String[domains.length-count];
|
||||
count = 0;
|
||||
for (int i=0;i<domains.length;i++)
|
||||
if (domains[i]!=null) res[count++]=domains[i];
|
||||
return res;
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for queries...
|
||||
//
|
||||
@Override
|
||||
boolean checkQuery(ObjectName routingName, String action) {
|
||||
try {
|
||||
final String className = getClassName(routingName);
|
||||
check(routingName,className,"-",action);
|
||||
return true;
|
||||
} catch (SecurityException x) { // DLS: OK
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,734 +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 com.sun.jmx.interceptor.MBeanServerInterceptor;
|
||||
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.OperationsException;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
import javax.management.loading.ClassLoaderRepository;
|
||||
import javax.management.namespace.JMXNamespace;
|
||||
|
||||
/**
|
||||
* This interceptor wraps a JMXNamespace, and performs
|
||||
* {@code ObjectName} rewriting. {@code HandlerInterceptor} are
|
||||
* created and managed by a {@link NamespaceDispatchInterceptor} or a
|
||||
* {@link DomainDispatchInterceptor}.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public abstract class HandlerInterceptor<T extends JMXNamespace>
|
||||
extends RoutingMBeanServerConnection<MBeanServer>
|
||||
implements MBeanServerInterceptor {
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
// The wrapped JMXNamespace
|
||||
private final T handler;
|
||||
|
||||
/**
|
||||
* Creates a new instance of HandlerInterceptor
|
||||
*/
|
||||
public HandlerInterceptor(T handler) {
|
||||
if (handler == null) throw new IllegalArgumentException("null");
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
//
|
||||
// The {@code source} connection is a connection to the MBeanServer
|
||||
// that contains the actual MBeans.
|
||||
// In the case of cascading, that would be a connection to the sub
|
||||
// agent. Practically, this is JMXNamespace.getSourceServer();
|
||||
//
|
||||
@Override
|
||||
protected MBeanServer source() {
|
||||
return handler.getSourceServer();
|
||||
}
|
||||
|
||||
// The MBeanServer on which getClassLoader / getClassLoaderFor
|
||||
// will be called.
|
||||
// The NamespaceInterceptor overrides this method - so that it
|
||||
// getClassLoader / getClassLoaderFor don't trigger the loop
|
||||
// detection mechanism.
|
||||
//
|
||||
MBeanServer getServerForLoading() {
|
||||
return source();
|
||||
}
|
||||
|
||||
// The namespace or domain handler - this either a JMXNamespace or a
|
||||
// a JMXDomain
|
||||
T getHandlerInterceptorMBean() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
// If the underlying JMXNamespace throws an IO, the IO will be
|
||||
// wrapped in a RuntimeOperationsException.
|
||||
RuntimeException handleIOException(IOException x,String fromMethodName,
|
||||
Object... params) {
|
||||
// Must do something here?
|
||||
if (LOG.isLoggable(Level.FINEST)) {
|
||||
LOG.finest("IO Exception in "+fromMethodName+": "+x+
|
||||
" - "+" rethrowing as RuntimeOperationsException.");
|
||||
}
|
||||
throw new RuntimeOperationsException(
|
||||
Util.newRuntimeIOException(x));
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public AttributeList getAttributes(ObjectName name, String[] attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
try {
|
||||
final String[] authorized =
|
||||
checkAttributes(name,attributes,"getAttribute");
|
||||
final AttributeList attrList =
|
||||
super.getAttributes(name,authorized);
|
||||
return attrList;
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"getAttributes",name,attributes);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public ClassLoader getClassLoaderFor(ObjectName mbeanName)
|
||||
throws InstanceNotFoundException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(mbeanName);
|
||||
try {
|
||||
check(mbeanName,null,"getClassLoaderFor");
|
||||
return getServerForLoading().getClassLoaderFor(sourceName);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// From MBeanServer
|
||||
public ClassLoader getClassLoader(ObjectName loaderName)
|
||||
throws InstanceNotFoundException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(loaderName);
|
||||
try {
|
||||
check(loaderName,null,"getClassLoader");
|
||||
return getServerForLoading().getClassLoader(sourceName);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public ObjectInstance registerMBean(Object object, ObjectName name)
|
||||
throws InstanceAlreadyExistsException, MBeanRegistrationException,
|
||||
NotCompliantMBeanException {
|
||||
final ObjectName sourceName = newSourceMBeanName(name);
|
||||
try {
|
||||
checkCreate(name,object.getClass().getName(),"registerMBean");
|
||||
return processOutputInstance(
|
||||
source().registerMBean(object,sourceName));
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name, ObjectName listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
check(name,null,"removeNotificationListener");
|
||||
super.removeNotificationListener(name,listener);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"removeNotificationListener",name,listener);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public String getDefaultDomain() {
|
||||
try {
|
||||
return super.getDefaultDomain();
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"getDefaultDomain");
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public String[] getDomains() {
|
||||
try {
|
||||
check(null,null,"getDomains");
|
||||
final String[] domains = super.getDomains();
|
||||
return checkDomains(domains,"getDomains");
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"getDomains");
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public Integer getMBeanCount() {
|
||||
try {
|
||||
return super.getMBeanCount();
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"getMBeanCount");
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void setAttribute(ObjectName name, Attribute attribute)
|
||||
throws InstanceNotFoundException, AttributeNotFoundException,
|
||||
InvalidAttributeValueException, MBeanException,
|
||||
ReflectionException {
|
||||
try {
|
||||
check(name,
|
||||
(attribute==null?null:attribute.getName()),
|
||||
"setAttribute");
|
||||
super.setAttribute(name,attribute);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"setAttribute",name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
|
||||
if (name == null) name=ObjectName.WILDCARD;
|
||||
try {
|
||||
checkPattern(name,null,"queryNames");
|
||||
return super.queryNames(name,query);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"queryNames",name, query);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
|
||||
if (name == null) name=ObjectName.WILDCARD;
|
||||
try {
|
||||
checkPattern(name,null,"queryMBeans");
|
||||
return super.queryMBeans(name,query);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"queryMBeans",name, query);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public boolean isInstanceOf(ObjectName name, String className)
|
||||
throws InstanceNotFoundException {
|
||||
try {
|
||||
check(name, null, "isInstanceOf");
|
||||
return super.isInstanceOf(name, className);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"isInstanceOf",name, className);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException {
|
||||
try {
|
||||
checkCreate(name, className, "instantiate");
|
||||
checkCreate(name, className, "registerMBean");
|
||||
return super.createMBean(className, name);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"createMBean",className, name);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
ObjectName loaderName)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, InstanceNotFoundException {
|
||||
try {
|
||||
checkCreate(name, className, "instantiate");
|
||||
checkCreate(name, className, "registerMBean");
|
||||
return super.createMBean(className, name, loaderName);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"createMBean",className, name, loaderName);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public Object getAttribute(ObjectName name, String attribute)
|
||||
throws MBeanException, AttributeNotFoundException,
|
||||
InstanceNotFoundException, ReflectionException {
|
||||
try {
|
||||
check(name, attribute, "getAttribute");
|
||||
return super.getAttribute(name, attribute);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"getAttribute",name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name, ObjectName listener,
|
||||
NotificationFilter filter, Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
check(name,null,"removeNotificationListener");
|
||||
super.removeNotificationListener(name, listener, filter, handback);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"removeNotificationListener",name,
|
||||
listener, filter, handback);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener, NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
check(name,null,"removeNotificationListener");
|
||||
super.removeNotificationListener(name, listener, filter, handback);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"removeNotificationListener",name,
|
||||
listener, filter, handback);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
check(name,null,"removeNotificationListener");
|
||||
super.removeNotificationListener(name, listener);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"removeNotificationListener",name,
|
||||
listener);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void addNotificationListener(ObjectName name,
|
||||
NotificationListener listener, NotificationFilter filter,
|
||||
Object handback) throws InstanceNotFoundException {
|
||||
try {
|
||||
check(name,null,"addNotificationListener");
|
||||
super.addNotificationListener(name, listener, filter, handback);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"addNotificationListener",name,
|
||||
listener, filter, handback);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void addNotificationListener(ObjectName name, ObjectName listener,
|
||||
NotificationFilter filter, Object handback)
|
||||
throws InstanceNotFoundException {
|
||||
try {
|
||||
check(name,null,"addNotificationListener");
|
||||
super.addNotificationListener(name, listener, filter, handback);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"addNotificationListener",name,
|
||||
listener, filter, handback);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public boolean isRegistered(ObjectName name) {
|
||||
try {
|
||||
return super.isRegistered(name);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"isRegistered",name);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void unregisterMBean(ObjectName name)
|
||||
throws InstanceNotFoundException, MBeanRegistrationException {
|
||||
try {
|
||||
check(name, null, "unregisterMBean");
|
||||
super.unregisterMBean(name);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"unregisterMBean",name);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public MBeanInfo getMBeanInfo(ObjectName name)
|
||||
throws InstanceNotFoundException, IntrospectionException,
|
||||
ReflectionException {
|
||||
try {
|
||||
check(name, null, "getMBeanInfo");
|
||||
return super.getMBeanInfo(name);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"getMBeanInfo",name);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public ObjectInstance getObjectInstance(ObjectName name)
|
||||
throws InstanceNotFoundException {
|
||||
try {
|
||||
check(name, null, "getObjectInstance");
|
||||
return super.getObjectInstance(name);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"getObjectInstance",name);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
Object[] params, String[] signature)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException {
|
||||
try {
|
||||
checkCreate(name, className, "instantiate");
|
||||
checkCreate(name, className, "registerMBean");
|
||||
return super.createMBean(className, name, params, signature);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"createMBean",className, name,
|
||||
params, signature);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
ObjectName loaderName, Object[] params, String[] signature)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, InstanceNotFoundException {
|
||||
try {
|
||||
checkCreate(name, className, "instantiate");
|
||||
checkCreate(name, className, "registerMBean");
|
||||
return super.createMBean(className, name, loaderName, params,
|
||||
signature);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"createMBean",className, name,loaderName,
|
||||
params, signature);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public AttributeList setAttributes(ObjectName name,AttributeList attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
try {
|
||||
final AttributeList authorized =
|
||||
checkAttributes(name, attributes, "setAttribute");
|
||||
return super.setAttributes(name, authorized);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"setAttributes",name, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public Object invoke(ObjectName name, String operationName, Object[] params,
|
||||
String[] signature)
|
||||
throws InstanceNotFoundException, MBeanException, ReflectionException {
|
||||
try {
|
||||
check(name, operationName, "invoke");
|
||||
return super.invoke(name, operationName, params, signature);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"invoke",name, operationName,
|
||||
params, signature);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// These methods are inherited from MBeanServer....
|
||||
//
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className)
|
||||
throws ReflectionException, MBeanException {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported instantiate method: " +
|
||||
"trowing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className, ObjectName loaderName)
|
||||
throws ReflectionException, MBeanException,
|
||||
InstanceNotFoundException {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported method: instantiate(...) -" +
|
||||
"throwing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className, Object[] params,
|
||||
String[] signature) throws ReflectionException, MBeanException {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported method: instantiate(...) -" +
|
||||
"throwing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className, ObjectName loaderName,
|
||||
Object[] params, String[] signature)
|
||||
throws ReflectionException, MBeanException,
|
||||
InstanceNotFoundException {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported method: instantiate(...) -" +
|
||||
"throwing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(ObjectName name, byte[] data)
|
||||
throws InstanceNotFoundException, OperationsException {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported method: deserialize(...) -" +
|
||||
"throwing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(String className, byte[] data)
|
||||
throws OperationsException, ReflectionException {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported method: deserialize(...) -" +
|
||||
"throwing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(String className,
|
||||
ObjectName loaderName, byte[] data)
|
||||
throws InstanceNotFoundException, OperationsException,
|
||||
ReflectionException {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported method: deserialize(...) -" +
|
||||
"throwing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public ClassLoaderRepository getClassLoaderRepository() {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported method: getClassLoaderRepository() -" +
|
||||
"throwing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
static RuntimeException newUnsupportedException(String namespace) {
|
||||
return new RuntimeOperationsException(
|
||||
new UnsupportedOperationException(
|
||||
"Not supported in this namespace: "+namespace));
|
||||
}
|
||||
|
||||
/**
|
||||
* A result might be excluded for security reasons.
|
||||
*/
|
||||
@Override
|
||||
boolean excludesFromResult(ObjectName targetName, String queryMethod) {
|
||||
return !checkQuery(targetName, queryMethod);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Hooks for checking permissions
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This method is a hook to implement permission checking in subclasses.
|
||||
* A subclass may override this method and throw a {@link
|
||||
* SecurityException} if the permission is denied.
|
||||
*
|
||||
* @param routingName The name of the MBean in the enclosing context.
|
||||
* This is of the form {@code <namespace>//<ObjectName>}.
|
||||
* @param member The {@link
|
||||
* javax.management.namespace.JMXNamespacePermission#getMember member}
|
||||
* name.
|
||||
* @param action The {@link
|
||||
* javax.management.namespace.JMXNamespacePermission#getActions action}
|
||||
* name.
|
||||
* @throws SecurityException if the caller doesn't have the permission
|
||||
* to perform the given action on the MBean pointed to
|
||||
* by routingName.
|
||||
*/
|
||||
abstract void check(ObjectName routingName,
|
||||
String member, String action);
|
||||
|
||||
// called in createMBean and registerMBean
|
||||
abstract void checkCreate(ObjectName routingName, String className,
|
||||
String action);
|
||||
|
||||
/**
|
||||
* This is a hook to implement permission checking in subclasses.
|
||||
*
|
||||
* Checks that the caller has sufficient permission for returning
|
||||
* information about {@code sourceName} in {@code action}.
|
||||
*
|
||||
* Subclass may override this method and return false if the caller
|
||||
* doesn't have sufficient permissions.
|
||||
*
|
||||
* @param routingName The name of the MBean to include or exclude from
|
||||
* the query, expressed in the enclosing context.
|
||||
* This is of the form {@code <namespace>//<ObjectName>}.
|
||||
* @param action one of "queryNames" or "queryMBeans"
|
||||
* @return true if {@code sourceName} can be returned.
|
||||
*/
|
||||
abstract boolean checkQuery(ObjectName routingName, String action);
|
||||
|
||||
/**
|
||||
* This method is a hook to implement permission checking in subclasses.
|
||||
*
|
||||
* @param routingName The name of the MBean in the enclosing context.
|
||||
* This is of the form {@code <namespace>//<ObjectName>}.
|
||||
* @param attributes The list of attributes to check permission for.
|
||||
* @param action one of "getAttribute" or "setAttribute"
|
||||
* @return The list of attributes for which the callers has the
|
||||
* appropriate {@link
|
||||
* javax.management.namespace.JMXNamespacePermission}.
|
||||
* @throws SecurityException if the caller doesn't have the permission
|
||||
* to perform {@code action} on the MBean pointed to by routingName.
|
||||
*/
|
||||
abstract String[] checkAttributes(ObjectName routingName,
|
||||
String[] attributes, String action);
|
||||
|
||||
/**
|
||||
* This method is a hook to implement permission checking in subclasses.
|
||||
*
|
||||
* @param routingName The name of the MBean in the enclosing context.
|
||||
* This is of the form {@code <namespace>//<ObjectName>}.
|
||||
* @param attributes The list of attributes to check permission for.
|
||||
* @param action one of "getAttribute" or "setAttribute"
|
||||
* @return The list of attributes for which the callers has the
|
||||
* appropriate {@link
|
||||
* javax.management.namespace.JMXNamespacePermission}.
|
||||
* @throws SecurityException if the caller doesn't have the permission
|
||||
* to perform {@code action} on the MBean pointed to by routingName.
|
||||
*/
|
||||
abstract AttributeList checkAttributes(ObjectName routingName,
|
||||
AttributeList attributes, String action);
|
||||
|
||||
/**
|
||||
* This method is a hook to implement permission checking in subclasses.
|
||||
* Checks that the caller as the necessary permissions to view the
|
||||
* given domain. If not remove the domains for which the caller doesn't
|
||||
* have permission from the list.
|
||||
* <p>
|
||||
* By default, this method always returns {@code domains}
|
||||
*
|
||||
* @param domains The domains to return.
|
||||
* @param action "getDomains"
|
||||
* @return a filtered list of domains.
|
||||
*/
|
||||
String[] checkDomains(String[] domains, String action) {
|
||||
return domains;
|
||||
}
|
||||
|
||||
// A priori check for queryNames/queryMBeans/
|
||||
void checkPattern(ObjectName routingPattern,
|
||||
String member, String action) {
|
||||
// pattern is checked only at posteriori by checkQuery.
|
||||
// checking it a priori usually doesn't work, because ObjectName.apply
|
||||
// does not work between two patterns.
|
||||
// We only check that we have the permission requested for 'action'.
|
||||
check(null,null,action);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,220 +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 java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.namespace.JMXNamespace;
|
||||
import javax.management.namespace.JMXNamespacePermission;
|
||||
|
||||
/**
|
||||
* A NamespaceInterceptor wraps a JMXNamespace, performing
|
||||
* ObjectName rewriting.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
|
||||
|
||||
|
||||
// The target name space in which the NamepsaceHandler is mounted.
|
||||
private final String targetNs;
|
||||
|
||||
private final String serverName;
|
||||
|
||||
private final ObjectNameRouter proc;
|
||||
|
||||
/**
|
||||
* Creates a new instance of NamespaceInterceptor
|
||||
*/
|
||||
public NamespaceInterceptor(
|
||||
String serverName,
|
||||
JMXNamespace handler,
|
||||
String targetNamespace) {
|
||||
super(handler);
|
||||
this.serverName = serverName;
|
||||
this.targetNs =
|
||||
ObjectNameRouter.normalizeNamespacePath(targetNamespace,
|
||||
true, true, false);
|
||||
proc = new ObjectNameRouter(targetNamespace, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getName()+"(parent="+serverName+
|
||||
", namespace="+this.targetNs+")";
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will send a probe to detect self-linking name spaces.
|
||||
* A self linking namespace is a namespace that links back directly
|
||||
* on itslef. Calling a method on such a name space always results
|
||||
* in an infinite loop going through:
|
||||
* [1]MBeanServer -> [2]NamespaceDispatcher -> [3]NamespaceInterceptor
|
||||
* [4]JMXNamespace -> { network // or cd // or ... } -> [5]MBeanServer
|
||||
* with exactly the same request than [1]...
|
||||
*
|
||||
* The namespace interceptor [2] tries to detect such condition the
|
||||
* *first time* that the connection is used. It does so by setting
|
||||
* a flag, and sending a queryNames() through the name space. If the
|
||||
* queryNames comes back, it knows that there's a loop.
|
||||
*
|
||||
* The DynamicProbe interface can also be used by a Sun JMXNamespace
|
||||
* implementation to request the emission of a probe at any time
|
||||
* (see JMXRemoteNamespace implementation).
|
||||
*/
|
||||
private MBeanServer connection() {
|
||||
final MBeanServer c = super.source();
|
||||
if (c != null) return c;
|
||||
// should not come here
|
||||
throw new NullPointerException("getMBeanServerConnection");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected MBeanServer source() {
|
||||
return connection();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MBeanServer getServerForLoading() {
|
||||
// don't want to send probe on getClassLoader/getClassLoaderFor
|
||||
return super.source();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectName toSource(ObjectName targetName) {
|
||||
return proc.toSourceContext(targetName, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectName toTarget(ObjectName sourceName) {
|
||||
return proc.toTargetContext(sourceName, false);
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission checks.
|
||||
//
|
||||
@Override
|
||||
void check(ObjectName routingName, String member, String action) {
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm == null) return;
|
||||
if ("getDomains".equals(action)) return;
|
||||
final JMXNamespacePermission perm =
|
||||
new JMXNamespacePermission(serverName,member,
|
||||
routingName,action);
|
||||
sm.checkPermission(perm);
|
||||
}
|
||||
|
||||
@Override
|
||||
void checkCreate(ObjectName routingName, String className, String action) {
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm == null) return;
|
||||
final JMXNamespacePermission perm =
|
||||
new JMXNamespacePermission(serverName,className,
|
||||
routingName,action);
|
||||
sm.checkPermission(perm);
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for attributes...
|
||||
//
|
||||
@Override
|
||||
AttributeList checkAttributes(ObjectName routingName,
|
||||
AttributeList attributes, String action) {
|
||||
check(routingName,null,action);
|
||||
if (attributes == null || attributes.isEmpty()) return attributes;
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm == null) return attributes;
|
||||
final AttributeList res = new AttributeList();
|
||||
for (Attribute at : attributes.asList()) {
|
||||
try {
|
||||
check(routingName,at.getName(),action);
|
||||
res.add(at);
|
||||
} catch (SecurityException x) { // DLS: OK
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for attributes...
|
||||
//
|
||||
@Override
|
||||
String[] checkAttributes(ObjectName routingName, String[] attributes,
|
||||
String action) {
|
||||
check(routingName,null,action);
|
||||
if (attributes == null || attributes.length==0) return attributes;
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm == null) return attributes;
|
||||
final List<String> res = new ArrayList<String>(attributes.length);
|
||||
for (String at : attributes) {
|
||||
try {
|
||||
check(routingName,at,action);
|
||||
res.add(at);
|
||||
} catch (SecurityException x) { // DLS: OK
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return res.toArray(new String[res.size()]);
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for domains...
|
||||
//
|
||||
@Override
|
||||
String[] checkDomains(String[] domains, String action) {
|
||||
// in principle, this method is never called because
|
||||
// getDomains() will never be called - since there's
|
||||
// no way that MBeanServer.getDomains() can be routed
|
||||
// to a NamespaceInterceptor.
|
||||
//
|
||||
// This is also why there's no getDomains() in a
|
||||
// JMXNamespacePermission...
|
||||
//
|
||||
return super.checkDomains(domains, action);
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for queries...
|
||||
//
|
||||
@Override
|
||||
boolean checkQuery(ObjectName routingName, String action) {
|
||||
try {
|
||||
check(routingName,null,action);
|
||||
return true;
|
||||
} catch (SecurityException x) { // DLS: OK
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,175 +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 static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
|
||||
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* The ObjectNameRouter is used to rewrite routing object names.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public class ObjectNameRouter {
|
||||
|
||||
private static final int NAMESPACE_SEPARATOR_LENGTH =
|
||||
NAMESPACE_SEPARATOR.length();
|
||||
|
||||
final String targetPrefix;
|
||||
final String sourcePrefix;
|
||||
final int slen;
|
||||
final int tlen;
|
||||
final boolean identity;
|
||||
|
||||
/** Creates a new instance of ObjectNameRouter */
|
||||
public ObjectNameRouter(final String remove, final String add) {
|
||||
this.targetPrefix = (remove==null?"":remove);
|
||||
this.sourcePrefix = (add==null?"":add);
|
||||
tlen = targetPrefix.length();
|
||||
slen = sourcePrefix.length();
|
||||
identity = targetPrefix.equals(sourcePrefix);
|
||||
}
|
||||
|
||||
public final ObjectName toTargetContext(ObjectName sourceName,
|
||||
boolean removeLeadingSeparators) {
|
||||
if (sourceName == null) return null;
|
||||
if (identity) return sourceName;
|
||||
String srcDomain = sourceName.getDomain();
|
||||
|
||||
// if the ObjectName starts with // and removeLeadingSeparators is
|
||||
// true, then recursively strip leading //.
|
||||
// Otherwise, do not rewrite ObjectName.
|
||||
//
|
||||
if (srcDomain.startsWith(NAMESPACE_SEPARATOR)) {
|
||||
if (!removeLeadingSeparators) return sourceName;
|
||||
else srcDomain = normalizeDomain(srcDomain,true);
|
||||
}
|
||||
if (slen != 0) {
|
||||
if (!srcDomain.startsWith(sourcePrefix) ||
|
||||
!srcDomain.startsWith(NAMESPACE_SEPARATOR,slen))
|
||||
throw new IllegalArgumentException(
|
||||
"ObjectName does not start with expected prefix "
|
||||
+ sourcePrefix + ": " +
|
||||
String.valueOf(sourceName));
|
||||
srcDomain = srcDomain.substring(slen+NAMESPACE_SEPARATOR_LENGTH);
|
||||
}
|
||||
final String targetDomain =
|
||||
(tlen>0?targetPrefix+NAMESPACE_SEPARATOR+srcDomain:srcDomain);
|
||||
return sourceName.withDomain(targetDomain);
|
||||
}
|
||||
|
||||
public final ObjectName toSourceContext(ObjectName targetName,
|
||||
boolean removeLeadingSeparators) {
|
||||
if (targetName == null) return null;
|
||||
if (identity) return targetName;
|
||||
String targetDomain = targetName.getDomain();
|
||||
if (targetDomain.startsWith(NAMESPACE_SEPARATOR)) {
|
||||
if (!removeLeadingSeparators) return targetName;
|
||||
else targetDomain =
|
||||
normalizeDomain(targetDomain,true);
|
||||
}
|
||||
if (tlen != 0) {
|
||||
if (!targetDomain.startsWith(targetPrefix) ||
|
||||
!targetDomain.startsWith(NAMESPACE_SEPARATOR,tlen))
|
||||
throw new IllegalArgumentException(
|
||||
"ObjectName does not start with expected prefix "
|
||||
+ targetPrefix + ": " +
|
||||
String.valueOf(targetName));
|
||||
targetDomain = targetDomain.
|
||||
substring(tlen+NAMESPACE_SEPARATOR_LENGTH);
|
||||
}
|
||||
final String sourceDomain =
|
||||
(slen>0?sourcePrefix+NAMESPACE_SEPARATOR+targetDomain:
|
||||
targetDomain);
|
||||
return targetName.withDomain(sourceDomain);
|
||||
}
|
||||
|
||||
public final ObjectInstance toTargetContext(ObjectInstance sourceMoi,
|
||||
boolean removeLeadingSeparators) {
|
||||
if (sourceMoi == null) return null;
|
||||
if (identity) return sourceMoi;
|
||||
return new ObjectInstance(
|
||||
toTargetContext(sourceMoi.getObjectName(),
|
||||
removeLeadingSeparators),
|
||||
sourceMoi.getClassName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes leading, trailing, or duplicate // in a name space path.
|
||||
**/
|
||||
public static String normalizeDomain(String domain,
|
||||
boolean removeLeadingSep) {
|
||||
return normalizeNamespacePath(domain,removeLeadingSep,false,true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes leading, trailing, or duplicate // in a name space path.
|
||||
**/
|
||||
public static String normalizeNamespacePath(String namespacePath,
|
||||
boolean removeLeadingSep,
|
||||
boolean removeTrailingSep,
|
||||
boolean endsWithDomain) {
|
||||
if (namespacePath.equals(""))
|
||||
return "";
|
||||
final String[] components = namespacePath.split(NAMESPACE_SEPARATOR);
|
||||
final StringBuilder b =
|
||||
new StringBuilder(namespacePath.length()+NAMESPACE_SEPARATOR_LENGTH);
|
||||
String sep = null;
|
||||
if (!removeLeadingSep && namespacePath.startsWith(NAMESPACE_SEPARATOR))
|
||||
b.append(NAMESPACE_SEPARATOR);
|
||||
int count = 0;
|
||||
for (int i=0; i<components.length; i++) {
|
||||
final String n=components[i];
|
||||
if (n.equals("")) continue;
|
||||
if (n.startsWith("/")||n.endsWith("/")) {
|
||||
// throw exception unless we're looking at the last domain
|
||||
// part of the ObjectName
|
||||
if (! (endsWithDomain && i==(components.length-1))) {
|
||||
throw new IllegalArgumentException(n+
|
||||
" is not a valid name space identifier");
|
||||
} else {
|
||||
// There's a dirty little corner case when the domain
|
||||
// part (last item) is exactly '/' - in that case we must
|
||||
// not append '//'
|
||||
//
|
||||
removeTrailingSep = removeTrailingSep || n.equals("/");
|
||||
}
|
||||
}
|
||||
if (sep != null) b.append(sep);
|
||||
b.append(n);
|
||||
sep = NAMESPACE_SEPARATOR;
|
||||
count++;
|
||||
}
|
||||
if (!removeTrailingSep && namespacePath.endsWith(NAMESPACE_SEPARATOR)
|
||||
&& count > 0)
|
||||
b.append(NAMESPACE_SEPARATOR);
|
||||
return b.toString();
|
||||
}
|
||||
}
|
@ -1,106 +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.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.MBeanServerConnection;
|
||||
|
||||
|
||||
/**
|
||||
* A RoutingConnectionProxy is an MBeanServerConnection proxy that proxies a
|
||||
* source name space in a source MBeanServerConnection.
|
||||
* It wraps a source MBeanServerConnection, and rewrites routing
|
||||
* ObjectNames. It is used to implement
|
||||
* {@code JMXNamespaces.narrowToNamespace(MBeanServerConnection)}.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
// See class hierarchy and detailled explanations in RoutingProxy in this
|
||||
// package.
|
||||
//
|
||||
public class RoutingConnectionProxy
|
||||
extends RoutingProxy<MBeanServerConnection> {
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of RoutingConnectionProxy
|
||||
*/
|
||||
public RoutingConnectionProxy(MBeanServerConnection source,
|
||||
String sourceDir,
|
||||
String targetDir,
|
||||
boolean probe) {
|
||||
super(source, sourceDir, targetDir, probe);
|
||||
|
||||
if (LOG.isLoggable(Level.FINER))
|
||||
LOG.finer("RoutingConnectionProxy for " + getSourceNamespace() +
|
||||
" created");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final String targetNs = getTargetNamespace();
|
||||
final String sourceNs = getSourceNamespace();
|
||||
String wrapped = String.valueOf(source());
|
||||
if ("".equals(targetNs)) {
|
||||
return "JMXNamespaces.narrowToNamespace("+
|
||||
wrapped+", \""+
|
||||
sourceNs+"\")";
|
||||
}
|
||||
return this.getClass().getSimpleName()+"("+wrapped+", \""+
|
||||
sourceNs+"\", \""+
|
||||
targetNs+"\")";
|
||||
}
|
||||
|
||||
static final RoutingProxyFactory
|
||||
<MBeanServerConnection,RoutingConnectionProxy>
|
||||
FACTORY = new RoutingProxyFactory
|
||||
<MBeanServerConnection,RoutingConnectionProxy>() {
|
||||
|
||||
public RoutingConnectionProxy newInstance(MBeanServerConnection source,
|
||||
String sourcePath, String targetPath, boolean probe) {
|
||||
return new RoutingConnectionProxy(source,sourcePath,
|
||||
targetPath, probe);
|
||||
}
|
||||
};
|
||||
|
||||
public static MBeanServerConnection cd(
|
||||
MBeanServerConnection source, String sourcePath, boolean probe) {
|
||||
return RoutingProxy.cd(RoutingConnectionProxy.class, FACTORY,
|
||||
source, sourcePath, probe);
|
||||
}
|
||||
|
||||
}
|
@ -1,556 +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 com.sun.jmx.mbeanserver.Util;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.JMRuntimeException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.RuntimeMBeanException;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
|
||||
/**
|
||||
* A RoutingMBeanServerConnection wraps a MBeanServerConnection, defining
|
||||
* abstract methods that can be implemented by subclasses to rewrite
|
||||
* routing ObjectNames. It is used to implement
|
||||
* HandlerInterceptors (wrapping JMXNamespace instances) and routing
|
||||
* proxies (used to implement cd operations).
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnection>
|
||||
implements MBeanServerConnection {
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
/**
|
||||
* Creates a new instance of RoutingMBeanServerConnection
|
||||
*/
|
||||
public RoutingMBeanServerConnection() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapped source connection. The {@code source} connection
|
||||
* is a connection to the MBeanServer that contains the actual MBean.
|
||||
* In the case of cascading, that would be a connection to the sub
|
||||
* agent.
|
||||
**/
|
||||
protected abstract T source() throws IOException;
|
||||
|
||||
/**
|
||||
* Converts a target ObjectName to a source ObjectName.
|
||||
* The target ObjectName is the name of the MBean in the mount point
|
||||
* target. In the case of cascading, that would be the name of the
|
||||
* MBean in the master agent. So if a subagent S containing an MBean
|
||||
* named "X" is mounted in the target namespace "foo//" of a master agent M,
|
||||
* the source is S, the target is "foo//" in M, the source name is "X", and
|
||||
* the target name is "foo//X".
|
||||
* In the case of cascading - such as in NamespaceInterceptor, this method
|
||||
* will convert "foo//X" (the targetName) into "X", the source name.
|
||||
* @throws IllegalArgumentException if the name cannot be converted.
|
||||
**/
|
||||
protected abstract ObjectName toSource(ObjectName targetName);
|
||||
/**
|
||||
* Converts a source ObjectName to a target ObjectName.
|
||||
* (see description of toSource above for explanations)
|
||||
* In the case of cascading - such as in NamespaceInterceptor, this method
|
||||
* will convert "X" (the sourceName) into "foo//X", the target name.
|
||||
* @throws IllegalArgumentException if the name cannot be converted.
|
||||
**/
|
||||
protected abstract ObjectName toTarget(ObjectName sourceName);
|
||||
|
||||
/**
|
||||
* Can be overridden by subclasses to check the validity of a new
|
||||
* ObjectName used in createMBean or registerMBean.
|
||||
* This method is typically used by subclasses which might require
|
||||
* special handling for "null";
|
||||
**/
|
||||
protected ObjectName newSourceMBeanName(ObjectName targetName)
|
||||
throws MBeanRegistrationException {
|
||||
try {
|
||||
return toSource(targetName);
|
||||
} catch (Exception x) {
|
||||
throw new MBeanRegistrationException(x,"Illegal MBean Name");
|
||||
}
|
||||
}
|
||||
|
||||
// Calls toSource(), Wraps IllegalArgumentException.
|
||||
ObjectName toSourceOrRuntime(ObjectName targetName) {
|
||||
try {
|
||||
return toSource(targetName);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Wraps given exception if needed.
|
||||
RuntimeException makeCompliantRuntimeException(Exception x) {
|
||||
if (x instanceof SecurityException) return (SecurityException)x;
|
||||
if (x instanceof JMRuntimeException) return (JMRuntimeException)x;
|
||||
if (x instanceof RuntimeException)
|
||||
return new RuntimeOperationsException((RuntimeException)x);
|
||||
if (x instanceof IOException)
|
||||
return Util.newRuntimeIOException((IOException)x);
|
||||
// shouldn't come here...
|
||||
final RuntimeException x2 = new UndeclaredThrowableException(x);
|
||||
return new RuntimeOperationsException(x2);
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public AttributeList getAttributes(ObjectName name, String[] attributes)
|
||||
throws InstanceNotFoundException, ReflectionException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return source().getAttributes(sourceName, attributes);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public Object invoke(ObjectName name, String operationName, Object[] params,
|
||||
String[] signature)
|
||||
throws InstanceNotFoundException, MBeanException, ReflectionException,
|
||||
IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
final Object result =
|
||||
source().invoke(sourceName,operationName,params,
|
||||
signature);
|
||||
return result;
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void unregisterMBean(ObjectName name)
|
||||
throws InstanceNotFoundException, MBeanRegistrationException,
|
||||
IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
source().unregisterMBean(sourceName);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public MBeanInfo getMBeanInfo(ObjectName name)
|
||||
throws InstanceNotFoundException, IntrospectionException,
|
||||
ReflectionException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return source().getMBeanInfo(sourceName);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public ObjectInstance getObjectInstance(ObjectName name)
|
||||
throws InstanceNotFoundException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return processOutputInstance(
|
||||
source().getObjectInstance(sourceName));
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public boolean isRegistered(ObjectName name) throws IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return source().isRegistered(sourceName);
|
||||
} catch (RuntimeMBeanException x) {
|
||||
throw new RuntimeOperationsException(x.getTargetException());
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void setAttribute(ObjectName name, Attribute attribute)
|
||||
throws InstanceNotFoundException, AttributeNotFoundException,
|
||||
InvalidAttributeValueException, MBeanException,
|
||||
ReflectionException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
source().setAttribute(sourceName,attribute);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public ObjectInstance createMBean(String className,
|
||||
ObjectName name, ObjectName loaderName,
|
||||
Object[] params, String[] signature)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, InstanceNotFoundException, IOException {
|
||||
final ObjectName sourceName = newSourceMBeanName(name);
|
||||
// Loader Name is already a sourceLoaderName.
|
||||
final ObjectName sourceLoaderName = loaderName;
|
||||
try {
|
||||
final ObjectInstance instance =
|
||||
source().createMBean(className,sourceName,
|
||||
sourceLoaderName,
|
||||
params,signature);
|
||||
return processOutputInstance(instance);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
Object[] params, String[] signature)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, IOException {
|
||||
final ObjectName sourceName = newSourceMBeanName(name);
|
||||
try {
|
||||
return processOutputInstance(source().createMBean(className,
|
||||
sourceName,params,signature));
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
ObjectName loaderName)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, InstanceNotFoundException, IOException {
|
||||
final ObjectName sourceName = newSourceMBeanName(name);
|
||||
// Loader Name is already a source Loader Name.
|
||||
final ObjectName sourceLoaderName = loaderName;
|
||||
try {
|
||||
return processOutputInstance(source().createMBean(className,
|
||||
sourceName,sourceLoaderName));
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public ObjectInstance createMBean(String className, ObjectName name)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, IOException {
|
||||
final ObjectName sourceName = newSourceMBeanName(name);
|
||||
try {
|
||||
return processOutputInstance(source().
|
||||
createMBean(className,sourceName));
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public Object getAttribute(ObjectName name, String attribute)
|
||||
throws MBeanException, AttributeNotFoundException,
|
||||
InstanceNotFoundException, ReflectionException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return source().getAttribute(sourceName,attribute);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public boolean isInstanceOf(ObjectName name, String className)
|
||||
throws InstanceNotFoundException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return source().isInstanceOf(sourceName,className);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public AttributeList setAttributes(ObjectName name, AttributeList attributes)
|
||||
throws InstanceNotFoundException, ReflectionException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return source().
|
||||
setAttributes(sourceName,attributes);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Return names in the target's context.
|
||||
Set<ObjectInstance> processOutputInstances(Set<ObjectInstance> sources) {
|
||||
|
||||
final Set<ObjectInstance> result = Util.equivalentEmptySet(sources);
|
||||
for (ObjectInstance i : sources) {
|
||||
try {
|
||||
final ObjectInstance target = processOutputInstance(i);
|
||||
if (excludesFromResult(target.getObjectName(), "queryMBeans"))
|
||||
continue;
|
||||
result.add(target);
|
||||
} catch (Exception x) {
|
||||
if (LOG.isLoggable(Level.FINE)) {
|
||||
LOG.fine("Skiping returned item: " +
|
||||
"Unexpected exception while processing " +
|
||||
"ObjectInstance: " + x);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Return names in the target's context.
|
||||
ObjectInstance processOutputInstance(ObjectInstance source) {
|
||||
if (source == null) return null;
|
||||
final ObjectName sourceName = source.getObjectName();
|
||||
try {
|
||||
final ObjectName targetName = toTarget(sourceName);
|
||||
return new ObjectInstance(targetName,source.getClassName());
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns names in the target's context.
|
||||
Set<ObjectName> processOutputNames(Set<ObjectName> sourceNames) {
|
||||
|
||||
final Set<ObjectName> names = Util.equivalentEmptySet(sourceNames);
|
||||
for (ObjectName n : sourceNames) {
|
||||
try {
|
||||
final ObjectName targetName = toTarget(n);
|
||||
if (excludesFromResult(targetName, "queryNames")) continue;
|
||||
names.add(targetName);
|
||||
} catch (Exception x) {
|
||||
if (LOG.isLoggable(Level.FINE)) {
|
||||
LOG.fine("Skiping returned item: " +
|
||||
"Unexpected exception while processing " +
|
||||
"ObjectInstance: " + x);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public Set<ObjectInstance> queryMBeans(ObjectName name,
|
||||
QueryExp query) throws IOException {
|
||||
if (name == null) name=ObjectName.WILDCARD;
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return processOutputInstances(
|
||||
source().queryMBeans(sourceName,query));
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
|
||||
public Set<ObjectName> queryNames(ObjectName name, QueryExp query)
|
||||
throws IOException {
|
||||
if (name == null) name=ObjectName.WILDCARD;
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
final Set<ObjectName> tmp = source().queryNames(sourceName,query);
|
||||
final Set<ObjectName> out = processOutputNames(tmp);
|
||||
//System.err.println("queryNames: out: "+out);
|
||||
return out;
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener)
|
||||
throws InstanceNotFoundException,
|
||||
ListenerNotFoundException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
source().removeNotificationListener(sourceName,listener);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void addNotificationListener(ObjectName name, ObjectName listener,
|
||||
NotificationFilter filter, Object handback)
|
||||
throws InstanceNotFoundException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
// Listener name is already a source listener name.
|
||||
try {
|
||||
source().addNotificationListener(sourceName,listener,
|
||||
filter,handback);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void addNotificationListener(ObjectName name,
|
||||
NotificationListener listener, NotificationFilter filter,
|
||||
Object handback) throws InstanceNotFoundException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
source().addNotificationListener(sourceName, listener, filter,
|
||||
handback);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener, NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException,
|
||||
IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
source().removeNotificationListener(sourceName,listener,filter,
|
||||
handback);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void removeNotificationListener(ObjectName name, ObjectName listener,
|
||||
NotificationFilter filter, Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException,
|
||||
IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
source().removeNotificationListener(sourceName,listener,
|
||||
filter,handback);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void removeNotificationListener(ObjectName name, ObjectName listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException,
|
||||
IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
// listener name is already a source name...
|
||||
final ObjectName sourceListener = listener;
|
||||
try {
|
||||
source().removeNotificationListener(sourceName,sourceListener);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public Integer getMBeanCount() throws IOException {
|
||||
try {
|
||||
return source().getMBeanCount();
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public String[] getDomains() throws IOException {
|
||||
try {
|
||||
return source().getDomains();
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public String getDefaultDomain() throws IOException {
|
||||
try {
|
||||
return source().getDefaultDomain();
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given targetName must be excluded from the
|
||||
* query result.
|
||||
* In this base class, always return {@code false}.
|
||||
* By default all object names returned by the sources are
|
||||
* transmitted to the caller - there is no filtering.
|
||||
*
|
||||
* @param name A target object name expressed in the caller's
|
||||
* context. In the case of cascading, where the source
|
||||
* is a sub agent mounted on e.g. namespace "foo",
|
||||
* that would be a name prefixed by "foo//"...
|
||||
* @param queryMethod either "queryNames" or "queryMBeans".
|
||||
* @return true if the name must be excluded.
|
||||
*/
|
||||
boolean excludesFromResult(ObjectName targetName, String queryMethod) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -1,395 +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.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.namespace.JMXNamespaces;
|
||||
|
||||
|
||||
/**
|
||||
* A RoutingProxy narrows on a given name space in a
|
||||
* source object implementing MBeanServerConnection.
|
||||
* It is used to implement
|
||||
* {@code JMXNamespaces.narrowToNamespace(...)}.
|
||||
* This abstract class has two concrete subclasses:
|
||||
* <p>{@link RoutingConnectionProxy}: to narrow down into an
|
||||
* MBeanServerConnection.</p>
|
||||
* <p>{@link RoutingServerProxy}: to narrow down into an MBeanServer.</p>
|
||||
*
|
||||
* <p>This class can also be used to "broaden" from a namespace. The same
|
||||
* class is used for both purposes because in both cases all that happens
|
||||
* is that ObjectNames are rewritten in one way on the way in (e.g. the
|
||||
* parameter of getMBeanInfo) and another way on the way out (e.g. the
|
||||
* return value of queryNames).</p>
|
||||
*
|
||||
* <p>Specifically, if you narrow into "a//" then you want to add the
|
||||
* "a//" prefix to ObjectNames on the way in and subtract it on the way
|
||||
* out. But ClientContext uses this class to subtract the
|
||||
* "jmx.context//foo=bar//" prefix on the way in and add it back on the
|
||||
* way out.</p>
|
||||
*
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
//
|
||||
// RoutingProxies are client side objects which are used to narrow down
|
||||
// into a namespace. They are used to perform ObjectName translation,
|
||||
// adding the namespace to the routing ObjectName before sending it over
|
||||
// to the source connection, and removing that prefix from results of
|
||||
// queries, createMBean, registerMBean, and getObjectInstance.
|
||||
// This translation is the opposite to that which is performed by
|
||||
// NamespaceInterceptors.
|
||||
//
|
||||
// There is however a special case where routing proxies are used on the
|
||||
// 'server' side to remove a namespace - rather than to add it:
|
||||
// This the case of ClientContext.
|
||||
// When an ObjectName like "jmx.context//c1=v1,c2=v2//D:k=v" reaches the
|
||||
// jmx.context namespace, a routing proxy is used to remove the prefix
|
||||
// c1=v1,c2=v2// from the routing objectname.
|
||||
//
|
||||
// For a RoutingProxy used in a narrowDownToNamespace operation, we have:
|
||||
// targetNs="" // targetNS is the namespace 'to remove'
|
||||
// sourceNS=<namespace-we-narrow-down-to> // namespace 'to add'
|
||||
//
|
||||
// For a RoutingProxy used in a ClientContext operation, we have:
|
||||
// targetNs=<encoded-context> // context must be removed from object name
|
||||
// sourceNs="" // nothing to add...
|
||||
//
|
||||
// Finally, in order to avoid too many layers of wrapping,
|
||||
// RoutingConnectionProxy and RoutingServerProxy can be created through a
|
||||
// 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
|
||||
//
|
||||
// The class hierarchy is as follows:
|
||||
//
|
||||
// RoutingMBeanServerConnection
|
||||
// [abstract class for all routing interceptors,
|
||||
// such as RoutingProxies and HandlerInterceptors]
|
||||
// / \
|
||||
// / \
|
||||
// RoutingProxy HandlerInterceptor
|
||||
// [base class for [base class for server side
|
||||
// client-side objects used objects, created by
|
||||
// in narrowDownTo] DispatchInterceptors]
|
||||
// / \ | \
|
||||
// RoutingConnectionProxy \ | NamespaceInterceptor
|
||||
// [wraps MBeanServerConnection \ | [used to remove
|
||||
// objects] \ | namespace prefix and
|
||||
// RoutingServerProxy | wrap JMXNamespace]
|
||||
// [wraps MBeanServer |
|
||||
// Objects] |
|
||||
// DomainInterceptor
|
||||
// [used to wrap JMXDomain]
|
||||
//
|
||||
// RoutingProxies also differ from HandlerInterceptors in that they transform
|
||||
// calls to MBeanServerConnection operations that do not have any parameters
|
||||
// into a call to the underlying JMXNamespace MBean.
|
||||
// So for instance a call to:
|
||||
// JMXNamespaces.narrowDownToNamespace(conn,"foo").getDomains()
|
||||
// is transformed into
|
||||
// conn.getAttribute("foo//type=JMXNamespace","Domains");
|
||||
//
|
||||
public abstract class RoutingProxy<T extends MBeanServerConnection>
|
||||
extends RoutingMBeanServerConnection<T> {
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
// The source MBeanServerConnection
|
||||
private final T source;
|
||||
|
||||
// The name space we're narrowing to (usually some name space in
|
||||
// the source MBeanServerConnection), 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. 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;
|
||||
private volatile String defaultDomain = null;
|
||||
|
||||
/**
|
||||
* Creates a new instance of RoutingProxy
|
||||
*/
|
||||
protected RoutingProxy(T source,
|
||||
String sourceNs,
|
||||
String targetNs,
|
||||
boolean probe) {
|
||||
if (source == null) throw new IllegalArgumentException("null");
|
||||
this.sourceNs = JMXNamespaces.normalizeNamespaceName(sourceNs);
|
||||
|
||||
// Usually sourceNs is not null, except when implementing
|
||||
// Client Contexts
|
||||
//
|
||||
if (sourceNs.equals("")) {
|
||||
this.handlerName = null;
|
||||
} else {
|
||||
// System.err.println("sourceNs: "+sourceNs);
|
||||
this.handlerName =
|
||||
JMXNamespaces.getNamespaceObjectName(this.sourceNs);
|
||||
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;
|
||||
this.targetNs = (targetNs==null?"":
|
||||
JMXNamespaces.normalizeNamespaceName(targetNs));
|
||||
this.router =
|
||||
new ObjectNameRouter(this.targetNs,this.sourceNs);
|
||||
|
||||
if (LOG.isLoggable(Level.FINER))
|
||||
LOG.finer("RoutingProxy for " + this.sourceNs + " created");
|
||||
}
|
||||
|
||||
@Override
|
||||
public T source() { return source; }
|
||||
|
||||
@Override
|
||||
public ObjectName toSource(ObjectName targetName) {
|
||||
if (targetName == null) return null;
|
||||
if (targetName.getDomain().equals("") && targetNs.equals("")) {
|
||||
try {
|
||||
if (defaultDomain == null)
|
||||
defaultDomain = getDefaultDomain();
|
||||
} catch(Exception x) {
|
||||
LOG.log(Level.FINEST,"Failed to get default domain",x);
|
||||
}
|
||||
if (defaultDomain != null)
|
||||
targetName = targetName.withDomain(defaultDomain);
|
||||
}
|
||||
return router.toSourceContext(targetName,true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectName newSourceMBeanName(ObjectName targetName)
|
||||
throws MBeanRegistrationException {
|
||||
if (targetName != null) return super.newSourceMBeanName(targetName);
|
||||
|
||||
// OK => we can accept null if sourceNs is empty.
|
||||
if (sourceNs.equals("")) return null;
|
||||
|
||||
throw new MBeanRegistrationException(
|
||||
new IllegalArgumentException(
|
||||
"Can't use null ObjectName with namespaces"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectName toTarget(ObjectName sourceName) {
|
||||
if (sourceName == null) return null;
|
||||
return router.toTargetContext(sourceName,false);
|
||||
}
|
||||
|
||||
private Object getAttributeFromHandler(String attributeName)
|
||||
throws IOException {
|
||||
|
||||
try {
|
||||
return source().getAttribute(handlerName,attributeName);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
} catch (IOException x) {
|
||||
throw x;
|
||||
} catch (MBeanException ex) {
|
||||
throw new IOException("Failed to get "+attributeName+": "+
|
||||
ex.getCause(),
|
||||
ex.getCause());
|
||||
} catch (Exception ex) {
|
||||
throw new IOException("Failed to get "+attributeName+": "+
|
||||
ex,ex);
|
||||
}
|
||||
}
|
||||
|
||||
// We cannot call getMBeanCount() on the underlying
|
||||
// MBeanServerConnection, because it would return the number of
|
||||
// 'top-level' MBeans, not the number of MBeans in the name space
|
||||
// we are narrowing to. Instead we're calling getMBeanCount() on
|
||||
// the JMXNamespace that handles the source name space.
|
||||
//
|
||||
// There is however one particular case when the sourceNs is empty.
|
||||
// In that case, there's no handler - and the 'source' is the top
|
||||
// level namespace. In that particular case, handlerName will be null,
|
||||
// and we directly invoke the top level source().
|
||||
// This later complex case is only used when implementing ClientContexts.
|
||||
//
|
||||
@Override
|
||||
public Integer getMBeanCount() throws IOException {
|
||||
try {
|
||||
if (handlerName == null) return source().getMBeanCount();
|
||||
return (Integer) getAttributeFromHandler("MBeanCount");
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// We cannot call getDomains() on the underlying
|
||||
// MBeanServerConnection, because it would return the domains of
|
||||
// 'top-level' MBeans, not the domains of MBeans in the name space
|
||||
// we are narrowing to. Instead we're calling getDomains() on
|
||||
// the JMXNamespace that handles the source name space.
|
||||
//
|
||||
// There is however one particular case when the sourceNs is empty.
|
||||
// In that case, there's no handler - and the 'source' is the top
|
||||
// level namespace. In that particular case, handlerName will be null,
|
||||
// and we directly invoke the top level source().
|
||||
// This later complex case is only used when implementing ClientContexts.
|
||||
//
|
||||
@Override
|
||||
public String[] getDomains() throws IOException {
|
||||
try {
|
||||
if (handlerName == null) return source().getDomains();
|
||||
return (String[]) getAttributeFromHandler("Domains");
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// We cannot call getDefaultDomain() on the underlying
|
||||
// MBeanServerConnection, because it would return the default domain of
|
||||
// 'top-level' namespace, not the default domain in the name space
|
||||
// we are narrowing to. Instead we're calling getDefaultDomain() on
|
||||
// the JMXNamespace that handles the source name space.
|
||||
//
|
||||
// There is however one particular case when the sourceNs is empty.
|
||||
// In that case, there's no handler - and the 'source' is the top
|
||||
// level namespace. In that particular case, handlerName will be null,
|
||||
// and we directly invoke the top level source().
|
||||
// This later complex case is only used when implementing ClientContexts.
|
||||
//
|
||||
@Override
|
||||
public String getDefaultDomain() throws IOException {
|
||||
try {
|
||||
if (handlerName == null) {
|
||||
defaultDomain = source().getDefaultDomain();
|
||||
} else {
|
||||
defaultDomain =(String)
|
||||
getAttributeFromHandler("DefaultDomain");
|
||||
}
|
||||
return defaultDomain;
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String getSourceNamespace() {
|
||||
return sourceNs;
|
||||
}
|
||||
|
||||
public String getTargetNamespace() {
|
||||
return targetNs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString()+", sourceNs="+
|
||||
sourceNs + (targetNs.equals("")?"":
|
||||
(" mounted on targetNs="+targetNs));
|
||||
}
|
||||
|
||||
// Creates an instance of a subclass 'R' of RoutingProxy<T>
|
||||
// RoutingServerProxy and RoutingConnectionProxy have their own factory
|
||||
// instance.
|
||||
static interface RoutingProxyFactory<T extends MBeanServerConnection,
|
||||
R extends RoutingProxy<T>> {
|
||||
public R newInstance(
|
||||
T source, String sourcePath, String targetPath, boolean probe);
|
||||
}
|
||||
|
||||
// Performs a narrowDownToNamespace operation.
|
||||
// This method will attempt to merge two RoutingProxies in a single
|
||||
// one if they are of the same class.
|
||||
//
|
||||
// This method is never called directly - it should be called only by
|
||||
// subclasses of RoutingProxy.
|
||||
//
|
||||
// As for now it is called by:
|
||||
// RoutingServerProxy.cd and RoutingConnectionProxy.cd.
|
||||
//
|
||||
static <T extends MBeanServerConnection, R extends RoutingProxy<T>>
|
||||
R cd(Class<R> routingProxyClass,
|
||||
RoutingProxyFactory<T,R> factory,
|
||||
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
|
||||
final R other = routingProxyClass.cast(source);
|
||||
final String target = other.getTargetNamespace();
|
||||
|
||||
// Avoid multiple layers of serialization.
|
||||
//
|
||||
// We construct a new proxy from the original source instead of
|
||||
// stacking a new proxy on top of the old one.
|
||||
// - that is we replace
|
||||
// cd ( cd ( x, dir1), dir2);
|
||||
// by
|
||||
// cd (x, dir1//dir2);
|
||||
//
|
||||
// We can do this only when the source class is exactly
|
||||
// RoutingServerProxy.
|
||||
//
|
||||
if (target == null || target.equals("")) {
|
||||
final String path =
|
||||
JMXNamespaces.concat(other.getSourceNamespace(),
|
||||
sourcePath);
|
||||
return factory.newInstance(other.source(), path, "", 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, "", probe);
|
||||
}
|
||||
}
|
@ -1,576 +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.mbeanserver.Util;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.OperationsException;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.loading.ClassLoaderRepository;
|
||||
|
||||
/**
|
||||
* A RoutingServerProxy is an MBeanServer proxy that proxies a
|
||||
* source name space in a source MBeanServer.
|
||||
* It wraps a source MBeanServer, and rewrites routing ObjectNames.
|
||||
* It is typically use for implementing 'cd' operations, and
|
||||
* will add the source name space to routing ObjectNames at input,
|
||||
* and remove it at output.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
// See class hierarchy and detailled explanations in RoutingProxy in this
|
||||
// package.
|
||||
//
|
||||
public class RoutingServerProxy
|
||||
extends RoutingProxy<MBeanServer>
|
||||
implements MBeanServer {
|
||||
|
||||
public RoutingServerProxy(MBeanServer source,
|
||||
String sourceNs,
|
||||
String targetNs,
|
||||
boolean probe) {
|
||||
super(source, sourceNs, targetNs, probe);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called each time an IOException is raised when
|
||||
* trying to forward an operation to the underlying
|
||||
* MBeanServerConnection, as a result of calling
|
||||
* {@link #getMBeanServerConnection()} or as a result of invoking the
|
||||
* operation on the returned connection.
|
||||
* Subclasses may redefine this method if they need to perform any
|
||||
* specific handling of IOException (logging etc...).
|
||||
* @param x The raised IOException.
|
||||
* @param method The name of the method in which the exception was
|
||||
* raised. This is one of the methods of the MBeanServer
|
||||
* interface.
|
||||
* @return A RuntimeException that should be thrown by the caller.
|
||||
* In this default implementation, this is an
|
||||
* {@link UndeclaredThrowableException} wrapping <var>x</var>.
|
||||
**/
|
||||
protected RuntimeException handleIOException(IOException x,
|
||||
String method) {
|
||||
return Util.newRuntimeIOException(x);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------
|
||||
//--------------------------------------------
|
||||
//
|
||||
// Implementation of the MBeanServer interface
|
||||
//
|
||||
//--------------------------------------------
|
||||
//--------------------------------------------
|
||||
@Override
|
||||
public void addNotificationListener(ObjectName name,
|
||||
NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException {
|
||||
try {
|
||||
super.addNotificationListener(name, listener,
|
||||
filter, handback);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"addNotificationListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotificationListener(ObjectName name,
|
||||
ObjectName listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException {
|
||||
try {
|
||||
super.addNotificationListener(name, listener,
|
||||
filter, handback);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"addNotificationListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name)
|
||||
throws
|
||||
ReflectionException,
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
MBeanException,
|
||||
NotCompliantMBeanException {
|
||||
try {
|
||||
return super.createMBean(className, name);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"createMBean");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
Object params[], String signature[])
|
||||
throws
|
||||
ReflectionException,
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
MBeanException,
|
||||
NotCompliantMBeanException {
|
||||
try {
|
||||
return super.createMBean(className, name,
|
||||
params, signature);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"createMBean");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className,
|
||||
ObjectName name,
|
||||
ObjectName loaderName)
|
||||
throws
|
||||
ReflectionException,
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
MBeanException,
|
||||
NotCompliantMBeanException,
|
||||
InstanceNotFoundException {
|
||||
try {
|
||||
return super.createMBean(className, name, loaderName);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"createMBean");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className,
|
||||
ObjectName name,
|
||||
ObjectName loaderName,
|
||||
Object params[],
|
||||
String signature[])
|
||||
throws
|
||||
ReflectionException,
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
MBeanException,
|
||||
NotCompliantMBeanException,
|
||||
InstanceNotFoundException {
|
||||
try {
|
||||
return super.createMBean(className, name, loaderName,
|
||||
params, signature);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"createMBean");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated see {@link MBeanServer#deserialize(ObjectName,byte[])
|
||||
* MBeanServer}
|
||||
**/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(ObjectName name, byte[] data)
|
||||
throws InstanceNotFoundException, OperationsException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return source().deserialize(sourceName,data);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated see {@link MBeanServer#deserialize(String,byte[])
|
||||
* MBeanServer}
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(String className, byte[] data)
|
||||
throws OperationsException, ReflectionException {
|
||||
try {
|
||||
return source().deserialize(className,data);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated see {@link MBeanServer#deserialize(String,ObjectName,byte[])
|
||||
* MBeanServer}
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(String className,
|
||||
ObjectName loaderName,
|
||||
byte[] data)
|
||||
throws
|
||||
InstanceNotFoundException,
|
||||
OperationsException,
|
||||
ReflectionException {
|
||||
try {
|
||||
return source().deserialize(className,loaderName,data);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(ObjectName name, String attribute)
|
||||
throws
|
||||
MBeanException,
|
||||
AttributeNotFoundException,
|
||||
InstanceNotFoundException,
|
||||
ReflectionException {
|
||||
try {
|
||||
return super.getAttribute(name, attribute);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"getAttribute");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeList getAttributes(ObjectName name, String[] attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
try {
|
||||
return super.getAttributes(name, attributes);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"getAttributes");
|
||||
}
|
||||
}
|
||||
|
||||
public ClassLoader getClassLoader(ObjectName loaderName)
|
||||
throws InstanceNotFoundException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(loaderName);
|
||||
try {
|
||||
return source().getClassLoader(sourceName);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public ClassLoader getClassLoaderFor(ObjectName mbeanName)
|
||||
throws InstanceNotFoundException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(mbeanName);
|
||||
try {
|
||||
return source().getClassLoaderFor(sourceName);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public ClassLoaderRepository getClassLoaderRepository() {
|
||||
try {
|
||||
return source().getClassLoaderRepository();
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultDomain() {
|
||||
try {
|
||||
return super.getDefaultDomain();
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"getDefaultDomain");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDomains() {
|
||||
try {
|
||||
return super.getDomains();
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"getDomains");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMBeanCount() {
|
||||
try {
|
||||
return super.getMBeanCount();
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"getMBeanCount");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MBeanInfo getMBeanInfo(ObjectName name)
|
||||
throws
|
||||
InstanceNotFoundException,
|
||||
IntrospectionException,
|
||||
ReflectionException {
|
||||
try {
|
||||
return super.getMBeanInfo(name);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"getMBeanInfo");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance getObjectInstance(ObjectName name)
|
||||
throws InstanceNotFoundException {
|
||||
try {
|
||||
return super.getObjectInstance(name);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"getObjectInstance");
|
||||
}
|
||||
}
|
||||
|
||||
public Object instantiate(String className)
|
||||
throws ReflectionException, MBeanException {
|
||||
try {
|
||||
return source().instantiate(className);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public Object instantiate(String className,
|
||||
Object params[],
|
||||
String signature[])
|
||||
throws ReflectionException, MBeanException {
|
||||
try {
|
||||
return source().instantiate(className,
|
||||
params,signature);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public Object instantiate(String className, ObjectName loaderName)
|
||||
throws ReflectionException, MBeanException,
|
||||
InstanceNotFoundException {
|
||||
final ObjectName srcLoaderName = toSourceOrRuntime(loaderName);
|
||||
try {
|
||||
return source().instantiate(className,srcLoaderName);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public Object instantiate(String className, ObjectName loaderName,
|
||||
Object params[], String signature[])
|
||||
throws ReflectionException, MBeanException,
|
||||
InstanceNotFoundException {
|
||||
final ObjectName srcLoaderName = toSourceOrRuntime(loaderName);
|
||||
try {
|
||||
return source().instantiate(className,srcLoaderName,
|
||||
params,signature);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(ObjectName name, String operationName,
|
||||
Object params[], String signature[])
|
||||
throws
|
||||
InstanceNotFoundException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
try {
|
||||
return super.invoke(name,operationName,params,signature);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"invoke");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstanceOf(ObjectName name, String className)
|
||||
throws InstanceNotFoundException {
|
||||
try {
|
||||
return super.isInstanceOf(name, className);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"isInstanceOf");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegistered(ObjectName name) {
|
||||
try {
|
||||
return super.isRegistered(name);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"isRegistered");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
|
||||
try {
|
||||
return super.queryMBeans(name, query);
|
||||
} catch (IOException x) {
|
||||
handleIOException(x,"queryMBeans");
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
|
||||
try {
|
||||
return super.queryNames(name, query);
|
||||
} catch (IOException x) {
|
||||
handleIOException(x,"queryNames");
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectInstance registerMBean(Object object, ObjectName name)
|
||||
throws
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
NotCompliantMBeanException {
|
||||
final ObjectName sourceName = newSourceMBeanName(name);
|
||||
try {
|
||||
return processOutputInstance(
|
||||
source().registerMBean(object,sourceName));
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
super.removeNotificationListener(name, listener);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"removeNotificationListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
super.removeNotificationListener(name, listener,
|
||||
filter, handback);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"removeNotificationListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
ObjectName listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
super.removeNotificationListener(name, listener);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"removeNotificationListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
ObjectName listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
super.removeNotificationListener(name, listener,
|
||||
filter, handback);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"removeNotificationListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(ObjectName name, Attribute attribute)
|
||||
throws
|
||||
InstanceNotFoundException,
|
||||
AttributeNotFoundException,
|
||||
InvalidAttributeValueException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
try {
|
||||
super.setAttribute(name, attribute);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"setAttribute");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeList setAttributes(ObjectName name,
|
||||
AttributeList attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
try {
|
||||
return super.setAttributes(name, attributes);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"setAttributes");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterMBean(ObjectName name)
|
||||
throws InstanceNotFoundException, MBeanRegistrationException {
|
||||
try {
|
||||
super.unregisterMBean(name);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"unregisterMBean");
|
||||
}
|
||||
}
|
||||
|
||||
static final RoutingProxyFactory<MBeanServer,RoutingServerProxy>
|
||||
FACTORY = new RoutingProxyFactory<MBeanServer,RoutingServerProxy>() {
|
||||
|
||||
public RoutingServerProxy newInstance(MBeanServer source,
|
||||
String sourcePath, String targetPath, boolean probe) {
|
||||
return new RoutingServerProxy(
|
||||
source, sourcePath, targetPath, probe);
|
||||
}
|
||||
};
|
||||
|
||||
public static MBeanServer cd(
|
||||
MBeanServer source, String sourcePath, boolean probe) {
|
||||
return RoutingProxy.cd(RoutingServerProxy.class, FACTORY,
|
||||
source, sourcePath, probe);
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>The <code>com.sun.jmx.namespace</code> package</title>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
<p>The <code>com.sun.jmx.namespace</code> package contains
|
||||
sun specific implementation classes used to implement the
|
||||
JMX namespaces.
|
||||
</p>
|
||||
<p><b>DO NOT USE THESE CLASSES DIRECTLY</b></p>
|
||||
<p><b>
|
||||
This API is a Sun internal API and is subject to changes without notice.
|
||||
</b></p>
|
||||
<p>The public API through wich these proprietary classes can be
|
||||
invoked is located in <code>javax.management.namespace</code>
|
||||
package.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
@ -1,150 +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.serial;
|
||||
|
||||
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* Class DefaultRewritingProcessor. Rewrite ObjectName in input & output
|
||||
* parameters.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
// We know that rewriting using serialization is costly.
|
||||
// This object tries to determine whether an object needs rewriting prior
|
||||
// to rewriting, and rewrites by creating a new object in those cases
|
||||
// where we know how to recreate a new object (e.g. a Notification).
|
||||
// Rewriting is however usually not used - so this object is just a
|
||||
// skeleton that eventually uses serialization...
|
||||
//
|
||||
class DefaultRewritingProcessor extends RewritingProcessor {
|
||||
|
||||
|
||||
private static enum RewriteMode {
|
||||
INPUT, // Input from target to source (parameters)
|
||||
OUTPUT // Output from source to target (results)
|
||||
};
|
||||
|
||||
private final boolean identity;
|
||||
|
||||
public DefaultRewritingProcessor(String targetDirName) {
|
||||
this(targetDirName,null);
|
||||
}
|
||||
|
||||
/** Creates a new instance of SerialParamProcessor */
|
||||
public DefaultRewritingProcessor(final String remove, final String add) {
|
||||
super(new SerialRewritingProcessor(remove, add));
|
||||
identity = remove.equals(add);
|
||||
}
|
||||
|
||||
private ObjectName rewriteObjectName(RewriteMode mode,
|
||||
ObjectName name) {
|
||||
return changeContext(mode, name);
|
||||
}
|
||||
|
||||
private ObjectInstance rewriteObjectInstance(RewriteMode mode,
|
||||
ObjectInstance moi) {
|
||||
final ObjectName srcName = moi.getObjectName();
|
||||
final ObjectName targetName = changeContext(mode,srcName);
|
||||
if (targetName == srcName) return moi;
|
||||
return new ObjectInstance(targetName,moi.getClassName());
|
||||
}
|
||||
|
||||
|
||||
private Object processObject(RewriteMode mode, Object obj) {
|
||||
if (obj == null) return null;
|
||||
|
||||
// Some things which will always needs rewriting:
|
||||
// ObjectName, ObjectInstance, and Notifications.
|
||||
// Take care of those we can handle here...
|
||||
//
|
||||
if (obj instanceof ObjectName)
|
||||
return rewriteObjectName(mode,(ObjectName) obj);
|
||||
else if (obj instanceof ObjectInstance)
|
||||
return rewriteObjectInstance(mode,(ObjectInstance) obj);
|
||||
|
||||
// TODO: add other standard JMX classes - like e.g. MBeanInfo...
|
||||
//
|
||||
|
||||
// Well, the object may contain an ObjectName => pass it to
|
||||
// our serial rewriting delegate...
|
||||
//
|
||||
return processAnyObject(mode,obj);
|
||||
}
|
||||
|
||||
|
||||
private Object processAnyObject(RewriteMode mode, Object obj) {
|
||||
switch (mode) {
|
||||
case INPUT:
|
||||
return super.rewriteInput(obj);
|
||||
case OUTPUT:
|
||||
return super.rewriteOutput(obj);
|
||||
default: // can't happen.
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private ObjectName changeContext(RewriteMode mode, ObjectName name) {
|
||||
switch (mode) {
|
||||
case INPUT:
|
||||
return toSourceContext(name);
|
||||
case OUTPUT:
|
||||
return toTargetContext(name);
|
||||
default: // can't happen.
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectName toTargetContext(ObjectName srcName) {
|
||||
if (identity) return srcName;
|
||||
return super.toTargetContext(srcName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectName toSourceContext(ObjectName targetName) {
|
||||
if (identity) return targetName;
|
||||
return super.toSourceContext(targetName);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T rewriteInput(T input) {
|
||||
if (identity) return input;
|
||||
return (T) processObject(RewriteMode.INPUT,input);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T rewriteOutput(T result) {
|
||||
if (identity) return result;
|
||||
return (T) processObject(RewriteMode.OUTPUT,result);
|
||||
}
|
||||
}
|
@ -1,145 +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.serial;
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* The JMXNamespaceContext class is used to implement a thread local
|
||||
* serialization / deserialization context for namespaces.
|
||||
* <p>
|
||||
* This class is consulted by {@link javax.management.ObjectName} at
|
||||
* serialization / deserialization time.
|
||||
* The serialization or deserialization context is established by
|
||||
* by the {@link SerialRewritingProcessor} defined in this package.
|
||||
* <p>
|
||||
* These classes are Sun proprietary APIs, subject to change without
|
||||
* notice. Do not use these classes directly.
|
||||
* The public API to rewrite ObjectNames embedded in parameters is
|
||||
* defined in {@link javax.management.namespace.JMXNamespaces}.
|
||||
*
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public class JMXNamespaceContext {
|
||||
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
public final String prefixToRemove;
|
||||
public final String prefixToAdd;
|
||||
|
||||
private JMXNamespaceContext(String add, String remove) {
|
||||
prefixToRemove = (remove==null?"":remove);
|
||||
prefixToAdd = (add==null?"":add);
|
||||
}
|
||||
|
||||
private final static class SerialContext {
|
||||
private JMXNamespaceContext serializationContext;
|
||||
private JMXNamespaceContext deserializationContext;
|
||||
public SerialContext(){
|
||||
serializationContext = new JMXNamespaceContext("","");
|
||||
deserializationContext = new JMXNamespaceContext("","");
|
||||
}
|
||||
}
|
||||
|
||||
private final static ThreadLocal<SerialContext> prefix =
|
||||
new ThreadLocal<SerialContext>() {
|
||||
@Override
|
||||
protected SerialContext initialValue() {
|
||||
return new SerialContext();
|
||||
}
|
||||
};
|
||||
|
||||
public static JMXNamespaceContext getSerializationContext() {
|
||||
return prefix.get().serializationContext;
|
||||
}
|
||||
|
||||
public static JMXNamespaceContext getDeserializationContext() {
|
||||
return prefix.get().deserializationContext;
|
||||
}
|
||||
|
||||
private static String[] setSerializationContext(String oldPrefix,
|
||||
String newPrefix) {
|
||||
final SerialContext c = prefix.get();
|
||||
JMXNamespaceContext dc = c.serializationContext;
|
||||
String[] old = {dc.prefixToRemove, dc.prefixToAdd};
|
||||
c.serializationContext = new JMXNamespaceContext(newPrefix,oldPrefix);
|
||||
return old;
|
||||
}
|
||||
|
||||
private static String[] setDeserializationContext(String oldPrefix,
|
||||
String newPrefix) {
|
||||
final SerialContext c = prefix.get();
|
||||
JMXNamespaceContext dc = c.deserializationContext;
|
||||
String[] old = {dc.prefixToRemove, dc.prefixToAdd};
|
||||
c.deserializationContext = new JMXNamespaceContext(newPrefix,oldPrefix);
|
||||
return old;
|
||||
}
|
||||
|
||||
static void serialize(ObjectOutputStream stream, Object obj,
|
||||
String prefixToRemove, String prefixToAdd)
|
||||
throws IOException {
|
||||
final String[] old =
|
||||
setSerializationContext(prefixToRemove,prefixToAdd);
|
||||
try {
|
||||
stream.writeObject(obj);
|
||||
} finally {
|
||||
try {
|
||||
setSerializationContext(old[0],old[1]);
|
||||
} catch (Exception x) {
|
||||
LOG.log(Level.FINEST,
|
||||
"failed to restore serialization context",x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Object deserialize(ObjectInputStream stream,
|
||||
String prefixToRemove,
|
||||
String prefixToAdd)
|
||||
throws IOException, ClassNotFoundException {
|
||||
final String[] old =
|
||||
setDeserializationContext(prefixToRemove,prefixToAdd);
|
||||
try {
|
||||
return stream.readObject();
|
||||
} finally {
|
||||
try {
|
||||
setDeserializationContext(old[0],old[1]);
|
||||
} catch (Exception x) {
|
||||
LOG.log(Level.FINEST,
|
||||
"failed to restore serialization context",x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,362 +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.serial;
|
||||
|
||||
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* An object that can rewrite ObjectNames contained in input/output
|
||||
* parameters when entering/leaving a {@link javax.management.namespace
|
||||
* namespace}.
|
||||
* <p>When entering a {@link javax.management.namespace
|
||||
* namespace}, the {@code namespace} prefix is stripped from
|
||||
* ObjectNames contained in input parameters. When leaving a
|
||||
* {@code namespace},
|
||||
* the {@code namespace} prefix is prepended to the ObjectNames contained in
|
||||
* the result parameters returned from that {@code namespace}.
|
||||
* </p>
|
||||
* <p>Objects that need to perform these operations usually use a
|
||||
* {@code RewritingProcessor} for that purpose.<br>
|
||||
* The {@code RewritingProcessor} allows a somewhat larger
|
||||
* transformation in which part of a prefix {@link #newRewritingProcessor
|
||||
* remove} can be replaced by another prefix {@link #newRewritingProcessor
|
||||
* add}. The transformation described above correspond to the case where
|
||||
* {@code remove} is the stripped {@link javax.management.namespace
|
||||
* namespace} prefix (removed when entering the {@code namespace}) and
|
||||
* {@code add} is the empty String {@code ""}.
|
||||
* <br>
|
||||
* It is interesting to note that {@link
|
||||
* javax.management.JMXNamespaces#narrowToNamespace narrowToNamespace}
|
||||
* operations use the inverse transformation (that is, {@code remove} is
|
||||
* the empty String {@code ""} and {@code add} is the {@link
|
||||
* javax.management.namespace namespace} prefix).
|
||||
* <br>
|
||||
* On a more general scale, {@link #rewriteInput rewriteInput} removes
|
||||
* {@link #newRewritingProcessor remove} and the prepend {@link
|
||||
* #newRewritingProcessor add}, and {@link #rewriteOutput rewriteOutput}
|
||||
* does the opposite, removing {@link #newRewritingProcessor add}, and
|
||||
* then adding {@link #newRewritingProcessor remove}.
|
||||
* <br>
|
||||
* An implementation of {@code RewritingProcessor} should make sure that
|
||||
* <code>rewriteInput(rewriteOutput(x,clp),clp)</code> and
|
||||
* <code>rewriteOutput(rewriteInput(x,clp),clp)</code> always return
|
||||
* {@code x} or an exact clone of {@code x}.
|
||||
* </p>
|
||||
* <p>A default implementation of {@code RewritingProcessor} based on
|
||||
* Java Object Serialization can be
|
||||
* obtained from {@link #newRewritingProcessor newRewritingProcessor}.
|
||||
* </p>
|
||||
* <p>
|
||||
* By default, the instances of {@code RewritingProcessor} returned by
|
||||
* {@link #newRewritingProcessor newRewritingProcessor} will rewrite
|
||||
* ObjectNames contained in instances of classes they don't know about by
|
||||
* serializing and then deserializing such object instances. This will
|
||||
* happen even if such instances don't - or can't contain ObjectNames,
|
||||
* because the default implementation of {@code RewritingProcessor} will
|
||||
* not be able to determine whether instances of such classes can/do contain
|
||||
* instance of ObjectNames before serializing/deserializing them.
|
||||
* </p>
|
||||
* <p>If you are using custom classes that the default implementation of
|
||||
* {@code RewritingProcessor} don't know about, it can be interesting to
|
||||
* prevent an instance of {@code RewritingProcessor} to serialize/deserialize
|
||||
* instances of such classes for nothing. In that case, you could customize
|
||||
* the behavior of such a {@code RewritingProcessor} by wrapping it in a
|
||||
* custom subclass of {@code RewritingProcessor} as shown below:
|
||||
* <pre>
|
||||
* public class MyRewritingProcessor extends RewritingProcessor {
|
||||
* MyRewritingProcessor(String remove, String add) {
|
||||
* this(RewritingProcessor.newRewritingProcessor(remove,add));
|
||||
* }
|
||||
* MyRewritingProcessor(RewritingProcessor delegate) {
|
||||
* super(delegate);
|
||||
* }
|
||||
*
|
||||
* <T> T rewriteInput(T input) {
|
||||
* if (input == null) return null;
|
||||
* if (MyClass.equals(input.getClass())) {
|
||||
* // I know that MyClass doesn't contain any ObjectName
|
||||
* return (T) input;
|
||||
* }
|
||||
* return super.rewriteInput(input);
|
||||
* }
|
||||
* <T> T rewriteOutput(T result) {
|
||||
* if (result == null) return null;
|
||||
* if (MyClass.equals(result.getClass())) {
|
||||
* // I know that MyClass doesn't contain any ObjectName
|
||||
* return (T) result;
|
||||
* }
|
||||
* return super.rewriteOutput(result);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* </p>
|
||||
* <p>Such a subclass may also provide an alternate way of rewriting
|
||||
* custom subclasses for which rewriting is needed - for instance:
|
||||
* <pre>
|
||||
* public class MyRewritingProcessor extends RewritingProcessor {
|
||||
* MyRewritingProcessor(String remove, String add) {
|
||||
* this(RewritingProcessor.newRewritingProcessor(remove,add));
|
||||
* }
|
||||
* MyRewritingProcessor(RewritingProcessor delegate) {
|
||||
* super(delegate);
|
||||
* }
|
||||
*
|
||||
* <T> T rewriteInput(T input) {
|
||||
* if (input == null) return null;
|
||||
* if (MyClass.equals(input.getClass())) {
|
||||
* // I know that MyClass doesn't contain any ObjectName
|
||||
* return (T) input;
|
||||
* } else if (MyOtherClass.equals(input.getClass())) {
|
||||
* // Returns a new instance in which ObjectNames have been
|
||||
* // replaced.
|
||||
* final ObjectName aname = ((MyOtherClass)input).getName();
|
||||
* return (T) (new MyOtherClass(super.rewriteInput(aname)));
|
||||
* }
|
||||
* return super.rewriteInput(input,clp);
|
||||
* }
|
||||
* <T> T rewriteOutput(T result) {
|
||||
* if (result == null) return null;
|
||||
* if (MyClass.equals(result.getClass())) {
|
||||
* // I know that MyClass doesn't contain any ObjectName
|
||||
* return (T) result;
|
||||
* } else if (MyOtherClass.equals(result.getClass())) {
|
||||
* // Returns a new instance in which ObjectNames have been
|
||||
* // replaced.
|
||||
* final ObjectName aname = ((MyOtherClass)result).getName();
|
||||
* return (T) (new MyOtherClass(super.rewriteOutput(aname)));
|
||||
* }
|
||||
* return super.rewriteOutput(result,clp);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* </p>
|
||||
* <p>If your application only uses {@link javax.management.MXBean MXBeans},
|
||||
* or MBeans using simple types, and doesn't define any custom subclass of
|
||||
* {@link javax.management.Notification}, you should never write such
|
||||
* such {@code RewitingProcessor} implementations.
|
||||
* </p>
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public abstract class RewritingProcessor {
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private final RewritingProcessor delegate;
|
||||
|
||||
/**
|
||||
* Creates a new instance of RewritingProcessor.
|
||||
* <p>This is equivalent to calling {@link
|
||||
* #RewritingProcessor(RewritingProcessor) RewritingProcessor(null)}.
|
||||
* </p>
|
||||
**/
|
||||
protected RewritingProcessor() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of RewritingProcessor, with a delegate.
|
||||
* @param delegate a {@code RewritingProcessor} to which all the
|
||||
* calls will be delegated. When implementing a subclass
|
||||
* of {@code RewritingProcessor}, calling {@link
|
||||
* #rewriteInput super.rewriteInput} will invoke
|
||||
* {@code delegate.rewriteInput} and calling {@link
|
||||
* #rewriteOutput super.rewriteOutput} will invoke
|
||||
* {@code delegate.rewriteOutput}.
|
||||
*
|
||||
**/
|
||||
protected RewritingProcessor(RewritingProcessor delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrites ObjectNames when {@link RewritingProcessor leaving} a {@link
|
||||
* javax.management.namespace namespace}.
|
||||
* <p>
|
||||
* Returns {@code obj}, if it is known that {@code obj} doesn't contain
|
||||
* any ObjectName, or a new copied instance of {@code obj} in which
|
||||
* ObjectNames (if any) will have been rewritten, if {@code obj} contains
|
||||
* ObjectNames, or if it is not known whether {@code obj} contains
|
||||
* ObjectNames or not.
|
||||
* </p>
|
||||
* <p>
|
||||
* The default implementation of this method is as follows: if the
|
||||
* {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code
|
||||
* null}, throws an {@link IllegalArgumentException}. Otherwise,
|
||||
* returns {@code delegate.rewriteOutput(obj)}.
|
||||
* </p>
|
||||
* <p>This behavior can be overridden by subclasses as shown in this
|
||||
* class {@link RewritingProcessor description}.
|
||||
* </p>
|
||||
* @param obj The result to be rewritten if needed.
|
||||
*
|
||||
* @return {@code obj}, or a clone of {@code obj} in which ObjectNames
|
||||
* have been rewritten. See this class {@link RewritingProcessor
|
||||
* description} for more details.
|
||||
* @throws IllegalArgumentException if this implementation does not know
|
||||
* how to rewrite the object.
|
||||
**/
|
||||
public <T> T rewriteOutput(T obj) {
|
||||
if (obj == null) return null;
|
||||
if (delegate != null)
|
||||
return delegate.rewriteOutput(obj);
|
||||
throw new IllegalArgumentException("can't rewrite "+
|
||||
obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrites ObjectNames when {@link RewritingProcessor entering} a {@link
|
||||
* javax.management.namespace namespace}.
|
||||
* <p>
|
||||
* Returns {@code obj}, if it is known that {@code obj} doesn't contain
|
||||
* any ObjectName, or a new copied instance of {@code obj} in which
|
||||
* ObjectNames (if any) will have been rewritten, if {@code obj} contains
|
||||
* ObjectNames, or if it is not known whether {@code obj} contains
|
||||
* ObjectNames or not.
|
||||
* </p>
|
||||
* <p>
|
||||
* The default implementation of this method is as follows: if the
|
||||
* {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code
|
||||
* null}, throws an {@link IllegalArgumentException}. Otherwise,
|
||||
* returns {@code delegate.rewriteInput(obj)}.
|
||||
* </p>
|
||||
* <p>This behavior can be overridden by subclasses as shown in this
|
||||
* class {@link RewritingProcessor description}.
|
||||
* </p>
|
||||
* @param obj The result to be rewritten if needed.
|
||||
* @return {@code obj}, or a clone of {@code obj} in which ObjectNames
|
||||
* have been rewritten. See this class {@link RewritingProcessor
|
||||
* description} for more details.
|
||||
* @throws IllegalArgumentException if this implementation does not know
|
||||
* how to rewrite the object.
|
||||
**/
|
||||
public <T> T rewriteInput(T obj) {
|
||||
if (obj == null) return null;
|
||||
if (delegate != null)
|
||||
return delegate.rewriteInput(obj);
|
||||
throw new IllegalArgumentException("can't rewrite "+
|
||||
obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a routing ObjectName from the target (calling) context to
|
||||
* the source (called) context when {@link RewritingProcessor entering} a
|
||||
* {@link javax.management.namespace namespace}.
|
||||
* <p>
|
||||
* The default implementation of this method is as follows: if the
|
||||
* {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code
|
||||
* null}, throws an {@link IllegalArgumentException}. Otherwise,
|
||||
* returns {@code delegate.toSourceContext(targetName)}.
|
||||
* </p>
|
||||
* <p>This behavior can be overridden by subclasses as shown in this
|
||||
* class {@link RewritingProcessor description}.
|
||||
* </p>
|
||||
* @param targetName The routing target ObjectName to translate.
|
||||
* @return The ObjectName translated to the source context.
|
||||
* @throws IllegalArgumentException if this implementation does not know
|
||||
* how to rewrite the object.
|
||||
**/
|
||||
public ObjectName toSourceContext(ObjectName targetName) {
|
||||
if (delegate != null)
|
||||
return delegate.toSourceContext(targetName);
|
||||
throw new IllegalArgumentException("can't rewrite targetName: "+
|
||||
" no delegate.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate an ObjectName returned from the source context into
|
||||
* the target (calling) context when {@link RewritingProcessor leaving} a
|
||||
* {@link javax.management.namespace namespace}.
|
||||
* <p>
|
||||
* The default implementation of this method is as follows: if the
|
||||
* {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code
|
||||
* null}, throws an {@link IllegalArgumentException}. Otherwise,
|
||||
* returns {@code delegate.toTargetContext(sourceName)}.
|
||||
* </p>
|
||||
* <p>This behavior can be overridden by subclasses as shown in this
|
||||
* class {@link RewritingProcessor description}.
|
||||
* </p>
|
||||
* @param sourceName The routing source ObjectName to translate to the
|
||||
* target context.
|
||||
* @return The ObjectName translated to the target context.
|
||||
* @throws IllegalArgumentException if this implementation does not know
|
||||
* how to rewrite the object.
|
||||
**/
|
||||
public ObjectName toTargetContext(ObjectName sourceName) {
|
||||
if (delegate != null)
|
||||
return delegate.toTargetContext(sourceName);
|
||||
throw new IllegalArgumentException("can't rewrite sourceName: "+
|
||||
" no delegate.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate an ObjectInstance returned from the source context into
|
||||
* the target (calling) context when {@link RewritingProcessor leaving} a
|
||||
* {@link javax.management.namespace namespace}.
|
||||
* <p>
|
||||
* The default implementation of this method is as follows: if the
|
||||
* {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code
|
||||
* null}, throws an {@link IllegalArgumentException}. Otherwise,
|
||||
* returns {@code delegate.toTargetContext(sourceMoi)}.
|
||||
* </p>
|
||||
* <p>This behavior can be overridden by subclasses as shown in this
|
||||
* class {@link RewritingProcessor description}.
|
||||
* </p>
|
||||
* @param sourceMoi The routing source ObjectInstance to translate.
|
||||
* @return The ObjectInstance translated to the target context.
|
||||
* @throws IllegalArgumentException if this implementation does not know
|
||||
* how to rewrite the object.
|
||||
**/
|
||||
public ObjectInstance toTargetContext(ObjectInstance sourceMoi) {
|
||||
if (delegate != null)
|
||||
return delegate.toTargetContext(sourceMoi);
|
||||
throw new IllegalArgumentException("can't rewrite sourceName: "+
|
||||
" no delegate.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new default instance of {@link RewritingProcessor}.
|
||||
* @param remove The prefix to remove from {@link ObjectName ObjectNames}
|
||||
* when {@link RewritingProcessor entering} the {@link
|
||||
* javax.management.namespace namespace}.
|
||||
* @param add The prefix to add to {@link ObjectName ObjectNames}
|
||||
* when {@link RewritingProcessor entering} the {@link
|
||||
* javax.management.namespace namespace} (this is performed
|
||||
* after having removed the {@code remove} prefix.
|
||||
* @return A new {@link RewritingProcessor} processor object that will
|
||||
* perform the requested operation, using Java serialization if
|
||||
* necessary.
|
||||
**/
|
||||
public static RewritingProcessor newRewritingProcessor(String remove,
|
||||
String add) {
|
||||
return new DefaultRewritingProcessor(remove,add);
|
||||
}
|
||||
|
||||
}
|
@ -1,74 +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.serial;
|
||||
|
||||
import com.sun.jmx.namespace.ObjectNameRouter;
|
||||
|
||||
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* Class RoutingOnlyProcessor. A RewritingProcessor that uses
|
||||
* Java Serialization to rewrite ObjectNames contained in
|
||||
* input and results...
|
||||
*
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
class RoutingOnlyProcessor extends RewritingProcessor {
|
||||
|
||||
final ObjectNameRouter router;
|
||||
|
||||
public RoutingOnlyProcessor(String targetDirName) {
|
||||
this(targetDirName,null);
|
||||
}
|
||||
|
||||
/** Creates a new instance of RoutingOnlyProcessor */
|
||||
public RoutingOnlyProcessor(final String remove, final String add) {
|
||||
super(new IdentityProcessor());
|
||||
if (remove == null || add == null)
|
||||
throw new IllegalArgumentException("Null argument");
|
||||
router = new ObjectNameRouter(remove,add);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ObjectName toTargetContext(ObjectName sourceName) {
|
||||
return router.toTargetContext(sourceName,false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ObjectName toSourceContext(ObjectName targetName) {
|
||||
return router.toSourceContext(targetName,false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ObjectInstance toTargetContext(ObjectInstance sourceMoi) {
|
||||
return router.toTargetContext(sourceMoi,false);
|
||||
}
|
||||
}
|
@ -1,172 +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.serial;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InvalidClassException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.io.OutputStream;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* Class SerialRewritingProcessor. A RewritingProcessor that uses
|
||||
* Java Serialization to rewrite ObjectNames contained in
|
||||
* input & results...
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
class SerialRewritingProcessor extends RewritingProcessor {
|
||||
|
||||
|
||||
private static class CloneOutput extends ObjectOutputStream {
|
||||
Queue<Class<?>> classQueue = new LinkedList<Class<?>>();
|
||||
|
||||
CloneOutput(OutputStream out) throws IOException {
|
||||
super(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void annotateClass(Class<?> c) {
|
||||
classQueue.add(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void annotateProxyClass(Class<?> c) {
|
||||
classQueue.add(c);
|
||||
}
|
||||
}
|
||||
|
||||
private static class CloneInput extends ObjectInputStream {
|
||||
private final CloneOutput output;
|
||||
|
||||
CloneInput(InputStream in, CloneOutput output) throws IOException {
|
||||
super(in);
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> resolveClass(ObjectStreamClass osc)
|
||||
throws IOException, ClassNotFoundException {
|
||||
Class<?> c = output.classQueue.poll();
|
||||
String expected = osc.getName();
|
||||
String found = (c == null) ? null : c.getName();
|
||||
if (!expected.equals(found)) {
|
||||
throw new InvalidClassException("Classes desynchronized: " +
|
||||
"found " + found + " when expecting " + expected);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> resolveProxyClass(String[] interfaceNames)
|
||||
throws IOException, ClassNotFoundException {
|
||||
return output.classQueue.poll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final String targetPrefix;
|
||||
final String sourcePrefix;
|
||||
final boolean identity;
|
||||
|
||||
|
||||
public SerialRewritingProcessor(String targetDirName) {
|
||||
this(targetDirName,null);
|
||||
}
|
||||
|
||||
/** Creates a new instance of SerialRewritingProcessor */
|
||||
public SerialRewritingProcessor(final String remove, final String add) {
|
||||
super(new RoutingOnlyProcessor(remove,add));
|
||||
this.targetPrefix = remove;
|
||||
this.sourcePrefix = add;
|
||||
identity = targetPrefix.equals(sourcePrefix);
|
||||
}
|
||||
|
||||
private <T> T switchContext(T result, String from,String to)
|
||||
throws IOException, ClassNotFoundException {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
final CloneOutput ostream = new CloneOutput(baos);
|
||||
|
||||
JMXNamespaceContext.serialize(ostream,result,from,null);
|
||||
ostream.flush();
|
||||
|
||||
final byte[] bytes = baos.toByteArray();
|
||||
final ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||
final CloneInput istream = new CloneInput(bais, ostream);
|
||||
@SuppressWarnings("unchecked")
|
||||
final T clone = (T) JMXNamespaceContext.deserialize(istream,null,to);
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T rewriteOutput(T result) {
|
||||
if (identity) return result;
|
||||
return (T) processOutput(result);
|
||||
}
|
||||
|
||||
private Object processOutput(Object result) {
|
||||
try {
|
||||
if (result instanceof ObjectName)
|
||||
return toTargetContext((ObjectName) result);
|
||||
return switchContext(result,sourcePrefix,targetPrefix);
|
||||
} catch (ClassNotFoundException x) {
|
||||
throw new IllegalArgumentException("Can't process result: "+x,x);
|
||||
} catch (IOException x) {
|
||||
throw new IllegalArgumentException("Can't process result: "+x,x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T rewriteInput(T input) {
|
||||
if (identity) return input;
|
||||
return (T) processInput(input);
|
||||
}
|
||||
|
||||
private Object processInput(Object input) {
|
||||
try {
|
||||
if (input instanceof ObjectName)
|
||||
return toSourceContext((ObjectName) input);
|
||||
return switchContext(input,targetPrefix,sourcePrefix);
|
||||
} catch (ClassNotFoundException x) {
|
||||
throw new IllegalArgumentException("Can't process input: "+x,x);
|
||||
} catch (IOException x) {
|
||||
throw new IllegalArgumentException("Can't process input: "+x,x);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>The <code>com.sun.jmx.namespace.serial</code> package</title>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
<p>The <code>com.sun.jmx.namespace.serial</code> package contains
|
||||
sun specific implementation classes used to switch namespace
|
||||
prefixes in ObjectName during serialization.
|
||||
</p>
|
||||
<p><b>NEVER USE THESE CLASSES DIRECTLY</b></p>
|
||||
<p><b>
|
||||
This API is a Sun internal API and is subject to changes without notice.
|
||||
</b></p>
|
||||
<p>The public API through which these proprietary classes can be invoked is
|
||||
located in <code>javax.management.namespace.JMXNamespaces</code>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright 2009 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.remote.internal;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.NoSuchObjectException;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.NoSuchObjectException;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* A helper class for RMI-IIOP and CORBA APIs.
|
||||
*/
|
||||
|
||||
public final class IIOPHelper {
|
||||
private IIOPHelper() { }
|
||||
|
||||
// loads IIOPProxy implementation class if available
|
||||
private static final String IMPL_CLASS =
|
||||
"com.sun.jmx.remote.protocol.iiop.IIOPProxyImpl";
|
||||
private static final IIOPProxy proxy =
|
||||
AccessController.doPrivileged(new PrivilegedAction<IIOPProxy>() {
|
||||
public IIOPProxy run() {
|
||||
try {
|
||||
Class<?> c = Class.forName(IMPL_CLASS, true, null);
|
||||
return (IIOPProxy)c.newInstance();
|
||||
} catch (ClassNotFoundException cnf) {
|
||||
return null;
|
||||
} catch (InstantiationException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}});
|
||||
|
||||
/**
|
||||
* Returns true if RMI-IIOP and CORBA is available.
|
||||
*/
|
||||
public static boolean isAvailable() {
|
||||
return proxy != null;
|
||||
}
|
||||
|
||||
private static void ensureAvailable() {
|
||||
if (proxy == null)
|
||||
throw new AssertionError("Should not here");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given object is a Stub.
|
||||
*/
|
||||
public static boolean isStub(Object obj) {
|
||||
return (proxy == null) ? false : proxy.isStub(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Delegate to which the given Stub delegates.
|
||||
*/
|
||||
public static Object getDelegate(Object stub) {
|
||||
ensureAvailable();
|
||||
return proxy.getDelegate(stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Delegate for a given Stub.
|
||||
*/
|
||||
public static void setDelegate(Object stub, Object delegate) {
|
||||
ensureAvailable();
|
||||
proxy.setDelegate(stub, delegate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ORB associated with the given stub
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* if the object does not support the operation that
|
||||
* was invoked
|
||||
*/
|
||||
public static Object getOrb(Object stub) {
|
||||
ensureAvailable();
|
||||
return proxy.getOrb(stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects the Stub to the given ORB.
|
||||
*/
|
||||
public static void connect(Object stub, Object orb)
|
||||
throws RemoteException
|
||||
{
|
||||
ensureAvailable();
|
||||
proxy.connect(stub, orb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given object is an ORB.
|
||||
*/
|
||||
public static boolean isOrb(Object obj) {
|
||||
ensureAvailable();
|
||||
return proxy.isOrb(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates, and returns, a new ORB instance.
|
||||
*/
|
||||
public static Object createOrb(String[] args, Properties props) {
|
||||
ensureAvailable();
|
||||
return proxy.createOrb(args, props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string, produced by the object_to_string method, back
|
||||
* to a CORBA object reference.
|
||||
*/
|
||||
public static Object stringToObject(Object orb, String str) {
|
||||
ensureAvailable();
|
||||
return proxy.stringToObject(orb, str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given CORBA object reference to a string.
|
||||
*/
|
||||
public static String objectToString(Object orb, Object obj) {
|
||||
ensureAvailable();
|
||||
return proxy.objectToString(orb, obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to ensure that an object of a remote or abstract interface
|
||||
* type can be cast to a desired type.
|
||||
*/
|
||||
public static <T> T narrow(Object narrowFrom, Class<T> narrowTo) {
|
||||
ensureAvailable();
|
||||
return proxy.narrow(narrowFrom, narrowTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a server object ready to receive remote calls
|
||||
*/
|
||||
public static void exportObject(Remote obj) throws RemoteException {
|
||||
ensureAvailable();
|
||||
proxy.exportObject(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deregisters a server object from the runtime.
|
||||
*/
|
||||
public static void unexportObject(Remote obj) throws NoSuchObjectException {
|
||||
ensureAvailable();
|
||||
proxy.unexportObject(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stub for the given server object.
|
||||
*/
|
||||
public static Remote toStub(Remote obj) throws NoSuchObjectException {
|
||||
ensureAvailable();
|
||||
return proxy.toStub(obj);
|
||||
}
|
||||
}
|
110
jdk/src/share/classes/com/sun/jmx/remote/internal/IIOPProxy.java
Normal file
110
jdk/src/share/classes/com/sun/jmx/remote/internal/IIOPProxy.java
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2009 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.remote.internal;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.NoSuchObjectException;
|
||||
|
||||
/**
|
||||
* An interface to a subset of the RMI-IIOP and CORBA APIs to avoid a
|
||||
* static dependencies on the types defined by these APIs.
|
||||
*/
|
||||
|
||||
public interface IIOPProxy {
|
||||
|
||||
/**
|
||||
* Returns true if the given object is a Stub.
|
||||
*/
|
||||
boolean isStub(Object obj);
|
||||
|
||||
/**
|
||||
* Returns the Delegate to which the given Stub delegates.
|
||||
*/
|
||||
Object getDelegate(Object stub);
|
||||
|
||||
/**
|
||||
* Sets the Delegate for a given Stub.
|
||||
*/
|
||||
void setDelegate(Object stub, Object delegate);
|
||||
|
||||
/**
|
||||
* Returns the ORB associated with the given stub
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* if the object does not support the operation that
|
||||
* was invoked
|
||||
*/
|
||||
Object getOrb(Object stub);
|
||||
|
||||
/**
|
||||
* Connects the Stub to the given ORB.
|
||||
*/
|
||||
void connect(Object stub, Object orb) throws RemoteException;
|
||||
|
||||
/**
|
||||
* Returns true if the given object is an ORB.
|
||||
*/
|
||||
boolean isOrb(Object obj);
|
||||
|
||||
/**
|
||||
* Creates, and returns, a new ORB instance.
|
||||
*/
|
||||
Object createOrb(String[] args, Properties props);
|
||||
|
||||
/**
|
||||
* Converts a string, produced by the object_to_string method, back
|
||||
* to a CORBA object reference.
|
||||
*/
|
||||
Object stringToObject(Object orb, String str);
|
||||
|
||||
/**
|
||||
* Converts the given CORBA object reference to a string.
|
||||
*/
|
||||
String objectToString(Object orb, Object obj);
|
||||
|
||||
/**
|
||||
* Checks to ensure that an object of a remote or abstract interface
|
||||
* type can be cast to a desired type.
|
||||
*/
|
||||
<T> T narrow(Object narrowFrom, Class<T> narrowTo);
|
||||
|
||||
/**
|
||||
* Makes a server object ready to receive remote calls
|
||||
*/
|
||||
void exportObject(Remote obj) throws RemoteException;
|
||||
|
||||
/**
|
||||
* Deregisters a server object from the runtime.
|
||||
*/
|
||||
void unexportObject(Remote obj) throws NoSuchObjectException;
|
||||
|
||||
/**
|
||||
* Returns a stub for the given server object.
|
||||
*/
|
||||
Remote toStub(Remote obj) throws NoSuchObjectException;
|
||||
}
|
@ -86,8 +86,7 @@ public class ServerNotifForwarder {
|
||||
|
||||
// Explicitly check MBeanPermission for addNotificationListener
|
||||
//
|
||||
checkMBeanPermission(getMBeanServerName(),
|
||||
mbeanServer, name, "addNotificationListener");
|
||||
checkMBeanPermission(name, "addNotificationListener");
|
||||
if (notificationAccessController != null) {
|
||||
notificationAccessController.addNotificationListener(
|
||||
connectionId, name, getSubject());
|
||||
@ -157,8 +156,7 @@ public class ServerNotifForwarder {
|
||||
|
||||
// Explicitly check MBeanPermission for removeNotificationListener
|
||||
//
|
||||
checkMBeanPermission(getMBeanServerName(),
|
||||
mbeanServer, name, "removeNotificationListener");
|
||||
checkMBeanPermission(name, "removeNotificationListener");
|
||||
if (notificationAccessController != null) {
|
||||
notificationAccessController.removeNotificationListener(
|
||||
connectionId, name, getSubject());
|
||||
@ -333,8 +331,8 @@ public class ServerNotifForwarder {
|
||||
* Explicitly check the MBeanPermission for
|
||||
* the current access control context.
|
||||
*/
|
||||
public static void checkMBeanPermission(String serverName,
|
||||
final MBeanServer mbs, final ObjectName name, final String actions)
|
||||
public void checkMBeanPermission(
|
||||
final ObjectName name, final String actions)
|
||||
throws InstanceNotFoundException, SecurityException {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
@ -345,7 +343,7 @@ public class ServerNotifForwarder {
|
||||
new PrivilegedExceptionAction<ObjectInstance>() {
|
||||
public ObjectInstance run()
|
||||
throws InstanceNotFoundException {
|
||||
return mbs.getObjectInstance(name);
|
||||
return mbeanServer.getObjectInstance(name);
|
||||
}
|
||||
});
|
||||
} catch (PrivilegedActionException e) {
|
||||
@ -353,7 +351,6 @@ public class ServerNotifForwarder {
|
||||
}
|
||||
String classname = oi.getClassName();
|
||||
MBeanPermission perm = new MBeanPermission(
|
||||
serverName,
|
||||
classname,
|
||||
null,
|
||||
name,
|
||||
@ -369,8 +366,7 @@ public class ServerNotifForwarder {
|
||||
TargetedNotification tn) {
|
||||
try {
|
||||
if (checkNotificationEmission) {
|
||||
checkMBeanPermission(getMBeanServerName(),
|
||||
mbeanServer, name, "addNotificationListener");
|
||||
checkMBeanPermission(name, "addNotificationListener");
|
||||
}
|
||||
if (notificationAccessController != null) {
|
||||
notificationAccessController.fetchNotification(
|
||||
@ -432,27 +428,12 @@ public class ServerNotifForwarder {
|
||||
}
|
||||
}
|
||||
|
||||
private String getMBeanServerName() {
|
||||
if (mbeanServerName != null) return mbeanServerName;
|
||||
else return (mbeanServerName = getMBeanServerName(mbeanServer));
|
||||
}
|
||||
|
||||
private static String getMBeanServerName(final MBeanServer server) {
|
||||
final PrivilegedAction<String> action = new PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
return Util.getMBeanServerSecurityName(server);
|
||||
}
|
||||
};
|
||||
return AccessController.doPrivileged(action);
|
||||
}
|
||||
|
||||
|
||||
//------------------
|
||||
// PRIVATE VARIABLES
|
||||
//------------------
|
||||
|
||||
private MBeanServer mbeanServer;
|
||||
private volatile String mbeanServerName;
|
||||
|
||||
private final String connectionId;
|
||||
|
||||
@ -462,7 +443,7 @@ public class ServerNotifForwarder {
|
||||
private final static int[] listenerCounterLock = new int[0];
|
||||
|
||||
private NotificationBuffer notifBuffer;
|
||||
private Map<ObjectName, Set<IdAndFilter>> listenerMap =
|
||||
private final Map<ObjectName, Set<IdAndFilter>> listenerMap =
|
||||
new HashMap<ObjectName, Set<IdAndFilter>>();
|
||||
|
||||
private boolean terminated = false;
|
||||
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2009 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.remote.protocol.iiop;
|
||||
|
||||
import org.omg.CORBA.ORB;
|
||||
import org.omg.CORBA.portable.Delegate;
|
||||
import javax.rmi.PortableRemoteObject;
|
||||
import javax.rmi.CORBA.Stub;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.NoSuchObjectException;
|
||||
|
||||
import com.sun.jmx.remote.internal.IIOPProxy;
|
||||
|
||||
/**
|
||||
* An implementatin of IIOPProxy that simply delegates to the appropriate
|
||||
* RMI-IIOP and CORBA APIs.
|
||||
*/
|
||||
|
||||
public class IIOPProxyImpl implements IIOPProxy {
|
||||
public IIOPProxyImpl() { }
|
||||
|
||||
@Override
|
||||
public boolean isStub(Object obj) {
|
||||
return (obj instanceof Stub);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDelegate(Object stub) {
|
||||
return ((Stub)stub)._get_delegate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDelegate(Object stub, Object delegate) {
|
||||
((Stub)stub)._set_delegate((Delegate)delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOrb(Object stub) {
|
||||
try {
|
||||
return ((Stub)stub)._orb();
|
||||
} catch (org.omg.CORBA.BAD_OPERATION x) {
|
||||
throw new UnsupportedOperationException(x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(Object stub, Object orb)
|
||||
throws RemoteException
|
||||
{
|
||||
((Stub)stub).connect((ORB)orb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOrb(Object obj) {
|
||||
return (obj instanceof ORB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createOrb(String[] args, Properties props) {
|
||||
return ORB.init(args, props);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object stringToObject(Object orb, String str) {
|
||||
return ((ORB)orb).string_to_object(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String objectToString(Object orb, Object obj) {
|
||||
return ((ORB)orb).object_to_string((org.omg.CORBA.Object)obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T narrow(Object narrowFrom, Class<T> narrowTo) {
|
||||
return (T)PortableRemoteObject.narrow(narrowFrom, narrowTo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportObject(Remote obj) throws RemoteException {
|
||||
PortableRemoteObject.exportObject(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unexportObject(Remote obj) throws NoSuchObjectException {
|
||||
PortableRemoteObject.unexportObject(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Remote toStub(Remote obj) throws NoSuchObjectException {
|
||||
return PortableRemoteObject.toStub(obj);
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.remote.internal;
|
||||
package com.sun.jmx.remote.protocol.iiop;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
@ -780,25 +780,6 @@ public class EnvHelp {
|
||||
return new Hashtable<K, V>(m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the parameter JMXConnector.USE_EVENT_SERVICE is set to a
|
||||
* String equals "true" by ignoring case in the map or in the System.
|
||||
*/
|
||||
public static boolean eventServiceEnabled(Map<String, ?> env) {
|
||||
return computeBooleanFromString(env, JMXConnector.USE_EVENT_SERVICE, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the parameter JMXConnectorServer.DELEGATE_TO_EVENT_SERVICE
|
||||
* is set to a String equals "true" (ignores case).
|
||||
* If the property DELEGATE_TO_EVENT_SERVICE is not set, returns
|
||||
* a default value of "true".
|
||||
*/
|
||||
public static boolean delegateToEventService(Map<String, ?> env) {
|
||||
return computeBooleanFromString(env,
|
||||
JMXConnectorServer.DELEGATE_TO_EVENT_SERVICE, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Name of the attribute that specifies whether a connector server
|
||||
* should not prevent the VM from exiting
|
||||
@ -817,46 +798,6 @@ public class EnvHelp {
|
||||
("true".equalsIgnoreCase((String)env.get(JMX_SERVER_DAEMON)));
|
||||
}
|
||||
|
||||
// /**
|
||||
// * <p>Name of the attribute that specifies an EventRelay object to use.
|
||||
// */
|
||||
// public static final String EVENT_RELAY =
|
||||
// "jmx.remote.x.event.relay";
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * Returns an EventRelay object. The default one is FetchingEventRelay.
|
||||
// * If {@code EVENT_RELAY} is specified in {@code env} as a key,
|
||||
// * its value will be returned as an EventRelay object, if the value is
|
||||
// * not of type {@code EventRelay}, the default {@code FetchingEventRelay}
|
||||
// * will be returned.
|
||||
// * If {@code EVENT_RELAY} is not specified but {@code ENABLE_EVENT_RELAY}
|
||||
// * is specified as a key and its value is <code true>, the default {@code FetchingEventRelay}
|
||||
// * will be returned.
|
||||
// */
|
||||
// public static EventRelay getEventRelay(Map env) {
|
||||
// Map info = env == null ?
|
||||
// Collections.EMPTY_MAP : env;
|
||||
//
|
||||
// Object o = env.get(EVENT_RELAY);
|
||||
// if (o instanceof EventRelay) {
|
||||
// return (EventRelay)o;
|
||||
// } else if (o != null) {
|
||||
// logger.warning("getEventRelay",
|
||||
// "The user specified object is not an EventRelay object, " +
|
||||
// "using the default class FetchingEventRelay.");
|
||||
//
|
||||
// return new FetchingEventRelay();
|
||||
// }
|
||||
//
|
||||
// if (enableEventRelay(env)) {
|
||||
// return new FetchingEventRelay();
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
|
||||
|
||||
private static final class SinkOutputStream extends OutputStream {
|
||||
public void write(byte[] b, int off, int len) {}
|
||||
public void write(int b) {}
|
||||
|
@ -1,469 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.remote.util;
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import com.sun.jmx.event.EventClientFactory;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.event.EventClient;
|
||||
import javax.management.event.EventClientDelegate;
|
||||
import javax.management.namespace.JMXNamespaces;
|
||||
|
||||
/**
|
||||
* Class EventClientConnection - a {@link Proxy} that wraps an
|
||||
* {@link MBeanServerConnection} and an {@link EventClient}.
|
||||
* All methods are routed to the underlying {@code MBeanServerConnection},
|
||||
* except add/remove notification listeners which are routed to the
|
||||
* {@code EventClient}.
|
||||
* The caller only sees an {@code MBeanServerConnection} which uses an
|
||||
* {@code EventClient} behind the scenes.
|
||||
*
|
||||
* @author Sun Microsystems, Inc.
|
||||
*/
|
||||
public class EventClientConnection implements InvocationHandler,
|
||||
EventClientFactory {
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NOTIFICATION_LOGGER;
|
||||
|
||||
private static final int NAMESPACE_SEPARATOR_LENGTH =
|
||||
JMXNamespaces.NAMESPACE_SEPARATOR.length();
|
||||
|
||||
/**
|
||||
* Creates a new {@code EventClientConnection}.
|
||||
* @param connection The underlying MBeanServerConnection.
|
||||
*/
|
||||
public EventClientConnection(MBeanServerConnection connection) {
|
||||
this(connection,null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code EventClientConnection}.
|
||||
* @param connection The underlying MBeanServerConnection.
|
||||
* @param eventClientFactory a factory object that will be invoked
|
||||
* to create an {@link EventClient} when needed.
|
||||
* 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}).
|
||||
*/
|
||||
public EventClientConnection(MBeanServerConnection connection,
|
||||
Callable<EventClient> eventClientFactory) {
|
||||
|
||||
if (connection == null) {
|
||||
throw new IllegalArgumentException("Null connection");
|
||||
}
|
||||
this.connection = connection;
|
||||
if (eventClientFactory == null) {
|
||||
eventClientFactory = new Callable<EventClient>() {
|
||||
public final EventClient call() throws Exception {
|
||||
return createEventClient(EventClientConnection.this.connection);
|
||||
}
|
||||
};
|
||||
}
|
||||
this.eventClientFactory = eventClientFactory;
|
||||
this.lock = new ReentrantLock();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The MBean server connection through which the methods of
|
||||
* a proxy using this handler are forwarded.</p>
|
||||
*
|
||||
* @return the MBean server connection.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public MBeanServerConnection getMBeanServerConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new EventClientConnection proxy instance.
|
||||
*
|
||||
* @param <T> The underlying {@code MBeanServerConnection} - which should
|
||||
* not be using the Event Service itself.
|
||||
* @param interfaceClass {@code MBeanServerConnection.class}, or a subclass.
|
||||
* @param eventClientFactory a factory used to create the EventClient.
|
||||
* If null, a default factory is used (see {@link
|
||||
* #createEventClient}).
|
||||
* @return the new proxy instance, which will route add/remove notification
|
||||
* listener calls through an {@code EventClient}.
|
||||
*
|
||||
*/
|
||||
private static <T extends MBeanServerConnection> T
|
||||
newProxyInstance(T connection,
|
||||
Class<T> interfaceClass, Callable<EventClient> eventClientFactory) {
|
||||
final InvocationHandler handler =
|
||||
new EventClientConnection(connection,eventClientFactory);
|
||||
final Class<?>[] interfaces =
|
||||
new Class<?>[] {interfaceClass, EventClientFactory.class};
|
||||
|
||||
Object proxy =
|
||||
Proxy.newProxyInstance(interfaceClass.getClassLoader(),
|
||||
interfaces,
|
||||
handler);
|
||||
return interfaceClass.cast(proxy);
|
||||
}
|
||||
|
||||
|
||||
public Object invoke(Object proxy, Method method, Object[] args)
|
||||
throws Throwable {
|
||||
final String methodName = method.getName();
|
||||
|
||||
// add/remove notification listener are routed to the EventClient
|
||||
if (methodName.equals("addNotificationListener")
|
||||
|| methodName.equals("removeNotificationListener")) {
|
||||
final Class<?>[] sig = method.getParameterTypes();
|
||||
if (sig.length>1 &&
|
||||
NotificationListener.class.isAssignableFrom(sig[1])) {
|
||||
return invokeBroadcasterMethod(proxy,method,args);
|
||||
}
|
||||
}
|
||||
|
||||
// subscribe/unsubscribe are also routed to the EventClient.
|
||||
final Class<?> clazz = method.getDeclaringClass();
|
||||
if (clazz.equals(EventClientFactory.class)) {
|
||||
return invokeEventClientSubscriberMethod(proxy,method,args);
|
||||
}
|
||||
|
||||
// local or not: equals, toString, hashCode
|
||||
if (shouldDoLocally(proxy, method))
|
||||
return doLocally(proxy, method, args);
|
||||
|
||||
return call(connection,method,args);
|
||||
}
|
||||
|
||||
// The purpose of this method is to unwrap InvocationTargetException,
|
||||
// in order to avoid throwing UndeclaredThrowableException for
|
||||
// declared exceptions.
|
||||
//
|
||||
// When calling method.invoke(), any exception thrown by the invoked
|
||||
// method will be wrapped in InvocationTargetException. If we don't
|
||||
// unwrap this exception, the proxy will always throw
|
||||
// UndeclaredThrowableException, even for runtime exceptions.
|
||||
//
|
||||
private Object call(final Object obj, final Method m,
|
||||
final Object[] args)
|
||||
throws Throwable {
|
||||
try {
|
||||
return m.invoke(obj,args);
|
||||
} catch (InvocationTargetException x) {
|
||||
final Throwable xx = x.getTargetException();
|
||||
if (xx == null) throw x;
|
||||
else throw xx;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Route add/remove notification listener to the event client.
|
||||
**/
|
||||
private Object invokeBroadcasterMethod(Object proxy, Method method,
|
||||
Object[] args) throws Exception {
|
||||
final String methodName = method.getName();
|
||||
final int nargs = (args == null) ? 0 : args.length;
|
||||
|
||||
if (nargs < 1) {
|
||||
final String msg =
|
||||
"Bad arg count: " + nargs;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
|
||||
final ObjectName mbean = (ObjectName) args[0];
|
||||
final EventClient evtClient = getEventClient();
|
||||
|
||||
// Fails if evtClient is null AND the MBean we try to listen to is
|
||||
// in a subnamespace. We fail here because we know this will not
|
||||
// work.
|
||||
//
|
||||
// Note that if the wrapped MBeanServerConnection points to a an
|
||||
// earlier agent (JDK 1.6 or earlier), then the EventClient will
|
||||
// be null (we can't use the event service with earlier JDKs).
|
||||
//
|
||||
// In principle a null evtClient indicates that the remote VM is of
|
||||
// an earlier version, in which case it shouldn't contain any namespace.
|
||||
//
|
||||
// So having a null evtClient AND an MBean contained in a namespace is
|
||||
// clearly an error case.
|
||||
//
|
||||
if (evtClient == null) {
|
||||
final String domain = mbean.getDomain();
|
||||
final int index = domain.indexOf(JMXNamespaces.NAMESPACE_SEPARATOR);
|
||||
if (index > -1 && index <
|
||||
(domain.length()-NAMESPACE_SEPARATOR_LENGTH)) {
|
||||
throw new UnsupportedOperationException(method.getName()+
|
||||
" on namespace "+domain.substring(0,index+
|
||||
NAMESPACE_SEPARATOR_LENGTH));
|
||||
}
|
||||
}
|
||||
|
||||
if (methodName.equals("addNotificationListener")) {
|
||||
/* The various throws of IllegalArgumentException here
|
||||
should not happen, since we know what the methods in
|
||||
NotificationBroadcaster and NotificationEmitter
|
||||
are. */
|
||||
if (nargs != 4) {
|
||||
final String msg =
|
||||
"Bad arg count to addNotificationListener: " + nargs;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
/* Other inconsistencies will produce ClassCastException
|
||||
below. */
|
||||
|
||||
final NotificationListener listener = (NotificationListener) args[1];
|
||||
final NotificationFilter filter = (NotificationFilter) args[2];
|
||||
final Object handback = args[3];
|
||||
|
||||
if (evtClient != null) {
|
||||
// general case
|
||||
evtClient.addNotificationListener(mbean,listener,filter,handback);
|
||||
} else {
|
||||
// deprecated case. Only works for mbean in local namespace.
|
||||
connection.addNotificationListener(mbean,listener,filter,
|
||||
handback);
|
||||
}
|
||||
return null;
|
||||
|
||||
} else if (methodName.equals("removeNotificationListener")) {
|
||||
|
||||
/* NullPointerException if method with no args, but that
|
||||
shouldn't happen because removeNL does have args. */
|
||||
NotificationListener listener = (NotificationListener) args[1];
|
||||
|
||||
switch (nargs) {
|
||||
case 2:
|
||||
if (evtClient != null) {
|
||||
// general case
|
||||
evtClient.removeNotificationListener(mbean,listener);
|
||||
} else {
|
||||
// deprecated case. Only works for mbean in local namespace.
|
||||
connection.removeNotificationListener(mbean, listener);
|
||||
}
|
||||
return null;
|
||||
|
||||
case 4:
|
||||
NotificationFilter filter = (NotificationFilter) args[2];
|
||||
Object handback = args[3];
|
||||
if (evtClient != null) {
|
||||
evtClient.removeNotificationListener(mbean,
|
||||
listener,
|
||||
filter,
|
||||
handback);
|
||||
} else {
|
||||
connection.removeNotificationListener(mbean,
|
||||
listener,
|
||||
filter,
|
||||
handback);
|
||||
}
|
||||
return null;
|
||||
|
||||
default:
|
||||
final String msg =
|
||||
"Bad arg count to removeNotificationListener: " + nargs;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException("Bad method name: " +
|
||||
methodName);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldDoLocally(Object proxy, Method method) {
|
||||
final String methodName = method.getName();
|
||||
if ((methodName.equals("hashCode") || methodName.equals("toString"))
|
||||
&& method.getParameterTypes().length == 0
|
||||
&& isLocal(proxy, method))
|
||||
return true;
|
||||
if (methodName.equals("equals")
|
||||
&& Arrays.equals(method.getParameterTypes(),
|
||||
new Class<?>[] {Object.class})
|
||||
&& isLocal(proxy, method))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private Object doLocally(Object proxy, Method method, Object[] args) {
|
||||
final String methodName = method.getName();
|
||||
|
||||
if (methodName.equals("equals")) {
|
||||
|
||||
if (this == args[0]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(args[0] instanceof Proxy)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final InvocationHandler ihandler =
|
||||
Proxy.getInvocationHandler(args[0]);
|
||||
|
||||
if (ihandler == null ||
|
||||
!(ihandler instanceof EventClientConnection)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final EventClientConnection handler =
|
||||
(EventClientConnection)ihandler;
|
||||
|
||||
return connection.equals(handler.connection) &&
|
||||
proxy.getClass().equals(args[0].getClass());
|
||||
} else if (methodName.equals("hashCode")) {
|
||||
return connection.hashCode();
|
||||
}
|
||||
|
||||
throw new RuntimeException("Unexpected method name: " + methodName);
|
||||
}
|
||||
|
||||
private static boolean isLocal(Object proxy, Method method) {
|
||||
final Class<?>[] interfaces = proxy.getClass().getInterfaces();
|
||||
if(interfaces == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final String methodName = method.getName();
|
||||
final Class<?>[] params = method.getParameterTypes();
|
||||
for (Class<?> intf : interfaces) {
|
||||
try {
|
||||
intf.getMethod(methodName, params);
|
||||
return false; // found method in one of our interfaces
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
// OK.
|
||||
}
|
||||
}
|
||||
|
||||
return true; // did not find in any interface
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the EventClient used by this object. Can be null if the
|
||||
* remote VM is of an earlier JDK version which doesn't have the
|
||||
* event service.<br>
|
||||
* This method will invoke the event client factory the first time
|
||||
* it is called.
|
||||
**/
|
||||
public final EventClient getEventClient() {
|
||||
if (initialized) return client;
|
||||
try {
|
||||
if (!lock.tryLock(TRYLOCK_TIMEOUT,TimeUnit.SECONDS))
|
||||
throw new IllegalStateException("can't acquire lock");
|
||||
try {
|
||||
client = eventClientFactory.call();
|
||||
initialized = true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} catch (RuntimeException x) {
|
||||
throw x;
|
||||
} catch (Exception x) {
|
||||
throw new IllegalStateException("Can't create EventClient: "+x,x);
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an event client for the wrapped {@code MBeanServerConnection}.
|
||||
* This is the method invoked by the default event client factory.
|
||||
* @param connection the wrapped {@code MBeanServerConnection}.
|
||||
**/
|
||||
protected EventClient createEventClient(MBeanServerConnection connection)
|
||||
throws Exception {
|
||||
final ObjectName name =
|
||||
EventClientDelegate.OBJECT_NAME;
|
||||
if (connection.isRegistered(name)) {
|
||||
return new EventClient(connection);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link MBeanServerConnection} that goes through an
|
||||
* {@link EventClient} to receive/subscribe to notifications.
|
||||
* @param connection the underlying {@link MBeanServerConnection}.
|
||||
* The given <code>connection</code> shouldn't be already
|
||||
* using an {@code EventClient}.
|
||||
* @param eventClientFactory a factory object that will be invoked
|
||||
* to create an {@link EventClient} when needed.
|
||||
* 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 MBeanServerConnection.
|
||||
**/
|
||||
public static MBeanServerConnection getEventConnectionFor(
|
||||
MBeanServerConnection connection,
|
||||
Callable<EventClient> eventClientFactory) {
|
||||
if (connection instanceof EventClientFactory
|
||||
&& eventClientFactory != null)
|
||||
throw new IllegalArgumentException("connection already uses EventClient");
|
||||
|
||||
if (connection instanceof EventClientFactory)
|
||||
return connection;
|
||||
|
||||
// create a new proxy using an event client.
|
||||
//
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("Creating EventClient for: "+connection);
|
||||
return newProxyInstance(connection,
|
||||
MBeanServerConnection.class,
|
||||
eventClientFactory);
|
||||
}
|
||||
|
||||
private Object invokeEventClientSubscriberMethod(Object proxy,
|
||||
Method method, Object[] args) throws Throwable {
|
||||
return call(this,method,args);
|
||||
}
|
||||
|
||||
// Maximum lock timeout in seconds. Obviously arbitrary.
|
||||
//
|
||||
private final static short TRYLOCK_TIMEOUT = 3;
|
||||
|
||||
private final MBeanServerConnection connection;
|
||||
private final Callable<EventClient> eventClientFactory;
|
||||
private final Lock lock;
|
||||
private volatile EventClient client = null;
|
||||
private volatile boolean initialized = false;
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -32,12 +32,8 @@ import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.Socket;
|
||||
import java.util.Vector;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import javax.naming.CommunicationException;
|
||||
import javax.naming.AuthenticationException;
|
||||
import javax.naming.AuthenticationNotSupportedException;
|
||||
import javax.naming.ServiceUnavailableException;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.InterruptedNamingException;
|
||||
@ -47,6 +43,8 @@ import javax.naming.ldap.Control;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import sun.misc.IOUtils;
|
||||
//import javax.net.SocketFactory;
|
||||
|
||||
/**
|
||||
@ -799,7 +797,6 @@ public final class Connection implements Runnable {
|
||||
byte inbuf[]; // Buffer for reading incoming bytes
|
||||
int inMsgId; // Message id of incoming response
|
||||
int bytesread; // Number of bytes in inbuf
|
||||
int bytesleft; // Number of bytes that need to read for completing resp
|
||||
int br; // Temp; number of bytes read from stream
|
||||
int offset; // Offset of where to store bytes in inbuf
|
||||
int seqlen; // Length of ASN sequence
|
||||
@ -811,7 +808,7 @@ public final class Connection implements Runnable {
|
||||
try {
|
||||
while (true) {
|
||||
try {
|
||||
inbuf = new byte[2048];
|
||||
inbuf = new byte[10];
|
||||
|
||||
offset = 0;
|
||||
seqlen = 0;
|
||||
@ -871,19 +868,10 @@ public final class Connection implements Runnable {
|
||||
}
|
||||
|
||||
// read in seqlen bytes
|
||||
bytesleft = seqlen;
|
||||
if ((offset + bytesleft) > inbuf.length) {
|
||||
byte nbuf[] = new byte[offset + bytesleft];
|
||||
System.arraycopy(inbuf, 0, nbuf, 0, offset);
|
||||
inbuf = nbuf;
|
||||
}
|
||||
while (bytesleft > 0) {
|
||||
bytesread = in.read(inbuf, offset, bytesleft);
|
||||
if (bytesread < 0)
|
||||
break; // EOF
|
||||
offset += bytesread;
|
||||
bytesleft -= bytesread;
|
||||
}
|
||||
byte[] left = IOUtils.readFully(in, seqlen, false);
|
||||
inbuf = Arrays.copyOf(inbuf, offset + left.length);
|
||||
System.arraycopy(left, 0, inbuf, offset, left.length);
|
||||
offset += left.length;
|
||||
/*
|
||||
if (dump > 0) {
|
||||
System.err.println("seqlen: " + seqlen);
|
||||
|
@ -40,7 +40,6 @@ import java.util.List;
|
||||
import java.security.Principal;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
@ -413,14 +412,15 @@ final public class StartTlsResponseImpl extends StartTlsResponse {
|
||||
try {
|
||||
HostnameChecker checker = HostnameChecker.getInstance(
|
||||
HostnameChecker.TYPE_LDAP);
|
||||
Principal principal = getPeerPrincipal(session);
|
||||
if (principal instanceof KerberosPrincipal) {
|
||||
if (!checker.match(hostname, (KerberosPrincipal) principal)) {
|
||||
// Use ciphersuite to determine whether Kerberos is active.
|
||||
if (session.getCipherSuite().startsWith("TLS_KRB5")) {
|
||||
Principal principal = getPeerPrincipal(session);
|
||||
if (!checker.match(hostname, principal)) {
|
||||
throw new SSLPeerUnverifiedException(
|
||||
"hostname of the kerberos principal:" + principal +
|
||||
" does not match the hostname:" + hostname);
|
||||
}
|
||||
} else {
|
||||
} else { // X.509
|
||||
|
||||
// get the subject's certificate
|
||||
certs = session.getPeerCertificates();
|
||||
|
@ -36,7 +36,6 @@ import java.security.Principal;
|
||||
import java.security.cert.*;
|
||||
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||
|
||||
import sun.security.util.HostnameChecker;
|
||||
import sun.security.util.DerValue;
|
||||
@ -109,20 +108,18 @@ class VerifierWrapper implements javax.net.ssl.HostnameVerifier {
|
||||
/*
|
||||
* In com.sun.net.ssl.HostnameVerifier the method is defined
|
||||
* as verify(String urlHostname, String certHostname).
|
||||
* This means we need to extract the hostname from the certificate
|
||||
* in this wrapper
|
||||
* This means we need to extract the hostname from the X.509 certificate
|
||||
* or from the Kerberos principal name, in this wrapper.
|
||||
*/
|
||||
public boolean verify(String hostname, javax.net.ssl.SSLSession session) {
|
||||
try {
|
||||
String serverName;
|
||||
Principal principal = getPeerPrincipal(session);
|
||||
// X.500 principal or Kerberos principal.
|
||||
// (Use ciphersuite check to determine whether Kerberos is present.)
|
||||
if (session.getCipherSuite().startsWith("TLS_KRB5") &&
|
||||
principal instanceof KerberosPrincipal) {
|
||||
// Use ciphersuite to determine whether Kerberos is active.
|
||||
if (session.getCipherSuite().startsWith("TLS_KRB5")) {
|
||||
serverName =
|
||||
HostnameChecker.getServerName((KerberosPrincipal)principal);
|
||||
} else {
|
||||
HostnameChecker.getServerName(getPeerPrincipal(session));
|
||||
|
||||
} else { // X.509
|
||||
Certificate[] serverChain = session.getPeerCertificates();
|
||||
if ((serverChain == null) || (serverChain.length == 0)) {
|
||||
return false;
|
||||
|
@ -229,6 +229,21 @@ public class Applet extends Panel {
|
||||
resize(d.width, d.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this container is a validate root.
|
||||
* <p>
|
||||
* {@code Applet} objects are the validate roots, and, therefore, they
|
||||
* override this method to return {@code true}.
|
||||
*
|
||||
* @return {@code true}
|
||||
* @since 1.7
|
||||
* @see java.awt.Container#isValidateRoot
|
||||
*/
|
||||
@Override
|
||||
public boolean isValidateRoot() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the argument string be displayed in the
|
||||
* "status window". Many browsers and applet viewers
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 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
|
||||
@ -92,7 +92,15 @@ import java.security.BasicPermission;
|
||||
* <td>Enter full-screen exclusive mode</td>
|
||||
* <td>Entering full-screen exclusive mode allows direct access to
|
||||
* low-level graphics card memory. This could be used to spoof the
|
||||
* system, since the program is in direct control of rendering.</td>
|
||||
* system, since the program is in direct control of rendering. Depending on
|
||||
* the implementation, the security warning may not be shown for the windows
|
||||
* used to enter the full-screen exclusive mode (assuming that the {@code
|
||||
* fullScreenExclusive} permission has been granted to this application). Note
|
||||
* that this behavior does not mean that the {@code
|
||||
* showWindowWithoutWarningBanner} permission will be automatically granted to
|
||||
* the application which has the {@code fullScreenExclusive} permission:
|
||||
* non-full-screen windows will continue to be shown with the security
|
||||
* warning.</td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
|
@ -2764,8 +2764,11 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that this component has a valid layout. This method is
|
||||
* primarily intended to operate on instances of <code>Container</code>.
|
||||
* Validates this component.
|
||||
* <p>
|
||||
* The meaning of the term <i>validating</i> is defined by the ancestors of
|
||||
* this class. See {@link Container#validate} for more details.
|
||||
*
|
||||
* @see #invalidate
|
||||
* @see #doLayout()
|
||||
* @see LayoutManager
|
||||
@ -2794,12 +2797,24 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates this component. This component and all parents
|
||||
* above it are marked as needing to be laid out. This method can
|
||||
* be called often, so it needs to execute quickly.
|
||||
* Invalidates this component and its ancestors.
|
||||
* <p>
|
||||
* All the ancestors of this component up to the nearest validate root are
|
||||
* marked invalid also. If there is no a validate root container for this
|
||||
* component, all of its ancestors up to the root of the hierarchy are
|
||||
* marked invalid as well. Marking a container <i>invalid</i> indicates
|
||||
* that the container needs to be laid out.
|
||||
* <p>
|
||||
* This method is called automatically when any layout-related information
|
||||
* changes (e.g. setting the bounds of the component, or adding the
|
||||
* component to a container).
|
||||
* <p>
|
||||
* This method might be called often, so it should work fast.
|
||||
*
|
||||
* @see #validate
|
||||
* @see #doLayout
|
||||
* @see LayoutManager
|
||||
* @see java.awt.Container#isValidateRoot
|
||||
* @since JDK1.0
|
||||
*/
|
||||
public void invalidate() {
|
||||
@ -2818,9 +2833,18 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
if (!isMaximumSizeSet()) {
|
||||
maxSize = null;
|
||||
}
|
||||
if (parent != null) {
|
||||
parent.invalidateIfValid();
|
||||
}
|
||||
invalidateParent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the parent of this component if any.
|
||||
*
|
||||
* This method MUST BE invoked under the TreeLock.
|
||||
*/
|
||||
void invalidateParent() {
|
||||
if (parent != null) {
|
||||
parent.invalidateIfValid();
|
||||
}
|
||||
}
|
||||
|
||||
@ -6727,12 +6751,13 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// It's native. If the parent is lightweight it
|
||||
// will need some help.
|
||||
Container parent = this.parent;
|
||||
if (parent != null && parent.peer instanceof LightweightPeer) {
|
||||
// It's native. If the parent is lightweight it will need some
|
||||
// help.
|
||||
Container parent = getContainer();
|
||||
if (parent != null && parent.isLightweight()) {
|
||||
relocateComponent();
|
||||
if (!isRecursivelyVisible()) {
|
||||
if (!parent.isRecursivelyVisibleUpToHeavyweightContainer())
|
||||
{
|
||||
peer.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
@ -1492,20 +1492,59 @@ public class Container extends Component {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the container. The container and all parents
|
||||
* above it are marked as needing to be laid out. This method can
|
||||
* be called often, so it needs to execute quickly.
|
||||
* Indicates if this container is a <i>validate root</i>.
|
||||
* <p>
|
||||
* Layout-related changes, such as bounds of the validate root descendants,
|
||||
* do not affect the layout of the validate root parent. This peculiarity
|
||||
* enables the {@code invalidate()} method to stop invalidating the
|
||||
* component hierarchy when the method encounters a validate root.
|
||||
* <p>
|
||||
* If a component hierarchy contains validate roots, the {@code validate()}
|
||||
* method must be invoked on the validate root of a previously invalidated
|
||||
* component, rather than on the top-level container (such as a {@code
|
||||
* Frame} object) to restore the validity of the hierarchy later.
|
||||
* <p>
|
||||
* The {@code Window} class and the {@code Applet} class are the validate
|
||||
* roots in AWT. Swing introduces more validate roots.
|
||||
*
|
||||
* <p> If the {@code LayoutManager} installed on this container is
|
||||
* an instance of {@code LayoutManager2}, then
|
||||
* {@link LayoutManager2#invalidateLayout(Container)} is invoked on
|
||||
* it supplying this {@code Container} as the argument.
|
||||
* @return whether this container is a validate root
|
||||
* @see #invalidate
|
||||
* @see java.awt.Component#invalidate
|
||||
* @see javax.swing.JComponent#isValidateRoot
|
||||
* @see javax.swing.JComponent#revalidate
|
||||
* @since 1.7
|
||||
*/
|
||||
public boolean isValidateRoot() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the parent of the container unless the container
|
||||
* is a validate root.
|
||||
*/
|
||||
@Override
|
||||
void invalidateParent() {
|
||||
if (!isValidateRoot()) {
|
||||
super.invalidateParent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the container.
|
||||
* <p>
|
||||
* If the {@code LayoutManager} installed on this container is an instance
|
||||
* of the {@code LayoutManager2} interface, then
|
||||
* the {@link LayoutManager2#invalidateLayout(Container)} method is invoked
|
||||
* on it supplying this {@code Container} as the argument.
|
||||
* <p>
|
||||
* Afterwards this method marks this container invalid, and invalidates its
|
||||
* ancestors. See the {@link Component#invalidate} method for more details.
|
||||
*
|
||||
* @see #validate
|
||||
* @see #layout
|
||||
* @see LayoutManager
|
||||
* @see LayoutManager2#invalidateLayout(Container)
|
||||
* @see LayoutManager2
|
||||
*/
|
||||
@Override
|
||||
public void invalidate() {
|
||||
LayoutManager layoutMgr = this.layoutMgr;
|
||||
if (layoutMgr instanceof LayoutManager2) {
|
||||
@ -1518,52 +1557,90 @@ public class Container extends Component {
|
||||
/**
|
||||
* Validates this container and all of its subcomponents.
|
||||
* <p>
|
||||
* The <code>validate</code> method is used to cause a container
|
||||
* to lay out its subcomponents again. It should be invoked when
|
||||
* this container's subcomponents are modified (added to or
|
||||
* removed from the container, or layout-related information
|
||||
* changed) after the container has been displayed.
|
||||
*
|
||||
* <p>If this {@code Container} is not valid, this method invokes
|
||||
* Validating a container means laying out its subcomponents.
|
||||
* Layout-related changes, such as setting the bounds of a component, or
|
||||
* adding a component to the container, invalidate the container
|
||||
* automatically. Note that the ancestors of the container may be
|
||||
* invalidated also (see {@link Component#invalidate} for details.)
|
||||
* Therefore, to restore the validity of the hierarchy, the {@code
|
||||
* validate()} method should be invoked on a validate root of an
|
||||
* invalidated component, or on the top-most container if the hierarchy
|
||||
* does not contain validate roots.
|
||||
* <p>
|
||||
* Validating the container may be a quite time-consuming operation. For
|
||||
* performance reasons a developer may postpone the validation of the
|
||||
* hierarchy till a set of layout-related operations completes, e.g. after
|
||||
* adding all the children to the container.
|
||||
* <p>
|
||||
* If this {@code Container} is not valid, this method invokes
|
||||
* the {@code validateTree} method and marks this {@code Container}
|
||||
* as valid. Otherwise, no action is performed.
|
||||
* <p>
|
||||
* Note that the {@code invalidate()} method may invalidate not only the
|
||||
* component it is called upon, but also the parents of the component.
|
||||
* Therefore, to restore the validity of the hierarchy, the {@code
|
||||
* validate()} method must be invoked on the top-most invalid container of
|
||||
* the hierarchy. For performance reasons a developer may postpone the
|
||||
* validation of the hierarchy till a bunch of layout-related operations
|
||||
* completes, e.g. after adding all the children to the container.
|
||||
*
|
||||
* @see #add(java.awt.Component)
|
||||
* @see #invalidate
|
||||
* @see Container#isValidateRoot
|
||||
* @see javax.swing.JComponent#revalidate()
|
||||
* @see #validateTree
|
||||
*/
|
||||
public void validate() {
|
||||
/* Avoid grabbing lock unless really necessary. */
|
||||
if (!isValid()) {
|
||||
boolean updateCur = false;
|
||||
synchronized (getTreeLock()) {
|
||||
if (!isValid() && peer != null) {
|
||||
ContainerPeer p = null;
|
||||
if (peer instanceof ContainerPeer) {
|
||||
p = (ContainerPeer) peer;
|
||||
}
|
||||
if (p != null) {
|
||||
p.beginValidate();
|
||||
}
|
||||
validateTree();
|
||||
if (p != null) {
|
||||
p.endValidate();
|
||||
boolean updateCur = false;
|
||||
synchronized (getTreeLock()) {
|
||||
if ((!isValid() || descendUnconditionallyWhenValidating)
|
||||
&& peer != null)
|
||||
{
|
||||
ContainerPeer p = null;
|
||||
if (peer instanceof ContainerPeer) {
|
||||
p = (ContainerPeer) peer;
|
||||
}
|
||||
if (p != null) {
|
||||
p.beginValidate();
|
||||
}
|
||||
validateTree();
|
||||
if (p != null) {
|
||||
p.endValidate();
|
||||
// Avoid updating cursor if this is an internal call.
|
||||
// See validateUnconditionally() for details.
|
||||
if (!descendUnconditionallyWhenValidating) {
|
||||
updateCur = isVisible();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (updateCur) {
|
||||
updateCursorImmediately();
|
||||
}
|
||||
if (updateCur) {
|
||||
updateCursorImmediately();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether valid containers should also traverse their
|
||||
* children and call the validateTree() method on them.
|
||||
*
|
||||
* Synchronization: TreeLock.
|
||||
*
|
||||
* The field is allowed to be static as long as the TreeLock itself is
|
||||
* static.
|
||||
*
|
||||
* @see #validateUnconditionally()
|
||||
*/
|
||||
private static boolean descendUnconditionallyWhenValidating = false;
|
||||
|
||||
/**
|
||||
* Unconditionally validate the component hierarchy.
|
||||
*/
|
||||
final void validateUnconditionally() {
|
||||
boolean updateCur = false;
|
||||
synchronized (getTreeLock()) {
|
||||
descendUnconditionallyWhenValidating = true;
|
||||
|
||||
validate();
|
||||
if (peer instanceof ContainerPeer) {
|
||||
updateCur = isVisible();
|
||||
}
|
||||
|
||||
descendUnconditionallyWhenValidating = false;
|
||||
}
|
||||
if (updateCur) {
|
||||
updateCursorImmediately();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1578,16 +1655,20 @@ public class Container extends Component {
|
||||
*/
|
||||
protected void validateTree() {
|
||||
checkTreeLock();
|
||||
if (!isValid()) {
|
||||
if (!isValid() || descendUnconditionallyWhenValidating) {
|
||||
if (peer instanceof ContainerPeer) {
|
||||
((ContainerPeer)peer).beginLayout();
|
||||
}
|
||||
doLayout();
|
||||
if (!isValid()) {
|
||||
doLayout();
|
||||
}
|
||||
for (int i = 0; i < component.size(); i++) {
|
||||
Component comp = component.get(i);
|
||||
if ( (comp instanceof Container)
|
||||
&& !(comp instanceof Window)
|
||||
&& !comp.isValid()) {
|
||||
&& (!comp.isValid() ||
|
||||
descendUnconditionallyWhenValidating))
|
||||
{
|
||||
((Container)comp).validateTree();
|
||||
} else {
|
||||
comp.validate();
|
||||
@ -4092,16 +4173,29 @@ public class Container extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Checks if the container and its direct lightweight containers are
|
||||
* visible.
|
||||
*
|
||||
* Consider the heavyweight container hides or shows the HW descendants
|
||||
* automatically. Therefore we care of LW containers' visibility only.
|
||||
*
|
||||
* This method MUST be invoked under the TreeLock.
|
||||
*/
|
||||
private boolean isRecursivelyVisibleUpToHeavyweightContainer() {
|
||||
final boolean isRecursivelyVisibleUpToHeavyweightContainer() {
|
||||
if (!isLightweight()) {
|
||||
return true;
|
||||
}
|
||||
return isVisible() && (getContainer() == null ||
|
||||
getContainer().isRecursivelyVisibleUpToHeavyweightContainer());
|
||||
|
||||
for (Container cont = getContainer();
|
||||
cont != null && cont.isLightweight();
|
||||
cont = cont.getContainer())
|
||||
{
|
||||
if (!cont.isVisible()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1027,7 +1027,9 @@ public class EventQueue {
|
||||
|
||||
synchronized (lock) {
|
||||
Toolkit.getEventQueue().postEvent(event);
|
||||
lock.wait();
|
||||
while (!event.isDispatched()) {
|
||||
lock.wait();
|
||||
}
|
||||
}
|
||||
|
||||
Throwable eventThrowable = event.getThrowable();
|
||||
|
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