diff --git a/.hgtags-top-repo b/.hgtags-top-repo index a3ac772f914..a82460bf48f 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -50,3 +50,4 @@ e1b972ff53cd58f825791f8ed9b2deffd16e768c jdk7-b68 3ac6dcf7823205546fbbc3d4ea59f37358d0b0d4 jdk7-b73 2c88089b6e1c053597418099a14232182c387edc jdk7-b74 d1516b9f23954b29b8e76e6f4efc467c08c78133 jdk7-b75 +c8b63075403d53a208104a8a6ea5072c1cb66aab jdk7-b76 diff --git a/corba/.hgtags b/corba/.hgtags index 98a13b65b6a..9e8067101da 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -50,3 +50,4 @@ c793a31209263fbb867c23c752599d85c21abb73 jdk7-b72 b751c528c55560cf2adeaeef24b39ca1f4d1cbf7 jdk7-b73 5d0cf59a3203b9f57aceebc33ae656b884987955 jdk7-b74 0fb137085952c8e47878e240d1cb40f14de463c4 jdk7-b75 +937144222e2219939101b0129d26a872a7956b13 jdk7-b76 diff --git a/corba/make/common/shared/Platform.gmk b/corba/make/common/shared/Platform.gmk index c444d06f802..b0474d82e16 100644 --- a/corba/make/common/shared/Platform.gmk +++ b/corba/make/common/shared/Platform.gmk @@ -187,6 +187,9 @@ ifeq ($(SYSTEM_UNAME), Linux) sparc*) \ echo sparc \ ;; \ + arm*) \ + echo arm \ + ;; \ *) \ echo $(mach) \ ;; \ diff --git a/hotspot/.hgtags b/hotspot/.hgtags index b8ce5272692..d91cec8c3fe 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -50,3 +50,4 @@ a94714c550658fd6741793ef036cb9625dc2ab1a jdk7-b72 faf94d94786b621f8e13cbcc941ca69c6d967c3f jdk7-b73 f4b900403d6e4b0af51447bd13bbe23fe3a1dac7 jdk7-b74 d8dd291a362acb656026a9c0a9da48501505a1e7 jdk7-b75 +9174bb32e934965288121f75394874eeb1fcb649 jdk7-b76 diff --git a/jaxp/.hgtags b/jaxp/.hgtags index e3f8d778afd..9f0017be4e7 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -50,3 +50,4 @@ ff94d8ce0daded647bb326630e643d010357afce jdk7-b71 feb05980f9f2964e6bc2b3a8532f9b3054c2289b jdk7-b73 ea7b88c676dd8b269bc858a4a17c14dc96c8aed1 jdk7-b74 555fb78ee4cebed082ca7ddabff46d2e5b4c9026 jdk7-b75 +233a4871d3364ec305efd4a58cfd676620a03a90 jdk7-b76 diff --git a/jaxp/build.properties b/jaxp/build.properties index 9e5f63306c9..f31b4057a9e 100644 --- a/jaxp/build.properties +++ b/jaxp/build.properties @@ -34,6 +34,10 @@ drops.dir=${slashjava}/devtools/share/jdk7-drops # one of the standard user build.properties files (see build.xml) javac.jar=${bootstrap.dir}/lib/javac.jar +# The tools.jar is needed in the classpath to compile these sources +jdk.home=${java.home}/.. +tools.jar=${jdk.home}/lib/tools.jar + # options for the tasks used to compile the tools javac.source = 7 javac.target = 7 diff --git a/jaxp/build.xml b/jaxp/build.xml index 28831d69a0b..2f263826d21 100644 --- a/jaxp/build.xml +++ b/jaxp/build.xml @@ -113,7 +113,10 @@ - =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) +# +# http://www.aad.gov.au/default.asp?casid=37079 +# +# +# We have more background information here: +# +# http://www.timeanddate.com/news/time/antarctica-new-times.html +# + # 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: # # Casey Weather (1998-02-26) diff --git a/jdk/make/sun/javazic/tzdata/asia b/jdk/make/sun/javazic/tzdata/asia index 81534b919a4..139df5ee0e1 100644 --- a/jdk/make/sun/javazic/tzdata/asia +++ b/jdk/make/sun/javazic/tzdata/asia @@ -21,7 +21,6 @@ # CA 95054 USA or visit www.sun.com if you need additional information or # have any questions. # -#
 # 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"
+# 
+# http://www.thedailystar.net/newDesign/news-details.php?nid=107021
+# 
+# or
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_bangladesh04.html
+# 
+
+# 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:
+# 
+# http://www.thaindian.com/newsportal/business/bangladesh-to-continue-indefinitely-with-advanced-time_100259987.html
+# 
 
 # 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
+# 
+# http://www.hko.gov.hk/gts/time/Summertime.htm
+# .
+
+# From Arthur David Olson (2009-10-28):
+# Here are the dates given at
+# 
+# http://www.hko.gov.hk/gts/time/Summertime.htm
+# 
+# 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." 
+# 
+# http://www.thenews.com.pk/updates.asp?id=87168
+# 
+
+# 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"
+# 
+# http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=86715&Itemid=2
+# 
+# or
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_pakistan07.htm
+# 
+
+# 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:
+# 
+# http://www.thenews.com.pk/top_story_detail.asp?Id=24742
+# 
+# "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:
+# 
+# http://www.timeanddate.com/news/time/pakistan-ends-dst09.html
+# 
+
+# 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
 # 
 
+# 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:
+# 
+# http://www.safa.ps/ara/?action=showdetail&seid=4158
+# 
+# (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:
+# 
+# http://www.timeanddate.com/news/time/westbank-gaza-dst-2009.html
+# 
+
+# 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):
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_gazastrip02.html
+# 
+
 # 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
 # 
 
+# 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:
+# 
+# http://www.sana.sy/ara/2/2009/09/29/247012.htm (Arabic)
+# 
+
+# 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
diff --git a/jdk/make/sun/javazic/tzdata/australasia b/jdk/make/sun/javazic/tzdata/australasia
index 8e336dcea30..d9150b5ffd5 100644
--- a/jdk/make/sun/javazic/tzdata/australasia
+++ b/jdk/make/sun/javazic/tzdata/australasia
@@ -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
 # 
 
+# 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:
+# 
+# http://www.timeanddate.com/news/time/samoa-dst-plan-2009.html
+# 
+
+# 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
diff --git a/jdk/make/sun/javazic/tzdata/europe b/jdk/make/sun/javazic/tzdata/europe
index 16dbe0ee500..d7fffc23c7e 100644
--- a/jdk/make/sun/javazic/tzdata/europe
+++ b/jdk/make/sun/javazic/tzdata/europe
@@ -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)
+# 
+# http://www.government.ru/content/governmentactivity/rfgovernmentdecisions/archive/2009/09/14/991633.htm
+# 
+# or Russian-English translation by WorldTimeZone.com with reference
+# map to local region and new Russia Time Zone map after March 28, 2010
+# 
+# http://www.worldtimezone.com/dst_news/dst_news_russia03.html
+# 
+#
+# 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
diff --git a/jdk/make/sun/javazic/tzdata/southamerica b/jdk/make/sun/javazic/tzdata/southamerica
index c886a28b126..693fec63423 100644
--- a/jdk/make/sun/javazic/tzdata/southamerica
+++ b/jdk/make/sun/javazic/tzdata/southamerica
@@ -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
 # 
 
+# From fullinet (2009-10-18):
+# As announced in
+# 
+# http://www.argentina.gob.ar/argentina/portal/paginas.dhtml?pagina=356
+# 
+# (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
-# 
-# http://www.timeanddate.com/news/time/san-luis-new-time-zone.html
-# 
-# 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
+# 
+# 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
diff --git a/jdk/make/sun/javazic/tzdata/zone.tab b/jdk/make/sun/javazic/tzdata/zone.tab
index 2a323ebb90e..3e6f4657739 100644
--- a/jdk/make/sun/javazic/tzdata/zone.tab
+++ b/jdk/make/sun/javazic/tzdata/zone.tab
@@ -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
diff --git a/jdk/make/sun/net/FILES_java.gmk b/jdk/make/sun/net/FILES_java.gmk
index 19dd2d6d7f5..3473630012d 100644
--- a/jdk/make/sun/net/FILES_java.gmk
+++ b/jdk/make/sun/net/FILES_java.gmk
@@ -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)
diff --git a/jdk/make/sun/security/other/Makefile b/jdk/make/sun/security/other/Makefile
index 2722fbc32cd..a54c4aabbd6 100644
--- a/jdk/make/sun/security/other/Makefile
+++ b/jdk/make/sun/security/other/Makefile
@@ -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 \
diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java b/jdk/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java
index f8e028d197b..388d7a1b6fb 100644
--- a/jdk/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java
+++ b/jdk/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java
@@ -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 a = new PrivilegedAction() {
+                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 a = new PrivilegedAction() {
+                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;
+        }
+    }
 }
diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java
index 5323b0ac786..bc3a224c091 100644
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java
@@ -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;
     }
 
diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java
index a356b57caaf..a4354d26981 100644
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java
@@ -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;
     }
 
diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java
index 7b040ea1c7f..bfa958857c8 100644
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java
@@ -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;
     }
 }
diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java
index ea3769c2bc6..5029779bc9d 100644
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java
@@ -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;
     }
 
diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java
index 43af4139dcc..984667e547e 100644
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java
@@ -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;
     }
 
diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java
index 4ebc563e0cd..2de1f4ec351 100644
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java
@@ -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) {
diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java
index fa388195a4d..29c8221a66b 100644
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java
@@ -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;
     }
 
diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java
index 5abbf512de2..b0c74100999 100644
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java
@@ -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;
     }
 
diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java
index 43665829347..9d784278780 100644
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java
@@ -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;
     }
 
diff --git a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java
index 3b49ad5ee4e..f7a8707aabe 100644
--- a/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java
+++ b/jdk/src/share/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java
@@ -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;
     }
 
diff --git a/jdk/src/share/classes/com/sun/jmx/defaults/JmxProperties.java b/jdk/src/share/classes/com/sun/jmx/defaults/JmxProperties.java
index fcf769bf643..89cd5bf16bf 100644
--- a/jdk/src/share/classes/com/sun/jmx/defaults/JmxProperties.java
+++ b/jdk/src/share/classes/com/sun/jmx/defaults/JmxProperties.java
@@ -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.
      */
diff --git a/jdk/src/share/classes/com/sun/jmx/defaults/ServiceName.java b/jdk/src/share/classes/com/sun/jmx/defaults/ServiceName.java
index cc851e67ecf..7eea67f4b19 100644
--- a/jdk/src/share/classes/com/sun/jmx/defaults/ServiceName.java
+++ b/jdk/src/share/classes/com/sun/jmx/defaults/ServiceName.java
@@ -69,9 +69,9 @@ public class ServiceName {
     /**
      * The version of the JMX specification implemented by this product.
      * 
- * The value is 2.0. + * The value is 1.4. */ - 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. diff --git a/jdk/src/share/classes/com/sun/jmx/event/DaemonThreadFactory.java b/jdk/src/share/classes/com/sun/jmx/event/DaemonThreadFactory.java deleted file mode 100644 index ca2462b32ad..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/event/DaemonThreadFactory.java +++ /dev/null @@ -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"); -} diff --git a/jdk/src/share/classes/com/sun/jmx/event/EventBuffer.java b/jdk/src/share/classes/com/sun/jmx/event/EventBuffer.java deleted file mode 100644 index ed804791097..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/event/EventBuffer.java +++ /dev/null @@ -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()); - } - - public EventBuffer(int capacity, final List 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 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 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"); -} diff --git a/jdk/src/share/classes/com/sun/jmx/event/EventConnection.java b/jdk/src/share/classes/com/sun/jmx/event/EventConnection.java deleted file mode 100644 index adadef1931d..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/event/EventConnection.java +++ /dev/null @@ -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); - } - } -} diff --git a/jdk/src/share/classes/com/sun/jmx/event/EventParams.java b/jdk/src/share/classes/com/sun/jmx/event/EventParams.java deleted file mode 100644 index c0e76634cbd..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/event/EventParams.java +++ /dev/null @@ -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"); -} diff --git a/jdk/src/share/classes/com/sun/jmx/event/LeaseManager.java b/jdk/src/share/classes/com/sun/jmx/event/LeaseManager.java deleted file mode 100644 index 2db6fea146b..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/event/LeaseManager.java +++ /dev/null @@ -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; - -/** - *

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.

- * @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); - } - - /** - *

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.

- * - *

Calling this method after the lease has expired will return zero - * immediately and have no other effect.

- * - * @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; - } - - /** - *

Cancel the lease without calling the expiry callback.

- */ - 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"); - -} diff --git a/jdk/src/share/classes/com/sun/jmx/event/LeaseRenewer.java b/jdk/src/share/classes/com/sun/jmx/event/LeaseRenewer.java deleted file mode 100644 index 8ba6877221e..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/event/LeaseRenewer.java +++ /dev/null @@ -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 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 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"); -} diff --git a/jdk/src/share/classes/com/sun/jmx/event/ReceiverBuffer.java b/jdk/src/share/classes/com/sun/jmx/event/ReceiverBuffer.java deleted file mode 100644 index a87e2dfd6f5..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/event/ReceiverBuffer.java +++ /dev/null @@ -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 notifList - = new ArrayList(); - private long start = 0; - private int lost = 0; - - private static final ClassLogger logger = - new ClassLogger("javax.management.event", "ReceiverBuffer"); -} diff --git a/jdk/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java b/jdk/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java deleted file mode 100644 index 768ed6f30fa..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/event/RepeatedSingletonJob.java +++ /dev/null @@ -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; - -/** - *

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()}.

- * @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"); -} diff --git a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java index faa39e7656f..c959120e4a7 100644 --- a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java @@ -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>(); - 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(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(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 result = new ArrayList(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(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 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 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 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 doneTaskQueue = new LinkedList(); - 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); diff --git a/jdk/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java b/jdk/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java deleted file mode 100644 index f68e539d2fc..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java +++ /dev/null @@ -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. - *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * @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 - - 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 { - abstract Set query(MBeanServer mbs, - ObjectName pattern, QueryExp query); - } - - /** - * Used to perform queryNames. A QueryInvoker that invokes - * queryNames on an MBeanServer. - **/ - final static QueryInvoker queryNamesInvoker = - new QueryInvoker() { - Set 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 queryMBeansInvoker = - new QueryInvoker() { - Set 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; - } - Set query(ObjectName pattern, QueryExp query, - QueryInvoker invoker, MBeanServer server) { - return invoker.query(server, pattern, query); - } - - public Set queryNames(ObjectName pattern, QueryExp query) { - return query(pattern,query,queryNamesInvoker,wrapped); - } - - public Set 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 handlerMap = - Collections.synchronizedMap( - new HashMap()); - - // 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 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 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 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 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 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 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); - } - -} diff --git a/jdk/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java b/jdk/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java deleted file mode 100644 index 388af6b21dd..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java +++ /dev/null @@ -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. - *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * @since 1.7 - */ -// -// See comments in DispatchInterceptor. -// -class DomainDispatchInterceptor - extends DispatchInterceptor { - - /** - * 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 - Set query(ObjectName pattern, QueryExp query, - QueryInvoker invoker, MBeanServer localNamespace) { - final Set local = invoker.query(localNamespace, pattern, query); - - // Add all matching MBeans from local namespace. - final Set 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 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 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; - } -} diff --git a/jdk/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java b/jdk/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java deleted file mode 100644 index 8e1cf681e86..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/interceptor/MBeanServerInterceptorSupport.java +++ /dev/null @@ -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}. - *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * @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."); - } - -} diff --git a/jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java b/jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java deleted file mode 100644 index 5ab61f8933a..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java +++ /dev/null @@ -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. - *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * @since 1.7 - */ -public class NamespaceDispatchInterceptor - extends DispatchInterceptor { - - /** - * 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. - *

Do not forget to call initialize(outer,delegate) - * 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: - *

-     *  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                      ->      ""
-     *
-     * 
- **/ - 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 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 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 postDeregisterQueue) { - if (handler instanceof JMXDomain) - nextInterceptor.removeInterceptorFor(name,(JMXDomain)handler, - postDeregisterQueue); - else super.removeInterceptorFor(name,handler,postDeregisterQueue); - } - - -} diff --git a/jdk/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java b/jdk/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java deleted file mode 100644 index cfb40092557..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/interceptor/SingleMBeanForwarder.java +++ /dev/null @@ -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; - -/** - *

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.

- */ -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 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 domainSet = new TreeSet(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 queryMBeans(ObjectName name, QueryExp query) { - Set 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 queryNames(ObjectName name, QueryExp query) { - Set 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); - } -} diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/ConvertingMethod.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/ConvertingMethod.java index 62239b5a984..37596dff260 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/ConvertingMethod.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/ConvertingMethod.java @@ -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(); diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java index 1b653c28eaf..99b3ce30d25 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java @@ -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> {} - private static final Map factoryMappings = - new WeakHashMap(); + private static final Mappings mappings = new Mappings(); - private static final Map permanentMappings = newMap(); + /** Following List simply serves to keep a reference to predefined + MXBeanMappings so they don't get garbage collected. */ + private static final List 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 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 wr = new WeakReference(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 c = mappingClass.value(); - Constructor 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 or ) - * and since we don't treat this as Foo elsewhere we shouldn't here. - */ - return Object.class; - } - private static > MXBeanMapping makeEnumMapping(Class enumClass, Class fake) { return new EnumMapping(Util.>cast(enumClass)); diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/DynamicMBean2.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/DynamicMBean2.java index d67b1660703..49d49ce4c1f 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/DynamicMBean2.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/DynamicMBean2.java @@ -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(). diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java index ba27f6e8398..09b5701a95e 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java @@ -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); } - /** - *

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}.

- * @param mbean the object to convert to a DynamicMBean. - * @param 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 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 Class getStandardMBeanInterface(Class baseClass) throws NotCompliantMBeanException { - if (baseClass.isAnnotationPresent(MBean.class)) - return baseClass; Class current = baseClass; Class mbeanInterface = null; while (current != null) { @@ -384,8 +318,6 @@ public class Introspector { */ public static Class getMXBeanInterface(Class 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 Class getStandardOrMXBeanInterface( - Class 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 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 descriptorMap = new HashMap(); for (Annotation a : annots) { - if (a instanceof DescriptorFields) - addDescriptorFieldsToMap(descriptorMap, (DescriptorFields) a); - addAnnotationFieldsToMap(descriptorMap, a); + Class 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 set = new LinkedHashSet(); - for(Classex : exceptions) - set.add(ex.getName()); - - String[] arr = new String[set.size()]; - return set.toArray(arr); - } - - private static void addDescriptorFieldsToMap( - Map 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 descriptorMap, Annotation a) { - Class 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 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 diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java index 4fc25e91278..cffae534312 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/JmxMBeanServer.java @@ -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; - /** * Package: 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); diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanAnalyzer.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanAnalyzer.java index e6f7e1f94b0..2619e29c706 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanAnalyzer.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanAnalyzer.java @@ -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 { - static interface MBeanVisitor { + static interface MBeanVisitor { public void visitAttribute(String attributeName, M getter, - M setter) throws X; + M setter); public void visitOperation(String operationName, - M operation) throws X; + M operation); } - void visit(MBeanVisitor visitor) throws X { + void visit(MBeanVisitor visitor) { // visit attributes for (Map.Entry> entry : attrMap.entrySet()) { String name = entry.getKey(); @@ -108,7 +104,10 @@ class MBeanAnalyzer { private MBeanAnalyzer(Class mbeanType, MBeanIntrospector 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 { 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 am = attrMap.get(attrName); @@ -165,7 +156,7 @@ class MBeanAnalyzer { 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 am = attrMap.get(attrName); @@ -178,9 +169,6 @@ class MBeanAnalyzer { } 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 cms = opMap.get(name); diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java deleted file mode 100644 index 4917d089e8d..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java +++ /dev/null @@ -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, List> fields; - private Map, List> 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); - } - - void inject(Object instance, Class type, T resource) - throws Exception { - List fs = fields.get(type); - if (fs != null) { - for (Field f : fs) - f.set(instance, resource); - } - List 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, List> entry : methods.entrySet()) { - List 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() { - 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() { - public Void run() { - member.setAccessible(true); - return null; - } - }); - addToMap(fields, injectedClass, field); - addToMap(methods, injectedClass, method); - } - } - } - } - } - - private static void addToMap(Map> map, K key, V value) { - if (value == null) - return; - List list = map.get(key); - if (list == null) - list = Collections.singletonList(value); - else { - if (list.size() == 1) - list = new ArrayList(list); - list.add(value); - } - map.put(key, list); - } - } - - private static synchronized ClassInjector injectorForClass(Class c) - throws NotCompliantMBeanException { - WeakReference wr = injectorMap.get(c); - ClassInjector ci = (wr == null) ? null : wr.get(); - if (ci == null) { - ci = new ClassInjector(c); - injectorMap.put(c, new WeakReference(ci)); - } - return ci; - } - - private static Map, WeakReference> injectorMap = - new WeakHashMap, WeakReference>(); -} diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java index f3bd67e2f23..992eba31419 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java @@ -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. diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java index e98b41bbaa9..9edde66faf2 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java @@ -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 { +abstract class MBeanIntrospector { static final class PerInterfaceMap extends WeakHashMap, WeakReference>> {} @@ -159,27 +151,7 @@ public abstract class MBeanIntrospector { * 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 { */ 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 getMethods(final Class mbeanType) throws Exception { - if (mbeanType.isInterface()) - return Arrays.asList(mbeanType.getMethods()); - - final List methods = newList(); - getAnnotatedMethods(mbeanType, methods); - return methods; + return Arrays.asList(mbeanType.getMethods()); } final PerInterface getPerInterface(Class mbeanInterface) @@ -265,14 +211,11 @@ public abstract class MBeanIntrospector { * the MBeanInfo's Descriptor. */ private MBeanInfo makeInterfaceMBeanInfo(Class mbeanInterface, - MBeanAnalyzer analyzer) throws IntrospectionException { + MBeanAnalyzer 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 { /** A visitor that constructs the per-interface MBeanInfo. */ private class MBeanInfoMaker - implements MBeanAnalyzer.MBeanVisitor { + implements MBeanAnalyzer.MBeanVisitor { 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 { 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 { * Return the MBeanInfo for the given resource, based on the given * per-interface data. */ - final MBeanInfo getMBeanInfo(Object resource, PerInterface perInterface) - throws NotCompliantMBeanException { + final MBeanInfo getMBeanInfo(Object resource, PerInterface 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 { } } - /* - * 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 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 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 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, WeakReference>> - annotatedNotificationInfoClasses = newWeakHashMap(); - - private static Class getAnnotatedNotificationInfoClass(Class baseClass) { - synchronized (annotatedNotificationInfoClasses) { - WeakReference> 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>(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; diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java index 20a776534ce..c5ad4e735a7 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanSupport.java @@ -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 implements DynamicMBean2, MBeanRegistration { - MBeanSupport(T resource, Class mbeanInterfaceType, - MXBeanMappingFactory mappingFactory) + MBeanSupport(T resource, Class mbeanInterfaceType) throws NotCompliantMBeanException { if (mbeanInterfaceType == null) throw new NotCompliantMBeanException("Null MBean interface"); @@ -133,14 +132,13 @@ public abstract class MBeanSupport throw new NotCompliantMBeanException(msg); } this.resource = resource; - MBeanIntrospector introspector = getMBeanIntrospector(mappingFactory); + MBeanIntrospector introspector = getMBeanIntrospector(); this.perInterface = introspector.getPerInterface(mbeanInterfaceType); this.mbeanInfo = introspector.getMBeanInfo(resource, perInterface); } /** Return the appropriate introspector for this type of MBean. */ - abstract MBeanIntrospector - getMBeanIntrospector(MXBeanMappingFactory mappingFactory); + abstract MBeanIntrospector getMBeanIntrospector(); /** * Return a cookie for this MBean. This cookie will be passed to @@ -262,14 +260,10 @@ public abstract class MBeanSupport 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(); } diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java index fb9b3ccb093..ea326f39416 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java @@ -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 { - /* 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> map = - new WeakHashMap>(); + private static final MXBeanIntrospector instance = new MXBeanIntrospector(); - static MXBeanIntrospector getInstance(MXBeanMappingFactory factory) { - if (factory == null) - factory = MXBeanMappingFactory.DEFAULT; - synchronized (map) { - MXBeanIntrospector intro; - WeakReference wr = map.get(factory); - if (wr != null) { - intro = wr.get(); - if (intro != null) - return intro; - } - intro = new MXBeanIntrospector(factory); - wr = new WeakReference(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 { @Override ConvertingMethod mFrom(Method m) { - return ConvertingMethod.from(m, mappingFactory); + return ConvertingMethod.from(m); } @Override @@ -176,17 +142,13 @@ class MXBeanIntrospector extends MBeanIntrospector { @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 { 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 { 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 { 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 { 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 { private final PerInterfaceMap perInterfaceMap = new PerInterfaceMap(); - private final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap(); - - private final MXBeanMappingFactory mappingFactory; + private static final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap(); } diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java index 605c67f16b4..9034cdb4817 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java @@ -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 weakLookup = mbscToLookup.get(mbsc); + MXBeanLookup lookup = (weakLookup == null) ? null : weakLookup.get(); + if (lookup == null) { + lookup = new MXBeanLookup(mbsc); + mbscToLookup.put(mbsc, new WeakReference(lookup)); + } + return lookup; + } } - abstract T objectNameToMXBean(ObjectName name, Class type) - throws InvalidObjectException; - - abstract ObjectName mxbeanToObjectName(Object mxbean) - throws OpenDataException; - - static class Plain extends MXBeanLookup { - Plain(MBeanServerConnection mbsc) { - super(mbsc); + synchronized T objectNameToMXBean(ObjectName name, Class type) { + WeakReference 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(proxy)); + return proxy; + } - static Plain lookupFor(MBeanServerConnection mbsc) { - synchronized (mbscToLookup) { - WeakReference weakLookup = mbscToLookup.get(mbsc); - Plain lookup = (weakLookup == null) ? null : weakLookup.get(); - if (lookup == null) { - lookup = new Plain(mbsc); - mbscToLookup.put(mbsc, new WeakReference(lookup)); - } - return lookup; - } - } - - @Override - synchronized T objectNameToMXBean(ObjectName name, Class type) { - WeakReference 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(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 - mxbeanToObjectName = WeakIdentityHashMap.make(); - private final Map> - objectNameToProxy = newMap(); - private static WeakIdentityHashMap> - 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 objectNameToMXBean(ObjectName name, Class 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 currentLookup = new ThreadLocal(); - final MBeanServerConnection mbsc; + private final MBeanServerConnection mbsc; + private final WeakIdentityHashMap + mxbeanToObjectName = WeakIdentityHashMap.make(); + private final Map> + objectNameToProxy = newMap(); + private static final WeakIdentityHashMap> + mbscToLookup = WeakIdentityHashMap.make(); } diff --git a/jdk/src/share/classes/javax/management/openmbean/MXBeanMapping.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanMapping.java similarity index 97% rename from jdk/src/share/classes/javax/management/openmbean/MXBeanMapping.java rename to jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanMapping.java index 339fbb21c09..5fb0e0fa366 100644 --- a/jdk/src/share/classes/javax/management/openmbean/MXBeanMapping.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanMapping.java @@ -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; /** *

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); } } diff --git a/jdk/src/share/classes/javax/management/openmbean/MXBeanMappingFactory.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanMappingFactory.java similarity index 72% rename from jdk/src/share/classes/javax/management/openmbean/MXBeanMappingFactory.java rename to jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanMappingFactory.java index f1dc6bcc080..7aab8555501 100644 --- a/jdk/src/share/classes/javax/management/openmbean/MXBeanMappingFactory.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanMappingFactory.java @@ -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(); - /** - *

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.

- * - * @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 factoryClass = annot.value(); - try { - return annot.value().newInstance(); - } catch (Exception e) { - throw new IllegalArgumentException( - "Could not instantiate MXBeanMappingFactory " + - factoryClass.getName() + - " from @MXBeanMappingFactoryClass", e); - } - } - /** *

Return the mapping for the given Java type. Typically, a * mapping factory will return mappings for types it handles, and diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanProxy.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanProxy.java index 1ad7598f126..1f2f19ad6d5 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanProxy.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanProxy.java @@ -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; /**

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 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 { + implements MBeanAnalyzer.MBeanVisitor { 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 handlerMap = newMap(); } diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanSupport.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanSupport.java index 7a9c5d2e7a8..9f8b6bebde8 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanSupport.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanSupport.java @@ -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 { if it does not implement the class {@code mxbeanInterface} or if that class is not a valid MXBean interface. */ - public MXBeanSupport(T resource, Class mxbeanInterface, - MXBeanMappingFactory mappingFactory) + public MXBeanSupport(T resource, Class mxbeanInterface) throws NotCompliantMBeanException { - super(resource, mxbeanInterface, mappingFactory); + super(resource, mxbeanInterface); } @Override - MBeanIntrospector - getMBeanIntrospector(MXBeanMappingFactory mappingFactory) { - return MXBeanIntrospector.getInstance(mappingFactory); + MBeanIntrospector getMBeanIntrospector() { + return MXBeanIntrospector.getInstance(); } @Override @@ -159,8 +156,8 @@ public class MXBeanSupport extends MBeanSupport { // 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 { 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; } diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/NotificationMBeanSupport.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/NotificationMBeanSupport.java deleted file mode 100644 index 08964f7dc2b..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/NotificationMBeanSupport.java +++ /dev/null @@ -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; - -/** - *

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 NotificationMBeanSupport(T n) - throws NotCompliantMBeanException { - super(n, Util.>cast(n.getClass())); - } - - @Override - MBeanIntrospector getMBeanIntrospector(MXBeanMappingFactory ignored) { - return introspector; - } - - private static class Introspector extends StandardMBeanIntrospector { - @Override - void checkCompliance(Class mbeanType) {} - - @Override - List getMethods(final Class mbeanType) - throws Exception { - List methods = new ArrayList(); - 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 introspector = - new Introspector(); -} diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/NotifySupport.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/NotifySupport.java deleted file mode 100644 index 00fbb027352..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/NotifySupport.java +++ /dev/null @@ -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; - } -} diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/PerInterface.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/PerInterface.java index 59fd71cdb98..d20fe5f5239 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/PerInterface.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/PerInterface.java @@ -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 { /** * Visitor that sets up the method maps (operations, getters, setters). */ - private class InitMaps implements MBeanAnalyzer.MBeanVisitor { + private class InitMaps implements MBeanAnalyzer.MBeanVisitor { public void visitAttribute(String attributeName, M getter, M setter) { diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/PerThreadGroupPool.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/PerThreadGroupPool.java deleted file mode 100644 index 2946f16fa12..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/PerThreadGroupPool.java +++ /dev/null @@ -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; - -/** - *

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.

- */ -// 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 { - private final WeakIdentityHashMap> map = - WeakIdentityHashMap.make(); - - public static interface Create { - public T createThreadPool(ThreadGroup group); - } - - private PerThreadGroupPool() {} - - public static PerThreadGroupPool make() { - return new PerThreadGroupPool(); - } - - public synchronized T getThreadPoolExecutor(Create 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 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(executor)); - } - return executor; - } -} diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Repository.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Repository.java index 03f3e5277bd..e35ac65c9b7 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Repository.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Repository.java @@ -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 moiTb = domainTb.get(dom); if (allNames) result.addAll(moiTb.values()); diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanIntrospector.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanIntrospector.java index 87aa9301d7a..2237a5192cd 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanIntrospector.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanIntrospector.java @@ -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 { @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 diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanSupport.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanSupport.java index 4b9963eee49..3deeb168c0e 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanSupport.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/StandardMBeanSupport.java @@ -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 { */ public StandardMBeanSupport(T resource, Class mbeanInterfaceType) throws NotCompliantMBeanException { - super(resource, mbeanInterfaceType, (MXBeanMappingFactory) null); + super(resource, mbeanInterfaceType); } @Override - MBeanIntrospector getMBeanIntrospector(MXBeanMappingFactory ignored) { + MBeanIntrospector getMBeanIntrospector() { return StandardMBeanIntrospector.getInstance(); } @@ -84,14 +83,13 @@ public class StandardMBeanSupport extends MBeanSupport { @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()); } } diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java index 1e575e419d2..b0a8eeb84c0 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java @@ -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 Map newMap() { return new HashMap(); @@ -89,10 +80,6 @@ public class Util { return new LinkedHashMap(); } - static WeakHashMap newWeakHashMap() { - return new WeakHashMap(); - } - static Set newSet() { return new HashSet(); } @@ -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 ////...// matches ////...// - * 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 filterMatchingNames(ObjectName pattern, - Set 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 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 - filterMatchingInstances(ObjectName pattern, - Set 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 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=[;*]]} 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=[;*]]} - * @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 Set cloneSet(Set set) { - if (set instanceof SortedSet) { - @SuppressWarnings("unchecked") - SortedSet sset = (SortedSet) set; - set = new TreeSet(sset.comparator()); - set.addAll(sset); - } else - set = new HashSet(set); - return set; - } - - public static Set equivalentEmptySet(Set set) { - if (set instanceof SortedSet) { - @SuppressWarnings("unchecked") - SortedSet sset = (SortedSet) set; - set = new TreeSet(sset.comparator()); - } else - set = new HashSet(); - 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); - } } diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java b/jdk/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java deleted file mode 100644 index 6e56c8385e8..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java +++ /dev/null @@ -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. - *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * @since 1.7 - */ -public class DomainInterceptor extends HandlerInterceptor { - - // 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 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 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 processOutputInstances(Set sources) { - if (sources == null || sources.isEmpty() || !checkOn()) - return sources; - final Set 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 processOutputNames(Set sourceNames) { - if (sourceNames == null || sourceNames.isEmpty() || !checkOn()) - return sourceNames; - final Set 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 queryNames(ObjectName name, QueryExp query) { - try { - // We don't trust the wrapped JMXDomain... - final ObjectName pattern = getPatternFor(name); - final Set 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 queryMBeans(ObjectName name, QueryExp query) { - try { - // We don't trust the wrapped JMXDomain... - final ObjectName pattern = getPatternFor(name); - final Set 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 res = new ArrayList(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 - * This API is a Sun internal API and is subject to changes without notice. - *

- * @since 1.7 - */ -public abstract class HandlerInterceptor - extends RoutingMBeanServerConnection - 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 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 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 //}. - * @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 //}. - * @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 //}. - * @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 //}. - * @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. - *

- * 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); - } - - - -} diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java b/jdk/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java deleted file mode 100644 index df03ed5ecba..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/namespace/NamespaceInterceptor.java +++ /dev/null @@ -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. - *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * @since 1.7 - */ -public class NamespaceInterceptor extends HandlerInterceptor { - - - // 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 res = new ArrayList(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; - } - } - -} diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java b/jdk/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java deleted file mode 100644 index 55a6465407c..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/namespace/ObjectNameRouter.java +++ /dev/null @@ -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. - *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * @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 0) - b.append(NAMESPACE_SEPARATOR); - return b.toString(); - } -} diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java deleted file mode 100644 index b09bc84365c..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingConnectionProxy.java +++ /dev/null @@ -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)}. - *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * @since 1.7 - */ -// See class hierarchy and detailled explanations in RoutingProxy in this -// package. -// -public class RoutingConnectionProxy - extends RoutingProxy { - - /** - * 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 - - FACTORY = new RoutingProxyFactory - () { - - 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); - } - -} diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java deleted file mode 100644 index 49b8290046b..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingMBeanServerConnection.java +++ /dev/null @@ -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). - *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * @since 1.7 - */ -public abstract class RoutingMBeanServerConnection - 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 processOutputInstances(Set sources) { - - final Set 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 processOutputNames(Set sourceNames) { - - final Set 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 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 queryNames(ObjectName name, QueryExp query) - throws IOException { - if (name == null) name=ObjectName.WILDCARD; - final ObjectName sourceName = toSourceOrRuntime(name); - try { - final Set tmp = source().queryNames(sourceName,query); - final Set 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; - } - -} diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java deleted file mode 100644 index 03531200cb6..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingProxy.java +++ /dev/null @@ -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: - *

{@link RoutingConnectionProxy}: to narrow down into an - * MBeanServerConnection.

- *

{@link RoutingServerProxy}: to narrow down into an MBeanServer.

- * - *

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).

- * - *

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.

- * - *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * @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 'to add' -// -// For a RoutingProxy used in a ClientContext operation, we have: -// targetNs= // 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 - extends RoutingMBeanServerConnection { - - /** - * 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 - // RoutingServerProxy and RoutingConnectionProxy have their own factory - // instance. - static interface RoutingProxyFactory> { - 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 > - R cd(Class routingProxyClass, - RoutingProxyFactory 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); - } -} diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java b/jdk/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java deleted file mode 100644 index a11b0eccbf5..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/namespace/RoutingServerProxy.java +++ /dev/null @@ -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. - *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * - * @since 1.7 - */ -// See class hierarchy and detailled explanations in RoutingProxy in this -// package. -// -public class RoutingServerProxy - extends RoutingProxy - 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 x. - **/ - 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 queryMBeans(ObjectName name, QueryExp query) { - try { - return super.queryMBeans(name, query); - } catch (IOException x) { - handleIOException(x,"queryMBeans"); - return Collections.emptySet(); - } - } - - @Override - public Set 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 - FACTORY = new RoutingProxyFactory() { - - 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); - } -} diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/package.html b/jdk/src/share/classes/com/sun/jmx/namespace/package.html deleted file mode 100644 index 6677288ca88..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/namespace/package.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - The <code>com.sun.jmx.namespace</code> package - - - -

The com.sun.jmx.namespace package contains - sun specific implementation classes used to implement the - JMX namespaces. -

-

DO NOT USE THESE CLASSES DIRECTLY

-

- This API is a Sun internal API and is subject to changes without notice. -

-

The public API through wich these proprietary classes can be - invoked is located in javax.management.namespace - package. -

- - diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/serial/DefaultRewritingProcessor.java b/jdk/src/share/classes/com/sun/jmx/namespace/serial/DefaultRewritingProcessor.java deleted file mode 100644 index f458378cbcc..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/namespace/serial/DefaultRewritingProcessor.java +++ /dev/null @@ -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. - *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * @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 rewriteInput(T input) { - if (identity) return input; - return (T) processObject(RewriteMode.INPUT,input); - } - - @SuppressWarnings("unchecked") - @Override - public T rewriteOutput(T result) { - if (identity) return result; - return (T) processObject(RewriteMode.OUTPUT,result); - } -} diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/serial/JMXNamespaceContext.java b/jdk/src/share/classes/com/sun/jmx/namespace/serial/JMXNamespaceContext.java deleted file mode 100644 index 6416bfb9644..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/namespace/serial/JMXNamespaceContext.java +++ /dev/null @@ -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. - *

- * 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. - *

- * 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}. - * - *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * @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 prefix = - new ThreadLocal() { - @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); - } - } - } - -} diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/serial/RewritingProcessor.java b/jdk/src/share/classes/com/sun/jmx/namespace/serial/RewritingProcessor.java deleted file mode 100644 index 2c81be934c5..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/namespace/serial/RewritingProcessor.java +++ /dev/null @@ -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}. - *

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}. - *

- *

Objects that need to perform these operations usually use a - * {@code RewritingProcessor} for that purpose.
- * 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 ""}. - *
- * 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). - *
- * 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}. - *
- * An implementation of {@code RewritingProcessor} should make sure that - * rewriteInput(rewriteOutput(x,clp),clp) and - * rewriteOutput(rewriteInput(x,clp),clp) always return - * {@code x} or an exact clone of {@code x}. - *

- *

A default implementation of {@code RewritingProcessor} based on - * Java Object Serialization can be - * obtained from {@link #newRewritingProcessor newRewritingProcessor}. - *

- *

- * 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. - *

- *

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: - *

- * public class MyRewritingProcessor extends RewritingProcessor {
- *      MyRewritingProcessor(String remove, String add) {
- *          this(RewritingProcessor.newRewritingProcessor(remove,add));
- *      }
- *      MyRewritingProcessor(RewritingProcessor delegate) {
- *          super(delegate);
- *      }
- *
- *   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 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);
- *      }
- * }
- * 
- *

- *

Such a subclass may also provide an alternate way of rewriting - * custom subclasses for which rewriting is needed - for instance: - *

- * public class MyRewritingProcessor extends RewritingProcessor {
- *      MyRewritingProcessor(String remove, String add) {
- *          this(RewritingProcessor.newRewritingProcessor(remove,add));
- *      }
- *      MyRewritingProcessor(RewritingProcessor delegate) {
- *          super(delegate);
- *      }
- *
- *   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 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);
- *      }
- * }
- * 
- *

- *

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. - *

- *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * @since 1.7 - */ -public abstract class RewritingProcessor { - /** - * A logger for this class. - **/ - private final RewritingProcessor delegate; - - /** - * Creates a new instance of RewritingProcessor. - *

This is equivalent to calling {@link - * #RewritingProcessor(RewritingProcessor) RewritingProcessor(null)}. - *

- **/ - 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}. - *

- * 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. - *

- *

- * 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)}. - *

- *

This behavior can be overridden by subclasses as shown in this - * class {@link RewritingProcessor description}. - *

- * @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 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}. - *

- * 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. - *

- *

- * 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)}. - *

- *

This behavior can be overridden by subclasses as shown in this - * class {@link RewritingProcessor description}. - *

- * @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 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}. - *

- * 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)}. - *

- *

This behavior can be overridden by subclasses as shown in this - * class {@link RewritingProcessor description}. - *

- * @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}. - *

- * 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)}. - *

- *

This behavior can be overridden by subclasses as shown in this - * class {@link RewritingProcessor description}. - *

- * @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}. - *

- * 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)}. - *

- *

This behavior can be overridden by subclasses as shown in this - * class {@link RewritingProcessor description}. - *

- * @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); - } - -} diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java b/jdk/src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java deleted file mode 100644 index 1df2e26a9c8..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/namespace/serial/RoutingOnlyProcessor.java +++ /dev/null @@ -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... - * - *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * @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); - } -} diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java b/jdk/src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java deleted file mode 100644 index d7e879822e3..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/namespace/serial/SerialRewritingProcessor.java +++ /dev/null @@ -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... - *

- * This API is a Sun internal API and is subject to changes without notice. - *

- * @since 1.7 - */ -class SerialRewritingProcessor extends RewritingProcessor { - - - private static class CloneOutput extends ObjectOutputStream { - Queue> classQueue = new LinkedList>(); - - 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 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 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 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); - } - } - -} diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/serial/package.html b/jdk/src/share/classes/com/sun/jmx/namespace/serial/package.html deleted file mode 100644 index fe2e8c64b94..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/namespace/serial/package.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - The <code>com.sun.jmx.namespace.serial</code> package - - - -

The com.sun.jmx.namespace.serial package contains - sun specific implementation classes used to switch namespace - prefixes in ObjectName during serialization. -

-

NEVER USE THESE CLASSES DIRECTLY

-

- This API is a Sun internal API and is subject to changes without notice. -

-

The public API through which these proprietary classes can be invoked is - located in javax.management.namespace.JMXNamespaces -

- - diff --git a/jdk/src/share/classes/com/sun/jmx/remote/internal/IIOPHelper.java b/jdk/src/share/classes/com/sun/jmx/remote/internal/IIOPHelper.java new file mode 100644 index 00000000000..c66aa8773e1 --- /dev/null +++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/IIOPHelper.java @@ -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() { + 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 narrow(Object narrowFrom, Class 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); + } +} diff --git a/jdk/src/share/classes/com/sun/jmx/remote/internal/IIOPProxy.java b/jdk/src/share/classes/com/sun/jmx/remote/internal/IIOPProxy.java new file mode 100644 index 00000000000..9c971afc6f3 --- /dev/null +++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/IIOPProxy.java @@ -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 narrow(Object narrowFrom, Class 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; +} diff --git a/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java b/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java index dab9b872d64..14b2f5d82b5 100644 --- a/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java +++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/ServerNotifForwarder.java @@ -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() { 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 action = new PrivilegedAction() { - 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> listenerMap = + private final Map> listenerMap = new HashMap>(); private boolean terminated = false; diff --git a/jdk/src/share/classes/com/sun/jmx/remote/protocol/iiop/IIOPProxyImpl.java b/jdk/src/share/classes/com/sun/jmx/remote/protocol/iiop/IIOPProxyImpl.java new file mode 100644 index 00000000000..9d428e5ae23 --- /dev/null +++ b/jdk/src/share/classes/com/sun/jmx/remote/protocol/iiop/IIOPProxyImpl.java @@ -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 narrow(Object narrowFrom, Class 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); + } +} diff --git a/jdk/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java b/jdk/src/share/classes/com/sun/jmx/remote/protocol/iiop/ProxyInputStream.java similarity index 99% rename from jdk/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java rename to jdk/src/share/classes/com/sun/jmx/remote/protocol/iiop/ProxyInputStream.java index b610828065a..205c10fe394 100644 --- a/jdk/src/share/classes/com/sun/jmx/remote/internal/ProxyInputStream.java +++ b/jdk/src/share/classes/com/sun/jmx/remote/protocol/iiop/ProxyInputStream.java @@ -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; diff --git a/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java b/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java index e95c1e049df..daee2d1210e 100644 --- a/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java +++ b/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java @@ -780,25 +780,6 @@ public class EnvHelp { return new Hashtable(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 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 env) { - return computeBooleanFromString(env, - JMXConnectorServer.DELEGATE_TO_EVENT_SERVICE, true, true); - } - /** *

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))); } -// /** -// *

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 , 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) {} diff --git a/jdk/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java b/jdk/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java deleted file mode 100644 index d02da69c047..00000000000 --- a/jdk/src/share/classes/com/sun/jmx/remote/util/EventClientConnection.java +++ /dev/null @@ -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 eventClientFactory) { - - if (connection == null) { - throw new IllegalArgumentException("Null connection"); - } - this.connection = connection; - if (eventClientFactory == null) { - eventClientFactory = new Callable() { - public final EventClient call() throws Exception { - return createEventClient(EventClientConnection.this.connection); - } - }; - } - this.eventClientFactory = eventClientFactory; - this.lock = new ReentrantLock(); - } - - /** - *

The MBean server connection through which the methods of - * a proxy using this handler are forwarded.

- * - * @return the MBean server connection. - * - * @since 1.6 - */ - public MBeanServerConnection getMBeanServerConnection() { - return connection; - } - - - - - /** - * Creates a new EventClientConnection proxy instance. - * - * @param 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 - newProxyInstance(T connection, - Class interfaceClass, Callable 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.
- * 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 connection 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 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 eventClientFactory; - private final Lock lock; - private volatile EventClient client = null; - private volatile boolean initialized = false; - -} diff --git a/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java b/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java index 2807e19d36f..364f000c839 100644 --- a/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java +++ b/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java @@ -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); diff --git a/jdk/src/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java b/jdk/src/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java index 85330c651f1..5f089c56332 100644 --- a/jdk/src/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java +++ b/jdk/src/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java @@ -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(); diff --git a/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/DelegateHttpsURLConnection.java b/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/DelegateHttpsURLConnection.java index e0512a33b87..b2459cb71f2 100644 --- a/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/DelegateHttpsURLConnection.java +++ b/jdk/src/share/classes/com/sun/net/ssl/internal/www/protocol/https/DelegateHttpsURLConnection.java @@ -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; diff --git a/jdk/src/share/classes/java/applet/Applet.java b/jdk/src/share/classes/java/applet/Applet.java index 0e2bcb87b56..b12e6fb3081 100644 --- a/jdk/src/share/classes/java/applet/Applet.java +++ b/jdk/src/share/classes/java/applet/Applet.java @@ -229,6 +229,21 @@ public class Applet extends Panel { resize(d.width, d.height); } + /** + * Indicates if this container is a validate root. + *

+ * {@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 diff --git a/jdk/src/share/classes/java/awt/AWTPermission.java b/jdk/src/share/classes/java/awt/AWTPermission.java index b6eb03f62c7..84b400f53d9 100644 --- a/jdk/src/share/classes/java/awt/AWTPermission.java +++ b/jdk/src/share/classes/java/awt/AWTPermission.java @@ -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; * Enter full-screen exclusive mode * 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. + * 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. * * * diff --git a/jdk/src/share/classes/java/awt/Component.java b/jdk/src/share/classes/java/awt/Component.java index e9c274fcb42..6a942e9ec5d 100644 --- a/jdk/src/share/classes/java/awt/Component.java +++ b/jdk/src/share/classes/java/awt/Component.java @@ -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 Container. + * Validates this component. + *

+ * The meaning of the term validating 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. + *

+ * 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 invalid indicates + * that the container needs to be laid out. + *

+ * 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). + *

+ * 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); } } diff --git a/jdk/src/share/classes/java/awt/Container.java b/jdk/src/share/classes/java/awt/Container.java index 010d8b08ac3..94273ade4cb 100644 --- a/jdk/src/share/classes/java/awt/Container.java +++ b/jdk/src/share/classes/java/awt/Container.java @@ -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 validate root. + *

+ * 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. + *

+ * 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. + *

+ * The {@code Window} class and the {@code Applet} class are the validate + * roots in AWT. Swing introduces more validate roots. * - *

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. + *

+ * 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. + *

+ * 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. *

- * The validate 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. - * - *

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. + *

+ * 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. + *

+ * 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. - *

- * 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 diff --git a/jdk/src/share/classes/java/awt/EventQueue.java b/jdk/src/share/classes/java/awt/EventQueue.java index 3e9febf79b7..b5635f4a25c 100644 --- a/jdk/src/share/classes/java/awt/EventQueue.java +++ b/jdk/src/share/classes/java/awt/EventQueue.java @@ -1027,7 +1027,9 @@ public class EventQueue { synchronized (lock) { Toolkit.getEventQueue().postEvent(event); - lock.wait(); + while (!event.isDispatched()) { + lock.wait(); + } } Throwable eventThrowable = event.getThrowable(); diff --git a/jdk/src/share/classes/java/awt/Frame.java b/jdk/src/share/classes/java/awt/Frame.java index 761b9b8420b..ea8c6154cf1 100644 --- a/jdk/src/share/classes/java/awt/Frame.java +++ b/jdk/src/share/classes/java/awt/Frame.java @@ -845,8 +845,11 @@ public class Frame extends Window implements MenuContainer { * others by setting those fields you want to accept from system * to Integer.MAX_VALUE. *

- * On some systems only the size portion of the bounds is taken - * into account. + * Note, the given maximized bounds are used as a hint for the native + * system, because the underlying platform may not support setting the + * location and/or size of the maximized windows. If that is the case, the + * provided values do not affect the appearance of the frame in the + * maximized state. * * @param bounds bounds for the maximized state * @see #getMaximizedBounds() diff --git a/jdk/src/share/classes/java/awt/KeyboardFocusManager.java b/jdk/src/share/classes/java/awt/KeyboardFocusManager.java index da94b624be0..fd412d8646e 100644 --- a/jdk/src/share/classes/java/awt/KeyboardFocusManager.java +++ b/jdk/src/share/classes/java/awt/KeyboardFocusManager.java @@ -53,7 +53,8 @@ import java.util.Set; import java.util.StringTokenizer; import java.util.WeakHashMap; -import sun.util.logging.PlatformLogger; +import java.util.logging.Level; +import java.util.logging.Logger; import sun.awt.AppContext; import sun.awt.HeadlessToolkit; @@ -110,7 +111,7 @@ public abstract class KeyboardFocusManager { // Shared focus engine logger - private static final PlatformLogger focusLog = PlatformLogger.getLogger("java.awt.focus.KeyboardFocusManager"); + private static final Logger focusLog = Logger.getLogger("java.awt.focus.KeyboardFocusManager"); static { /* ensure that the necessary native libraries are loaded */ @@ -153,7 +154,7 @@ public abstract class KeyboardFocusManager */ private static native void initIDs(); - private static final PlatformLogger log = PlatformLogger.getLogger("java.awt.KeyboardFocusManager"); + private static final Logger log = Logger.getLogger("java.awt.KeyboardFocusManager"); /** * The identifier for the Forward focus traversal keys. @@ -503,8 +504,8 @@ public abstract class KeyboardFocusManager if (this == getCurrentKeyboardFocusManager()) { return focusOwner; } else { - if (focusLog.isLoggable(PlatformLogger.FINER)) { - focusLog.finer("This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); + if (focusLog.isLoggable(Level.FINER)) { + focusLog.log(Level.FINER, "This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); } throw new SecurityException(notPrivileged); } @@ -608,9 +609,9 @@ public abstract class KeyboardFocusManager } void setNativeFocusOwner(Component comp) { - if (focusLog.isLoggable(PlatformLogger.FINEST)) { - focusLog.finest("Calling peer {0} setCurrentFocusOwner for {1}", - peer, comp); + if (focusLog.isLoggable(Level.FINEST)) { + focusLog.log(Level.FINEST, "Calling peer {0} setCurrentFocusOwner for {1}", + new Object[] {String.valueOf(peer), String.valueOf(comp)}); } peer.setCurrentFocusOwner(comp); } @@ -672,8 +673,8 @@ public abstract class KeyboardFocusManager if (this == getCurrentKeyboardFocusManager()) { return permanentFocusOwner; } else { - if (focusLog.isLoggable(PlatformLogger.FINER)) { - focusLog.finer("This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); + if (focusLog.isLoggable(Level.FINER)) { + focusLog.log(Level.FINER, "This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); } throw new SecurityException(notPrivileged); } @@ -780,8 +781,8 @@ public abstract class KeyboardFocusManager if (this == getCurrentKeyboardFocusManager()) { return focusedWindow; } else { - if (focusLog.isLoggable(PlatformLogger.FINER)) { - focusLog.finer("This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); + if (focusLog.isLoggable(Level.FINER)) { + focusLog.log(Level.FINER, "This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); } throw new SecurityException(notPrivileged); } @@ -884,8 +885,8 @@ public abstract class KeyboardFocusManager if (this == getCurrentKeyboardFocusManager()) { return activeWindow; } else { - if (focusLog.isLoggable(PlatformLogger.FINER)) { - focusLog.finer("This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); + if (focusLog.isLoggable(Level.FINER)) { + focusLog.log(Level.FINER, "This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); } throw new SecurityException(notPrivileged); } @@ -918,8 +919,8 @@ public abstract class KeyboardFocusManager Window oldActiveWindow; synchronized (KeyboardFocusManager.class) { oldActiveWindow = getActiveWindow(); - if (focusLog.isLoggable(PlatformLogger.FINER)) { - focusLog.finer("Setting global active window to " + activeWindow + ", old active " + oldActiveWindow); + if (focusLog.isLoggable(Level.FINER)) { + focusLog.log(Level.FINER, "Setting global active window to " + activeWindow + ", old active " + oldActiveWindow); } try { @@ -1214,8 +1215,8 @@ public abstract class KeyboardFocusManager if (this == getCurrentKeyboardFocusManager()) { return currentFocusCycleRoot; } else { - if (focusLog.isLoggable(PlatformLogger.FINER)) { - focusLog.finer("This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); + if (focusLog.isLoggable(Level.FINER)) { + focusLog.log(Level.FINER, "This manager is " + this + ", current is " + getCurrentKeyboardFocusManager()); } throw new SecurityException(notPrivileged); } @@ -2148,9 +2149,9 @@ public abstract class KeyboardFocusManager HeavyweightFocusRequest(Component heavyweight, Component descendant, boolean temporary, CausedFocusEvent.Cause cause) { - if (log.isLoggable(PlatformLogger.FINE)) { + if (log.isLoggable(Level.FINE)) { if (heavyweight == null) { - log.fine("Assertion (heavyweight != null) failed"); + log.log(Level.FINE, "Assertion (heavyweight != null) failed"); } } @@ -2160,12 +2161,12 @@ public abstract class KeyboardFocusManager } boolean addLightweightRequest(Component descendant, boolean temporary, CausedFocusEvent.Cause cause) { - if (log.isLoggable(PlatformLogger.FINE)) { + if (log.isLoggable(Level.FINE)) { if (this == HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER) { - log.fine("Assertion (this != HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER) failed"); + log.log(Level.FINE, "Assertion (this != HeavyweightFocusRequest.CLEAR_GLOBAL_FOCUS_OWNER) failed"); } if (descendant == null) { - log.fine("Assertion (descendant != null) failed"); + log.log(Level.FINE, "Assertion (descendant != null) failed"); } } @@ -2338,12 +2339,12 @@ public abstract class KeyboardFocusManager (Component heavyweight, Component descendant, boolean temporary, boolean focusedWindowChangeAllowed, long time, CausedFocusEvent.Cause cause) { - if (log.isLoggable(PlatformLogger.FINE)) { + if (log.isLoggable(Level.FINE)) { if (heavyweight == null) { - log.fine("Assertion (heavyweight != null) failed"); + log.log(Level.FINE, "Assertion (heavyweight != null) failed"); } if (time == 0) { - log.fine("Assertion (time != 0) failed"); + log.log(Level.FINE, "Assertion (time != 0) failed"); } } @@ -2360,31 +2361,31 @@ public abstract class KeyboardFocusManager Component currentFocusOwner = thisManager.getGlobalFocusOwner(); Component nativeFocusOwner = thisManager.getNativeFocusOwner(); Window nativeFocusedWindow = thisManager.getNativeFocusedWindow(); - if (focusLog.isLoggable(PlatformLogger.FINER)) { - focusLog.finer("SNFH for {0} in {1}", - descendant, heavyweight); + if (focusLog.isLoggable(Level.FINER)) { + focusLog.log(Level.FINER, "SNFH for {0} in {1}", + new Object[] {String.valueOf(descendant), String.valueOf(heavyweight)}); } - if (focusLog.isLoggable(PlatformLogger.FINEST)) { - focusLog.finest("0. Current focus owner {0}", - currentFocusOwner); - focusLog.finest("0. Native focus owner {0}", - nativeFocusOwner); - focusLog.finest("0. Native focused window {0}", - nativeFocusedWindow); + if (focusLog.isLoggable(Level.FINEST)) { + focusLog.log(Level.FINEST, "0. Current focus owner {0}", + String.valueOf(currentFocusOwner)); + focusLog.log(Level.FINEST, "0. Native focus owner {0}", + String.valueOf(nativeFocusOwner)); + focusLog.log(Level.FINEST, "0. Native focused window {0}", + String.valueOf(nativeFocusedWindow)); } synchronized (heavyweightRequests) { HeavyweightFocusRequest hwFocusRequest = getLastHWRequest(); - if (focusLog.isLoggable(PlatformLogger.FINEST)) { - focusLog.finest("Request {0}", hwFocusRequest); + if (focusLog.isLoggable(Level.FINEST)) { + focusLog.log(Level.FINEST, "Request {0}", String.valueOf(hwFocusRequest)); } if (hwFocusRequest == null && heavyweight == nativeFocusOwner) { if (descendant == currentFocusOwner) { // Redundant request. - if (focusLog.isLoggable(PlatformLogger.FINEST)) - focusLog.finest("1. SNFH_FAILURE for {0}", - descendant); + if (focusLog.isLoggable(Level.FINEST)) + focusLog.log(Level.FINEST, "1. SNFH_FAILURE for {0}", + String.valueOf(descendant)); return SNFH_FAILURE; } @@ -2416,8 +2417,8 @@ public abstract class KeyboardFocusManager // SunToolkit.postPriorityEvent(newFocusOwnerEvent); SunToolkit.postEvent(descendant.appContext, newFocusOwnerEvent); - if (focusLog.isLoggable(PlatformLogger.FINEST)) - focusLog.finest("2. SNFH_HANDLED for {0}", descendant); + if (focusLog.isLoggable(Level.FINEST)) + focusLog.log(Level.FINEST, "2. SNFH_HANDLED for {0}", String.valueOf(descendant)); return SNFH_SUCCESS_HANDLED; } else if (hwFocusRequest != null && hwFocusRequest.heavyweight == heavyweight) { @@ -2430,7 +2431,7 @@ public abstract class KeyboardFocusManager manager.enqueueKeyEvents(time, descendant); } - if (focusLog.isLoggable(PlatformLogger.FINEST)) + if (focusLog.isLoggable(Level.FINEST)) focusLog.finest("3. SNFH_HANDLED for lightweight" + descendant + " in " + heavyweight); return SNFH_SUCCESS_HANDLED; @@ -2453,7 +2454,7 @@ public abstract class KeyboardFocusManager (hwFocusRequest != null) ? hwFocusRequest.heavyweight : nativeFocusedWindow)) { - if (focusLog.isLoggable(PlatformLogger.FINEST)) + if (focusLog.isLoggable(Level.FINEST)) focusLog.finest("4. SNFH_FAILURE for " + descendant); return SNFH_FAILURE; } @@ -2463,7 +2464,7 @@ public abstract class KeyboardFocusManager heavyweightRequests.add (new HeavyweightFocusRequest(heavyweight, descendant, temporary, cause)); - if (focusLog.isLoggable(PlatformLogger.FINEST)) + if (focusLog.isLoggable(Level.FINEST)) focusLog.finest("5. SNFH_PROCEED for " + descendant); return SNFH_SUCCESS_PROCEED; } @@ -2854,13 +2855,14 @@ public abstract class KeyboardFocusManager } KeyboardFocusManager manager = getCurrentKeyboardFocusManager(); - if (focusLog.isLoggable(PlatformLogger.FINER)) { + if (focusLog.isLoggable(Level.FINER)) { if (event instanceof FocusEvent || event instanceof WindowEvent) { - focusLog.finer(">>> {0}", event); + focusLog.log(Level.FINER, ">>> {0}", new Object[] {String.valueOf(event)}); } - if (focusLog.isLoggable(PlatformLogger.FINER) && event instanceof KeyEvent) { - focusLog.finer(" focus owner is {0}", manager.getGlobalFocusOwner()); - focusLog.finer(">>> {0}", event); + if (focusLog.isLoggable(Level.FINER) && event instanceof KeyEvent) { + focusLog.log(Level.FINER, " focus owner is {0}", + new Object[] {String.valueOf(manager.getGlobalFocusOwner())}); + focusLog.log(Level.FINER, ">>> {0}", new Object[] {String.valueOf(event)}); } } @@ -2944,9 +2946,9 @@ public abstract class KeyboardFocusManager } } static void removeLastFocusRequest(Component heavyweight) { - if (log.isLoggable(PlatformLogger.FINE)) { + if (log.isLoggable(Level.FINE)) { if (heavyweight == null) { - log.fine("Assertion (heavyweight != null) failed"); + log.log(Level.FINE, "Assertion (heavyweight != null) failed"); } } diff --git a/jdk/src/share/classes/java/awt/Window.java b/jdk/src/share/classes/java/awt/Window.java index 8ea9ec821d8..c039a717984 100644 --- a/jdk/src/share/classes/java/awt/Window.java +++ b/jdk/src/share/classes/java/awt/Window.java @@ -767,7 +767,7 @@ public class Window extends Container implements Accessible { isPacked = true; } - validate(); + validateUnconditionally(); } /** @@ -943,7 +943,7 @@ public class Window extends Container implements Accessible { if (peer == null) { addNotify(); } - validate(); + validateUnconditionally(); isInShow = true; if (visible) { @@ -2599,6 +2599,21 @@ public class Window extends Container implements Accessible { super.addPropertyChangeListener(propertyName, listener); } + /** + * Indicates if this container is a validate root. + *

+ * {@code Window} 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; + } + /** * Dispatches an event to this window or one of its sub components. * @param e the event diff --git a/jdk/src/share/classes/java/awt/color/ICC_Profile.java b/jdk/src/share/classes/java/awt/color/ICC_Profile.java index 78ba43d4bc4..3243dbfc6c3 100644 --- a/jdk/src/share/classes/java/awt/color/ICC_Profile.java +++ b/jdk/src/share/classes/java/awt/color/ICC_Profile.java @@ -865,7 +865,9 @@ public class ICC_Profile implements Serializable { case ColorSpace.CS_PYCC: synchronized(ICC_Profile.class) { if (PYCCprofile == null) { - if (getProfileFile("PYCC.pf") != null) { + if (BootClassLoaderHook.getHook() != null || + standardProfileExists("PYCC.pf")) + { ProfileDeferralInfo pInfo = new ProfileDeferralInfo("PYCC.pf", ColorSpace.TYPE_3CLR, 3, @@ -963,15 +965,15 @@ public class ICC_Profile implements Serializable { * and it does not permit read access to the given file. */ public static ICC_Profile getInstance(String fileName) throws IOException { - ICC_Profile thisProfile; - FileInputStream fis; + ICC_Profile thisProfile; + FileInputStream fis = null; - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkRead(fileName); + + File f = getProfileFile(fileName); + if (f != null) { + fis = new FileInputStream(f); } - - if ((fis = openProfile(fileName)) == null) { + if (fis == null) { throw new IOException("Cannot open file " + fileName); } @@ -1083,11 +1085,22 @@ public class ICC_Profile implements Serializable { void activateDeferredProfile() throws ProfileDataException { byte profileData[]; FileInputStream fis; - String fileName = deferralInfo.filename; + final String fileName = deferralInfo.filename; profileActivator = null; deferralInfo = null; - if ((fis = openProfile(fileName)) == null) { + PrivilegedAction pa = new PrivilegedAction() { + public FileInputStream run() { + File f = getStandardProfileFile(fileName); + if (f != null) { + try { + return new FileInputStream(f); + } catch (FileNotFoundException e) {} + } + return null; + } + }; + if ((fis = AccessController.doPrivileged(pa)) == null) { throw new ProfileDataException("Cannot open file " + fileName); } try { @@ -1786,85 +1799,104 @@ public class ICC_Profile implements Serializable { * available, such as a profile for sRGB. Built-in profiles use .pf as * the file name extension for profiles, e.g. sRGB.pf. */ - private static FileInputStream openProfile(final String fileName) { - return (FileInputStream)java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { - File f = privilegedGetProfileFile(fileName); - if (f != null) { - try { - return new FileInputStream(f); - } catch (FileNotFoundException e) { - } - } - return null; - } - }); - } - - private static File getProfileFile(final String fileName) { - return (File)java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { - return privilegedGetProfileFile(fileName); - } - }); - } - - /* - * this version is called from doPrivileged in openProfile - * or getProfileFile, so the whole method is privileged! - */ - - private static File privilegedGetProfileFile(String fileName) { + private static File getProfileFile(String fileName) { String path, dir, fullPath; File f = new File(fileName); /* try absolute file name */ - + if (f.isAbsolute()) { + /* Rest of code has little sense for an absolute pathname, + so return here. */ + return f.isFile() ? f : null; + } if ((!f.isFile()) && ((path = System.getProperty("java.iccprofile.path")) != null)){ /* try relative to java.iccprofile.path */ StringTokenizer st = new StringTokenizer(path, File.pathSeparator); - while (st.hasMoreTokens() && (!f.isFile())) { + while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) { dir = st.nextToken(); fullPath = dir + File.separatorChar + fileName; f = new File(fullPath); - } - } - - if ((!f.isFile()) && - ((path = System.getProperty("java.class.path")) != null)) { - /* try relative to java.class.path */ - StringTokenizer st = - new StringTokenizer(path, File.pathSeparator); - while (st.hasMoreTokens() && (!f.isFile())) { - dir = st.nextToken(); - fullPath = dir + File.separatorChar + fileName; - f = new File(fullPath); - } - } - - if (!f.isFile()) { /* try the directory of built-in profiles */ - dir = System.getProperty("java.home") + - File.separatorChar + "lib" + File.separatorChar + "cmm"; - fullPath = dir + File.separatorChar + fileName; - f = new File(fullPath); - if (!f.isFile()) { - //make sure file was installed in the kernel mode - BootClassLoaderHook hook = BootClassLoaderHook.getHook(); - if (hook.getHook() != null) { - hook.prefetchFile("lib/cmm/"+fileName); + if (!isChildOf(f, dir)) { + f = null; } } } - if (f.isFile()) { + if (((f == null) || (!f.isFile())) && + ((path = System.getProperty("java.class.path")) != null)) { + /* try relative to java.class.path */ + StringTokenizer st = + new StringTokenizer(path, File.pathSeparator); + while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) { + dir = st.nextToken(); + fullPath = dir + File.separatorChar + fileName; + f = new File(fullPath); + } + } + + if ((f == null) || (!f.isFile())) { + /* try the directory of built-in profiles */ + f = getStandardProfileFile(fileName); + } + if (f != null && f.isFile()) { return f; } return null; } + /** + * Returns a file object corresponding to a built-in profile + * specified by fileName. + * If there is no built-in profile with such name, then the method + * returns null. + */ + private static File getStandardProfileFile(String fileName) { + String dir = System.getProperty("java.home") + + File.separatorChar + "lib" + File.separatorChar + "cmm"; + String fullPath = dir + File.separatorChar + fileName; + File f = new File(fullPath); + if (!f.isFile()) { + //make sure file was installed in the kernel mode + BootClassLoaderHook hook = BootClassLoaderHook.getHook(); + if (hook != null) { + hook.prefetchFile("lib/cmm/"+fileName); + } + } + return (f.isFile() && isChildOf(f, dir)) ? f : null; + } + + /** + * Checks whether given file resides inside give directory. + */ + private static boolean isChildOf(File f, String dirName) { + try { + File dir = new File(dirName); + String canonicalDirName = dir.getCanonicalPath(); + if (!canonicalDirName.endsWith(File.separator)) { + canonicalDirName += File.separator; + } + String canonicalFileName = f.getCanonicalPath(); + return canonicalFileName.startsWith(canonicalDirName); + } catch (IOException e) { + /* we do not expect the IOException here, because invocation + * of this function is always preceeded by isFile() call. + */ + return false; + } + } + + /** + * Checks whether built-in profile specified by fileName exists. + */ + private static boolean standardProfileExists(final String fileName) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Boolean run() { + return getStandardProfileFile(fileName) != null; + } + }); + } + /* * Serialization support. diff --git a/jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java b/jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java index 0e559e5d359..36378882e15 100644 --- a/jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java +++ b/jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java @@ -1184,7 +1184,7 @@ public class DataFlavor implements Externalizable, Cloneable { */ public boolean isRepresentationClassRemote() { - return java.rmi.Remote.class.isAssignableFrom(representationClass); + return DataTransferer.isRemote(representationClass); } /** diff --git a/jdk/src/share/classes/java/awt/event/InvocationEvent.java b/jdk/src/share/classes/java/awt/event/InvocationEvent.java index 0959a86cb35..e21adf352bb 100644 --- a/jdk/src/share/classes/java/awt/event/InvocationEvent.java +++ b/jdk/src/share/classes/java/awt/event/InvocationEvent.java @@ -78,10 +78,21 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { /** * The (potentially null) Object whose notifyAll() method will be called - * immediately after the Runnable.run() method returns. + * immediately after the Runnable.run() method has returned or thrown an exception. + * + * @see #isDispatched */ protected Object notifier; + /** + * Indicates whether the run() method of the runnable + * was executed or not. + * + * @see #isDispatched + * @since 1.7 + */ + private volatile boolean dispatched = false; + /** * Set to true if dispatch() catches Throwable and stores it in the * exception instance variable. If false, Throwables are propagated up @@ -144,7 +155,7 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { * source which will execute the runnable's run * method when dispatched. If notifier is non-null, * notifyAll() will be called on it - * immediately after run returns. + * immediately after run has returned or thrown an exception. *

An invocation of the form InvocationEvent(source, * runnable, notifier, catchThrowables) * behaves in exactly the same way as the invocation of @@ -159,7 +170,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { * executed * @param notifier The {@code Object} whose notifyAll * method will be called after - * Runnable.run has returned + * Runnable.run has returned or + * thrown an exception * @param catchThrowables Specifies whether dispatch * should catch Throwable when executing * the Runnable's run @@ -180,8 +192,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { * Constructs an InvocationEvent with the specified * source and ID which will execute the runnable's run * method when dispatched. If notifier is non-null, - * notifyAll will be called on it - * immediately after run returns. + * notifyAll will be called on it immediately after + * run has returned or thrown an exception. *

This method throws an * IllegalArgumentException if source * is null. @@ -195,7 +207,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { * run method will be executed * @param notifier The Object whose notifyAll * method will be called after - * Runnable.run has returned + * Runnable.run has returned or + * thrown an exception * @param catchThrowables Specifies whether dispatch * should catch Throwable when executing the * Runnable's run @@ -217,27 +230,33 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { /** * Executes the Runnable's run() method and notifies the - * notifier (if any) when run() returns. + * notifier (if any) when run() has returned or thrown an exception. + * + * @see #isDispatched */ public void dispatch() { - if (catchExceptions) { - try { + try { + if (catchExceptions) { + try { + runnable.run(); + } + catch (Throwable t) { + if (t instanceof Exception) { + exception = (Exception) t; + } + throwable = t; + } + } + else { runnable.run(); } - catch (Throwable t) { - if (t instanceof Exception) { - exception = (Exception) t; - } - throwable = t; - } - } - else { - runnable.run(); - } + } finally { + dispatched = true; - if (notifier != null) { - synchronized (notifier) { - notifier.notifyAll(); + if (notifier != null) { + synchronized (notifier) { + notifier.notifyAll(); + } } } } @@ -277,6 +296,40 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { return when; } + /** + * Returns {@code true} if the event is dispatched or any exception is + * thrown while dispatching, {@code false} otherwise. The method should + * be called by a waiting thread that calls the {@code notifier.wait()} method. + * Since spurious wakeups are possible (as explained in {@link Object#wait()}), + * this method should be used in a waiting loop to ensure that the event + * got dispatched: + *

+     *     while (!event.isDispatched()) {
+     *         notifier.wait();
+     *     }
+     * 
+ * If the waiting thread wakes up without dispatching the event, + * the {@code isDispatched()} method returns {@code false}, and + * the {@code while} loop executes once more, thus, causing + * the awakened thread to revert to the waiting mode. + *

+ * If the {@code notifier.notifyAll()} happens before the waiting thread + * enters the {@code notifier.wait()} method, the {@code while} loop ensures + * that the waiting thread will not enter the {@code notifier.wait()} method. + * Otherwise, there is no guarantee that the waiting thread will ever be woken + * from the wait. + * + * @return {@code true} if the event has been dispatched, or any exception + * has been thrown while dispatching, {@code false} otherwise + * @see #dispatch + * @see #notifier + * @see #catchExceptions + * @since 1.7 + */ + public boolean isDispatched() { + return dispatched; + } + /** * Returns a parameter string identifying this event. * This method is useful for event-logging and for debugging. diff --git a/jdk/src/share/classes/java/awt/font/NumericShaper.java b/jdk/src/share/classes/java/awt/font/NumericShaper.java index a1ffbf0b7c3..435b60213f0 100644 --- a/jdk/src/share/classes/java/awt/font/NumericShaper.java +++ b/jdk/src/share/classes/java/awt/font/NumericShaper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-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 @@ -25,6 +25,13 @@ package java.awt.font; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.util.Arrays; +import java.util.Comparator; +import java.util.EnumSet; +import java.util.Set; + /** * The NumericShaper class is used to convert Latin-1 (European) * digits to other Unicode decimal digits. Users of this class will @@ -64,13 +71,261 @@ package java.awt.font; * NumericShaper.getContextualShaper(NumericShaper.ARABIC | * NumericShaper.TAMIL, * NumericShaper.EUROPEAN); - * shaper.shape(text. start, count); + * shaper.shape(text, start, count); * * + *

Bit mask- and enum-based Unicode ranges

+ * + *

This class supports two different programming interfaces to + * represent Unicode ranges for script-specific digits: bit + * mask-based ones, such as {@link #ARABIC NumericShaper.ARABIC}, and + * enum-based ones, such as {@link NumericShaper.Range#ARABIC}. + * Multiple ranges can be specified by ORing bit mask-based constants, + * such as: + *

+ * NumericShaper.ARABIC | NumericShaper.TAMIL
+ * 
+ * or creating a {@code Set} with the {@link NumericShaper.Range} + * constants, such as: + *
+ * EnumSet.of(NumericShaper.Scirpt.ARABIC, NumericShaper.Range.TAMIL)
+ * 
+ * The enum-based ranges are a super set of the bit mask-based ones. + * + *

If the two interfaces are mixed (including serialization), + * Unicode range values are mapped to their counterparts where such + * mapping is possible, such as {@code NumericShaper.Range.ARABIC} + * from/to {@code NumericShaper.ARABIC}. If any unmappable range + * values are specified, such as {@code NumericShaper.Range.BALINESE}, + * those ranges are ignored. + * * @since 1.4 */ public final class NumericShaper implements java.io.Serializable { + /** + * A {@code NumericShaper.Range} represents a Unicode range of a + * script having its own decimal digits. For example, the {@link + * NumericShaper.Range#THAI} range has the Thai digits, THAI DIGIT + * ZERO (U+0E50) to THAI DIGIT NINE (U+0E59). + * + *

The Range enum replaces the traditional bit + * mask-based values (e.g., {@link NumericShaper#ARABIC}), and + * supports more Unicode ranges than the bit mask-based ones. For + * example, the following code using the bit mask: + *

+     * NumericShaper.getContextualShaper(NumericShaper.ARABIC |
+     *                                     NumericShaper.TAMIL,
+     *                                   NumericShaper.EUROPEAN);
+     * 
+ * can be written using this enum as: + *
+     * NumericShaper.getContextualShaper(EnumSet.of(
+     *                                     NumericShaper.Range.ARABIC,
+     *                                     NumericShaper.Range.TAMIL),
+     *                                   NumericShaper.Range.EUROPEAN);
+     * 
+ * + * @since 1.7 + */ + public static enum Range { + /** + * The Latin (European) range with the Latin (ASCII) digits. + */ + EUROPEAN ('\u0030', '\u0000', '\u0300'), + /** + * The Arabic range with the Arabic-Indic digits. + */ + ARABIC ('\u0660', '\u0600', '\u0780'), + /** + * The Arabic range with the Eastern Arabic-Indic digits. + */ + EASTERN_ARABIC ('\u06f0', '\u0600', '\u0780'), + /** + * The Devanagari range with the Devanagari digits. + */ + DEVANAGARI ('\u0966', '\u0900', '\u0980'), + /** + * The Bengali range with the Bengali digits. + */ + BENGALI ('\u09e6', '\u0980', '\u0a00'), + /** + * The Gurmukhi range with the Gurmukhi digits. + */ + GURMUKHI ('\u0a66', '\u0a00', '\u0a80'), + /** + * The Gujarati range with the Gujarati digits. + */ + GUJARATI ('\u0ae6', '\u0b00', '\u0b80'), + /** + * The Oriya range with the Oriya digits. + */ + ORIYA ('\u0b66', '\u0b00', '\u0b80'), + /** + * The Tamil range with the Tamil digits. + */ + TAMIL ('\u0be6', '\u0b80', '\u0c00'), + /** + * The Telugu range with the Telugu digits. + */ + TELUGU ('\u0c66', '\u0c00', '\u0c80'), + /** + * The Kannada range with the Kannada digits. + */ + KANNADA ('\u0ce6', '\u0c80', '\u0d00'), + /** + * The Malayalam range with the Malayalam digits. + */ + MALAYALAM ('\u0d66', '\u0d00', '\u0d80'), + /** + * The Thai range with the Thai digits. + */ + THAI ('\u0e50', '\u0e00', '\u0e80'), + /** + * The Lao range with the Lao digits. + */ + LAO ('\u0ed0', '\u0e80', '\u0f00'), + /** + * The Tibetan range with the Tibetan digits. + */ + TIBETAN ('\u0f20', '\u0f00', '\u1000'), + /** + * The Myanmar range with the Myanmar digits. + */ + MYANMAR ('\u1040', '\u1000', '\u1080'), + /** + * The Ethiopic range with the Ethiopic digits. Ethiopic + * does not have a decimal digit 0 so Latin (European) 0 is + * used. + */ + ETHIOPIC ('\u1369', '\u1200', '\u1380') { + @Override + char getNumericBase() { return 1; } + }, + /** + * The Khmer range with the Khmer digits. + */ + KHMER ('\u17e0', '\u1780', '\u1800'), + /** + * The Mongolian range with the Mongolian digits. + */ + MONGOLIAN ('\u1810', '\u1800', '\u1900'), + /** + * The N'Ko range with the N'Ko digits. + */ + NKO ('\u07c0', '\u07c0', '\u0800'), + /** + * The Myanmar range with the Myanmar Shan digits. + */ + MYANMAR_SHAN ('\u1090', '\u1000', '\u10a0'), + /** + * The Limbu range with the Limbu digits. + */ + LIMBU ('\u1946', '\u1900', '\u1950'), + /** + * The New Tai Lue range with the New Tai Lue digits. + */ + NEW_TAI_LUE ('\u19d0', '\u1980', '\u19e0'), + /** + * The Balinese range with the Balinese digits. + */ + BALINESE ('\u1b50', '\u1b00', '\u1b80'), + /** + * The Sundanese range with the Sundanese digits. + */ + SUNDANESE ('\u1bb0', '\u1b80', '\u1bc0'), + /** + * The Lepcha range with the Lepcha digits. + */ + LEPCHA ('\u1c40', '\u1c00', '\u1c50'), + /** + * The Ol Chiki range with the Ol Chiki digits. + */ + OL_CHIKI ('\u1c50', '\u1c50', '\u1c80'), + /** + * The Vai range with the Vai digits. + */ + VAI ('\ua620', '\ua500', '\ua640'), + /** + * The Saurashtra range with the Saurashtra digits. + */ + SAURASHTRA ('\ua8d0', '\ua880', '\ua8e0'), + /** + * The Kayah Li range with the Kayah Li digits. + */ + KAYAH_LI ('\ua900', '\ua900', '\ua930'), + /** + * The Cham range with the Cham digits. + */ + CHAM ('\uaa50', '\uaa00', '\uaa60'); + + private static final Range[] ranges = Range.class.getEnumConstants(); + static { + // sort ranges[] by base for binary search + Arrays.sort(ranges, + new Comparator() { + public int compare(Range s1, Range s2) { + return s1.base > s2.base ? 1 : s1.base == s2.base ? 0 : -1; + } + }); + } + + private static int toRangeIndex(Range script) { + int index = script.ordinal(); + return index < NUM_KEYS ? index : -1; + } + + private static Range indexToRange(int index) { + return index < NUM_KEYS ? Range.values()[index] : null; + } + + private static int toRangeMask(Set ranges) { + int m = 0; + for (Range range : ranges) { + int index = range.ordinal(); + if (index < NUM_KEYS) { + m |= 1 << index; + } + } + return m; + } + + private static Set maskToRangeSet(int mask) { + Set set = EnumSet.noneOf(Range.class); + Range[] a = Range.values(); + for (int i = 0; i < NUM_KEYS; i++) { + if ((mask & (1 << i)) != 0) { + set.add(a[i]); + } + } + return set; + } + + // base character of range digits + private final int base; + // Unicode range + private final int start, // inclusive + end; // exclusive + + private Range(int base, int start, int end) { + this.base = base - ('0' + getNumericBase()); + this.start = start; + this.end = end; + } + + private int getDigitBase() { + return base; + } + + char getNumericBase() { + return 0; + } + + private boolean inRange(int c) { + return start <= c && c < end; + } + } + /** index of context for contextual shaping - values range from 0 to 18 */ private int key; @@ -79,6 +334,25 @@ public final class NumericShaper implements java.io.Serializable { */ private int mask; + /** + * The context {@code Range} for contextual shaping or the {@code + * Range} for non-contextual shaping. {@code null} for the bit + * mask-based API. + * + * @since 1.7 + */ + private Range shapingRange; + + /** + * {@code Set} indicating which Unicode ranges to + * shape. {@code null} for the bit mask-based API. + * + * @since 1.7 + */ + private transient Set rangeSet; + + private static final long serialVersionUID = -8022764705923730308L; + /** Identifies the Latin-1 (European) and extended range, and * Latin-1 (European) decimal base. */ @@ -105,9 +379,8 @@ public final class NumericShaper implements java.io.Serializable { /** Identifies the ORIYA range and decimal base. */ public static final int ORIYA = 1<<7; - /** Identifies the TAMIL range and decimal base. Tamil does not have a - * decimal digit 0 so Latin-1 (European) 0 is used. - */ + /** Identifies the TAMIL range and decimal base. */ + // TAMIL DIGIT ZERO was added in Unicode 4.1 public static final int TAMIL = 1<<8; /** Identifies the TELUGU range and decimal base. */ @@ -140,7 +413,12 @@ public final class NumericShaper implements java.io.Serializable { /** Identifies the MONGOLIAN range and decimal base. */ public static final int MONGOLIAN = 1<<18; - /** Identifies all ranges, for full contextual shaping. */ + /** Identifies all ranges, for full contextual shaping. + * + *

This constant specifies all of the bit mask-based + * ranges. Use {@code EmunSet.allOf(NumericShaper.Range.class)} to + * specify all of the enum-based ranges. + */ public static final int ALL_RANGES = 0x0007ffff; private static final int EUROPEAN_KEY = 0; @@ -163,42 +441,20 @@ public final class NumericShaper implements java.io.Serializable { private static final int KHMER_KEY = 17; private static final int MONGOLIAN_KEY = 18; - private static final int NUM_KEYS = 19; - - private static final String[] keyNames = { - "EUROPEAN", - "ARABIC", - "EASTERN_ARABIC", - "DEVANAGARI", - "BENGALI", - "GURMUKHI", - "GUJARATI", - "ORIYA", - "TAMIL", - "TELUGU", - "KANNADA", - "MALAYALAM", - "THAI", - "LAO", - "TIBETAN", - "MYANMAR", - "ETHIOPIC", - "KHMER", - "MONGOLIAN" - }; + private static final int NUM_KEYS = MONGOLIAN_KEY + 1; // fixed private static final int CONTEXTUAL_MASK = 1<<31; private static final char[] bases = { '\u0030' - '\u0030', // EUROPEAN - '\u0660' - '\u0030', // ARABIC - '\u06f0' - '\u0030', // EASTERN_ARABIC + '\u0660' - '\u0030', // ARABIC-INDIC + '\u06f0' - '\u0030', // EXTENDED ARABIC-INDIC (EASTERN_ARABIC) '\u0966' - '\u0030', // DEVANAGARI '\u09e6' - '\u0030', // BENGALI '\u0a66' - '\u0030', // GURMUKHI '\u0ae6' - '\u0030', // GUJARATI '\u0b66' - '\u0030', // ORIYA - '\u0be7' - '\u0030', // TAMIL - note missing zero + '\u0be6' - '\u0030', // TAMIL - zero was added in Unicode 4.1 '\u0c66' - '\u0030', // TELUGU '\u0ce6' - '\u0030', // KANNADA '\u0d66' - '\u0030', // MALAYALAM @@ -206,7 +462,7 @@ public final class NumericShaper implements java.io.Serializable { '\u0ed0' - '\u0030', // LAO '\u0f20' - '\u0030', // TIBETAN '\u1040' - '\u0030', // MYANMAR - '\u1369' - '\u0030', // ETHIOPIC + '\u1369' - '\u0031', // ETHIOPIC - no zero '\u17e0' - '\u0030', // KHMER '\u1810' - '\u0030', // MONGOLIAN }; @@ -215,14 +471,14 @@ public final class NumericShaper implements java.io.Serializable { private static final char[] contexts = { '\u0000', '\u0300', // 'EUROPEAN' (really latin-1 and extended) - '\u0600', '\u0700', // ARABIC - '\u0600', '\u0700', // EASTERN_ARABIC -- note overlap with arabic + '\u0600', '\u0780', // ARABIC + '\u0600', '\u0780', // EASTERN_ARABIC -- note overlap with arabic '\u0900', '\u0980', // DEVANAGARI '\u0980', '\u0a00', // BENGALI '\u0a00', '\u0a80', // GURMUKHI '\u0a80', '\u0b00', // GUJARATI '\u0b00', '\u0b80', // ORIYA - '\u0b80', '\u0c00', // TAMIL - note missing zero + '\u0b80', '\u0c00', // TAMIL '\u0c00', '\u0c80', // TELUGU '\u0c80', '\u0d00', // KANNADA '\u0d00', '\u0d80', // MALAYALAM @@ -230,7 +486,7 @@ public final class NumericShaper implements java.io.Serializable { '\u0e80', '\u0f00', // LAO '\u0f00', '\u1000', // TIBETAN '\u1000', '\u1080', // MYANMAR - '\u1200', '\u1380', // ETHIOPIC + '\u1200', '\u1380', // ETHIOPIC - note missing zero '\u1780', '\u1800', // KHMER '\u1800', '\u1900', // MONGOLIAN '\uffff', @@ -254,378 +510,290 @@ public final class NumericShaper implements java.io.Serializable { return (ctCache & 0x1) == 0 ? (ctCache / 2) : EUROPEAN_KEY; } + // cache for the NumericShaper.Range version + private transient volatile Range currentRange = Range.EUROPEAN; + + private Range rangeForCodePoint(int codepoint) { + Range range = currentRange; + if (range.inRange(codepoint)) { + return range; + } + + final Range[] ranges = Range.ranges; + int lo = 0; + int hi = ranges.length - 1; + while (lo <= hi) { + int mid = (lo + hi) / 2; + range = ranges[mid]; + if (codepoint < range.start) { + hi = mid - 1; + } else if (codepoint >= range.end) { + lo = mid + 1; + } else { + currentRange = range; + return range; + } + } + return Range.EUROPEAN; + } + /* * A range table of strong directional characters (types L, R, AL). * Even (left) indexes are starts of ranges of non-strong-directional (or undefined) * characters, odd (right) indexes are starts of ranges of strong directional * characters. */ - private static char[] strongTable = { - '\u0000', '\u0041', - '\u005b', '\u0061', - '\u007b', '\u00aa', - '\u00ab', '\u00b5', - '\u00b6', '\u00ba', - '\u00bb', '\u00c0', - '\u00d7', '\u00d8', - '\u00f7', '\u00f8', - '\u0220', '\u0222', - '\u0234', '\u0250', - '\u02ae', '\u02b0', - '\u02b9', '\u02bb', - '\u02c2', '\u02d0', - '\u02d2', '\u02e0', - '\u02e5', '\u02ee', - '\u02ef', '\u037a', - '\u037b', '\u0386', - '\u0387', '\u0388', - '\u038b', '\u038c', - '\u038d', '\u038e', - '\u03a2', '\u03a3', - '\u03cf', '\u03d0', - '\u03d8', '\u03da', - '\u03f4', '\u0400', - '\u0483', '\u048c', - '\u04c5', '\u04c7', - '\u04c9', '\u04cb', - '\u04cd', '\u04d0', - '\u04f6', '\u04f8', - '\u04fa', '\u0531', - '\u0557', '\u0559', - '\u0560', '\u0561', - '\u0588', '\u0589', - '\u058a', '\u05be', - '\u05bf', '\u05c0', - '\u05c1', '\u05c3', - '\u05c4', '\u05d0', - '\u05eb', '\u05f0', - '\u05f5', '\u061b', - '\u061c', '\u061f', - '\u0620', '\u0621', - '\u063b', '\u0640', - '\u064b', '\u066d', - '\u066e', '\u0671', - '\u06d6', '\u06e5', - '\u06e7', '\u06fa', - '\u06ff', '\u0700', - '\u070e', '\u0710', - '\u0711', '\u0712', - '\u072d', '\u0780', - '\u07a6', '\u0903', - '\u0904', '\u0905', - '\u093a', '\u093d', - '\u0941', '\u0949', - '\u094d', '\u0950', - '\u0951', '\u0958', - '\u0962', '\u0964', - '\u0971', '\u0982', - '\u0984', '\u0985', - '\u098d', '\u098f', - '\u0991', '\u0993', - '\u09a9', '\u09aa', - '\u09b1', '\u09b2', - '\u09b3', '\u09b6', - '\u09ba', '\u09be', - '\u09c1', '\u09c7', - '\u09c9', '\u09cb', - '\u09cd', '\u09d7', - '\u09d8', '\u09dc', - '\u09de', '\u09df', - '\u09e2', '\u09e6', - '\u09f2', '\u09f4', - '\u09fb', '\u0a05', - '\u0a0b', '\u0a0f', - '\u0a11', '\u0a13', - '\u0a29', '\u0a2a', - '\u0a31', '\u0a32', - '\u0a34', '\u0a35', - '\u0a37', '\u0a38', - '\u0a3a', '\u0a3e', - '\u0a41', '\u0a59', - '\u0a5d', '\u0a5e', - '\u0a5f', '\u0a66', - '\u0a70', '\u0a72', - '\u0a75', '\u0a83', - '\u0a84', '\u0a85', - '\u0a8c', '\u0a8d', - '\u0a8e', '\u0a8f', - '\u0a92', '\u0a93', - '\u0aa9', '\u0aaa', - '\u0ab1', '\u0ab2', - '\u0ab4', '\u0ab5', - '\u0aba', '\u0abd', - '\u0ac1', '\u0ac9', - '\u0aca', '\u0acb', - '\u0acd', '\u0ad0', - '\u0ad1', '\u0ae0', - '\u0ae1', '\u0ae6', - '\u0af0', '\u0b02', - '\u0b04', '\u0b05', - '\u0b0d', '\u0b0f', - '\u0b11', '\u0b13', - '\u0b29', '\u0b2a', - '\u0b31', '\u0b32', - '\u0b34', '\u0b36', - '\u0b3a', '\u0b3d', - '\u0b3f', '\u0b40', - '\u0b41', '\u0b47', - '\u0b49', '\u0b4b', - '\u0b4d', '\u0b57', - '\u0b58', '\u0b5c', - '\u0b5e', '\u0b5f', - '\u0b62', '\u0b66', - '\u0b71', '\u0b83', - '\u0b84', '\u0b85', - '\u0b8b', '\u0b8e', - '\u0b91', '\u0b92', - '\u0b96', '\u0b99', - '\u0b9b', '\u0b9c', - '\u0b9d', '\u0b9e', - '\u0ba0', '\u0ba3', - '\u0ba5', '\u0ba8', - '\u0bab', '\u0bae', - '\u0bb6', '\u0bb7', - '\u0bba', '\u0bbe', - '\u0bc0', '\u0bc1', - '\u0bc3', '\u0bc6', - '\u0bc9', '\u0bca', - '\u0bcd', '\u0bd7', - '\u0bd8', '\u0be7', - '\u0bf3', '\u0c01', - '\u0c04', '\u0c05', - '\u0c0d', '\u0c0e', - '\u0c11', '\u0c12', - '\u0c29', '\u0c2a', - '\u0c34', '\u0c35', - '\u0c3a', '\u0c41', - '\u0c45', '\u0c60', - '\u0c62', '\u0c66', - '\u0c70', '\u0c82', - '\u0c84', '\u0c85', - '\u0c8d', '\u0c8e', - '\u0c91', '\u0c92', - '\u0ca9', '\u0caa', - '\u0cb4', '\u0cb5', - '\u0cba', '\u0cbe', - '\u0cbf', '\u0cc0', - '\u0cc5', '\u0cc7', - '\u0cc9', '\u0cca', - '\u0ccc', '\u0cd5', - '\u0cd7', '\u0cde', - '\u0cdf', '\u0ce0', - '\u0ce2', '\u0ce6', - '\u0cf0', '\u0d02', - '\u0d04', '\u0d05', - '\u0d0d', '\u0d0e', - '\u0d11', '\u0d12', - '\u0d29', '\u0d2a', - '\u0d3a', '\u0d3e', - '\u0d41', '\u0d46', - '\u0d49', '\u0d4a', - '\u0d4d', '\u0d57', - '\u0d58', '\u0d60', - '\u0d62', '\u0d66', - '\u0d70', '\u0d82', - '\u0d84', '\u0d85', - '\u0d97', '\u0d9a', - '\u0db2', '\u0db3', - '\u0dbc', '\u0dbd', - '\u0dbe', '\u0dc0', - '\u0dc7', '\u0dcf', - '\u0dd2', '\u0dd8', - '\u0de0', '\u0df2', - '\u0df5', '\u0e01', - '\u0e31', '\u0e32', - '\u0e34', '\u0e40', - '\u0e47', '\u0e4f', - '\u0e5c', '\u0e81', - '\u0e83', '\u0e84', - '\u0e85', '\u0e87', - '\u0e89', '\u0e8a', - '\u0e8b', '\u0e8d', - '\u0e8e', '\u0e94', - '\u0e98', '\u0e99', - '\u0ea0', '\u0ea1', - '\u0ea4', '\u0ea5', - '\u0ea6', '\u0ea7', - '\u0ea8', '\u0eaa', - '\u0eac', '\u0ead', - '\u0eb1', '\u0eb2', - '\u0eb4', '\u0ebd', - '\u0ebe', '\u0ec0', - '\u0ec5', '\u0ec6', - '\u0ec7', '\u0ed0', - '\u0eda', '\u0edc', - '\u0ede', '\u0f00', - '\u0f18', '\u0f1a', - '\u0f35', '\u0f36', - '\u0f37', '\u0f38', - '\u0f39', '\u0f3e', - '\u0f48', '\u0f49', - '\u0f6b', '\u0f7f', - '\u0f80', '\u0f85', - '\u0f86', '\u0f88', - '\u0f8c', '\u0fbe', - '\u0fc6', '\u0fc7', - '\u0fcd', '\u0fcf', - '\u0fd0', '\u1000', - '\u1022', '\u1023', - '\u1028', '\u1029', - '\u102b', '\u102c', - '\u102d', '\u1031', - '\u1032', '\u1038', - '\u1039', '\u1040', - '\u1058', '\u10a0', - '\u10c6', '\u10d0', - '\u10f7', '\u10fb', - '\u10fc', '\u1100', - '\u115a', '\u115f', - '\u11a3', '\u11a8', - '\u11fa', '\u1200', - '\u1207', '\u1208', - '\u1247', '\u1248', - '\u1249', '\u124a', - '\u124e', '\u1250', - '\u1257', '\u1258', - '\u1259', '\u125a', - '\u125e', '\u1260', - '\u1287', '\u1288', - '\u1289', '\u128a', - '\u128e', '\u1290', - '\u12af', '\u12b0', - '\u12b1', '\u12b2', - '\u12b6', '\u12b8', - '\u12bf', '\u12c0', - '\u12c1', '\u12c2', - '\u12c6', '\u12c8', - '\u12cf', '\u12d0', - '\u12d7', '\u12d8', - '\u12ef', '\u12f0', - '\u130f', '\u1310', - '\u1311', '\u1312', - '\u1316', '\u1318', - '\u131f', '\u1320', - '\u1347', '\u1348', - '\u135b', '\u1361', - '\u137d', '\u13a0', - '\u13f5', '\u1401', - '\u1677', '\u1681', - '\u169b', '\u16a0', - '\u16f1', '\u1780', - '\u17b7', '\u17be', - '\u17c6', '\u17c7', - '\u17c9', '\u17d4', - '\u17db', '\u17dc', - '\u17dd', '\u17e0', - '\u17ea', '\u1810', - '\u181a', '\u1820', - '\u1878', '\u1880', - '\u18a9', '\u1e00', - '\u1e9c', '\u1ea0', - '\u1efa', '\u1f00', - '\u1f16', '\u1f18', - '\u1f1e', '\u1f20', - '\u1f46', '\u1f48', - '\u1f4e', '\u1f50', - '\u1f58', '\u1f59', - '\u1f5a', '\u1f5b', - '\u1f5c', '\u1f5d', - '\u1f5e', '\u1f5f', - '\u1f7e', '\u1f80', - '\u1fb5', '\u1fb6', - '\u1fbd', '\u1fbe', - '\u1fbf', '\u1fc2', - '\u1fc5', '\u1fc6', - '\u1fcd', '\u1fd0', - '\u1fd4', '\u1fd6', - '\u1fdc', '\u1fe0', - '\u1fed', '\u1ff2', - '\u1ff5', '\u1ff6', - '\u1ffd', '\u200e', - '\u2010', '\u207f', - '\u2080', '\u2102', - '\u2103', '\u2107', - '\u2108', '\u210a', - '\u2114', '\u2115', - '\u2116', '\u2119', - '\u211e', '\u2124', - '\u2125', '\u2126', - '\u2127', '\u2128', - '\u2129', '\u212a', - '\u212e', '\u212f', - '\u2132', '\u2133', - '\u213a', '\u2160', - '\u2184', '\u2336', - '\u237b', '\u2395', - '\u2396', '\u249c', - '\u24ea', '\u3005', - '\u3008', '\u3021', - '\u302a', '\u3031', - '\u3036', '\u3038', - '\u303b', '\u3041', - '\u3095', '\u309d', - '\u309f', '\u30a1', - '\u30fb', '\u30fc', - '\u30ff', '\u3105', - '\u312d', '\u3131', - '\u318f', '\u3190', - '\u31b8', '\u3200', - '\u321d', '\u3220', - '\u3244', '\u3260', - '\u327c', '\u327f', - '\u32b1', '\u32c0', - '\u32cc', '\u32d0', - '\u32ff', '\u3300', - '\u3377', '\u337b', - '\u33de', '\u33e0', - '\u33ff', '\u3400', - '\u4db6', '\u4e00', - '\u9fa6', '\ua000', - '\ua48d', '\uac00', - '\ud7a4', '\uf900', - '\ufa2e', '\ufb00', - '\ufb07', '\ufb13', - '\ufb18', '\ufb1d', - '\ufb1e', '\ufb1f', - '\ufb29', '\ufb2a', - '\ufb37', '\ufb38', - '\ufb3d', '\ufb3e', - '\ufb3f', '\ufb40', - '\ufb42', '\ufb43', - '\ufb45', '\ufb46', - '\ufbb2', '\ufbd3', - '\ufd3e', '\ufd50', - '\ufd90', '\ufd92', - '\ufdc8', '\ufdf0', - '\ufdfc', '\ufe70', - '\ufe73', '\ufe74', - '\ufe75', '\ufe76', - '\ufefd', '\uff21', - '\uff3b', '\uff41', - '\uff5b', '\uff66', - '\uffbf', '\uffc2', - '\uffc8', '\uffca', - '\uffd0', '\uffd2', - '\uffd8', '\uffda', - '\uffdd', '\uffff' // last entry is sentinel, actually never checked + private static int[] strongTable = { + 0x0000, 0x0041, + 0x005b, 0x0061, + 0x007b, 0x00aa, + 0x00ab, 0x00b5, + 0x00b6, 0x00ba, + 0x00bb, 0x00c0, + 0x00d7, 0x00d8, + 0x00f7, 0x00f8, + 0x02b9, 0x02bb, + 0x02c2, 0x02d0, + 0x02d2, 0x02e0, + 0x02e5, 0x02ee, + 0x02ef, 0x0370, + 0x0374, 0x0376, + 0x037e, 0x0386, + 0x0387, 0x0388, + 0x03f6, 0x03f7, + 0x0483, 0x048a, + 0x058a, 0x05be, + 0x05bf, 0x05c0, + 0x05c1, 0x05c3, + 0x05c4, 0x05c6, + 0x05c7, 0x05d0, + 0x0600, 0x0608, + 0x0609, 0x060b, + 0x060c, 0x060d, + 0x060e, 0x061b, + 0x064b, 0x066d, + 0x0670, 0x0671, + 0x06d6, 0x06e5, + 0x06e7, 0x06ee, + 0x06f0, 0x06fa, + 0x070f, 0x0710, + 0x0711, 0x0712, + 0x0730, 0x074d, + 0x07a6, 0x07b1, + 0x07eb, 0x07f4, + 0x07f6, 0x07fa, + 0x0901, 0x0903, + 0x093c, 0x093d, + 0x0941, 0x0949, + 0x094d, 0x0950, + 0x0951, 0x0958, + 0x0962, 0x0964, + 0x0981, 0x0982, + 0x09bc, 0x09bd, + 0x09c1, 0x09c7, + 0x09cd, 0x09ce, + 0x09e2, 0x09e6, + 0x09f2, 0x09f4, + 0x0a01, 0x0a03, + 0x0a3c, 0x0a3e, + 0x0a41, 0x0a59, + 0x0a70, 0x0a72, + 0x0a75, 0x0a83, + 0x0abc, 0x0abd, + 0x0ac1, 0x0ac9, + 0x0acd, 0x0ad0, + 0x0ae2, 0x0ae6, + 0x0af1, 0x0b02, + 0x0b3c, 0x0b3d, + 0x0b3f, 0x0b40, + 0x0b41, 0x0b47, + 0x0b4d, 0x0b57, + 0x0b62, 0x0b66, + 0x0b82, 0x0b83, + 0x0bc0, 0x0bc1, + 0x0bcd, 0x0bd0, + 0x0bf3, 0x0c01, + 0x0c3e, 0x0c41, + 0x0c46, 0x0c58, + 0x0c62, 0x0c66, + 0x0c78, 0x0c7f, + 0x0cbc, 0x0cbd, + 0x0ccc, 0x0cd5, + 0x0ce2, 0x0ce6, + 0x0cf1, 0x0d02, + 0x0d41, 0x0d46, + 0x0d4d, 0x0d57, + 0x0d62, 0x0d66, + 0x0dca, 0x0dcf, + 0x0dd2, 0x0dd8, + 0x0e31, 0x0e32, + 0x0e34, 0x0e40, + 0x0e47, 0x0e4f, + 0x0eb1, 0x0eb2, + 0x0eb4, 0x0ebd, + 0x0ec8, 0x0ed0, + 0x0f18, 0x0f1a, + 0x0f35, 0x0f36, + 0x0f37, 0x0f38, + 0x0f39, 0x0f3e, + 0x0f71, 0x0f7f, + 0x0f80, 0x0f85, + 0x0f86, 0x0f88, + 0x0f90, 0x0fbe, + 0x0fc6, 0x0fc7, + 0x102d, 0x1031, + 0x1032, 0x1038, + 0x1039, 0x103b, + 0x103d, 0x103f, + 0x1058, 0x105a, + 0x105e, 0x1061, + 0x1071, 0x1075, + 0x1082, 0x1083, + 0x1085, 0x1087, + 0x108d, 0x108e, + 0x135f, 0x1360, + 0x1390, 0x13a0, + 0x1680, 0x1681, + 0x169b, 0x16a0, + 0x1712, 0x1720, + 0x1732, 0x1735, + 0x1752, 0x1760, + 0x1772, 0x1780, + 0x17b7, 0x17be, + 0x17c6, 0x17c7, + 0x17c9, 0x17d4, + 0x17db, 0x17dc, + 0x17dd, 0x17e0, + 0x17f0, 0x1810, + 0x18a9, 0x18aa, + 0x1920, 0x1923, + 0x1927, 0x1929, + 0x1932, 0x1933, + 0x1939, 0x1946, + 0x19de, 0x1a00, + 0x1a17, 0x1a19, + 0x1b00, 0x1b04, + 0x1b34, 0x1b35, + 0x1b36, 0x1b3b, + 0x1b3c, 0x1b3d, + 0x1b42, 0x1b43, + 0x1b6b, 0x1b74, + 0x1b80, 0x1b82, + 0x1ba2, 0x1ba6, + 0x1ba8, 0x1baa, + 0x1c2c, 0x1c34, + 0x1c36, 0x1c3b, + 0x1dc0, 0x1e00, + 0x1fbd, 0x1fbe, + 0x1fbf, 0x1fc2, + 0x1fcd, 0x1fd0, + 0x1fdd, 0x1fe0, + 0x1fed, 0x1ff2, + 0x1ffd, 0x200e, + 0x2010, 0x2071, + 0x2074, 0x207f, + 0x2080, 0x2090, + 0x20a0, 0x2102, + 0x2103, 0x2107, + 0x2108, 0x210a, + 0x2114, 0x2115, + 0x2116, 0x2119, + 0x211e, 0x2124, + 0x2125, 0x2126, + 0x2127, 0x2128, + 0x2129, 0x212a, + 0x212e, 0x212f, + 0x213a, 0x213c, + 0x2140, 0x2145, + 0x214a, 0x214e, + 0x2153, 0x2160, + 0x2190, 0x2336, + 0x237b, 0x2395, + 0x2396, 0x249c, + 0x24ea, 0x26ac, + 0x26ad, 0x2800, + 0x2900, 0x2c00, + 0x2ce5, 0x2d00, + 0x2de0, 0x3005, + 0x3008, 0x3021, + 0x302a, 0x3031, + 0x3036, 0x3038, + 0x303d, 0x3041, + 0x3099, 0x309d, + 0x30a0, 0x30a1, + 0x30fb, 0x30fc, + 0x31c0, 0x31f0, + 0x321d, 0x3220, + 0x3250, 0x3260, + 0x327c, 0x327f, + 0x32b1, 0x32c0, + 0x32cc, 0x32d0, + 0x3377, 0x337b, + 0x33de, 0x33e0, + 0x33ff, 0x3400, + 0x4dc0, 0x4e00, + 0xa490, 0xa500, + 0xa60d, 0xa610, + 0xa66f, 0xa680, + 0xa700, 0xa722, + 0xa788, 0xa789, + 0xa802, 0xa803, + 0xa806, 0xa807, + 0xa80b, 0xa80c, + 0xa825, 0xa827, + 0xa828, 0xa840, + 0xa874, 0xa880, + 0xa8c4, 0xa8ce, + 0xa926, 0xa92e, + 0xa947, 0xa952, + 0xaa29, 0xaa2f, + 0xaa31, 0xaa33, + 0xaa35, 0xaa40, + 0xaa43, 0xaa44, + 0xaa4c, 0xaa4d, + 0xfb1e, 0xfb1f, + 0xfb29, 0xfb2a, + 0xfd3e, 0xfd50, + 0xfdfd, 0xfe70, + 0xfeff, 0xff21, + 0xff3b, 0xff41, + 0xff5b, 0xff66, + 0xffe0, 0x10000, + 0x10101, 0x10102, + 0x10140, 0x101d0, + 0x101fd, 0x10280, + 0x1091f, 0x10920, + 0x10a01, 0x10a10, + 0x10a38, 0x10a40, + 0x1d167, 0x1d16a, + 0x1d173, 0x1d183, + 0x1d185, 0x1d18c, + 0x1d1aa, 0x1d1ae, + 0x1d200, 0x1d360, + 0x1d7ce, 0x20000, + 0xe0001, 0xf0000, + 0x10fffe, 0x10ffff // sentinel }; // use a binary search with a cache - private static int stCache = 0; + private transient volatile int stCache = 0; - // warning, synchronize access to this as it modifies state - private static boolean isStrongDirectional(char c) { - if (c < strongTable[stCache]) { - stCache = search(c, strongTable, 0, stCache); - } else if (c >= strongTable[stCache + 1]) { - stCache = search(c, strongTable, stCache + 1, strongTable.length - stCache - 1); + private boolean isStrongDirectional(char c) { + int cachedIndex = stCache; + if (c < strongTable[cachedIndex]) { + cachedIndex = search(c, strongTable, 0, cachedIndex); + } else if (c >= strongTable[cachedIndex + 1]) { + cachedIndex = search(c, strongTable, cachedIndex + 1, + strongTable.length - cachedIndex - 1); } - return (stCache & 0x1) == 1; + boolean val = (cachedIndex & 0x1) == 1; + stCache = cachedIndex; + return val; } - static private int getKeyFromMask(int mask) { + private static int getKeyFromMask(int mask) { int key = 0; while (key < NUM_KEYS && ((mask & (1<The shaper assumes EUROPEAN as the starting context, that + * is, if EUROPEAN digits are encountered before any strong + * directional text in the string, the context is presumed to be + * EUROPEAN, and so the digits will not shape. + * + * @param ranges the specified Unicode ranges + * @return a contextual shaper for the specified ranges + * @throws NullPointerException if {@code ranges} is {@code null}. + * @since 1.7 + */ + public static NumericShaper getContextualShaper(Set ranges) { + NumericShaper shaper = new NumericShaper(Range.EUROPEAN, ranges); + shaper.mask = CONTEXTUAL_MASK; + return shaper; + } + /** * Returns a contextual shaper for the provided unicode range(s). * Latin-1 (EUROPEAN) digits will be converted to the decimal digits @@ -683,12 +888,37 @@ public final class NumericShaper implements java.io.Serializable { * @throws IllegalArgumentException if the specified * defaultContext is not a single valid range. */ - static public NumericShaper getContextualShaper(int ranges, int defaultContext) { + public static NumericShaper getContextualShaper(int ranges, int defaultContext) { int key = getKeyFromMask(defaultContext); ranges |= CONTEXTUAL_MASK; return new NumericShaper(key, ranges); } + /** + * Returns a contextual shaper for the provided Unicode range(s). + * The Latin-1 (EUROPEAN) digits will be converted to the decimal + * digits corresponding to the range of the preceding text, if the + * range is one of the provided ranges. The shaper uses {@code + * defaultContext} as the starting context. + * + * @param ranges the specified Unicode ranges + * @param defaultContext the starting context, such as + * {@code NumericShaper.Range.EUROPEAN} + * @return a contextual shaper for the specified Unicode ranges. + * @throws NullPointerException + * if {@code ranges} or {@code defaultContext} is {@code null} + * @since 1.7 + */ + public static NumericShaper getContextualShaper(Set ranges, + Range defaultContext) { + if (defaultContext == null) { + throw new NullPointerException(); + } + NumericShaper shaper = new NumericShaper(defaultContext, ranges); + shaper.mask = CONTEXTUAL_MASK; + return shaper; + } + /** * Private constructor. */ @@ -697,6 +927,11 @@ public final class NumericShaper implements java.io.Serializable { this.mask = mask; } + private NumericShaper(Range defaultContext, Set ranges) { + this.shapingRange = defaultContext; + this.rangeSet = EnumSet.copyOf(ranges); // throws NPE if ranges is null. + } + /** * Converts the digits in the text that occur between start and * start + count. @@ -710,19 +945,13 @@ public final class NumericShaper implements java.io.Serializable { * @throws NullPointerException if text is null */ public void shape(char[] text, int start, int count) { - if (text == null) { - throw new NullPointerException("text is null"); - } - if ((start < 0) - || (start > text.length) - || ((start + count) < 0) - || ((start + count) > text.length)) { - throw new IndexOutOfBoundsException( - "bad start or count for text of length " + text.length); - } - + checkParams(text, start, count); if (isContextual()) { - shapeContextually(text, start, count, key); + if (rangeSet == null) { + shapeContextually(text, start, count, key); + } else { + shapeContextually(text, start, count, shapingRange); + } } else { shapeNonContextually(text, start, count); } @@ -747,6 +976,60 @@ public final class NumericShaper implements java.io.Serializable { * range. */ public void shape(char[] text, int start, int count, int context) { + checkParams(text, start, count); + if (isContextual()) { + int ctxKey = getKeyFromMask(context); + if (rangeSet == null) { + shapeContextually(text, start, count, ctxKey); + } else { + shapeContextually(text, start, count, Range.values()[ctxKey]); + } + } else { + shapeNonContextually(text, start, count); + } + } + + /** + * Converts the digits in the text that occur between {@code + * start} and {@code start + count}, using the provided {@code + * context}. {@code Context} is ignored if the shaper is not a + * contextual shaper. + * + * @param text a {@code char} array + * @param start the index into {@code text} to start converting + * @param count the number of {@code char}s in {@code text} + * to convert + * @param context the context to which to convert the characters, + * such as {@code NumericShaper.Range.EUROPEAN} + * @throws IndexOutOfBoundsException + * if {@code start} or {@code start + count} is out of bounds + * @throws NullPointerException + * if {@code text} or {@code context} is null + * @since 1.7 + */ + public void shape(char[] text, int start, int count, Range context) { + checkParams(text, start, count); + if (context == null) { + throw new NullPointerException("context is null"); + } + + if (isContextual()) { + if (rangeSet != null) { + shapeContextually(text, start, count, context); + } else { + int key = Range.toRangeIndex(context); + if (key >= 0) { + shapeContextually(text, start, count, key); + } else { + shapeContextually(text, start, count, shapingRange); + } + } + } else { + shapeNonContextually(text, start, count); + } + } + + private void checkParams(char[] text, int start, int count) { if (text == null) { throw new NullPointerException("text is null"); } @@ -757,13 +1040,6 @@ public final class NumericShaper implements java.io.Serializable { throw new IndexOutOfBoundsException( "bad start or count for text of length " + text.length); } - - if (isContextual()) { - int ctxKey = getKeyFromMask(context); - shapeContextually(text, start, count, ctxKey); - } else { - shapeNonContextually(text, start, count); - } } /** @@ -785,18 +1061,45 @@ public final class NumericShaper implements java.io.Serializable { *

* if ((shaper.getRanges() & shaper.ARABIC) != 0) { ... *
+ * + *

Note that this method supports only the bit mask-based + * ranges. Call {@link #getRangeSet()} for the enum-based ranges. + * * @return the values for all the ranges to be shaped. */ public int getRanges() { return mask & ~CONTEXTUAL_MASK; } + /** + * Returns a {@code Set} representing all the Unicode ranges in + * this {@code NumericShaper} that will be shaped. + * + * @return all the Unicode ranges to be shaped. + * @since 1.7 + */ + public Set getRangeSet() { + if (rangeSet != null) { + return EnumSet.copyOf(rangeSet); + } + return Range.maskToRangeSet(mask); + } + /** * Perform non-contextual shaping. */ private void shapeNonContextually(char[] text, int start, int count) { - int base = bases[key]; - char minDigit = key == TAMIL_KEY ? '\u0031' : '\u0030'; // Tamil doesn't use decimal zero + int base; + char minDigit = '0'; + if (shapingRange != null) { + base = shapingRange.getDigitBase(); + minDigit += shapingRange.getNumericBase(); + } else { + base = bases[key]; + if (key == ETHIOPIC_KEY) { + minDigit++; // Ethiopic doesn't use decimal zero + } + } for (int i = start, e = start + count; i < e; ++i) { char c = text[i]; if (c >= minDigit && c <= '\u0039') { @@ -807,7 +1110,7 @@ public final class NumericShaper implements java.io.Serializable { /** * Perform contextual shaping. - * Synchronized to protect caches used in getContextKey and isStrongDirectional. + * Synchronized to protect caches used in getContextKey. */ private synchronized void shapeContextually(char[] text, int start, int count, int ctxKey) { @@ -818,29 +1121,64 @@ public final class NumericShaper implements java.io.Serializable { int lastkey = ctxKey; int base = bases[ctxKey]; - char minDigit = ctxKey == TAMIL_KEY ? '\u0031' : '\u0030'; // Tamil doesn't use decimal zero + char minDigit = ctxKey == ETHIOPIC_KEY ? '1' : '0'; // Ethiopic doesn't use decimal zero - for (int i = start, e = start + count; i < e; ++i) { - char c = text[i]; - if (c >= minDigit && c <= '\u0039') { - text[i] = (char)(c + base); + synchronized (NumericShaper.class) { + for (int i = start, e = start + count; i < e; ++i) { + char c = text[i]; + if (c >= minDigit && c <= '\u0039') { + text[i] = (char)(c + base); + } + + if (isStrongDirectional(c)) { + int newkey = getContextKey(c); + if (newkey != lastkey) { + lastkey = newkey; + + ctxKey = newkey; + if (((mask & EASTERN_ARABIC) != 0) && (ctxKey == ARABIC_KEY || ctxKey == EASTERN_ARABIC_KEY)) { + ctxKey = EASTERN_ARABIC_KEY; + } else if ((mask & (1<= minDigit && c <= '9') { + text[i] = (char)(c + base); + continue; + } if (isStrongDirectional(c)) { - int newkey = getContextKey(c); - if (newkey != lastkey) { - lastkey = newkey; - - ctxKey = newkey; - if (((mask & EASTERN_ARABIC) != 0) && (ctxKey == ARABIC_KEY || ctxKey == EASTERN_ARABIC_KEY)) { - ctxKey = EASTERN_ARABIC_KEY; - } else if ((mask & (1<NumericShaper and shapes identically to this one. + * Returns {@code true} if the specified object is an instance of + * NumericShaper and shapes identically to this one, + * regardless of the range representations, the bit mask or the + * enum. For example, the following code produces {@code "true"}. + *

+     * NumericShaper ns1 = NumericShaper.getShaper(NumericShaper.ARABIC);
+     * NumericShaper ns2 = NumericShaper.getShaper(NumericShaper.Range.ARABIC);
+     * System.out.println(ns1.equals(ns2));
+     * 
+ * * @param o the specified object to compare to this * NumericShaper * @return true if o is an instance @@ -869,6 +1223,22 @@ public final class NumericShaper implements java.io.Serializable { if (o != null) { try { NumericShaper rhs = (NumericShaper)o; + if (rangeSet != null) { + if (rhs.rangeSet != null) { + return isContextual() == rhs.isContextual() + && rangeSet.equals(rhs.rangeSet) + && shapingRange == rhs.shapingRange; + } + return isContextual() == rhs.isContextual() + && rangeSet.equals(Range.maskToRangeSet(rhs.mask)) + && shapingRange == Range.indexToRange(rhs.key); + } else if (rhs.rangeSet != null) { + Set rset = Range.maskToRangeSet(mask); + Range srange = Range.indexToRange(key); + return isContextual() == rhs.isContextual() + && rset.equals(rhs.rangeSet) + && srange == rhs.shapingRange; + } return rhs.mask == mask && rhs.key == key; } catch (ClassCastException e) { @@ -885,23 +1255,29 @@ public final class NumericShaper implements java.io.Serializable { public String toString() { StringBuilder buf = new StringBuilder(super.toString()); - buf.append("[contextual:" + isContextual()); + buf.append("[contextual:").append(isContextual()); + String[] keyNames = null; if (isContextual()) { - buf.append(", context:" + keyNames[key]); + buf.append(", context:"); + buf.append(shapingRange == null ? Range.values()[key] : shapingRange); } - buf.append(", range(s): "); - boolean first = true; - for (int i = 0; i < NUM_KEYS; ++i) { - if ((mask & (1 << i)) != 0) { - if (first) { - first = false; - } else { - buf.append(", "); + if (rangeSet == null) { + buf.append(", range(s): "); + boolean first = true; + for (int i = 0; i < NUM_KEYS; ++i) { + if ((mask & (1 << i)) != 0) { + if (first) { + first = false; + } else { + buf.append(", "); + } + buf.append(Range.values()[i]); } - buf.append(keyNames[i]); } + } else { + buf.append(", range set: ").append(rangeSet); } buf.append(']'); @@ -940,7 +1316,6 @@ public final class NumericShaper implements java.io.Serializable { } if (value >= 1 << 1) { - value >>= 1; bit += 1; } @@ -950,7 +1325,7 @@ public final class NumericShaper implements java.io.Serializable { /** * fast binary search over subrange of array. */ - private static int search(char value, char[] array, int start, int length) + private static int search(int value, int[] array, int start, int length) { int power = 1 << getHighBit(length); int extra = length - power; @@ -971,4 +1346,27 @@ public final class NumericShaper implements java.io.Serializable { return index; } + + /** + * Converts the {@code NumericShaper.Range} enum-based parameters, + * if any, to the bit mask-based counterparts and writes this + * object to the {@code stream}. Any enum constants that have no + * bit mask-based counterparts are ignored in the conversion. + * + * @param stream the output stream to write to + * @throws IOException if an I/O error occurs while writing to {@code stream} + * @since 1.7 + */ + private void writeObject(ObjectOutputStream stream) throws IOException { + if (shapingRange != null) { + int index = Range.toRangeIndex(shapingRange); + if (index >= 0) { + key = index; + } + } + if (rangeSet != null) { + mask |= Range.toRangeMask(rangeSet); + } + stream.defaultWriteObject(); + } } diff --git a/jdk/src/share/classes/java/beans/MetaData.java b/jdk/src/share/classes/java/beans/MetaData.java index fa67901b7a1..4827d785b38 100644 --- a/jdk/src/share/classes/java/beans/MetaData.java +++ b/jdk/src/share/classes/java/beans/MetaData.java @@ -42,12 +42,11 @@ import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; import java.security.AccessController; import java.security.PrivilegedAction; -import java.sql.Timestamp; - import java.util.*; import javax.swing.Box; @@ -290,13 +289,44 @@ class java_util_Date_PersistenceDelegate extends PersistenceDelegate { * @author Sergey A. Malenkov */ final class java_sql_Timestamp_PersistenceDelegate extends java_util_Date_PersistenceDelegate { - protected void initialize(Class type, Object oldInstance, Object newInstance, Encoder out) { - Timestamp oldTime = (Timestamp)oldInstance; - Timestamp newTime = (Timestamp)newInstance; + private static final Method getNanosMethod = getNanosMethod(); - int nanos = oldTime.getNanos(); - if (nanos != newTime.getNanos()) { - out.writeStatement(new Statement(oldTime, "setNanos", new Object[] {nanos})); + private static Method getNanosMethod() { + try { + Class c = Class.forName("java.sql.Timestamp", true, null); + return c.getMethod("getNanos"); + } catch (ClassNotFoundException e) { + return null; + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + /** + * Invoke Timstamp getNanos. + */ + private static int getNanos(Object obj) { + if (getNanosMethod == null) + throw new AssertionError("Should not get here"); + try { + return (Integer)getNanosMethod.invoke(obj); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof RuntimeException) + throw (RuntimeException)cause; + if (cause instanceof Error) + throw (Error)cause; + throw new AssertionError(e); + } catch (IllegalAccessException iae) { + throw new AssertionError(iae); + } + } + + protected void initialize(Class type, Object oldInstance, Object newInstance, Encoder out) { + // assumes oldInstance and newInstance are Timestamps + int nanos = getNanos(oldInstance); + if (nanos != getNanos(newInstance)) { + out.writeStatement(new Statement(oldInstance, "setNanos", new Object[] {nanos})); } } } diff --git a/jdk/src/share/classes/java/io/ObjectStreamClass.java b/jdk/src/share/classes/java/io/ObjectStreamClass.java index bbaaa505d6d..3a753498da8 100644 --- a/jdk/src/share/classes/java/io/ObjectStreamClass.java +++ b/jdk/src/share/classes/java/io/ObjectStreamClass.java @@ -99,7 +99,7 @@ public class ObjectStreamClass implements Serializable { } /** class associated with this descriptor (if any) */ - private Class cl; + private Class cl; /** name of class represented by this descriptor */ private String name; /** serialVersionUID of represented class (null if not computed yet) */ @@ -276,7 +276,7 @@ public class ObjectStreamClass implements Serializable { * @param all if true, return descriptors for all classes; if false, only * return descriptors for serializable classes */ - static ObjectStreamClass lookup(Class cl, boolean all) { + static ObjectStreamClass lookup(Class cl, boolean all) { if (!(all || Serializable.class.isAssignableFrom(cl))) { return null; } @@ -414,7 +414,7 @@ public class ObjectStreamClass implements Serializable { /** * Creates local class descriptor representing given class. */ - private ObjectStreamClass(final Class cl) { + private ObjectStreamClass(final Class cl) { this.cl = cl; name = cl.getName(); isProxy = Proxy.isProxyClass(cl); @@ -422,7 +422,7 @@ public class ObjectStreamClass implements Serializable { serializable = Serializable.class.isAssignableFrom(cl); externalizable = Externalizable.class.isAssignableFrom(cl); - Class superCl = cl.getSuperclass(); + Class superCl = cl.getSuperclass(); superDesc = (superCl != null) ? lookup(superCl, false) : null; localDesc = this; @@ -453,10 +453,10 @@ public class ObjectStreamClass implements Serializable { } else { cons = getSerializableConstructor(cl); writeObjectMethod = getPrivateMethod(cl, "writeObject", - new Class[] { ObjectOutputStream.class }, + new Class[] { ObjectOutputStream.class }, Void.TYPE); readObjectMethod = getPrivateMethod(cl, "readObject", - new Class[] { ObjectInputStream.class }, + new Class[] { ObjectInputStream.class }, Void.TYPE); readObjectNoDataMethod = getPrivateMethod( cl, "readObjectNoData", null, Void.TYPE); @@ -507,7 +507,7 @@ public class ObjectStreamClass implements Serializable { /** * Initializes class descriptor representing a proxy class. */ - void initProxy(Class cl, + void initProxy(Class cl, ClassNotFoundException resolveEx, ObjectStreamClass superDesc) throws InvalidClassException @@ -540,7 +540,7 @@ public class ObjectStreamClass implements Serializable { * Initializes class descriptor representing a non-proxy class. */ void initNonProxy(ObjectStreamClass model, - Class cl, + Class cl, ClassNotFoundException resolveEx, ObjectStreamClass superDesc) throws InvalidClassException @@ -1131,7 +1131,7 @@ public class ObjectStreamClass implements Serializable { throws InvalidClassException { ArrayList slots = new ArrayList(); - Class start = cl, end = cl; + Class start = cl, end = cl; // locate closest non-serializable superclass while (end != null && Serializable.class.isAssignableFrom(end)) { @@ -1142,8 +1142,8 @@ public class ObjectStreamClass implements Serializable { // search up inheritance hierarchy for class with matching name String searchName = (d.cl != null) ? d.cl.getName() : d.name; - Class match = null; - for (Class c = start; c != end; c = c.getSuperclass()) { + Class match = null; + for (Class c = start; c != end; c = c.getSuperclass()) { if (searchName.equals(c.getName())) { match = c; break; @@ -1152,7 +1152,7 @@ public class ObjectStreamClass implements Serializable { // add "no data" slot for each unmatched class below match if (match != null) { - for (Class c = start; c != match; c = c.getSuperclass()) { + for (Class c = start; c != match; c = c.getSuperclass()) { slots.add(new ClassDataSlot( ObjectStreamClass.lookup(c, true), false)); } @@ -1164,7 +1164,7 @@ public class ObjectStreamClass implements Serializable { } // add "no data" slot for any leftover unmatched classes - for (Class c = start; c != end; c = c.getSuperclass()) { + for (Class c = start; c != end; c = c.getSuperclass()) { slots.add(new ClassDataSlot( ObjectStreamClass.lookup(c, true), false)); } @@ -1288,7 +1288,7 @@ public class ObjectStreamClass implements Serializable { * descriptor, returns reference to this class descriptor. Otherwise, * returns variant of this class descriptor bound to given class. */ - private ObjectStreamClass getVariantFor(Class cl) + private ObjectStreamClass getVariantFor(Class cl) throws InvalidClassException { if (this.cl == cl) { @@ -1355,8 +1355,8 @@ public class ObjectStreamClass implements Serializable { * method (if any). */ private static Method getInheritableMethod(Class cl, String name, - Class[] argTypes, - Class returnType) + Class[] argTypes, + Class returnType) { Method meth = null; Class defCl = cl; @@ -1410,7 +1410,7 @@ public class ObjectStreamClass implements Serializable { * Returns true if classes are defined in the same runtime package, false * otherwise. */ - private static boolean packageEquals(Class cl1, Class cl2) { + private static boolean packageEquals(Class cl1, Class cl2) { return (cl1.getClassLoader() == cl2.getClassLoader() && getPackageName(cl1).equals(getPackageName(cl2))); } @@ -1418,7 +1418,7 @@ public class ObjectStreamClass implements Serializable { /** * Returns package name of given class. */ - private static String getPackageName(Class cl) { + private static String getPackageName(Class cl) { String s = cl.getName(); int i = s.lastIndexOf('['); if (i >= 0) { @@ -1441,7 +1441,7 @@ public class ObjectStreamClass implements Serializable { /** * Returns JVM type signature for given class. */ - static String getClassSignature(Class cl) { + private static String getClassSignature(Class cl) { StringBuilder sbuf = new StringBuilder(); while (cl.isArray()) { sbuf.append('['); @@ -1478,8 +1478,8 @@ public class ObjectStreamClass implements Serializable { /** * Returns JVM type signature for given list of parameters and return type. */ - private static String getMethodSignature(Class[] paramTypes, - Class retType) + private static String getMethodSignature(Class[] paramTypes, + Class retType) { StringBuilder sbuf = new StringBuilder(); sbuf.append('('); @@ -1515,7 +1515,7 @@ public class ObjectStreamClass implements Serializable { * Field objects. Throws InvalidClassException if the (explicitly * declared) serializable fields are invalid. */ - private static ObjectStreamField[] getSerialFields(Class cl) + private static ObjectStreamField[] getSerialFields(Class cl) throws InvalidClassException { ObjectStreamField[] fields; @@ -1545,7 +1545,7 @@ public class ObjectStreamClass implements Serializable { * InvalidClassException if the declared serializable fields are * invalid--e.g., if multiple fields share the same name. */ - private static ObjectStreamField[] getDeclaredSerialFields(Class cl) + private static ObjectStreamField[] getDeclaredSerialFields(Class cl) throws InvalidClassException { ObjectStreamField[] serialPersistentFields = null; @@ -1602,7 +1602,7 @@ public class ObjectStreamClass implements Serializable { * contains a Field object for the field it represents. If no default * serializable fields exist, NO_FIELDS is returned. */ - private static ObjectStreamField[] getDefaultSerialFields(Class cl) { + private static ObjectStreamField[] getDefaultSerialFields(Class cl) { Field[] clFields = cl.getDeclaredFields(); ArrayList list = new ArrayList(); int mask = Modifier.STATIC | Modifier.TRANSIENT; @@ -1621,7 +1621,7 @@ public class ObjectStreamClass implements Serializable { * Returns explicit serial version UID value declared by given class, or * null if none. */ - private static Long getDeclaredSUID(Class cl) { + private static Long getDeclaredSUID(Class cl) { try { Field f = cl.getDeclaredField("serialVersionUID"); int mask = Modifier.STATIC | Modifier.FINAL; @@ -1637,7 +1637,7 @@ public class ObjectStreamClass implements Serializable { /** * Computes the default serial version UID value for the given class. */ - private static long computeDefaultSUID(Class cl) { + private static long computeDefaultSUID(Class cl) { if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl)) { return 0L; @@ -1671,7 +1671,7 @@ public class ObjectStreamClass implements Serializable { * Class.getInterfaces() was modified to return Cloneable and * Serializable for array classes. */ - Class[] interfaces = cl.getInterfaces(); + Class[] interfaces = cl.getInterfaces(); String[] ifaceNames = new String[interfaces.length]; for (int i = 0; i < interfaces.length; i++) { ifaceNames[i] = interfaces[i].getName(); @@ -1784,7 +1784,7 @@ public class ObjectStreamClass implements Serializable { * Returns true if the given class defines a static initializer method, * false otherwise. */ - private native static boolean hasStaticInitializer(Class cl); + private native static boolean hasStaticInitializer(Class cl); /** * Class for computing and caching field/constructor/method signatures @@ -1837,7 +1837,7 @@ public class ObjectStreamClass implements Serializable { /** field type codes */ private final char[] typeCodes; /** field types */ - private final Class[] types; + private final Class[] types; /** * Constructs FieldReflector capable of setting/getting values from the @@ -2071,7 +2071,7 @@ public class ObjectStreamClass implements Serializable { throws InvalidClassException { // class irrelevant if no fields - Class cl = (localDesc != null && fields.length > 0) ? + Class cl = (localDesc != null && fields.length > 0) ? localDesc.cl : null; processQueue(Caches.reflectorsQueue, Caches.reflectors); FieldReflectorKey key = new FieldReflectorKey(cl, fields, @@ -2136,7 +2136,7 @@ public class ObjectStreamClass implements Serializable { private final int hash; private final boolean nullClass; - FieldReflectorKey(Class cl, ObjectStreamField[] fields, + FieldReflectorKey(Class cl, ObjectStreamField[] fields, ReferenceQueue> queue) { super(cl, queue); diff --git a/jdk/src/share/classes/java/io/ObjectStreamField.java b/jdk/src/share/classes/java/io/ObjectStreamField.java index b8e784f4549..dc368bc8d38 100644 --- a/jdk/src/share/classes/java/io/ObjectStreamField.java +++ b/jdk/src/share/classes/java/io/ObjectStreamField.java @@ -45,7 +45,7 @@ public class ObjectStreamField /** canonical JVM signature of field type */ private final String signature; /** field type (Object.class if unknown non-primitive type) */ - private final Class type; + private final Class type; /** whether or not to (de)serialize field values as unshared */ private final boolean unshared; /** corresponding reflective field object, if any */ @@ -88,7 +88,7 @@ public class ObjectStreamField this.name = name; this.type = type; this.unshared = unshared; - signature = ObjectStreamClass.getClassSignature(type).intern(); + signature = getClassSignature(type).intern(); field = null; } @@ -132,9 +132,9 @@ public class ObjectStreamField this.field = field; this.unshared = unshared; name = field.getName(); - Class ftype = field.getType(); + Class ftype = field.getType(); type = (showType || ftype.isPrimitive()) ? ftype : Object.class; - signature = ObjectStreamClass.getClassSignature(ftype).intern(); + signature = getClassSignature(ftype).intern(); } /** @@ -274,4 +274,41 @@ public class ObjectStreamField String getSignature() { return signature; } + + /** + * Returns JVM type signature for given class. + */ + private static String getClassSignature(Class cl) { + StringBuilder sbuf = new StringBuilder(); + while (cl.isArray()) { + sbuf.append('['); + cl = cl.getComponentType(); + } + if (cl.isPrimitive()) { + if (cl == Integer.TYPE) { + sbuf.append('I'); + } else if (cl == Byte.TYPE) { + sbuf.append('B'); + } else if (cl == Long.TYPE) { + sbuf.append('J'); + } else if (cl == Float.TYPE) { + sbuf.append('F'); + } else if (cl == Double.TYPE) { + sbuf.append('D'); + } else if (cl == Short.TYPE) { + sbuf.append('S'); + } else if (cl == Character.TYPE) { + sbuf.append('C'); + } else if (cl == Boolean.TYPE) { + sbuf.append('Z'); + } else if (cl == Void.TYPE) { + sbuf.append('V'); + } else { + throw new InternalError(); + } + } else { + sbuf.append('L' + cl.getName().replace('.', '/') + ';'); + } + return sbuf.toString(); + } } diff --git a/jdk/src/share/classes/java/lang/ClassLoader.java b/jdk/src/share/classes/java/lang/ClassLoader.java index bd59d95667a..323240b395c 100644 --- a/jdk/src/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/share/classes/java/lang/ClassLoader.java @@ -186,11 +186,6 @@ public abstract class ClassLoader { parallelLoaders.add(ClassLoader.class); } - // If initialization succeed this is set to true and security checks will - // succeed. Otherwise the object is not initialized and the object is - // useless. - private final boolean initialized; - // The parent class loader for delegation // Note: VM hardcoded the offset of this field, thus all new fields // must be added *after* it. @@ -232,6 +227,31 @@ public abstract class ClassLoader { private final HashMap packages = new HashMap(); + private static Void checkCreateClassLoader() { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkCreateClassLoader(); + } + return null; + } + + private ClassLoader(Void unused, ClassLoader parent) { + this.parent = parent; + if (parallelLoaders.contains(this.getClass())) { + parallelLockMap = new ConcurrentHashMap(); + package2certs = new ConcurrentHashMap(); + domains = + Collections.synchronizedSet(new HashSet()); + assertionLock = new Object(); + } else { + // no finer-grained lock; lock on the classloader instance + parallelLockMap = null; + package2certs = new Hashtable(); + domains = new HashSet(); + assertionLock = this; + } + } + /** * Creates a new class loader using the specified parent class loader for * delegation. @@ -252,25 +272,7 @@ public abstract class ClassLoader { * @since 1.2 */ protected ClassLoader(ClassLoader parent) { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkCreateClassLoader(); - } - this.parent = parent; - if (parallelLoaders.contains(this.getClass())) { - parallelLockMap = new ConcurrentHashMap(); - package2certs = new ConcurrentHashMap(); - domains = - Collections.synchronizedSet(new HashSet()); - assertionLock = new Object(); - } else { - // no finer-grained lock; lock on the classloader instance - parallelLockMap = null; - package2certs = new Hashtable(); - domains = new HashSet(); - assertionLock = this; - } - initialized = true; + this(checkCreateClassLoader(), parent); } /** @@ -289,25 +291,7 @@ public abstract class ClassLoader { * of a new class loader. */ protected ClassLoader() { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkCreateClassLoader(); - } - this.parent = getSystemClassLoader(); - if (parallelLoaders.contains(this.getClass())) { - parallelLockMap = new ConcurrentHashMap(); - package2certs = new ConcurrentHashMap(); - domains = - Collections.synchronizedSet(new HashSet()); - assertionLock = new Object(); - } else { - // no finer-grained lock; lock on the classloader instance - parallelLockMap = null; - package2certs = new Hashtable(); - domains = new HashSet(); - assertionLock = this; - } - initialized = true; + this(checkCreateClassLoader(), getSystemClassLoader()); } // -- Class -- @@ -754,7 +738,6 @@ public abstract class ClassLoader { ProtectionDomain protectionDomain) throws ClassFormatError { - check(); protectionDomain = preDefineClass(name, protectionDomain); Class c = null; @@ -838,8 +821,6 @@ public abstract class ClassLoader { ProtectionDomain protectionDomain) throws ClassFormatError { - check(); - int len = b.remaining(); // Use byte[] if not a direct ByteBufer: @@ -984,7 +965,6 @@ public abstract class ClassLoader { * @see #defineClass(String, byte[], int, int) */ protected final void resolveClass(Class c) { - check(); resolveClass0(c); } @@ -1015,7 +995,6 @@ public abstract class ClassLoader { protected final Class findSystemClass(String name) throws ClassNotFoundException { - check(); ClassLoader system = getSystemClassLoader(); if (system == null) { if (!checkName(name)) @@ -1035,7 +1014,6 @@ public abstract class ClassLoader { */ private Class findBootstrapClassOrNull(String name) { - check(); if (!checkName(name)) return null; return findBootstrapClass(name); @@ -1044,13 +1022,6 @@ public abstract class ClassLoader { // return null if not found private native Class findBootstrapClass(String name); - // Check to make sure the class loader has been initialized. - private void check() { - if (!initialized) { - throw new SecurityException("ClassLoader object not initialized"); - } - } - /** * Returns the class with the given binary name if this * loader has been recorded by the Java virtual machine as an initiating @@ -1066,7 +1037,6 @@ public abstract class ClassLoader { * @since 1.1 */ protected final Class findLoadedClass(String name) { - check(); if (!checkName(name)) return null; return findLoadedClass0(name); @@ -1087,7 +1057,6 @@ public abstract class ClassLoader { * @since 1.1 */ protected final void setSigners(Class c, Object[] signers) { - check(); c.setSigners(signers); } @@ -2205,3 +2174,4 @@ class SystemClassLoaderAction return sys; } } + diff --git a/jdk/src/share/classes/java/lang/management/PlatformComponent.java b/jdk/src/share/classes/java/lang/management/PlatformComponent.java index 3dc5a68400d..e0d5d683412 100644 --- a/jdk/src/share/classes/java/lang/management/PlatformComponent.java +++ b/jdk/src/share/classes/java/lang/management/PlatformComponent.java @@ -30,8 +30,7 @@ import java.util.Collections; import java.util.List; import java.util.HashSet; import java.util.Set; -import java.util.logging.LoggingMXBean; -import java.util.logging.LogManager; +import java.util.logging.PlatformLoggingMXBean; import java.nio.BufferPoolMXBean; import javax.management.MBeanServerConnection; import javax.management.ObjectName; @@ -40,6 +39,7 @@ import com.sun.management.HotSpotDiagnosticMXBean; import com.sun.management.UnixOperatingSystemMXBean; import sun.management.ManagementFactoryHelper; +import sun.management.Util; /** * This enum class defines the list of platform components @@ -180,15 +180,14 @@ enum PlatformComponent { * Logging facility. */ LOGGING( - "java.util.logging.LoggingMXBean", + "java.util.logging.PlatformLoggingMXBean", "java.util.logging", "Logging", defaultKeyProperties(), - new MXBeanFetcher() { - public List getMXBeans() { - return Collections.singletonList(LogManager.getLoggingMXBean()); + new MXBeanFetcher() { + public List getMXBeans() { + return ManagementFactoryHelper.getLoggingMXBean(); } }), - /** * Buffer pools. */ @@ -384,7 +383,7 @@ enum PlatformComponent { // if there are more than 1 key properties (i.e. other than "type") domainAndType += ",*"; } - ObjectName on = ObjectName.valueOf(domainAndType); + ObjectName on = Util.newObjectName(domainAndType); Set set = mbs.queryNames(on, null); for (PlatformComponent pc : subComponents) { set.addAll(pc.getObjectNames(mbs)); diff --git a/jdk/src/share/classes/java/math/BigInteger.java b/jdk/src/share/classes/java/math/BigInteger.java index ec979898ffd..d7d4f19f040 100644 --- a/jdk/src/share/classes/java/math/BigInteger.java +++ b/jdk/src/share/classes/java/math/BigInteger.java @@ -288,11 +288,11 @@ public class BigInteger extends Number implements Comparable { */ public BigInteger(String val, int radix) { int cursor = 0, numDigits; - int len = val.length(); + final int len = val.length(); if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) throw new NumberFormatException("Radix out of range"); - if (val.length() == 0) + if (len == 0) throw new NumberFormatException("Zero length BigInteger"); // Check for at most one leading sign @@ -303,7 +303,7 @@ public class BigInteger extends Number implements Comparable { // No leading sign character or at most one leading sign character if (index1 == 0 || index2 == 0) { cursor = 1; - if (val.length() == 1) + if (len == 1) throw new NumberFormatException("Zero length BigInteger"); } if (index1 == 0) @@ -342,7 +342,7 @@ public class BigInteger extends Number implements Comparable { // Process remaining digit groups int superRadix = intRadix[radix]; int groupVal = 0; - while (cursor < val.length()) { + while (cursor < len) { group = val.substring(cursor, cursor += digitsPerInt[radix]); groupVal = Integer.parseInt(group, radix); if (groupVal < 0) @@ -478,7 +478,7 @@ public class BigInteger extends Number implements Comparable { /** * Constructs a randomly generated BigInteger, uniformly distributed over - * the range {@code 0} to (2{@code numBits} - 1), inclusive. + * the range 0 to (2{@code numBits} - 1), inclusive. * The uniformity of the distribution assumes that a fair source of random * bits is provided in {@code rnd}. Note that this constructor always * constructs a non-negative BigInteger. @@ -1332,7 +1332,7 @@ public class BigInteger extends Number implements Comparable { * * @param val value by which this BigInteger is to be divided. * @return {@code this / val} - * @throws ArithmeticException {@code val==0} + * @throws ArithmeticException if {@code val} is zero. */ public BigInteger divide(BigInteger val) { MutableBigInteger q = new MutableBigInteger(), @@ -1352,7 +1352,7 @@ public class BigInteger extends Number implements Comparable { * @return an array of two BigIntegers: the quotient {@code (this / val)} * is the initial element, and the remainder {@code (this % val)} * is the final element. - * @throws ArithmeticException {@code val==0} + * @throws ArithmeticException if {@code val} is zero. */ public BigInteger[] divideAndRemainder(BigInteger val) { BigInteger[] result = new BigInteger[2]; @@ -1371,7 +1371,7 @@ public class BigInteger extends Number implements Comparable { * @param val value by which this BigInteger is to be divided, and the * remainder computed. * @return {@code this % val} - * @throws ArithmeticException {@code val==0} + * @throws ArithmeticException if {@code val} is zero. */ public BigInteger remainder(BigInteger val) { MutableBigInteger q = new MutableBigInteger(), @@ -1547,7 +1547,7 @@ public class BigInteger extends Number implements Comparable { * * @param m the modulus. * @return {@code this mod m} - * @throws ArithmeticException {@code m <= 0} + * @throws ArithmeticException {@code m} ≤ 0 * @see #remainder */ public BigInteger mod(BigInteger m) { @@ -1566,7 +1566,9 @@ public class BigInteger extends Number implements Comparable { * @param exponent the exponent. * @param m the modulus. * @return thisexponent mod m - * @throws ArithmeticException {@code m <= 0} + * @throws ArithmeticException {@code m} ≤ 0 or the exponent is + * negative and this BigInteger is not relatively + * prime to {@code m}. * @see #modInverse */ public BigInteger modPow(BigInteger exponent, BigInteger m) { @@ -2015,7 +2017,7 @@ public class BigInteger extends Number implements Comparable { * * @param m the modulus. * @return {@code this}-1 {@code mod m}. - * @throws ArithmeticException {@code m <= 0}, or this BigInteger + * @throws ArithmeticException {@code m} ≤ 0, or this BigInteger * has no multiplicative inverse mod m (that is, this BigInteger * is not relatively prime to m). */ @@ -2051,6 +2053,8 @@ public class BigInteger extends Number implements Comparable { * * @param n shift distance, in bits. * @return {@code this << n} + * @throws ArithmeticException if the shift distance is {@code + * Integer.MIN_VALUE}. * @see #shiftRight */ public BigInteger shiftLeft(int n) { @@ -2058,8 +2062,13 @@ public class BigInteger extends Number implements Comparable { return ZERO; if (n==0) return this; - if (n<0) - return shiftRight(-n); + if (n<0) { + if (n == Integer.MIN_VALUE) { + throw new ArithmeticException("Shift distance of Integer.MIN_VALUE not supported."); + } else { + return shiftRight(-n); + } + } int nInts = n >>> 5; int nBits = n & 0x1f; @@ -2097,13 +2106,20 @@ public class BigInteger extends Number implements Comparable { * * @param n shift distance, in bits. * @return {@code this >> n} + * @throws ArithmeticException if the shift distance is {@code + * Integer.MIN_VALUE}. * @see #shiftLeft */ public BigInteger shiftRight(int n) { if (n==0) return this; - if (n<0) - return shiftLeft(-n); + if (n<0) { + if (n == Integer.MIN_VALUE) { + throw new ArithmeticException("Shift distance of Integer.MIN_VALUE not supported."); + } else { + return shiftLeft(-n); + } + } int nInts = n >>> 5; int nBits = n & 0x1f; @@ -2435,7 +2451,7 @@ public class BigInteger extends Number implements Comparable { /** * Returns {@code true} if this BigInteger is probably prime, * {@code false} if it's definitely composite. If - * {@code certainty} is {@code <= 0}, {@code true} is + * {@code certainty} is ≤ 0, {@code true} is * returned. * * @param certainty a measure of the uncertainty that the caller is diff --git a/jdk/src/share/classes/java/net/CookieHandler.java b/jdk/src/share/classes/java/net/CookieHandler.java index 0de42ac43f0..1bdfe3c8577 100644 --- a/jdk/src/share/classes/java/net/CookieHandler.java +++ b/jdk/src/share/classes/java/net/CookieHandler.java @@ -101,11 +101,21 @@ public abstract class CookieHandler { * Gets all the applicable cookies from a cookie cache for the * specified uri in the request header. * - * HTTP protocol implementers should make sure that this method is - * called after all request headers related to choosing cookies - * are added, and before the request is sent. + *

The {@code URI} passed as an argument specifies the intended use for + * the cookies. In particular the scheme should reflect whether the cookies + * will be sent over http, https or used in another context like javascript. + * The host part should reflect either the destination of the cookies or + * their origin in the case of javascript.

+ *

It is up to the implementation to take into account the {@code URI} and + * the cookies attributes and security settings to determine which ones + * should be returned.

* - * @param uri a URI to send cookies to in a request + *

HTTP protocol implementers should make sure that this method is + * called after all request headers related to choosing cookies + * are added, and before the request is sent.

+ * + * @param uri a URI representing the intended use for the + * cookies * @param requestHeaders - a Map from request header * field names to lists of field values representing * the current request headers diff --git a/jdk/src/share/classes/java/net/CookieManager.java b/jdk/src/share/classes/java/net/CookieManager.java index 95de8c0db3b..57038fcdbf2 100644 --- a/jdk/src/share/classes/java/net/CookieManager.java +++ b/jdk/src/share/classes/java/net/CookieManager.java @@ -218,6 +218,13 @@ public class CookieManager extends CookieHandler // 'secure' cookies over unsecure links) if (pathMatches(path, cookie.getPath()) && (secureLink || !cookie.getSecure())) { + // Enforce httponly attribute + if (cookie.isHttpOnly()) { + String s = uri.getScheme(); + if (!"http".equalsIgnoreCase(s) && !"https".equalsIgnoreCase(s)) { + continue; + } + } // Let's check the authorize port list if it exists String ports = cookie.getPortlist(); if (ports != null && !ports.isEmpty()) { diff --git a/jdk/src/share/classes/java/security/MessageDigest.java b/jdk/src/share/classes/java/security/MessageDigest.java index 9ff8390d92d..f08b6fd9502 100644 --- a/jdk/src/share/classes/java/security/MessageDigest.java +++ b/jdk/src/share/classes/java/security/MessageDigest.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-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 @@ -414,16 +414,17 @@ public abstract class MessageDigest extends MessageDigestSpi { * * @return true if the digests are equal, false otherwise. */ - public static boolean isEqual(byte digesta[], byte digestb[]) { - if (digesta.length != digestb.length) + public static boolean isEqual(byte[] digesta, byte[] digestb) { + if (digesta.length != digestb.length) { return false; - - for (int i = 0; i < digesta.length; i++) { - if (digesta[i] != digestb[i]) { - return false; - } } - return true; + + int result = 0; + // time-constant comparison + for (int i = 0; i < digesta.length; i++) { + result |= digesta[i] ^ digestb[i]; + } + return result == 0; } /** diff --git a/jdk/src/share/classes/java/util/Arrays.java b/jdk/src/share/classes/java/util/Arrays.java index eac5521cd86..9aa9045f032 100644 --- a/jdk/src/share/classes/java/util/Arrays.java +++ b/jdk/src/share/classes/java/util/Arrays.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 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 @@ -29,1047 +29,353 @@ import java.lang.reflect.*; /** * This class contains various methods for manipulating arrays (such as - * sorting and searching). This class also contains a static factory + * sorting and searching). This class also contains a static factory * that allows arrays to be viewed as lists. * - *

The methods in this class all throw a NullPointerException if - * the specified array reference is null, except where noted. + *

The methods in this class all throw a {@code NullPointerException}, + * if the specified array reference is null, except where noted. * *

The documentation for the methods contained in this class includes - * briefs description of the implementations. Such descriptions should + * briefs description of the implementations. Such descriptions should * be regarded as implementation notes, rather than parts of the - * specification. Implementors should feel free to substitute other - * algorithms, so long as the specification itself is adhered to. (For - * example, the algorithm used by sort(Object[]) does not have to be - * a mergesort, but it does have to be stable.) + * specification. Implementors should feel free to substitute other + * algorithms, so long as the specification itself is adhered to. (For + * example, the algorithm used by {@code sort(Object[])} does not have to be + * a MergeSort, but it does have to be stable.) * *

This class is a member of the * * Java Collections Framework. * - * @author Josh Bloch - * @author Neal Gafter - * @author John Rose - * @since 1.2 + * @author Josh Bloch + * @author Neal Gafter + * @author John Rose + * @since 1.2 */ - public class Arrays { + // Suppresses default constructor, ensuring non-instantiability. - private Arrays() { - } + private Arrays() {} - // Sorting - - /** - * Sorts the specified array of longs into ascending numerical order. - * The sorting algorithm is a tuned quicksort, adapted from Jon - * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", - * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November - * 1993). This algorithm offers n*log(n) performance on many data sets - * that cause other quicksorts to degrade to quadratic performance. - * - * @param a the array to be sorted + /* + * Sorting of primitive type arrays. */ - public static void sort(long[] a) { - sort1(a, 0, a.length); - } /** - * Sorts the specified range of the specified array of longs into - * ascending numerical order. The range to be sorted extends from index - * fromIndex, inclusive, to index toIndex, exclusive. - * (If fromIndex==toIndex, the range to be sorted is empty.) + * Sorts the specified array into ascending numerical order. * - *

The sorting algorithm is a tuned quicksort, adapted from Jon - * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", - * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November - * 1993). This algorithm offers n*log(n) performance on many data sets - * that cause other quicksorts to degrade to quadratic performance. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element (inclusive) to be - * sorted - * @param toIndex the index of the last element (exclusive) to be sorted - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length - */ - public static void sort(long[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - sort1(a, fromIndex, toIndex-fromIndex); - } - - /** - * Sorts the specified array of ints into ascending numerical order. - * The sorting algorithm is a tuned quicksort, adapted from Jon - * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", - * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November - * 1993). This algorithm offers n*log(n) performance on many data sets - * that cause other quicksorts to degrade to quadratic performance. + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted */ public static void sort(int[] a) { - sort1(a, 0, a.length); + DualPivotQuicksort.sort(a); } /** - * Sorts the specified range of the specified array of ints into - * ascending numerical order. The range to be sorted extends from index - * fromIndex, inclusive, to index toIndex, exclusive. - * (If fromIndex==toIndex, the range to be sorted is empty.)

+ * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. * - * The sorting algorithm is a tuned quicksort, adapted from Jon - * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", - * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November - * 1993). This algorithm offers n*log(n) performance on many data sets - * that cause other quicksorts to degrade to quadratic performance. + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted - * @param fromIndex the index of the first element (inclusive) to be - * sorted - * @param toIndex the index of the last element (exclusive) to be sorted - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} */ public static void sort(int[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - sort1(a, fromIndex, toIndex-fromIndex); + DualPivotQuicksort.sort(a, fromIndex, toIndex); } /** - * Sorts the specified array of shorts into ascending numerical order. - * The sorting algorithm is a tuned quicksort, adapted from Jon - * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", - * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November - * 1993). This algorithm offers n*log(n) performance on many data sets - * that cause other quicksorts to degrade to quadratic performance. + * Sorts the specified array into ascending numerical order. + * + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + */ + public static void sort(long[] a) { + DualPivotQuicksort.sort(a); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(long[] a, int fromIndex, int toIndex) { + DualPivotQuicksort.sort(a, fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted */ public static void sort(short[] a) { - sort1(a, 0, a.length); + DualPivotQuicksort.sort(a); } /** - * Sorts the specified range of the specified array of shorts into - * ascending numerical order. The range to be sorted extends from index - * fromIndex, inclusive, to index toIndex, exclusive. - * (If fromIndex==toIndex, the range to be sorted is empty.)

+ * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. * - * The sorting algorithm is a tuned quicksort, adapted from Jon - * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", - * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November - * 1993). This algorithm offers n*log(n) performance on many data sets - * that cause other quicksorts to degrade to quadratic performance. + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted - * @param fromIndex the index of the first element (inclusive) to be - * sorted - * @param toIndex the index of the last element (exclusive) to be sorted - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} */ public static void sort(short[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - sort1(a, fromIndex, toIndex-fromIndex); + DualPivotQuicksort.sort(a, fromIndex, toIndex); } /** - * Sorts the specified array of chars into ascending numerical order. - * The sorting algorithm is a tuned quicksort, adapted from Jon - * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", - * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November - * 1993). This algorithm offers n*log(n) performance on many data sets - * that cause other quicksorts to degrade to quadratic performance. + * Sorts the specified array into ascending numerical order. + * + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted */ public static void sort(char[] a) { - sort1(a, 0, a.length); + DualPivotQuicksort.sort(a); } /** - * Sorts the specified range of the specified array of chars into - * ascending numerical order. The range to be sorted extends from index - * fromIndex, inclusive, to index toIndex, exclusive. - * (If fromIndex==toIndex, the range to be sorted is empty.)

+ * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. * - * The sorting algorithm is a tuned quicksort, adapted from Jon - * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", - * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November - * 1993). This algorithm offers n*log(n) performance on many data sets - * that cause other quicksorts to degrade to quadratic performance. + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted - * @param fromIndex the index of the first element (inclusive) to be - * sorted - * @param toIndex the index of the last element (exclusive) to be sorted - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} */ public static void sort(char[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - sort1(a, fromIndex, toIndex-fromIndex); + DualPivotQuicksort.sort(a, fromIndex, toIndex); } /** - * Sorts the specified array of bytes into ascending numerical order. - * The sorting algorithm is a tuned quicksort, adapted from Jon - * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", - * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November - * 1993). This algorithm offers n*log(n) performance on many data sets - * that cause other quicksorts to degrade to quadratic performance. + * Sorts the specified array into ascending numerical order. + * + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted */ public static void sort(byte[] a) { - sort1(a, 0, a.length); + DualPivotQuicksort.sort(a); } /** - * Sorts the specified range of the specified array of bytes into - * ascending numerical order. The range to be sorted extends from index - * fromIndex, inclusive, to index toIndex, exclusive. - * (If fromIndex==toIndex, the range to be sorted is empty.)

+ * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. * - * The sorting algorithm is a tuned quicksort, adapted from Jon - * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", - * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November - * 1993). This algorithm offers n*log(n) performance on many data sets - * that cause other quicksorts to degrade to quadratic performance. + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted - * @param fromIndex the index of the first element (inclusive) to be - * sorted - * @param toIndex the index of the last element (exclusive) to be sorted - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} */ public static void sort(byte[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - sort1(a, fromIndex, toIndex-fromIndex); + DualPivotQuicksort.sort(a, fromIndex, toIndex); } /** - * Sorts the specified array of doubles into ascending numerical order. - *

- * The < relation does not provide a total order on - * all floating-point values; although they are distinct numbers - * -0.0 == 0.0 is true and a NaN value - * compares neither less than, greater than, nor equal to any - * floating-point value, even itself. To allow the sort to - * proceed, instead of using the < relation to - * determine ascending numerical order, this method uses the total - * order imposed by {@link Double#compareTo}. This ordering - * differs from the < relation in that - * -0.0 is treated as less than 0.0 and - * NaN is considered greater than any other floating-point value. - * For the purposes of sorting, all NaN values are considered - * equivalent and equal. - *

- * The sorting algorithm is a tuned quicksort, adapted from Jon - * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", - * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November - * 1993). This algorithm offers n*log(n) performance on many data sets - * that cause other quicksorts to degrade to quadratic performance. + * Sorts the specified array into ascending numerical order. * - * @param a the array to be sorted - */ - public static void sort(double[] a) { - sort2(a, 0, a.length); - } - - /** - * Sorts the specified range of the specified array of doubles into - * ascending numerical order. The range to be sorted extends from index - * fromIndex, inclusive, to index toIndex, exclusive. - * (If fromIndex==toIndex, the range to be sorted is empty.) - *

- * The < relation does not provide a total order on - * all floating-point values; although they are distinct numbers - * -0.0 == 0.0 is true and a NaN value - * compares neither less than, greater than, nor equal to any - * floating-point value, even itself. To allow the sort to - * proceed, instead of using the < relation to - * determine ascending numerical order, this method uses the total - * order imposed by {@link Double#compareTo}. This ordering - * differs from the < relation in that - * -0.0 is treated as less than 0.0 and - * NaN is considered greater than any other floating-point value. - * For the purposes of sorting, all NaN values are considered - * equivalent and equal. - *

- * The sorting algorithm is a tuned quicksort, adapted from Jon - * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", - * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November - * 1993). This algorithm offers n*log(n) performance on many data sets - * that cause other quicksorts to degrade to quadratic performance. + *

The {@code <} relation does not provide a total order on all float + * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Float#compareTo}: {@code -0.0f} is treated as less than value + * {@code 0.0f} and {@code Float.NaN} is considered greater than any + * other value and all {@code Float.NaN} values are considered equal. * - * @param a the array to be sorted - * @param fromIndex the index of the first element (inclusive) to be - * sorted - * @param toIndex the index of the last element (exclusive) to be sorted - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length - */ - public static void sort(double[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - sort2(a, fromIndex, toIndex); - } - - /** - * Sorts the specified array of floats into ascending numerical order. - *

- * The < relation does not provide a total order on - * all floating-point values; although they are distinct numbers - * -0.0f == 0.0f is true and a NaN value - * compares neither less than, greater than, nor equal to any - * floating-point value, even itself. To allow the sort to - * proceed, instead of using the < relation to - * determine ascending numerical order, this method uses the total - * order imposed by {@link Float#compareTo}. This ordering - * differs from the < relation in that - * -0.0f is treated as less than 0.0f and - * NaN is considered greater than any other floating-point value. - * For the purposes of sorting, all NaN values are considered - * equivalent and equal. - *

- * The sorting algorithm is a tuned quicksort, adapted from Jon - * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", - * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November - * 1993). This algorithm offers n*log(n) performance on many data sets - * that cause other quicksorts to degrade to quadratic performance. + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted */ public static void sort(float[] a) { - sort2(a, 0, a.length); + DualPivotQuicksort.sort(a); } /** - * Sorts the specified range of the specified array of floats into - * ascending numerical order. The range to be sorted extends from index - * fromIndex, inclusive, to index toIndex, exclusive. - * (If fromIndex==toIndex, the range to be sorted is empty.) - *

- * The < relation does not provide a total order on - * all floating-point values; although they are distinct numbers - * -0.0f == 0.0f is true and a NaN value - * compares neither less than, greater than, nor equal to any - * floating-point value, even itself. To allow the sort to - * proceed, instead of using the < relation to - * determine ascending numerical order, this method uses the total - * order imposed by {@link Float#compareTo}. This ordering - * differs from the < relation in that - * -0.0f is treated as less than 0.0f and - * NaN is considered greater than any other floating-point value. - * For the purposes of sorting, all NaN values are considered - * equivalent and equal. - *

- * The sorting algorithm is a tuned quicksort, adapted from Jon - * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function", - * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November - * 1993). This algorithm offers n*log(n) performance on many data sets - * that cause other quicksorts to degrade to quadratic performance. + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + *

The {@code <} relation does not provide a total order on all float + * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Float#compareTo}: {@code -0.0f} is treated as less than value + * {@code 0.0f} and {@code Float.NaN} is considered greater than any + * other value and all {@code Float.NaN} values are considered equal. + * + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. * * @param a the array to be sorted - * @param fromIndex the index of the first element (inclusive) to be - * sorted - * @param toIndex the index of the last element (exclusive) to be sorted - * @throws IllegalArgumentException if fromIndex > toIndex - * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or - * toIndex > a.length + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} */ public static void sort(float[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - sort2(a, fromIndex, toIndex); + DualPivotQuicksort.sort(a, fromIndex, toIndex); } - private static void sort2(double a[], int fromIndex, int toIndex) { - final long NEG_ZERO_BITS = Double.doubleToLongBits(-0.0d); - /* - * The sort is done in three phases to avoid the expense of using - * NaN and -0.0 aware comparisons during the main sort. - */ - - /* - * Preprocessing phase: Move any NaN's to end of array, count the - * number of -0.0's, and turn them into 0.0's. - */ - int numNegZeros = 0; - int i = fromIndex, n = toIndex; - while(i < n) { - if (a[i] != a[i]) { - swap(a, i, --n); - } else { - if (a[i]==0 && Double.doubleToLongBits(a[i])==NEG_ZERO_BITS) { - a[i] = 0.0d; - numNegZeros++; - } - i++; - } - } - - // Main sort phase: quicksort everything but the NaN's - sort1(a, fromIndex, n-fromIndex); - - // Postprocessing phase: change 0.0's to -0.0's as required - if (numNegZeros != 0) { - int j = binarySearch0(a, fromIndex, n, 0.0d); // posn of ANY zero - do { - j--; - } while (j>=fromIndex && a[j]==0.0d); - - // j is now one less than the index of the FIRST zero - for (int k=0; kThe {@code <} relation does not provide a total order on all double + * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Double#compareTo}: {@code -0.0d} is treated as less than value + * {@code 0.0d} and {@code Double.NaN} is considered greater than any + * other value and all {@code Double.NaN} values are considered equal. + * + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + */ + public static void sort(double[] a) { + DualPivotQuicksort.sort(a); } - - private static void sort2(float a[], int fromIndex, int toIndex) { - final int NEG_ZERO_BITS = Float.floatToIntBits(-0.0f); - /* - * The sort is done in three phases to avoid the expense of using - * NaN and -0.0 aware comparisons during the main sort. - */ - - /* - * Preprocessing phase: Move any NaN's to end of array, count the - * number of -0.0's, and turn them into 0.0's. - */ - int numNegZeros = 0; - int i = fromIndex, n = toIndex; - while(i < n) { - if (a[i] != a[i]) { - swap(a, i, --n); - } else { - if (a[i]==0 && Float.floatToIntBits(a[i])==NEG_ZERO_BITS) { - a[i] = 0.0f; - numNegZeros++; - } - i++; - } - } - - // Main sort phase: quicksort everything but the NaN's - sort1(a, fromIndex, n-fromIndex); - - // Postprocessing phase: change 0.0's to -0.0's as required - if (numNegZeros != 0) { - int j = binarySearch0(a, fromIndex, n, 0.0f); // posn of ANY zero - do { - j--; - } while (j>=fromIndex && a[j]==0.0f); - - // j is now one less than the index of the FIRST zero - for (int k=0; kThe {@code <} relation does not provide a total order on all double + * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Double#compareTo}: {@code -0.0d} is treated as less than value + * {@code 0.0d} and {@code Double.NaN} is considered greater than any + * other value and all {@code Double.NaN} values are considered equal. + * + *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort + * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(double[] a, int fromIndex, int toIndex) { + DualPivotQuicksort.sort(a, fromIndex, toIndex); } - /* - * The code for each of the seven primitive types is largely identical. - * C'est la vie. + * Sorting of complex type arrays. + * */ - /** - * Sorts the specified sub-array of longs into ascending order. - */ - private static void sort1(long x[], int off, int len) { - // Insertion sort on smallest arrays - if (len < 7) { - for (int i=off; ioff && x[j-1]>x[j]; j--) - swap(x, j, j-1); - return; - } - - // Choose a partition element, v - int m = off + (len >> 1); // Small arrays, middle element - if (len > 7) { - int l = off; - int n = off + len - 1; - if (len > 40) { // Big arrays, pseudomedian of 9 - int s = len/8; - l = med3(x, l, l+s, l+2*s); - m = med3(x, m-s, m, m+s); - n = med3(x, n-2*s, n-s, n); - } - m = med3(x, l, m, n); // Mid-size, med of 3 - } - long v = x[m]; - - // Establish Invariant: v* (v)* v* - int a = off, b = a, c = off + len - 1, d = c; - while(true) { - while (b <= c && x[b] <= v) { - if (x[b] == v) - swap(x, a++, b); - b++; - } - while (c >= b && x[c] >= v) { - if (x[c] == v) - swap(x, c, d--); - c--; - } - if (b > c) - break; - swap(x, b++, c--); - } - - // Swap partition elements back to middle - int s, n = off + len; - s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s); - s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s); - - // Recursively sort non-partition-elements - if ((s = b-a) > 1) - sort1(x, off, s); - if ((s = d-c) > 1) - sort1(x, n-s, s); - } - - /** - * Swaps x[a] with x[b]. - */ - private static void swap(long x[], int a, int b) { - long t = x[a]; - x[a] = x[b]; - x[b] = t; - } - - /** - * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)]. - */ - private static void vecswap(long x[], int a, int b, int n) { - for (int i=0; i x[c] ? b : x[a] > x[c] ? c : a)); - } - - /** - * Sorts the specified sub-array of integers into ascending order. - */ - private static void sort1(int x[], int off, int len) { - // Insertion sort on smallest arrays - if (len < 7) { - for (int i=off; ioff && x[j-1]>x[j]; j--) - swap(x, j, j-1); - return; - } - - // Choose a partition element, v - int m = off + (len >> 1); // Small arrays, middle element - if (len > 7) { - int l = off; - int n = off + len - 1; - if (len > 40) { // Big arrays, pseudomedian of 9 - int s = len/8; - l = med3(x, l, l+s, l+2*s); - m = med3(x, m-s, m, m+s); - n = med3(x, n-2*s, n-s, n); - } - m = med3(x, l, m, n); // Mid-size, med of 3 - } - int v = x[m]; - - // Establish Invariant: v* (v)* v* - int a = off, b = a, c = off + len - 1, d = c; - while(true) { - while (b <= c && x[b] <= v) { - if (x[b] == v) - swap(x, a++, b); - b++; - } - while (c >= b && x[c] >= v) { - if (x[c] == v) - swap(x, c, d--); - c--; - } - if (b > c) - break; - swap(x, b++, c--); - } - - // Swap partition elements back to middle - int s, n = off + len; - s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s); - s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s); - - // Recursively sort non-partition-elements - if ((s = b-a) > 1) - sort1(x, off, s); - if ((s = d-c) > 1) - sort1(x, n-s, s); - } - - /** - * Swaps x[a] with x[b]. - */ - private static void swap(int x[], int a, int b) { - int t = x[a]; - x[a] = x[b]; - x[b] = t; - } - - /** - * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)]. - */ - private static void vecswap(int x[], int a, int b, int n) { - for (int i=0; i x[c] ? b : x[a] > x[c] ? c : a)); - } - - /** - * Sorts the specified sub-array of shorts into ascending order. - */ - private static void sort1(short x[], int off, int len) { - // Insertion sort on smallest arrays - if (len < 7) { - for (int i=off; ioff && x[j-1]>x[j]; j--) - swap(x, j, j-1); - return; - } - - // Choose a partition element, v - int m = off + (len >> 1); // Small arrays, middle element - if (len > 7) { - int l = off; - int n = off + len - 1; - if (len > 40) { // Big arrays, pseudomedian of 9 - int s = len/8; - l = med3(x, l, l+s, l+2*s); - m = med3(x, m-s, m, m+s); - n = med3(x, n-2*s, n-s, n); - } - m = med3(x, l, m, n); // Mid-size, med of 3 - } - short v = x[m]; - - // Establish Invariant: v* (v)* v* - int a = off, b = a, c = off + len - 1, d = c; - while(true) { - while (b <= c && x[b] <= v) { - if (x[b] == v) - swap(x, a++, b); - b++; - } - while (c >= b && x[c] >= v) { - if (x[c] == v) - swap(x, c, d--); - c--; - } - if (b > c) - break; - swap(x, b++, c--); - } - - // Swap partition elements back to middle - int s, n = off + len; - s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s); - s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s); - - // Recursively sort non-partition-elements - if ((s = b-a) > 1) - sort1(x, off, s); - if ((s = d-c) > 1) - sort1(x, n-s, s); - } - - /** - * Swaps x[a] with x[b]. - */ - private static void swap(short x[], int a, int b) { - short t = x[a]; - x[a] = x[b]; - x[b] = t; - } - - /** - * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)]. - */ - private static void vecswap(short x[], int a, int b, int n) { - for (int i=0; i x[c] ? b : x[a] > x[c] ? c : a)); - } - - - /** - * Sorts the specified sub-array of chars into ascending order. - */ - private static void sort1(char x[], int off, int len) { - // Insertion sort on smallest arrays - if (len < 7) { - for (int i=off; ioff && x[j-1]>x[j]; j--) - swap(x, j, j-1); - return; - } - - // Choose a partition element, v - int m = off + (len >> 1); // Small arrays, middle element - if (len > 7) { - int l = off; - int n = off + len - 1; - if (len > 40) { // Big arrays, pseudomedian of 9 - int s = len/8; - l = med3(x, l, l+s, l+2*s); - m = med3(x, m-s, m, m+s); - n = med3(x, n-2*s, n-s, n); - } - m = med3(x, l, m, n); // Mid-size, med of 3 - } - char v = x[m]; - - // Establish Invariant: v* (v)* v* - int a = off, b = a, c = off + len - 1, d = c; - while(true) { - while (b <= c && x[b] <= v) { - if (x[b] == v) - swap(x, a++, b); - b++; - } - while (c >= b && x[c] >= v) { - if (x[c] == v) - swap(x, c, d--); - c--; - } - if (b > c) - break; - swap(x, b++, c--); - } - - // Swap partition elements back to middle - int s, n = off + len; - s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s); - s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s); - - // Recursively sort non-partition-elements - if ((s = b-a) > 1) - sort1(x, off, s); - if ((s = d-c) > 1) - sort1(x, n-s, s); - } - - /** - * Swaps x[a] with x[b]. - */ - private static void swap(char x[], int a, int b) { - char t = x[a]; - x[a] = x[b]; - x[b] = t; - } - - /** - * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)]. - */ - private static void vecswap(char x[], int a, int b, int n) { - for (int i=0; i x[c] ? b : x[a] > x[c] ? c : a)); - } - - - /** - * Sorts the specified sub-array of bytes into ascending order. - */ - private static void sort1(byte x[], int off, int len) { - // Insertion sort on smallest arrays - if (len < 7) { - for (int i=off; ioff && x[j-1]>x[j]; j--) - swap(x, j, j-1); - return; - } - - // Choose a partition element, v - int m = off + (len >> 1); // Small arrays, middle element - if (len > 7) { - int l = off; - int n = off + len - 1; - if (len > 40) { // Big arrays, pseudomedian of 9 - int s = len/8; - l = med3(x, l, l+s, l+2*s); - m = med3(x, m-s, m, m+s); - n = med3(x, n-2*s, n-s, n); - } - m = med3(x, l, m, n); // Mid-size, med of 3 - } - byte v = x[m]; - - // Establish Invariant: v* (v)* v* - int a = off, b = a, c = off + len - 1, d = c; - while(true) { - while (b <= c && x[b] <= v) { - if (x[b] == v) - swap(x, a++, b); - b++; - } - while (c >= b && x[c] >= v) { - if (x[c] == v) - swap(x, c, d--); - c--; - } - if (b > c) - break; - swap(x, b++, c--); - } - - // Swap partition elements back to middle - int s, n = off + len; - s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s); - s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s); - - // Recursively sort non-partition-elements - if ((s = b-a) > 1) - sort1(x, off, s); - if ((s = d-c) > 1) - sort1(x, n-s, s); - } - - /** - * Swaps x[a] with x[b]. - */ - private static void swap(byte x[], int a, int b) { - byte t = x[a]; - x[a] = x[b]; - x[b] = t; - } - - /** - * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)]. - */ - private static void vecswap(byte x[], int a, int b, int n) { - for (int i=0; i x[c] ? b : x[a] > x[c] ? c : a)); - } - - - /** - * Sorts the specified sub-array of doubles into ascending order. - */ - private static void sort1(double x[], int off, int len) { - // Insertion sort on smallest arrays - if (len < 7) { - for (int i=off; ioff && x[j-1]>x[j]; j--) - swap(x, j, j-1); - return; - } - - // Choose a partition element, v - int m = off + (len >> 1); // Small arrays, middle element - if (len > 7) { - int l = off; - int n = off + len - 1; - if (len > 40) { // Big arrays, pseudomedian of 9 - int s = len/8; - l = med3(x, l, l+s, l+2*s); - m = med3(x, m-s, m, m+s); - n = med3(x, n-2*s, n-s, n); - } - m = med3(x, l, m, n); // Mid-size, med of 3 - } - double v = x[m]; - - // Establish Invariant: v* (v)* v* - int a = off, b = a, c = off + len - 1, d = c; - while(true) { - while (b <= c && x[b] <= v) { - if (x[b] == v) - swap(x, a++, b); - b++; - } - while (c >= b && x[c] >= v) { - if (x[c] == v) - swap(x, c, d--); - c--; - } - if (b > c) - break; - swap(x, b++, c--); - } - - // Swap partition elements back to middle - int s, n = off + len; - s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s); - s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s); - - // Recursively sort non-partition-elements - if ((s = b-a) > 1) - sort1(x, off, s); - if ((s = d-c) > 1) - sort1(x, n-s, s); - } - - /** - * Swaps x[a] with x[b]. - */ - private static void swap(double x[], int a, int b) { - double t = x[a]; - x[a] = x[b]; - x[b] = t; - } - - /** - * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)]. - */ - private static void vecswap(double x[], int a, int b, int n) { - for (int i=0; i x[c] ? b : x[a] > x[c] ? c : a)); - } - - - /** - * Sorts the specified sub-array of floats into ascending order. - */ - private static void sort1(float x[], int off, int len) { - // Insertion sort on smallest arrays - if (len < 7) { - for (int i=off; ioff && x[j-1]>x[j]; j--) - swap(x, j, j-1); - return; - } - - // Choose a partition element, v - int m = off + (len >> 1); // Small arrays, middle element - if (len > 7) { - int l = off; - int n = off + len - 1; - if (len > 40) { // Big arrays, pseudomedian of 9 - int s = len/8; - l = med3(x, l, l+s, l+2*s); - m = med3(x, m-s, m, m+s); - n = med3(x, n-2*s, n-s, n); - } - m = med3(x, l, m, n); // Mid-size, med of 3 - } - float v = x[m]; - - // Establish Invariant: v* (v)* v* - int a = off, b = a, c = off + len - 1, d = c; - while(true) { - while (b <= c && x[b] <= v) { - if (x[b] == v) - swap(x, a++, b); - b++; - } - while (c >= b && x[c] >= v) { - if (x[c] == v) - swap(x, c, d--); - c--; - } - if (b > c) - break; - swap(x, b++, c--); - } - - // Swap partition elements back to middle - int s, n = off + len; - s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s); - s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s); - - // Recursively sort non-partition-elements - if ((s = b-a) > 1) - sort1(x, off, s); - if ((s = d-c) > 1) - sort1(x, n-s, s); - } - - /** - * Swaps x[a] with x[b]. - */ - private static void swap(float x[], int a, int b) { - float t = x[a]; - x[a] = x[b]; - x[b] = t; - } - - /** - * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)]. - */ - private static void vecswap(float x[], int a, int b, int n) { - for (int i=0; i x[c] ? b : x[a] > x[c] ? c : a)); - } - /** * Old merge sort implementation can be selected (for * compatibility with broken comparators) using a system property. * Cannot be a static boolean in the enclosing class due to - * circular dependencies. To be removed in a future release. + * circular dependencies. To be removed in a future release. */ static final class LegacyMergeSort { private static final boolean userRequested = @@ -1235,7 +541,7 @@ public class Arrays { /** * Tuning parameter: list size at or below which insertion sort will be - * used in preference to mergesort or quicksort. + * used in preference to mergesort. * To be removed in a future release. */ private static final int INSERTIONSORT_THRESHOLD = 7; @@ -1474,17 +780,20 @@ public class Arrays { } /** - * Check that fromIndex and toIndex are in range, and throw an - * appropriate exception if they aren't. + * Checks that {@code fromIndex} and {@code toIndex} are in + * the range and throws an appropriate exception, if they aren't. */ - private static void rangeCheck(int arrayLen, int fromIndex, int toIndex) { - if (fromIndex > toIndex) - throw new IllegalArgumentException("fromIndex(" + fromIndex + - ") > toIndex(" + toIndex+")"); - if (fromIndex < 0) + private static void rangeCheck(int length, int fromIndex, int toIndex) { + if (fromIndex > toIndex) { + throw new IllegalArgumentException( + "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); + } + if (fromIndex < 0) { throw new ArrayIndexOutOfBoundsException(fromIndex); - if (toIndex > arrayLen) + } + if (toIndex > length) { throw new ArrayIndexOutOfBoundsException(toIndex); + } } // Searching @@ -1987,21 +1296,21 @@ public class Arrays { /** * Searches the specified array of floats for the specified value using - * the binary search algorithm. The array must be sorted - * (as by the {@link #sort(float[])} method) prior to making this call. If - * it is not sorted, the results are undefined. If the array contains + * the binary search algorithm. The array must be sorted + * (as by the {@link #sort(float[])} method) prior to making this call. If + * it is not sorted, the results are undefined. If the array contains * multiple elements with the specified value, there is no guarantee which - * one will be found. This method considers all NaN values to be + * one will be found. This method considers all NaN values to be * equivalent and equal. * * @param a the array to be searched * @param key the value to be searched for * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first * element greater than the key, or a.length if all - * elements in the array are less than the specified key. Note + * elements in the array are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. */ @@ -2015,10 +1324,10 @@ public class Arrays { * the binary search algorithm. * The range must be sorted * (as by the {@link #sort(float[], int, int)} method) - * prior to making this call. If - * it is not sorted, the results are undefined. If the range contains + * prior to making this call. If + * it is not sorted, the results are undefined. If the range contains * multiple elements with the specified value, there is no guarantee which - * one will be found. This method considers all NaN values to be + * one will be found. This method considers all NaN values to be * equivalent and equal. * * @param a the array to be searched @@ -2028,12 +1337,12 @@ public class Arrays { * @param key the value to be searched for * @return index of the search key, if it is contained in the array * within the specified range; - * otherwise, (-(insertion point) - 1). The + * otherwise, (-(insertion point) - 1). The * insertion point is defined as the point at which the * key would be inserted into the array: the index of the first * element in the range greater than the key, * or toIndex if all - * elements in the range are less than the specified key. Note + * elements in the range are less than the specified key. Note * that this guarantees that the return value will be >= 0 if * and only if the key is found. * @throws IllegalArgumentException @@ -2076,10 +1385,9 @@ public class Arrays { return -(low + 1); // key not found. } - /** * Searches the specified array for the specified object using the binary - * search algorithm. The array must be sorted into ascending order + * search algorithm. The array must be sorted into ascending order * according to the * {@linkplain Comparable natural ordering} * of its elements (as by the @@ -2269,7 +1577,6 @@ public class Arrays { int mid = (low + high) >>> 1; T midVal = a[mid]; int cmp = c.compare(midVal, key); - if (cmp < 0) low = mid + 1; else if (cmp > 0) @@ -2280,7 +1587,6 @@ public class Arrays { return -(low + 1); // key not found. } - // Equality Testing /** @@ -2527,7 +1833,6 @@ public class Arrays { return true; } - /** * Returns true if the two specified arrays of Objects are * equal to one another. The two arrays are considered equal if @@ -2562,7 +1867,6 @@ public class Arrays { return true; } - // Filling /** @@ -2885,8 +2189,8 @@ public class Arrays { a[i] = val; } - // Cloning + /** * Copies the specified array, truncating or padding with nulls (if necessary) * so the copy has the specified length. For all indices that are @@ -3495,7 +2799,6 @@ public class Arrays { return copy; } - // Misc /** @@ -3928,6 +3231,7 @@ public class Arrays { * @param a2 the other array to be tested for equality * @return true if the two arrays are equal * @see #equals(Object[],Object[]) + * @see Objects#deepEquals(Object, Object) * @since 1.5 */ public static boolean deepEquals(Object[] a1, Object[] a2) { @@ -3949,27 +3253,7 @@ public class Arrays { return false; // Figure out whether the two elements are equal - boolean eq; - if (e1 instanceof Object[] && e2 instanceof Object[]) - eq = deepEquals ((Object[]) e1, (Object[]) e2); - else if (e1 instanceof byte[] && e2 instanceof byte[]) - eq = equals((byte[]) e1, (byte[]) e2); - else if (e1 instanceof short[] && e2 instanceof short[]) - eq = equals((short[]) e1, (short[]) e2); - else if (e1 instanceof int[] && e2 instanceof int[]) - eq = equals((int[]) e1, (int[]) e2); - else if (e1 instanceof long[] && e2 instanceof long[]) - eq = equals((long[]) e1, (long[]) e2); - else if (e1 instanceof char[] && e2 instanceof char[]) - eq = equals((char[]) e1, (char[]) e2); - else if (e1 instanceof float[] && e2 instanceof float[]) - eq = equals((float[]) e1, (float[]) e2); - else if (e1 instanceof double[] && e2 instanceof double[]) - eq = equals((double[]) e1, (double[]) e2); - else if (e1 instanceof boolean[] && e2 instanceof boolean[]) - eq = equals((boolean[]) e1, (boolean[]) e2); - else - eq = e1.equals(e2); + boolean eq = deepEquals0(e1, e2); if (!eq) return false; @@ -3977,6 +3261,32 @@ public class Arrays { return true; } + static boolean deepEquals0(Object e1, Object e2) { + assert e1 != null; + boolean eq; + if (e1 instanceof Object[] && e2 instanceof Object[]) + eq = deepEquals ((Object[]) e1, (Object[]) e2); + else if (e1 instanceof byte[] && e2 instanceof byte[]) + eq = equals((byte[]) e1, (byte[]) e2); + else if (e1 instanceof short[] && e2 instanceof short[]) + eq = equals((short[]) e1, (short[]) e2); + else if (e1 instanceof int[] && e2 instanceof int[]) + eq = equals((int[]) e1, (int[]) e2); + else if (e1 instanceof long[] && e2 instanceof long[]) + eq = equals((long[]) e1, (long[]) e2); + else if (e1 instanceof char[] && e2 instanceof char[]) + eq = equals((char[]) e1, (char[]) e2); + else if (e1 instanceof float[] && e2 instanceof float[]) + eq = equals((float[]) e1, (float[]) e2); + else if (e1 instanceof double[] && e2 instanceof double[]) + eq = equals((double[]) e1, (double[]) e2); + else if (e1 instanceof boolean[] && e2 instanceof boolean[]) + eq = equals((boolean[]) e1, (boolean[]) e2); + else + eq = e1.equals(e2); + return eq; + } + /** * Returns a string representation of the contents of the specified array. * The string representation consists of a list of the array's elements, @@ -4173,6 +3483,7 @@ public class Arrays { public static String toString(float[] a) { if (a == null) return "null"; + int iMax = a.length - 1; if (iMax == -1) return "[]"; @@ -4236,6 +3547,7 @@ public class Arrays { public static String toString(Object[] a) { if (a == null) return "null"; + int iMax = a.length - 1; if (iMax == -1) return "[]"; diff --git a/jdk/src/share/classes/java/util/DualPivotQuicksort.java b/jdk/src/share/classes/java/util/DualPivotQuicksort.java new file mode 100644 index 00000000000..b368d0b95b1 --- /dev/null +++ b/jdk/src/share/classes/java/util/DualPivotQuicksort.java @@ -0,0 +1,2051 @@ +/* + * 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 java.util; + +/** + * This class implements the Dual-Pivot Quicksort algorithm by + * Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. The algorithm + * offers O(n log(n)) performance on many data sets that cause other + * quicksorts to degrade to quadratic performance, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @author Vladimir Yaroslavskiy + * @author Jon Bentley + * @author Josh Bloch + * + * @version 2009.11.16 m765.827.v12a + */ +final class DualPivotQuicksort { + + /** + * Suppresses default constructor. + */ + private DualPivotQuicksort() {} + + /* + * Tuning parameters. + */ + + /** + * If the length of an array to be sorted is less than this + * constant, insertion sort is used in preference to Quicksort. + */ + private static final int INSERTION_SORT_THRESHOLD = 32; + + /** + * If the length of a byte array to be sorted is greater than + * this constant, counting sort is used in preference to Quicksort. + */ + private static final int COUNTING_SORT_THRESHOLD_FOR_BYTE = 128; + + /** + * If the length of a short or char array to be sorted is greater + * than this constant, counting sort is used in preference to Quicksort. + */ + private static final int COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR = 32768; + + /* + * Sorting methods for 7 primitive types. + */ + + /** + * Sorts the specified array into ascending numerical order. + * + * @param a the array to be sorted + */ + public static void sort(int[] a) { + doSort(a, 0, a.length - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(int[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + doSort(a, fromIndex, toIndex - 1); + } + + /** + * Sorts the specified range of the array into ascending order. This + * method differs from the public {@code sort} method in that the + * {@code right} index is inclusive, and it does no range checking on + * {@code left} or {@code right}. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void doSort(int[] a, int left, int right) { + // Use insertion sort on tiny arrays + if (right - left + 1 < INSERTION_SORT_THRESHOLD) { + for (int k = left + 1; k <= right; k++) { + int ak = a[k]; + int j; + for (j = k - 1; j >= left && ak < a[j]; j--) { + a[j + 1] = a[j]; + } + a[j + 1] = ak; + } + } else { // Use Dual-Pivot Quicksort on large arrays + dualPivotQuicksort(a, left, right); + } + } + + /** + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void dualPivotQuicksort(int[] a, int left, int right) { + // Compute indices of five evenly spaced elements + int sixth = (right - left + 1) / 6; + int e1 = left + sixth; + int e5 = right - sixth; + int e3 = (left + right) >>> 1; // The midpoint + int e4 = e3 + sixth; + int e2 = e3 - sixth; + + // Sort these elements using a 5-element sorting network + int ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5]; + + if (ae1 > ae2) { int t = ae1; ae1 = ae2; ae2 = t; } + if (ae4 > ae5) { int t = ae4; ae4 = ae5; ae5 = t; } + if (ae1 > ae3) { int t = ae1; ae1 = ae3; ae3 = t; } + if (ae2 > ae3) { int t = ae2; ae2 = ae3; ae3 = t; } + if (ae1 > ae4) { int t = ae1; ae1 = ae4; ae4 = t; } + if (ae3 > ae4) { int t = ae3; ae3 = ae4; ae4 = t; } + if (ae2 > ae5) { int t = ae2; ae2 = ae5; ae5 = t; } + if (ae2 > ae3) { int t = ae2; ae2 = ae3; ae3 = t; } + if (ae4 > ae5) { int t = ae4; ae4 = ae5; ae5 = t; } + + a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; + + /* + * Use the second and fourth of the five sorted elements as pivots. + * These values are inexpensive approximations of the first and + * second terciles of the array. Note that pivot1 <= pivot2. + * + * The pivots are stored in local variables, and the first and + * the last of the sorted elements are moved to the locations + * formerly occupied by the pivots. When partitioning is complete, + * the pivots are swapped back into their final positions, and + * excluded from subsequent sorting. + */ + int pivot1 = ae2; a[e2] = a[left]; + int pivot2 = ae4; a[e4] = a[right]; + + /* + * Partitioning + * + * left part center part right part + * ------------------------------------------------------------ + * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ] + * ------------------------------------------------------------ + * ^ ^ ^ + * | | | + * less k great + */ + + // Pointers + int less = left + 1; // The index of first element of center part + int great = right - 1; // The index before first element of right part + + boolean pivotsDiffer = pivot1 != pivot2; + + if (pivotsDiffer) { + /* + * Invariants: + * all in (left, less) < pivot1 + * pivot1 <= all in [less, k) <= pivot2 + * all in (great, right) > pivot2 + * + * Pointer k is the first index of ?-part + */ + outer: + for (int k = less; k <= great; k++) { + int ak = a[k]; + if (ak < pivot1) { + if (k > less) { + a[k] = a[less]; + a[less] = ak; + } + less++; + } else if (ak > pivot2) { + while (a[great] > pivot2) { + if (k == great--) { + break outer; + } + } + a[k] = a[great]; + a[great--] = ak; + + if ((ak = a[k]) < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } else { // Pivots are equal + /* + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") partition: + * + * left part center part right part + * ------------------------------------------------- + * [ < pivot | == pivot | ? | > pivot ] + * ------------------------------------------------- + * + * ^ ^ ^ + * | | | + * less k great + * + * Invariants: + * + * all in (left, less) < pivot + * all in [less, k) == pivot + * all in (great, right) > pivot + * + * Pointer k is the first index of ?-part + */ + outer: + for (int k = less; k <= great; k++) { + int ak = a[k]; + if (ak == pivot1) { + continue; + } + if (ak < pivot1) { + if (k > less) { + a[k] = a[less]; + a[less] = ak; + } + less++; + } else { // a[k] > pivot + while (a[great] > pivot1) { + if (k == great--) { + break outer; + } + } + a[k] = a[great]; + a[great--] = ak; + + if ((ak = a[k]) < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } + + // Swap pivots into their final positions + a[left] = a[less - 1]; a[less - 1] = pivot1; + a[right] = a[great + 1]; a[great + 1] = pivot2; + + // Sort left and right parts recursively, excluding known pivot values + doSort(a, left, less - 2); + doSort(a, great + 2, right); + + /* + * If pivot1 == pivot2, all elements from center + * part are equal and, therefore, already sorted + */ + if (!pivotsDiffer) { + return; + } + + /* + * If center part is too large (comprises > 5/6 of + * the array), swap internal pivot values to ends + */ + if (less < e1 && e5 < great) { + while (a[less] == pivot1) { + less++; + } + while (a[great] == pivot2) { + great--; + } + for (int k = less + 1; k <= great; ) { + int ak = a[k]; + if (ak == pivot1) { + a[k++] = a[less]; + a[less++] = pivot1; + } else if (ak == pivot2) { + a[k] = a[great]; + a[great--] = pivot2; + } else { + k++; + } + } + } + + // Sort center part recursively, excluding known pivot values + doSort(a, less, great); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @param a the array to be sorted + */ + public static void sort(long[] a) { + doSort(a, 0, a.length - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(long[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + doSort(a, fromIndex, toIndex - 1); + } + + /** + * Sorts the specified range of the array into ascending order. This + * method differs from the public {@code sort} method in that the + * {@code right} index is inclusive, and it does no range checking on + * {@code left} or {@code right}. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void doSort(long[] a, int left, int right) { + // Use insertion sort on tiny arrays + if (right - left + 1 < INSERTION_SORT_THRESHOLD) { + for (int k = left + 1; k <= right; k++) { + long ak = a[k]; + int j; + for (j = k - 1; j >= left && ak < a[j]; j--) { + a[j + 1] = a[j]; + } + a[j + 1] = ak; + } + } else { // Use Dual-Pivot Quicksort on large arrays + dualPivotQuicksort(a, left, right); + } + } + + /** + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void dualPivotQuicksort(long[] a, int left, int right) { + // Compute indices of five evenly spaced elements + int sixth = (right - left + 1) / 6; + int e1 = left + sixth; + int e5 = right - sixth; + int e3 = (left + right) >>> 1; // The midpoint + int e4 = e3 + sixth; + int e2 = e3 - sixth; + + // Sort these elements using a 5-element sorting network + long ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5]; + + if (ae1 > ae2) { long t = ae1; ae1 = ae2; ae2 = t; } + if (ae4 > ae5) { long t = ae4; ae4 = ae5; ae5 = t; } + if (ae1 > ae3) { long t = ae1; ae1 = ae3; ae3 = t; } + if (ae2 > ae3) { long t = ae2; ae2 = ae3; ae3 = t; } + if (ae1 > ae4) { long t = ae1; ae1 = ae4; ae4 = t; } + if (ae3 > ae4) { long t = ae3; ae3 = ae4; ae4 = t; } + if (ae2 > ae5) { long t = ae2; ae2 = ae5; ae5 = t; } + if (ae2 > ae3) { long t = ae2; ae2 = ae3; ae3 = t; } + if (ae4 > ae5) { long t = ae4; ae4 = ae5; ae5 = t; } + + a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; + + /* + * Use the second and fourth of the five sorted elements as pivots. + * These values are inexpensive approximations of the first and + * second terciles of the array. Note that pivot1 <= pivot2. + * + * The pivots are stored in local variables, and the first and + * the last of the sorted elements are moved to the locations + * formerly occupied by the pivots. When partitioning is complete, + * the pivots are swapped back into their final positions, and + * excluded from subsequent sorting. + */ + long pivot1 = ae2; a[e2] = a[left]; + long pivot2 = ae4; a[e4] = a[right]; + + /* + * Partitioning + * + * left part center part right part + * ------------------------------------------------------------ + * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ] + * ------------------------------------------------------------ + * ^ ^ ^ + * | | | + * less k great + */ + + // Pointers + int less = left + 1; // The index of first element of center part + int great = right - 1; // The index before first element of right part + + boolean pivotsDiffer = pivot1 != pivot2; + + if (pivotsDiffer) { + /* + * Invariants: + * all in (left, less) < pivot1 + * pivot1 <= all in [less, k) <= pivot2 + * all in (great, right) > pivot2 + * + * Pointer k is the first index of ?-part + */ + outer: + for (int k = less; k <= great; k++) { + long ak = a[k]; + if (ak < pivot1) { + if (k > less) { + a[k] = a[less]; + a[less] = ak; + } + less++; + } else if (ak > pivot2) { + while (a[great] > pivot2) { + if (k == great--) { + break outer; + } + } + a[k] = a[great]; + a[great--] = ak; + + if ((ak = a[k]) < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } else { // Pivots are equal + /* + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") partition: + * + * left part center part right part + * ------------------------------------------------- + * [ < pivot | == pivot | ? | > pivot ] + * ------------------------------------------------- + * + * ^ ^ ^ + * | | | + * less k great + * + * Invariants: + * + * all in (left, less) < pivot + * all in [less, k) == pivot + * all in (great, right) > pivot + * + * Pointer k is the first index of ?-part + */ + outer: + for (int k = less; k <= great; k++) { + long ak = a[k]; + if (ak == pivot1) { + continue; + } + if (ak < pivot1) { + if (k > less) { + a[k] = a[less]; + a[less] = ak; + } + less++; + } else { // a[k] > pivot + while (a[great] > pivot1) { + if (k == great--) { + break outer; + } + } + a[k] = a[great]; + a[great--] = ak; + + if ((ak = a[k]) < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } + + // Swap pivots into their final positions + a[left] = a[less - 1]; a[less - 1] = pivot1; + a[right] = a[great + 1]; a[great + 1] = pivot2; + + // Sort left and right parts recursively, excluding known pivot values + doSort(a, left, less - 2); + doSort(a, great + 2, right); + + /* + * If pivot1 == pivot2, all elements from center + * part are equal and, therefore, already sorted + */ + if (!pivotsDiffer) { + return; + } + + /* + * If center part is too large (comprises > 5/6 of + * the array), swap internal pivot values to ends + */ + if (less < e1 && e5 < great) { + while (a[less] == pivot1) { + less++; + } + while (a[great] == pivot2) { + great--; + } + for (int k = less + 1; k <= great; ) { + long ak = a[k]; + if (ak == pivot1) { + a[k++] = a[less]; + a[less++] = pivot1; + } else if (ak == pivot2) { + a[k] = a[great]; + a[great--] = pivot2; + } else { + k++; + } + } + } + + // Sort center part recursively, excluding known pivot values + doSort(a, less, great); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @param a the array to be sorted + */ + public static void sort(short[] a) { + doSort(a, 0, a.length - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(short[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + doSort(a, fromIndex, toIndex - 1); + } + + /** The number of distinct short values. */ + private static final int NUM_SHORT_VALUES = 1 << 16; + + /** + * Sorts the specified range of the array into ascending order. This + * method differs from the public {@code sort} method in that the + * {@code right} index is inclusive, and it does no range checking on + * {@code left} or {@code right}. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void doSort(short[] a, int left, int right) { + // Use insertion sort on tiny arrays + if (right - left + 1 < INSERTION_SORT_THRESHOLD) { + for (int k = left + 1; k <= right; k++) { + short ak = a[k]; + int j; + for (j = k - 1; j >= left && ak < a[j]; j--) { + a[j + 1] = a[j]; + } + a[j + 1] = ak; + } + } else if (right-left+1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { + // Use counting sort on huge arrays + int[] count = new int[NUM_SHORT_VALUES]; + + for (int i = left; i <= right; i++) { + count[a[i] - Short.MIN_VALUE]++; + } + for (int i = 0, k = left; i < count.length && k <= right; i++) { + short value = (short) (i + Short.MIN_VALUE); + + for (int s = count[i]; s > 0; s--) { + a[k++] = value; + } + } + } else { // Use Dual-Pivot Quicksort on large arrays + dualPivotQuicksort(a, left, right); + } + } + + /** + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void dualPivotQuicksort(short[] a, int left, int right) { + // Compute indices of five evenly spaced elements + int sixth = (right - left + 1) / 6; + int e1 = left + sixth; + int e5 = right - sixth; + int e3 = (left + right) >>> 1; // The midpoint + int e4 = e3 + sixth; + int e2 = e3 - sixth; + + // Sort these elements using a 5-element sorting network + short ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5]; + + if (ae1 > ae2) { short t = ae1; ae1 = ae2; ae2 = t; } + if (ae4 > ae5) { short t = ae4; ae4 = ae5; ae5 = t; } + if (ae1 > ae3) { short t = ae1; ae1 = ae3; ae3 = t; } + if (ae2 > ae3) { short t = ae2; ae2 = ae3; ae3 = t; } + if (ae1 > ae4) { short t = ae1; ae1 = ae4; ae4 = t; } + if (ae3 > ae4) { short t = ae3; ae3 = ae4; ae4 = t; } + if (ae2 > ae5) { short t = ae2; ae2 = ae5; ae5 = t; } + if (ae2 > ae3) { short t = ae2; ae2 = ae3; ae3 = t; } + if (ae4 > ae5) { short t = ae4; ae4 = ae5; ae5 = t; } + + a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; + + /* + * Use the second and fourth of the five sorted elements as pivots. + * These values are inexpensive approximations of the first and + * second terciles of the array. Note that pivot1 <= pivot2. + * + * The pivots are stored in local variables, and the first and + * the last of the sorted elements are moved to the locations + * formerly occupied by the pivots. When partitioning is complete, + * the pivots are swapped back into their final positions, and + * excluded from subsequent sorting. + */ + short pivot1 = ae2; a[e2] = a[left]; + short pivot2 = ae4; a[e4] = a[right]; + + /* + * Partitioning + * + * left part center part right part + * ------------------------------------------------------------ + * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ] + * ------------------------------------------------------------ + * ^ ^ ^ + * | | | + * less k great + */ + + // Pointers + int less = left + 1; // The index of first element of center part + int great = right - 1; // The index before first element of right part + + boolean pivotsDiffer = pivot1 != pivot2; + + if (pivotsDiffer) { + /* + * Invariants: + * all in (left, less) < pivot1 + * pivot1 <= all in [less, k) <= pivot2 + * all in (great, right) > pivot2 + * + * Pointer k is the first index of ?-part + */ + outer: + for (int k = less; k <= great; k++) { + short ak = a[k]; + if (ak < pivot1) { + if (k > less) { + a[k] = a[less]; + a[less] = ak; + } + less++; + } else if (ak > pivot2) { + while (a[great] > pivot2) { + if (k == great--) { + break outer; + } + } + a[k] = a[great]; + a[great--] = ak; + + if ((ak = a[k]) < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } else { // Pivots are equal + /* + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") partition: + * + * left part center part right part + * ------------------------------------------------- + * [ < pivot | == pivot | ? | > pivot ] + * ------------------------------------------------- + * + * ^ ^ ^ + * | | | + * less k great + * + * Invariants: + * + * all in (left, less) < pivot + * all in [less, k) == pivot + * all in (great, right) > pivot + * + * Pointer k is the first index of ?-part + */ + outer: + for (int k = less; k <= great; k++) { + short ak = a[k]; + if (ak == pivot1) { + continue; + } + if (ak < pivot1) { + if (k > less) { + a[k] = a[less]; + a[less] = ak; + } + less++; + } else { // a[k] > pivot + while (a[great] > pivot1) { + if (k == great--) { + break outer; + } + } + a[k] = a[great]; + a[great--] = ak; + + if ((ak = a[k]) < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } + + // Swap pivots into their final positions + a[left] = a[less - 1]; a[less - 1] = pivot1; + a[right] = a[great + 1]; a[great + 1] = pivot2; + + // Sort left and right parts recursively, excluding known pivot values + doSort(a, left, less - 2); + doSort(a, great + 2, right); + + /* + * If pivot1 == pivot2, all elements from center + * part are equal and, therefore, already sorted + */ + if (!pivotsDiffer) { + return; + } + + /* + * If center part is too large (comprises > 5/6 of + * the array), swap internal pivot values to ends + */ + if (less < e1 && e5 < great) { + while (a[less] == pivot1) { + less++; + } + while (a[great] == pivot2) { + great--; + } + for (int k = less + 1; k <= great; ) { + short ak = a[k]; + if (ak == pivot1) { + a[k++] = a[less]; + a[less++] = pivot1; + } else if (ak == pivot2) { + a[k] = a[great]; + a[great--] = pivot2; + } else { + k++; + } + } + } + + // Sort center part recursively, excluding known pivot values + doSort(a, less, great); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @param a the array to be sorted + */ + public static void sort(char[] a) { + doSort(a, 0, a.length - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(char[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + doSort(a, fromIndex, toIndex - 1); + } + + /** The number of distinct char values. */ + private static final int NUM_CHAR_VALUES = 1 << 16; + + /** + * Sorts the specified range of the array into ascending order. This + * method differs from the public {@code sort} method in that the + * {@code right} index is inclusive, and it does no range checking on + * {@code left} or {@code right}. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void doSort(char[] a, int left, int right) { + // Use insertion sort on tiny arrays + if (right - left + 1 < INSERTION_SORT_THRESHOLD) { + for (int k = left + 1; k <= right; k++) { + char ak = a[k]; + int j; + for (j = k - 1; j >= left && ak < a[j]; j--) { + a[j + 1] = a[j]; + } + a[j + 1] = ak; + } + } else if (right-left+1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { + // Use counting sort on huge arrays + int[] count = new int[NUM_CHAR_VALUES]; + + for (int i = left; i <= right; i++) { + count[a[i]]++; + } + for (int i = 0, k = left; i < count.length && k <= right; i++) { + for (int s = count[i]; s > 0; s--) { + a[k++] = (char) i; + } + } + } else { // Use Dual-Pivot Quicksort on large arrays + dualPivotQuicksort(a, left, right); + } + } + + /** + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void dualPivotQuicksort(char[] a, int left, int right) { + // Compute indices of five evenly spaced elements + int sixth = (right - left + 1) / 6; + int e1 = left + sixth; + int e5 = right - sixth; + int e3 = (left + right) >>> 1; // The midpoint + int e4 = e3 + sixth; + int e2 = e3 - sixth; + + // Sort these elements using a 5-element sorting network + char ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5]; + + if (ae1 > ae2) { char t = ae1; ae1 = ae2; ae2 = t; } + if (ae4 > ae5) { char t = ae4; ae4 = ae5; ae5 = t; } + if (ae1 > ae3) { char t = ae1; ae1 = ae3; ae3 = t; } + if (ae2 > ae3) { char t = ae2; ae2 = ae3; ae3 = t; } + if (ae1 > ae4) { char t = ae1; ae1 = ae4; ae4 = t; } + if (ae3 > ae4) { char t = ae3; ae3 = ae4; ae4 = t; } + if (ae2 > ae5) { char t = ae2; ae2 = ae5; ae5 = t; } + if (ae2 > ae3) { char t = ae2; ae2 = ae3; ae3 = t; } + if (ae4 > ae5) { char t = ae4; ae4 = ae5; ae5 = t; } + + a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; + + /* + * Use the second and fourth of the five sorted elements as pivots. + * These values are inexpensive approximations of the first and + * second terciles of the array. Note that pivot1 <= pivot2. + * + * The pivots are stored in local variables, and the first and + * the last of the sorted elements are moved to the locations + * formerly occupied by the pivots. When partitioning is complete, + * the pivots are swapped back into their final positions, and + * excluded from subsequent sorting. + */ + char pivot1 = ae2; a[e2] = a[left]; + char pivot2 = ae4; a[e4] = a[right]; + + /* + * Partitioning + * + * left part center part right part + * ------------------------------------------------------------ + * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ] + * ------------------------------------------------------------ + * ^ ^ ^ + * | | | + * less k great + */ + + // Pointers + int less = left + 1; // The index of first element of center part + int great = right - 1; // The index before first element of right part + + boolean pivotsDiffer = pivot1 != pivot2; + + if (pivotsDiffer) { + /* + * Invariants: + * all in (left, less) < pivot1 + * pivot1 <= all in [less, k) <= pivot2 + * all in (great, right) > pivot2 + * + * Pointer k is the first index of ?-part + */ + outer: + for (int k = less; k <= great; k++) { + char ak = a[k]; + if (ak < pivot1) { + if (k > less) { + a[k] = a[less]; + a[less] = ak; + } + less++; + } else if (ak > pivot2) { + while (a[great] > pivot2) { + if (k == great--) { + break outer; + } + } + a[k] = a[great]; + a[great--] = ak; + + if ((ak = a[k]) < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } else { // Pivots are equal + /* + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") partition: + * + * left part center part right part + * ------------------------------------------------- + * [ < pivot | == pivot | ? | > pivot ] + * ------------------------------------------------- + * + * ^ ^ ^ + * | | | + * less k great + * + * Invariants: + * + * all in (left, less) < pivot + * all in [less, k) == pivot + * all in (great, right) > pivot + * + * Pointer k is the first index of ?-part + */ + outer: + for (int k = less; k <= great; k++) { + char ak = a[k]; + if (ak == pivot1) { + continue; + } + if (ak < pivot1) { + if (k > less) { + a[k] = a[less]; + a[less] = ak; + } + less++; + } else { // a[k] > pivot + while (a[great] > pivot1) { + if (k == great--) { + break outer; + } + } + a[k] = a[great]; + a[great--] = ak; + + if ((ak = a[k]) < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } + + // Swap pivots into their final positions + a[left] = a[less - 1]; a[less - 1] = pivot1; + a[right] = a[great + 1]; a[great + 1] = pivot2; + + // Sort left and right parts recursively, excluding known pivot values + doSort(a, left, less - 2); + doSort(a, great + 2, right); + + /* + * If pivot1 == pivot2, all elements from center + * part are equal and, therefore, already sorted + */ + if (!pivotsDiffer) { + return; + } + + /* + * If center part is too large (comprises > 5/6 of + * the array), swap internal pivot values to ends + */ + if (less < e1 && e5 < great) { + while (a[less] == pivot1) { + less++; + } + while (a[great] == pivot2) { + great--; + } + for (int k = less + 1; k <= great; ) { + char ak = a[k]; + if (ak == pivot1) { + a[k++] = a[less]; + a[less++] = pivot1; + } else if (ak == pivot2) { + a[k] = a[great]; + a[great--] = pivot2; + } else { + k++; + } + } + } + + // Sort center part recursively, excluding known pivot values + doSort(a, less, great); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @param a the array to be sorted + */ + public static void sort(byte[] a) { + doSort(a, 0, a.length - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(byte[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + doSort(a, fromIndex, toIndex - 1); + } + + /** The number of distinct byte values. */ + private static final int NUM_BYTE_VALUES = 1 << 8; + + /** + * Sorts the specified range of the array into ascending order. This + * method differs from the public {@code sort} method in that the + * {@code right} index is inclusive, and it does no range checking on + * {@code left} or {@code right}. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void doSort(byte[] a, int left, int right) { + // Use insertion sort on tiny arrays + if (right - left + 1 < INSERTION_SORT_THRESHOLD) { + for (int k = left + 1; k <= right; k++) { + byte ak = a[k]; + int j; + for (j = k - 1; j >= left && ak < a[j]; j--) { + a[j + 1] = a[j]; + } + a[j + 1] = ak; + } + } else if (right - left + 1 > COUNTING_SORT_THRESHOLD_FOR_BYTE) { + // Use counting sort on huge arrays + int[] count = new int[NUM_BYTE_VALUES]; + + for (int i = left; i <= right; i++) { + count[a[i] - Byte.MIN_VALUE]++; + } + for (int i = 0, k = left; i < count.length && k <= right; i++) { + byte value = (byte) (i + Byte.MIN_VALUE); + + for (int s = count[i]; s > 0; s--) { + a[k++] = value; + } + } + } else { // Use Dual-Pivot Quicksort on large arrays + dualPivotQuicksort(a, left, right); + } + } + + /** + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void dualPivotQuicksort(byte[] a, int left, int right) { + // Compute indices of five evenly spaced elements + int sixth = (right - left + 1) / 6; + int e1 = left + sixth; + int e5 = right - sixth; + int e3 = (left + right) >>> 1; // The midpoint + int e4 = e3 + sixth; + int e2 = e3 - sixth; + + // Sort these elements using a 5-element sorting network + byte ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5]; + + if (ae1 > ae2) { byte t = ae1; ae1 = ae2; ae2 = t; } + if (ae4 > ae5) { byte t = ae4; ae4 = ae5; ae5 = t; } + if (ae1 > ae3) { byte t = ae1; ae1 = ae3; ae3 = t; } + if (ae2 > ae3) { byte t = ae2; ae2 = ae3; ae3 = t; } + if (ae1 > ae4) { byte t = ae1; ae1 = ae4; ae4 = t; } + if (ae3 > ae4) { byte t = ae3; ae3 = ae4; ae4 = t; } + if (ae2 > ae5) { byte t = ae2; ae2 = ae5; ae5 = t; } + if (ae2 > ae3) { byte t = ae2; ae2 = ae3; ae3 = t; } + if (ae4 > ae5) { byte t = ae4; ae4 = ae5; ae5 = t; } + + a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; + + /* + * Use the second and fourth of the five sorted elements as pivots. + * These values are inexpensive approximations of the first and + * second terciles of the array. Note that pivot1 <= pivot2. + * + * The pivots are stored in local variables, and the first and + * the last of the sorted elements are moved to the locations + * formerly occupied by the pivots. When partitioning is complete, + * the pivots are swapped back into their final positions, and + * excluded from subsequent sorting. + */ + byte pivot1 = ae2; a[e2] = a[left]; + byte pivot2 = ae4; a[e4] = a[right]; + + /* + * Partitioning + * + * left part center part right part + * ------------------------------------------------------------ + * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ] + * ------------------------------------------------------------ + * ^ ^ ^ + * | | | + * less k great + */ + + // Pointers + int less = left + 1; // The index of first element of center part + int great = right - 1; // The index before first element of right part + + boolean pivotsDiffer = pivot1 != pivot2; + + if (pivotsDiffer) { + /* + * Invariants: + * all in (left, less) < pivot1 + * pivot1 <= all in [less, k) <= pivot2 + * all in (great, right) > pivot2 + * + * Pointer k is the first index of ?-part + */ + outer: + for (int k = less; k <= great; k++) { + byte ak = a[k]; + if (ak < pivot1) { + if (k > less) { + a[k] = a[less]; + a[less] = ak; + } + less++; + } else if (ak > pivot2) { + while (a[great] > pivot2) { + if (k == great--) { + break outer; + } + } + a[k] = a[great]; + a[great--] = ak; + + if ((ak = a[k]) < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } else { // Pivots are equal + /* + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") partition: + * + * left part center part right part + * ------------------------------------------------- + * [ < pivot | == pivot | ? | > pivot ] + * ------------------------------------------------- + * + * ^ ^ ^ + * | | | + * less k great + * + * Invariants: + * + * all in (left, less) < pivot + * all in [less, k) == pivot + * all in (great, right) > pivot + * + * Pointer k is the first index of ?-part + */ + outer: + for (int k = less; k <= great; k++) { + byte ak = a[k]; + if (ak == pivot1) { + continue; + } + if (ak < pivot1) { + if (k > less) { + a[k] = a[less]; + a[less] = ak; + } + less++; + } else { // a[k] > pivot + while (a[great] > pivot1) { + if (k == great--) { + break outer; + } + } + a[k] = a[great]; + a[great--] = ak; + + if ((ak = a[k]) < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } + + // Swap pivots into their final positions + a[left] = a[less - 1]; a[less - 1] = pivot1; + a[right] = a[great + 1]; a[great + 1] = pivot2; + + // Sort left and right parts recursively, excluding known pivot values + doSort(a, left, less - 2); + doSort(a, great + 2, right); + + /* + * If pivot1 == pivot2, all elements from center + * part are equal and, therefore, already sorted + */ + if (!pivotsDiffer) { + return; + } + + /* + * If center part is too large (comprises > 5/6 of + * the array), swap internal pivot values to ends + */ + if (less < e1 && e5 < great) { + while (a[less] == pivot1) { + less++; + } + while (a[great] == pivot2) { + great--; + } + for (int k = less + 1; k <= great; ) { + byte ak = a[k]; + if (ak == pivot1) { + a[k++] = a[less]; + a[less++] = pivot1; + } else if (ak == pivot2) { + a[k] = a[great]; + a[great--] = pivot2; + } else { + k++; + } + } + } + + // Sort center part recursively, excluding known pivot values + doSort(a, less, great); + } + + /** + * Sorts the specified array into ascending numerical order. + * + *

The {@code <} relation does not provide a total order on all float + * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Float#compareTo}: {@code -0.0f} is treated as less than value + * {@code 0.0f} and {@code Float.NaN} is considered greater than any + * other value and all {@code Float.NaN} values are considered equal. + * + * @param a the array to be sorted + */ + public static void sort(float[] a) { + sortNegZeroAndNaN(a, 0, a.length - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + *

The {@code <} relation does not provide a total order on all float + * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Float#compareTo}: {@code -0.0f} is treated as less than value + * {@code 0.0f} and {@code Float.NaN} is considered greater than any + * other value and all {@code Float.NaN} values are considered equal. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(float[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + sortNegZeroAndNaN(a, fromIndex, toIndex - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The + * sort is done in three phases to avoid expensive comparisons in the + * inner loop. The comparisons would be expensive due to anomalies + * associated with negative zero {@code -0.0f} and {@code Float.NaN}. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void sortNegZeroAndNaN(float[] a, int left, int right) { + /* + * Phase 1: Count negative zeros and move NaNs to end of array + */ + final int NEGATIVE_ZERO = Float.floatToIntBits(-0.0f); + int numNegativeZeros = 0; + int n = right; + + for (int k = left; k <= n; k++) { + float ak = a[k]; + if (ak == 0.0f && NEGATIVE_ZERO == Float.floatToIntBits(ak)) { + a[k] = 0.0f; + numNegativeZeros++; + } else if (ak != ak) { // i.e., ak is NaN + a[k--] = a[n]; + a[n--] = Float.NaN; + } + } + + /* + * Phase 2: Sort everything except NaNs (which are already in place) + */ + doSort(a, left, n); + + /* + * Phase 3: Turn positive zeros back into negative zeros as appropriate + */ + if (numNegativeZeros == 0) { + return; + } + + // Find first zero element + int zeroIndex = findAnyZero(a, left, n); + + for (int i = zeroIndex - 1; i >= left && a[i] == 0.0f; i--) { + zeroIndex = i; + } + + // Turn the right number of positive zeros back into negative zeros + for (int i = zeroIndex, m = zeroIndex + numNegativeZeros; i < m; i++) { + a[i] = -0.0f; + } + } + + /** + * Returns the index of some zero element in the specified range via + * binary search. The range is assumed to be sorted, and must contain + * at least one zero. + * + * @param a the array to be searched + * @param low the index of the first element, inclusive, to be searched + * @param high the index of the last element, inclusive, to be searched + */ + private static int findAnyZero(float[] a, int low, int high) { + while (true) { + int middle = (low + high) >>> 1; + float middleValue = a[middle]; + + if (middleValue < 0.0f) { + low = middle + 1; + } else if (middleValue > 0.0f) { + high = middle - 1; + } else { // middleValue == 0.0f + return middle; + } + } + } + + /** + * Sorts the specified range of the array into ascending order. This + * method differs from the public {@code sort} method in three ways: + * {@code right} index is inclusive, it does no range checking on + * {@code left} or {@code right}, and it does not handle negative + * zeros or NaNs in the array. + * + * @param a the array to be sorted, which must not contain -0.0f or NaN + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void doSort(float[] a, int left, int right) { + // Use insertion sort on tiny arrays + if (right - left + 1 < INSERTION_SORT_THRESHOLD) { + for (int k = left + 1; k <= right; k++) { + float ak = a[k]; + int j; + for (j = k - 1; j >= left && ak < a[j]; j--) { + a[j + 1] = a[j]; + } + a[j + 1] = ak; + } + } else { // Use Dual-Pivot Quicksort on large arrays + dualPivotQuicksort(a, left, right); + } + } + + /** + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void dualPivotQuicksort(float[] a, int left, int right) { + // Compute indices of five evenly spaced elements + int sixth = (right - left + 1) / 6; + int e1 = left + sixth; + int e5 = right - sixth; + int e3 = (left + right) >>> 1; // The midpoint + int e4 = e3 + sixth; + int e2 = e3 - sixth; + + // Sort these elements using a 5-element sorting network + float ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5]; + + if (ae1 > ae2) { float t = ae1; ae1 = ae2; ae2 = t; } + if (ae4 > ae5) { float t = ae4; ae4 = ae5; ae5 = t; } + if (ae1 > ae3) { float t = ae1; ae1 = ae3; ae3 = t; } + if (ae2 > ae3) { float t = ae2; ae2 = ae3; ae3 = t; } + if (ae1 > ae4) { float t = ae1; ae1 = ae4; ae4 = t; } + if (ae3 > ae4) { float t = ae3; ae3 = ae4; ae4 = t; } + if (ae2 > ae5) { float t = ae2; ae2 = ae5; ae5 = t; } + if (ae2 > ae3) { float t = ae2; ae2 = ae3; ae3 = t; } + if (ae4 > ae5) { float t = ae4; ae4 = ae5; ae5 = t; } + + a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; + + /* + * Use the second and fourth of the five sorted elements as pivots. + * These values are inexpensive approximations of the first and + * second terciles of the array. Note that pivot1 <= pivot2. + * + * The pivots are stored in local variables, and the first and + * the last of the sorted elements are moved to the locations + * formerly occupied by the pivots. When partitioning is complete, + * the pivots are swapped back into their final positions, and + * excluded from subsequent sorting. + */ + float pivot1 = ae2; a[e2] = a[left]; + float pivot2 = ae4; a[e4] = a[right]; + + /* + * Partitioning + * + * left part center part right part + * ------------------------------------------------------------ + * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ] + * ------------------------------------------------------------ + * ^ ^ ^ + * | | | + * less k great + */ + + // Pointers + int less = left + 1; // The index of first element of center part + int great = right - 1; // The index before first element of right part + + boolean pivotsDiffer = pivot1 != pivot2; + + if (pivotsDiffer) { + /* + * Invariants: + * all in (left, less) < pivot1 + * pivot1 <= all in [less, k) <= pivot2 + * all in (great, right) > pivot2 + * + * Pointer k is the first index of ?-part + */ + outer: + for (int k = less; k <= great; k++) { + float ak = a[k]; + if (ak < pivot1) { + if (k > less) { + a[k] = a[less]; + a[less] = ak; + } + less++; + } else if (ak > pivot2) { + while (a[great] > pivot2) { + if (k == great--) { + break outer; + } + } + a[k] = a[great]; + a[great--] = ak; + + if ((ak = a[k]) < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } else { // Pivots are equal + /* + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") partition: + * + * left part center part right part + * ------------------------------------------------- + * [ < pivot | == pivot | ? | > pivot ] + * ------------------------------------------------- + * + * ^ ^ ^ + * | | | + * less k great + * + * Invariants: + * + * all in (left, less) < pivot + * all in [less, k) == pivot + * all in (great, right) > pivot + * + * Pointer k is the first index of ?-part + */ + outer: + for (int k = less; k <= great; k++) { + float ak = a[k]; + if (ak == pivot1) { + continue; + } + if (ak < pivot1) { + if (k > less) { + a[k] = a[less]; + a[less] = ak; + } + less++; + } else { // a[k] > pivot + while (a[great] > pivot1) { + if (k == great--) { + break outer; + } + } + a[k] = a[great]; + a[great--] = ak; + + if ((ak = a[k]) < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } + + // Swap pivots into their final positions + a[left] = a[less - 1]; a[less - 1] = pivot1; + a[right] = a[great + 1]; a[great + 1] = pivot2; + + // Sort left and right parts recursively, excluding known pivot values + doSort(a, left, less - 2); + doSort(a, great + 2, right); + + /* + * If pivot1 == pivot2, all elements from center + * part are equal and, therefore, already sorted + */ + if (!pivotsDiffer) { + return; + } + + /* + * If center part is too large (comprises > 5/6 of + * the array), swap internal pivot values to ends + */ + if (less < e1 && e5 < great) { + while (a[less] == pivot1) { + less++; + } + while (a[great] == pivot2) { + great--; + } + for (int k = less + 1; k <= great; ) { + float ak = a[k]; + if (ak == pivot1) { + a[k++] = a[less]; + a[less++] = pivot1; + } else if (ak == pivot2) { + a[k] = a[great]; + a[great--] = pivot2; + } else { + k++; + } + } + } + + // Sort center part recursively, excluding known pivot values + doSort(a, less, great); + } + + /** + * Sorts the specified array into ascending numerical order. + * + *

The {@code <} relation does not provide a total order on all double + * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Double#compareTo}: {@code -0.0d} is treated as less than value + * {@code 0.0d} and {@code Double.NaN} is considered greater than any + * other value and all {@code Double.NaN} values are considered equal. + * + * @param a the array to be sorted + */ + public static void sort(double[] a) { + sortNegZeroAndNaN(a, 0, a.length - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + *

The {@code <} relation does not provide a total order on all double + * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Double#compareTo}: {@code -0.0d} is treated as less than value + * {@code 0.0d} and {@code Double.NaN} is considered greater than any + * other value and all {@code Double.NaN} values are considered equal. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(double[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + sortNegZeroAndNaN(a, fromIndex, toIndex - 1); + } + + /** + * Sorts the specified range of the array into ascending order. The + * sort is done in three phases to avoid expensive comparisons in the + * inner loop. The comparisons would be expensive due to anomalies + * associated with negative zero {@code -0.0d} and {@code Double.NaN}. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void sortNegZeroAndNaN(double[] a, int left, int right) { + /* + * Phase 1: Count negative zeros and move NaNs to end of array + */ + final long NEGATIVE_ZERO = Double.doubleToLongBits(-0.0d); + int numNegativeZeros = 0; + int n = right; + + for (int k = left; k <= n; k++) { + double ak = a[k]; + if (ak == 0.0d && NEGATIVE_ZERO == Double.doubleToLongBits(ak)) { + a[k] = 0.0d; + numNegativeZeros++; + } else if (ak != ak) { // i.e., ak is NaN + a[k--] = a[n]; + a[n--] = Double.NaN; + } + } + + /* + * Phase 2: Sort everything except NaNs (which are already in place) + */ + doSort(a, left, n); + + /* + * Phase 3: Turn positive zeros back into negative zeros as appropriate + */ + if (numNegativeZeros == 0) { + return; + } + + // Find first zero element + int zeroIndex = findAnyZero(a, left, n); + + for (int i = zeroIndex - 1; i >= left && a[i] == 0.0d; i--) { + zeroIndex = i; + } + + // Turn the right number of positive zeros back into negative zeros + for (int i = zeroIndex, m = zeroIndex + numNegativeZeros; i < m; i++) { + a[i] = -0.0d; + } + } + + /** + * Returns the index of some zero element in the specified range via + * binary search. The range is assumed to be sorted, and must contain + * at least one zero. + * + * @param a the array to be searched + * @param low the index of the first element, inclusive, to be searched + * @param high the index of the last element, inclusive, to be searched + */ + private static int findAnyZero(double[] a, int low, int high) { + while (true) { + int middle = (low + high) >>> 1; + double middleValue = a[middle]; + + if (middleValue < 0.0d) { + low = middle + 1; + } else if (middleValue > 0.0d) { + high = middle - 1; + } else { // middleValue == 0.0d + return middle; + } + } + } + + /** + * Sorts the specified range of the array into ascending order. This + * method differs from the public {@code sort} method in three ways: + * {@code right} index is inclusive, it does no range checking on + * {@code left} or {@code right}, and it does not handle negative + * zeros or NaNs in the array. + * + * @param a the array to be sorted, which must not contain -0.0d and NaN + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void doSort(double[] a, int left, int right) { + // Use insertion sort on tiny arrays + if (right - left + 1 < INSERTION_SORT_THRESHOLD) { + for (int k = left + 1; k <= right; k++) { + double ak = a[k]; + int j; + for (j = k - 1; j >= left && ak < a[j]; j--) { + a[j + 1] = a[j]; + } + a[j + 1] = ak; + } + } else { // Use Dual-Pivot Quicksort on large arrays + dualPivotQuicksort(a, left, right); + } + } + + /** + * Sorts the specified range of the array into ascending order by the + * Dual-Pivot Quicksort algorithm. + * + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + private static void dualPivotQuicksort(double[] a, int left, int right) { + // Compute indices of five evenly spaced elements + int sixth = (right - left + 1) / 6; + int e1 = left + sixth; + int e5 = right - sixth; + int e3 = (left + right) >>> 1; // The midpoint + int e4 = e3 + sixth; + int e2 = e3 - sixth; + + // Sort these elements using a 5-element sorting network + double ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5]; + + if (ae1 > ae2) { double t = ae1; ae1 = ae2; ae2 = t; } + if (ae4 > ae5) { double t = ae4; ae4 = ae5; ae5 = t; } + if (ae1 > ae3) { double t = ae1; ae1 = ae3; ae3 = t; } + if (ae2 > ae3) { double t = ae2; ae2 = ae3; ae3 = t; } + if (ae1 > ae4) { double t = ae1; ae1 = ae4; ae4 = t; } + if (ae3 > ae4) { double t = ae3; ae3 = ae4; ae4 = t; } + if (ae2 > ae5) { double t = ae2; ae2 = ae5; ae5 = t; } + if (ae2 > ae3) { double t = ae2; ae2 = ae3; ae3 = t; } + if (ae4 > ae5) { double t = ae4; ae4 = ae5; ae5 = t; } + + a[e1] = ae1; a[e3] = ae3; a[e5] = ae5; + + /* + * Use the second and fourth of the five sorted elements as pivots. + * These values are inexpensive approximations of the first and + * second terciles of the array. Note that pivot1 <= pivot2. + * + * The pivots are stored in local variables, and the first and + * the last of the sorted elements are moved to the locations + * formerly occupied by the pivots. When partitioning is complete, + * the pivots are swapped back into their final positions, and + * excluded from subsequent sorting. + */ + double pivot1 = ae2; a[e2] = a[left]; + double pivot2 = ae4; a[e4] = a[right]; + + /* + * Partitioning + * + * left part center part right part + * ------------------------------------------------------------ + * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ] + * ------------------------------------------------------------ + * ^ ^ ^ + * | | | + * less k great + */ + + // Pointers + int less = left + 1; // The index of first element of center part + int great = right - 1; // The index before first element of right part + + boolean pivotsDiffer = pivot1 != pivot2; + + if (pivotsDiffer) { + /* + * Invariants: + * all in (left, less) < pivot1 + * pivot1 <= all in [less, k) <= pivot2 + * all in (great, right) > pivot2 + * + * Pointer k is the first index of ?-part + */ + outer: + for (int k = less; k <= great; k++) { + double ak = a[k]; + if (ak < pivot1) { + if (k > less) { + a[k] = a[less]; + a[less] = ak; + } + less++; + } else if (ak > pivot2) { + while (a[great] > pivot2) { + if (k == great--) { + break outer; + } + } + a[k] = a[great]; + a[great--] = ak; + + if ((ak = a[k]) < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } else { // Pivots are equal + /* + * Partition degenerates to the traditional 3-way + * (or "Dutch National Flag") partition: + * + * left part center part right part + * ------------------------------------------------- + * [ < pivot | == pivot | ? | > pivot ] + * ------------------------------------------------- + * + * ^ ^ ^ + * | | | + * less k great + * + * Invariants: + * + * all in (left, less) < pivot + * all in [less, k) == pivot + * all in (great, right) > pivot + * + * Pointer k is the first index of ?-part + */ + outer: + for (int k = less; k <= great; k++) { + double ak = a[k]; + if (ak == pivot1) { + continue; + } + if (ak < pivot1) { + if (k > less) { + a[k] = a[less]; + a[less] = ak; + } + less++; + } else { // a[k] > pivot + while (a[great] > pivot1) { + if (k == great--) { + break outer; + } + } + a[k] = a[great]; + a[great--] = ak; + + if ((ak = a[k]) < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } + } + } + } + + // Swap pivots into their final positions + a[left] = a[less - 1]; a[less - 1] = pivot1; + a[right] = a[great + 1]; a[great + 1] = pivot2; + + // Sort left and right parts recursively, excluding known pivot values + doSort(a, left, less - 2); + doSort(a, great + 2, right); + + /* + * If pivot1 == pivot2, all elements from center + * part are equal and, therefore, already sorted + */ + if (!pivotsDiffer) { + return; + } + + /* + * If center part is too large (comprises > 5/6 of + * the array), swap internal pivot values to ends + */ + if (less < e1 && e5 < great) { + while (a[less] == pivot1) { + less++; + } + while (a[great] == pivot2) { + great--; + } + for (int k = less + 1; k <= great; ) { + double ak = a[k]; + if (ak == pivot1) { + a[k++] = a[less]; + a[less++] = pivot1; + } else if (ak == pivot2) { + a[k] = a[great]; + a[great--] = pivot2; + } else { + k++; + } + } + } + + // Sort center part recursively, excluding known pivot values + doSort(a, less, great); + } + + /** + * Checks that {@code fromIndex} and {@code toIndex} are in + * the range and throws an appropriate exception, if they aren't. + */ + private static void rangeCheck(int length, int fromIndex, int toIndex) { + if (fromIndex > toIndex) { + throw new IllegalArgumentException( + "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); + } + if (fromIndex < 0) { + throw new ArrayIndexOutOfBoundsException(fromIndex); + } + if (toIndex > length) { + throw new ArrayIndexOutOfBoundsException(toIndex); + } + } +} diff --git a/jdk/src/share/classes/java/util/Formatter.java b/jdk/src/share/classes/java/util/Formatter.java index 027e36dcc81..59ff1da0711 100644 --- a/jdk/src/share/classes/java/util/Formatter.java +++ b/jdk/src/share/classes/java/util/Formatter.java @@ -2485,55 +2485,45 @@ public final class Formatter implements Closeable, Flushable { private static Pattern fsPattern = Pattern.compile(formatSpecifier); - // Look for format specifiers in the format string. + /** + * Finds format specifiers in the format string. + */ private FormatString[] parse(String s) { - ArrayList al = new ArrayList(); + ArrayList al = new ArrayList(); Matcher m = fsPattern.matcher(s); - int i = 0; - while (i < s.length()) { + for (int i = 0, len = s.length(); i < len; ) { if (m.find(i)) { // Anything between the start of the string and the beginning // of the format specifier is either fixed text or contains // an invalid format string. if (m.start() != i) { // Make sure we didn't miss any invalid format specifiers - checkText(s.substring(i, m.start())); + checkText(s, i, m.start()); // Assume previous characters were fixed text al.add(new FixedString(s.substring(i, m.start()))); } - // Expect 6 groups in regular expression - String[] sa = new String[6]; - for (int j = 0; j < m.groupCount(); j++) - { - sa[j] = m.group(j + 1); -// System.out.print(sa[j] + " "); - } -// System.out.println(); - al.add(new FormatSpecifier(this, sa)); + al.add(new FormatSpecifier(m)); i = m.end(); } else { // No more valid format specifiers. Check for possible invalid // format specifiers. - checkText(s.substring(i)); + checkText(s, i, len); // The rest of the string is fixed text al.add(new FixedString(s.substring(i))); break; } } -// FormatString[] fs = new FormatString[al.size()]; -// for (int j = 0; j < al.size(); j++) -// System.out.println(((FormatString) al.get(j)).toString()); - return (FormatString[]) al.toArray(new FormatString[0]); + return al.toArray(new FormatString[al.size()]); } - private void checkText(String s) { - int idx; - // If there are any '%' in the given string, we got a bad format - // specifier. - if ((idx = s.indexOf('%')) != -1) { - char c = (idx > s.length() - 2 ? '%' : s.charAt(idx + 1)); - throw new UnknownFormatConversionException(String.valueOf(c)); + private static void checkText(String s, int start, int end) { + for (int i = start; i < end; i++) { + // Any '%' found in the region starts an invalid format specifier. + if (s.charAt(i) == '%') { + char c = (i == end - 1) ? '%' : s.charAt(i + 1); + throw new UnknownFormatConversionException(String.valueOf(c)); + } } } @@ -2562,8 +2552,6 @@ public final class Formatter implements Closeable, Flushable { private boolean dt = false; private char c; - private Formatter formatter; - // cache the line separator private String ls; @@ -2650,21 +2638,22 @@ public final class Formatter implements Closeable, Flushable { return c; } - FormatSpecifier(Formatter formatter, String[] sa) { - this.formatter = formatter; - int idx = 0; + FormatSpecifier(Matcher m) { + int idx = 1; - index(sa[idx++]); - flags(sa[idx++]); - width(sa[idx++]); - precision(sa[idx++]); + index(m.group(idx++)); + flags(m.group(idx++)); + width(m.group(idx++)); + precision(m.group(idx++)); - if (sa[idx] != null) { + String tT = m.group(idx++); + if (tT != null) { dt = true; - if (sa[idx].equals("T")) + if (tT.equals("T")) f.add(Flags.UPPERCASE); } - conversion(sa[++idx]); + + conversion(m.group(idx)); if (dt) checkDateTime(); @@ -2819,9 +2808,9 @@ public final class Formatter implements Closeable, Flushable { private void printString(Object arg, Locale l) throws IOException { if (arg instanceof Formattable) { - Formatter fmt = formatter; - if (formatter.locale() != l) - fmt = new Formatter(formatter.out(), l); + Formatter fmt = Formatter.this; + if (fmt.locale() != l) + fmt = new Formatter(fmt.out(), l); ((Formattable)arg).formatTo(fmt, f.valueOf(), width, precision); } else { if (f.contains(Flags.ALTERNATE)) diff --git a/jdk/src/share/classes/java/util/LinkedList.java b/jdk/src/share/classes/java/util/LinkedList.java index 6b7636c8f81..24f465179e2 100644 --- a/jdk/src/share/classes/java/util/LinkedList.java +++ b/jdk/src/share/classes/java/util/LinkedList.java @@ -26,22 +26,22 @@ package java.util; /** - * Linked list implementation of the List interface. Implements all + * Linked list implementation of the {@code List} interface. Implements all * optional list operations, and permits all elements (including - * null). In addition to implementing the List interface, - * the LinkedList class provides uniformly named methods to - * get, remove and insert an element at the + * {@code null}). In addition to implementing the {@code List} interface, + * the {@code LinkedList} class provides uniformly named methods to + * {@code get}, {@code remove} and {@code insert} an element at the * beginning and end of the list. These operations allow linked lists to be * used as a stack, {@linkplain Queue queue}, or {@linkplain Deque - * double-ended queue}.

+ * double-ended queue}. * - * The class implements the Deque interface, providing - * first-in-first-out queue operations for add, - * poll, along with other stack and deque operations.

+ *

The class implements the {@code Deque} interface, providing + * first-in-first-out queue operations for {@code add}, + * {@code poll}, along with other stack and deque operations. * - * All of the operations perform as could be expected for a doubly-linked + *

All of the operations perform as could be expected for a doubly-linked * list. Operations that index into the list will traverse the list from - * the beginning or the end, whichever is closer to the specified index.

+ * the beginning or the end, whichever is closer to the specified index. * *

Note that this implementation is not synchronized. * If multiple threads access a linked list concurrently, and at least @@ -58,11 +58,11 @@ package java.util; * unsynchronized access to the list:

  *   List list = Collections.synchronizedList(new LinkedList(...));
* - *

The iterators returned by this class's iterator and - * listIterator methods are fail-fast: if the list is + *

The iterators returned by this class's {@code iterator} and + * {@code listIterator} methods are fail-fast: if the list is * structurally modified at any time after the iterator is created, in - * any way except through the Iterator's own remove or - * add methods, the iterator will throw a {@link + * any way except through the Iterator's own {@code remove} or + * {@code add} methods, the iterator will throw a {@link * ConcurrentModificationException}. Thus, in the face of concurrent * modification, the iterator fails quickly and cleanly, rather than * risking arbitrary, non-deterministic behavior at an undetermined @@ -71,7 +71,7 @@ package java.util; *

Note that the fail-fast behavior of an iterator cannot be guaranteed * as it is, generally speaking, impossible to make any hard guarantees in the * presence of unsynchronized concurrent modification. Fail-fast iterators - * throw ConcurrentModificationException on a best-effort basis. + * throw {@code ConcurrentModificationException} on a best-effort basis. * Therefore, it would be wrong to write a program that depended on this * exception for its correctness: the fail-fast behavior of iterators * should be used only to detect bugs. @@ -83,7 +83,6 @@ package java.util; * @author Josh Bloch * @see List * @see ArrayList - * @see Vector * @since 1.2 * @param the type of elements held in this collection */ @@ -92,14 +91,26 @@ public class LinkedList extends AbstractSequentialList implements List, Deque, Cloneable, java.io.Serializable { - private transient Entry header = new Entry(null, null, null); - private transient int size = 0; + transient int size = 0; + + /** + * Pointer to first node. + * Invariant: (first == null && last == null) || + * (first.prev == null && first.item != null) + */ + transient Node first; + + /** + * Pointer to last node. + * Invariant: (first == null && last == null) || + * (last.next == null && last.item != null) + */ + transient Node last; /** * Constructs an empty list. */ public LinkedList() { - header.next = header.previous = header; } /** @@ -115,6 +126,119 @@ public class LinkedList addAll(c); } + /** + * Links e as first element. + */ + private void linkFirst(E e) { + final Node f = first; + final Node newNode = new Node(null, e, f); + first = newNode; + if (f == null) + last = newNode; + else + f.prev = newNode; + size++; + modCount++; + } + + /** + * Links e as last element. + */ + void linkLast(E e) { + final Node l = last; + final Node newNode = new Node(l, e, null); + last = newNode; + if (l == null) + first = newNode; + else + l.next = newNode; + size++; + modCount++; + } + + /** + * Inserts element e before non-null Node succ. + */ + void linkBefore(E e, Node succ) { + // assert succ != null; + final Node pred = succ.prev; + final Node newNode = new Node(pred, e, succ); + succ.prev = newNode; + if (pred == null) + first = newNode; + else + pred.next = newNode; + size++; + modCount++; + } + + /** + * Unlinks non-null first node f. + */ + private E unlinkFirst(Node f) { + // assert f == first && f != null; + final E element = f.item; + final Node next = f.next; + f.item = null; + f.next = null; // help GC + first = next; + if (next == null) + last = null; + else + next.prev = null; + size--; + modCount++; + return element; + } + + /** + * Unlinks non-null last node l. + */ + private E unlinkLast(Node l) { + // assert l == last && l != null; + final E element = l.item; + final Node prev = l.prev; + l.item = null; + l.prev = null; // help GC + last = prev; + if (prev == null) + first = null; + else + prev.next = null; + size--; + modCount++; + return element; + } + + /** + * Unlinks non-null node x. + */ + E unlink(Node x) { + // assert x != null; + final E element = x.item; + final Node next = x.next; + final Node prev = x.prev; + + if (prev == null) { + first = next; + } else { + prev.next = next; + x.prev = null; + } + + if (next == null) { + last = prev; + } else { + next.prev = prev; + x.next = null; + } + + x.item = null; + size--; + modCount++; + return element; + } + /** * Returns the first element in this list. * @@ -122,10 +246,10 @@ public class LinkedList * @throws NoSuchElementException if this list is empty */ public E getFirst() { - if (size==0) + final Node f = first; + if (f == null) throw new NoSuchElementException(); - - return header.next.element; + return f.item; } /** @@ -135,10 +259,10 @@ public class LinkedList * @throws NoSuchElementException if this list is empty */ public E getLast() { - if (size==0) + final Node l = last; + if (l == null) throw new NoSuchElementException(); - - return header.previous.element; + return l.item; } /** @@ -148,7 +272,10 @@ public class LinkedList * @throws NoSuchElementException if this list is empty */ public E removeFirst() { - return remove(header.next); + final Node f = first; + if (f == null) + throw new NoSuchElementException(); + return unlinkFirst(f); } /** @@ -158,7 +285,10 @@ public class LinkedList * @throws NoSuchElementException if this list is empty */ public E removeLast() { - return remove(header.previous); + final Node l = last; + if (l == null) + throw new NoSuchElementException(); + return unlinkLast(l); } /** @@ -167,7 +297,7 @@ public class LinkedList * @param e the element to add */ public void addFirst(E e) { - addBefore(e, header.next); + linkFirst(e); } /** @@ -178,17 +308,17 @@ public class LinkedList * @param e the element to add */ public void addLast(E e) { - addBefore(e, header); + linkLast(e); } /** - * Returns true if this list contains the specified element. - * More formally, returns true if and only if this list contains - * at least one element e such that + * Returns {@code true} if this list contains the specified element. + * More formally, returns {@code true} if and only if this list contains + * at least one element {@code e} such that * (o==null ? e==null : o.equals(e)). * * @param o element whose presence in this list is to be tested - * @return true if this list contains the specified element + * @return {@code true} if this list contains the specified element */ public boolean contains(Object o) { return indexOf(o) != -1; @@ -209,10 +339,10 @@ public class LinkedList *

This method is equivalent to {@link #addLast}. * * @param e element to be appended to this list - * @return true (as specified by {@link Collection#add}) + * @return {@code true} (as specified by {@link Collection#add}) */ public boolean add(E e) { - addBefore(e, header); + linkLast(e); return true; } @@ -220,27 +350,27 @@ public class LinkedList * Removes the first occurrence of the specified element from this list, * if it is present. If this list does not contain the element, it is * unchanged. More formally, removes the element with the lowest index - * i such that + * {@code i} such that * (o==null ? get(i)==null : o.equals(get(i))) - * (if such an element exists). Returns true if this list + * (if such an element exists). Returns {@code true} if this list * contained the specified element (or equivalently, if this list * changed as a result of the call). * * @param o element to be removed from this list, if present - * @return true if this list contained the specified element + * @return {@code true} if this list contained the specified element */ public boolean remove(Object o) { - if (o==null) { - for (Entry e = header.next; e != header; e = e.next) { - if (e.element==null) { - remove(e); + if (o == null) { + for (Node x = first; x != null; x = x.next) { + if (x.item == null) { + unlink(x); return true; } } } else { - for (Entry e = header.next; e != header; e = e.next) { - if (o.equals(e.element)) { - remove(e); + for (Node x = first; x != null; x = x.next) { + if (o.equals(x.item)) { + unlink(x); return true; } } @@ -257,7 +387,7 @@ public class LinkedList * this list, and it's nonempty.) * * @param c collection containing elements to be added to this list - * @return true if this list changed as a result of the call + * @return {@code true} if this list changed as a result of the call * @throws NullPointerException if the specified collection is null */ public boolean addAll(Collection c) { @@ -275,45 +405,66 @@ public class LinkedList * @param index index at which to insert the first element * from the specified collection * @param c collection containing elements to be added to this list - * @return true if this list changed as a result of the call + * @return {@code true} if this list changed as a result of the call * @throws IndexOutOfBoundsException {@inheritDoc} * @throws NullPointerException if the specified collection is null */ public boolean addAll(int index, Collection c) { - if (index < 0 || index > size) - throw new IndexOutOfBoundsException("Index: "+index+ - ", Size: "+size); + checkPositionIndex(index); + Object[] a = c.toArray(); int numNew = a.length; - if (numNew==0) + if (numNew == 0) return false; - modCount++; - Entry successor = (index==size ? header : entry(index)); - Entry predecessor = successor.previous; - for (int i=0; i e = new Entry((E)a[i], successor, predecessor); - predecessor.next = e; - predecessor = e; + Node pred, succ; + if (index == size) { + succ = null; + pred = last; + } else { + succ = node(index); + pred = succ.prev; + } + + for (Object o : a) { + @SuppressWarnings("unchecked") E e = (E) o; + Node newNode = new Node(pred, e, null); + if (pred == null) + first = newNode; + else + pred.next = newNode; + pred = newNode; + } + + if (succ == null) { + last = pred; + } else { + pred.next = succ; + succ.prev = pred; } - successor.previous = predecessor; size += numNew; + modCount++; return true; } /** * Removes all of the elements from this list. + * The list will be empty after this call returns. */ public void clear() { - Entry e = header.next; - while (e != header) { - Entry next = e.next; - e.next = e.previous = null; - e.element = null; - e = next; + // Clearing all of the links between nodes is "unnecessary", but: + // - helps a generational GC if the discarded nodes inhabit + // more than one generation + // - is sure to free memory even if there is a reachable Iterator + for (Node x = first; x != null; ) { + Node next = x.next; + x.item = null; + x.next = null; + x.prev = null; + x = next; } - header.next = header.previous = header; + first = last = null; size = 0; modCount++; } @@ -329,7 +480,8 @@ public class LinkedList * @throws IndexOutOfBoundsException {@inheritDoc} */ public E get(int index) { - return entry(index).element; + checkElementIndex(index); + return node(index).item; } /** @@ -342,9 +494,10 @@ public class LinkedList * @throws IndexOutOfBoundsException {@inheritDoc} */ public E set(int index, E element) { - Entry e = entry(index); - E oldVal = e.element; - e.element = element; + checkElementIndex(index); + Node x = node(index); + E oldVal = x.item; + x.item = element; return oldVal; } @@ -358,7 +511,12 @@ public class LinkedList * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { - addBefore(element, (index==size ? header : entry(index))); + checkPositionIndex(index); + + if (index == size) + linkLast(element); + else + linkBefore(element, node(index)); } /** @@ -371,34 +529,69 @@ public class LinkedList * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { - return remove(entry(index)); + checkElementIndex(index); + return unlink(node(index)); } /** - * Returns the indexed entry. + * Tells if the argument is the index of an existing element. */ - private Entry entry(int index) { - if (index < 0 || index >= size) - throw new IndexOutOfBoundsException("Index: "+index+ - ", Size: "+size); - Entry e = header; - if (index < (size >> 1)) { - for (int i = 0; i <= index; i++) - e = e.next; - } else { - for (int i = size; i > index; i--) - e = e.previous; - } - return e; + private boolean isElementIndex(int index) { + return index >= 0 && index < size; } + /** + * Tells if the argument is the index of a valid position for an + * iterator or an add operation. + */ + private boolean isPositionIndex(int index) { + return index >= 0 && index <= size; + } + + /** + * Constructs an IndexOutOfBoundsException detail message. + * Of the many possible refactorings of the error handling code, + * this "outlining" performs best with both server and client VMs. + */ + private String outOfBoundsMsg(int index) { + return "Index: "+index+", Size: "+size; + } + + private void checkElementIndex(int index) { + if (!isElementIndex(index)) + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + + private void checkPositionIndex(int index) { + if (!isPositionIndex(index)) + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } + + /** + * Returns the (non-null) Node at the specified element index. + */ + Node node(int index) { + // assert isElementIndex(index); + + if (index < (size >> 1)) { + Node x = first; + for (int i = 0; i < index; i++) + x = x.next; + return x; + } else { + Node x = last; + for (int i = size - 1; i > index; i--) + x = x.prev; + return x; + } + } // Search Operations /** * Returns the index of the first occurrence of the specified element * in this list, or -1 if this list does not contain the element. - * More formally, returns the lowest index i such that + * More formally, returns the lowest index {@code i} such that * (o==null ? get(i)==null : o.equals(get(i))), * or -1 if there is no such index. * @@ -408,15 +601,15 @@ public class LinkedList */ public int indexOf(Object o) { int index = 0; - if (o==null) { - for (Entry e = header.next; e != header; e = e.next) { - if (e.element==null) + if (o == null) { + for (Node x = first; x != null; x = x.next) { + if (x.item == null) return index; index++; } } else { - for (Entry e = header.next; e != header; e = e.next) { - if (o.equals(e.element)) + for (Node x = first; x != null; x = x.next) { + if (o.equals(x.item)) return index; index++; } @@ -427,7 +620,7 @@ public class LinkedList /** * Returns the index of the last occurrence of the specified element * in this list, or -1 if this list does not contain the element. - * More formally, returns the highest index i such that + * More formally, returns the highest index {@code i} such that * (o==null ? get(i)==null : o.equals(get(i))), * or -1 if there is no such index. * @@ -437,16 +630,16 @@ public class LinkedList */ public int lastIndexOf(Object o) { int index = size; - if (o==null) { - for (Entry e = header.previous; e != header; e = e.previous) { + if (o == null) { + for (Node x = last; x != null; x = x.prev) { index--; - if (e.element==null) + if (x.item == null) return index; } } else { - for (Entry e = header.previous; e != header; e = e.previous) { + for (Node x = last; x != null; x = x.prev) { index--; - if (o.equals(e.element)) + if (o.equals(x.item)) return index; } } @@ -457,17 +650,18 @@ public class LinkedList /** * Retrieves, but does not remove, the head (first element) of this list. - * @return the head of this list, or null if this list is empty + * + * @return the head of this list, or {@code null} if this list is empty * @since 1.5 */ public E peek() { - if (size==0) - return null; - return getFirst(); + final Node f = first; + return (f == null) ? null : f.item; } /** * Retrieves, but does not remove, the head (first element) of this list. + * * @return the head of this list * @throws NoSuchElementException if this list is empty * @since 1.5 @@ -477,14 +671,14 @@ public class LinkedList } /** - * Retrieves and removes the head (first element) of this list - * @return the head of this list, or null if this list is empty + * Retrieves and removes the head (first element) of this list. + * + * @return the head of this list, or {@code null} if this list is empty * @since 1.5 */ public E poll() { - if (size==0) - return null; - return removeFirst(); + final Node f = first; + return (f == null) ? null : unlinkFirst(f); } /** @@ -502,7 +696,7 @@ public class LinkedList * Adds the specified element as the tail (last element) of this list. * * @param e the element to add - * @return true (as specified by {@link Queue#offer}) + * @return {@code true} (as specified by {@link Queue#offer}) * @since 1.5 */ public boolean offer(E e) { @@ -514,7 +708,7 @@ public class LinkedList * Inserts the specified element at the front of this list. * * @param e the element to insert - * @return true (as specified by {@link Deque#offerFirst}) + * @return {@code true} (as specified by {@link Deque#offerFirst}) * @since 1.6 */ public boolean offerFirst(E e) { @@ -526,7 +720,7 @@ public class LinkedList * Inserts the specified element at the end of this list. * * @param e the element to insert - * @return true (as specified by {@link Deque#offerLast}) + * @return {@code true} (as specified by {@link Deque#offerLast}) * @since 1.6 */ public boolean offerLast(E e) { @@ -536,58 +730,54 @@ public class LinkedList /** * Retrieves, but does not remove, the first element of this list, - * or returns null if this list is empty. + * or returns {@code null} if this list is empty. * - * @return the first element of this list, or null + * @return the first element of this list, or {@code null} * if this list is empty * @since 1.6 */ public E peekFirst() { - if (size==0) - return null; - return getFirst(); - } + final Node f = first; + return (f == null) ? null : f.item; + } /** * Retrieves, but does not remove, the last element of this list, - * or returns null if this list is empty. + * or returns {@code null} if this list is empty. * - * @return the last element of this list, or null + * @return the last element of this list, or {@code null} * if this list is empty * @since 1.6 */ public E peekLast() { - if (size==0) - return null; - return getLast(); + final Node l = last; + return (l == null) ? null : l.item; } /** * Retrieves and removes the first element of this list, - * or returns null if this list is empty. + * or returns {@code null} if this list is empty. * - * @return the first element of this list, or null if + * @return the first element of this list, or {@code null} if * this list is empty * @since 1.6 */ public E pollFirst() { - if (size==0) - return null; - return removeFirst(); + final Node f = first; + return (f == null) ? null : unlinkFirst(f); } /** * Retrieves and removes the last element of this list, - * or returns null if this list is empty. + * or returns {@code null} if this list is empty. * - * @return the last element of this list, or null if + * @return the last element of this list, or {@code null} if * this list is empty * @since 1.6 */ public E pollLast() { - if (size==0) - return null; - return removeLast(); + final Node l = last; + return (l == null) ? null : unlinkLast(l); } /** @@ -624,7 +814,7 @@ public class LinkedList * does not contain the element, it is unchanged. * * @param o element to be removed from this list, if present - * @return true if the list contained the specified element + * @return {@code true} if the list contained the specified element * @since 1.6 */ public boolean removeFirstOccurrence(Object o) { @@ -637,21 +827,21 @@ public class LinkedList * does not contain the element, it is unchanged. * * @param o element to be removed from this list, if present - * @return true if the list contained the specified element + * @return {@code true} if the list contained the specified element * @since 1.6 */ public boolean removeLastOccurrence(Object o) { - if (o==null) { - for (Entry e = header.previous; e != header; e = e.previous) { - if (e.element==null) { - remove(e); + if (o == null) { + for (Node x = last; x != null; x = x.prev) { + if (x.item == null) { + unlink(x); return true; } } } else { - for (Entry e = header.previous; e != header; e = e.previous) { - if (o.equals(e.element)) { - remove(e); + for (Node x = last; x != null; x = x.prev) { + if (o.equals(x.item)) { + unlink(x); return true; } } @@ -662,76 +852,68 @@ public class LinkedList /** * Returns a list-iterator of the elements in this list (in proper * sequence), starting at the specified position in the list. - * Obeys the general contract of List.listIterator(int).

+ * Obeys the general contract of {@code List.listIterator(int)}.

* * The list-iterator is fail-fast: if the list is structurally * modified at any time after the Iterator is created, in any way except - * through the list-iterator's own remove or add + * through the list-iterator's own {@code remove} or {@code add} * methods, the list-iterator will throw a - * ConcurrentModificationException. Thus, in the face of + * {@code ConcurrentModificationException}. Thus, in the face of * concurrent modification, the iterator fails quickly and cleanly, rather * than risking arbitrary, non-deterministic behavior at an undetermined * time in the future. * * @param index index of the first element to be returned from the - * list-iterator (by a call to next) + * list-iterator (by a call to {@code next}) * @return a ListIterator of the elements in this list (in proper * sequence), starting at the specified position in the list * @throws IndexOutOfBoundsException {@inheritDoc} * @see List#listIterator(int) */ public ListIterator listIterator(int index) { + checkPositionIndex(index); return new ListItr(index); } private class ListItr implements ListIterator { - private Entry lastReturned = header; - private Entry next; + private Node lastReturned = null; + private Node next; private int nextIndex; private int expectedModCount = modCount; ListItr(int index) { - if (index < 0 || index > size) - throw new IndexOutOfBoundsException("Index: "+index+ - ", Size: "+size); - if (index < (size >> 1)) { - next = header.next; - for (nextIndex=0; nextIndexindex; nextIndex--) - next = next.previous; - } + // assert isPositionIndex(index); + next = (index == size) ? null : node(index); + nextIndex = index; } public boolean hasNext() { - return nextIndex != size; + return nextIndex < size; } public E next() { checkForComodification(); - if (nextIndex == size) + if (!hasNext()) throw new NoSuchElementException(); lastReturned = next; next = next.next; nextIndex++; - return lastReturned.element; + return lastReturned.item; } public boolean hasPrevious() { - return nextIndex != 0; + return nextIndex > 0; } public E previous() { - if (nextIndex == 0) + checkForComodification(); + if (!hasPrevious()) throw new NoSuchElementException(); - lastReturned = next = next.previous; + lastReturned = next = (next == null) ? last : next.prev; nextIndex--; - checkForComodification(); - return lastReturned.element; + return lastReturned.item; } public int nextIndex() { @@ -739,36 +921,38 @@ public class LinkedList } public int previousIndex() { - return nextIndex-1; + return nextIndex - 1; } public void remove() { checkForComodification(); - Entry lastNext = lastReturned.next; - try { - LinkedList.this.remove(lastReturned); - } catch (NoSuchElementException e) { + if (lastReturned == null) throw new IllegalStateException(); - } - if (next==lastReturned) + + Node lastNext = lastReturned.next; + unlink(lastReturned); + if (next == lastReturned) next = lastNext; else nextIndex--; - lastReturned = header; + lastReturned = null; expectedModCount++; } public void set(E e) { - if (lastReturned == header) + if (lastReturned == null) throw new IllegalStateException(); checkForComodification(); - lastReturned.element = e; + lastReturned.item = e; } public void add(E e) { checkForComodification(); - lastReturned = header; - addBefore(e, next); + lastReturned = null; + if (next == null) + linkLast(e); + else + linkBefore(e, next); nextIndex++; expectedModCount++; } @@ -779,41 +963,18 @@ public class LinkedList } } - private static class Entry { - E element; - Entry next; - Entry previous; + private static class Node { + E item; + Node next; + Node prev; - Entry(E element, Entry next, Entry previous) { - this.element = element; + Node(Node prev, E element, Node next) { + this.item = element; this.next = next; - this.previous = previous; + this.prev = prev; } } - private Entry addBefore(E e, Entry entry) { - Entry newEntry = new Entry(e, entry, entry.previous); - newEntry.previous.next = newEntry; - newEntry.next.previous = newEntry; - size++; - modCount++; - return newEntry; - } - - private E remove(Entry e) { - if (e == header) - throw new NoSuchElementException(); - - E result = e.element; - e.previous.next = e.next; - e.next.previous = e.previous; - e.next = e.previous = null; - e.element = null; - size--; - modCount++; - return result; - } - /** * @since 1.6 */ @@ -821,9 +982,11 @@ public class LinkedList return new DescendingIterator(); } - /** Adapter to provide descending iterators via ListItr.previous */ - private class DescendingIterator implements Iterator { - final ListItr itr = new ListItr(size()); + /** + * Adapter to provide descending iterators via ListItr.previous + */ + private class DescendingIterator implements Iterator { + private final ListItr itr = new ListItr(size()); public boolean hasNext() { return itr.hasPrevious(); } @@ -835,29 +998,32 @@ public class LinkedList } } - /** - * Returns a shallow copy of this LinkedList. (The elements - * themselves are not cloned.) - * - * @return a shallow copy of this LinkedList instance - */ - public Object clone() { - LinkedList clone = null; + @SuppressWarnings("unchecked") + private LinkedList superClone() { try { - clone = (LinkedList) super.clone(); + return (LinkedList) super.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(); } + } + + /** + * Returns a shallow copy of this {@code LinkedList}. (The elements + * themselves are not cloned.) + * + * @return a shallow copy of this {@code LinkedList} instance + */ + public Object clone() { + LinkedList clone = superClone(); // Put clone into "virgin" state - clone.header = new Entry(null, null, null); - clone.header.next = clone.header.previous = clone.header; + clone.first = clone.last = null; clone.size = 0; clone.modCount = 0; // Initialize clone with our elements - for (Entry e = header.next; e != header; e = e.next) - clone.add(e.element); + for (Node x = first; x != null; x = x.next) + clone.add(x.item); return clone; } @@ -879,8 +1045,8 @@ public class LinkedList public Object[] toArray() { Object[] result = new Object[size]; int i = 0; - for (Entry e = header.next; e != header; e = e.next) - result[i++] = e.element; + for (Node x = first; x != null; x = x.next) + result[i++] = x.item; return result; } @@ -894,7 +1060,7 @@ public class LinkedList * *

If the list fits in the specified array with room to spare (i.e., * the array has more elements than the list), the element in the array - * immediately following the end of the list is set to null. + * immediately following the end of the list is set to {@code null}. * (This is useful in determining the length of the list only if * the caller knows that the list does not contain any null elements.) * @@ -903,15 +1069,15 @@ public class LinkedList * precise control over the runtime type of the output array, and may, * under certain circumstances, be used to save allocation costs. * - *

Suppose x is a list known to contain only strings. + *

Suppose {@code x} is a list known to contain only strings. * The following code can be used to dump the list into a newly - * allocated array of String: + * allocated array of {@code String}: * *

      *     String[] y = x.toArray(new String[0]);
* - * Note that toArray(new Object[0]) is identical in function to - * toArray(). + * Note that {@code toArray(new Object[0])} is identical in function to + * {@code toArray()}. * * @param a the array into which the elements of the list are to * be stored, if it is big enough; otherwise, a new array of the @@ -922,14 +1088,15 @@ public class LinkedList * this list * @throws NullPointerException if the specified array is null */ + @SuppressWarnings("unchecked") public T[] toArray(T[] a) { if (a.length < size) a = (T[])java.lang.reflect.Array.newInstance( a.getClass().getComponentType(), size); int i = 0; Object[] result = a; - for (Entry e = header.next; e != header; e = e.next) - result[i++] = e.element; + for (Node x = first; x != null; x = x.next) + result[i++] = x.item; if (a.length > size) a[size] = null; @@ -940,8 +1107,8 @@ public class LinkedList private static final long serialVersionUID = 876323262645176354L; /** - * Save the state of this LinkedList instance to a stream (that - * is, serialize it). + * Saves the state of this {@code LinkedList} instance to a stream + * (that is, serializes it). * * @serialData The size of the list (the number of elements it * contains) is emitted (int), followed by all of its @@ -956,14 +1123,15 @@ public class LinkedList s.writeInt(size); // Write out all elements in the proper order. - for (Entry e = header.next; e != header; e = e.next) - s.writeObject(e.element); + for (Node x = first; x != null; x = x.next) + s.writeObject(x.item); } /** - * Reconstitute this LinkedList instance from a stream (that is - * deserialize it). + * Reconstitutes this {@code LinkedList} instance from a stream + * (that is, deserializes it). */ + @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in any hidden serialization magic @@ -972,12 +1140,8 @@ public class LinkedList // Read in size int size = s.readInt(); - // Initialize header - header = new Entry(null, null, null); - header.next = header.previous = header; - // Read in all elements in the proper order. - for (int i=0; iThis method is useful for implementing {@link + * Object#hashCode()} on objects containing multiple fields. For + * example, if an object that has three fields, {@code x}, {@code + * y}, and {@code z}, one could write: + * + *
+    * @Override public int hashCode() {
+    *     return Objects.hash(x, y, z);
+    * }
+    * 
+ * + * Warning: When a single object reference is supplied, the returned + * value does not equal the hash code of that object reference. This + * value can be computed by calling {@link #hashCode(Object)}. + * + * @param values the values to be hashed + * @return a hash value of the sequence of input values + * @see Arrays#hashCode + * @see List#hashCode + */ + public static int hash(Object... values) { + return Arrays.hashCode(values); + } + /** * Returns the result of calling {@code toString} for a non-{@code * null} argument and {@code "null"} for a {@code null} argument. @@ -84,6 +140,23 @@ public class Objects { return String.valueOf(o); } + /** + * Returns the result of calling {@code toString} on the first + * argument if the first argument is not {@code null} and returns + * the second argument otherwise. + * + * @param o an object + * @param nullDefault string to return if the first argument is + * {@code null} + * @return the result of calling {@code toString} on the first + * argument if it is not {@code null} and the second argument + * otherwise. + * @see Objects#toString(Object) + */ + public static String toString(Object o, String nullDefault) { + return (o != null) ? o.toString() : nullDefault; + } + /** * Returns 0 if the arguments are identical and {@code * c.compare(a, b)} otherwise. diff --git a/jdk/src/share/classes/java/util/jar/JarFile.java b/jdk/src/share/classes/java/util/jar/JarFile.java index 309f4ff48a7..79b1be9e6ce 100644 --- a/jdk/src/share/classes/java/util/jar/JarFile.java +++ b/jdk/src/share/classes/java/util/jar/JarFile.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 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 @@ -297,6 +297,7 @@ class JarFile extends ZipFile { String name = names[i].toUpperCase(Locale.ENGLISH); if (name.endsWith(".DSA") || name.endsWith(".RSA") || + name.endsWith(".EC") || name.endsWith(".SF")) { // Assume since we found a signature-related file // that the jar is signed and that we therefore diff --git a/jdk/src/share/classes/java/util/jar/JarVerifier.java b/jdk/src/share/classes/java/util/jar/JarVerifier.java index 099cf7abbb4..a4ceaa790fd 100644 --- a/jdk/src/share/classes/java/util/jar/JarVerifier.java +++ b/jdk/src/share/classes/java/util/jar/JarVerifier.java @@ -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 @@ -50,7 +50,7 @@ class JarVerifier { private Hashtable verifiedSigners; /* a table mapping names to code signers, for jar entries that have - passed the .SF/.DSA -> MANIFEST check */ + passed the .SF/.DSA/.EC -> MANIFEST check */ private Hashtable sigFileSigners; /* a hash table to hold .SF bytes */ @@ -111,7 +111,7 @@ class JarVerifier { /* * Assumptions: * 1. The manifest should be the first entry in the META-INF directory. - * 2. The .SF/.DSA files follow the manifest, before any normal entries + * 2. The .SF/.DSA/.EC files follow the manifest, before any normal entries * 3. Any of the following will throw a SecurityException: * a. digest mismatch between a manifest section and * the SF section. @@ -129,7 +129,7 @@ class JarVerifier { } if (SignatureFileVerifier.isBlockOrSF(uname)) { - /* We parse only DSA or RSA PKCS7 blocks. */ + /* We parse only DSA, RSA or EC PKCS7 blocks. */ parsingBlockOrSF = true; baos.reset(); mev.setEntry(null, je); diff --git a/jdk/src/share/classes/java/util/logging/LogManager.java b/jdk/src/share/classes/java/util/logging/LogManager.java index 4faea17d79e..fe09557d637 100644 --- a/jdk/src/share/classes/java/util/logging/LogManager.java +++ b/jdk/src/share/classes/java/util/logging/LogManager.java @@ -1039,12 +1039,16 @@ public class LogManager { /** * Returns LoggingMXBean for managing loggers. - * The LoggingMXBean can also obtained from the - * {@link java.lang.management.ManagementFactory#getPlatformMBeanServer - * platform MBeanServer} method. + * An alternative way to manage loggers is using + * the {@link java.lang.management.ManagementFactory#getPlatformMXBeans(Class) + * ManagementFactory.getPlatformMXBeans} method as follows: + *
+     *     List<{@link PlatformLoggingMXBean}> result = ManagementFactory.getPlatformMXBeans(PlatformLoggingMXBean.class);
+     * 
* * @return a {@link LoggingMXBean} object. * + * @see PlatformLoggingMXBean * @see java.lang.management.ManagementFactory * @since 1.5 */ diff --git a/jdk/src/share/classes/java/util/logging/Logging.java b/jdk/src/share/classes/java/util/logging/Logging.java index d99782407a5..9ce97a3cfba 100644 --- a/jdk/src/share/classes/java/util/logging/Logging.java +++ b/jdk/src/share/classes/java/util/logging/Logging.java @@ -29,8 +29,6 @@ import java.util.Enumeration; import java.util.List; import java.util.ArrayList; -import javax.management.ObjectName; - /** * Logging is the implementation class of LoggingMXBean. * @@ -116,8 +114,4 @@ class Logging implements LoggingMXBean { return p.getName(); } } - - public ObjectName getObjectName() { - return ObjectName.valueOf(LogManager.LOGGING_MXBEAN_NAME); - } } diff --git a/jdk/src/share/classes/java/util/logging/LoggingMXBean.java b/jdk/src/share/classes/java/util/logging/LoggingMXBean.java index a3abe3c69b1..e9dda046a26 100644 --- a/jdk/src/share/classes/java/util/logging/LoggingMXBean.java +++ b/jdk/src/share/classes/java/util/logging/LoggingMXBean.java @@ -25,7 +25,6 @@ package java.util.logging; -import java.lang.management.PlatformManagedObject; /** * The management interface for the logging facility. @@ -35,27 +34,26 @@ import java.lang.management.PlatformManagedObject; * MXBean * can be obtained by calling * the {@link LogManager#getLoggingMXBean} method or from the - * {@link java.lang.management.ManagementFactory#getPlatformMBeanServer - * platform MBeanServer} method. + * {@linkplain java.lang.management.ManagementFactory#getPlatformMBeanServer + * platform MBeanServer}. * - *

The {@link javax.management.ObjectName ObjectName} for uniquely + * The {@link javax.management.ObjectName ObjectName} for uniquely * identifying the LoggingMXBean within an MBeanServer is: *

* {@link LogManager#LOGGING_MXBEAN_NAME * java.util.logging:type=Logging} *
* - * It can be obtained by calling the - * {@link PlatformManagedObject#getObjectName} method. - * - * @see java.lang.management.ManagementFactory#getPlatformMXBeans(Class) + * The instance registered in the platform MBeanServer with + * this {@code ObjectName} is also a {@link PlatformLoggingMXBean}. * * @author Ron Mann * @author Mandy Chung * @since 1.5 * + * @see PlatformLoggingMXBean */ -public interface LoggingMXBean extends PlatformManagedObject { +public interface LoggingMXBean { /** * Returns the list of currently registered loggers. This method diff --git a/jdk/src/share/classes/java/util/logging/LoggingProxyImpl.java b/jdk/src/share/classes/java/util/logging/LoggingProxyImpl.java new file mode 100644 index 00000000000..c6422412a98 --- /dev/null +++ b/jdk/src/share/classes/java/util/logging/LoggingProxyImpl.java @@ -0,0 +1,102 @@ +/* + * 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 java.util.logging; + +import sun.util.logging.LoggingProxy; + +/** + * Implementation of LoggingProxy when java.util.logging classes exist. + */ +class LoggingProxyImpl implements LoggingProxy { + static final LoggingProxy INSTANCE = new LoggingProxyImpl(); + + private LoggingProxyImpl() { } + + @Override + public Object getLogger(String name) { + return Logger.getLogger(name); + } + + @Override + public Object getLevel(Object logger) { + return ((Logger) logger).getLevel(); + } + + @Override + public void setLevel(Object logger, Object newLevel) { + ((Logger) logger).setLevel((Level) newLevel); + } + + @Override + public boolean isLoggable(Object logger, Object level) { + return ((Logger) logger).isLoggable((Level) level); + } + + @Override + public void log(Object logger, Object level, String msg) { + ((Logger) logger).log((Level) level, msg); + } + + @Override + public void log(Object logger, Object level, String msg, Throwable t) { + ((Logger) logger).log((Level) level, msg, t); + } + + @Override + public void log(Object logger, Object level, String msg, Object... params) { + ((Logger) logger).log((Level) level, msg, params); + } + + @Override + public java.util.List getLoggerNames() { + return LogManager.getLoggingMXBean().getLoggerNames(); + } + + @Override + public String getLoggerLevel(String loggerName) { + return LogManager.getLoggingMXBean().getLoggerLevel(loggerName); + } + + @Override + public void setLoggerLevel(String loggerName, String levelName) { + LogManager.getLoggingMXBean().setLoggerLevel(loggerName, levelName); + } + + @Override + public String getParentLoggerName(String loggerName) { + return LogManager.getLoggingMXBean().getParentLoggerName(loggerName); + } + + @Override + public Object parseLevel(String levelName) { + return Level.parse(levelName); + } + + @Override + public String getLevelName(Object level) { + return ((Level) level).getName(); + } +} diff --git a/jdk/src/share/classes/java/util/logging/PlatformLoggingMXBean.java b/jdk/src/share/classes/java/util/logging/PlatformLoggingMXBean.java new file mode 100644 index 00000000000..f994e285bcd --- /dev/null +++ b/jdk/src/share/classes/java/util/logging/PlatformLoggingMXBean.java @@ -0,0 +1,60 @@ +/* + * 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 java.util.logging; + +import java.lang.management.PlatformManagedObject; + +/** + * The {@linkplain PlatformManagedObject platform managed object} for the + * logging facility. This interface simply unifies {@link LoggingMXBean} + * {@link PlatformManagedObject}; + * and it does not specify any new operations. + * + *

The {@link java.lang.management.ManagementFactory#getPlatformMXBeans(Class) + * ManagementFactory.getPlatformMXBeans} method can be used to obtain + * the {@code PlatformLoggingMXBean} object as follows: + *

+ *     ManagementFactory.getPlatformMXBeans(PlatformLoggingMXBean.class);
+ * 
+ * or from the {@linkplain java.lang.management.ManagementFactory#getPlatformMBeanServer + * platform MBeanServer}. + * + * The {@link javax.management.ObjectName ObjectName} for uniquely + * identifying the LoggingMXBean within an MBeanServer is: + *
+ * java.util.logging:type=Logging + *
+ * + * The {@link PlatformManagedObject#getObjectName} method + * can be used to obtain its {@code ObjectName}. + * + * @See java.lang.management.PlatformManagedObject + * + * @author Mandy Chung + * @since 1.7 + */ +public interface PlatformLoggingMXBean extends LoggingMXBean, PlatformManagedObject { +} diff --git a/jdk/src/share/classes/java/util/regex/Matcher.java b/jdk/src/share/classes/java/util/regex/Matcher.java index 488e47da89a..76883d930c7 100644 --- a/jdk/src/share/classes/java/util/regex/Matcher.java +++ b/jdk/src/share/classes/java/util/regex/Matcher.java @@ -688,7 +688,7 @@ public final class Matcher implements MatchResult { * *

The replacement string may contain references to subsequences * captured during the previous match: Each occurrence of - * $<name> or $g + * ${name} or $g * will be replaced by the result of evaluating the corresponding * {@link #group(String) group(name)} or {@link #group(int) group(g)} * respectively. For $g, @@ -770,7 +770,7 @@ public final class Matcher implements MatchResult { // more appropriate. nextChar = replacement.charAt(cursor); int refNum = -1; - if (nextChar == '<') { + if (nextChar == '{') { cursor++; StringBuilder gsb = new StringBuilder(); while (cursor < replacement.length()) { @@ -787,13 +787,17 @@ public final class Matcher implements MatchResult { if (gsb.length() == 0) throw new IllegalArgumentException( "named capturing group has 0 length name"); - if (nextChar != '>') + if (nextChar != '}') throw new IllegalArgumentException( - "named capturing group is missing trailing '>'"); + "named capturing group is missing trailing '}'"); String gname = gsb.toString(); + if (ASCII.isDigit(gname.charAt(0))) + throw new IllegalArgumentException( + "capturing group name {" + gname + + "} starts with digit character"); if (!parentPattern.namedGroups().containsKey(gname)) throw new IllegalArgumentException( - "No group with name <" + gname + ">"); + "No group with name {" + gname + "}"); refNum = parentPattern.namedGroups().get(gname); cursor++; } else { diff --git a/jdk/src/share/classes/java/util/regex/Pattern.java b/jdk/src/share/classes/java/util/regex/Pattern.java index bda83849a37..a69c8da669f 100644 --- a/jdk/src/share/classes/java/util/regex/Pattern.java +++ b/jdk/src/share/classes/java/util/regex/Pattern.java @@ -484,7 +484,7 @@ import java.util.Arrays; *

Group name
*

A capturing group can also be assigned a "name", a named-capturing group, * and then be back-referenced later by the "name". Group names are composed of - * the following characters: + * the following characters. The first character must be a letter. * *