Mercurial > hg > release > icedtea7-forest-2.1 > jdk
changeset 1967:49eb9c3d7ce7
Merge
author | vinnie |
---|---|
date | Thu, 12 Nov 2009 23:04:42 +0000 |
parents | 7475a2e71c40 (current diff) eb8b08775b82 (diff) |
children | 60646a58322b |
files | make/tools/fontchecker/Makefile make/tools/src/build/tools/fontchecker/FontCheckDummy.java make/tools/src/build/tools/fontchecker/FontChecker.java make/tools/src/build/tools/fontchecker/FontCheckerConstants.java make/tools/src/build/tools/fontchecker/FontFileFilter.java make/tools/src/build/tools/fontchecker/README.txt src/share/classes/java/nio/ByteBufferAs-X-Buffer.java src/share/classes/java/nio/Direct-X-Buffer-bin.java src/share/classes/java/nio/Direct-X-Buffer.java src/share/classes/java/nio/Heap-X-Buffer.java src/share/classes/java/nio/X-Buffer-bin.java src/share/classes/java/nio/X-Buffer.java src/share/classes/java/nio/charset/Charset-X-Coder.java src/share/classes/sun/misc/Version-template.java src/share/classes/sun/tools/jconsole/Version-template.java test/java/nio/Buffer/Basic-X.java test/java/nio/Buffer/CopyDirect-X-Memory.java |
diffstat | 199 files changed, 23072 insertions(+), 8043 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Thu Nov 12 23:00:23 2009 +0000 +++ b/.hgtags Thu Nov 12 23:04:42 2009 +0000 @@ -49,3 +49,4 @@ 460639b036f327282832a4fe52b7aa45688afd50 jdk7-b72 f708138c9aca4b389872838fe6773872fce3609e jdk7-b73 eacb36e30327e7ae33baa068e82ddccbd91eaae2 jdk7-b74 +8885b22565077236a927e824ef450742e434a230 jdk7-b75
--- a/make/common/Defs-linux.gmk Thu Nov 12 23:00:23 2009 +0000 +++ b/make/common/Defs-linux.gmk Thu Nov 12 23:04:42 2009 +0000 @@ -116,8 +116,16 @@ LDFLAGS_COMMON_sparcv9 += -m64 -mcpu=v9 CFLAGS_REQUIRED_sparc += -m32 -mcpu=v9 LDFLAGS_COMMON_sparc += -m32 -mcpu=v9 -CFLAGS_REQUIRED = $(CFLAGS_REQUIRED_$(ARCH)) -LDFLAGS_COMMON += $(LDFLAGS_COMMON_$(ARCH)) +ifeq ($(ZERO_BUILD), true) + CFLAGS_REQUIRED = $(ZERO_ARCHFLAG) + ifeq ($(ZERO_ENDIANNESS), little) + CFLAGS_REQUIRED += -D_LITTLE_ENDIAN + endif + LDFLAGS_COMMON += $(ZERO_ARCHFLAG) +else + CFLAGS_REQUIRED = $(CFLAGS_REQUIRED_$(ARCH)) + LDFLAGS_COMMON += $(LDFLAGS_COMMON_$(ARCH)) +endif # If this is a --hash-style=gnu system, use --hash-style=both # The gnu .hash section won't work on some Linux systems like SuSE 10. @@ -217,7 +225,7 @@ EXTRA_LIBS += -lc -LDFLAGS_DEFS_OPTION = -z defs +LDFLAGS_DEFS_OPTION = -Xlinker -z -Xlinker defs LDFLAGS_COMMON += $(LDFLAGS_DEFS_OPTION) #
--- a/make/common/Defs.gmk Thu Nov 12 23:00:23 2009 +0000 +++ b/make/common/Defs.gmk Thu Nov 12 23:04:42 2009 +0000 @@ -667,12 +667,7 @@ LINTFLAGS = $(LINTFLAGS_$(VARIANT)) $(LINTFLAGS_COMMON) \ $(OTHER_LINTFLAGS) -# this should be moved into Defs-<platform>.gmk..... -ifeq ($(PLATFORM), windows) - VERSION_DEFINES = -DRELEASE="\"$(RELEASE)\"" -else - VERSION_DEFINES = -DRELEASE='"$(RELEASE)"' -endif +VERSION_DEFINES = -DRELEASE='"$(RELEASE)"' # Note: As a rule, GNU Make rules should not appear in any of the # Defs*.gmk files. These were added for Kestrel-Solaris and do address
--- a/make/common/Program.gmk Thu Nov 12 23:00:23 2009 +0000 +++ b/make/common/Program.gmk Thu Nov 12 23:04:42 2009 +0000 @@ -85,7 +85,7 @@ endif endif ifeq ($(PLATFORM), linux) - LDFLAGS += -z origin + LDFLAGS += -Wl,-z -Wl,origin LDFLAGS += -Wl,--allow-shlib-undefined LDFLAGS += -Wl,-rpath -Wl,\$$ORIGIN/../lib/$(LIBARCH)/jli LDFLAGS += -Wl,-rpath -Wl,\$$ORIGIN/../jre/lib/$(LIBARCH)/jli @@ -236,13 +236,13 @@ endif # INCREMENTAL_BUILD ifdef JAVA_ARGS -OTHER_CPPFLAGS += -DJAVA_ARGS=$(JAVA_ARGS) -OTHER_CPPFLAGS += -DLAUNCHER_NAME=\"$(LAUNCHER_NAME)\" +OTHER_CPPFLAGS += -DJAVA_ARGS='$(JAVA_ARGS)' +OTHER_CPPFLAGS += -DLAUNCHER_NAME='"$(LAUNCHER_NAME)"' endif ifeq ($(PLATFORM), windows) ifdef RELEASE -OTHER_CPPFLAGS += -DVERSION="$(RELEASE)" +OTHER_CPPFLAGS += -DVERSION='"$(RELEASE)"' endif endif @@ -258,14 +258,8 @@ OTHER_INCLUDES += -I$(LAUNCHER_SHARE_SRC)/bin -I$(LAUNCHER_PLATFORM_SRC)/bin OTHER_INCLUDES += -I$(SHARE_SRC)/native/java/util/zip/zlib-1.1.3 -# this may not be necessary... -ifeq ($(PLATFORM), windows) -OTHER_CPPFLAGS += -DPROGNAME="\"$(PROGRAM)\"" -VERSION_DEFINES += -DFULL_VERSION="\"$(FULL_VERSION)\"" -else OTHER_CPPFLAGS += -DPROGNAME='"$(PROGRAM)"' VERSION_DEFINES += -DFULL_VERSION='"$(FULL_VERSION)"' -endif VERSION_DEFINES += -DJDK_MAJOR_VERSION='"$(JDK_MAJOR_VERSION)"' \ -DJDK_MINOR_VERSION='"$(JDK_MINOR_VERSION)"' @@ -279,8 +273,14 @@ # # How to install jvm.cfg. -# -$(JVMCFG): $(LAUNCHER_PLATFORM_SRC)/bin/$(ARCH)/jvm.cfg +# +ifeq ($(ZERO_BUILD), true) +JVMCFG_ARCH = zero +else +JVMCFG_ARCH = $(ARCH) +endif + +$(JVMCFG): $(LAUNCHER_PLATFORM_SRC)/bin/$(JVMCFG_ARCH)/jvm.cfg $(install-file) #
--- a/make/common/Release.gmk Thu Nov 12 23:00:23 2009 +0000 +++ b/make/common/Release.gmk Thu Nov 12 23:04:42 2009 +0000 @@ -330,7 +330,7 @@ # # Specific files and directories that will be filtered out from above areas. # -SOURCE_FILTERs = $(SCM_DIRs) 'X-*' '*-X-*' '*-template.java' ',*' +SOURCE_FILTERs = $(SCM_DIRs) ',*' SOURCE_FILES_filter = $(SOURCE_FILTERs:%=-name % -prune -o) #
--- a/make/common/Rules.gmk Thu Nov 12 23:00:23 2009 +0000 +++ b/make/common/Rules.gmk Thu Nov 12 23:04:42 2009 +0000 @@ -63,7 +63,7 @@ # If AUTO_FILES_PROPERTIES_DIRS used, automatically find properties files # ifdef AUTO_FILES_PROPERTIES_DIRS - AUTO_FILES_PROPERTIES_FILTERS1 = $(SCM_DIRs) 'X-*' '*-X-*' ',*' + AUTO_FILES_PROPERTIES_FILTERS1 = $(SCM_DIRs) ',*' AUTO_FILES_PROPERTIES_FILTERS1 += $(AUTO_PROPERTIES_PRUNE) FILES_properties_find_filters1 = $(AUTO_FILES_PROPERTIES_FILTERS1:%=-name % -prune -o) FILES_properties_auto1 := \ @@ -111,7 +111,7 @@ ifdef AUTO_FILES_JAVA_DIRS # Filter out these files or directories - AUTO_FILES_JAVA_SOURCE_FILTERS1 = $(SCM_DIRs) 'X-*' '*-X-*' '*-template.java' ',*' + AUTO_FILES_JAVA_SOURCE_FILTERS1 = $(SCM_DIRs) ',*' AUTO_FILES_JAVA_SOURCE_FILTERS2 = AUTO_FILES_JAVA_SOURCE_FILTERS1 += $(AUTO_JAVA_PRUNE) AUTO_FILES_JAVA_SOURCE_FILTERS2 += $(AUTO_JAVA_PRUNE)
--- a/make/java/instrument/Makefile Thu Nov 12 23:00:23 2009 +0000 +++ b/make/java/instrument/Makefile Thu Nov 12 23:04:42 2009 +0000 @@ -109,7 +109,7 @@ LDFLAGS += -R \$$ORIGIN/jli endif ifeq ($(PLATFORM), linux) - LDFLAGS += -z origin + LDFLAGS += -Wl,-z -Wl,origin LDFLAGS += -Wl,--allow-shlib-undefined LDFLAGS += -Wl,-rpath -Wl,\$$ORIGIN/jli endif
--- a/make/java/java/FILES_java.gmk Thu Nov 12 23:00:23 2009 +0000 +++ b/make/java/java/FILES_java.gmk Thu Nov 12 23:04:42 2009 +0000 @@ -287,11 +287,18 @@ java/util/concurrent/ExecutorService.java \ java/util/concurrent/ExecutorCompletionService.java \ java/util/concurrent/Executors.java \ + java/util/concurrent/ForkJoinPool.java \ + java/util/concurrent/ForkJoinTask.java \ + java/util/concurrent/ForkJoinWorkerThread.java \ java/util/concurrent/Future.java \ java/util/concurrent/FutureTask.java \ java/util/concurrent/LinkedBlockingDeque.java \ java/util/concurrent/LinkedBlockingQueue.java \ + java/util/concurrent/LinkedTransferQueue.java \ + java/util/concurrent/Phaser.java \ java/util/concurrent/PriorityBlockingQueue.java \ + java/util/concurrent/RecursiveAction.java \ + java/util/concurrent/RecursiveTask.java \ java/util/concurrent/RejectedExecutionException.java \ java/util/concurrent/RejectedExecutionHandler.java \ java/util/concurrent/RunnableFuture.java \ @@ -302,9 +309,11 @@ java/util/concurrent/Semaphore.java \ java/util/concurrent/SynchronousQueue.java \ java/util/concurrent/ThreadFactory.java \ + java/util/concurrent/ThreadLocalRandom.java \ java/util/concurrent/ThreadPoolExecutor.java \ java/util/concurrent/TimeUnit.java \ java/util/concurrent/TimeoutException.java \ + java/util/concurrent/TransferQueue.java \ java/util/concurrent/atomic/AtomicBoolean.java \ java/util/concurrent/atomic/AtomicInteger.java \ java/util/concurrent/atomic/AtomicIntegerArray.java \
--- a/make/java/jli/Makefile Thu Nov 12 23:00:23 2009 +0000 +++ b/make/java/jli/Makefile Thu Nov 12 23:04:42 2009 +0000 @@ -48,11 +48,15 @@ LAUNCHER_SHARE_SRC = $(SHARE_SRC)/bin LAUNCHER_PLATFORM_SRC = $(PLATFORM_SRC)/bin +ifeq ($(ZERO_BUILD), true) +ERGO_FAMILY=zero +else ifeq ($(ARCH_FAMILY), amd64) ERGO_FAMILY=i586 else ERGO_FAMILY=$(ARCH_FAMILY) endif +endif #
--- a/make/java/main/java/Makefile Thu Nov 12 23:00:23 2009 +0000 +++ b/make/java/main/java/Makefile Thu Nov 12 23:04:42 2009 +0000 @@ -57,7 +57,7 @@ # include $(BUILDDIR)/common/Program.gmk OTHER_CPPFLAGS += -DEXPAND_CLASSPATH_WILDCARDS -OTHER_CPPFLAGS += -DLAUNCHER_NAME=\"$(LAUNCHER_NAME)\" +OTHER_CPPFLAGS += -DLAUNCHER_NAME='"$(LAUNCHER_NAME)"' ifeq ($(PLATFORM), solaris) LDFLAGS += -R$(OPENWIN_LIB)
--- a/make/java/main/javaw/Makefile Thu Nov 12 23:00:23 2009 +0000 +++ b/make/java/main/javaw/Makefile Thu Nov 12 23:04:42 2009 +0000 @@ -62,4 +62,5 @@ # include $(BUILDDIR)/common/Program.gmk OTHER_CPPFLAGS += -DEXPAND_CLASSPATH_WILDCARDS -OTHER_CPPFLAGS += -DLAUNCHER_NAME=\"$(LAUNCHER_NAME)\" +OTHER_CPPFLAGS += -DLAUNCHER_NAME='"$(LAUNCHER_NAME)"' +
--- a/make/java/nio/Makefile Thu Nov 12 23:00:23 2009 +0000 +++ b/make/java/nio/Makefile Thu Nov 12 23:04:42 2009 +0000 @@ -335,6 +335,15 @@ SCS_SRC=$(SNIO_SRC)/cs SFS_SRC=$(SNIO_SRC)/fs +# Template files +HEAP_X_BUF_TEMPLATE=$(BUF_SRC)/Heap-X-Buffer.java.template +BYTE_X_BUF_TEMPLATE=$(BUF_SRC)/ByteBufferAs-X-Buffer.java.template +X_BUF_TEMPLATE=$(BUF_SRC)/X-Buffer.java.template +X_BUF_BIN_TEMPLATE=$(BUF_SRC)/X-Buffer-bin.java.template +DIRECT_X_BUF_TEMPLATE=$(BUF_SRC)/Direct-X-Buffer.java.template +DIRECT_X_BUF_BIN_TEMPLATE=$(BUF_SRC)/Direct-X-Buffer-bin.java.template +CHARSET_X_CODER_TEMPLATE=$(CS_SRC)/Charset-X-Coder.java.template + BUF_GEN=$(NIO_GEN) CH_GEN=$(NIO_GEN)/channels CS_GEN=$(NIO_GEN)/charset @@ -357,39 +366,39 @@ # Public abstract buffer classes # -$(BUF_GEN)/ByteBuffer.java: $(BUF_SRC)/X-Buffer.java \ - $(BUF_SRC)/X-Buffer-bin.java \ +$(BUF_GEN)/ByteBuffer.java: $(X_BUF_TEMPLATE) \ + $(X_BUF_BIN_TEMPLATE) \ $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=byte BIN=1 SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/CharBuffer.java: $(BUF_SRC)/X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/CharBuffer.java: $(X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ShortBuffer.java: $(BUF_SRC)/X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ShortBuffer.java: $(X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/IntBuffer.java: $(BUF_SRC)/X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/IntBuffer.java: $(X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/LongBuffer.java: $(BUF_SRC)/X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/LongBuffer.java: $(X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/FloatBuffer.java: $(BUF_SRC)/X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/FloatBuffer.java: $(X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DoubleBuffer.java: $(BUF_SRC)/X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DoubleBuffer.java: $(X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) @@ -397,72 +406,72 @@ # Buffers whose contents are heap-allocated # -$(BUF_GEN)/HeapByteBuffer.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapByteBuffer.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=byte SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapByteBuffer%.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapByteBuffer%.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=byte RW=$* SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapCharBuffer.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapCharBuffer.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapCharBuffer%.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapCharBuffer%.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char RW=$* SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapShortBuffer.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapShortBuffer.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapShortBuffer%.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapShortBuffer%.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short RW=$* SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapIntBuffer.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapIntBuffer.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapIntBuffer%.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapIntBuffer%.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int RW=$* SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapLongBuffer.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapLongBuffer.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapLongBuffer%.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapLongBuffer%.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long RW=$* SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapFloatBuffer.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapFloatBuffer.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapFloatBuffer%.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapFloatBuffer%.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float RW=$* SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapDoubleBuffer.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapDoubleBuffer.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/HeapDoubleBuffer%.java: $(BUF_SRC)/Heap-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/HeapDoubleBuffer%.java: $(HEAP_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double RW=$* SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) @@ -470,15 +479,15 @@ # Direct byte buffer # -$(BUF_GEN)/DirectByteBuffer.java: $(BUF_SRC)/Direct-X-Buffer.java \ - $(BUF_SRC)/Direct-X-Buffer.java \ +$(BUF_GEN)/DirectByteBuffer.java: $(DIRECT_X_BUF_TEMPLATE) \ + $(DIRECT_X_BUF_TEMPLATE) \ $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=byte BIN=1 SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectByteBuffer%.java: $(BUF_SRC)/Direct-X-Buffer.java \ - $(BUF_SRC)/Direct-X-Buffer.java \ +$(BUF_GEN)/DirectByteBuffer%.java: $(DIRECT_X_BUF_TEMPLATE) \ + $(DIRECT_X_BUF_TEMPLATE) \ $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp @@ -487,62 +496,62 @@ # Unswapped views of direct byte buffers # -$(BUF_GEN)/DirectCharBufferU.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectCharBufferU.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectCharBuffer%U.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectCharBuffer%U.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char RW=$* BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectShortBufferU.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectShortBufferU.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectShortBuffer%U.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectShortBuffer%U.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short RW=$* BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectIntBufferU.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectIntBufferU.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectIntBuffer%U.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectIntBuffer%U.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int RW=$* BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectLongBufferU.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectLongBufferU.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectLongBuffer%U.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectLongBuffer%U.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long RW=$* BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectFloatBufferU.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectFloatBufferU.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectFloatBuffer%U.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectFloatBuffer%U.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float RW=$* BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectDoubleBufferU.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectDoubleBufferU.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectDoubleBuffer%U.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectDoubleBuffer%U.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double RW=$* BO=U SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) @@ -550,62 +559,62 @@ # Swapped views of direct byte buffers # -$(BUF_GEN)/DirectCharBufferS.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectCharBufferS.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectCharBuffer%S.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectCharBuffer%S.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char RW=$* BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectShortBufferS.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectShortBufferS.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectShortBuffer%S.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectShortBuffer%S.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short RW=$* BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectIntBufferS.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectIntBufferS.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectIntBuffer%S.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectIntBuffer%S.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int RW=$* BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectLongBufferS.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectLongBufferS.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectLongBuffer%S.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectLongBuffer%S.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long RW=$* BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectFloatBufferS.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectFloatBufferS.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectFloatBuffer%S.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectFloatBuffer%S.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float RW=$* BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectDoubleBufferS.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectDoubleBufferS.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/DirectDoubleBuffer%S.java: $(BUF_SRC)/Direct-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/DirectDoubleBuffer%S.java: $(DIRECT_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double RW=$* BO=S SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) @@ -613,62 +622,62 @@ # Big-endian views of byte buffers # -$(BUF_GEN)/ByteBufferAsCharBufferB.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsCharBufferB.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsCharBuffer%B.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsCharBuffer%B.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char RW=$* BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsShortBufferB.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsShortBufferB.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsShortBuffer%B.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsShortBuffer%B.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short RW=$* BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsIntBufferB.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsIntBufferB.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsIntBuffer%B.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsIntBuffer%B.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int RW=$* BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsLongBufferB.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsLongBufferB.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsLongBuffer%B.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsLongBuffer%B.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long RW=$* BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsFloatBufferB.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsFloatBufferB.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsFloatBuffer%B.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsFloatBuffer%B.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float RW=$* BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsDoubleBufferB.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsDoubleBufferB.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsDoubleBuffer%B.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsDoubleBuffer%B.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double RW=$* BO=B SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) @@ -676,62 +685,62 @@ # Little-endian views of byte buffers # -$(BUF_GEN)/ByteBufferAsCharBufferL.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsCharBufferL.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsCharBuffer%L.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsCharBuffer%L.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=char RW=$* BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsShortBufferL.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsShortBufferL.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsShortBuffer%L.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsShortBuffer%L.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=short RW=$* BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsIntBufferL.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsIntBufferL.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsIntBuffer%L.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsIntBuffer%L.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=int RW=$* BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsLongBufferL.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsLongBufferL.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsLongBuffer%L.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsLongBuffer%L.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=long RW=$* BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsFloatBufferL.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsFloatBufferL.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsFloatBuffer%L.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsFloatBuffer%L.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=float RW=$* BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsDoubleBufferL.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsDoubleBufferL.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) $(MV) $@.temp $@ -$(BUF_GEN)/ByteBufferAsDoubleBuffer%L.java: $(BUF_SRC)/ByteBufferAs-X-Buffer.java $(GEN_BUFFER_SH) +$(BUF_GEN)/ByteBufferAsDoubleBuffer%L.java: $(BYTE_X_BUF_TEMPLATE) $(GEN_BUFFER_SH) $(prep-target) @$(RM) $@.temp TYPE=double RW=$* BO=L SRC=$< DST=$@.temp $(GEN_BUFFER_CMD) @@ -745,13 +754,13 @@ GEN_CODER_CMD = SPP="$(SPP_CMD)" SED="$(SED)" NAWK="$(NAWK)" SH="$(SH)" $(SH) $(GEN_CODER_SH) -$(CS_GEN)/CharsetDecoder.java: $(CS_SRC)/Charset-X-Coder.java $(GEN_CODER_SH) +$(CS_GEN)/CharsetDecoder.java: $(CHARSET_X_CODER_TEMPLATE) $(GEN_CODER_SH) $(prep-target) @$(RM) $@.temp $(GEN_CODER_CMD) decoder $< $@.temp $(MV) $@.temp $@ -$(CS_GEN)/CharsetEncoder.java: $(CS_SRC)/Charset-X-Coder.java $(GEN_CODER_SH) +$(CS_GEN)/CharsetEncoder.java: $(CHARSET_X_CODER_TEMPLATE) $(GEN_CODER_SH) $(prep-target) @$(RM) $@.temp $(GEN_CODER_CMD) encoder $< $@.temp
--- a/make/java/nio/genBuffer.sh Thu Nov 12 23:00:23 2009 +0000 +++ b/make/java/nio/genBuffer.sh Thu Nov 12 23:04:42 2009 +0000 @@ -154,7 +154,7 @@ mv $DST $DST.tmp sed -e '/#BIN/,$d' <$DST.tmp >$DST rm -f $DST.tmp - binops=`dirname $SRC`/`basename $SRC .java`-bin.java + binops=`dirname $SRC`/`basename $SRC .java.template`-bin.java.template genBinOps char character 1 two one $binops >>$DST genBinOps short short 1 two one $binops >>$DST genBinOps int integer 2 four three $binops >>$DST
--- a/make/java/redist/Makefile Thu Nov 12 23:00:23 2009 +0000 +++ b/make/java/redist/Makefile Thu Nov 12 23:04:42 2009 +0000 @@ -94,11 +94,13 @@ endif endif # INCLUDE_SA -# Hotspot client is only available on 32-bit builds +# Hotspot client is only available on 32-bit non-Zero builds +ifneq ($(ZERO_BUILD), true) ifeq ($(ARCH_DATA_MODEL), 32) IMPORT_LIST += $(LIB_LOCATION)/$(CLIENT_LOCATION)/$(JVM_NAME) \ $(LIB_LOCATION)/$(CLIENT_LOCATION)/Xusage.txt endif +endif ifeq ($(PLATFORM), windows) # Windows vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Windows @@ -171,6 +173,7 @@ IMPORT_LIST += $(LIB_LOCATION)/$(SERVER_LOCATION)/$(JVMDB_NAME) endif +ifneq ($(ZERO_BUILD), true) ifeq ($(ARCH_DATA_MODEL), 32) IMPORT_LIST += $(LIB_LOCATION)/$(CLIENT_LOCATION)/$(LIBJSIG_NAME) @@ -201,6 +204,8 @@ endif # 32bit +endif # ZERO_BUILD + # NOT Windows ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NOT Windows endif # PLATFORM
--- a/make/java/version/Makefile Thu Nov 12 23:00:23 2009 +0000 +++ b/make/java/version/Makefile Thu Nov 12 23:04:42 2009 +0000 @@ -33,7 +33,7 @@ all build: $(GENSRCDIR)/sun/misc/Version.java $(GENSRCDIR)/sun/misc/Version.java: \ - $(SHARE_SRC)/classes/sun/misc/Version-template.java + $(SHARE_SRC)/classes/sun/misc/Version.java.template $(prep-target) $(RM) $@.temp $(SED) -e 's/@@launcher_name@@/$(LAUNCHER_NAME)/g' \
--- a/make/javax/sound/Makefile Thu Nov 12 23:00:23 2009 +0000 +++ b/make/javax/sound/Makefile Thu Nov 12 23:04:42 2009 +0000 @@ -128,7 +128,7 @@ # for dynamic inclusion of extra sound libs: these # JNI libs will be loaded from Platform.java -CPPFLAGS += -DEXTRA_SOUND_JNI_LIBS="\"$(EXTRA_SOUND_JNI_LIBS)\"" +CPPFLAGS += -DEXTRA_SOUND_JNI_LIBS='"$(EXTRA_SOUND_JNI_LIBS)"' # integrate MIDI i/o in jsound lib ifeq ($(INCLUDE_MIDI),TRUE)
--- a/make/javax/sound/SoundDefs.gmk Thu Nov 12 23:00:23 2009 +0000 +++ b/make/javax/sound/SoundDefs.gmk Thu Nov 12 23:04:42 2009 +0000 @@ -55,21 +55,25 @@ endif # PLATFORM solaris -ifeq ($(ARCH), i586) - CPPFLAGS += -DX_ARCH=X_I586 -endif # ARCH i586 - -ifeq ($(ARCH), sparc) - CPPFLAGS += -DX_ARCH=X_SPARC -endif # ARCH sparc +ifeq ($(ZERO_BUILD), true) + CPPFLAGS += -DX_ARCH=X_ZERO +else + ifeq ($(ARCH), i586) + CPPFLAGS += -DX_ARCH=X_I586 + endif # ARCH i586 -ifeq ($(ARCH), sparcv9) - CPPFLAGS += -DX_ARCH=X_SPARCV9 -endif # ARCH sparcv9 + ifeq ($(ARCH), sparc) + CPPFLAGS += -DX_ARCH=X_SPARC + endif # ARCH sparc -ifeq ($(ARCH), amd64) - CPPFLAGS += -DX_ARCH=X_AMD64 -endif # ARCH amd64 + ifeq ($(ARCH), sparcv9) + CPPFLAGS += -DX_ARCH=X_SPARCV9 + endif # ARCH sparcv9 + + ifeq ($(ARCH), amd64) + CPPFLAGS += -DX_ARCH=X_AMD64 + endif # ARCH amd64 +endif # files needed for MIDI i/o
--- a/make/jdk_generic_profile.sh Thu Nov 12 23:00:23 2009 +0000 +++ b/make/jdk_generic_profile.sh Thu Nov 12 23:04:42 2009 +0000 @@ -339,3 +339,82 @@ PATH="${path4sdk}" export PATH +# Export variables required for Zero +if [ "${ZERO_BUILD}" = true ] ; then + # ZERO_LIBARCH is the name of the architecture-specific + # subdirectory under $JAVA_HOME/jre/lib + arch=$(uname -m) + case "${arch}" in + x86_64) ZERO_LIBARCH=amd64 ;; + i?86) ZERO_LIBARCH=i386 ;; + sparc64) ZERO_LIBARCH=sparcv9 ;; + arm*) ZERO_LIBARCH=arm ;; + *) ZERO_LIBARCH="$(arch)" + esac + export ZERO_LIBARCH + + # ARCH_DATA_MODEL is the number of bits in a pointer + case "${ZERO_LIBARCH}" in + i386|ppc|s390|sparc|arm) + ARCH_DATA_MODEL=32 + ;; + amd64|ppc64|s390x|sparcv9|ia64|alpha) + ARCH_DATA_MODEL=64 + ;; + *) + echo "ERROR: Unable to determine ARCH_DATA_MODEL for ${ZERO_LIBARCH}" + exit 1 + esac + export ARCH_DATA_MODEL + + # ZERO_ENDIANNESS is the endianness of the processor + case "${ZERO_LIBARCH}" in + i386|amd64|ia64) + ZERO_ENDIANNESS=little + ;; + ppc*|s390*|sparc*|alpha) + ZERO_ENDIANNESS=big + ;; + *) + echo "ERROR: Unable to determine ZERO_ENDIANNESS for ${ZERO_LIBARCH}" + exit 1 + esac + export ZERO_ENDIANNESS + + # ZERO_ARCHDEF is used to enable architecture-specific code + case "${ZERO_LIBARCH}" in + i386) ZERO_ARCHDEF=IA32 ;; + ppc*) ZERO_ARCHDEF=PPC ;; + s390*) ZERO_ARCHDEF=S390 ;; + sparc*) ZERO_ARCHDEF=SPARC ;; + *) ZERO_ARCHDEF=$(echo "${ZERO_LIBARCH}" | tr a-z A-Z) + esac + export ZERO_ARCHDEF + + # ZERO_ARCHFLAG tells the compiler which mode to build for + case "${ZERO_LIBARCH}" in + s390) + ZERO_ARCHFLAG="-m31" + ;; + *) + ZERO_ARCHFLAG="-m${ARCH_DATA_MODEL}" + esac + export ZERO_ARCHFLAG + + # LIBFFI_CFLAGS and LIBFFI_LIBS tell the compiler how to compile and + # link against libffi + pkgconfig=$(which pkg-config 2>/dev/null) + if [ -x "${pkgconfig}" ] ; then + if [ "${LIBFFI_CFLAGS}" = "" ] ; then + LIBFFI_CFLAGS=$("${pkgconfig}" --cflags libffi) + fi + if [ "${LIBFFI_LIBS}" = "" ] ; then + LIBFFI_LIBS=$("${pkgconfig}" --libs libffi) + fi + fi + if [ "${LIBFFI_LIBS}" = "" ] ; then + LIBFFI_LIBS="-lffi" + fi + export LIBFFI_CFLAGS + export LIBFFI_LIBS +fi
--- a/make/jprt.properties Thu Nov 12 23:00:23 2009 +0000 +++ b/make/jprt.properties Thu Nov 12 23:04:42 2009 +0000 @@ -1,5 +1,5 @@ # -# Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2006-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -34,8 +34,8 @@ solaris_x64_5.10,\ linux_i586_2.6,\ linux_x64_2.6,\ -windows_i586,\ -windows_x64 +windows_i586_5.0,\ +windows_x64_5.2 # The different build flavors we want jprt.build.flavors=product,fastdebug @@ -51,21 +51,37 @@ jprt.solaris_sparcv9.build.platform.match32=solaris_sparc_5.10 jprt.solaris_x64.build.platform.match32=solaris_i586_5.10 -# Standard list of jprt test targets for this workspace +# Standard test target for everybody jprt.test.targets=*-*-*-jvm98 -jprt.regression.test.targets= \ - *-product-*-java/lang, \ - *-product-*-java/security, \ - *-product-*-java/text, \ - *-product-*-java/util -#jprt.regression.test.targets= \ -# *-product-*-java/awt, \ -# *-product-*-java/beans, \ -# *-product-*-java/io, \ -# *-product-*-java/net, \ -# *-product-*-java/nio, \ -# *-product-*-java/rmi, \ +# Test targets in test/Makefile (some longer running tests only test c2) +jprt.make.rule.test.targets= \ + *-product-*-jdk_beans1, \ + *-product-*-jdk_beans2, \ + *-product-*-jdk_beans3, \ + *-product-*-jdk_io, \ + *-product-*-jdk_lang, \ + *-product-*-jdk_management1, \ + *-product-*-jdk_management2, \ + *-product-*-jdk_math, \ + *-product-*-jdk_misc, \ + *-product-*-jdk_net, \ + *-product-*-jdk_nio1, \ + *-product-*-jdk_nio2, \ + *-product-*-jdk_nio3, \ + *-product-*-jdk_security1, \ + *-product-*-jdk_security2, \ + *-product-*-jdk_security3, \ + *-product-*-jdk_text, \ + *-product-*-jdk_tools1, \ + *-product-*-jdk_tools2, \ + *-product-*-jdk_util + +# Some of these are crashing Xvfb or windows manager, need dedicated DISPLAY per test batch +jprt2.make.rule.test.targets= \ + *-product-*-jdk_awt, \ + *-product-*-jdk_rmi, \ + *-product-*-jdk_swing, \ # Directories needed to build jprt.bundle.exclude.src.dirs=build
--- a/make/launchers/Makefile.launcher Thu Nov 12 23:00:23 2009 +0000 +++ b/make/launchers/Makefile.launcher Thu Nov 12 23:04:42 2009 +0000 @@ -137,15 +137,15 @@ # PROGRAM, JAVA_ARGS, and APP_CLASSPATH are used in src/share/bin/java.c # SA is currently not available on windows (for any ARCH), or linux-ia64: ifneq ($(ARCH), ia64) - JDB_CLASSPATH = "{ \"/lib/tools.jar\", \"/lib/sa-jdi.jar\", \"/classes\" }" - OTHER_CPPFLAGS += -DAPP_CLASSPATH=$(JDB_CLASSPATH) + JDB_CLASSPATH = { "/lib/tools.jar", "/lib/sa-jdi.jar", "/classes" } + OTHER_CPPFLAGS += -DAPP_CLASSPATH='$(JDB_CLASSPATH)' endif endif # jconsole only ifeq ($(PROGRAM),jconsole) - JCONSOLE_CLASSPATH = "{ \"/lib/jconsole.jar\", \"/lib/tools.jar\", \"/classes\" }" - OTHER_CPPFLAGS += -DAPP_CLASSPATH=$(JCONSOLE_CLASSPATH) + JCONSOLE_CLASSPATH = { "/lib/jconsole.jar", "/lib/tools.jar", "/classes" } + OTHER_CPPFLAGS += -DAPP_CLASSPATH='$(JCONSOLE_CLASSPATH)' ifeq ($(PLATFORM), windows) OTHER_CPPFLAGS += -DJAVAW LDLIBS_COMMON += user32.lib @@ -163,8 +163,8 @@ # SA tools need special app classpath ifeq ($(SA_TOOL),true) - SA_CLASSPATH = "{ \"/lib/tools.jar\", \"/lib/sa-jdi.jar\", \"/classes\"}" - OTHER_CPPFLAGS += -DAPP_CLASSPATH=$(SA_CLASSPATH) + SA_CLASSPATH = { "/lib/tools.jar", "/lib/sa-jdi.jar", "/classes" } + OTHER_CPPFLAGS += -DAPP_CLASSPATH='$(SA_CLASSPATH)' endif # Wildcards @@ -173,11 +173,11 @@ endif # Always tell native code what the main class is -OTHER_CPPFLAGS += -DMAIN_CLASS=\"$(MAIN_CLASS)\" +OTHER_CPPFLAGS += -DMAIN_CLASS='"$(MAIN_CLASS)"' # Construct initializer for initial arguments to java ALL_ARGS = -J-ms8m $(MAIN_JAVA_ARGS) $(MAIN_CLASS) $(MAIN_ARGS) -JAVA_ARGS = "{ $(ALL_ARGS:%=\"%\",) }" +JAVA_ARGS = { $(ALL_ARGS:%="%",) } # Always report launcher info build: launcher_info
--- a/make/netbeans/jconsole/build.properties Thu Nov 12 23:00:23 2009 +0000 +++ b/make/netbeans/jconsole/build.properties Thu Nov 12 23:04:42 2009 +0000 @@ -33,7 +33,7 @@ com/sun/tools/jconsole/ \ sun/tools/jconsole/ excludes=\ - sun/tools/jconsole/Version-template.java + sun/tools/jconsole/Version.java.template jtreg.tests=\ sun/tools/jconsole/ javadoc.packagenames=\
--- a/make/netbeans/jconsole/build.xml Thu Nov 12 23:00:23 2009 +0000 +++ b/make/netbeans/jconsole/build.xml Thu Nov 12 23:04:42 2009 +0000 @@ -35,7 +35,7 @@ <target name="-pre-compile"> <copy - file="${root}/src/share/classes/sun/tools/jconsole/Version-template.java" + file="${root}/src/share/classes/sun/tools/jconsole/Version.java.template" tofile="${gensrc.dir}/sun/tools/jconsole/Version.java"/> <replace file="${gensrc.dir}/sun/tools/jconsole/Version.java"
--- a/make/sun/awt/mapfile-vers Thu Nov 12 23:00:23 2009 +0000 +++ b/make/sun/awt/mapfile-vers Thu Nov 12 23:04:42 2009 +0000 @@ -53,7 +53,6 @@ Java_sun_awt_image_GifImageDecoder_initIDs; Java_sun_awt_image_GifImageDecoder_parseImage; Java_sun_awt_image_ImageRepresentation_initIDs; - Java_sun_awt_image_ImageRepresentation_setBytePixels; Java_sun_awt_image_ImageRepresentation_setDiffICM; Java_sun_awt_image_ImageRepresentation_setICMpixels; Java_sun_awt_image_ImagingLib_convolveBI;
--- a/make/sun/awt/mapfile-vers-linux Thu Nov 12 23:00:23 2009 +0000 +++ b/make/sun/awt/mapfile-vers-linux Thu Nov 12 23:04:42 2009 +0000 @@ -55,7 +55,6 @@ Java_sun_awt_image_GifImageDecoder_parseImage; Java_sun_awt_image_Image_initIDs; Java_sun_awt_image_ImageRepresentation_initIDs; - Java_sun_awt_image_ImageRepresentation_setBytePixels; Java_sun_awt_image_ImageRepresentation_setDiffICM; Java_sun_awt_image_ImageRepresentation_setICMpixels; Java_sun_awt_image_ImagingLib_convolveBI;
--- a/make/sun/jconsole/Makefile Thu Nov 12 23:00:23 2009 +0000 +++ b/make/sun/jconsole/Makefile Thu Nov 12 23:04:42 2009 +0000 @@ -70,7 +70,7 @@ build: $(FILES_png) $(FILES_gif) $(TEMPDIR)/manifest $(JARFILE) $(GENSRCDIR)/sun/tools/jconsole/Version.java: \ - $(SHARE_SRC)/classes/sun/tools/jconsole/Version-template.java + $(SHARE_SRC)/classes/sun/tools/jconsole/Version.java.template $(MKDIR) -p $(@D) $(SED) -e 's/@@jconsole_version@@/$(FULL_VERSION)/g' $< > $@
--- a/make/sun/nio/Makefile Thu Nov 12 23:00:23 2009 +0000 +++ b/make/sun/nio/Makefile Thu Nov 12 23:04:42 2009 +0000 @@ -44,14 +44,6 @@ include FILES_java.gmk AUTO_FILES_JAVA_DIRS = sun/nio/cs/ext -# Exclude a few sources on windows -ifeq ($(PLATFORM), windows) - AUTO_JAVA_PRUNE = sun/nio/cs/ext/COMPOUND_TEXT.java \ - sun/nio/cs/ext/COMPOUND_TEXT_Decoder.java \ - sun/nio/cs/ext/COMPOUND_TEXT_Encoder.java \ - sun/nio/cs/ext/CompoundTextSupport.java -endif # PLATFORM - # For Cygwin, command line arguments that are paths must be converted to # windows style paths. These paths cannot be used as targets, however, because # the ":" in them will interfere with GNU Make rules, generating "multiple
--- a/make/tools/Makefile Thu Nov 12 23:00:23 2009 +0000 +++ b/make/tools/Makefile Thu Nov 12 23:04:42 2009 +0000 @@ -38,7 +38,6 @@ compile_properties \ dir_diff \ dtdbuilder \ - fontchecker \ freetypecheck \ generate_break_iterator \ GenerateCharacter \
--- a/make/tools/fontchecker/Makefile Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -# -# Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -# CA 95054 USA or visit www.sun.com if you need additional information or -# have any questions. -# - -# -# Makefile for building the fontchecker tool -# - -BUILDDIR = ../.. -PACKAGE = build.tools.fontchecker -PRODUCT = tools -PROGRAM = fontchecker -include $(BUILDDIR)/common/Defs.gmk - -BUILDTOOL_SOURCE_ROOT = $(BUILDDIR)/tools/src -BUILDTOOL_MAIN = $(PKGDIR)/FontChecker.java - -# -# Build tool jar rules. -# -include $(BUILDDIR)/common/BuildToolJar.gmk -
--- a/make/tools/src/build/tools/fontchecker/FontCheckDummy.java Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,175 +0,0 @@ -/* - * Copyright 2002-2004 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 build.tools.fontchecker; - -import java.awt.*; -import java.awt.image.*; -import java.io.*; - -/** - * FontCheckDummy (not unlike Crash Test Dummy). - * - * <PRE> - * FontCheckDummy is the "child" process. Its task is to verify - * integrity of system fonts. Since unexpected crashes are known - * to occur when certain fonts are manipulated, the process is - * "monitored" by the parent process, which might have to restart - * the "child" if it crashes. - * </PRE> - * - * @author Ilya Bagrak - */ -public class FontCheckDummy implements FontCheckerConstants { - - /** - * Input stream from parent process. - */ - private BufferedReader is; - - /** - * Output stream to parent process. - */ - private BufferedOutputStream os; - - /** - * Image on which font characters will be drawn. - */ - private BufferedImage bi; - - /** - * graphics object on which characters will be drawn. - */ - private Graphics graphics; - - /** - * This constructor wraps the process's standard output and input streams - * to enable easier communication with parent process. It also initializes - * the graphics object used for drawing font characters. - * <BR><BR> - * @see FontCheckerConstants - */ - public FontCheckDummy() { - is = new BufferedReader(new InputStreamReader(System.in)); - os = new BufferedOutputStream(System.out); - /* make suffficient space for 12 point font */ - bi = new BufferedImage(40, 40, BufferedImage.TYPE_INT_RGB); - graphics = bi.getGraphics(); - try { - os.write(CHILD_STARTED_OK); - os.flush(); - } catch (IOException e) { - System.exit(-1); - } - } - - /** - * Initializes an instance of Font from given font path. - * <BR> - * This methods attempts to create an instance of font from - * a string that represents path to the font file. - * <BR><BR> - * @param fontPath string representing path to font file - * @param flag indicating whether or not checking of non-TrueType fonts - * is necessary - */ - private void testFont(String fontPath, boolean checkNonTTF) { - - FontFileFilter fff = new FontFileFilter(checkNonTTF); - File fontFile = new File(fontPath); - if (!fontFile.canRead()) { - try { - os.write(ERR_FONT_NOT_FOUND); - os.flush(); - } catch (IOException e) { - System.exit(-1); - } - } - Font font = null; - try { - File file = new File(fontPath); - font = Font.createFont(fff.getFontType(fontPath), file); - } catch (FontFormatException e1) { - } catch (IOException e2) { - } - if (font == null) { - return; - } - font = font.deriveFont(Font.PLAIN, 12); - String name = font.getFontName(); - String family = font.getFamily(); - - char[] testChars = { '0' }; - if (font.canDisplay(testChars[0])) { - graphics.setFont(font); - graphics.drawChars(testChars, 0, 1, 20, 20); - } - try { - os.write(ERR_FONT_OK); - os.flush(); - } catch (IOException e) { - System.exit(-1); - } - } - - /** - * Begins synchronous communication betweeen parent and child processes. - * <BR> - * This method begins communication between parent and child processes. - * FontCheckDummy reads a line of text from input stream (@see #is). - */ - public void run() { - String command = null; - while (true) { - try { - command = is.readLine(); - } catch (IOException e) { - System.exit(-1); - } - if (command != null && command.length() >= 1) { - int cmd = Integer.parseInt(command.substring(0,1)); - if (cmd == EXITCOMMAND) { - return; - } - boolean checkNonTTF = ((cmd == 1) ? true : false); - String fontPath = command.substring(1); - testFont(fontPath, checkNonTTF); - } else { - return; - } - } - } - - public static void main(String[] args) { - try { - /* Background app. */ - System.setProperty("java.awt.headless", "true"); - System.setProperty("sun.java2d.noddraw", "true"); - new FontCheckDummy().run(); - } catch (Throwable t) { - } - System.exit(0); - } -}
--- a/make/tools/src/build/tools/fontchecker/FontChecker.java Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,452 +0,0 @@ -/* - * Copyright 2002-2004 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 build.tools.fontchecker; - -import java.io.*; -import java.util.*; -import java.awt.event.*; -import sun.font.FontManager; - -/** - * FontChecker. - * - * <PRE> - * This is a FontChecker program. This class is a "parent" process - * which invokes a "child" process. The child process will test - * series of fonts and may crash as it encounters invalid fonts. - * The "parent" process must then interpret error codes passed to it - * by the "child" process and restart the "child" process if necessary. - * - * usage: java FontChecker [-v] -o outputfile - * - * -o is the name of the file to contains canonical path names of - * bad fonts that are identified. This file is not created if - * no bad fonts are found. - * -v verbose: prints progress messages. - * - * </PRE> - * - * @author Ilya Bagrak - */ -public class FontChecker implements ActionListener, FontCheckerConstants { - - /** - * Output stream to subprocess. - * Corresponds to the subprocess's System.in". - */ - private PrintWriter procPipeOut; - - /** - * Input stream from subprocess. - * Corresponds to the subprocess's System.out". - */ - private BufferedInputStream procPipeIn; - - /** - * Child process. - */ - private Process childProc; - - /** - * Name of output file to write file names of bad fonts - */ - private String outputFile; - - /** - * Reference to currently executing thread. - */ - private Thread currThread; - - /** - * Timeout timer for a single font check - */ - private javax.swing.Timer timeOne; - - /** - * Timeout timer for all font checks - */ - private javax.swing.Timer timeAll; - - /** - * max time (in milliseconds) allowed for checking a single font. - */ - private static int timeoutOne = 10000; - - /** - * max time (in milliseconds) allowed for checking all fonts. - */ - private static int timeoutAll = 120000; - - /** - * Boolean flag indicating whether FontChecker is required to - * check non-TrueType fonts. - */ - private boolean checkNonTTF = false; - - /** - * List of bad fonts found in the system. - */ - private Vector badFonts = new Vector(); - - /** - * whether to print warnings messges etc to stdout/err - * default is false - */ - private static boolean verbose = false; - - /* Command to use to exec sub-process. */ - private static String javaCmd = "java"; - - static void printlnMessage(String s) { - if (verbose) { - System.out.println(s); - } - } - - /** - * Event handler for timer event. - * <BR> - * Stops the timer and interrupts the current thread which is - * still waiting on I/O from the child process. - * <BR><BR> - * @param evt timer event - */ - public void actionPerformed(ActionEvent evt) { - if (evt.getSource() == timeOne) { - timeOne.stop(); - printlnMessage("Child timed out: killing"); - childProc.destroy(); - } else { - doExit(); // went on too long (ie timeAll timed out). - } - } - - /** - * Initializes a FontChecker. - * <BR> - * This method is usually called after an unrecoverable error has - * been detected and a child process has either crashed or is in bad - * state. The method creates a new child process from - * scratch and initializes it's input/output streams. - */ - public void initialize() { - try { - if (childProc != null) { - childProc.destroy(); - } - String fileSeparator = System.getProperty("file.separator"); - String javaHome = System.getProperty("java.home"); - String classPath = System.getProperty("java.class.path"); - classPath = "\"" + classPath + "\""; - String opt = "-cp " + classPath + " -Dsun.java2d.fontpath=\"" + - javaHome + fileSeparator + "lib" + fileSeparator + "fonts\""; - - /* command to exec the child process with the same JRE */ - String cmd = - new String(javaHome + fileSeparator + "bin" + - fileSeparator + javaCmd + - " -XXsuppressExitMessage " + opt + - " com.sun.java2d.fontchecker.FontCheckDummy"); - printlnMessage("cmd="+cmd); - childProc = Runtime.getRuntime().exec(cmd); - - } catch (IOException e) { - printlnMessage("can't execute child process"); - System.exit(0); - } catch (SecurityException e) { - printlnMessage("Error: access denied"); - System.exit(0); - } - - /* initialize input/output streams to/from child process */ - procPipeOut = new PrintWriter(childProc.getOutputStream()); - procPipeIn = new BufferedInputStream(childProc.getInputStream()); - - try { - int code = procPipeIn.read(); - if (code != CHILD_STARTED_OK) { - printlnMessage("bad child process start status="+code); - doExit(); - } - } catch (IOException e) { - printlnMessage("can't read child process start status unknown"); - doExit(); - } - } - - private void doExit() { - try { - if (procPipeOut != null) { - /* Tell the child to exit */ - procPipeOut.write(EXITCOMMAND+System.getProperty("line.separator")); - procPipeOut.flush(); - procPipeOut.close(); - } - } catch (Throwable t) { - } - System.exit(0); - } - - /** - * Tries to verify integrity of a font specified by a path. - * <BR> - * This method is used to test whether a font specified by the given - * path is valid and does not crash the system. - * <BR><BR> - * @param fontPath a string representation of font path - * to standard out during while this font is tried - * @return returns <code>true</code> if font is OK, and - * <code>false</code> otherwise. - */ - public boolean tryFont(File fontFile) { - int bytesRead = 0; - String fontPath = fontFile.getAbsolutePath(); - - printlnMessage("Checking font "+fontPath); - - /* store reference to the current thread, so that when the timer - * fires it can be interrupted - */ - currThread = Thread.currentThread(); - timeOne.restart(); - - /* write a string command out to child process - * The command is formed by appending whether to test non-TT fonts - * and font path to be tested - */ - String command = Integer.toString(checkNonTTF ? 1 : 0) + - fontPath + - System.getProperty("line.separator"); - procPipeOut.write(command); - procPipeOut.flush(); - - /* check if underlying stream has encountered an error after - * command has been issued - */ - if (procPipeOut.checkError()){ - printlnMessage("Error: font crashed"); - initialize(); - return false; - } - - /* trying reading error code back from child process */ - try { - bytesRead = procPipeIn.read(); - } catch(InterruptedIOException e) { - /* A timeout timer fired before the operation completed */ - printlnMessage("Error: timeout occured"); - initialize(); - return false; - } catch(IOException e) { - /* there was an error reading from the stream */ - timeOne.stop(); - printlnMessage("Error: font crashed"); - initialize(); - return false; - } catch (Throwable t) { - bytesRead = ERR_FONT_READ_EXCPT; - } finally { - timeOne.stop(); - } - - if (bytesRead == ERR_FONT_OK) { - printlnMessage("Font integrity verified"); - return true; - } else if (bytesRead > 0) { - - switch(bytesRead){ - case ERR_FONT_NOT_FOUND: - printlnMessage("Error: font not found!"); - break; - case ERR_FONT_BAD_FORMAT: - printlnMessage("Error: incorrect font format"); - break; - case ERR_FONT_READ_EXCPT: - printlnMessage("Error: exception reading font"); - break; - case ERR_FONT_DISPLAY: - printlnMessage("Error: can't display characters"); - break; - case ERR_FONT_CRASH: - printlnMessage("Error: font crashed"); - break; - default: - printlnMessage("Error: invalid error code:"+bytesRead); - break; - - } - } else if (bytesRead == ERR_FONT_EOS) { - printlnMessage("Error: end of stream marker encountered"); - } else { - printlnMessage("Error: invalid error code:"+bytesRead); - } - - /* if we still haven't returned from this method, some error - * condition has occured and it is safer to re-initialize - */ - initialize(); - return false; - } - - /** - * Checks the integrity of all system fonts. - * <BR> - * This method goes through every font in system's font path and verifies - * its integrity via the tryFont method. - * <BR><BR> - * @param restart <code>true</code> if checking of fonts should continue - * after the first bad font is found, and <code>false</code> otherwise - * @return returns <code>true</code> if all fonts are valid, - * <code>false</code> otherwise - * @see #tryFont(String, boolean, boolean) - */ - public boolean checkFonts(boolean restart) { - - /* file filter to filter out none-truetype font files */ - FontFileFilter fff = new FontFileFilter(checkNonTTF); - boolean checkOk = true; - - /* get platform-independent font path. Note that this bypasses - * the normal GraphicsEnvironment initialisation. In conjunction with - * the headless setting above, so we want to add - * java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(); - * to trigger a more normal initialisation. - */ - java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(); - String fontPath = FontManager.getFontPath(true); - StringTokenizer st = - new StringTokenizer(fontPath, - System.getProperty("path.separator")); - - /* some systems may have multiple font paths separated by - * platform-dependent characters, so fontPath string needs to be - * parsed - */ - timeOne = new javax.swing.Timer(timeoutOne, this); - timeAll = new javax.swing.Timer(timeoutAll, this); - timeAll.restart(); - while (st.hasMoreTokens()) { - File fontRoot = new File(st.nextToken()); - File[] fontFiles = fontRoot.listFiles(fff); - - for (int i = 0; i < fontFiles.length; i++) { - /* for each font file that is not a directory and passes - * through the font filter run the test - */ - if (!fontFiles[i].isDirectory() && - !tryFont(fontFiles[i])) { - - checkOk = false; - badFonts.add(fontFiles[i].getAbsolutePath()); - if (!restart) { - break; - } - } - } - } - - /* Tell the child to exit */ - procPipeOut.write(EXITCOMMAND+System.getProperty("line.separator")); - procPipeOut.flush(); - procPipeOut.close(); - - return checkOk; - } - - public static void main(String args[]){ - try { - /* Background app. */ - System.setProperty("java.awt.headless", "true"); - System.setProperty("sun.java2d.noddraw", "true"); - - boolean restart = true; - boolean errorFlag = false; - - FontChecker fc = new FontChecker(); - int arg = 0; - - while (arg < args.length && errorFlag == false) { - if (args[arg].equals("-v")) { - verbose = true; - } - else if (args[arg].equals("-w") && - System.getProperty("os.name", "unknown"). - startsWith("Windows")) { - javaCmd = "javaw"; - } - else if (args[arg].equals("-o")) { - /* set output file */ - if (++arg < args.length) - fc.outputFile = args[arg]; - else { - /* invalid argument format */ - printlnMessage("Error: invalid argument format"); - errorFlag = true; - } - } - else { - /* invalid command line argument */ - printlnMessage("Error: invalid argument value"); - errorFlag = true; - } - arg++; - } - - if (errorFlag || fc.outputFile == null) { - System.exit(0); - } - - File outfile = new File(fc.outputFile); - if (outfile.exists()) { - outfile.delete(); - } - - fc.initialize(); - - if (!fc.checkFonts(restart)) { - String[] badFonts = (String[])fc.badFonts.toArray(new String[0]); - if (badFonts.length > 0) { - printlnMessage("Bad Fonts:"); - try { - FileOutputStream fos = - new FileOutputStream(fc.outputFile); - PrintStream ps = new PrintStream(fos); - for (int i = 0; i < badFonts.length; i++) { - ps.println(badFonts[i]); - printlnMessage(badFonts[i]); - } - fos.close(); - } catch (IOException e) { - } - } - } else { - printlnMessage("No bad fonts found."); - } - } catch (Throwable t) { - } - System.exit(0); - } -}
--- a/make/tools/src/build/tools/fontchecker/FontCheckerConstants.java Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright 2002-2004 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 build.tools.fontchecker; - -public interface FontCheckerConstants { - - /* code sent to indicate child process started OK */ - public static final int CHILD_STARTED_OK = 100; - - /* error codes returned from child process */ - public static final int ERR_FONT_OK = 65; - public static final int ERR_FONT_NOT_FOUND = 60; - public static final int ERR_FONT_BAD_FORMAT = 61; - public static final int ERR_FONT_READ_EXCPT = 62; - public static final int ERR_FONT_DISPLAY = 64; - public static final int ERR_FONT_EOS = -1; - /* nl char sent after child crashes */ - public static final int ERR_FONT_CRASH = 10; - - /* 0 and 1 are reserved, and commands can only be a single digit integer */ - public static final int EXITCOMMAND = 2; -}
--- a/make/tools/src/build/tools/fontchecker/FontFileFilter.java Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * Copyright 2002-2003 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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. - */ - -/* - * <PRE> - * This class filters TrueType font files from other file - * found in the font path. - * - * </PRE> - * - * @author Ilya Bagrak - */ - -package build.tools.fontchecker; - -import java.awt.*; -import java.io.*; - -public class FontFileFilter implements java.io.FileFilter, FontCheckerConstants { - - /** - * Boolean flag indicating whether this filter filters out - * non-TrueType fonts. - */ - private boolean checkNonTTF; - - public FontFileFilter() { - this(false); - } - - public FontFileFilter(boolean checkNonTTF) { - super(); - this.checkNonTTF = checkNonTTF; - } - - /** - * Checks whether a file is accepted by this filter. - * <BR> - * This method checks whehter a file is accepted by this filter. - * This filter is made to accept all the file whose extension is - * either .ttf or .TTF. These files are assumed to be TrueType fonts. - * <BR><BR> - * @return returns a boolean value indicating whether or not a file is - * accepted - */ - public boolean accept(File pathname) { - - String name = pathname.getName(); - return (name.endsWith(".ttf") || - name.endsWith(".TTF") || - name.endsWith(".ttc") || - name.endsWith(".TTC")) || - (name.endsWith(".pfb") || - name.endsWith(".PFB") || - name.endsWith(".pfa") || - name.endsWith(".PFA") && - checkNonTTF == true); - } - - public static int getFontType(String filename) { - if (filename.endsWith(".ttf") || - filename.endsWith(".TTF") || - filename.endsWith(".ttc") || - filename.endsWith(".TTC")) - return Font.TRUETYPE_FONT; - else if (filename.endsWith(".pfb") || - filename.endsWith(".PFB") || - filename.endsWith(".pfa") || - filename.endsWith(".PFA")) - return Font.TYPE1_FONT; - else - return 999; - } - -}
--- a/make/tools/src/build/tools/fontchecker/README.txt Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * Copyright 2002-2003 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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. - */ -Instructions for running FontChecker ------------------------------------- - -FontChecker is a program designed to identify fonts that may cause JRE -crashes. Such fonts may be corrupted files, or badly constructed fonts. -Some crashes may also be due to bugs in the JRE's font code. -This test is designed to run quickly and silently as part of the JRE -installation process. It will only benefit users who install the JRE -via that mechanism. It cannot guarantee to identify all "bad fonts" because -the tests are minimal. Nor can it prevent problems due to fonts installed -subsequently to the JRE's installation. However it does ensure that the -vast majority of problem fonts are identified. This is important -"RAS" functionality. It is targeted at the consumer/plugin market where -there is substantial likelihood of end-users having installed software -packages which may be delivered with fonts that are not up to commercial -standards. - -The test is designed to be "fail safe". If the program fails to run -properly it has no impact on the installer or on JRE execution. -Thus there is no need to monitor successful execution of the test. - -The test is not a new "tool" in the sense of "javah" etc. -The test is not designed to be user executable or visible, and should -be unpacked by the installer into a temporary location, and executed -once the rest of the JRE is installed (ie as a postinstall step), and -can then be deleted from the temporary location once installation is -complete. Not deleting the jar file before execution is complete is -probably the sole reason that the installer may want to wait for -the program to complete. - -The FontChecker application can be run directly from the jar -file with this command: - %java -jar fontchecker.jar -o <file> - -The output file is a required parameter in this version of the application. -The JRE installer should use the above form, and use it to create an -output file which must be named "badfonts.txt" and be placed into -the JRE's lib\fonts directory eg:- - - java -jar fontchecker.jar -o "C:\Program Files\jre\lib\fonts\badfonts.txt" - -Note the lower case "badfonts.txt", and the string quotes because of the spaces -in the path name. -The location given here is an example and needs to be calculated at install -time as $JREHOME\lib\fonts\badfonts.txt -The location and name are important, because the JRE at runtime will -look for this exactly located name and file. -This location is private to that JRE instance. It will not affect -any other JRE installed on the system. - -If running from a different directory than that containing the jar file, -use the form containing the full path to the jar file, eg : - - java -jar C:\fc\fontchecker.jar -o "C:\Program Files\jre\lib\fonts\badfonts.txt" - -FontChecker application accepts following command line flags. -usage: java -jar fontchecker.jar -o outputfile - -v - - -o is the name of the file to contains canonical path names of - bad fonts that are identified. This file is not created if - no bad fonts are found. - - -v verbose mode: print progress/warning messages. Not recommended - for installer use. - - -w if running on Windows, use "javaw" to exec the sub-process.
--- a/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java Thu Nov 12 23:04:42 2009 +0000 @@ -62,6 +62,8 @@ 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 @@ 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 void sequenceStarted(ImageReader src, int minIndex) {} public void readAborted(ImageReader src) {} } + + private static Boolean isLinkedProfileDisabled = null; + + private static boolean isLinkedProfileAllowed() { + if (isLinkedProfileDisabled == null) { + PrivilegedAction<Boolean> a = new PrivilegedAction<Boolean>() { + public Boolean run() { + return Boolean.getBoolean("sun.imageio.plugins.bmp.disableLinkedProfiles"); + } + }; + isLinkedProfileDisabled = AccessController.doPrivileged(a); + } + return !isLinkedProfileDisabled; + } + + private static Boolean isWindowsPlatform = null; + + /** + * Verifies whether the byte array contans a unc path. + * Non-UNC path examples: + * c:\path\to\file - simple notation + * \\?\c:\path\to\file - long notation + * + * UNC path examples: + * \\server\share - a UNC path in simple notation + * \\?\UNC\server\share - a UNC path in long notation + * \\.\some\device - a path to device. + */ + private static boolean isUncOrDevicePath(byte[] p) { + if (isWindowsPlatform == null) { + PrivilegedAction<Boolean> a = new PrivilegedAction<Boolean>() { + public Boolean run() { + String osname = System.getProperty("os.name"); + return (osname != null && + osname.toLowerCase().startsWith("win")); + } + }; + isWindowsPlatform = AccessController.doPrivileged(a); + } + + if (!isWindowsPlatform) { + /* no need for the check on platforms except windows */ + return false; + } + + /* normalize prefix of the path */ + if (p[0] == '/') p[0] = '\\'; + if (p[1] == '/') p[1] = '\\'; + if (p[3] == '/') p[3] = '\\'; + + + if ((p[0] == '\\') && (p[1] == '\\')) { + if ((p[2] == '?') && (p[3] == '\\')) { + // long path: whether unc or local + return ((p[4] == 'U' || p[4] == 'u') && + (p[5] == 'N' || p[5] == 'n') && + (p[6] == 'C' || p[6] == 'c')); + } else { + // device path or short unc notation + return true; + } + } else { + return false; + } + } }
--- a/src/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -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 @@ */ 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; }
--- a/src/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -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 @@ */ 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 @@ // ******************************** // 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; }
--- a/src/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -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 @@ */ 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; } }
--- a/src/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -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 @@ */ 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 @@ // 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; }
--- a/src/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -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 @@ */ 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 @@ // 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; }
--- a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -35,6 +35,7 @@ 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 @@ */ 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 @@ 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 @@ * 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) {
--- a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -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 @@ // 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 @@ // 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; }
--- a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -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 @@ */ 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; }
--- a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -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 @@ */ 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 @@ // 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; }
--- a/src/share/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -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 @@ */ 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; }
--- a/src/share/classes/com/sun/jndi/ldap/Connection.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/com/sun/jndi/ldap/Connection.java Thu Nov 12 23:04:42 2009 +0000 @@ -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.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 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 @@ 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 @@ try { while (true) { try { - inbuf = new byte[2048]; + inbuf = new byte[10]; offset = 0; seqlen = 0; @@ -871,19 +868,10 @@ } // 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);
--- a/src/share/classes/java/awt/KeyboardFocusManager.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/awt/KeyboardFocusManager.java Thu Nov 12 23:04:42 2009 +0000 @@ -53,7 +53,8 @@ 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 @@ { // 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 @@ */ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ (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 @@ 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 @@ // 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 @@ 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 @@ (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 @@ 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 @@ } 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 @@ } } 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"); } }
--- a/src/share/classes/java/awt/color/ICC_Profile.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/awt/color/ICC_Profile.java Thu Nov 12 23:04:42 2009 +0000 @@ -865,7 +865,9 @@ case ColorSpace.CS_PYCC: synchronized(ICC_Profile.class) { if (PYCCprofile == null) { - if (getProfileFile("PYCC.pf") != null) { + if (!sun.jkernel.DownloadManager.isJREComplete() || + standardProfileExists("PYCC.pf")) + { ProfileDeferralInfo pInfo = new ProfileDeferralInfo("PYCC.pf", ColorSpace.TYPE_3CLR, 3, @@ -963,15 +965,15 @@ * 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 @@ 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<FileInputStream> pa = new PrivilegedAction<FileInputStream>() { + 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,59 +1799,36 @@ * 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 (!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.isFile())) { + while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) { dir = st.nextToken(); fullPath = dir + File.separatorChar + fileName; f = new File(fullPath); @@ -1858,13 +1848,69 @@ } } } - - if (f.isFile()) { + 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 + try { + //kernel uses platform independent paths => + // should not use platform separator char + sun.jkernel.DownloadManager.downloadFile("lib/cmm/"+fileName); + } catch (IOException ioe) {} + } + 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<Boolean>() { + public Boolean run() { + return getStandardProfileFile(fileName) != null; + } + }); + } + /* * Serialization support.
--- a/src/share/classes/java/beans/MetaData.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/beans/MetaData.java Thu Nov 12 23:04:42 2009 +0000 @@ -42,12 +42,11 @@ 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 @@ * @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(); + + 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); + } + } - int nanos = oldTime.getNanos(); - if (nanos != newTime.getNanos()) { - out.writeStatement(new Statement(oldTime, "setNanos", new Object[] {nanos})); + /** + * 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})); } } }
--- a/src/share/classes/java/lang/ClassLoader.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/lang/ClassLoader.java Thu Nov 12 23:04:42 2009 +0000 @@ -186,11 +186,6 @@ 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 @@ private final HashMap<String, Package> packages = new HashMap<String, Package>(); + 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<String, Object>(); + package2certs = new ConcurrentHashMap<String, Certificate[]>(); + domains = + Collections.synchronizedSet(new HashSet<ProtectionDomain>()); + assertionLock = new Object(); + } else { + // no finer-grained lock; lock on the classloader instance + parallelLockMap = null; + package2certs = new Hashtable<String, Certificate[]>(); + domains = new HashSet<ProtectionDomain>(); + assertionLock = this; + } + } + /** * Creates a new class loader using the specified parent class loader for * delegation. @@ -252,25 +272,7 @@ * @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<String, Object>(); - package2certs = new ConcurrentHashMap<String, Certificate[]>(); - domains = - Collections.synchronizedSet(new HashSet<ProtectionDomain>()); - assertionLock = new Object(); - } else { - // no finer-grained lock; lock on the classloader instance - parallelLockMap = null; - package2certs = new Hashtable<String, Certificate[]>(); - domains = new HashSet<ProtectionDomain>(); - assertionLock = this; - } - initialized = true; + this(checkCreateClassLoader(), parent); } /** @@ -289,25 +291,7 @@ * 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<String, Object>(); - package2certs = new ConcurrentHashMap<String, Certificate[]>(); - domains = - Collections.synchronizedSet(new HashSet<ProtectionDomain>()); - assertionLock = new Object(); - } else { - // no finer-grained lock; lock on the classloader instance - parallelLockMap = null; - package2certs = new Hashtable<String, Certificate[]>(); - domains = new HashSet<ProtectionDomain>(); - assertionLock = this; - } - initialized = true; + this(checkCreateClassLoader(), getSystemClassLoader()); } // -- Class -- @@ -754,7 +738,6 @@ ProtectionDomain protectionDomain) throws ClassFormatError { - check(); protectionDomain = preDefineClass(name, protectionDomain); Class c = null; @@ -838,8 +821,6 @@ ProtectionDomain protectionDomain) throws ClassFormatError { - check(); - int len = b.remaining(); // Use byte[] if not a direct ByteBufer: @@ -984,7 +965,6 @@ * @see #defineClass(String, byte[], int, int) */ protected final void resolveClass(Class<?> c) { - check(); resolveClass0(c); } @@ -1015,7 +995,6 @@ protected final Class<?> findSystemClass(String name) throws ClassNotFoundException { - check(); ClassLoader system = getSystemClassLoader(); if (system == null) { if (!checkName(name)) @@ -1035,7 +1014,6 @@ */ private Class findBootstrapClassOrNull(String name) { - check(); if (!checkName(name)) return null; return findBootstrapClass(name); @@ -1044,13 +1022,6 @@ // 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 <a href="#name">binary name</a> if this * loader has been recorded by the Java virtual machine as an initiating @@ -1066,7 +1037,6 @@ * @since 1.1 */ protected final Class<?> findLoadedClass(String name) { - check(); if (!checkName(name)) return null; return findLoadedClass0(name); @@ -1087,7 +1057,6 @@ * @since 1.1 */ protected final void setSigners(Class<?> c, Object[] signers) { - check(); c.setSigners(signers); } @@ -2205,3 +2174,4 @@ return sys; } } +
--- a/src/share/classes/java/math/BigInteger.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/math/BigInteger.java Thu Nov 12 23:04:42 2009 +0000 @@ -288,11 +288,11 @@ */ 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 @@ // 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 @@ // 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)
--- a/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,219 +0,0 @@ -/* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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. - */ - -#warn This file is preprocessed before being compiled - -package java.nio; - - -class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private - extends {#if[ro]?ByteBufferAs}$Type$Buffer{#if[ro]?$BO$} -{ - -#if[rw] - - protected final ByteBuffer bb; - protected final int offset; - -#end[rw] - - ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb) { // package-private -#if[rw] - super(-1, 0, - bb.remaining() >> $LG_BYTES_PER_VALUE$, - bb.remaining() >> $LG_BYTES_PER_VALUE$); - this.bb = bb; - // enforce limit == capacity - int cap = this.capacity(); - this.limit(cap); - int pos = this.position(); - assert (pos <= cap); - offset = pos; -#else[rw] - super(bb); -#end[rw] - } - - ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb, - int mark, int pos, int lim, int cap, - int off) - { -#if[rw] - super(mark, pos, lim, cap); - this.bb = bb; - offset = off; -#else[rw] - super(bb, mark, pos, lim, cap, off); -#end[rw] - } - - public $Type$Buffer slice() { - int pos = this.position(); - int lim = this.limit(); - assert (pos <= lim); - int rem = (pos <= lim ? lim - pos : 0); - int off = (pos << $LG_BYTES_PER_VALUE$) + offset; - assert (off >= 0); - return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, -1, 0, rem, rem, off); - } - - public $Type$Buffer duplicate() { - return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, - this.markValue(), - this.position(), - this.limit(), - this.capacity(), - offset); - } - - public $Type$Buffer asReadOnlyBuffer() { -#if[rw] - return new ByteBufferAs$Type$BufferR$BO$(bb, - this.markValue(), - this.position(), - this.limit(), - this.capacity(), - offset); -#else[rw] - return duplicate(); -#end[rw] - } - -#if[rw] - - protected int ix(int i) { - return (i << $LG_BYTES_PER_VALUE$) + offset; - } - - public $type$ get() { - return Bits.get$Type$$BO$(bb, ix(nextGetIndex())); - } - - public $type$ get(int i) { - return Bits.get$Type$$BO$(bb, ix(checkIndex(i))); - } - -#end[rw] - - public $Type$Buffer put($type$ x) { -#if[rw] - Bits.put$Type$$BO$(bb, ix(nextPutIndex()), x); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer put(int i, $type$ x) { -#if[rw] - Bits.put$Type$$BO$(bb, ix(checkIndex(i)), x); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer compact() { -#if[rw] - int pos = position(); - int lim = limit(); - assert (pos <= lim); - int rem = (pos <= lim ? lim - pos : 0); - - ByteBuffer db = bb.duplicate(); - db.limit(ix(lim)); - db.position(ix(0)); - ByteBuffer sb = db.slice(); - sb.position(pos << $LG_BYTES_PER_VALUE$); - sb.compact(); - position(rem); - limit(capacity()); - discardMark(); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public boolean isDirect() { - return bb.isDirect(); - } - - public boolean isReadOnly() { - return {#if[rw]?false:true}; - } - -#if[char] - - public String toString(int start, int end) { - if ((end > limit()) || (start > end)) - throw new IndexOutOfBoundsException(); - try { - int len = end - start; - char[] ca = new char[len]; - CharBuffer cb = CharBuffer.wrap(ca); - CharBuffer db = this.duplicate(); - db.position(start); - db.limit(end); - cb.put(db); - return new String(ca); - } catch (StringIndexOutOfBoundsException x) { - throw new IndexOutOfBoundsException(); - } - } - - - // --- Methods to support CharSequence --- - - public CharBuffer subSequence(int start, int end) { - int pos = position(); - int lim = limit(); - assert (pos <= lim); - pos = (pos <= lim ? pos : lim); - int len = lim - pos; - - if ((start < 0) || (end > len) || (start > end)) - throw new IndexOutOfBoundsException(); - return new ByteBufferAsCharBuffer$RW$$BO$(bb, - -1, - pos + start, - pos + end, - capacity(), - offset); - } - -#end[char] - - - public ByteOrder order() { -#if[boB] - return ByteOrder.BIG_ENDIAN; -#end[boB] -#if[boL] - return ByteOrder.LITTLE_ENDIAN; -#end[boL] - } - -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,219 @@ +/* + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +#warn This file is preprocessed before being compiled + +package java.nio; + + +class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private + extends {#if[ro]?ByteBufferAs}$Type$Buffer{#if[ro]?$BO$} +{ + +#if[rw] + + protected final ByteBuffer bb; + protected final int offset; + +#end[rw] + + ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb) { // package-private +#if[rw] + super(-1, 0, + bb.remaining() >> $LG_BYTES_PER_VALUE$, + bb.remaining() >> $LG_BYTES_PER_VALUE$); + this.bb = bb; + // enforce limit == capacity + int cap = this.capacity(); + this.limit(cap); + int pos = this.position(); + assert (pos <= cap); + offset = pos; +#else[rw] + super(bb); +#end[rw] + } + + ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb, + int mark, int pos, int lim, int cap, + int off) + { +#if[rw] + super(mark, pos, lim, cap); + this.bb = bb; + offset = off; +#else[rw] + super(bb, mark, pos, lim, cap, off); +#end[rw] + } + + public $Type$Buffer slice() { + int pos = this.position(); + int lim = this.limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + int off = (pos << $LG_BYTES_PER_VALUE$) + offset; + assert (off >= 0); + return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, -1, 0, rem, rem, off); + } + + public $Type$Buffer duplicate() { + return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, + this.markValue(), + this.position(), + this.limit(), + this.capacity(), + offset); + } + + public $Type$Buffer asReadOnlyBuffer() { +#if[rw] + return new ByteBufferAs$Type$BufferR$BO$(bb, + this.markValue(), + this.position(), + this.limit(), + this.capacity(), + offset); +#else[rw] + return duplicate(); +#end[rw] + } + +#if[rw] + + protected int ix(int i) { + return (i << $LG_BYTES_PER_VALUE$) + offset; + } + + public $type$ get() { + return Bits.get$Type$$BO$(bb, ix(nextGetIndex())); + } + + public $type$ get(int i) { + return Bits.get$Type$$BO$(bb, ix(checkIndex(i))); + } + +#end[rw] + + public $Type$Buffer put($type$ x) { +#if[rw] + Bits.put$Type$$BO$(bb, ix(nextPutIndex()), x); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer put(int i, $type$ x) { +#if[rw] + Bits.put$Type$$BO$(bb, ix(checkIndex(i)), x); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer compact() { +#if[rw] + int pos = position(); + int lim = limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + + ByteBuffer db = bb.duplicate(); + db.limit(ix(lim)); + db.position(ix(0)); + ByteBuffer sb = db.slice(); + sb.position(pos << $LG_BYTES_PER_VALUE$); + sb.compact(); + position(rem); + limit(capacity()); + discardMark(); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public boolean isDirect() { + return bb.isDirect(); + } + + public boolean isReadOnly() { + return {#if[rw]?false:true}; + } + +#if[char] + + public String toString(int start, int end) { + if ((end > limit()) || (start > end)) + throw new IndexOutOfBoundsException(); + try { + int len = end - start; + char[] ca = new char[len]; + CharBuffer cb = CharBuffer.wrap(ca); + CharBuffer db = this.duplicate(); + db.position(start); + db.limit(end); + cb.put(db); + return new String(ca); + } catch (StringIndexOutOfBoundsException x) { + throw new IndexOutOfBoundsException(); + } + } + + + // --- Methods to support CharSequence --- + + public CharBuffer subSequence(int start, int end) { + int pos = position(); + int lim = limit(); + assert (pos <= lim); + pos = (pos <= lim ? pos : lim); + int len = lim - pos; + + if ((start < 0) || (end > len) || (start > end)) + throw new IndexOutOfBoundsException(); + return new ByteBufferAsCharBuffer$RW$$BO$(bb, + -1, + pos + start, + pos + end, + capacity(), + offset); + } + +#end[char] + + + public ByteOrder order() { +#if[boB] + return ByteOrder.BIG_ENDIAN; +#end[boB] +#if[boL] + return ByteOrder.LITTLE_ENDIAN; +#end[boL] + } + +}
--- a/src/share/classes/java/nio/Direct-X-Buffer-bin.java Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/* - * Copyright 2000-2003 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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. - */ - -#warn This file is preprocessed before being compiled - -class XXX { - -#begin - -#if[rw] - - private $type$ get$Type$(long a) { - if (unaligned) { - $memtype$ x = unsafe.get$Memtype$(a); - return $fromBits$(nativeByteOrder ? x : Bits.swap(x)); - } - return Bits.get$Type$(a, bigEndian); - } - - public $type$ get$Type$() { - return get$Type$(ix(nextGetIndex($BYTES_PER_VALUE$))); - } - - public $type$ get$Type$(int i) { - return get$Type$(ix(checkIndex(i, $BYTES_PER_VALUE$))); - } - -#end[rw] - - private ByteBuffer put$Type$(long a, $type$ x) { -#if[rw] - if (unaligned) { - $memtype$ y = $toBits$(x); - unsafe.put$Memtype$(a, (nativeByteOrder ? y : Bits.swap(y))); - } else { - Bits.put$Type$(a, x, bigEndian); - } - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public ByteBuffer put$Type$($type$ x) { -#if[rw] - put$Type$(ix(nextPutIndex($BYTES_PER_VALUE$)), x); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public ByteBuffer put$Type$(int i, $type$ x) { -#if[rw] - put$Type$(ix(checkIndex(i, $BYTES_PER_VALUE$)), x); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer as$Type$Buffer() { - int off = this.position(); - int lim = this.limit(); - assert (off <= lim); - int rem = (off <= lim ? lim - off : 0); - - int size = rem >> $LG_BYTES_PER_VALUE$; - if (!unaligned && ((address + off) % $BYTES_PER_VALUE$ != 0)) { - return (bigEndian - ? ($Type$Buffer)(new ByteBufferAs$Type$Buffer$RW$B(this, - -1, - 0, - size, - size, - off)) - : ($Type$Buffer)(new ByteBufferAs$Type$Buffer$RW$L(this, - -1, - 0, - size, - size, - off))); - } else { - return (nativeByteOrder - ? ($Type$Buffer)(new Direct$Type$Buffer$RW$U(this, - -1, - 0, - size, - size, - off)) - : ($Type$Buffer)(new Direct$Type$Buffer$RW$S(this, - -1, - 0, - size, - size, - off))); - } - } - -#end - -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/nio/Direct-X-Buffer-bin.java.template Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,124 @@ +/* + * Copyright 2000-2003 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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. + */ + +#warn This file is preprocessed before being compiled + +class XXX { + +#begin + +#if[rw] + + private $type$ get$Type$(long a) { + if (unaligned) { + $memtype$ x = unsafe.get$Memtype$(a); + return $fromBits$(nativeByteOrder ? x : Bits.swap(x)); + } + return Bits.get$Type$(a, bigEndian); + } + + public $type$ get$Type$() { + return get$Type$(ix(nextGetIndex($BYTES_PER_VALUE$))); + } + + public $type$ get$Type$(int i) { + return get$Type$(ix(checkIndex(i, $BYTES_PER_VALUE$))); + } + +#end[rw] + + private ByteBuffer put$Type$(long a, $type$ x) { +#if[rw] + if (unaligned) { + $memtype$ y = $toBits$(x); + unsafe.put$Memtype$(a, (nativeByteOrder ? y : Bits.swap(y))); + } else { + Bits.put$Type$(a, x, bigEndian); + } + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public ByteBuffer put$Type$($type$ x) { +#if[rw] + put$Type$(ix(nextPutIndex($BYTES_PER_VALUE$)), x); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public ByteBuffer put$Type$(int i, $type$ x) { +#if[rw] + put$Type$(ix(checkIndex(i, $BYTES_PER_VALUE$)), x); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer as$Type$Buffer() { + int off = this.position(); + int lim = this.limit(); + assert (off <= lim); + int rem = (off <= lim ? lim - off : 0); + + int size = rem >> $LG_BYTES_PER_VALUE$; + if (!unaligned && ((address + off) % $BYTES_PER_VALUE$ != 0)) { + return (bigEndian + ? ($Type$Buffer)(new ByteBufferAs$Type$Buffer$RW$B(this, + -1, + 0, + size, + size, + off)) + : ($Type$Buffer)(new ByteBufferAs$Type$Buffer$RW$L(this, + -1, + 0, + size, + size, + off))); + } else { + return (nativeByteOrder + ? ($Type$Buffer)(new Direct$Type$Buffer$RW$U(this, + -1, + 0, + size, + size, + off)) + : ($Type$Buffer)(new Direct$Type$Buffer$RW$S(this, + -1, + 0, + size, + size, + off))); + } + } + +#end + +}
--- a/src/share/classes/java/nio/Direct-X-Buffer.java Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,464 +0,0 @@ -/* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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. - */ - -#warn This file is preprocessed before being compiled - -package java.nio; - -import sun.misc.Cleaner; -import sun.misc.Unsafe; -import sun.nio.ch.DirectBuffer; - - -class Direct$Type$Buffer$RW$$BO$ -#if[rw] - extends {#if[byte]?Mapped$Type$Buffer:$Type$Buffer} -#else[rw] - extends Direct$Type$Buffer$BO$ -#end[rw] - implements DirectBuffer -{ - -#if[rw] - - // Cached unsafe-access object - protected static final Unsafe unsafe = Bits.unsafe(); - - // Cached array base offset - private static final long arrayBaseOffset = (long)unsafe.arrayBaseOffset($type$[].class); - - // Cached unaligned-access capability - protected static final boolean unaligned = Bits.unaligned(); - - // Base address, used in all indexing calculations - // NOTE: moved up to Buffer.java for speed in JNI GetDirectBufferAddress - // protected long address; - - // If this buffer is a view of another buffer then we keep a reference to - // that buffer so that its memory isn't freed before we're done with it - protected Object viewedBuffer = null; - - public Object viewedBuffer() { - return viewedBuffer; - } - -#if[byte] - - private static class Deallocator - implements Runnable - { - - private static Unsafe unsafe = Unsafe.getUnsafe(); - - private long address; - private long size; - private int capacity; - - private Deallocator(long address, long size, int capacity) { - assert (address != 0); - this.address = address; - this.size = size; - this.capacity = capacity; - } - - public void run() { - if (address == 0) { - // Paranoia - return; - } - unsafe.freeMemory(address); - address = 0; - Bits.unreserveMemory(size, capacity); - } - - } - - private final Cleaner cleaner; - - public Cleaner cleaner() { return cleaner; } - -#else[byte] - - public Cleaner cleaner() { return null; } - -#end[byte] - -#end[rw] - -#if[byte] - - // Primary constructor - // - Direct$Type$Buffer$RW$(int cap) { // package-private -#if[rw] - super(-1, 0, cap, cap, false); - int ps = Bits.pageSize(); - int size = cap + ps; - Bits.reserveMemory(size, cap); - - long base = 0; - try { - base = unsafe.allocateMemory(size); - } catch (OutOfMemoryError x) { - Bits.unreserveMemory(size, cap); - throw x; - } - unsafe.setMemory(base, size, (byte) 0); - if (base % ps != 0) { - // Round up to page boundary - address = base + ps - (base & (ps - 1)); - } else { - address = base; - } - cleaner = Cleaner.create(this, new Deallocator(base, size, cap)); -#else[rw] - super(cap); -#end[rw] - } - -#if[rw] - - // Invoked only by JNI: NewDirectByteBuffer(void*, long) - // - private Direct$Type$Buffer(long addr, int cap) { - super(-1, 0, cap, cap, false); - address = addr; - cleaner = null; - } - -#end[rw] - - // For memory-mapped buffers -- invoked by FileChannelImpl via reflection - // - protected Direct$Type$Buffer$RW$(int cap, long addr, Runnable unmapper) { -#if[rw] - super(-1, 0, cap, cap, true); - address = addr; - viewedBuffer = null; - cleaner = Cleaner.create(this, unmapper); -#else[rw] - super(cap, addr, unmapper); -#end[rw] - } - -#end[byte] - - // For duplicates and slices - // - Direct$Type$Buffer$RW$$BO$(DirectBuffer db, // package-private - int mark, int pos, int lim, int cap, - int off) - { -#if[rw] - super(mark, pos, lim, cap); - address = db.address() + off; - viewedBuffer = db; -#if[byte] - cleaner = null; -#end[byte] -#else[rw] - super(db, mark, pos, lim, cap, off); -#end[rw] - } - - public $Type$Buffer slice() { - int pos = this.position(); - int lim = this.limit(); - assert (pos <= lim); - int rem = (pos <= lim ? lim - pos : 0); - int off = (pos << $LG_BYTES_PER_VALUE$); - assert (off >= 0); - return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, off); - } - - public $Type$Buffer duplicate() { - return new Direct$Type$Buffer$RW$$BO$(this, - this.markValue(), - this.position(), - this.limit(), - this.capacity(), - 0); - } - - public $Type$Buffer asReadOnlyBuffer() { -#if[rw] - return new Direct$Type$BufferR$BO$(this, - this.markValue(), - this.position(), - this.limit(), - this.capacity(), - 0); -#else[rw] - return duplicate(); -#end[rw] - } - -#if[rw] - - public long address() { - return address; - } - - private long ix(int i) { - return address + (i << $LG_BYTES_PER_VALUE$); - } - - public $type$ get() { - return $fromBits$($swap$(unsafe.get$Swaptype$(ix(nextGetIndex())))); - } - - public $type$ get(int i) { - return $fromBits$($swap$(unsafe.get$Swaptype$(ix(checkIndex(i))))); - } - - public $Type$Buffer get($type$[] dst, int offset, int length) { -#if[rw] - if ((length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) { - checkBounds(offset, length, dst.length); - int pos = position(); - int lim = limit(); - assert (pos <= lim); - int rem = (pos <= lim ? lim - pos : 0); - if (length > rem) - throw new BufferUnderflowException(); - -#if[!byte] - if (order() != ByteOrder.nativeOrder()) - Bits.copyTo$Memtype$Array(ix(pos), dst, - offset << $LG_BYTES_PER_VALUE$, - length << $LG_BYTES_PER_VALUE$); - else -#end[!byte] - Bits.copyToArray(ix(pos), dst, arrayBaseOffset, - offset << $LG_BYTES_PER_VALUE$, - length << $LG_BYTES_PER_VALUE$); - position(pos + length); - } else { - super.get(dst, offset, length); - } - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - -#end[rw] - - public $Type$Buffer put($type$ x) { -#if[rw] - unsafe.put$Swaptype$(ix(nextPutIndex()), $swap$($toBits$(x))); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer put(int i, $type$ x) { -#if[rw] - unsafe.put$Swaptype$(ix(checkIndex(i)), $swap$($toBits$(x))); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer put($Type$Buffer src) { -#if[rw] - if (src instanceof Direct$Type$Buffer$BO$) { - if (src == this) - throw new IllegalArgumentException(); - Direct$Type$Buffer$RW$$BO$ sb = (Direct$Type$Buffer$RW$$BO$)src; - - int spos = sb.position(); - int slim = sb.limit(); - assert (spos <= slim); - int srem = (spos <= slim ? slim - spos : 0); - - int pos = position(); - int lim = limit(); - assert (pos <= lim); - int rem = (pos <= lim ? lim - pos : 0); - - if (srem > rem) - throw new BufferOverflowException(); - unsafe.copyMemory(sb.ix(spos), ix(pos), srem << $LG_BYTES_PER_VALUE$); - sb.position(spos + srem); - position(pos + srem); - } else if (src.hb != null) { - - int spos = src.position(); - int slim = src.limit(); - assert (spos <= slim); - int srem = (spos <= slim ? slim - spos : 0); - - put(src.hb, src.offset + spos, srem); - src.position(spos + srem); - - } else { - super.put(src); - } - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer put($type$[] src, int offset, int length) { -#if[rw] - if ((length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_FROM_ARRAY_THRESHOLD) { - checkBounds(offset, length, src.length); - int pos = position(); - int lim = limit(); - assert (pos <= lim); - int rem = (pos <= lim ? lim - pos : 0); - if (length > rem) - throw new BufferOverflowException(); - -#if[!byte] - if (order() != ByteOrder.nativeOrder()) - Bits.copyFrom$Memtype$Array(src, offset << $LG_BYTES_PER_VALUE$, - ix(pos), length << $LG_BYTES_PER_VALUE$); - else -#end[!byte] - Bits.copyFromArray(src, arrayBaseOffset, offset << $LG_BYTES_PER_VALUE$, - ix(pos), length << $LG_BYTES_PER_VALUE$); - position(pos + length); - } else { - super.put(src, offset, length); - } - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer compact() { -#if[rw] - int pos = position(); - int lim = limit(); - assert (pos <= lim); - int rem = (pos <= lim ? lim - pos : 0); - - unsafe.copyMemory(ix(pos), ix(0), rem << $LG_BYTES_PER_VALUE$); - position(rem); - limit(capacity()); - discardMark(); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public boolean isDirect() { - return true; - } - - public boolean isReadOnly() { - return {#if[rw]?false:true}; - } - - -#if[char] - - public String toString(int start, int end) { - if ((end > limit()) || (start > end)) - throw new IndexOutOfBoundsException(); - try { - int len = end - start; - char[] ca = new char[len]; - CharBuffer cb = CharBuffer.wrap(ca); - CharBuffer db = this.duplicate(); - db.position(start); - db.limit(end); - cb.put(db); - return new String(ca); - } catch (StringIndexOutOfBoundsException x) { - throw new IndexOutOfBoundsException(); - } - } - - - // --- Methods to support CharSequence --- - - public CharBuffer subSequence(int start, int end) { - int pos = position(); - int lim = limit(); - assert (pos <= lim); - pos = (pos <= lim ? pos : lim); - int len = lim - pos; - - if ((start < 0) || (end > len) || (start > end)) - throw new IndexOutOfBoundsException(); - return new DirectCharBuffer$RW$$BO$(this, - -1, - pos + start, - pos + end, - capacity(), - offset); - } - -#end[char] - - - -#if[!byte] - - public ByteOrder order() { -#if[boS] - return ((ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) - ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); -#end[boS] -#if[boU] - return ((ByteOrder.nativeOrder() != ByteOrder.BIG_ENDIAN) - ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); -#end[boU] - } - -#end[!byte] - - - -#if[byte] - - byte _get(int i) { // package-private - return unsafe.getByte(address + i); - } - - void _put(int i, byte b) { // package-private -#if[rw] - unsafe.putByte(address + i, b); -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - // #BIN - // - // Binary-data access methods for short, char, int, long, float, - // and double will be inserted here - -#end[byte] - -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/nio/Direct-X-Buffer.java.template Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,464 @@ +/* + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +#warn This file is preprocessed before being compiled + +package java.nio; + +import sun.misc.Cleaner; +import sun.misc.Unsafe; +import sun.nio.ch.DirectBuffer; + + +class Direct$Type$Buffer$RW$$BO$ +#if[rw] + extends {#if[byte]?Mapped$Type$Buffer:$Type$Buffer} +#else[rw] + extends Direct$Type$Buffer$BO$ +#end[rw] + implements DirectBuffer +{ + +#if[rw] + + // Cached unsafe-access object + protected static final Unsafe unsafe = Bits.unsafe(); + + // Cached array base offset + private static final long arrayBaseOffset = (long)unsafe.arrayBaseOffset($type$[].class); + + // Cached unaligned-access capability + protected static final boolean unaligned = Bits.unaligned(); + + // Base address, used in all indexing calculations + // NOTE: moved up to Buffer.java for speed in JNI GetDirectBufferAddress + // protected long address; + + // If this buffer is a view of another buffer then we keep a reference to + // that buffer so that its memory isn't freed before we're done with it + protected Object viewedBuffer = null; + + public Object viewedBuffer() { + return viewedBuffer; + } + +#if[byte] + + private static class Deallocator + implements Runnable + { + + private static Unsafe unsafe = Unsafe.getUnsafe(); + + private long address; + private long size; + private int capacity; + + private Deallocator(long address, long size, int capacity) { + assert (address != 0); + this.address = address; + this.size = size; + this.capacity = capacity; + } + + public void run() { + if (address == 0) { + // Paranoia + return; + } + unsafe.freeMemory(address); + address = 0; + Bits.unreserveMemory(size, capacity); + } + + } + + private final Cleaner cleaner; + + public Cleaner cleaner() { return cleaner; } + +#else[byte] + + public Cleaner cleaner() { return null; } + +#end[byte] + +#end[rw] + +#if[byte] + + // Primary constructor + // + Direct$Type$Buffer$RW$(int cap) { // package-private +#if[rw] + super(-1, 0, cap, cap, false); + int ps = Bits.pageSize(); + int size = cap + ps; + Bits.reserveMemory(size, cap); + + long base = 0; + try { + base = unsafe.allocateMemory(size); + } catch (OutOfMemoryError x) { + Bits.unreserveMemory(size, cap); + throw x; + } + unsafe.setMemory(base, size, (byte) 0); + if (base % ps != 0) { + // Round up to page boundary + address = base + ps - (base & (ps - 1)); + } else { + address = base; + } + cleaner = Cleaner.create(this, new Deallocator(base, size, cap)); +#else[rw] + super(cap); +#end[rw] + } + +#if[rw] + + // Invoked only by JNI: NewDirectByteBuffer(void*, long) + // + private Direct$Type$Buffer(long addr, int cap) { + super(-1, 0, cap, cap, false); + address = addr; + cleaner = null; + } + +#end[rw] + + // For memory-mapped buffers -- invoked by FileChannelImpl via reflection + // + protected Direct$Type$Buffer$RW$(int cap, long addr, Runnable unmapper) { +#if[rw] + super(-1, 0, cap, cap, true); + address = addr; + viewedBuffer = null; + cleaner = Cleaner.create(this, unmapper); +#else[rw] + super(cap, addr, unmapper); +#end[rw] + } + +#end[byte] + + // For duplicates and slices + // + Direct$Type$Buffer$RW$$BO$(DirectBuffer db, // package-private + int mark, int pos, int lim, int cap, + int off) + { +#if[rw] + super(mark, pos, lim, cap); + address = db.address() + off; + viewedBuffer = db; +#if[byte] + cleaner = null; +#end[byte] +#else[rw] + super(db, mark, pos, lim, cap, off); +#end[rw] + } + + public $Type$Buffer slice() { + int pos = this.position(); + int lim = this.limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + int off = (pos << $LG_BYTES_PER_VALUE$); + assert (off >= 0); + return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, off); + } + + public $Type$Buffer duplicate() { + return new Direct$Type$Buffer$RW$$BO$(this, + this.markValue(), + this.position(), + this.limit(), + this.capacity(), + 0); + } + + public $Type$Buffer asReadOnlyBuffer() { +#if[rw] + return new Direct$Type$BufferR$BO$(this, + this.markValue(), + this.position(), + this.limit(), + this.capacity(), + 0); +#else[rw] + return duplicate(); +#end[rw] + } + +#if[rw] + + public long address() { + return address; + } + + private long ix(int i) { + return address + (i << $LG_BYTES_PER_VALUE$); + } + + public $type$ get() { + return $fromBits$($swap$(unsafe.get$Swaptype$(ix(nextGetIndex())))); + } + + public $type$ get(int i) { + return $fromBits$($swap$(unsafe.get$Swaptype$(ix(checkIndex(i))))); + } + + public $Type$Buffer get($type$[] dst, int offset, int length) { +#if[rw] + if ((length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) { + checkBounds(offset, length, dst.length); + int pos = position(); + int lim = limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + if (length > rem) + throw new BufferUnderflowException(); + +#if[!byte] + if (order() != ByteOrder.nativeOrder()) + Bits.copyTo$Memtype$Array(ix(pos), dst, + offset << $LG_BYTES_PER_VALUE$, + length << $LG_BYTES_PER_VALUE$); + else +#end[!byte] + Bits.copyToArray(ix(pos), dst, arrayBaseOffset, + offset << $LG_BYTES_PER_VALUE$, + length << $LG_BYTES_PER_VALUE$); + position(pos + length); + } else { + super.get(dst, offset, length); + } + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + +#end[rw] + + public $Type$Buffer put($type$ x) { +#if[rw] + unsafe.put$Swaptype$(ix(nextPutIndex()), $swap$($toBits$(x))); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer put(int i, $type$ x) { +#if[rw] + unsafe.put$Swaptype$(ix(checkIndex(i)), $swap$($toBits$(x))); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer put($Type$Buffer src) { +#if[rw] + if (src instanceof Direct$Type$Buffer$BO$) { + if (src == this) + throw new IllegalArgumentException(); + Direct$Type$Buffer$RW$$BO$ sb = (Direct$Type$Buffer$RW$$BO$)src; + + int spos = sb.position(); + int slim = sb.limit(); + assert (spos <= slim); + int srem = (spos <= slim ? slim - spos : 0); + + int pos = position(); + int lim = limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + + if (srem > rem) + throw new BufferOverflowException(); + unsafe.copyMemory(sb.ix(spos), ix(pos), srem << $LG_BYTES_PER_VALUE$); + sb.position(spos + srem); + position(pos + srem); + } else if (src.hb != null) { + + int spos = src.position(); + int slim = src.limit(); + assert (spos <= slim); + int srem = (spos <= slim ? slim - spos : 0); + + put(src.hb, src.offset + spos, srem); + src.position(spos + srem); + + } else { + super.put(src); + } + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer put($type$[] src, int offset, int length) { +#if[rw] + if ((length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_FROM_ARRAY_THRESHOLD) { + checkBounds(offset, length, src.length); + int pos = position(); + int lim = limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + if (length > rem) + throw new BufferOverflowException(); + +#if[!byte] + if (order() != ByteOrder.nativeOrder()) + Bits.copyFrom$Memtype$Array(src, offset << $LG_BYTES_PER_VALUE$, + ix(pos), length << $LG_BYTES_PER_VALUE$); + else +#end[!byte] + Bits.copyFromArray(src, arrayBaseOffset, offset << $LG_BYTES_PER_VALUE$, + ix(pos), length << $LG_BYTES_PER_VALUE$); + position(pos + length); + } else { + super.put(src, offset, length); + } + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer compact() { +#if[rw] + int pos = position(); + int lim = limit(); + assert (pos <= lim); + int rem = (pos <= lim ? lim - pos : 0); + + unsafe.copyMemory(ix(pos), ix(0), rem << $LG_BYTES_PER_VALUE$); + position(rem); + limit(capacity()); + discardMark(); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public boolean isDirect() { + return true; + } + + public boolean isReadOnly() { + return {#if[rw]?false:true}; + } + + +#if[char] + + public String toString(int start, int end) { + if ((end > limit()) || (start > end)) + throw new IndexOutOfBoundsException(); + try { + int len = end - start; + char[] ca = new char[len]; + CharBuffer cb = CharBuffer.wrap(ca); + CharBuffer db = this.duplicate(); + db.position(start); + db.limit(end); + cb.put(db); + return new String(ca); + } catch (StringIndexOutOfBoundsException x) { + throw new IndexOutOfBoundsException(); + } + } + + + // --- Methods to support CharSequence --- + + public CharBuffer subSequence(int start, int end) { + int pos = position(); + int lim = limit(); + assert (pos <= lim); + pos = (pos <= lim ? pos : lim); + int len = lim - pos; + + if ((start < 0) || (end > len) || (start > end)) + throw new IndexOutOfBoundsException(); + return new DirectCharBuffer$RW$$BO$(this, + -1, + pos + start, + pos + end, + capacity(), + offset); + } + +#end[char] + + + +#if[!byte] + + public ByteOrder order() { +#if[boS] + return ((ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) + ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); +#end[boS] +#if[boU] + return ((ByteOrder.nativeOrder() != ByteOrder.BIG_ENDIAN) + ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); +#end[boU] + } + +#end[!byte] + + + +#if[byte] + + byte _get(int i) { // package-private + return unsafe.getByte(address + i); + } + + void _put(int i, byte b) { // package-private +#if[rw] + unsafe.putByte(address + i, b); +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + // #BIN + // + // Binary-data access methods for short, char, int, long, float, + // and double will be inserted here + +#end[byte] + +}
--- a/src/share/classes/java/nio/Heap-X-Buffer.java Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,595 +0,0 @@ -/* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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. - */ - -#warn This file is preprocessed before being compiled - -package java.nio; - - -/** -#if[rw] - * A read/write Heap$Type$Buffer. -#else[rw] - * A read-only Heap$Type$Buffer. This class extends the corresponding - * read/write class, overriding the mutation methods to throw a {@link - * ReadOnlyBufferException} and overriding the view-buffer methods to return an - * instance of this class rather than of the superclass. -#end[rw] - */ - -class Heap$Type$Buffer$RW$ - extends {#if[ro]?Heap}$Type$Buffer -{ - - // For speed these fields are actually declared in X-Buffer; - // these declarations are here as documentation - /* -#if[rw] - protected final $type$[] hb; - protected final int offset; -#end[rw] - */ - - Heap$Type$Buffer$RW$(int cap, int lim) { // package-private -#if[rw] - super(-1, 0, lim, cap, new $type$[cap], 0); - /* - hb = new $type$[cap]; - offset = 0; - */ -#else[rw] - super(cap, lim); - this.isReadOnly = true; -#end[rw] - } - - Heap$Type$Buffer$RW$($type$[] buf, int off, int len) { // package-private -#if[rw] - super(-1, off, off + len, buf.length, buf, 0); - /* - hb = buf; - offset = 0; - */ -#else[rw] - super(buf, off, len); - this.isReadOnly = true; -#end[rw] - } - - protected Heap$Type$Buffer$RW$($type$[] buf, - int mark, int pos, int lim, int cap, - int off) - { -#if[rw] - super(mark, pos, lim, cap, buf, off); - /* - hb = buf; - offset = off; - */ -#else[rw] - super(buf, mark, pos, lim, cap, off); - this.isReadOnly = true; -#end[rw] - } - - public $Type$Buffer slice() { - return new Heap$Type$Buffer$RW$(hb, - -1, - 0, - this.remaining(), - this.remaining(), - this.position() + offset); - } - - public $Type$Buffer duplicate() { - return new Heap$Type$Buffer$RW$(hb, - this.markValue(), - this.position(), - this.limit(), - this.capacity(), - offset); - } - - public $Type$Buffer asReadOnlyBuffer() { -#if[rw] - return new Heap$Type$BufferR(hb, - this.markValue(), - this.position(), - this.limit(), - this.capacity(), - offset); -#else[rw] - return duplicate(); -#end[rw] - } - -#if[rw] - - protected int ix(int i) { - return i + offset; - } - - public $type$ get() { - return hb[ix(nextGetIndex())]; - } - - public $type$ get(int i) { - return hb[ix(checkIndex(i))]; - } - - public $Type$Buffer get($type$[] dst, int offset, int length) { - checkBounds(offset, length, dst.length); - if (length > remaining()) - throw new BufferUnderflowException(); - System.arraycopy(hb, ix(position()), dst, offset, length); - position(position() + length); - return this; - } - - public boolean isDirect() { - return false; - } - -#end[rw] - - public boolean isReadOnly() { - return {#if[rw]?false:true}; - } - - public $Type$Buffer put($type$ x) { -#if[rw] - hb[ix(nextPutIndex())] = x; - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer put(int i, $type$ x) { -#if[rw] - hb[ix(checkIndex(i))] = x; - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer put($type$[] src, int offset, int length) { -#if[rw] - checkBounds(offset, length, src.length); - if (length > remaining()) - throw new BufferOverflowException(); - System.arraycopy(src, offset, hb, ix(position()), length); - position(position() + length); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer put($Type$Buffer src) { -#if[rw] - if (src instanceof Heap$Type$Buffer) { - if (src == this) - throw new IllegalArgumentException(); - Heap$Type$Buffer sb = (Heap$Type$Buffer)src; - int n = sb.remaining(); - if (n > remaining()) - throw new BufferOverflowException(); - System.arraycopy(sb.hb, sb.ix(sb.position()), - hb, ix(position()), n); - sb.position(sb.position() + n); - position(position() + n); - } else if (src.isDirect()) { - int n = src.remaining(); - if (n > remaining()) - throw new BufferOverflowException(); - src.get(hb, ix(position()), n); - position(position() + n); - } else { - super.put(src); - } - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer compact() { -#if[rw] - System.arraycopy(hb, ix(position()), hb, ix(0), remaining()); - position(remaining()); - limit(capacity()); - discardMark(); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - - -#if[byte] - - byte _get(int i) { // package-private - return hb[i]; - } - - void _put(int i, byte b) { // package-private -#if[rw] - hb[i] = b; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - // char - -#if[rw] - - public char getChar() { - return Bits.getChar(this, ix(nextGetIndex(2)), bigEndian); - } - - public char getChar(int i) { - return Bits.getChar(this, ix(checkIndex(i, 2)), bigEndian); - } - -#end[rw] - - public $Type$Buffer putChar(char x) { -#if[rw] - Bits.putChar(this, ix(nextPutIndex(2)), x, bigEndian); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer putChar(int i, char x) { -#if[rw] - Bits.putChar(this, ix(checkIndex(i, 2)), x, bigEndian); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public CharBuffer asCharBuffer() { - int size = this.remaining() >> 1; - int off = offset + position(); - return (bigEndian - ? (CharBuffer)(new ByteBufferAsCharBuffer$RW$B(this, - -1, - 0, - size, - size, - off)) - : (CharBuffer)(new ByteBufferAsCharBuffer$RW$L(this, - -1, - 0, - size, - size, - off))); - } - - - // short - -#if[rw] - - public short getShort() { - return Bits.getShort(this, ix(nextGetIndex(2)), bigEndian); - } - - public short getShort(int i) { - return Bits.getShort(this, ix(checkIndex(i, 2)), bigEndian); - } - -#end[rw] - - public $Type$Buffer putShort(short x) { -#if[rw] - Bits.putShort(this, ix(nextPutIndex(2)), x, bigEndian); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer putShort(int i, short x) { -#if[rw] - Bits.putShort(this, ix(checkIndex(i, 2)), x, bigEndian); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public ShortBuffer asShortBuffer() { - int size = this.remaining() >> 1; - int off = offset + position(); - return (bigEndian - ? (ShortBuffer)(new ByteBufferAsShortBuffer$RW$B(this, - -1, - 0, - size, - size, - off)) - : (ShortBuffer)(new ByteBufferAsShortBuffer$RW$L(this, - -1, - 0, - size, - size, - off))); - } - - - // int - -#if[rw] - - public int getInt() { - return Bits.getInt(this, ix(nextGetIndex(4)), bigEndian); - } - - public int getInt(int i) { - return Bits.getInt(this, ix(checkIndex(i, 4)), bigEndian); - } - -#end[rw] - - public $Type$Buffer putInt(int x) { -#if[rw] - Bits.putInt(this, ix(nextPutIndex(4)), x, bigEndian); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer putInt(int i, int x) { -#if[rw] - Bits.putInt(this, ix(checkIndex(i, 4)), x, bigEndian); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public IntBuffer asIntBuffer() { - int size = this.remaining() >> 2; - int off = offset + position(); - return (bigEndian - ? (IntBuffer)(new ByteBufferAsIntBuffer$RW$B(this, - -1, - 0, - size, - size, - off)) - : (IntBuffer)(new ByteBufferAsIntBuffer$RW$L(this, - -1, - 0, - size, - size, - off))); - } - - - // long - -#if[rw] - - public long getLong() { - return Bits.getLong(this, ix(nextGetIndex(8)), bigEndian); - } - - public long getLong(int i) { - return Bits.getLong(this, ix(checkIndex(i, 8)), bigEndian); - } - -#end[rw] - - public $Type$Buffer putLong(long x) { -#if[rw] - Bits.putLong(this, ix(nextPutIndex(8)), x, bigEndian); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer putLong(int i, long x) { -#if[rw] - Bits.putLong(this, ix(checkIndex(i, 8)), x, bigEndian); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public LongBuffer asLongBuffer() { - int size = this.remaining() >> 3; - int off = offset + position(); - return (bigEndian - ? (LongBuffer)(new ByteBufferAsLongBuffer$RW$B(this, - -1, - 0, - size, - size, - off)) - : (LongBuffer)(new ByteBufferAsLongBuffer$RW$L(this, - -1, - 0, - size, - size, - off))); - } - - - // float - -#if[rw] - - public float getFloat() { - return Bits.getFloat(this, ix(nextGetIndex(4)), bigEndian); - } - - public float getFloat(int i) { - return Bits.getFloat(this, ix(checkIndex(i, 4)), bigEndian); - } - -#end[rw] - - public $Type$Buffer putFloat(float x) { -#if[rw] - Bits.putFloat(this, ix(nextPutIndex(4)), x, bigEndian); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer putFloat(int i, float x) { -#if[rw] - Bits.putFloat(this, ix(checkIndex(i, 4)), x, bigEndian); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public FloatBuffer asFloatBuffer() { - int size = this.remaining() >> 2; - int off = offset + position(); - return (bigEndian - ? (FloatBuffer)(new ByteBufferAsFloatBuffer$RW$B(this, - -1, - 0, - size, - size, - off)) - : (FloatBuffer)(new ByteBufferAsFloatBuffer$RW$L(this, - -1, - 0, - size, - size, - off))); - } - - - // double - -#if[rw] - - public double getDouble() { - return Bits.getDouble(this, ix(nextGetIndex(8)), bigEndian); - } - - public double getDouble(int i) { - return Bits.getDouble(this, ix(checkIndex(i, 8)), bigEndian); - } - -#end[rw] - - public $Type$Buffer putDouble(double x) { -#if[rw] - Bits.putDouble(this, ix(nextPutIndex(8)), x, bigEndian); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public $Type$Buffer putDouble(int i, double x) { -#if[rw] - Bits.putDouble(this, ix(checkIndex(i, 8)), x, bigEndian); - return this; -#else[rw] - throw new ReadOnlyBufferException(); -#end[rw] - } - - public DoubleBuffer asDoubleBuffer() { - int size = this.remaining() >> 3; - int off = offset + position(); - return (bigEndian - ? (DoubleBuffer)(new ByteBufferAsDoubleBuffer$RW$B(this, - -1, - 0, - size, - size, - off)) - : (DoubleBuffer)(new ByteBufferAsDoubleBuffer$RW$L(this, - -1, - 0, - size, - size, - off))); - } - - -#end[byte] - - -#if[char] - - String toString(int start, int end) { // package-private - try { - return new String(hb, start + offset, end - start); - } catch (StringIndexOutOfBoundsException x) { - throw new IndexOutOfBoundsException(); - } - } - - - // --- Methods to support CharSequence --- - - public CharBuffer subSequence(int start, int end) { - if ((start < 0) - || (end > length()) - || (start > end)) - throw new IndexOutOfBoundsException(); - int pos = position(); - return new HeapCharBuffer$RW$(hb, - -1, - pos + start, - pos + end, - capacity(), - offset); - } - -#end[char] - - -#if[!byte] - - public ByteOrder order() { - return ByteOrder.nativeOrder(); - } - -#end[!byte] - -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/nio/Heap-X-Buffer.java.template Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,595 @@ +/* + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +#warn This file is preprocessed before being compiled + +package java.nio; + + +/** +#if[rw] + * A read/write Heap$Type$Buffer. +#else[rw] + * A read-only Heap$Type$Buffer. This class extends the corresponding + * read/write class, overriding the mutation methods to throw a {@link + * ReadOnlyBufferException} and overriding the view-buffer methods to return an + * instance of this class rather than of the superclass. +#end[rw] + */ + +class Heap$Type$Buffer$RW$ + extends {#if[ro]?Heap}$Type$Buffer +{ + + // For speed these fields are actually declared in X-Buffer; + // these declarations are here as documentation + /* +#if[rw] + protected final $type$[] hb; + protected final int offset; +#end[rw] + */ + + Heap$Type$Buffer$RW$(int cap, int lim) { // package-private +#if[rw] + super(-1, 0, lim, cap, new $type$[cap], 0); + /* + hb = new $type$[cap]; + offset = 0; + */ +#else[rw] + super(cap, lim); + this.isReadOnly = true; +#end[rw] + } + + Heap$Type$Buffer$RW$($type$[] buf, int off, int len) { // package-private +#if[rw] + super(-1, off, off + len, buf.length, buf, 0); + /* + hb = buf; + offset = 0; + */ +#else[rw] + super(buf, off, len); + this.isReadOnly = true; +#end[rw] + } + + protected Heap$Type$Buffer$RW$($type$[] buf, + int mark, int pos, int lim, int cap, + int off) + { +#if[rw] + super(mark, pos, lim, cap, buf, off); + /* + hb = buf; + offset = off; + */ +#else[rw] + super(buf, mark, pos, lim, cap, off); + this.isReadOnly = true; +#end[rw] + } + + public $Type$Buffer slice() { + return new Heap$Type$Buffer$RW$(hb, + -1, + 0, + this.remaining(), + this.remaining(), + this.position() + offset); + } + + public $Type$Buffer duplicate() { + return new Heap$Type$Buffer$RW$(hb, + this.markValue(), + this.position(), + this.limit(), + this.capacity(), + offset); + } + + public $Type$Buffer asReadOnlyBuffer() { +#if[rw] + return new Heap$Type$BufferR(hb, + this.markValue(), + this.position(), + this.limit(), + this.capacity(), + offset); +#else[rw] + return duplicate(); +#end[rw] + } + +#if[rw] + + protected int ix(int i) { + return i + offset; + } + + public $type$ get() { + return hb[ix(nextGetIndex())]; + } + + public $type$ get(int i) { + return hb[ix(checkIndex(i))]; + } + + public $Type$Buffer get($type$[] dst, int offset, int length) { + checkBounds(offset, length, dst.length); + if (length > remaining()) + throw new BufferUnderflowException(); + System.arraycopy(hb, ix(position()), dst, offset, length); + position(position() + length); + return this; + } + + public boolean isDirect() { + return false; + } + +#end[rw] + + public boolean isReadOnly() { + return {#if[rw]?false:true}; + } + + public $Type$Buffer put($type$ x) { +#if[rw] + hb[ix(nextPutIndex())] = x; + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer put(int i, $type$ x) { +#if[rw] + hb[ix(checkIndex(i))] = x; + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer put($type$[] src, int offset, int length) { +#if[rw] + checkBounds(offset, length, src.length); + if (length > remaining()) + throw new BufferOverflowException(); + System.arraycopy(src, offset, hb, ix(position()), length); + position(position() + length); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer put($Type$Buffer src) { +#if[rw] + if (src instanceof Heap$Type$Buffer) { + if (src == this) + throw new IllegalArgumentException(); + Heap$Type$Buffer sb = (Heap$Type$Buffer)src; + int n = sb.remaining(); + if (n > remaining()) + throw new BufferOverflowException(); + System.arraycopy(sb.hb, sb.ix(sb.position()), + hb, ix(position()), n); + sb.position(sb.position() + n); + position(position() + n); + } else if (src.isDirect()) { + int n = src.remaining(); + if (n > remaining()) + throw new BufferOverflowException(); + src.get(hb, ix(position()), n); + position(position() + n); + } else { + super.put(src); + } + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer compact() { +#if[rw] + System.arraycopy(hb, ix(position()), hb, ix(0), remaining()); + position(remaining()); + limit(capacity()); + discardMark(); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + + +#if[byte] + + byte _get(int i) { // package-private + return hb[i]; + } + + void _put(int i, byte b) { // package-private +#if[rw] + hb[i] = b; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + // char + +#if[rw] + + public char getChar() { + return Bits.getChar(this, ix(nextGetIndex(2)), bigEndian); + } + + public char getChar(int i) { + return Bits.getChar(this, ix(checkIndex(i, 2)), bigEndian); + } + +#end[rw] + + public $Type$Buffer putChar(char x) { +#if[rw] + Bits.putChar(this, ix(nextPutIndex(2)), x, bigEndian); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer putChar(int i, char x) { +#if[rw] + Bits.putChar(this, ix(checkIndex(i, 2)), x, bigEndian); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public CharBuffer asCharBuffer() { + int size = this.remaining() >> 1; + int off = offset + position(); + return (bigEndian + ? (CharBuffer)(new ByteBufferAsCharBuffer$RW$B(this, + -1, + 0, + size, + size, + off)) + : (CharBuffer)(new ByteBufferAsCharBuffer$RW$L(this, + -1, + 0, + size, + size, + off))); + } + + + // short + +#if[rw] + + public short getShort() { + return Bits.getShort(this, ix(nextGetIndex(2)), bigEndian); + } + + public short getShort(int i) { + return Bits.getShort(this, ix(checkIndex(i, 2)), bigEndian); + } + +#end[rw] + + public $Type$Buffer putShort(short x) { +#if[rw] + Bits.putShort(this, ix(nextPutIndex(2)), x, bigEndian); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer putShort(int i, short x) { +#if[rw] + Bits.putShort(this, ix(checkIndex(i, 2)), x, bigEndian); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public ShortBuffer asShortBuffer() { + int size = this.remaining() >> 1; + int off = offset + position(); + return (bigEndian + ? (ShortBuffer)(new ByteBufferAsShortBuffer$RW$B(this, + -1, + 0, + size, + size, + off)) + : (ShortBuffer)(new ByteBufferAsShortBuffer$RW$L(this, + -1, + 0, + size, + size, + off))); + } + + + // int + +#if[rw] + + public int getInt() { + return Bits.getInt(this, ix(nextGetIndex(4)), bigEndian); + } + + public int getInt(int i) { + return Bits.getInt(this, ix(checkIndex(i, 4)), bigEndian); + } + +#end[rw] + + public $Type$Buffer putInt(int x) { +#if[rw] + Bits.putInt(this, ix(nextPutIndex(4)), x, bigEndian); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer putInt(int i, int x) { +#if[rw] + Bits.putInt(this, ix(checkIndex(i, 4)), x, bigEndian); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public IntBuffer asIntBuffer() { + int size = this.remaining() >> 2; + int off = offset + position(); + return (bigEndian + ? (IntBuffer)(new ByteBufferAsIntBuffer$RW$B(this, + -1, + 0, + size, + size, + off)) + : (IntBuffer)(new ByteBufferAsIntBuffer$RW$L(this, + -1, + 0, + size, + size, + off))); + } + + + // long + +#if[rw] + + public long getLong() { + return Bits.getLong(this, ix(nextGetIndex(8)), bigEndian); + } + + public long getLong(int i) { + return Bits.getLong(this, ix(checkIndex(i, 8)), bigEndian); + } + +#end[rw] + + public $Type$Buffer putLong(long x) { +#if[rw] + Bits.putLong(this, ix(nextPutIndex(8)), x, bigEndian); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer putLong(int i, long x) { +#if[rw] + Bits.putLong(this, ix(checkIndex(i, 8)), x, bigEndian); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public LongBuffer asLongBuffer() { + int size = this.remaining() >> 3; + int off = offset + position(); + return (bigEndian + ? (LongBuffer)(new ByteBufferAsLongBuffer$RW$B(this, + -1, + 0, + size, + size, + off)) + : (LongBuffer)(new ByteBufferAsLongBuffer$RW$L(this, + -1, + 0, + size, + size, + off))); + } + + + // float + +#if[rw] + + public float getFloat() { + return Bits.getFloat(this, ix(nextGetIndex(4)), bigEndian); + } + + public float getFloat(int i) { + return Bits.getFloat(this, ix(checkIndex(i, 4)), bigEndian); + } + +#end[rw] + + public $Type$Buffer putFloat(float x) { +#if[rw] + Bits.putFloat(this, ix(nextPutIndex(4)), x, bigEndian); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer putFloat(int i, float x) { +#if[rw] + Bits.putFloat(this, ix(checkIndex(i, 4)), x, bigEndian); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public FloatBuffer asFloatBuffer() { + int size = this.remaining() >> 2; + int off = offset + position(); + return (bigEndian + ? (FloatBuffer)(new ByteBufferAsFloatBuffer$RW$B(this, + -1, + 0, + size, + size, + off)) + : (FloatBuffer)(new ByteBufferAsFloatBuffer$RW$L(this, + -1, + 0, + size, + size, + off))); + } + + + // double + +#if[rw] + + public double getDouble() { + return Bits.getDouble(this, ix(nextGetIndex(8)), bigEndian); + } + + public double getDouble(int i) { + return Bits.getDouble(this, ix(checkIndex(i, 8)), bigEndian); + } + +#end[rw] + + public $Type$Buffer putDouble(double x) { +#if[rw] + Bits.putDouble(this, ix(nextPutIndex(8)), x, bigEndian); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public $Type$Buffer putDouble(int i, double x) { +#if[rw] + Bits.putDouble(this, ix(checkIndex(i, 8)), x, bigEndian); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + + public DoubleBuffer asDoubleBuffer() { + int size = this.remaining() >> 3; + int off = offset + position(); + return (bigEndian + ? (DoubleBuffer)(new ByteBufferAsDoubleBuffer$RW$B(this, + -1, + 0, + size, + size, + off)) + : (DoubleBuffer)(new ByteBufferAsDoubleBuffer$RW$L(this, + -1, + 0, + size, + size, + off))); + } + + +#end[byte] + + +#if[char] + + String toString(int start, int end) { // package-private + try { + return new String(hb, start + offset, end - start); + } catch (StringIndexOutOfBoundsException x) { + throw new IndexOutOfBoundsException(); + } + } + + + // --- Methods to support CharSequence --- + + public CharBuffer subSequence(int start, int end) { + if ((start < 0) + || (end > length()) + || (start > end)) + throw new IndexOutOfBoundsException(); + int pos = position(); + return new HeapCharBuffer$RW$(hb, + -1, + pos + start, + pos + end, + capacity(), + offset); + } + +#end[char] + + +#if[!byte] + + public ByteOrder order() { + return ByteOrder.nativeOrder(); + } + +#end[!byte] + +}
--- a/src/share/classes/java/nio/X-Buffer-bin.java Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * Copyright 2000-2002 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. - */ - -#warn This file is preprocessed before being compiled - -class XXX { - -#begin - - /** - * Relative <i>get</i> method for reading $a$ $type$ value. - * - * <p> Reads the next $nbytes$ bytes at this buffer's current position, - * composing them into $a$ $type$ value according to the current byte order, - * and then increments the position by $nbytes$. </p> - * - * @return The $type$ value at the buffer's current position - * - * @throws BufferUnderflowException - * If there are fewer than $nbytes$ bytes - * remaining in this buffer - */ - public abstract $type$ get$Type$(); - - /** - * Relative <i>put</i> method for writing $a$ $type$ - * value <i>(optional operation)</i>. - * - * <p> Writes $nbytes$ bytes containing the given $type$ value, in the - * current byte order, into this buffer at the current position, and then - * increments the position by $nbytes$. </p> - * - * @param value - * The $type$ value to be written - * - * @return This buffer - * - * @throws BufferOverflowException - * If there are fewer than $nbytes$ bytes - * remaining in this buffer - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - */ - public abstract ByteBuffer put$Type$($type$ value); - - /** - * Absolute <i>get</i> method for reading $a$ $type$ value. - * - * <p> Reads $nbytes$ bytes at the given index, composing them into a - * $type$ value according to the current byte order. </p> - * - * @param index - * The index from which the bytes will be read - * - * @return The $type$ value at the given index - * - * @throws IndexOutOfBoundsException - * If <tt>index</tt> is negative - * or not smaller than the buffer's limit, - * minus $nbytesButOne$ - */ - public abstract $type$ get$Type$(int index); - - /** - * Absolute <i>put</i> method for writing $a$ $type$ - * value <i>(optional operation)</i>. - * - * <p> Writes $nbytes$ bytes containing the given $type$ value, in the - * current byte order, into this buffer at the given index. </p> - * - * @param index - * The index at which the bytes will be written - * - * @param value - * The $type$ value to be written - * - * @return This buffer - * - * @throws IndexOutOfBoundsException - * If <tt>index</tt> is negative - * or not smaller than the buffer's limit, - * minus $nbytesButOne$ - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - */ - public abstract ByteBuffer put$Type$(int index, $type$ value); - - /** - * Creates a view of this byte buffer as $a$ $type$ buffer. - * - * <p> The content of the new buffer will start at this buffer's current - * position. Changes to this buffer's content will be visible in the new - * buffer, and vice versa; the two buffers' position, limit, and mark - * values will be independent. - * - * <p> The new buffer's position will be zero, its capacity and its limit - * will be the number of bytes remaining in this buffer divided by - * $nbytes$, and its mark will be undefined. The new buffer will be direct - * if, and only if, this buffer is direct, and it will be read-only if, and - * only if, this buffer is read-only. </p> - * - * @return A new $type$ buffer - */ - public abstract $Type$Buffer as$Type$Buffer(); - -#end - -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/nio/X-Buffer-bin.java.template Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,132 @@ +/* + * Copyright 2000-2002 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. + */ + +#warn This file is preprocessed before being compiled + +class XXX { + +#begin + + /** + * Relative <i>get</i> method for reading $a$ $type$ value. + * + * <p> Reads the next $nbytes$ bytes at this buffer's current position, + * composing them into $a$ $type$ value according to the current byte order, + * and then increments the position by $nbytes$. </p> + * + * @return The $type$ value at the buffer's current position + * + * @throws BufferUnderflowException + * If there are fewer than $nbytes$ bytes + * remaining in this buffer + */ + public abstract $type$ get$Type$(); + + /** + * Relative <i>put</i> method for writing $a$ $type$ + * value <i>(optional operation)</i>. + * + * <p> Writes $nbytes$ bytes containing the given $type$ value, in the + * current byte order, into this buffer at the current position, and then + * increments the position by $nbytes$. </p> + * + * @param value + * The $type$ value to be written + * + * @return This buffer + * + * @throws BufferOverflowException + * If there are fewer than $nbytes$ bytes + * remaining in this buffer + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + */ + public abstract ByteBuffer put$Type$($type$ value); + + /** + * Absolute <i>get</i> method for reading $a$ $type$ value. + * + * <p> Reads $nbytes$ bytes at the given index, composing them into a + * $type$ value according to the current byte order. </p> + * + * @param index + * The index from which the bytes will be read + * + * @return The $type$ value at the given index + * + * @throws IndexOutOfBoundsException + * If <tt>index</tt> is negative + * or not smaller than the buffer's limit, + * minus $nbytesButOne$ + */ + public abstract $type$ get$Type$(int index); + + /** + * Absolute <i>put</i> method for writing $a$ $type$ + * value <i>(optional operation)</i>. + * + * <p> Writes $nbytes$ bytes containing the given $type$ value, in the + * current byte order, into this buffer at the given index. </p> + * + * @param index + * The index at which the bytes will be written + * + * @param value + * The $type$ value to be written + * + * @return This buffer + * + * @throws IndexOutOfBoundsException + * If <tt>index</tt> is negative + * or not smaller than the buffer's limit, + * minus $nbytesButOne$ + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + */ + public abstract ByteBuffer put$Type$(int index, $type$ value); + + /** + * Creates a view of this byte buffer as $a$ $type$ buffer. + * + * <p> The content of the new buffer will start at this buffer's current + * position. Changes to this buffer's content will be visible in the new + * buffer, and vice versa; the two buffers' position, limit, and mark + * values will be independent. + * + * <p> The new buffer's position will be zero, its capacity and its limit + * will be the number of bytes remaining in this buffer divided by + * $nbytes$, and its mark will be undefined. The new buffer will be direct + * if, and only if, this buffer is direct, and it will be read-only if, and + * only if, this buffer is read-only. </p> + * + * @return A new $type$ buffer + */ + public abstract $Type$Buffer as$Type$Buffer(); + +#end + +}
--- a/src/share/classes/java/nio/X-Buffer.java Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1428 +0,0 @@ -/* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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. - */ - -#warn This file is preprocessed before being compiled - -package java.nio; - -#if[char] -import java.io.IOException; -#end[char] - -/** - * $A$ $fulltype$ buffer. - * - * <p> This class defines {#if[byte]?six:four} categories of operations upon - * $fulltype$ buffers: - * - * <ul> - * - * <li><p> Absolute and relative {@link #get() </code><i>get</i><code>} and - * {@link #put($type$) </code><i>put</i><code>} methods that read and write - * single $fulltype$s; </p></li> - * - * <li><p> Relative {@link #get($type$[]) </code><i>bulk get</i><code>} - * methods that transfer contiguous sequences of $fulltype$s from this buffer - * into an array; {#if[!byte]?and}</p></li> - * - * <li><p> Relative {@link #put($type$[]) </code><i>bulk put</i><code>} - * methods that transfer contiguous sequences of $fulltype$s from $a$ - * $fulltype$ array{#if[char]?, a string,} or some other $fulltype$ - * buffer into this buffer;{#if[!byte]? and} </p></li> - * -#if[byte] - * - * <li><p> Absolute and relative {@link #getChar() </code><i>get</i><code>} - * and {@link #putChar(char) </code><i>put</i><code>} methods that read and - * write values of other primitive types, translating them to and from - * sequences of bytes in a particular byte order; </p></li> - * - * <li><p> Methods for creating <i><a href="#views">view buffers</a></i>, - * which allow a byte buffer to be viewed as a buffer containing values of - * some other primitive type; and </p></li> - * -#end[byte] - * - * <li><p> Methods for {@link #compact </code>compacting<code>}, {@link - * #duplicate </code>duplicating<code>}, and {@link #slice - * </code>slicing<code>} $a$ $fulltype$ buffer. </p></li> - * - * </ul> - * - * <p> $Fulltype$ buffers can be created either by {@link #allocate - * </code><i>allocation</i><code>}, which allocates space for the buffer's - * -#if[byte] - * - * content, or by {@link #wrap($type$[]) </code><i>wrapping</i><code>} an - * existing $fulltype$ array {#if[char]?or string} into a buffer. - * -#else[byte] - * - * content, by {@link #wrap($type$[]) </code><i>wrapping</i><code>} an existing - * $fulltype$ array {#if[char]?or string} into a buffer, or by creating a - * <a href="ByteBuffer.html#views"><i>view</i></a> of an existing byte buffer. - * -#end[byte] - * -#if[byte] - * - * <a name="direct"> - * <h4> Direct <i>vs.</i> non-direct buffers </h4> - * - * <p> A byte buffer is either <i>direct</i> or <i>non-direct</i>. Given a - * direct byte buffer, the Java virtual machine will make a best effort to - * perform native I/O operations directly upon it. That is, it will attempt to - * avoid copying the buffer's content to (or from) an intermediate buffer - * before (or after) each invocation of one of the underlying operating - * system's native I/O operations. - * - * <p> A direct byte buffer may be created by invoking the {@link - * #allocateDirect(int) allocateDirect} factory method of this class. The - * buffers returned by this method typically have somewhat higher allocation - * and deallocation costs than non-direct buffers. The contents of direct - * buffers may reside outside of the normal garbage-collected heap, and so - * their impact upon the memory footprint of an application might not be - * obvious. It is therefore recommended that direct buffers be allocated - * primarily for large, long-lived buffers that are subject to the underlying - * system's native I/O operations. In general it is best to allocate direct - * buffers only when they yield a measureable gain in program performance. - * - * <p> A direct byte buffer may also be created by {@link - * java.nio.channels.FileChannel#map </code>mapping<code>} a region of a file - * directly into memory. An implementation of the Java platform may optionally - * support the creation of direct byte buffers from native code via JNI. If an - * instance of one of these kinds of buffers refers to an inaccessible region - * of memory then an attempt to access that region will not change the buffer's - * content and will cause an unspecified exception to be thrown either at the - * time of the access or at some later time. - * - * <p> Whether a byte buffer is direct or non-direct may be determined by - * invoking its {@link #isDirect isDirect} method. This method is provided so - * that explicit buffer management can be done in performance-critical code. - * - * - * <a name="bin"> - * <h4> Access to binary data </h4> - * - * <p> This class defines methods for reading and writing values of all other - * primitive types, except <tt>boolean</tt>. Primitive values are translated - * to (or from) sequences of bytes according to the buffer's current byte - * order, which may be retrieved and modified via the {@link #order order} - * methods. Specific byte orders are represented by instances of the {@link - * ByteOrder} class. The initial order of a byte buffer is always {@link - * ByteOrder#BIG_ENDIAN BIG_ENDIAN}. - * - * <p> For access to heterogeneous binary data, that is, sequences of values of - * different types, this class defines a family of absolute and relative - * <i>get</i> and <i>put</i> methods for each type. For 32-bit floating-point - * values, for example, this class defines: - * - * <blockquote><pre> - * float {@link #getFloat()} - * float {@link #getFloat(int) getFloat(int index)} - * void {@link #putFloat(float) putFloat(float f)} - * void {@link #putFloat(int,float) putFloat(int index, float f)}</pre></blockquote> - * - * <p> Corresponding methods are defined for the types <tt>char</tt>, - * <tt>short</tt>, <tt>int</tt>, <tt>long</tt>, and <tt>double</tt>. The index - * parameters of the absolute <i>get</i> and <i>put</i> methods are in terms of - * bytes rather than of the type being read or written. - * - * <a name="views"> - * - * <p> For access to homogeneous binary data, that is, sequences of values of - * the same type, this class defines methods that can create <i>views</i> of a - * given byte buffer. A <i>view buffer</i> is simply another buffer whose - * content is backed by the byte buffer. Changes to the byte buffer's content - * will be visible in the view buffer, and vice versa; the two buffers' - * position, limit, and mark values are independent. The {@link - * #asFloatBuffer() asFloatBuffer} method, for example, creates an instance of - * the {@link FloatBuffer} class that is backed by the byte buffer upon which - * the method is invoked. Corresponding view-creation methods are defined for - * the types <tt>char</tt>, <tt>short</tt>, <tt>int</tt>, <tt>long</tt>, and - * <tt>double</tt>. - * - * <p> View buffers have three important advantages over the families of - * type-specific <i>get</i> and <i>put</i> methods described above: - * - * <ul> - * - * <li><p> A view buffer is indexed not in terms of bytes but rather in terms - * of the type-specific size of its values; </p></li> - * - * <li><p> A view buffer provides relative bulk <i>get</i> and <i>put</i> - * methods that can transfer contiguous sequences of values between a buffer - * and an array or some other buffer of the same type; and </p></li> - * - * <li><p> A view buffer is potentially much more efficient because it will - * be direct if, and only if, its backing byte buffer is direct. </p></li> - * - * </ul> - * - * <p> The byte order of a view buffer is fixed to be that of its byte buffer - * at the time that the view is created. </p> - * -#end[byte] -* -#if[!byte] - * - * <p> Like a byte buffer, $a$ $fulltype$ buffer is either <a - * href="ByteBuffer.html#direct"><i>direct</i> or <i>non-direct</i></a>. A - * $fulltype$ buffer created via the <tt>wrap</tt> methods of this class will - * be non-direct. $A$ $fulltype$ buffer created as a view of a byte buffer will - * be direct if, and only if, the byte buffer itself is direct. Whether or not - * $a$ $fulltype$ buffer is direct may be determined by invoking the {@link - * #isDirect isDirect} method. </p> - * -#end[!byte] -* -#if[char] - * - * <p> This class implements the {@link CharSequence} interface so that - * character buffers may be used wherever character sequences are accepted, for - * example in the regular-expression package <tt>{@link java.util.regex}</tt>. - * </p> - * -#end[char] - * -#if[byte] - * <h4> Invocation chaining </h4> -#end[byte] - * - * <p> Methods in this class that do not otherwise have a value to return are - * specified to return the buffer upon which they are invoked. This allows - * method invocations to be chained. - * -#if[byte] - * - * The sequence of statements - * - * <blockquote><pre> - * bb.putInt(0xCAFEBABE); - * bb.putShort(3); - * bb.putShort(45);</pre></blockquote> - * - * can, for example, be replaced by the single statement - * - * <blockquote><pre> - * bb.putInt(0xCAFEBABE).putShort(3).putShort(45);</pre></blockquote> - * -#end[byte] -#if[char] - * - * The sequence of statements - * - * <blockquote><pre> - * cb.put("text/"); - * cb.put(subtype); - * cb.put("; charset="); - * cb.put(enc);</pre></blockquote> - * - * can, for example, be replaced by the single statement - * - * <blockquote><pre> - * cb.put("text/").put(subtype).put("; charset=").put(enc);</pre></blockquote> - * -#end[char] - * - * - * @author Mark Reinhold - * @author JSR-51 Expert Group - * @since 1.4 - */ - -public abstract class $Type$Buffer - extends Buffer - implements Comparable<$Type$Buffer>{#if[char]?, Appendable, CharSequence, Readable} -{ - - // These fields are declared here rather than in Heap-X-Buffer in order to - // reduce the number of virtual method invocations needed to access these - // values, which is especially costly when coding small buffers. - // - final $type$[] hb; // Non-null only for heap buffers - final int offset; - boolean isReadOnly; // Valid only for heap buffers - - // Creates a new buffer with the given mark, position, limit, capacity, - // backing array, and array offset - // - $Type$Buffer(int mark, int pos, int lim, int cap, // package-private - $type$[] hb, int offset) - { - super(mark, pos, lim, cap); - this.hb = hb; - this.offset = offset; - } - - // Creates a new buffer with the given mark, position, limit, and capacity - // - $Type$Buffer(int mark, int pos, int lim, int cap) { // package-private - this(mark, pos, lim, cap, null, 0); - } - -#if[byte] - - /** - * Allocates a new direct $fulltype$ buffer. - * - * <p> The new buffer's position will be zero, its limit will be its - * capacity, its mark will be undefined, and each of its elements will be - * initialized to zero. Whether or not it has a - * {@link #hasArray </code>backing array<code>} is unspecified. - * - * @param capacity - * The new buffer's capacity, in $fulltype$s - * - * @return The new $fulltype$ buffer - * - * @throws IllegalArgumentException - * If the <tt>capacity</tt> is a negative integer - */ - public static $Type$Buffer allocateDirect(int capacity) { - return new Direct$Type$Buffer(capacity); - } - -#end[byte] - - /** - * Allocates a new $fulltype$ buffer. - * - * <p> The new buffer's position will be zero, its limit will be its - * capacity, its mark will be undefined, and each of its elements will be - * initialized to zero. It will have a {@link #array - * </code>backing array<code>}, and its {@link #arrayOffset </code>array - * offset<code>} will be zero. - * - * @param capacity - * The new buffer's capacity, in $fulltype$s - * - * @return The new $fulltype$ buffer - * - * @throws IllegalArgumentException - * If the <tt>capacity</tt> is a negative integer - */ - public static $Type$Buffer allocate(int capacity) { - if (capacity < 0) - throw new IllegalArgumentException(); - return new Heap$Type$Buffer(capacity, capacity); - } - - /** - * Wraps $a$ $fulltype$ array into a buffer. - * - * <p> The new buffer will be backed by the given $fulltype$ array; - * that is, modifications to the buffer will cause the array to be modified - * and vice versa. The new buffer's capacity will be - * <tt>array.length</tt>, its position will be <tt>offset</tt>, its limit - * will be <tt>offset + length</tt>, and its mark will be undefined. Its - * {@link #array </code>backing array<code>} will be the given array, and - * its {@link #arrayOffset </code>array offset<code>} will be zero. </p> - * - * @param array - * The array that will back the new buffer - * - * @param offset - * The offset of the subarray to be used; must be non-negative and - * no larger than <tt>array.length</tt>. The new buffer's position - * will be set to this value. - * - * @param length - * The length of the subarray to be used; - * must be non-negative and no larger than - * <tt>array.length - offset</tt>. - * The new buffer's limit will be set to <tt>offset + length</tt>. - * - * @return The new $fulltype$ buffer - * - * @throws IndexOutOfBoundsException - * If the preconditions on the <tt>offset</tt> and <tt>length</tt> - * parameters do not hold - */ - public static $Type$Buffer wrap($type$[] array, - int offset, int length) - { - try { - return new Heap$Type$Buffer(array, offset, length); - } catch (IllegalArgumentException x) { - throw new IndexOutOfBoundsException(); - } - } - - /** - * Wraps $a$ $fulltype$ array into a buffer. - * - * <p> The new buffer will be backed by the given $fulltype$ array; - * that is, modifications to the buffer will cause the array to be modified - * and vice versa. The new buffer's capacity and limit will be - * <tt>array.length</tt>, its position will be zero, and its mark will be - * undefined. Its {@link #array </code>backing array<code>} will be the - * given array, and its {@link #arrayOffset </code>array offset<code>} will - * be zero. </p> - * - * @param array - * The array that will back this buffer - * - * @return The new $fulltype$ buffer - */ - public static $Type$Buffer wrap($type$[] array) { - return wrap(array, 0, array.length); - } - -#if[char] - - /** - * Attempts to read characters into the specified character buffer. - * The buffer is used as a repository of characters as-is: the only - * changes made are the results of a put operation. No flipping or - * rewinding of the buffer is performed. - * - * @param target the buffer to read characters into - * @return The number of characters added to the buffer, or - * -1 if this source of characters is at its end - * @throws IOException if an I/O error occurs - * @throws NullPointerException if target is null - * @throws ReadOnlyBufferException if target is a read only buffer - * @since 1.5 - */ - public int read(CharBuffer target) throws IOException { - // Determine the number of bytes n that can be transferred - int targetRemaining = target.remaining(); - int remaining = remaining(); - if (remaining == 0) - return -1; - int n = Math.min(remaining, targetRemaining); - int limit = limit(); - // Set source limit to prevent target overflow - if (targetRemaining < remaining) - limit(position() + n); - try { - if (n > 0) - target.put(this); - } finally { - limit(limit); // restore real limit - } - return n; - } - - /** - * Wraps a character sequence into a buffer. - * - * <p> The content of the new, read-only buffer will be the content of the - * given character sequence. The buffer's capacity will be - * <tt>csq.length()</tt>, its position will be <tt>start</tt>, its limit - * will be <tt>end</tt>, and its mark will be undefined. </p> - * - * @param csq - * The character sequence from which the new character buffer is to - * be created - * - * @param start - * The index of the first character to be used; - * must be non-negative and no larger than <tt>csq.length()</tt>. - * The new buffer's position will be set to this value. - * - * @param end - * The index of the character following the last character to be - * used; must be no smaller than <tt>start</tt> and no larger - * than <tt>csq.length()</tt>. - * The new buffer's limit will be set to this value. - * - * @return The new character buffer - * - * @throws IndexOutOfBoundsException - * If the preconditions on the <tt>start</tt> and <tt>end</tt> - * parameters do not hold - */ - public static CharBuffer wrap(CharSequence csq, int start, int end) { - try { - return new StringCharBuffer(csq, start, end); - } catch (IllegalArgumentException x) { - throw new IndexOutOfBoundsException(); - } - } - - /** - * Wraps a character sequence into a buffer. - * - * <p> The content of the new, read-only buffer will be the content of the - * given character sequence. The new buffer's capacity and limit will be - * <tt>csq.length()</tt>, its position will be zero, and its mark will be - * undefined. </p> - * - * @param csq - * The character sequence from which the new character buffer is to - * be created - * - * @return The new character buffer - */ - public static CharBuffer wrap(CharSequence csq) { - return wrap(csq, 0, csq.length()); - } - -#end[char] - - /** - * Creates a new $fulltype$ buffer whose content is a shared subsequence of - * this buffer's content. - * - * <p> The content of the new buffer will start at this buffer's current - * position. Changes to this buffer's content will be visible in the new - * buffer, and vice versa; the two buffers' position, limit, and mark - * values will be independent. - * - * <p> The new buffer's position will be zero, its capacity and its limit - * will be the number of $fulltype$s remaining in this buffer, and its mark - * will be undefined. The new buffer will be direct if, and only if, this - * buffer is direct, and it will be read-only if, and only if, this buffer - * is read-only. </p> - * - * @return The new $fulltype$ buffer - */ - public abstract $Type$Buffer slice(); - - /** - * Creates a new $fulltype$ buffer that shares this buffer's content. - * - * <p> The content of the new buffer will be that of this buffer. Changes - * to this buffer's content will be visible in the new buffer, and vice - * versa; the two buffers' position, limit, and mark values will be - * independent. - * - * <p> The new buffer's capacity, limit, position, and mark values will be - * identical to those of this buffer. The new buffer will be direct if, - * and only if, this buffer is direct, and it will be read-only if, and - * only if, this buffer is read-only. </p> - * - * @return The new $fulltype$ buffer - */ - public abstract $Type$Buffer duplicate(); - - /** - * Creates a new, read-only $fulltype$ buffer that shares this buffer's - * content. - * - * <p> The content of the new buffer will be that of this buffer. Changes - * to this buffer's content will be visible in the new buffer; the new - * buffer itself, however, will be read-only and will not allow the shared - * content to be modified. The two buffers' position, limit, and mark - * values will be independent. - * - * <p> The new buffer's capacity, limit, position, and mark values will be - * identical to those of this buffer. - * - * <p> If this buffer is itself read-only then this method behaves in - * exactly the same way as the {@link #duplicate duplicate} method. </p> - * - * @return The new, read-only $fulltype$ buffer - */ - public abstract $Type$Buffer asReadOnlyBuffer(); - - - // -- Singleton get/put methods -- - - /** - * Relative <i>get</i> method. Reads the $fulltype$ at this buffer's - * current position, and then increments the position. </p> - * - * @return The $fulltype$ at the buffer's current position - * - * @throws BufferUnderflowException - * If the buffer's current position is not smaller than its limit - */ - public abstract $type$ get(); - - /** - * Relative <i>put</i> method <i>(optional operation)</i>. - * - * <p> Writes the given $fulltype$ into this buffer at the current - * position, and then increments the position. </p> - * - * @param $x$ - * The $fulltype$ to be written - * - * @return This buffer - * - * @throws BufferOverflowException - * If this buffer's current position is not smaller than its limit - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - */ - public abstract $Type$Buffer put($type$ $x$); - - /** - * Absolute <i>get</i> method. Reads the $fulltype$ at the given - * index. </p> - * - * @param index - * The index from which the $fulltype$ will be read - * - * @return The $fulltype$ at the given index - * - * @throws IndexOutOfBoundsException - * If <tt>index</tt> is negative - * or not smaller than the buffer's limit - */ - public abstract $type$ get(int index); - - /** - * Absolute <i>put</i> method <i>(optional operation)</i>. - * - * <p> Writes the given $fulltype$ into this buffer at the given - * index. </p> - * - * @param index - * The index at which the $fulltype$ will be written - * - * @param $x$ - * The $fulltype$ value to be written - * - * @return This buffer - * - * @throws IndexOutOfBoundsException - * If <tt>index</tt> is negative - * or not smaller than the buffer's limit - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - */ - public abstract $Type$Buffer put(int index, $type$ $x$); - - - // -- Bulk get operations -- - - /** - * Relative bulk <i>get</i> method. - * - * <p> This method transfers $fulltype$s from this buffer into the given - * destination array. If there are fewer $fulltype$s remaining in the - * buffer than are required to satisfy the request, that is, if - * <tt>length</tt> <tt>></tt> <tt>remaining()</tt>, then no - * $fulltype$s are transferred and a {@link BufferUnderflowException} is - * thrown. - * - * <p> Otherwise, this method copies <tt>length</tt> $fulltype$s from this - * buffer into the given array, starting at the current position of this - * buffer and at the given offset in the array. The position of this - * buffer is then incremented by <tt>length</tt>. - * - * <p> In other words, an invocation of this method of the form - * <tt>src.get(dst, off, len)</tt> has exactly the same effect as - * the loop - * - * <pre> - * for (int i = off; i < off + len; i++) - * dst[i] = src.get(); </pre> - * - * except that it first checks that there are sufficient $fulltype$s in - * this buffer and it is potentially much more efficient. </p> - * - * @param dst - * The array into which $fulltype$s are to be written - * - * @param offset - * The offset within the array of the first $fulltype$ to be - * written; must be non-negative and no larger than - * <tt>dst.length</tt> - * - * @param length - * The maximum number of $fulltype$s to be written to the given - * array; must be non-negative and no larger than - * <tt>dst.length - offset</tt> - * - * @return This buffer - * - * @throws BufferUnderflowException - * If there are fewer than <tt>length</tt> $fulltype$s - * remaining in this buffer - * - * @throws IndexOutOfBoundsException - * If the preconditions on the <tt>offset</tt> and <tt>length</tt> - * parameters do not hold - */ - public $Type$Buffer get($type$[] dst, int offset, int length) { - checkBounds(offset, length, dst.length); - if (length > remaining()) - throw new BufferUnderflowException(); - int end = offset + length; - for (int i = offset; i < end; i++) - dst[i] = get(); - return this; - } - - /** - * Relative bulk <i>get</i> method. - * - * <p> This method transfers $fulltype$s from this buffer into the given - * destination array. An invocation of this method of the form - * <tt>src.get(a)</tt> behaves in exactly the same way as the invocation - * - * <pre> - * src.get(a, 0, a.length) </pre> - * - * @return This buffer - * - * @throws BufferUnderflowException - * If there are fewer than <tt>length</tt> $fulltype$s - * remaining in this buffer - */ - public $Type$Buffer get($type$[] dst) { - return get(dst, 0, dst.length); - } - - - // -- Bulk put operations -- - - /** - * Relative bulk <i>put</i> method <i>(optional operation)</i>. - * - * <p> This method transfers the $fulltype$s remaining in the given source - * buffer into this buffer. If there are more $fulltype$s remaining in the - * source buffer than in this buffer, that is, if - * <tt>src.remaining()</tt> <tt>></tt> <tt>remaining()</tt>, - * then no $fulltype$s are transferred and a {@link - * BufferOverflowException} is thrown. - * - * <p> Otherwise, this method copies - * <i>n</i> = <tt>src.remaining()</tt> $fulltype$s from the given - * buffer into this buffer, starting at each buffer's current position. - * The positions of both buffers are then incremented by <i>n</i>. - * - * <p> In other words, an invocation of this method of the form - * <tt>dst.put(src)</tt> has exactly the same effect as the loop - * - * <pre> - * while (src.hasRemaining()) - * dst.put(src.get()); </pre> - * - * except that it first checks that there is sufficient space in this - * buffer and it is potentially much more efficient. </p> - * - * @param src - * The source buffer from which $fulltype$s are to be read; - * must not be this buffer - * - * @return This buffer - * - * @throws BufferOverflowException - * If there is insufficient space in this buffer - * for the remaining $fulltype$s in the source buffer - * - * @throws IllegalArgumentException - * If the source buffer is this buffer - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - */ - public $Type$Buffer put($Type$Buffer src) { - if (src == this) - throw new IllegalArgumentException(); - int n = src.remaining(); - if (n > remaining()) - throw new BufferOverflowException(); - for (int i = 0; i < n; i++) - put(src.get()); - return this; - } - - /** - * Relative bulk <i>put</i> method <i>(optional operation)</i>. - * - * <p> This method transfers $fulltype$s into this buffer from the given - * source array. If there are more $fulltype$s to be copied from the array - * than remain in this buffer, that is, if - * <tt>length</tt> <tt>></tt> <tt>remaining()</tt>, then no - * $fulltype$s are transferred and a {@link BufferOverflowException} is - * thrown. - * - * <p> Otherwise, this method copies <tt>length</tt> $fulltype$s from the - * given array into this buffer, starting at the given offset in the array - * and at the current position of this buffer. The position of this buffer - * is then incremented by <tt>length</tt>. - * - * <p> In other words, an invocation of this method of the form - * <tt>dst.put(src, off, len)</tt> has exactly the same effect as - * the loop - * - * <pre> - * for (int i = off; i < off + len; i++) - * dst.put(a[i]); </pre> - * - * except that it first checks that there is sufficient space in this - * buffer and it is potentially much more efficient. </p> - * - * @param src - * The array from which $fulltype$s are to be read - * - * @param offset - * The offset within the array of the first $fulltype$ to be read; - * must be non-negative and no larger than <tt>array.length</tt> - * - * @param length - * The number of $fulltype$s to be read from the given array; - * must be non-negative and no larger than - * <tt>array.length - offset</tt> - * - * @return This buffer - * - * @throws BufferOverflowException - * If there is insufficient space in this buffer - * - * @throws IndexOutOfBoundsException - * If the preconditions on the <tt>offset</tt> and <tt>length</tt> - * parameters do not hold - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - */ - public $Type$Buffer put($type$[] src, int offset, int length) { - checkBounds(offset, length, src.length); - if (length > remaining()) - throw new BufferOverflowException(); - int end = offset + length; - for (int i = offset; i < end; i++) - this.put(src[i]); - return this; - } - - /** - * Relative bulk <i>put</i> method <i>(optional operation)</i>. - * - * <p> This method transfers the entire content of the given source - * $fulltype$ array into this buffer. An invocation of this method of the - * form <tt>dst.put(a)</tt> behaves in exactly the same way as the - * invocation - * - * <pre> - * dst.put(a, 0, a.length) </pre> - * - * @return This buffer - * - * @throws BufferOverflowException - * If there is insufficient space in this buffer - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - */ - public final $Type$Buffer put($type$[] src) { - return put(src, 0, src.length); - } - -#if[char] - - /** - * Relative bulk <i>put</i> method <i>(optional operation)</i>. - * - * <p> This method transfers $fulltype$s from the given string into this - * buffer. If there are more $fulltype$s to be copied from the string than - * remain in this buffer, that is, if - * <tt>end - start</tt> <tt>></tt> <tt>remaining()</tt>, - * then no $fulltype$s are transferred and a {@link - * BufferOverflowException} is thrown. - * - * <p> Otherwise, this method copies - * <i>n</i> = <tt>end</tt> - <tt>start</tt> $fulltype$s - * from the given string into this buffer, starting at the given - * <tt>start</tt> index and at the current position of this buffer. The - * position of this buffer is then incremented by <i>n</i>. - * - * <p> In other words, an invocation of this method of the form - * <tt>dst.put(src, start, end)</tt> has exactly the same effect - * as the loop - * - * <pre> - * for (int i = start; i < end; i++) - * dst.put(src.charAt(i)); </pre> - * - * except that it first checks that there is sufficient space in this - * buffer and it is potentially much more efficient. </p> - * - * @param src - * The string from which $fulltype$s are to be read - * - * @param start - * The offset within the string of the first $fulltype$ to be read; - * must be non-negative and no larger than - * <tt>string.length()</tt> - * - * @param end - * The offset within the string of the last $fulltype$ to be read, - * plus one; must be non-negative and no larger than - * <tt>string.length()</tt> - * - * @return This buffer - * - * @throws BufferOverflowException - * If there is insufficient space in this buffer - * - * @throws IndexOutOfBoundsException - * If the preconditions on the <tt>start</tt> and <tt>end</tt> - * parameters do not hold - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - */ - public $Type$Buffer put(String src, int start, int end) { - checkBounds(start, end - start, src.length()); - for (int i = start; i < end; i++) - this.put(src.charAt(i)); - return this; - } - - /** - * Relative bulk <i>put</i> method <i>(optional operation)</i>. - * - * <p> This method transfers the entire content of the given source string - * into this buffer. An invocation of this method of the form - * <tt>dst.put(s)</tt> behaves in exactly the same way as the invocation - * - * <pre> - * dst.put(s, 0, s.length()) </pre> - * - * @return This buffer - * - * @throws BufferOverflowException - * If there is insufficient space in this buffer - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - */ - public final $Type$Buffer put(String src) { - return put(src, 0, src.length()); - } - -#end[char] - - - // -- Other stuff -- - - /** - * Tells whether or not this buffer is backed by an accessible $fulltype$ - * array. - * - * <p> If this method returns <tt>true</tt> then the {@link #array() array} - * and {@link #arrayOffset() arrayOffset} methods may safely be invoked. - * </p> - * - * @return <tt>true</tt> if, and only if, this buffer - * is backed by an array and is not read-only - */ - public final boolean hasArray() { - return (hb != null) && !isReadOnly; - } - - /** - * Returns the $fulltype$ array that backs this - * buffer <i>(optional operation)</i>. - * - * <p> Modifications to this buffer's content will cause the returned - * array's content to be modified, and vice versa. - * - * <p> Invoke the {@link #hasArray hasArray} method before invoking this - * method in order to ensure that this buffer has an accessible backing - * array. </p> - * - * @return The array that backs this buffer - * - * @throws ReadOnlyBufferException - * If this buffer is backed by an array but is read-only - * - * @throws UnsupportedOperationException - * If this buffer is not backed by an accessible array - */ - public final $type$[] array() { - if (hb == null) - throw new UnsupportedOperationException(); - if (isReadOnly) - throw new ReadOnlyBufferException(); - return hb; - } - - /** - * Returns the offset within this buffer's backing array of the first - * element of the buffer <i>(optional operation)</i>. - * - * <p> If this buffer is backed by an array then buffer position <i>p</i> - * corresponds to array index <i>p</i> + <tt>arrayOffset()</tt>. - * - * <p> Invoke the {@link #hasArray hasArray} method before invoking this - * method in order to ensure that this buffer has an accessible backing - * array. </p> - * - * @return The offset within this buffer's array - * of the first element of the buffer - * - * @throws ReadOnlyBufferException - * If this buffer is backed by an array but is read-only - * - * @throws UnsupportedOperationException - * If this buffer is not backed by an accessible array - */ - public final int arrayOffset() { - if (hb == null) - throw new UnsupportedOperationException(); - if (isReadOnly) - throw new ReadOnlyBufferException(); - return offset; - } - - /** - * Compacts this buffer <i>(optional operation)</i>. - * - * <p> The $fulltype$s between the buffer's current position and its limit, - * if any, are copied to the beginning of the buffer. That is, the - * $fulltype$ at index <i>p</i> = <tt>position()</tt> is copied - * to index zero, the $fulltype$ at index <i>p</i> + 1 is copied - * to index one, and so forth until the $fulltype$ at index - * <tt>limit()</tt> - 1 is copied to index - * <i>n</i> = <tt>limit()</tt> - <tt>1</tt> - <i>p</i>. - * The buffer's position is then set to <i>n+1</i> and its limit is set to - * its capacity. The mark, if defined, is discarded. - * - * <p> The buffer's position is set to the number of $fulltype$s copied, - * rather than to zero, so that an invocation of this method can be - * followed immediately by an invocation of another relative <i>put</i> - * method. </p> - * -#if[byte] - * - * <p> Invoke this method after writing data from a buffer in case the - * write was incomplete. The following loop, for example, copies bytes - * from one channel to another via the buffer <tt>buf</tt>: - * - * <blockquote><pre> - * buf.clear(); // Prepare buffer for use - * while (in.read(buf) >= 0 || buf.position != 0) { - * buf.flip(); - * out.write(buf); - * buf.compact(); // In case of partial write - * }</pre></blockquote> - * -#end[byte] - * - * @return This buffer - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - */ - public abstract $Type$Buffer compact(); - - /** - * Tells whether or not this $fulltype$ buffer is direct. </p> - * - * @return <tt>true</tt> if, and only if, this buffer is direct - */ - public abstract boolean isDirect(); - -#if[!char] - - /** - * Returns a string summarizing the state of this buffer. </p> - * - * @return A summary string - */ - public String toString() { - StringBuffer sb = new StringBuffer(); - sb.append(getClass().getName()); - sb.append("[pos="); - sb.append(position()); - sb.append(" lim="); - sb.append(limit()); - sb.append(" cap="); - sb.append(capacity()); - sb.append("]"); - return sb.toString(); - } - -#end[!char] - - - // ## Should really use unchecked accessors here for speed - - /** - * Returns the current hash code of this buffer. - * - * <p> The hash code of a $type$ buffer depends only upon its remaining - * elements; that is, upon the elements from <tt>position()</tt> up to, and - * including, the element at <tt>limit()</tt> - <tt>1</tt>. - * - * <p> Because buffer hash codes are content-dependent, it is inadvisable - * to use buffers as keys in hash maps or similar data structures unless it - * is known that their contents will not change. </p> - * - * @return The current hash code of this buffer - */ - public int hashCode() { - int h = 1; - int p = position(); - for (int i = limit() - 1; i >= p; i--) - h = 31 * h + (int)get(i); - return h; - } - - /** - * Tells whether or not this buffer is equal to another object. - * - * <p> Two $type$ buffers are equal if, and only if, - * - * <p><ol> - * - * <li><p> They have the same element type, </p></li> - * - * <li><p> They have the same number of remaining elements, and - * </p></li> - * - * <li><p> The two sequences of remaining elements, considered - * independently of their starting positions, are pointwise equal. - * </p></li> - * - * </ol> - * - * <p> A $type$ buffer is not equal to any other type of object. </p> - * - * @param ob The object to which this buffer is to be compared - * - * @return <tt>true</tt> if, and only if, this buffer is equal to the - * given object - */ - public boolean equals(Object ob) { - if (this == ob) - return true; - if (!(ob instanceof $Type$Buffer)) - return false; - $Type$Buffer that = ($Type$Buffer)ob; - if (this.remaining() != that.remaining()) - return false; - int p = this.position(); - for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) { - $type$ v1 = this.get(i); - $type$ v2 = that.get(j); - if (v1 != v2) { - if ((v1 != v1) && (v2 != v2)) // For float and double - continue; - return false; - } - } - return true; - } - - /** - * Compares this buffer to another. - * - * <p> Two $type$ buffers are compared by comparing their sequences of - * remaining elements lexicographically, without regard to the starting - * position of each sequence within its corresponding buffer. - * - * <p> A $type$ buffer is not comparable to any other type of object. - * - * @return A negative integer, zero, or a positive integer as this buffer - * is less than, equal to, or greater than the given buffer - */ - public int compareTo($Type$Buffer that) { - int n = this.position() + Math.min(this.remaining(), that.remaining()); - for (int i = this.position(), j = that.position(); i < n; i++, j++) { - $type$ v1 = this.get(i); - $type$ v2 = that.get(j); - if (v1 == v2) - continue; - if ((v1 != v1) && (v2 != v2)) // For float and double - continue; - if (v1 < v2) - return -1; - return +1; - } - return this.remaining() - that.remaining(); - } - - - - // -- Other char stuff -- - -#if[char] - - /** - * Returns a string containing the characters in this buffer. - * - * <p> The first character of the resulting string will be the character at - * this buffer's position, while the last character will be the character - * at index <tt>limit()</tt> - 1. Invoking this method does not - * change the buffer's position. </p> - * - * @return The specified string - */ - public String toString() { - return toString(position(), limit()); - } - - abstract String toString(int start, int end); // package-private - - - // --- Methods to support CharSequence --- - - /** - * Returns the length of this character buffer. - * - * <p> When viewed as a character sequence, the length of a character - * buffer is simply the number of characters between the position - * (inclusive) and the limit (exclusive); that is, it is equivalent to - * <tt>remaining()</tt>. </p> - * - * @return The length of this character buffer - */ - public final int length() { - return remaining(); - } - - /** - * Reads the character at the given index relative to the current - * position. </p> - * - * @param index - * The index of the character to be read, relative to the position; - * must be non-negative and smaller than <tt>remaining()</tt> - * - * @return The character at index - * <tt>position() + index</tt> - * - * @throws IndexOutOfBoundsException - * If the preconditions on <tt>index</tt> do not hold - */ - public final char charAt(int index) { - return get(position() + checkIndex(index, 1)); - } - - /** - * Creates a new character buffer that represents the specified subsequence - * of this buffer, relative to the current position. - * - * <p> The new buffer will share this buffer's content; that is, if the - * content of this buffer is mutable then modifications to one buffer will - * cause the other to be modified. The new buffer's capacity will be that - * of this buffer, its position will be - * <tt>position()</tt> + <tt>start</tt>, and its limit will be - * <tt>position()</tt> + <tt>end</tt>. The new buffer will be - * direct if, and only if, this buffer is direct, and it will be read-only - * if, and only if, this buffer is read-only. </p> - * - * @param start - * The index, relative to the current position, of the first - * character in the subsequence; must be non-negative and no larger - * than <tt>remaining()</tt> - * - * @param end - * The index, relative to the current position, of the character - * following the last character in the subsequence; must be no - * smaller than <tt>start</tt> and no larger than - * <tt>remaining()</tt> - * - * @return The new character buffer - * - * @throws IndexOutOfBoundsException - * If the preconditions on <tt>start</tt> and <tt>end</tt> - * do not hold - */ - public abstract CharBuffer subSequence(int start, int end); - - - // --- Methods to support Appendable --- - - /** - * Appends the specified character sequence to this - * buffer <i>(optional operation)</i>. - * - * <p> An invocation of this method of the form <tt>dst.append(csq)</tt> - * behaves in exactly the same way as the invocation - * - * <pre> - * dst.put(csq.toString()) </pre> - * - * <p> Depending on the specification of <tt>toString</tt> for the - * character sequence <tt>csq</tt>, the entire sequence may not be - * appended. For instance, invoking the {@link $Type$Buffer#toString() - * toString} method of a character buffer will return a subsequence whose - * content depends upon the buffer's position and limit. - * - * @param csq - * The character sequence to append. If <tt>csq</tt> is - * <tt>null</tt>, then the four characters <tt>"null"</tt> are - * appended to this character buffer. - * - * @return This buffer - * - * @throws BufferOverflowException - * If there is insufficient space in this buffer - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - * - * @since 1.5 - */ - public $Type$Buffer append(CharSequence csq) { - if (csq == null) - return put("null"); - else - return put(csq.toString()); - } - - /** - * Appends a subsequence of the specified character sequence to this - * buffer <i>(optional operation)</i>. - * - * <p> An invocation of this method of the form <tt>dst.append(csq, start, - * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in exactly the - * same way as the invocation - * - * <pre> - * dst.put(csq.subSequence(start, end).toString()) </pre> - * - * @param csq - * The character sequence from which a subsequence will be - * appended. If <tt>csq</tt> is <tt>null</tt>, then characters - * will be appended as if <tt>csq</tt> contained the four - * characters <tt>"null"</tt>. - * - * @return This buffer - * - * @throws BufferOverflowException - * If there is insufficient space in this buffer - * - * @throws IndexOutOfBoundsException - * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt> - * is greater than <tt>end</tt>, or <tt>end</tt> is greater than - * <tt>csq.length()</tt> - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - * - * @since 1.5 - */ - public $Type$Buffer append(CharSequence csq, int start, int end) { - CharSequence cs = (csq == null ? "null" : csq); - return put(cs.subSequence(start, end).toString()); - } - - /** - * Appends the specified $fulltype$ to this - * buffer <i>(optional operation)</i>. - * - * <p> An invocation of this method of the form <tt>dst.append($x$)</tt> - * behaves in exactly the same way as the invocation - * - * <pre> - * dst.put($x$) </pre> - * - * @param $x$ - * The 16-bit $fulltype$ to append - * - * @return This buffer - * - * @throws BufferOverflowException - * If there is insufficient space in this buffer - * - * @throws ReadOnlyBufferException - * If this buffer is read-only - * - * @since 1.5 - */ - public $Type$Buffer append($type$ $x$) { - return put($x$); - } - -#end[char] - - - // -- Other byte stuff: Access to binary data -- - -#if[!byte] - - /** - * Retrieves this buffer's byte order. - * - * <p> The byte order of $a$ $fulltype$ buffer created by allocation or by - * wrapping an existing <tt>$type$</tt> array is the {@link - * ByteOrder#nativeOrder </code>native order<code>} of the underlying - * hardware. The byte order of $a$ $fulltype$ buffer created as a <a - * href="ByteBuffer.html#views">view</a> of a byte buffer is that of the - * byte buffer at the moment that the view is created. </p> - * - * @return This buffer's byte order - */ - public abstract ByteOrder order(); - -#end[!byte] - -#if[byte] - - boolean bigEndian // package-private - = true; - boolean nativeByteOrder // package-private - = (Bits.byteOrder() == ByteOrder.BIG_ENDIAN); - - /** - * Retrieves this buffer's byte order. - * - * <p> The byte order is used when reading or writing multibyte values, and - * when creating buffers that are views of this byte buffer. The order of - * a newly-created byte buffer is always {@link ByteOrder#BIG_ENDIAN - * BIG_ENDIAN}. </p> - * - * @return This buffer's byte order - */ - public final ByteOrder order() { - return bigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; - } - - /** - * Modifies this buffer's byte order. </p> - * - * @param bo - * The new byte order, - * either {@link ByteOrder#BIG_ENDIAN BIG_ENDIAN} - * or {@link ByteOrder#LITTLE_ENDIAN LITTLE_ENDIAN} - * - * @return This buffer - */ - public final $Type$Buffer order(ByteOrder bo) { - bigEndian = (bo == ByteOrder.BIG_ENDIAN); - nativeByteOrder = - (bigEndian == (Bits.byteOrder() == ByteOrder.BIG_ENDIAN)); - return this; - } - - // Unchecked accessors, for use by ByteBufferAs-X-Buffer classes - // - abstract byte _get(int i); // package-private - abstract void _put(int i, byte b); // package-private - - // #BIN - // - // Binary-data access methods for short, char, int, long, float, - // and double will be inserted here - -#end[byte] - -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/nio/X-Buffer.java.template Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,1428 @@ +/* + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +#warn This file is preprocessed before being compiled + +package java.nio; + +#if[char] +import java.io.IOException; +#end[char] + +/** + * $A$ $fulltype$ buffer. + * + * <p> This class defines {#if[byte]?six:four} categories of operations upon + * $fulltype$ buffers: + * + * <ul> + * + * <li><p> Absolute and relative {@link #get() </code><i>get</i><code>} and + * {@link #put($type$) </code><i>put</i><code>} methods that read and write + * single $fulltype$s; </p></li> + * + * <li><p> Relative {@link #get($type$[]) </code><i>bulk get</i><code>} + * methods that transfer contiguous sequences of $fulltype$s from this buffer + * into an array; {#if[!byte]?and}</p></li> + * + * <li><p> Relative {@link #put($type$[]) </code><i>bulk put</i><code>} + * methods that transfer contiguous sequences of $fulltype$s from $a$ + * $fulltype$ array{#if[char]?, a string,} or some other $fulltype$ + * buffer into this buffer;{#if[!byte]? and} </p></li> + * +#if[byte] + * + * <li><p> Absolute and relative {@link #getChar() </code><i>get</i><code>} + * and {@link #putChar(char) </code><i>put</i><code>} methods that read and + * write values of other primitive types, translating them to and from + * sequences of bytes in a particular byte order; </p></li> + * + * <li><p> Methods for creating <i><a href="#views">view buffers</a></i>, + * which allow a byte buffer to be viewed as a buffer containing values of + * some other primitive type; and </p></li> + * +#end[byte] + * + * <li><p> Methods for {@link #compact </code>compacting<code>}, {@link + * #duplicate </code>duplicating<code>}, and {@link #slice + * </code>slicing<code>} $a$ $fulltype$ buffer. </p></li> + * + * </ul> + * + * <p> $Fulltype$ buffers can be created either by {@link #allocate + * </code><i>allocation</i><code>}, which allocates space for the buffer's + * +#if[byte] + * + * content, or by {@link #wrap($type$[]) </code><i>wrapping</i><code>} an + * existing $fulltype$ array {#if[char]?or string} into a buffer. + * +#else[byte] + * + * content, by {@link #wrap($type$[]) </code><i>wrapping</i><code>} an existing + * $fulltype$ array {#if[char]?or string} into a buffer, or by creating a + * <a href="ByteBuffer.html#views"><i>view</i></a> of an existing byte buffer. + * +#end[byte] + * +#if[byte] + * + * <a name="direct"> + * <h4> Direct <i>vs.</i> non-direct buffers </h4> + * + * <p> A byte buffer is either <i>direct</i> or <i>non-direct</i>. Given a + * direct byte buffer, the Java virtual machine will make a best effort to + * perform native I/O operations directly upon it. That is, it will attempt to + * avoid copying the buffer's content to (or from) an intermediate buffer + * before (or after) each invocation of one of the underlying operating + * system's native I/O operations. + * + * <p> A direct byte buffer may be created by invoking the {@link + * #allocateDirect(int) allocateDirect} factory method of this class. The + * buffers returned by this method typically have somewhat higher allocation + * and deallocation costs than non-direct buffers. The contents of direct + * buffers may reside outside of the normal garbage-collected heap, and so + * their impact upon the memory footprint of an application might not be + * obvious. It is therefore recommended that direct buffers be allocated + * primarily for large, long-lived buffers that are subject to the underlying + * system's native I/O operations. In general it is best to allocate direct + * buffers only when they yield a measureable gain in program performance. + * + * <p> A direct byte buffer may also be created by {@link + * java.nio.channels.FileChannel#map </code>mapping<code>} a region of a file + * directly into memory. An implementation of the Java platform may optionally + * support the creation of direct byte buffers from native code via JNI. If an + * instance of one of these kinds of buffers refers to an inaccessible region + * of memory then an attempt to access that region will not change the buffer's + * content and will cause an unspecified exception to be thrown either at the + * time of the access or at some later time. + * + * <p> Whether a byte buffer is direct or non-direct may be determined by + * invoking its {@link #isDirect isDirect} method. This method is provided so + * that explicit buffer management can be done in performance-critical code. + * + * + * <a name="bin"> + * <h4> Access to binary data </h4> + * + * <p> This class defines methods for reading and writing values of all other + * primitive types, except <tt>boolean</tt>. Primitive values are translated + * to (or from) sequences of bytes according to the buffer's current byte + * order, which may be retrieved and modified via the {@link #order order} + * methods. Specific byte orders are represented by instances of the {@link + * ByteOrder} class. The initial order of a byte buffer is always {@link + * ByteOrder#BIG_ENDIAN BIG_ENDIAN}. + * + * <p> For access to heterogeneous binary data, that is, sequences of values of + * different types, this class defines a family of absolute and relative + * <i>get</i> and <i>put</i> methods for each type. For 32-bit floating-point + * values, for example, this class defines: + * + * <blockquote><pre> + * float {@link #getFloat()} + * float {@link #getFloat(int) getFloat(int index)} + * void {@link #putFloat(float) putFloat(float f)} + * void {@link #putFloat(int,float) putFloat(int index, float f)}</pre></blockquote> + * + * <p> Corresponding methods are defined for the types <tt>char</tt>, + * <tt>short</tt>, <tt>int</tt>, <tt>long</tt>, and <tt>double</tt>. The index + * parameters of the absolute <i>get</i> and <i>put</i> methods are in terms of + * bytes rather than of the type being read or written. + * + * <a name="views"> + * + * <p> For access to homogeneous binary data, that is, sequences of values of + * the same type, this class defines methods that can create <i>views</i> of a + * given byte buffer. A <i>view buffer</i> is simply another buffer whose + * content is backed by the byte buffer. Changes to the byte buffer's content + * will be visible in the view buffer, and vice versa; the two buffers' + * position, limit, and mark values are independent. The {@link + * #asFloatBuffer() asFloatBuffer} method, for example, creates an instance of + * the {@link FloatBuffer} class that is backed by the byte buffer upon which + * the method is invoked. Corresponding view-creation methods are defined for + * the types <tt>char</tt>, <tt>short</tt>, <tt>int</tt>, <tt>long</tt>, and + * <tt>double</tt>. + * + * <p> View buffers have three important advantages over the families of + * type-specific <i>get</i> and <i>put</i> methods described above: + * + * <ul> + * + * <li><p> A view buffer is indexed not in terms of bytes but rather in terms + * of the type-specific size of its values; </p></li> + * + * <li><p> A view buffer provides relative bulk <i>get</i> and <i>put</i> + * methods that can transfer contiguous sequences of values between a buffer + * and an array or some other buffer of the same type; and </p></li> + * + * <li><p> A view buffer is potentially much more efficient because it will + * be direct if, and only if, its backing byte buffer is direct. </p></li> + * + * </ul> + * + * <p> The byte order of a view buffer is fixed to be that of its byte buffer + * at the time that the view is created. </p> + * +#end[byte] +* +#if[!byte] + * + * <p> Like a byte buffer, $a$ $fulltype$ buffer is either <a + * href="ByteBuffer.html#direct"><i>direct</i> or <i>non-direct</i></a>. A + * $fulltype$ buffer created via the <tt>wrap</tt> methods of this class will + * be non-direct. $A$ $fulltype$ buffer created as a view of a byte buffer will + * be direct if, and only if, the byte buffer itself is direct. Whether or not + * $a$ $fulltype$ buffer is direct may be determined by invoking the {@link + * #isDirect isDirect} method. </p> + * +#end[!byte] +* +#if[char] + * + * <p> This class implements the {@link CharSequence} interface so that + * character buffers may be used wherever character sequences are accepted, for + * example in the regular-expression package <tt>{@link java.util.regex}</tt>. + * </p> + * +#end[char] + * +#if[byte] + * <h4> Invocation chaining </h4> +#end[byte] + * + * <p> Methods in this class that do not otherwise have a value to return are + * specified to return the buffer upon which they are invoked. This allows + * method invocations to be chained. + * +#if[byte] + * + * The sequence of statements + * + * <blockquote><pre> + * bb.putInt(0xCAFEBABE); + * bb.putShort(3); + * bb.putShort(45);</pre></blockquote> + * + * can, for example, be replaced by the single statement + * + * <blockquote><pre> + * bb.putInt(0xCAFEBABE).putShort(3).putShort(45);</pre></blockquote> + * +#end[byte] +#if[char] + * + * The sequence of statements + * + * <blockquote><pre> + * cb.put("text/"); + * cb.put(subtype); + * cb.put("; charset="); + * cb.put(enc);</pre></blockquote> + * + * can, for example, be replaced by the single statement + * + * <blockquote><pre> + * cb.put("text/").put(subtype).put("; charset=").put(enc);</pre></blockquote> + * +#end[char] + * + * + * @author Mark Reinhold + * @author JSR-51 Expert Group + * @since 1.4 + */ + +public abstract class $Type$Buffer + extends Buffer + implements Comparable<$Type$Buffer>{#if[char]?, Appendable, CharSequence, Readable} +{ + + // These fields are declared here rather than in Heap-X-Buffer in order to + // reduce the number of virtual method invocations needed to access these + // values, which is especially costly when coding small buffers. + // + final $type$[] hb; // Non-null only for heap buffers + final int offset; + boolean isReadOnly; // Valid only for heap buffers + + // Creates a new buffer with the given mark, position, limit, capacity, + // backing array, and array offset + // + $Type$Buffer(int mark, int pos, int lim, int cap, // package-private + $type$[] hb, int offset) + { + super(mark, pos, lim, cap); + this.hb = hb; + this.offset = offset; + } + + // Creates a new buffer with the given mark, position, limit, and capacity + // + $Type$Buffer(int mark, int pos, int lim, int cap) { // package-private + this(mark, pos, lim, cap, null, 0); + } + +#if[byte] + + /** + * Allocates a new direct $fulltype$ buffer. + * + * <p> The new buffer's position will be zero, its limit will be its + * capacity, its mark will be undefined, and each of its elements will be + * initialized to zero. Whether or not it has a + * {@link #hasArray </code>backing array<code>} is unspecified. + * + * @param capacity + * The new buffer's capacity, in $fulltype$s + * + * @return The new $fulltype$ buffer + * + * @throws IllegalArgumentException + * If the <tt>capacity</tt> is a negative integer + */ + public static $Type$Buffer allocateDirect(int capacity) { + return new Direct$Type$Buffer(capacity); + } + +#end[byte] + + /** + * Allocates a new $fulltype$ buffer. + * + * <p> The new buffer's position will be zero, its limit will be its + * capacity, its mark will be undefined, and each of its elements will be + * initialized to zero. It will have a {@link #array + * </code>backing array<code>}, and its {@link #arrayOffset </code>array + * offset<code>} will be zero. + * + * @param capacity + * The new buffer's capacity, in $fulltype$s + * + * @return The new $fulltype$ buffer + * + * @throws IllegalArgumentException + * If the <tt>capacity</tt> is a negative integer + */ + public static $Type$Buffer allocate(int capacity) { + if (capacity < 0) + throw new IllegalArgumentException(); + return new Heap$Type$Buffer(capacity, capacity); + } + + /** + * Wraps $a$ $fulltype$ array into a buffer. + * + * <p> The new buffer will be backed by the given $fulltype$ array; + * that is, modifications to the buffer will cause the array to be modified + * and vice versa. The new buffer's capacity will be + * <tt>array.length</tt>, its position will be <tt>offset</tt>, its limit + * will be <tt>offset + length</tt>, and its mark will be undefined. Its + * {@link #array </code>backing array<code>} will be the given array, and + * its {@link #arrayOffset </code>array offset<code>} will be zero. </p> + * + * @param array + * The array that will back the new buffer + * + * @param offset + * The offset of the subarray to be used; must be non-negative and + * no larger than <tt>array.length</tt>. The new buffer's position + * will be set to this value. + * + * @param length + * The length of the subarray to be used; + * must be non-negative and no larger than + * <tt>array.length - offset</tt>. + * The new buffer's limit will be set to <tt>offset + length</tt>. + * + * @return The new $fulltype$ buffer + * + * @throws IndexOutOfBoundsException + * If the preconditions on the <tt>offset</tt> and <tt>length</tt> + * parameters do not hold + */ + public static $Type$Buffer wrap($type$[] array, + int offset, int length) + { + try { + return new Heap$Type$Buffer(array, offset, length); + } catch (IllegalArgumentException x) { + throw new IndexOutOfBoundsException(); + } + } + + /** + * Wraps $a$ $fulltype$ array into a buffer. + * + * <p> The new buffer will be backed by the given $fulltype$ array; + * that is, modifications to the buffer will cause the array to be modified + * and vice versa. The new buffer's capacity and limit will be + * <tt>array.length</tt>, its position will be zero, and its mark will be + * undefined. Its {@link #array </code>backing array<code>} will be the + * given array, and its {@link #arrayOffset </code>array offset<code>} will + * be zero. </p> + * + * @param array + * The array that will back this buffer + * + * @return The new $fulltype$ buffer + */ + public static $Type$Buffer wrap($type$[] array) { + return wrap(array, 0, array.length); + } + +#if[char] + + /** + * Attempts to read characters into the specified character buffer. + * The buffer is used as a repository of characters as-is: the only + * changes made are the results of a put operation. No flipping or + * rewinding of the buffer is performed. + * + * @param target the buffer to read characters into + * @return The number of characters added to the buffer, or + * -1 if this source of characters is at its end + * @throws IOException if an I/O error occurs + * @throws NullPointerException if target is null + * @throws ReadOnlyBufferException if target is a read only buffer + * @since 1.5 + */ + public int read(CharBuffer target) throws IOException { + // Determine the number of bytes n that can be transferred + int targetRemaining = target.remaining(); + int remaining = remaining(); + if (remaining == 0) + return -1; + int n = Math.min(remaining, targetRemaining); + int limit = limit(); + // Set source limit to prevent target overflow + if (targetRemaining < remaining) + limit(position() + n); + try { + if (n > 0) + target.put(this); + } finally { + limit(limit); // restore real limit + } + return n; + } + + /** + * Wraps a character sequence into a buffer. + * + * <p> The content of the new, read-only buffer will be the content of the + * given character sequence. The buffer's capacity will be + * <tt>csq.length()</tt>, its position will be <tt>start</tt>, its limit + * will be <tt>end</tt>, and its mark will be undefined. </p> + * + * @param csq + * The character sequence from which the new character buffer is to + * be created + * + * @param start + * The index of the first character to be used; + * must be non-negative and no larger than <tt>csq.length()</tt>. + * The new buffer's position will be set to this value. + * + * @param end + * The index of the character following the last character to be + * used; must be no smaller than <tt>start</tt> and no larger + * than <tt>csq.length()</tt>. + * The new buffer's limit will be set to this value. + * + * @return The new character buffer + * + * @throws IndexOutOfBoundsException + * If the preconditions on the <tt>start</tt> and <tt>end</tt> + * parameters do not hold + */ + public static CharBuffer wrap(CharSequence csq, int start, int end) { + try { + return new StringCharBuffer(csq, start, end); + } catch (IllegalArgumentException x) { + throw new IndexOutOfBoundsException(); + } + } + + /** + * Wraps a character sequence into a buffer. + * + * <p> The content of the new, read-only buffer will be the content of the + * given character sequence. The new buffer's capacity and limit will be + * <tt>csq.length()</tt>, its position will be zero, and its mark will be + * undefined. </p> + * + * @param csq + * The character sequence from which the new character buffer is to + * be created + * + * @return The new character buffer + */ + public static CharBuffer wrap(CharSequence csq) { + return wrap(csq, 0, csq.length()); + } + +#end[char] + + /** + * Creates a new $fulltype$ buffer whose content is a shared subsequence of + * this buffer's content. + * + * <p> The content of the new buffer will start at this buffer's current + * position. Changes to this buffer's content will be visible in the new + * buffer, and vice versa; the two buffers' position, limit, and mark + * values will be independent. + * + * <p> The new buffer's position will be zero, its capacity and its limit + * will be the number of $fulltype$s remaining in this buffer, and its mark + * will be undefined. The new buffer will be direct if, and only if, this + * buffer is direct, and it will be read-only if, and only if, this buffer + * is read-only. </p> + * + * @return The new $fulltype$ buffer + */ + public abstract $Type$Buffer slice(); + + /** + * Creates a new $fulltype$ buffer that shares this buffer's content. + * + * <p> The content of the new buffer will be that of this buffer. Changes + * to this buffer's content will be visible in the new buffer, and vice + * versa; the two buffers' position, limit, and mark values will be + * independent. + * + * <p> The new buffer's capacity, limit, position, and mark values will be + * identical to those of this buffer. The new buffer will be direct if, + * and only if, this buffer is direct, and it will be read-only if, and + * only if, this buffer is read-only. </p> + * + * @return The new $fulltype$ buffer + */ + public abstract $Type$Buffer duplicate(); + + /** + * Creates a new, read-only $fulltype$ buffer that shares this buffer's + * content. + * + * <p> The content of the new buffer will be that of this buffer. Changes + * to this buffer's content will be visible in the new buffer; the new + * buffer itself, however, will be read-only and will not allow the shared + * content to be modified. The two buffers' position, limit, and mark + * values will be independent. + * + * <p> The new buffer's capacity, limit, position, and mark values will be + * identical to those of this buffer. + * + * <p> If this buffer is itself read-only then this method behaves in + * exactly the same way as the {@link #duplicate duplicate} method. </p> + * + * @return The new, read-only $fulltype$ buffer + */ + public abstract $Type$Buffer asReadOnlyBuffer(); + + + // -- Singleton get/put methods -- + + /** + * Relative <i>get</i> method. Reads the $fulltype$ at this buffer's + * current position, and then increments the position. </p> + * + * @return The $fulltype$ at the buffer's current position + * + * @throws BufferUnderflowException + * If the buffer's current position is not smaller than its limit + */ + public abstract $type$ get(); + + /** + * Relative <i>put</i> method <i>(optional operation)</i>. + * + * <p> Writes the given $fulltype$ into this buffer at the current + * position, and then increments the position. </p> + * + * @param $x$ + * The $fulltype$ to be written + * + * @return This buffer + * + * @throws BufferOverflowException + * If this buffer's current position is not smaller than its limit + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + */ + public abstract $Type$Buffer put($type$ $x$); + + /** + * Absolute <i>get</i> method. Reads the $fulltype$ at the given + * index. </p> + * + * @param index + * The index from which the $fulltype$ will be read + * + * @return The $fulltype$ at the given index + * + * @throws IndexOutOfBoundsException + * If <tt>index</tt> is negative + * or not smaller than the buffer's limit + */ + public abstract $type$ get(int index); + + /** + * Absolute <i>put</i> method <i>(optional operation)</i>. + * + * <p> Writes the given $fulltype$ into this buffer at the given + * index. </p> + * + * @param index + * The index at which the $fulltype$ will be written + * + * @param $x$ + * The $fulltype$ value to be written + * + * @return This buffer + * + * @throws IndexOutOfBoundsException + * If <tt>index</tt> is negative + * or not smaller than the buffer's limit + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + */ + public abstract $Type$Buffer put(int index, $type$ $x$); + + + // -- Bulk get operations -- + + /** + * Relative bulk <i>get</i> method. + * + * <p> This method transfers $fulltype$s from this buffer into the given + * destination array. If there are fewer $fulltype$s remaining in the + * buffer than are required to satisfy the request, that is, if + * <tt>length</tt> <tt>></tt> <tt>remaining()</tt>, then no + * $fulltype$s are transferred and a {@link BufferUnderflowException} is + * thrown. + * + * <p> Otherwise, this method copies <tt>length</tt> $fulltype$s from this + * buffer into the given array, starting at the current position of this + * buffer and at the given offset in the array. The position of this + * buffer is then incremented by <tt>length</tt>. + * + * <p> In other words, an invocation of this method of the form + * <tt>src.get(dst, off, len)</tt> has exactly the same effect as + * the loop + * + * <pre> + * for (int i = off; i < off + len; i++) + * dst[i] = src.get(); </pre> + * + * except that it first checks that there are sufficient $fulltype$s in + * this buffer and it is potentially much more efficient. </p> + * + * @param dst + * The array into which $fulltype$s are to be written + * + * @param offset + * The offset within the array of the first $fulltype$ to be + * written; must be non-negative and no larger than + * <tt>dst.length</tt> + * + * @param length + * The maximum number of $fulltype$s to be written to the given + * array; must be non-negative and no larger than + * <tt>dst.length - offset</tt> + * + * @return This buffer + * + * @throws BufferUnderflowException + * If there are fewer than <tt>length</tt> $fulltype$s + * remaining in this buffer + * + * @throws IndexOutOfBoundsException + * If the preconditions on the <tt>offset</tt> and <tt>length</tt> + * parameters do not hold + */ + public $Type$Buffer get($type$[] dst, int offset, int length) { + checkBounds(offset, length, dst.length); + if (length > remaining()) + throw new BufferUnderflowException(); + int end = offset + length; + for (int i = offset; i < end; i++) + dst[i] = get(); + return this; + } + + /** + * Relative bulk <i>get</i> method. + * + * <p> This method transfers $fulltype$s from this buffer into the given + * destination array. An invocation of this method of the form + * <tt>src.get(a)</tt> behaves in exactly the same way as the invocation + * + * <pre> + * src.get(a, 0, a.length) </pre> + * + * @return This buffer + * + * @throws BufferUnderflowException + * If there are fewer than <tt>length</tt> $fulltype$s + * remaining in this buffer + */ + public $Type$Buffer get($type$[] dst) { + return get(dst, 0, dst.length); + } + + + // -- Bulk put operations -- + + /** + * Relative bulk <i>put</i> method <i>(optional operation)</i>. + * + * <p> This method transfers the $fulltype$s remaining in the given source + * buffer into this buffer. If there are more $fulltype$s remaining in the + * source buffer than in this buffer, that is, if + * <tt>src.remaining()</tt> <tt>></tt> <tt>remaining()</tt>, + * then no $fulltype$s are transferred and a {@link + * BufferOverflowException} is thrown. + * + * <p> Otherwise, this method copies + * <i>n</i> = <tt>src.remaining()</tt> $fulltype$s from the given + * buffer into this buffer, starting at each buffer's current position. + * The positions of both buffers are then incremented by <i>n</i>. + * + * <p> In other words, an invocation of this method of the form + * <tt>dst.put(src)</tt> has exactly the same effect as the loop + * + * <pre> + * while (src.hasRemaining()) + * dst.put(src.get()); </pre> + * + * except that it first checks that there is sufficient space in this + * buffer and it is potentially much more efficient. </p> + * + * @param src + * The source buffer from which $fulltype$s are to be read; + * must not be this buffer + * + * @return This buffer + * + * @throws BufferOverflowException + * If there is insufficient space in this buffer + * for the remaining $fulltype$s in the source buffer + * + * @throws IllegalArgumentException + * If the source buffer is this buffer + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + */ + public $Type$Buffer put($Type$Buffer src) { + if (src == this) + throw new IllegalArgumentException(); + int n = src.remaining(); + if (n > remaining()) + throw new BufferOverflowException(); + for (int i = 0; i < n; i++) + put(src.get()); + return this; + } + + /** + * Relative bulk <i>put</i> method <i>(optional operation)</i>. + * + * <p> This method transfers $fulltype$s into this buffer from the given + * source array. If there are more $fulltype$s to be copied from the array + * than remain in this buffer, that is, if + * <tt>length</tt> <tt>></tt> <tt>remaining()</tt>, then no + * $fulltype$s are transferred and a {@link BufferOverflowException} is + * thrown. + * + * <p> Otherwise, this method copies <tt>length</tt> $fulltype$s from the + * given array into this buffer, starting at the given offset in the array + * and at the current position of this buffer. The position of this buffer + * is then incremented by <tt>length</tt>. + * + * <p> In other words, an invocation of this method of the form + * <tt>dst.put(src, off, len)</tt> has exactly the same effect as + * the loop + * + * <pre> + * for (int i = off; i < off + len; i++) + * dst.put(a[i]); </pre> + * + * except that it first checks that there is sufficient space in this + * buffer and it is potentially much more efficient. </p> + * + * @param src + * The array from which $fulltype$s are to be read + * + * @param offset + * The offset within the array of the first $fulltype$ to be read; + * must be non-negative and no larger than <tt>array.length</tt> + * + * @param length + * The number of $fulltype$s to be read from the given array; + * must be non-negative and no larger than + * <tt>array.length - offset</tt> + * + * @return This buffer + * + * @throws BufferOverflowException + * If there is insufficient space in this buffer + * + * @throws IndexOutOfBoundsException + * If the preconditions on the <tt>offset</tt> and <tt>length</tt> + * parameters do not hold + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + */ + public $Type$Buffer put($type$[] src, int offset, int length) { + checkBounds(offset, length, src.length); + if (length > remaining()) + throw new BufferOverflowException(); + int end = offset + length; + for (int i = offset; i < end; i++) + this.put(src[i]); + return this; + } + + /** + * Relative bulk <i>put</i> method <i>(optional operation)</i>. + * + * <p> This method transfers the entire content of the given source + * $fulltype$ array into this buffer. An invocation of this method of the + * form <tt>dst.put(a)</tt> behaves in exactly the same way as the + * invocation + * + * <pre> + * dst.put(a, 0, a.length) </pre> + * + * @return This buffer + * + * @throws BufferOverflowException + * If there is insufficient space in this buffer + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + */ + public final $Type$Buffer put($type$[] src) { + return put(src, 0, src.length); + } + +#if[char] + + /** + * Relative bulk <i>put</i> method <i>(optional operation)</i>. + * + * <p> This method transfers $fulltype$s from the given string into this + * buffer. If there are more $fulltype$s to be copied from the string than + * remain in this buffer, that is, if + * <tt>end - start</tt> <tt>></tt> <tt>remaining()</tt>, + * then no $fulltype$s are transferred and a {@link + * BufferOverflowException} is thrown. + * + * <p> Otherwise, this method copies + * <i>n</i> = <tt>end</tt> - <tt>start</tt> $fulltype$s + * from the given string into this buffer, starting at the given + * <tt>start</tt> index and at the current position of this buffer. The + * position of this buffer is then incremented by <i>n</i>. + * + * <p> In other words, an invocation of this method of the form + * <tt>dst.put(src, start, end)</tt> has exactly the same effect + * as the loop + * + * <pre> + * for (int i = start; i < end; i++) + * dst.put(src.charAt(i)); </pre> + * + * except that it first checks that there is sufficient space in this + * buffer and it is potentially much more efficient. </p> + * + * @param src + * The string from which $fulltype$s are to be read + * + * @param start + * The offset within the string of the first $fulltype$ to be read; + * must be non-negative and no larger than + * <tt>string.length()</tt> + * + * @param end + * The offset within the string of the last $fulltype$ to be read, + * plus one; must be non-negative and no larger than + * <tt>string.length()</tt> + * + * @return This buffer + * + * @throws BufferOverflowException + * If there is insufficient space in this buffer + * + * @throws IndexOutOfBoundsException + * If the preconditions on the <tt>start</tt> and <tt>end</tt> + * parameters do not hold + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + */ + public $Type$Buffer put(String src, int start, int end) { + checkBounds(start, end - start, src.length()); + for (int i = start; i < end; i++) + this.put(src.charAt(i)); + return this; + } + + /** + * Relative bulk <i>put</i> method <i>(optional operation)</i>. + * + * <p> This method transfers the entire content of the given source string + * into this buffer. An invocation of this method of the form + * <tt>dst.put(s)</tt> behaves in exactly the same way as the invocation + * + * <pre> + * dst.put(s, 0, s.length()) </pre> + * + * @return This buffer + * + * @throws BufferOverflowException + * If there is insufficient space in this buffer + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + */ + public final $Type$Buffer put(String src) { + return put(src, 0, src.length()); + } + +#end[char] + + + // -- Other stuff -- + + /** + * Tells whether or not this buffer is backed by an accessible $fulltype$ + * array. + * + * <p> If this method returns <tt>true</tt> then the {@link #array() array} + * and {@link #arrayOffset() arrayOffset} methods may safely be invoked. + * </p> + * + * @return <tt>true</tt> if, and only if, this buffer + * is backed by an array and is not read-only + */ + public final boolean hasArray() { + return (hb != null) && !isReadOnly; + } + + /** + * Returns the $fulltype$ array that backs this + * buffer <i>(optional operation)</i>. + * + * <p> Modifications to this buffer's content will cause the returned + * array's content to be modified, and vice versa. + * + * <p> Invoke the {@link #hasArray hasArray} method before invoking this + * method in order to ensure that this buffer has an accessible backing + * array. </p> + * + * @return The array that backs this buffer + * + * @throws ReadOnlyBufferException + * If this buffer is backed by an array but is read-only + * + * @throws UnsupportedOperationException + * If this buffer is not backed by an accessible array + */ + public final $type$[] array() { + if (hb == null) + throw new UnsupportedOperationException(); + if (isReadOnly) + throw new ReadOnlyBufferException(); + return hb; + } + + /** + * Returns the offset within this buffer's backing array of the first + * element of the buffer <i>(optional operation)</i>. + * + * <p> If this buffer is backed by an array then buffer position <i>p</i> + * corresponds to array index <i>p</i> + <tt>arrayOffset()</tt>. + * + * <p> Invoke the {@link #hasArray hasArray} method before invoking this + * method in order to ensure that this buffer has an accessible backing + * array. </p> + * + * @return The offset within this buffer's array + * of the first element of the buffer + * + * @throws ReadOnlyBufferException + * If this buffer is backed by an array but is read-only + * + * @throws UnsupportedOperationException + * If this buffer is not backed by an accessible array + */ + public final int arrayOffset() { + if (hb == null) + throw new UnsupportedOperationException(); + if (isReadOnly) + throw new ReadOnlyBufferException(); + return offset; + } + + /** + * Compacts this buffer <i>(optional operation)</i>. + * + * <p> The $fulltype$s between the buffer's current position and its limit, + * if any, are copied to the beginning of the buffer. That is, the + * $fulltype$ at index <i>p</i> = <tt>position()</tt> is copied + * to index zero, the $fulltype$ at index <i>p</i> + 1 is copied + * to index one, and so forth until the $fulltype$ at index + * <tt>limit()</tt> - 1 is copied to index + * <i>n</i> = <tt>limit()</tt> - <tt>1</tt> - <i>p</i>. + * The buffer's position is then set to <i>n+1</i> and its limit is set to + * its capacity. The mark, if defined, is discarded. + * + * <p> The buffer's position is set to the number of $fulltype$s copied, + * rather than to zero, so that an invocation of this method can be + * followed immediately by an invocation of another relative <i>put</i> + * method. </p> + * +#if[byte] + * + * <p> Invoke this method after writing data from a buffer in case the + * write was incomplete. The following loop, for example, copies bytes + * from one channel to another via the buffer <tt>buf</tt>: + * + * <blockquote><pre> + * buf.clear(); // Prepare buffer for use + * while (in.read(buf) >= 0 || buf.position != 0) { + * buf.flip(); + * out.write(buf); + * buf.compact(); // In case of partial write + * }</pre></blockquote> + * +#end[byte] + * + * @return This buffer + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + */ + public abstract $Type$Buffer compact(); + + /** + * Tells whether or not this $fulltype$ buffer is direct. </p> + * + * @return <tt>true</tt> if, and only if, this buffer is direct + */ + public abstract boolean isDirect(); + +#if[!char] + + /** + * Returns a string summarizing the state of this buffer. </p> + * + * @return A summary string + */ + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append(getClass().getName()); + sb.append("[pos="); + sb.append(position()); + sb.append(" lim="); + sb.append(limit()); + sb.append(" cap="); + sb.append(capacity()); + sb.append("]"); + return sb.toString(); + } + +#end[!char] + + + // ## Should really use unchecked accessors here for speed + + /** + * Returns the current hash code of this buffer. + * + * <p> The hash code of a $type$ buffer depends only upon its remaining + * elements; that is, upon the elements from <tt>position()</tt> up to, and + * including, the element at <tt>limit()</tt> - <tt>1</tt>. + * + * <p> Because buffer hash codes are content-dependent, it is inadvisable + * to use buffers as keys in hash maps or similar data structures unless it + * is known that their contents will not change. </p> + * + * @return The current hash code of this buffer + */ + public int hashCode() { + int h = 1; + int p = position(); + for (int i = limit() - 1; i >= p; i--) + h = 31 * h + (int)get(i); + return h; + } + + /** + * Tells whether or not this buffer is equal to another object. + * + * <p> Two $type$ buffers are equal if, and only if, + * + * <p><ol> + * + * <li><p> They have the same element type, </p></li> + * + * <li><p> They have the same number of remaining elements, and + * </p></li> + * + * <li><p> The two sequences of remaining elements, considered + * independently of their starting positions, are pointwise equal. + * </p></li> + * + * </ol> + * + * <p> A $type$ buffer is not equal to any other type of object. </p> + * + * @param ob The object to which this buffer is to be compared + * + * @return <tt>true</tt> if, and only if, this buffer is equal to the + * given object + */ + public boolean equals(Object ob) { + if (this == ob) + return true; + if (!(ob instanceof $Type$Buffer)) + return false; + $Type$Buffer that = ($Type$Buffer)ob; + if (this.remaining() != that.remaining()) + return false; + int p = this.position(); + for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) { + $type$ v1 = this.get(i); + $type$ v2 = that.get(j); + if (v1 != v2) { + if ((v1 != v1) && (v2 != v2)) // For float and double + continue; + return false; + } + } + return true; + } + + /** + * Compares this buffer to another. + * + * <p> Two $type$ buffers are compared by comparing their sequences of + * remaining elements lexicographically, without regard to the starting + * position of each sequence within its corresponding buffer. + * + * <p> A $type$ buffer is not comparable to any other type of object. + * + * @return A negative integer, zero, or a positive integer as this buffer + * is less than, equal to, or greater than the given buffer + */ + public int compareTo($Type$Buffer that) { + int n = this.position() + Math.min(this.remaining(), that.remaining()); + for (int i = this.position(), j = that.position(); i < n; i++, j++) { + $type$ v1 = this.get(i); + $type$ v2 = that.get(j); + if (v1 == v2) + continue; + if ((v1 != v1) && (v2 != v2)) // For float and double + continue; + if (v1 < v2) + return -1; + return +1; + } + return this.remaining() - that.remaining(); + } + + + + // -- Other char stuff -- + +#if[char] + + /** + * Returns a string containing the characters in this buffer. + * + * <p> The first character of the resulting string will be the character at + * this buffer's position, while the last character will be the character + * at index <tt>limit()</tt> - 1. Invoking this method does not + * change the buffer's position. </p> + * + * @return The specified string + */ + public String toString() { + return toString(position(), limit()); + } + + abstract String toString(int start, int end); // package-private + + + // --- Methods to support CharSequence --- + + /** + * Returns the length of this character buffer. + * + * <p> When viewed as a character sequence, the length of a character + * buffer is simply the number of characters between the position + * (inclusive) and the limit (exclusive); that is, it is equivalent to + * <tt>remaining()</tt>. </p> + * + * @return The length of this character buffer + */ + public final int length() { + return remaining(); + } + + /** + * Reads the character at the given index relative to the current + * position. </p> + * + * @param index + * The index of the character to be read, relative to the position; + * must be non-negative and smaller than <tt>remaining()</tt> + * + * @return The character at index + * <tt>position() + index</tt> + * + * @throws IndexOutOfBoundsException + * If the preconditions on <tt>index</tt> do not hold + */ + public final char charAt(int index) { + return get(position() + checkIndex(index, 1)); + } + + /** + * Creates a new character buffer that represents the specified subsequence + * of this buffer, relative to the current position. + * + * <p> The new buffer will share this buffer's content; that is, if the + * content of this buffer is mutable then modifications to one buffer will + * cause the other to be modified. The new buffer's capacity will be that + * of this buffer, its position will be + * <tt>position()</tt> + <tt>start</tt>, and its limit will be + * <tt>position()</tt> + <tt>end</tt>. The new buffer will be + * direct if, and only if, this buffer is direct, and it will be read-only + * if, and only if, this buffer is read-only. </p> + * + * @param start + * The index, relative to the current position, of the first + * character in the subsequence; must be non-negative and no larger + * than <tt>remaining()</tt> + * + * @param end + * The index, relative to the current position, of the character + * following the last character in the subsequence; must be no + * smaller than <tt>start</tt> and no larger than + * <tt>remaining()</tt> + * + * @return The new character buffer + * + * @throws IndexOutOfBoundsException + * If the preconditions on <tt>start</tt> and <tt>end</tt> + * do not hold + */ + public abstract CharBuffer subSequence(int start, int end); + + + // --- Methods to support Appendable --- + + /** + * Appends the specified character sequence to this + * buffer <i>(optional operation)</i>. + * + * <p> An invocation of this method of the form <tt>dst.append(csq)</tt> + * behaves in exactly the same way as the invocation + * + * <pre> + * dst.put(csq.toString()) </pre> + * + * <p> Depending on the specification of <tt>toString</tt> for the + * character sequence <tt>csq</tt>, the entire sequence may not be + * appended. For instance, invoking the {@link $Type$Buffer#toString() + * toString} method of a character buffer will return a subsequence whose + * content depends upon the buffer's position and limit. + * + * @param csq + * The character sequence to append. If <tt>csq</tt> is + * <tt>null</tt>, then the four characters <tt>"null"</tt> are + * appended to this character buffer. + * + * @return This buffer + * + * @throws BufferOverflowException + * If there is insufficient space in this buffer + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + * + * @since 1.5 + */ + public $Type$Buffer append(CharSequence csq) { + if (csq == null) + return put("null"); + else + return put(csq.toString()); + } + + /** + * Appends a subsequence of the specified character sequence to this + * buffer <i>(optional operation)</i>. + * + * <p> An invocation of this method of the form <tt>dst.append(csq, start, + * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in exactly the + * same way as the invocation + * + * <pre> + * dst.put(csq.subSequence(start, end).toString()) </pre> + * + * @param csq + * The character sequence from which a subsequence will be + * appended. If <tt>csq</tt> is <tt>null</tt>, then characters + * will be appended as if <tt>csq</tt> contained the four + * characters <tt>"null"</tt>. + * + * @return This buffer + * + * @throws BufferOverflowException + * If there is insufficient space in this buffer + * + * @throws IndexOutOfBoundsException + * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt> + * is greater than <tt>end</tt>, or <tt>end</tt> is greater than + * <tt>csq.length()</tt> + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + * + * @since 1.5 + */ + public $Type$Buffer append(CharSequence csq, int start, int end) { + CharSequence cs = (csq == null ? "null" : csq); + return put(cs.subSequence(start, end).toString()); + } + + /** + * Appends the specified $fulltype$ to this + * buffer <i>(optional operation)</i>. + * + * <p> An invocation of this method of the form <tt>dst.append($x$)</tt> + * behaves in exactly the same way as the invocation + * + * <pre> + * dst.put($x$) </pre> + * + * @param $x$ + * The 16-bit $fulltype$ to append + * + * @return This buffer + * + * @throws BufferOverflowException + * If there is insufficient space in this buffer + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + * + * @since 1.5 + */ + public $Type$Buffer append($type$ $x$) { + return put($x$); + } + +#end[char] + + + // -- Other byte stuff: Access to binary data -- + +#if[!byte] + + /** + * Retrieves this buffer's byte order. + * + * <p> The byte order of $a$ $fulltype$ buffer created by allocation or by + * wrapping an existing <tt>$type$</tt> array is the {@link + * ByteOrder#nativeOrder </code>native order<code>} of the underlying + * hardware. The byte order of $a$ $fulltype$ buffer created as a <a + * href="ByteBuffer.html#views">view</a> of a byte buffer is that of the + * byte buffer at the moment that the view is created. </p> + * + * @return This buffer's byte order + */ + public abstract ByteOrder order(); + +#end[!byte] + +#if[byte] + + boolean bigEndian // package-private + = true; + boolean nativeByteOrder // package-private + = (Bits.byteOrder() == ByteOrder.BIG_ENDIAN); + + /** + * Retrieves this buffer's byte order. + * + * <p> The byte order is used when reading or writing multibyte values, and + * when creating buffers that are views of this byte buffer. The order of + * a newly-created byte buffer is always {@link ByteOrder#BIG_ENDIAN + * BIG_ENDIAN}. </p> + * + * @return This buffer's byte order + */ + public final ByteOrder order() { + return bigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; + } + + /** + * Modifies this buffer's byte order. </p> + * + * @param bo + * The new byte order, + * either {@link ByteOrder#BIG_ENDIAN BIG_ENDIAN} + * or {@link ByteOrder#LITTLE_ENDIAN LITTLE_ENDIAN} + * + * @return This buffer + */ + public final $Type$Buffer order(ByteOrder bo) { + bigEndian = (bo == ByteOrder.BIG_ENDIAN); + nativeByteOrder = + (bigEndian == (Bits.byteOrder() == ByteOrder.BIG_ENDIAN)); + return this; + } + + // Unchecked accessors, for use by ByteBufferAs-X-Buffer classes + // + abstract byte _get(int i); // package-private + abstract void _put(int i, byte b); // package-private + + // #BIN + // + // Binary-data access methods for short, char, int, long, float, + // and double will be inserted here + +#end[byte] + +}
--- a/src/share/classes/java/nio/charset/Charset-X-Coder.java Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,972 +0,0 @@ -/* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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. - */ - -#warn This file is preprocessed before being compiled - -package java.nio.charset; - -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.BufferOverflowException; -import java.nio.BufferUnderflowException; -import java.lang.ref.WeakReference; -import java.nio.charset.CoderMalfunctionError; // javadoc - - -/** - * An engine that can transform a sequence of $itypesPhrase$ into a sequence of - * $otypesPhrase$. - * - * <a name="steps"> - * - * <p> The input $itype$ sequence is provided in a $itype$ buffer or a series - * of such buffers. The output $otype$ sequence is written to a $otype$ buffer - * or a series of such buffers. $A$ $coder$ should always be used by making - * the following sequence of method invocations, hereinafter referred to as $a$ - * <i>$coding$ operation</i>: - * - * <ol> - * - * <li><p> Reset the $coder$ via the {@link #reset reset} method, unless it - * has not been used before; </p></li> - * - * <li><p> Invoke the {@link #$code$ $code$} method zero or more times, as - * long as additional input may be available, passing <tt>false</tt> for the - * <tt>endOfInput</tt> argument and filling the input buffer and flushing the - * output buffer between invocations; </p></li> - * - * <li><p> Invoke the {@link #$code$ $code$} method one final time, passing - * <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li> - * - * <li><p> Invoke the {@link #flush flush} method so that the $coder$ can - * flush any internal state to the output buffer. </p></li> - * - * </ol> - * - * Each invocation of the {@link #$code$ $code$} method will $code$ as many - * $itype$s as possible from the input buffer, writing the resulting $otype$s - * to the output buffer. The {@link #$code$ $code$} method returns when more - * input is required, when there is not enough room in the output buffer, or - * when $a$ $coding$ error has occurred. In each case a {@link CoderResult} - * object is returned to describe the reason for termination. An invoker can - * examine this object and fill the input buffer, flush the output buffer, or - * attempt to recover from $a$ $coding$ error, as appropriate, and try again. - * - * <a name="ce"> - * - * <p> There are two general types of $coding$ errors. If the input $itype$ - * sequence is $notLegal$ then the input is considered <i>malformed</i>. If - * the input $itype$ sequence is legal but cannot be mapped to a valid - * $outSequence$ then an <i>unmappable character</i> has been encountered. - * - * <a name="cae"> - * - * <p> How $a$ $coding$ error is handled depends upon the action requested for - * that type of error, which is described by an instance of the {@link - * CodingErrorAction} class. The possible error actions are to {@link - * CodingErrorAction#IGNORE </code>ignore<code>} the erroneous input, {@link - * CodingErrorAction#REPORT </code>report<code>} the error to the invoker via - * the returned {@link CoderResult} object, or {@link CodingErrorAction#REPLACE - * </code>replace<code>} the erroneous input with the current value of the - * replacement $replTypeName$. The replacement - * -#if[encoder] - * is initially set to the $coder$'s default replacement, which often - * (but not always) has the initial value $defaultReplName$; -#end[encoder] -#if[decoder] - * has the initial value $defaultReplName$; -#end[decoder] - * - * its value may be changed via the {@link #replaceWith($replFQType$) - * replaceWith} method. - * - * <p> The default action for malformed-input and unmappable-character errors - * is to {@link CodingErrorAction#REPORT </code>report<code>} them. The - * malformed-input error action may be changed via the {@link - * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the - * unmappable-character action may be changed via the {@link - * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method. - * - * <p> This class is designed to handle many of the details of the $coding$ - * process, including the implementation of error actions. $A$ $coder$ for a - * specific charset, which is a concrete subclass of this class, need only - * implement the abstract {@link #$code$Loop $code$Loop} method, which - * encapsulates the basic $coding$ loop. A subclass that maintains internal - * state should, additionally, override the {@link #implFlush implFlush} and - * {@link #implReset implReset} methods. - * - * <p> Instances of this class are not safe for use by multiple concurrent - * threads. </p> - * - * - * @author Mark Reinhold - * @author JSR-51 Expert Group - * @since 1.4 - * - * @see ByteBuffer - * @see CharBuffer - * @see Charset - * @see Charset$OtherCoder$ - */ - -public abstract class Charset$Coder$ { - - private final Charset charset; - private final float average$ItypesPerOtype$; - private final float max$ItypesPerOtype$; - - private $replType$ replacement; - private CodingErrorAction malformedInputAction - = CodingErrorAction.REPORT; - private CodingErrorAction unmappableCharacterAction - = CodingErrorAction.REPORT; - - // Internal states - // - private static final int ST_RESET = 0; - private static final int ST_CODING = 1; - private static final int ST_END = 2; - private static final int ST_FLUSHED = 3; - - private int state = ST_RESET; - - private static String stateNames[] - = { "RESET", "CODING", "CODING_END", "FLUSHED" }; - - - /** - * Initializes a new $coder$. The new $coder$ will have the given - * $otypes-per-itype$ and replacement values. </p> - * - * @param average$ItypesPerOtype$ - * A positive float value indicating the expected number of - * $otype$s that will be produced for each input $itype$ - * - * @param max$ItypesPerOtype$ - * A positive float value indicating the maximum number of - * $otype$s that will be produced for each input $itype$ - * - * @param replacement - * The initial replacement; must not be <tt>null</tt>, must have - * non-zero length, must not be longer than max$ItypesPerOtype$, - * and must be {@link #isLegalReplacement </code>legal<code>} - * - * @throws IllegalArgumentException - * If the preconditions on the parameters do not hold - */ - {#if[encoder]?protected:private} - Charset$Coder$(Charset cs, - float average$ItypesPerOtype$, - float max$ItypesPerOtype$, - $replType$ replacement) - { - this.charset = cs; - if (average$ItypesPerOtype$ <= 0.0f) - throw new IllegalArgumentException("Non-positive " - + "average$ItypesPerOtype$"); - if (max$ItypesPerOtype$ <= 0.0f) - throw new IllegalArgumentException("Non-positive " - + "max$ItypesPerOtype$"); - if (!Charset.atBugLevel("1.4")) { - if (average$ItypesPerOtype$ > max$ItypesPerOtype$) - throw new IllegalArgumentException("average$ItypesPerOtype$" - + " exceeds " - + "max$ItypesPerOtype$"); - } - this.replacement = replacement; - this.average$ItypesPerOtype$ = average$ItypesPerOtype$; - this.max$ItypesPerOtype$ = max$ItypesPerOtype$; - replaceWith(replacement); - } - - /** - * Initializes a new $coder$. The new $coder$ will have the given - * $otypes-per-itype$ values and its replacement will be the - * $replTypeName$ $defaultReplName$. </p> - * - * @param average$ItypesPerOtype$ - * A positive float value indicating the expected number of - * $otype$s that will be produced for each input $itype$ - * - * @param max$ItypesPerOtype$ - * A positive float value indicating the maximum number of - * $otype$s that will be produced for each input $itype$ - * - * @throws IllegalArgumentException - * If the preconditions on the parameters do not hold - */ - protected Charset$Coder$(Charset cs, - float average$ItypesPerOtype$, - float max$ItypesPerOtype$) - { - this(cs, - average$ItypesPerOtype$, max$ItypesPerOtype$, - $defaultRepl$); - } - - /** - * Returns the charset that created this $coder$. </p> - * - * @return This $coder$'s charset - */ - public final Charset charset() { - return charset; - } - - /** - * Returns this $coder$'s replacement value. </p> - * - * @return This $coder$'s current replacement, - * which is never <tt>null</tt> and is never empty - */ - public final $replType$ replacement() { - return replacement; - } - - /** - * Changes this $coder$'s replacement value. - * - * <p> This method invokes the {@link #implReplaceWith implReplaceWith} - * method, passing the new replacement, after checking that the new - * replacement is acceptable. </p> - * - * @param newReplacement - * -#if[decoder] - * The new replacement; must not be <tt>null</tt> - * and must have non-zero length -#end[decoder] -#if[encoder] - * The new replacement; must not be <tt>null</tt>, must have - * non-zero length, must not be longer than the value returned by - * the {@link #max$ItypesPerOtype$() max$ItypesPerOtype$} method, and - * must be {@link #isLegalReplacement </code>legal<code>} -#end[encoder] - * - * @return This $coder$ - * - * @throws IllegalArgumentException - * If the preconditions on the parameter do not hold - */ - public final Charset$Coder$ replaceWith($replType$ newReplacement) { - if (newReplacement == null) - throw new IllegalArgumentException("Null replacement"); - int len = newReplacement.$replLength$; - if (len == 0) - throw new IllegalArgumentException("Empty replacement"); - if (len > max$ItypesPerOtype$) - throw new IllegalArgumentException("Replacement too long"); -#if[encoder] - if (!isLegalReplacement(newReplacement)) - throw new IllegalArgumentException("Illegal replacement"); -#end[encoder] - this.replacement = newReplacement; - implReplaceWith(newReplacement); - return this; - } - - /** - * Reports a change to this $coder$'s replacement value. - * - * <p> The default implementation of this method does nothing. This method - * should be overridden by $coder$s that require notification of changes to - * the replacement. </p> - * - * @param newReplacement - */ - protected void implReplaceWith($replType$ newReplacement) { - } - -#if[encoder] - - private WeakReference<CharsetDecoder> cachedDecoder = null; - - /** - * Tells whether or not the given byte array is a legal replacement value - * for this encoder. - * - * <p> A replacement is legal if, and only if, it is a legal sequence of - * bytes in this encoder's charset; that is, it must be possible to decode - * the replacement into one or more sixteen-bit Unicode characters. - * - * <p> The default implementation of this method is not very efficient; it - * should generally be overridden to improve performance. </p> - * - * @param repl The byte array to be tested - * - * @return <tt>true</tt> if, and only if, the given byte array - * is a legal replacement value for this encoder - */ - public boolean isLegalReplacement(byte[] repl) { - WeakReference<CharsetDecoder> wr = cachedDecoder; - CharsetDecoder dec = null; - if ((wr == null) || ((dec = wr.get()) == null)) { - dec = charset().newDecoder(); - dec.onMalformedInput(CodingErrorAction.REPORT); - dec.onUnmappableCharacter(CodingErrorAction.REPORT); - cachedDecoder = new WeakReference<CharsetDecoder>(dec); - } else { - dec.reset(); - } - ByteBuffer bb = ByteBuffer.wrap(repl); - CharBuffer cb = CharBuffer.allocate((int)(bb.remaining() - * dec.maxCharsPerByte())); - CoderResult cr = dec.decode(bb, cb, true); - return !cr.isError(); - } - -#end[encoder] - - /** - * Returns this $coder$'s current action for malformed-input errors. </p> - * - * @return The current malformed-input action, which is never <tt>null</tt> - */ - public CodingErrorAction malformedInputAction() { - return malformedInputAction; - } - - /** - * Changes this $coder$'s action for malformed-input errors. </p> - * - * <p> This method invokes the {@link #implOnMalformedInput - * implOnMalformedInput} method, passing the new action. </p> - * - * @param newAction The new action; must not be <tt>null</tt> - * - * @return This $coder$ - * - * @throws IllegalArgumentException - * If the precondition on the parameter does not hold - */ - public final Charset$Coder$ onMalformedInput(CodingErrorAction newAction) { - if (newAction == null) - throw new IllegalArgumentException("Null action"); - malformedInputAction = newAction; - implOnMalformedInput(newAction); - return this; - } - - /** - * Reports a change to this $coder$'s malformed-input action. - * - * <p> The default implementation of this method does nothing. This method - * should be overridden by $coder$s that require notification of changes to - * the malformed-input action. </p> - */ - protected void implOnMalformedInput(CodingErrorAction newAction) { } - - /** - * Returns this $coder$'s current action for unmappable-character errors. - * </p> - * - * @return The current unmappable-character action, which is never - * <tt>null</tt> - */ - public CodingErrorAction unmappableCharacterAction() { - return unmappableCharacterAction; - } - - /** - * Changes this $coder$'s action for unmappable-character errors. - * - * <p> This method invokes the {@link #implOnUnmappableCharacter - * implOnUnmappableCharacter} method, passing the new action. </p> - * - * @param newAction The new action; must not be <tt>null</tt> - * - * @return This $coder$ - * - * @throws IllegalArgumentException - * If the precondition on the parameter does not hold - */ - public final Charset$Coder$ onUnmappableCharacter(CodingErrorAction - newAction) - { - if (newAction == null) - throw new IllegalArgumentException("Null action"); - unmappableCharacterAction = newAction; - implOnUnmappableCharacter(newAction); - return this; - } - - /** - * Reports a change to this $coder$'s unmappable-character action. - * - * <p> The default implementation of this method does nothing. This method - * should be overridden by $coder$s that require notification of changes to - * the unmappable-character action. </p> - */ - protected void implOnUnmappableCharacter(CodingErrorAction newAction) { } - - /** - * Returns the average number of $otype$s that will be produced for each - * $itype$ of input. This heuristic value may be used to estimate the size - * of the output buffer required for a given input sequence. </p> - * - * @return The average number of $otype$s produced - * per $itype$ of input - */ - public final float average$ItypesPerOtype$() { - return average$ItypesPerOtype$; - } - - /** - * Returns the maximum number of $otype$s that will be produced for each - * $itype$ of input. This value may be used to compute the worst-case size - * of the output buffer required for a given input sequence. </p> - * - * @return The maximum number of $otype$s that will be produced per - * $itype$ of input - */ - public final float max$ItypesPerOtype$() { - return max$ItypesPerOtype$; - } - - /** - * $Code$s as many $itype$s as possible from the given input buffer, - * writing the results to the given output buffer. - * - * <p> The buffers are read from, and written to, starting at their current - * positions. At most {@link Buffer#remaining in.remaining()} $itype$s - * will be read and at most {@link Buffer#remaining out.remaining()} - * $otype$s will be written. The buffers' positions will be advanced to - * reflect the $itype$s read and the $otype$s written, but their marks and - * limits will not be modified. - * - * <p> In addition to reading $itype$s from the input buffer and writing - * $otype$s to the output buffer, this method returns a {@link CoderResult} - * object to describe its reason for termination: - * - * <ul> - * - * <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the - * input buffer as possible has been $code$d. If there is no further - * input then the invoker can proceed to the next step of the - * <a href="#steps">$coding$ operation</a>. Otherwise this method - * should be invoked again with further input. </p></li> - * - * <li><p> {@link CoderResult#OVERFLOW} indicates that there is - * insufficient space in the output buffer to $code$ any more $itype$s. - * This method should be invoked again with an output buffer that has - * more {@linkplain Buffer#remaining remaining} $otype$s. This is - * typically done by draining any $code$d $otype$s from the output - * buffer. </p></li> - * - * <li><p> A {@link CoderResult#malformedForLength - * </code>malformed-input<code>} result indicates that a malformed-input - * error has been detected. The malformed $itype$s begin at the input - * buffer's (possibly incremented) position; the number of malformed - * $itype$s may be determined by invoking the result object's {@link - * CoderResult#length() length} method. This case applies only if the - * {@link #onMalformedInput </code>malformed action<code>} of this $coder$ - * is {@link CodingErrorAction#REPORT}; otherwise the malformed input - * will be ignored or replaced, as requested. </p></li> - * - * <li><p> An {@link CoderResult#unmappableForLength - * </code>unmappable-character<code>} result indicates that an - * unmappable-character error has been detected. The $itype$s that - * $code$ the unmappable character begin at the input buffer's (possibly - * incremented) position; the number of such $itype$s may be determined - * by invoking the result object's {@link CoderResult#length() length} - * method. This case applies only if the {@link #onUnmappableCharacter - * </code>unmappable action<code>} of this $coder$ is {@link - * CodingErrorAction#REPORT}; otherwise the unmappable character will be - * ignored or replaced, as requested. </p></li> - * - * </ul> - * - * In any case, if this method is to be reinvoked in the same $coding$ - * operation then care should be taken to preserve any $itype$s remaining - * in the input buffer so that they are available to the next invocation. - * - * <p> The <tt>endOfInput</tt> parameter advises this method as to whether - * the invoker can provide further input beyond that contained in the given - * input buffer. If there is a possibility of providing additional input - * then the invoker should pass <tt>false</tt> for this parameter; if there - * is no possibility of providing further input then the invoker should - * pass <tt>true</tt>. It is not erroneous, and in fact it is quite - * common, to pass <tt>false</tt> in one invocation and later discover that - * no further input was actually available. It is critical, however, that - * the final invocation of this method in a sequence of invocations always - * pass <tt>true</tt> so that any remaining un$code$d input will be treated - * as being malformed. - * - * <p> This method works by invoking the {@link #$code$Loop $code$Loop} - * method, interpreting its results, handling error conditions, and - * reinvoking it as necessary. </p> - * - * - * @param in - * The input $itype$ buffer - * - * @param out - * The output $otype$ buffer - * - * @param endOfInput - * <tt>true</tt> if, and only if, the invoker can provide no - * additional input $itype$s beyond those in the given buffer - * - * @return A coder-result object describing the reason for termination - * - * @throws IllegalStateException - * If $a$ $coding$ operation is already in progress and the previous - * step was an invocation neither of the {@link #reset reset} - * method, nor of this method with a value of <tt>false</tt> for - * the <tt>endOfInput</tt> parameter, nor of this method with a - * value of <tt>true</tt> for the <tt>endOfInput</tt> parameter - * but a return value indicating an incomplete $coding$ operation - * - * @throws CoderMalfunctionError - * If an invocation of the $code$Loop method threw - * an unexpected exception - */ - public final CoderResult $code$($Itype$Buffer in, $Otype$Buffer out, - boolean endOfInput) - { - int newState = endOfInput ? ST_END : ST_CODING; - if ((state != ST_RESET) && (state != ST_CODING) - && !(endOfInput && (state == ST_END))) - throwIllegalStateException(state, newState); - state = newState; - - for (;;) { - - CoderResult cr; - try { - cr = $code$Loop(in, out); - } catch (BufferUnderflowException x) { - throw new CoderMalfunctionError(x); - } catch (BufferOverflowException x) { - throw new CoderMalfunctionError(x); - } - - if (cr.isOverflow()) - return cr; - - if (cr.isUnderflow()) { - if (endOfInput && in.hasRemaining()) { - cr = CoderResult.malformedForLength(in.remaining()); - // Fall through to malformed-input case - } else { - return cr; - } - } - - CodingErrorAction action = null; - if (cr.isMalformed()) - action = malformedInputAction; - else if (cr.isUnmappable()) - action = unmappableCharacterAction; - else - assert false : cr.toString(); - - if (action == CodingErrorAction.REPORT) - return cr; - - if (action == CodingErrorAction.REPLACE) { - if (out.remaining() < replacement.$replLength$) - return CoderResult.OVERFLOW; - out.put(replacement); - } - - if ((action == CodingErrorAction.IGNORE) - || (action == CodingErrorAction.REPLACE)) { - // Skip erroneous input either way - in.position(in.position() + cr.length()); - continue; - } - - assert false; - } - - } - - /** - * Flushes this $coder$. - * - * <p> Some $coder$s maintain internal state and may need to write some - * final $otype$s to the output buffer once the overall input sequence has - * been read. - * - * <p> Any additional output is written to the output buffer beginning at - * its current position. At most {@link Buffer#remaining out.remaining()} - * $otype$s will be written. The buffer's position will be advanced - * appropriately, but its mark and limit will not be modified. - * - * <p> If this method completes successfully then it returns {@link - * CoderResult#UNDERFLOW}. If there is insufficient room in the output - * buffer then it returns {@link CoderResult#OVERFLOW}. If this happens - * then this method must be invoked again, with an output buffer that has - * more room, in order to complete the current <a href="#steps">$coding$ - * operation</a>. - * - * <p> If this $coder$ has already been flushed then invoking this method - * has no effect. - * - * <p> This method invokes the {@link #implFlush implFlush} method to - * perform the actual flushing operation. </p> - * - * @param out - * The output $otype$ buffer - * - * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or - * {@link CoderResult#OVERFLOW} - * - * @throws IllegalStateException - * If the previous step of the current $coding$ operation was an - * invocation neither of the {@link #flush flush} method nor of - * the three-argument {@link - * #$code$($Itype$Buffer,$Otype$Buffer,boolean) $code$} method - * with a value of <tt>true</tt> for the <tt>endOfInput</tt> - * parameter - */ - public final CoderResult flush($Otype$Buffer out) { - if (state == ST_END) { - CoderResult cr = implFlush(out); - if (cr.isUnderflow()) - state = ST_FLUSHED; - return cr; - } - - if (state != ST_FLUSHED) - throwIllegalStateException(state, ST_FLUSHED); - - return CoderResult.UNDERFLOW; // Already flushed - } - - /** - * Flushes this $coder$. - * - * <p> The default implementation of this method does nothing, and always - * returns {@link CoderResult#UNDERFLOW}. This method should be overridden - * by $coder$s that may need to write final $otype$s to the output buffer - * once the entire input sequence has been read. </p> - * - * @param out - * The output $otype$ buffer - * - * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or - * {@link CoderResult#OVERFLOW} - */ - protected CoderResult implFlush($Otype$Buffer out) { - return CoderResult.UNDERFLOW; - } - - /** - * Resets this $coder$, clearing any internal state. - * - * <p> This method resets charset-independent state and also invokes the - * {@link #implReset() implReset} method in order to perform any - * charset-specific reset actions. </p> - * - * @return This $coder$ - * - */ - public final Charset$Coder$ reset() { - implReset(); - state = ST_RESET; - return this; - } - - /** - * Resets this $coder$, clearing any charset-specific internal state. - * - * <p> The default implementation of this method does nothing. This method - * should be overridden by $coder$s that maintain internal state. </p> - */ - protected void implReset() { } - - /** - * $Code$s one or more $itype$s into one or more $otype$s. - * - * <p> This method encapsulates the basic $coding$ loop, $coding$ as many - * $itype$s as possible until it either runs out of input, runs out of room - * in the output buffer, or encounters $a$ $coding$ error. This method is - * invoked by the {@link #$code$ $code$} method, which handles result - * interpretation and error recovery. - * - * <p> The buffers are read from, and written to, starting at their current - * positions. At most {@link Buffer#remaining in.remaining()} $itype$s - * will be read, and at most {@link Buffer#remaining out.remaining()} - * $otype$s will be written. The buffers' positions will be advanced to - * reflect the $itype$s read and the $otype$s written, but their marks and - * limits will not be modified. - * - * <p> This method returns a {@link CoderResult} object to describe its - * reason for termination, in the same manner as the {@link #$code$ $code$} - * method. Most implementations of this method will handle $coding$ errors - * by returning an appropriate result object for interpretation by the - * {@link #$code$ $code$} method. An optimized implementation may instead - * examine the relevant error action and implement that action itself. - * - * <p> An implementation of this method may perform arbitrary lookahead by - * returning {@link CoderResult#UNDERFLOW} until it receives sufficient - * input. </p> - * - * @param in - * The input $itype$ buffer - * - * @param out - * The output $otype$ buffer - * - * @return A coder-result object describing the reason for termination - */ - protected abstract CoderResult $code$Loop($Itype$Buffer in, - $Otype$Buffer out); - - /** - * Convenience method that $code$s the remaining content of a single input - * $itype$ buffer into a newly-allocated $otype$ buffer. - * - * <p> This method implements an entire <a href="#steps">$coding$ - * operation</a>; that is, it resets this $coder$, then it $code$s the - * $itype$s in the given $itype$ buffer, and finally it flushes this - * $coder$. This method should therefore not be invoked if $a$ $coding$ - * operation is already in progress. </p> - * - * @param in - * The input $itype$ buffer - * - * @return A newly-allocated $otype$ buffer containing the result of the - * $coding$ operation. The buffer's position will be zero and its - * limit will follow the last $otype$ written. - * - * @throws IllegalStateException - * If $a$ $coding$ operation is already in progress - * - * @throws MalformedInputException - * If the $itype$ sequence starting at the input buffer's current - * position is $notLegal$ and the current malformed-input action - * is {@link CodingErrorAction#REPORT} - * - * @throws UnmappableCharacterException - * If the $itype$ sequence starting at the input buffer's current - * position cannot be mapped to an equivalent $otype$ sequence and - * the current unmappable-character action is {@link - * CodingErrorAction#REPORT} - */ - public final $Otype$Buffer $code$($Itype$Buffer in) - throws CharacterCodingException - { - int n = (int)(in.remaining() * average$ItypesPerOtype$()); - $Otype$Buffer out = $Otype$Buffer.allocate(n); - - if ((n == 0) && (in.remaining() == 0)) - return out; - reset(); - for (;;) { - CoderResult cr = in.hasRemaining() ? - $code$(in, out, true) : CoderResult.UNDERFLOW; - if (cr.isUnderflow()) - cr = flush(out); - - if (cr.isUnderflow()) - break; - if (cr.isOverflow()) { - n = 2*n + 1; // Ensure progress; n might be 0! - $Otype$Buffer o = $Otype$Buffer.allocate(n); - out.flip(); - o.put(out); - out = o; - continue; - } - cr.throwException(); - } - out.flip(); - return out; - } - -#if[decoder] - - /** - * Tells whether or not this decoder implements an auto-detecting charset. - * - * <p> The default implementation of this method always returns - * <tt>false</tt>; it should be overridden by auto-detecting decoders to - * return <tt>true</tt>. </p> - * - * @return <tt>true</tt> if, and only if, this decoder implements an - * auto-detecting charset - */ - public boolean isAutoDetecting() { - return false; - } - - /** - * Tells whether or not this decoder has yet detected a - * charset <i>(optional operation)</i>. - * - * <p> If this decoder implements an auto-detecting charset then at a - * single point during a decoding operation this method may start returning - * <tt>true</tt> to indicate that a specific charset has been detected in - * the input byte sequence. Once this occurs, the {@link #detectedCharset - * detectedCharset} method may be invoked to retrieve the detected charset. - * - * <p> That this method returns <tt>false</tt> does not imply that no bytes - * have yet been decoded. Some auto-detecting decoders are capable of - * decoding some, or even all, of an input byte sequence without fixing on - * a particular charset. - * - * <p> The default implementation of this method always throws an {@link - * UnsupportedOperationException}; it should be overridden by - * auto-detecting decoders to return <tt>true</tt> once the input charset - * has been determined. </p> - * - * @return <tt>true</tt> if, and only if, this decoder has detected a - * specific charset - * - * @throws UnsupportedOperationException - * If this decoder does not implement an auto-detecting charset - */ - public boolean isCharsetDetected() { - throw new UnsupportedOperationException(); - } - - /** - * Retrieves the charset that was detected by this - * decoder <i>(optional operation)</i>. - * - * <p> If this decoder implements an auto-detecting charset then this - * method returns the actual charset once it has been detected. After that - * point, this method returns the same value for the duration of the - * current decoding operation. If not enough input bytes have yet been - * read to determine the actual charset then this method throws an {@link - * IllegalStateException}. - * - * <p> The default implementation of this method always throws an {@link - * UnsupportedOperationException}; it should be overridden by - * auto-detecting decoders to return the appropriate value. </p> - * - * @return The charset detected by this auto-detecting decoder, - * or <tt>null</tt> if the charset has not yet been determined - * - * @throws IllegalStateException - * If insufficient bytes have been read to determine a charset - * - * @throws UnsupportedOperationException - * If this decoder does not implement an auto-detecting charset - */ - public Charset detectedCharset() { - throw new UnsupportedOperationException(); - } - -#end[decoder] - -#if[encoder] - - private boolean canEncode(CharBuffer cb) { - if (state == ST_FLUSHED) - reset(); - else if (state != ST_RESET) - throwIllegalStateException(state, ST_CODING); - CodingErrorAction ma = malformedInputAction(); - CodingErrorAction ua = unmappableCharacterAction(); - try { - onMalformedInput(CodingErrorAction.REPORT); - onUnmappableCharacter(CodingErrorAction.REPORT); - encode(cb); - } catch (CharacterCodingException x) { - return false; - } finally { - onMalformedInput(ma); - onUnmappableCharacter(ua); - reset(); - } - return true; - } - - /** - * Tells whether or not this encoder can encode the given character. - * - * <p> This method returns <tt>false</tt> if the given character is a - * surrogate character; such characters can be interpreted only when they - * are members of a pair consisting of a high surrogate followed by a low - * surrogate. The {@link #canEncode(java.lang.CharSequence) - * canEncode(CharSequence)} method may be used to test whether or not a - * character sequence can be encoded. - * - * <p> This method may modify this encoder's state; it should therefore not - * be invoked if an <a href="#steps">encoding operation</a> is already in - * progress. - * - * <p> The default implementation of this method is not very efficient; it - * should generally be overridden to improve performance. </p> - * - * @return <tt>true</tt> if, and only if, this encoder can encode - * the given character - * - * @throws IllegalStateException - * If $a$ $coding$ operation is already in progress - */ - public boolean canEncode(char c) { - CharBuffer cb = CharBuffer.allocate(1); - cb.put(c); - cb.flip(); - return canEncode(cb); - } - - /** - * Tells whether or not this encoder can encode the given character - * sequence. - * - * <p> If this method returns <tt>false</tt> for a particular character - * sequence then more information about why the sequence cannot be encoded - * may be obtained by performing a full <a href="#steps">encoding - * operation</a>. - * - * <p> This method may modify this encoder's state; it should therefore not - * be invoked if an encoding operation is already in progress. - * - * <p> The default implementation of this method is not very efficient; it - * should generally be overridden to improve performance. </p> - * - * @return <tt>true</tt> if, and only if, this encoder can encode - * the given character without throwing any exceptions and without - * performing any replacements - * - * @throws IllegalStateException - * If $a$ $coding$ operation is already in progress - */ - public boolean canEncode(CharSequence cs) { - CharBuffer cb; - if (cs instanceof CharBuffer) - cb = ((CharBuffer)cs).duplicate(); - else - cb = CharBuffer.wrap(cs.toString()); - return canEncode(cb); - } - -#end[encoder] - - - private void throwIllegalStateException(int from, int to) { - throw new IllegalStateException("Current state = " + stateNames[from] - + ", new state = " + stateNames[to]); - } - -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/nio/charset/Charset-X-Coder.java.template Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,972 @@ +/* + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +#warn This file is preprocessed before being compiled + +package java.nio.charset; + +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.BufferOverflowException; +import java.nio.BufferUnderflowException; +import java.lang.ref.WeakReference; +import java.nio.charset.CoderMalfunctionError; // javadoc + + +/** + * An engine that can transform a sequence of $itypesPhrase$ into a sequence of + * $otypesPhrase$. + * + * <a name="steps"> + * + * <p> The input $itype$ sequence is provided in a $itype$ buffer or a series + * of such buffers. The output $otype$ sequence is written to a $otype$ buffer + * or a series of such buffers. $A$ $coder$ should always be used by making + * the following sequence of method invocations, hereinafter referred to as $a$ + * <i>$coding$ operation</i>: + * + * <ol> + * + * <li><p> Reset the $coder$ via the {@link #reset reset} method, unless it + * has not been used before; </p></li> + * + * <li><p> Invoke the {@link #$code$ $code$} method zero or more times, as + * long as additional input may be available, passing <tt>false</tt> for the + * <tt>endOfInput</tt> argument and filling the input buffer and flushing the + * output buffer between invocations; </p></li> + * + * <li><p> Invoke the {@link #$code$ $code$} method one final time, passing + * <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li> + * + * <li><p> Invoke the {@link #flush flush} method so that the $coder$ can + * flush any internal state to the output buffer. </p></li> + * + * </ol> + * + * Each invocation of the {@link #$code$ $code$} method will $code$ as many + * $itype$s as possible from the input buffer, writing the resulting $otype$s + * to the output buffer. The {@link #$code$ $code$} method returns when more + * input is required, when there is not enough room in the output buffer, or + * when $a$ $coding$ error has occurred. In each case a {@link CoderResult} + * object is returned to describe the reason for termination. An invoker can + * examine this object and fill the input buffer, flush the output buffer, or + * attempt to recover from $a$ $coding$ error, as appropriate, and try again. + * + * <a name="ce"> + * + * <p> There are two general types of $coding$ errors. If the input $itype$ + * sequence is $notLegal$ then the input is considered <i>malformed</i>. If + * the input $itype$ sequence is legal but cannot be mapped to a valid + * $outSequence$ then an <i>unmappable character</i> has been encountered. + * + * <a name="cae"> + * + * <p> How $a$ $coding$ error is handled depends upon the action requested for + * that type of error, which is described by an instance of the {@link + * CodingErrorAction} class. The possible error actions are to {@link + * CodingErrorAction#IGNORE </code>ignore<code>} the erroneous input, {@link + * CodingErrorAction#REPORT </code>report<code>} the error to the invoker via + * the returned {@link CoderResult} object, or {@link CodingErrorAction#REPLACE + * </code>replace<code>} the erroneous input with the current value of the + * replacement $replTypeName$. The replacement + * +#if[encoder] + * is initially set to the $coder$'s default replacement, which often + * (but not always) has the initial value $defaultReplName$; +#end[encoder] +#if[decoder] + * has the initial value $defaultReplName$; +#end[decoder] + * + * its value may be changed via the {@link #replaceWith($replFQType$) + * replaceWith} method. + * + * <p> The default action for malformed-input and unmappable-character errors + * is to {@link CodingErrorAction#REPORT </code>report<code>} them. The + * malformed-input error action may be changed via the {@link + * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the + * unmappable-character action may be changed via the {@link + * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method. + * + * <p> This class is designed to handle many of the details of the $coding$ + * process, including the implementation of error actions. $A$ $coder$ for a + * specific charset, which is a concrete subclass of this class, need only + * implement the abstract {@link #$code$Loop $code$Loop} method, which + * encapsulates the basic $coding$ loop. A subclass that maintains internal + * state should, additionally, override the {@link #implFlush implFlush} and + * {@link #implReset implReset} methods. + * + * <p> Instances of this class are not safe for use by multiple concurrent + * threads. </p> + * + * + * @author Mark Reinhold + * @author JSR-51 Expert Group + * @since 1.4 + * + * @see ByteBuffer + * @see CharBuffer + * @see Charset + * @see Charset$OtherCoder$ + */ + +public abstract class Charset$Coder$ { + + private final Charset charset; + private final float average$ItypesPerOtype$; + private final float max$ItypesPerOtype$; + + private $replType$ replacement; + private CodingErrorAction malformedInputAction + = CodingErrorAction.REPORT; + private CodingErrorAction unmappableCharacterAction + = CodingErrorAction.REPORT; + + // Internal states + // + private static final int ST_RESET = 0; + private static final int ST_CODING = 1; + private static final int ST_END = 2; + private static final int ST_FLUSHED = 3; + + private int state = ST_RESET; + + private static String stateNames[] + = { "RESET", "CODING", "CODING_END", "FLUSHED" }; + + + /** + * Initializes a new $coder$. The new $coder$ will have the given + * $otypes-per-itype$ and replacement values. </p> + * + * @param average$ItypesPerOtype$ + * A positive float value indicating the expected number of + * $otype$s that will be produced for each input $itype$ + * + * @param max$ItypesPerOtype$ + * A positive float value indicating the maximum number of + * $otype$s that will be produced for each input $itype$ + * + * @param replacement + * The initial replacement; must not be <tt>null</tt>, must have + * non-zero length, must not be longer than max$ItypesPerOtype$, + * and must be {@link #isLegalReplacement </code>legal<code>} + * + * @throws IllegalArgumentException + * If the preconditions on the parameters do not hold + */ + {#if[encoder]?protected:private} + Charset$Coder$(Charset cs, + float average$ItypesPerOtype$, + float max$ItypesPerOtype$, + $replType$ replacement) + { + this.charset = cs; + if (average$ItypesPerOtype$ <= 0.0f) + throw new IllegalArgumentException("Non-positive " + + "average$ItypesPerOtype$"); + if (max$ItypesPerOtype$ <= 0.0f) + throw new IllegalArgumentException("Non-positive " + + "max$ItypesPerOtype$"); + if (!Charset.atBugLevel("1.4")) { + if (average$ItypesPerOtype$ > max$ItypesPerOtype$) + throw new IllegalArgumentException("average$ItypesPerOtype$" + + " exceeds " + + "max$ItypesPerOtype$"); + } + this.replacement = replacement; + this.average$ItypesPerOtype$ = average$ItypesPerOtype$; + this.max$ItypesPerOtype$ = max$ItypesPerOtype$; + replaceWith(replacement); + } + + /** + * Initializes a new $coder$. The new $coder$ will have the given + * $otypes-per-itype$ values and its replacement will be the + * $replTypeName$ $defaultReplName$. </p> + * + * @param average$ItypesPerOtype$ + * A positive float value indicating the expected number of + * $otype$s that will be produced for each input $itype$ + * + * @param max$ItypesPerOtype$ + * A positive float value indicating the maximum number of + * $otype$s that will be produced for each input $itype$ + * + * @throws IllegalArgumentException + * If the preconditions on the parameters do not hold + */ + protected Charset$Coder$(Charset cs, + float average$ItypesPerOtype$, + float max$ItypesPerOtype$) + { + this(cs, + average$ItypesPerOtype$, max$ItypesPerOtype$, + $defaultRepl$); + } + + /** + * Returns the charset that created this $coder$. </p> + * + * @return This $coder$'s charset + */ + public final Charset charset() { + return charset; + } + + /** + * Returns this $coder$'s replacement value. </p> + * + * @return This $coder$'s current replacement, + * which is never <tt>null</tt> and is never empty + */ + public final $replType$ replacement() { + return replacement; + } + + /** + * Changes this $coder$'s replacement value. + * + * <p> This method invokes the {@link #implReplaceWith implReplaceWith} + * method, passing the new replacement, after checking that the new + * replacement is acceptable. </p> + * + * @param newReplacement + * +#if[decoder] + * The new replacement; must not be <tt>null</tt> + * and must have non-zero length +#end[decoder] +#if[encoder] + * The new replacement; must not be <tt>null</tt>, must have + * non-zero length, must not be longer than the value returned by + * the {@link #max$ItypesPerOtype$() max$ItypesPerOtype$} method, and + * must be {@link #isLegalReplacement </code>legal<code>} +#end[encoder] + * + * @return This $coder$ + * + * @throws IllegalArgumentException + * If the preconditions on the parameter do not hold + */ + public final Charset$Coder$ replaceWith($replType$ newReplacement) { + if (newReplacement == null) + throw new IllegalArgumentException("Null replacement"); + int len = newReplacement.$replLength$; + if (len == 0) + throw new IllegalArgumentException("Empty replacement"); + if (len > max$ItypesPerOtype$) + throw new IllegalArgumentException("Replacement too long"); +#if[encoder] + if (!isLegalReplacement(newReplacement)) + throw new IllegalArgumentException("Illegal replacement"); +#end[encoder] + this.replacement = newReplacement; + implReplaceWith(newReplacement); + return this; + } + + /** + * Reports a change to this $coder$'s replacement value. + * + * <p> The default implementation of this method does nothing. This method + * should be overridden by $coder$s that require notification of changes to + * the replacement. </p> + * + * @param newReplacement + */ + protected void implReplaceWith($replType$ newReplacement) { + } + +#if[encoder] + + private WeakReference<CharsetDecoder> cachedDecoder = null; + + /** + * Tells whether or not the given byte array is a legal replacement value + * for this encoder. + * + * <p> A replacement is legal if, and only if, it is a legal sequence of + * bytes in this encoder's charset; that is, it must be possible to decode + * the replacement into one or more sixteen-bit Unicode characters. + * + * <p> The default implementation of this method is not very efficient; it + * should generally be overridden to improve performance. </p> + * + * @param repl The byte array to be tested + * + * @return <tt>true</tt> if, and only if, the given byte array + * is a legal replacement value for this encoder + */ + public boolean isLegalReplacement(byte[] repl) { + WeakReference<CharsetDecoder> wr = cachedDecoder; + CharsetDecoder dec = null; + if ((wr == null) || ((dec = wr.get()) == null)) { + dec = charset().newDecoder(); + dec.onMalformedInput(CodingErrorAction.REPORT); + dec.onUnmappableCharacter(CodingErrorAction.REPORT); + cachedDecoder = new WeakReference<CharsetDecoder>(dec); + } else { + dec.reset(); + } + ByteBuffer bb = ByteBuffer.wrap(repl); + CharBuffer cb = CharBuffer.allocate((int)(bb.remaining() + * dec.maxCharsPerByte())); + CoderResult cr = dec.decode(bb, cb, true); + return !cr.isError(); + } + +#end[encoder] + + /** + * Returns this $coder$'s current action for malformed-input errors. </p> + * + * @return The current malformed-input action, which is never <tt>null</tt> + */ + public CodingErrorAction malformedInputAction() { + return malformedInputAction; + } + + /** + * Changes this $coder$'s action for malformed-input errors. </p> + * + * <p> This method invokes the {@link #implOnMalformedInput + * implOnMalformedInput} method, passing the new action. </p> + * + * @param newAction The new action; must not be <tt>null</tt> + * + * @return This $coder$ + * + * @throws IllegalArgumentException + * If the precondition on the parameter does not hold + */ + public final Charset$Coder$ onMalformedInput(CodingErrorAction newAction) { + if (newAction == null) + throw new IllegalArgumentException("Null action"); + malformedInputAction = newAction; + implOnMalformedInput(newAction); + return this; + } + + /** + * Reports a change to this $coder$'s malformed-input action. + * + * <p> The default implementation of this method does nothing. This method + * should be overridden by $coder$s that require notification of changes to + * the malformed-input action. </p> + */ + protected void implOnMalformedInput(CodingErrorAction newAction) { } + + /** + * Returns this $coder$'s current action for unmappable-character errors. + * </p> + * + * @return The current unmappable-character action, which is never + * <tt>null</tt> + */ + public CodingErrorAction unmappableCharacterAction() { + return unmappableCharacterAction; + } + + /** + * Changes this $coder$'s action for unmappable-character errors. + * + * <p> This method invokes the {@link #implOnUnmappableCharacter + * implOnUnmappableCharacter} method, passing the new action. </p> + * + * @param newAction The new action; must not be <tt>null</tt> + * + * @return This $coder$ + * + * @throws IllegalArgumentException + * If the precondition on the parameter does not hold + */ + public final Charset$Coder$ onUnmappableCharacter(CodingErrorAction + newAction) + { + if (newAction == null) + throw new IllegalArgumentException("Null action"); + unmappableCharacterAction = newAction; + implOnUnmappableCharacter(newAction); + return this; + } + + /** + * Reports a change to this $coder$'s unmappable-character action. + * + * <p> The default implementation of this method does nothing. This method + * should be overridden by $coder$s that require notification of changes to + * the unmappable-character action. </p> + */ + protected void implOnUnmappableCharacter(CodingErrorAction newAction) { } + + /** + * Returns the average number of $otype$s that will be produced for each + * $itype$ of input. This heuristic value may be used to estimate the size + * of the output buffer required for a given input sequence. </p> + * + * @return The average number of $otype$s produced + * per $itype$ of input + */ + public final float average$ItypesPerOtype$() { + return average$ItypesPerOtype$; + } + + /** + * Returns the maximum number of $otype$s that will be produced for each + * $itype$ of input. This value may be used to compute the worst-case size + * of the output buffer required for a given input sequence. </p> + * + * @return The maximum number of $otype$s that will be produced per + * $itype$ of input + */ + public final float max$ItypesPerOtype$() { + return max$ItypesPerOtype$; + } + + /** + * $Code$s as many $itype$s as possible from the given input buffer, + * writing the results to the given output buffer. + * + * <p> The buffers are read from, and written to, starting at their current + * positions. At most {@link Buffer#remaining in.remaining()} $itype$s + * will be read and at most {@link Buffer#remaining out.remaining()} + * $otype$s will be written. The buffers' positions will be advanced to + * reflect the $itype$s read and the $otype$s written, but their marks and + * limits will not be modified. + * + * <p> In addition to reading $itype$s from the input buffer and writing + * $otype$s to the output buffer, this method returns a {@link CoderResult} + * object to describe its reason for termination: + * + * <ul> + * + * <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the + * input buffer as possible has been $code$d. If there is no further + * input then the invoker can proceed to the next step of the + * <a href="#steps">$coding$ operation</a>. Otherwise this method + * should be invoked again with further input. </p></li> + * + * <li><p> {@link CoderResult#OVERFLOW} indicates that there is + * insufficient space in the output buffer to $code$ any more $itype$s. + * This method should be invoked again with an output buffer that has + * more {@linkplain Buffer#remaining remaining} $otype$s. This is + * typically done by draining any $code$d $otype$s from the output + * buffer. </p></li> + * + * <li><p> A {@link CoderResult#malformedForLength + * </code>malformed-input<code>} result indicates that a malformed-input + * error has been detected. The malformed $itype$s begin at the input + * buffer's (possibly incremented) position; the number of malformed + * $itype$s may be determined by invoking the result object's {@link + * CoderResult#length() length} method. This case applies only if the + * {@link #onMalformedInput </code>malformed action<code>} of this $coder$ + * is {@link CodingErrorAction#REPORT}; otherwise the malformed input + * will be ignored or replaced, as requested. </p></li> + * + * <li><p> An {@link CoderResult#unmappableForLength + * </code>unmappable-character<code>} result indicates that an + * unmappable-character error has been detected. The $itype$s that + * $code$ the unmappable character begin at the input buffer's (possibly + * incremented) position; the number of such $itype$s may be determined + * by invoking the result object's {@link CoderResult#length() length} + * method. This case applies only if the {@link #onUnmappableCharacter + * </code>unmappable action<code>} of this $coder$ is {@link + * CodingErrorAction#REPORT}; otherwise the unmappable character will be + * ignored or replaced, as requested. </p></li> + * + * </ul> + * + * In any case, if this method is to be reinvoked in the same $coding$ + * operation then care should be taken to preserve any $itype$s remaining + * in the input buffer so that they are available to the next invocation. + * + * <p> The <tt>endOfInput</tt> parameter advises this method as to whether + * the invoker can provide further input beyond that contained in the given + * input buffer. If there is a possibility of providing additional input + * then the invoker should pass <tt>false</tt> for this parameter; if there + * is no possibility of providing further input then the invoker should + * pass <tt>true</tt>. It is not erroneous, and in fact it is quite + * common, to pass <tt>false</tt> in one invocation and later discover that + * no further input was actually available. It is critical, however, that + * the final invocation of this method in a sequence of invocations always + * pass <tt>true</tt> so that any remaining un$code$d input will be treated + * as being malformed. + * + * <p> This method works by invoking the {@link #$code$Loop $code$Loop} + * method, interpreting its results, handling error conditions, and + * reinvoking it as necessary. </p> + * + * + * @param in + * The input $itype$ buffer + * + * @param out + * The output $otype$ buffer + * + * @param endOfInput + * <tt>true</tt> if, and only if, the invoker can provide no + * additional input $itype$s beyond those in the given buffer + * + * @return A coder-result object describing the reason for termination + * + * @throws IllegalStateException + * If $a$ $coding$ operation is already in progress and the previous + * step was an invocation neither of the {@link #reset reset} + * method, nor of this method with a value of <tt>false</tt> for + * the <tt>endOfInput</tt> parameter, nor of this method with a + * value of <tt>true</tt> for the <tt>endOfInput</tt> parameter + * but a return value indicating an incomplete $coding$ operation + * + * @throws CoderMalfunctionError + * If an invocation of the $code$Loop method threw + * an unexpected exception + */ + public final CoderResult $code$($Itype$Buffer in, $Otype$Buffer out, + boolean endOfInput) + { + int newState = endOfInput ? ST_END : ST_CODING; + if ((state != ST_RESET) && (state != ST_CODING) + && !(endOfInput && (state == ST_END))) + throwIllegalStateException(state, newState); + state = newState; + + for (;;) { + + CoderResult cr; + try { + cr = $code$Loop(in, out); + } catch (BufferUnderflowException x) { + throw new CoderMalfunctionError(x); + } catch (BufferOverflowException x) { + throw new CoderMalfunctionError(x); + } + + if (cr.isOverflow()) + return cr; + + if (cr.isUnderflow()) { + if (endOfInput && in.hasRemaining()) { + cr = CoderResult.malformedForLength(in.remaining()); + // Fall through to malformed-input case + } else { + return cr; + } + } + + CodingErrorAction action = null; + if (cr.isMalformed()) + action = malformedInputAction; + else if (cr.isUnmappable()) + action = unmappableCharacterAction; + else + assert false : cr.toString(); + + if (action == CodingErrorAction.REPORT) + return cr; + + if (action == CodingErrorAction.REPLACE) { + if (out.remaining() < replacement.$replLength$) + return CoderResult.OVERFLOW; + out.put(replacement); + } + + if ((action == CodingErrorAction.IGNORE) + || (action == CodingErrorAction.REPLACE)) { + // Skip erroneous input either way + in.position(in.position() + cr.length()); + continue; + } + + assert false; + } + + } + + /** + * Flushes this $coder$. + * + * <p> Some $coder$s maintain internal state and may need to write some + * final $otype$s to the output buffer once the overall input sequence has + * been read. + * + * <p> Any additional output is written to the output buffer beginning at + * its current position. At most {@link Buffer#remaining out.remaining()} + * $otype$s will be written. The buffer's position will be advanced + * appropriately, but its mark and limit will not be modified. + * + * <p> If this method completes successfully then it returns {@link + * CoderResult#UNDERFLOW}. If there is insufficient room in the output + * buffer then it returns {@link CoderResult#OVERFLOW}. If this happens + * then this method must be invoked again, with an output buffer that has + * more room, in order to complete the current <a href="#steps">$coding$ + * operation</a>. + * + * <p> If this $coder$ has already been flushed then invoking this method + * has no effect. + * + * <p> This method invokes the {@link #implFlush implFlush} method to + * perform the actual flushing operation. </p> + * + * @param out + * The output $otype$ buffer + * + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or + * {@link CoderResult#OVERFLOW} + * + * @throws IllegalStateException + * If the previous step of the current $coding$ operation was an + * invocation neither of the {@link #flush flush} method nor of + * the three-argument {@link + * #$code$($Itype$Buffer,$Otype$Buffer,boolean) $code$} method + * with a value of <tt>true</tt> for the <tt>endOfInput</tt> + * parameter + */ + public final CoderResult flush($Otype$Buffer out) { + if (state == ST_END) { + CoderResult cr = implFlush(out); + if (cr.isUnderflow()) + state = ST_FLUSHED; + return cr; + } + + if (state != ST_FLUSHED) + throwIllegalStateException(state, ST_FLUSHED); + + return CoderResult.UNDERFLOW; // Already flushed + } + + /** + * Flushes this $coder$. + * + * <p> The default implementation of this method does nothing, and always + * returns {@link CoderResult#UNDERFLOW}. This method should be overridden + * by $coder$s that may need to write final $otype$s to the output buffer + * once the entire input sequence has been read. </p> + * + * @param out + * The output $otype$ buffer + * + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or + * {@link CoderResult#OVERFLOW} + */ + protected CoderResult implFlush($Otype$Buffer out) { + return CoderResult.UNDERFLOW; + } + + /** + * Resets this $coder$, clearing any internal state. + * + * <p> This method resets charset-independent state and also invokes the + * {@link #implReset() implReset} method in order to perform any + * charset-specific reset actions. </p> + * + * @return This $coder$ + * + */ + public final Charset$Coder$ reset() { + implReset(); + state = ST_RESET; + return this; + } + + /** + * Resets this $coder$, clearing any charset-specific internal state. + * + * <p> The default implementation of this method does nothing. This method + * should be overridden by $coder$s that maintain internal state. </p> + */ + protected void implReset() { } + + /** + * $Code$s one or more $itype$s into one or more $otype$s. + * + * <p> This method encapsulates the basic $coding$ loop, $coding$ as many + * $itype$s as possible until it either runs out of input, runs out of room + * in the output buffer, or encounters $a$ $coding$ error. This method is + * invoked by the {@link #$code$ $code$} method, which handles result + * interpretation and error recovery. + * + * <p> The buffers are read from, and written to, starting at their current + * positions. At most {@link Buffer#remaining in.remaining()} $itype$s + * will be read, and at most {@link Buffer#remaining out.remaining()} + * $otype$s will be written. The buffers' positions will be advanced to + * reflect the $itype$s read and the $otype$s written, but their marks and + * limits will not be modified. + * + * <p> This method returns a {@link CoderResult} object to describe its + * reason for termination, in the same manner as the {@link #$code$ $code$} + * method. Most implementations of this method will handle $coding$ errors + * by returning an appropriate result object for interpretation by the + * {@link #$code$ $code$} method. An optimized implementation may instead + * examine the relevant error action and implement that action itself. + * + * <p> An implementation of this method may perform arbitrary lookahead by + * returning {@link CoderResult#UNDERFLOW} until it receives sufficient + * input. </p> + * + * @param in + * The input $itype$ buffer + * + * @param out + * The output $otype$ buffer + * + * @return A coder-result object describing the reason for termination + */ + protected abstract CoderResult $code$Loop($Itype$Buffer in, + $Otype$Buffer out); + + /** + * Convenience method that $code$s the remaining content of a single input + * $itype$ buffer into a newly-allocated $otype$ buffer. + * + * <p> This method implements an entire <a href="#steps">$coding$ + * operation</a>; that is, it resets this $coder$, then it $code$s the + * $itype$s in the given $itype$ buffer, and finally it flushes this + * $coder$. This method should therefore not be invoked if $a$ $coding$ + * operation is already in progress. </p> + * + * @param in + * The input $itype$ buffer + * + * @return A newly-allocated $otype$ buffer containing the result of the + * $coding$ operation. The buffer's position will be zero and its + * limit will follow the last $otype$ written. + * + * @throws IllegalStateException + * If $a$ $coding$ operation is already in progress + * + * @throws MalformedInputException + * If the $itype$ sequence starting at the input buffer's current + * position is $notLegal$ and the current malformed-input action + * is {@link CodingErrorAction#REPORT} + * + * @throws UnmappableCharacterException + * If the $itype$ sequence starting at the input buffer's current + * position cannot be mapped to an equivalent $otype$ sequence and + * the current unmappable-character action is {@link + * CodingErrorAction#REPORT} + */ + public final $Otype$Buffer $code$($Itype$Buffer in) + throws CharacterCodingException + { + int n = (int)(in.remaining() * average$ItypesPerOtype$()); + $Otype$Buffer out = $Otype$Buffer.allocate(n); + + if ((n == 0) && (in.remaining() == 0)) + return out; + reset(); + for (;;) { + CoderResult cr = in.hasRemaining() ? + $code$(in, out, true) : CoderResult.UNDERFLOW; + if (cr.isUnderflow()) + cr = flush(out); + + if (cr.isUnderflow()) + break; + if (cr.isOverflow()) { + n = 2*n + 1; // Ensure progress; n might be 0! + $Otype$Buffer o = $Otype$Buffer.allocate(n); + out.flip(); + o.put(out); + out = o; + continue; + } + cr.throwException(); + } + out.flip(); + return out; + } + +#if[decoder] + + /** + * Tells whether or not this decoder implements an auto-detecting charset. + * + * <p> The default implementation of this method always returns + * <tt>false</tt>; it should be overridden by auto-detecting decoders to + * return <tt>true</tt>. </p> + * + * @return <tt>true</tt> if, and only if, this decoder implements an + * auto-detecting charset + */ + public boolean isAutoDetecting() { + return false; + } + + /** + * Tells whether or not this decoder has yet detected a + * charset <i>(optional operation)</i>. + * + * <p> If this decoder implements an auto-detecting charset then at a + * single point during a decoding operation this method may start returning + * <tt>true</tt> to indicate that a specific charset has been detected in + * the input byte sequence. Once this occurs, the {@link #detectedCharset + * detectedCharset} method may be invoked to retrieve the detected charset. + * + * <p> That this method returns <tt>false</tt> does not imply that no bytes + * have yet been decoded. Some auto-detecting decoders are capable of + * decoding some, or even all, of an input byte sequence without fixing on + * a particular charset. + * + * <p> The default implementation of this method always throws an {@link + * UnsupportedOperationException}; it should be overridden by + * auto-detecting decoders to return <tt>true</tt> once the input charset + * has been determined. </p> + * + * @return <tt>true</tt> if, and only if, this decoder has detected a + * specific charset + * + * @throws UnsupportedOperationException + * If this decoder does not implement an auto-detecting charset + */ + public boolean isCharsetDetected() { + throw new UnsupportedOperationException(); + } + + /** + * Retrieves the charset that was detected by this + * decoder <i>(optional operation)</i>. + * + * <p> If this decoder implements an auto-detecting charset then this + * method returns the actual charset once it has been detected. After that + * point, this method returns the same value for the duration of the + * current decoding operation. If not enough input bytes have yet been + * read to determine the actual charset then this method throws an {@link + * IllegalStateException}. + * + * <p> The default implementation of this method always throws an {@link + * UnsupportedOperationException}; it should be overridden by + * auto-detecting decoders to return the appropriate value. </p> + * + * @return The charset detected by this auto-detecting decoder, + * or <tt>null</tt> if the charset has not yet been determined + * + * @throws IllegalStateException + * If insufficient bytes have been read to determine a charset + * + * @throws UnsupportedOperationException + * If this decoder does not implement an auto-detecting charset + */ + public Charset detectedCharset() { + throw new UnsupportedOperationException(); + } + +#end[decoder] + +#if[encoder] + + private boolean canEncode(CharBuffer cb) { + if (state == ST_FLUSHED) + reset(); + else if (state != ST_RESET) + throwIllegalStateException(state, ST_CODING); + CodingErrorAction ma = malformedInputAction(); + CodingErrorAction ua = unmappableCharacterAction(); + try { + onMalformedInput(CodingErrorAction.REPORT); + onUnmappableCharacter(CodingErrorAction.REPORT); + encode(cb); + } catch (CharacterCodingException x) { + return false; + } finally { + onMalformedInput(ma); + onUnmappableCharacter(ua); + reset(); + } + return true; + } + + /** + * Tells whether or not this encoder can encode the given character. + * + * <p> This method returns <tt>false</tt> if the given character is a + * surrogate character; such characters can be interpreted only when they + * are members of a pair consisting of a high surrogate followed by a low + * surrogate. The {@link #canEncode(java.lang.CharSequence) + * canEncode(CharSequence)} method may be used to test whether or not a + * character sequence can be encoded. + * + * <p> This method may modify this encoder's state; it should therefore not + * be invoked if an <a href="#steps">encoding operation</a> is already in + * progress. + * + * <p> The default implementation of this method is not very efficient; it + * should generally be overridden to improve performance. </p> + * + * @return <tt>true</tt> if, and only if, this encoder can encode + * the given character + * + * @throws IllegalStateException + * If $a$ $coding$ operation is already in progress + */ + public boolean canEncode(char c) { + CharBuffer cb = CharBuffer.allocate(1); + cb.put(c); + cb.flip(); + return canEncode(cb); + } + + /** + * Tells whether or not this encoder can encode the given character + * sequence. + * + * <p> If this method returns <tt>false</tt> for a particular character + * sequence then more information about why the sequence cannot be encoded + * may be obtained by performing a full <a href="#steps">encoding + * operation</a>. + * + * <p> This method may modify this encoder's state; it should therefore not + * be invoked if an encoding operation is already in progress. + * + * <p> The default implementation of this method is not very efficient; it + * should generally be overridden to improve performance. </p> + * + * @return <tt>true</tt> if, and only if, this encoder can encode + * the given character without throwing any exceptions and without + * performing any replacements + * + * @throws IllegalStateException + * If $a$ $coding$ operation is already in progress + */ + public boolean canEncode(CharSequence cs) { + CharBuffer cb; + if (cs instanceof CharBuffer) + cb = ((CharBuffer)cs).duplicate(); + else + cb = CharBuffer.wrap(cs.toString()); + return canEncode(cb); + } + +#end[encoder] + + + private void throwIllegalStateException(int from, int to) { + throw new IllegalStateException("Current state = " + stateNames[from] + + ", new state = " + stateNames[to]); + } + +}
--- a/src/share/classes/java/security/MessageDigest.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/security/MessageDigest.java Thu Nov 12 23:04:42 2009 +0000 @@ -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 @@ * * @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; + } + int result = 0; + // time-constant comparison for (int i = 0; i < digesta.length; i++) { - if (digesta[i] != digestb[i]) { - return false; - } + result |= digesta[i] ^ digestb[i]; } - return true; + return result == 0; } /**
--- a/src/share/classes/java/util/AbstractList.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/AbstractList.java Thu Nov 12 23:04:42 2009 +0000 @@ -256,9 +256,8 @@ public boolean addAll(int index, Collection<? extends E> c) { rangeCheckForAdd(index); boolean modified = false; - Iterator<? extends E> e = c.iterator(); - while (e.hasNext()) { - add(index++, e.next()); + for (E e : c) { + add(index++, e); modified = true; } return modified;
--- a/src/share/classes/java/util/AbstractQueue.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/AbstractQueue.java Thu Nov 12 23:04:42 2009 +0000 @@ -183,11 +183,9 @@ if (c == this) throw new IllegalArgumentException(); boolean modified = false; - Iterator<? extends E> e = c.iterator(); - while (e.hasNext()) { - if (add(e.next())) + for (E e : c) + if (add(e)) modified = true; - } return modified; }
--- a/src/share/classes/java/util/Arrays.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/Arrays.java Thu Nov 12 23:04:42 2009 +0000 @@ -57,51 +57,14 @@ // Suppresses default constructor, ensuring non-instantiability. private Arrays() {} - // Sorting + /* + * Sorting of primitive type arrays. + */ /** * Sorts the specified array into ascending numerical order. * - * <p>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) { - sort(a, 0, a.length); - } - - /** - * Sorts the specified range of the specified array into ascending order. The - * range of 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. - * - * <p>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, inclusively, to be sorted - * @param toIndex the index of the last element, exclusively, 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); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); - } - - /** - * Sorts the specified array into ascending numerical order. - * - * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + * <p>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 @@ -110,37 +73,76 @@ * @param a the array to be sorted */ public static void sort(int[] a) { - sort(a, 0, a.length); + DualPivotQuicksort.sort(a); } /** - * Sorts the specified range of the specified array into ascending order. The - * range of to be sorted extends from the index {@code fromIndex}, inclusive, - * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * 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. * - * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + * <p>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, inclusively, to be sorted - * @param toIndex the index of the last element, exclusively, 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); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); + DualPivotQuicksort.sort(a, fromIndex, toIndex); } /** * Sorts the specified array into ascending numerical order. * - * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + * <p>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. + * + * <p>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. + * + * <p>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 @@ -149,37 +151,37 @@ * @param a the array to be sorted */ public static void sort(short[] a) { - sort(a, 0, a.length); + DualPivotQuicksort.sort(a); } /** - * Sorts the specified range of the specified array into ascending order. The - * range of to be sorted extends from the index {@code fromIndex}, inclusive, - * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * 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. * - * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + * <p>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, inclusively, to be sorted - * @param toIndex the index of the last element, exclusively, 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); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); + DualPivotQuicksort.sort(a, fromIndex, toIndex); } /** * Sorts the specified array into ascending numerical order. * - * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + * <p>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 @@ -188,37 +190,37 @@ * @param a the array to be sorted */ public static void sort(char[] a) { - sort(a, 0, a.length); + DualPivotQuicksort.sort(a); } /** - * Sorts the specified range of the specified array into ascending order. The - * range of to be sorted extends from the index {@code fromIndex}, inclusive, - * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * 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. * - * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + * <p>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, inclusively, to be sorted - * @param toIndex the index of the last element, exclusively, 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); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); + DualPivotQuicksort.sort(a, fromIndex, toIndex); } /** * Sorts the specified array into ascending numerical order. * - * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + * <p>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 @@ -227,49 +229,100 @@ * @param a the array to be sorted */ public static void sort(byte[] a) { - sort(a, 0, a.length); + DualPivotQuicksort.sort(a); } /** - * Sorts the specified range of the specified array into ascending order. The - * range of to be sorted extends from the index {@code fromIndex}, inclusive, - * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * 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. * - * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + * <p>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(byte[] a, int fromIndex, int toIndex) { + DualPivotQuicksort.sort(a, fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * <p>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. + * + * <p>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, inclusively, to be sorted - * @param toIndex the index of the last element, exclusively, to be sorted + */ + public static void sort(float[] 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. + * + * <p>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. + * + * <p>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(byte[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); + public static void sort(float[] a, int fromIndex, int toIndex) { + DualPivotQuicksort.sort(a, fromIndex, toIndex); } /** * Sorts the specified array into ascending numerical order. * - * <p>The {@code <} relation does not provide a total order on - * all floating-point values; although they are distinct numbers - * {@code -0.0d == 0.0d} is {@code 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 {@code <} relation to determine ascending numerical order, - * this method uses the total order imposed by {@link Double#compareTo}. - * This ordering differs from the {@code <} relation in that {@code -0.0d} - * is treated as less than {@code 0.0d} and NaN is considered greater than - * any other floating-point value. For the purposes of sorting, all NaN - * values are considered equivalent and equal. + * <p>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. * - * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + * <p>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 @@ -278,203 +331,45 @@ * @param a the array to be sorted */ public static void sort(double[] a) { - sort(a, 0, a.length); + DualPivotQuicksort.sort(a); } /** - * Sorts the specified range of the specified array into ascending order. The - * range of to be sorted extends from the index {@code fromIndex}, inclusive, - * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * 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. * - * <p>The {@code <} relation does not provide a total order on - * all floating-point values; although they are distinct numbers - * {@code -0.0d == 0.0d} is {@code 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 {@code <} relation to determine ascending numerical order, - * this method uses the total order imposed by {@link Double#compareTo}. - * This ordering differs from the {@code <} relation in that {@code -0.0d} - * is treated as less than {@code 0.0d} and NaN is considered greater than - * any other floating-point value. For the purposes of sorting, all NaN - * values are considered equivalent and equal. + * <p>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. * - * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort, + * <p>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, inclusively, to be sorted - * @param toIndex the index of the last element, exclusively, 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); - } - - private static void sortNegZeroAndNaN(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.0d aware comparisons during the main sort. - * - * Preprocessing phase: move any NaN's to end of array, count the - * number of -0.0d's, and turn them into 0.0d's. - */ - int numNegZeros = 0; - int i = fromIndex; - int n = toIndex; - double temp; - - while (i < n) { - if (a[i] != a[i]) { - n--; - temp = a[i]; - a[i] = a[n]; - a[n] = temp; - } - 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 - DualPivotQuicksort.sort(a, fromIndex, n - 1); - - // Postprocessing phase: change 0.0d's to -0.0d's as required - if (numNegZeros != 0) { - int j = binarySearch0(a, fromIndex, n, 0.0d); // position 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; k < numNegZeros; k++) { - a[++j] = -0.0d; - } - } - } - - /** - * Sorts the specified array into ascending numerical order. - * - * <p>The {@code <} relation does not provide a total order on - * all floating-point values; although they are distinct numbers - * {@code -0.0f == 0.0f} is {@code 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 {@code <} relation to determine ascending numerical order, - * this method uses the total order imposed by {@link Float#compareTo}. - * This ordering differs from the {@code <} relation in that {@code -0.0f} - * is treated as less than {@code 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. - * - * <p>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) { - sort(a, 0, a.length); + DualPivotQuicksort.sort(a, fromIndex, toIndex); } - /** - * Sorts the specified range of the specified array into ascending order. The - * range of 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. + /* + * Sorting of complex type arrays. * - * <p>The {@code <} relation does not provide a total order on - * all floating-point values; although they are distinct numbers - * {@code -0.0f == 0.0f} is {@code 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 {@code <} relation to determine ascending numerical order, - * this method uses the total order imposed by {@link Float#compareTo}. - * This ordering differs from the {@code <} relation in that {@code -0.0f} - * is treated as less than {@code 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. - * - * <p>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, inclusively, to be sorted - * @param toIndex the index of the last element, exclusively, 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); - } - - private static void sortNegZeroAndNaN(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.0f aware comparisons during the main sort. - * - * Preprocessing phase: move any NaN's to end of array, count the - * number of -0.0f's, and turn them into 0.0f's. - */ - int numNegZeros = 0; - int i = fromIndex; - int n = toIndex; - float temp; - - while (i < n) { - if (a[i] != a[i]) { - n--; - temp = a[i]; - a[i] = a[n]; - a[n] = temp; - } - 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 - DualPivotQuicksort.sort(a, fromIndex, n - 1); - - // Postprocessing phase: change 0.0f's to -0.0f's as required - if (numNegZeros != 0) { - int j = binarySearch0(a, fromIndex, n, 0.0f); // position 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; k < numNegZeros; k++) { - a[++j] = -0.0f; - } - } - } /** * Old merge sort implementation can be selected (for
--- a/src/share/classes/java/util/DualPivotQuicksort.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/DualPivotQuicksort.java Thu Nov 12 23:04:42 2009 +0000 @@ -36,11 +36,11 @@ * @author Jon Bentley * @author Josh Bloch * - * @version 2009.10.29 m765.827.v5 + * @version 2009.11.09 m765.827.v8 */ final class DualPivotQuicksort { - // Suppresses default constructor, ensuring non-instantiability. + // Suppresses default constructor private DualPivotQuicksort() {} /* @@ -70,13 +70,43 @@ */ /** - * Sorts the specified range of the array into ascending order. + * 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 left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, 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} */ - static void sort(int[] a, int left, int right) { + 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++) { @@ -94,12 +124,12 @@ } /** - * Sorts the specified range of the array into ascending order - * by Dual-Pivot Quicksort. + * 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, inclusively, to be sorted - * @param right the index of the last element, inclusively, 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 @@ -234,8 +264,8 @@ a[right] = a[great + 1]; a[great + 1] = pivot2; // Sort left and right parts recursively, excluding known pivot values - sort(a, left, less - 2); - sort(a, great + 2, right); + doSort(a, left, less - 2); + doSort(a, great + 2, right); /* * If pivot1 == pivot2, all elements from center @@ -271,17 +301,47 @@ } // Sort center part recursively, excluding known pivot values - sort(a, less, great); + 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. + * 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 left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, 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} */ - static void sort(long[] a, int left, int right) { + 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++) { @@ -299,12 +359,12 @@ } /** - * Sorts the specified range of the array into ascending order - * by Dual-Pivot Quicksort. + * 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, inclusively, to be sorted - * @param right the index of the last element, inclusively, 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 @@ -439,8 +499,8 @@ a[right] = a[great + 1]; a[great + 1] = pivot2; // Sort left and right parts recursively, excluding known pivot values - sort(a, left, less - 2); - sort(a, great + 2, right); + doSort(a, left, less - 2); + doSort(a, great + 2, right); /* * If pivot1 == pivot2, all elements from center @@ -476,20 +536,50 @@ } // Sort center part recursively, excluding known pivot values - sort(a, less, great); + 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); } - /** The number of distinct short values */ + /** + * 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. + * 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, inclusively, to be sorted - * @param right the index of the last element, inclusively, 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 */ - static void sort(short[] a, int left, int right) { + 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++) { @@ -501,7 +591,7 @@ } a[j + 1] = ak; } - } else if (right - left + 1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { + } 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]; @@ -521,12 +611,12 @@ } /** - * Sorts the specified range of the array into ascending order - * by Dual-Pivot Quicksort. + * 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, inclusively, to be sorted - * @param right the index of the last element, inclusively, 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 @@ -661,8 +751,8 @@ a[right] = a[great + 1]; a[great + 1] = pivot2; // Sort left and right parts recursively, excluding known pivot values - sort(a, left, less - 2); - sort(a, great + 2, right); + doSort(a, left, less - 2); + doSort(a, great + 2, right); /* * If pivot1 == pivot2, all elements from center @@ -698,242 +788,50 @@ } // Sort center part recursively, excluding known pivot values - sort(a, less, great); + doSort(a, less, great); } - /** 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. + * Sorts the specified array into ascending numerical order. * * @param a the array to be sorted - * @param left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, to be sorted */ - static void sort(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); - } + public static void sort(char[] a) { + doSort(a, 0, a.length - 1); } /** - * Sorts the specified range of the array into ascending order - * by Dual-Pivot Quicksort. + * 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 left the index of the first element, inclusively, to be sorted - * @param right the index of the last element, inclusively, 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} */ - 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 in place using a 5-element sorting network - if (a[e1] > a[e2]) { byte t = a[e1]; a[e1] = a[e2]; a[e2] = t; } - if (a[e4] > a[e5]) { byte t = a[e4]; a[e4] = a[e5]; a[e5] = t; } - if (a[e1] > a[e3]) { byte t = a[e1]; a[e1] = a[e3]; a[e3] = t; } - if (a[e2] > a[e3]) { byte t = a[e2]; a[e2] = a[e3]; a[e3] = t; } - if (a[e1] > a[e4]) { byte t = a[e1]; a[e1] = a[e4]; a[e4] = t; } - if (a[e3] > a[e4]) { byte t = a[e3]; a[e3] = a[e4]; a[e4] = t; } - if (a[e2] > a[e5]) { byte t = a[e2]; a[e2] = a[e5]; a[e5] = t; } - if (a[e2] > a[e3]) { byte t = a[e2]; a[e2] = a[e3]; a[e3] = t; } - if (a[e4] > a[e5]) { byte t = a[e4]; a[e4] = a[e5]; a[e5] = t; } - - /* - * 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 = a[e2]; a[e2] = a[left]; - byte pivot2 = a[e4]; 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 - */ - for (int k = less; k <= great; k++) { - byte ak = a[k]; - - if (ak < pivot1) { - a[k] = a[less]; - a[less++] = ak; - } else if (ak > pivot2) { - while (a[great] > pivot2 && k < great) { - great--; - } - a[k] = a[great]; - a[great--] = ak; - ak = a[k]; - - if (ak < 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 - */ - for (int k = less; k <= great; k++) { - byte ak = a[k]; - - if (ak == pivot1) { - continue; - } - if (ak < pivot1) { - a[k] = a[less]; - a[less++] = ak; - } else { - while (a[great] > pivot1) { - great--; - } - a[k] = a[great]; - a[great--] = ak; - ak = a[k]; - - if (ak < 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 - sort(a, left, less - 2); - sort(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++; - } - for (int k = less + 1; k <= great; k++) { - if (a[k] == pivot1) { - a[k] = a[less]; - a[less++] = pivot1; - } - } - while (a[great] == pivot2) { - great--; - } - for (int k = great - 1; k >= less; k--) { - if (a[k] == pivot2) { - a[k] = a[great]; - a[great--] = pivot2; - } - } - } - - // Sort center part recursively, excluding known pivot values - sort(a, less, great); + 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 */ + /** 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. + * 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, inclusively, to be sorted - * @param right the index of the last element, inclusively, 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 */ - static void sort(char[] a, int left, int right) { + 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++) { @@ -945,7 +843,7 @@ } a[j + 1] = ak; } - } else if (right - left + 1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { + } 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]; @@ -963,12 +861,12 @@ } /** - * Sorts the specified range of the array into ascending order - * by Dual-Pivot Quicksort. + * 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, inclusively, to be sorted - * @param right the index of the last element, inclusively, 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 @@ -1103,8 +1001,8 @@ a[right] = a[great + 1]; a[great + 1] = pivot2; // Sort left and right parts recursively, excluding known pivot values - sort(a, left, less - 2); - sort(a, great + 2, right); + doSort(a, left, less - 2); + doSort(a, great + 2, right); /* * If pivot1 == pivot2, all elements from center @@ -1140,17 +1038,395 @@ } // Sort center part recursively, excluding known pivot values - sort(a, less, great); + 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. + * 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, inclusively, to be sorted - * @param right the index of the last element, inclusively, 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 */ - static void sort(float[] a, int left, int right) { + 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 in place using a 5-element sorting network + if (a[e1] > a[e2]) { byte t = a[e1]; a[e1] = a[e2]; a[e2] = t; } + if (a[e4] > a[e5]) { byte t = a[e4]; a[e4] = a[e5]; a[e5] = t; } + if (a[e1] > a[e3]) { byte t = a[e1]; a[e1] = a[e3]; a[e3] = t; } + if (a[e2] > a[e3]) { byte t = a[e2]; a[e2] = a[e3]; a[e3] = t; } + if (a[e1] > a[e4]) { byte t = a[e1]; a[e1] = a[e4]; a[e4] = t; } + if (a[e3] > a[e4]) { byte t = a[e3]; a[e3] = a[e4]; a[e4] = t; } + if (a[e2] > a[e5]) { byte t = a[e2]; a[e2] = a[e5]; a[e5] = t; } + if (a[e2] > a[e3]) { byte t = a[e2]; a[e2] = a[e3]; a[e3] = t; } + if (a[e4] > a[e5]) { byte t = a[e4]; a[e4] = a[e5]; a[e5] = t; } + + /* + * 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 = a[e2]; a[e2] = a[left]; + byte pivot2 = a[e4]; 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 + */ + for (int k = less; k <= great; k++) { + byte ak = a[k]; + + if (ak < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } else if (ak > pivot2) { + while (a[great] > pivot2 && k < great) { + great--; + } + a[k] = a[great]; + a[great--] = ak; + ak = a[k]; + + if (ak < 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 + */ + for (int k = less; k <= great; k++) { + byte ak = a[k]; + + if (ak == pivot1) { + continue; + } + if (ak < pivot1) { + a[k] = a[less]; + a[less++] = ak; + } else { + while (a[great] > pivot1) { + great--; + } + a[k] = a[great]; + a[great--] = ak; + ak = a[k]; + + if (ak < 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++; + } + for (int k = less + 1; k <= great; k++) { + if (a[k] == pivot1) { + a[k] = a[less]; + a[less++] = pivot1; + } + } + while (a[great] == pivot2) { + great--; + } + for (int k = great - 1; k >= less; k--) { + if (a[k] == pivot2) { + a[k] = a[great]; + a[great--] = pivot2; + } + } + } + + // Sort center part recursively, excluding known pivot values + doSort(a, less, great); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * <p>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. + * + * <p>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++) { @@ -1168,12 +1444,12 @@ } /** - * Sorts the specified range of the array into ascending order - * by Dual-Pivot Quicksort. + * 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, inclusively, to be sorted - * @param right the index of the last element, inclusively, 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 @@ -1308,8 +1584,8 @@ a[right] = a[great + 1]; a[great + 1] = pivot2; // Sort left and right parts recursively, excluding known pivot values - sort(a, left, less - 2); - sort(a, great + 2, right); + doSort(a, left, less - 2); + doSort(a, great + 2, right); /* * If pivot1 == pivot2, all elements from center @@ -1345,17 +1621,143 @@ } // Sort center part recursively, excluding known pivot values - sort(a, less, great); + doSort(a, less, great); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * <p>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. + * + * <p>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. + * 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, inclusively, to be sorted - * @param right the index of the last element, inclusively, 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 */ - static void sort(double[] a, int left, int right) { + 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++) { @@ -1373,12 +1775,12 @@ } /** - * Sorts the specified range of the array into ascending order - * by Dual-Pivot Quicksort. + * 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, inclusively, to be sorted - * @param right the index of the last element, inclusively, 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 @@ -1513,8 +1915,8 @@ a[right] = a[great + 1]; a[great + 1] = pivot2; // Sort left and right parts recursively, excluding known pivot values - sort(a, left, less - 2); - sort(a, great + 2, right); + doSort(a, left, less - 2); + doSort(a, great + 2, right); /* * If pivot1 == pivot2, all elements from center @@ -1550,6 +1952,23 @@ } // Sort center part recursively, excluding known pivot values - sort(a, less, great); + 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); + } } }
--- a/src/share/classes/java/util/Formatter.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/Formatter.java Thu Nov 12 23:04:42 2009 +0000 @@ -2485,55 +2485,45 @@ 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<FormatString> al = new ArrayList<FormatString>(); 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 @@ private boolean dt = false; private char c; - private Formatter formatter; - // cache the line separator private String ls; @@ -2650,21 +2638,22 @@ return c; } - FormatSpecifier(Formatter formatter, String[] sa) { - this.formatter = formatter; - int idx = 0; - - index(sa[idx++]); - flags(sa[idx++]); - width(sa[idx++]); - precision(sa[idx++]); - - if (sa[idx] != null) { + FormatSpecifier(Matcher m) { + int idx = 1; + + index(m.group(idx++)); + flags(m.group(idx++)); + width(m.group(idx++)); + precision(m.group(idx++)); + + 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 @@ 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))
--- a/src/share/classes/java/util/HashMap.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/HashMap.java Thu Nov 12 23:04:42 2009 +0000 @@ -448,10 +448,8 @@ } private void putAllForCreate(Map<? extends K, ? extends V> m) { - for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) { - Map.Entry<? extends K, ? extends V> e = i.next(); + for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) putForCreate(e.getKey(), e.getValue()); - } } /** @@ -536,10 +534,8 @@ resize(newCapacity); } - for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) { - Map.Entry<? extends K, ? extends V> e = i.next(); + for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) put(e.getKey(), e.getValue()); - } } /**
--- a/src/share/classes/java/util/HashSet.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/HashSet.java Thu Nov 12 23:04:42 2009 +0000 @@ -280,8 +280,8 @@ s.writeInt(map.size()); // Write out all elements in the proper order. - for (Iterator i=map.keySet().iterator(); i.hasNext(); ) - s.writeObject(i.next()); + for (E e : map.keySet()) + s.writeObject(e); } /**
--- a/src/share/classes/java/util/LinkedList.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/LinkedList.java Thu Nov 12 23:04:42 2009 +0000 @@ -26,22 +26,22 @@ package java.util; /** - * Linked list implementation of the <tt>List</tt> interface. Implements all + * Linked list implementation of the {@code List} interface. Implements all * optional list operations, and permits all elements (including - * <tt>null</tt>). In addition to implementing the <tt>List</tt> interface, - * the <tt>LinkedList</tt> class provides uniformly named methods to - * <tt>get</tt>, <tt>remove</tt> and <tt>insert</tt> 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}. <p> + * double-ended queue}. * - * The class implements the <tt>Deque</tt> interface, providing - * first-in-first-out queue operations for <tt>add</tt>, - * <tt>poll</tt>, along with other stack and deque operations.<p> + * <p>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 + * <p>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.<p> + * the beginning or the end, whichever is closer to the specified index. * * <p><strong>Note that this implementation is not synchronized.</strong> * If multiple threads access a linked list concurrently, and at least @@ -58,11 +58,11 @@ * unsynchronized access to the list:<pre> * List list = Collections.synchronizedList(new LinkedList(...));</pre> * - * <p>The iterators returned by this class's <tt>iterator</tt> and - * <tt>listIterator</tt> methods are <i>fail-fast</i>: if the list is + * <p>The iterators returned by this class's {@code iterator} and + * {@code listIterator} methods are <i>fail-fast</i>: if the list is * structurally modified at any time after the iterator is created, in - * any way except through the Iterator's own <tt>remove</tt> or - * <tt>add</tt> 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 @@ * <p>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 <tt>ConcurrentModificationException</tt> 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: <i>the fail-fast behavior of iterators * should be used only to detect bugs.</i> @@ -83,7 +83,6 @@ * @author Josh Bloch * @see List * @see ArrayList - * @see Vector * @since 1.2 * @param <E> the type of elements held in this collection */ @@ -92,14 +91,26 @@ extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable { - private transient Entry<E> header = new Entry<E>(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<E> first; + + /** + * Pointer to last node. + * Invariant: (first == null && last == null) || + * (last.next == null && last.item != null) + */ + transient Node<E> last; /** * Constructs an empty list. */ public LinkedList() { - header.next = header.previous = header; } /** @@ -116,16 +127,129 @@ } /** + * Links e as first element. + */ + private void linkFirst(E e) { + final Node<E> f = first; + final Node<E> newNode = new Node<E>(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<E> l = last; + final Node<E> newNode = new Node<E>(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<E> succ) { + // assert succ != null; + final Node<E> pred = succ.prev; + final Node<E> newNode = new Node<E>(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<E> f) { + // assert f == first && f != null; + final E element = f.item; + final Node<E> 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<E> l) { + // assert l == last && l != null; + final E element = l.item; + final Node<E> 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<E> x) { + // assert x != null; + final E element = x.item; + final Node<E> next = x.next; + final Node<E> 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. * * @return the first element in this list * @throws NoSuchElementException if this list is empty */ public E getFirst() { - if (size==0) + final Node<E> f = first; + if (f == null) throw new NoSuchElementException(); - - return header.next.element; + return f.item; } /** @@ -135,10 +259,10 @@ * @throws NoSuchElementException if this list is empty */ public E getLast() { - if (size==0) + final Node<E> l = last; + if (l == null) throw new NoSuchElementException(); - - return header.previous.element; + return l.item; } /** @@ -148,7 +272,10 @@ * @throws NoSuchElementException if this list is empty */ public E removeFirst() { - return remove(header.next); + final Node<E> f = first; + if (f == null) + throw new NoSuchElementException(); + return unlinkFirst(f); } /** @@ -158,7 +285,10 @@ * @throws NoSuchElementException if this list is empty */ public E removeLast() { - return remove(header.previous); + final Node<E> l = last; + if (l == null) + throw new NoSuchElementException(); + return unlinkLast(l); } /** @@ -167,7 +297,7 @@ * @param e the element to add */ public void addFirst(E e) { - addBefore(e, header.next); + linkFirst(e); } /** @@ -178,17 +308,17 @@ * @param e the element to add */ public void addLast(E e) { - addBefore(e, header); + linkLast(e); } /** - * Returns <tt>true</tt> if this list contains the specified element. - * More formally, returns <tt>true</tt> if and only if this list contains - * at least one element <tt>e</tt> 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 * <tt>(o==null ? e==null : o.equals(e))</tt>. * * @param o element whose presence in this list is to be tested - * @return <tt>true</tt> 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 @@ * <p>This method is equivalent to {@link #addLast}. * * @param e element to be appended to this list - * @return <tt>true</tt> (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 @@ * 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 - * <tt>i</tt> such that + * {@code i} such that * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt> - * (if such an element exists). Returns <tt>true</tt> 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 <tt>true</tt> 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> e = header.next; e != header; e = e.next) { - if (e.element==null) { - remove(e); + if (o == null) { + for (Node<E> x = first; x != null; x = x.next) { + if (x.item == null) { + unlink(x); return true; } } } else { - for (Entry<E> e = header.next; e != header; e = e.next) { - if (o.equals(e.element)) { - remove(e); + for (Node<E> x = first; x != null; x = x.next) { + if (o.equals(x.item)) { + unlink(x); return true; } } @@ -257,7 +387,7 @@ * this list, and it's nonempty.) * * @param c collection containing elements to be added to this list - * @return <tt>true</tt> 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<? extends E> c) { @@ -275,45 +405,66 @@ * @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 <tt>true</tt> 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<? extends E> 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++; + + Node<E> pred, succ; + if (index == size) { + succ = null; + pred = last; + } else { + succ = node(index); + pred = succ.prev; + } - Entry<E> successor = (index==size ? header : entry(index)); - Entry<E> predecessor = successor.previous; - for (int i=0; i<numNew; i++) { - Entry<E> e = new Entry<E>((E)a[i], successor, predecessor); - predecessor.next = e; - predecessor = e; + for (Object o : a) { + @SuppressWarnings("unchecked") E e = (E) o; + Node<E> newNode = new Node<E>(pred, e, null); + if (pred == null) + first = newNode; + else + pred.next = newNode; + pred = newNode; } - successor.previous = predecessor; + + if (succ == null) { + last = pred; + } else { + pred.next = succ; + succ.prev = pred; + } 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> e = header.next; - while (e != header) { - Entry<E> 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<E> x = first; x != null; ) { + Node<E> 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 @@ * @throws IndexOutOfBoundsException {@inheritDoc} */ public E get(int index) { - return entry(index).element; + checkElementIndex(index); + return node(index).item; } /** @@ -342,9 +494,10 @@ * @throws IndexOutOfBoundsException {@inheritDoc} */ public E set(int index, E element) { - Entry<E> e = entry(index); - E oldVal = e.element; - e.element = element; + checkElementIndex(index); + Node<E> x = node(index); + E oldVal = x.item; + x.item = element; return oldVal; } @@ -358,7 +511,12 @@ * @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 @@ * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { - return remove(entry(index)); + checkElementIndex(index); + return unlink(node(index)); + } + + /** + * Tells if the argument is the index of an existing element. + */ + 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; } /** - * Returns the indexed entry. + * 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 Entry<E> entry(int index) { - if (index < 0 || index >= size) - throw new IndexOutOfBoundsException("Index: "+index+ - ", Size: "+size); - Entry<E> 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 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<E> node(int index) { + // assert isElementIndex(index); + + if (index < (size >> 1)) { + Node<E> x = first; + for (int i = 0; i < index; i++) + x = x.next; + return x; + } else { + Node<E> 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 <tt>i</tt> such that + * More formally, returns the lowest index {@code i} such that * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>, * or -1 if there is no such index. * @@ -408,15 +601,15 @@ */ 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<E> 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<E> x = first; x != null; x = x.next) { + if (o.equals(x.item)) return index; index++; } @@ -427,7 +620,7 @@ /** * 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 <tt>i</tt> such that + * More formally, returns the highest index {@code i} such that * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>, * or -1 if there is no such index. * @@ -437,16 +630,16 @@ */ 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<E> 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<E> x = last; x != null; x = x.prev) { index--; - if (o.equals(e.element)) + if (o.equals(x.item)) return index; } } @@ -457,17 +650,18 @@ /** * Retrieves, but does not remove, the head (first element) of this list. - * @return the head of this list, or <tt>null</tt> 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<E> 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 @@ } /** - * Retrieves and removes the head (first element) of this list - * @return the head of this list, or <tt>null</tt> 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<E> f = first; + return (f == null) ? null : unlinkFirst(f); } /** @@ -502,7 +696,7 @@ * Adds the specified element as the tail (last element) of this list. * * @param e the element to add - * @return <tt>true</tt> (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 @@ * Inserts the specified element at the front of this list. * * @param e the element to insert - * @return <tt>true</tt> (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 @@ * Inserts the specified element at the end of this list. * * @param e the element to insert - * @return <tt>true</tt> (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 @@ /** * Retrieves, but does not remove, the first element of this list, - * or returns <tt>null</tt> if this list is empty. + * or returns {@code null} if this list is empty. * - * @return the first element of this list, or <tt>null</tt> + * @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<E> f = first; + return (f == null) ? null : f.item; + } /** * Retrieves, but does not remove, the last element of this list, - * or returns <tt>null</tt> if this list is empty. + * or returns {@code null} if this list is empty. * - * @return the last element of this list, or <tt>null</tt> + * @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<E> l = last; + return (l == null) ? null : l.item; } /** * Retrieves and removes the first element of this list, - * or returns <tt>null</tt> if this list is empty. + * or returns {@code null} if this list is empty. * - * @return the first element of this list, or <tt>null</tt> 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<E> f = first; + return (f == null) ? null : unlinkFirst(f); } /** * Retrieves and removes the last element of this list, - * or returns <tt>null</tt> if this list is empty. + * or returns {@code null} if this list is empty. * - * @return the last element of this list, or <tt>null</tt> 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<E> l = last; + return (l == null) ? null : unlinkLast(l); } /** @@ -624,7 +814,7 @@ * does not contain the element, it is unchanged. * * @param o element to be removed from this list, if present - * @return <tt>true</tt> 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 @@ * does not contain the element, it is unchanged. * * @param o element to be removed from this list, if present - * @return <tt>true</tt> 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> e = header.previous; e != header; e = e.previous) { - if (e.element==null) { - remove(e); + if (o == null) { + for (Node<E> x = last; x != null; x = x.prev) { + if (x.item == null) { + unlink(x); return true; } } } else { - for (Entry<E> e = header.previous; e != header; e = e.previous) { - if (o.equals(e.element)) { - remove(e); + for (Node<E> x = last; x != null; x = x.prev) { + if (o.equals(x.item)) { + unlink(x); return true; } } @@ -662,76 +852,68 @@ /** * 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 <tt>List.listIterator(int)</tt>.<p> + * Obeys the general contract of {@code List.listIterator(int)}.<p> * * The list-iterator is <i>fail-fast</i>: if the list is structurally * modified at any time after the Iterator is created, in any way except - * through the list-iterator's own <tt>remove</tt> or <tt>add</tt> + * through the list-iterator's own {@code remove} or {@code add} * methods, the list-iterator will throw a - * <tt>ConcurrentModificationException</tt>. 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 <tt>next</tt>) + * 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<E> listIterator(int index) { + checkPositionIndex(index); return new ListItr(index); } private class ListItr implements ListIterator<E> { - private Entry<E> lastReturned = header; - private Entry<E> next; + private Node<E> lastReturned = null; + private Node<E> 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; nextIndex<index; nextIndex++) - next = next.next; - } else { - next = header; - for (nextIndex=size; nextIndex>index; 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 int previousIndex() { - return nextIndex-1; + return nextIndex - 1; } public void remove() { checkForComodification(); - Entry<E> lastNext = lastReturned.next; - try { - LinkedList.this.remove(lastReturned); - } catch (NoSuchElementException e) { + if (lastReturned == null) throw new IllegalStateException(); - } - if (next==lastReturned) + + Node<E> 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,39 +963,16 @@ } } - private static class Entry<E> { - E element; - Entry<E> next; - Entry<E> previous; - - Entry(E element, Entry<E> next, Entry<E> previous) { - this.element = element; - this.next = next; - this.previous = previous; - } - } + private static class Node<E> { + E item; + Node<E> next; + Node<E> prev; - private Entry<E> addBefore(E e, Entry<E> entry) { - Entry<E> newEntry = new Entry<E>(e, entry, entry.previous); - newEntry.previous.next = newEntry; - newEntry.next.previous = newEntry; - size++; - modCount++; - return newEntry; - } - - private E remove(Entry<E> 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; + Node(Node<E> prev, E element, Node<E> next) { + this.item = element; + this.next = next; + this.prev = prev; + } } /** @@ -821,9 +982,11 @@ 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<E> { + private final ListItr itr = new ListItr(size()); public boolean hasNext() { return itr.hasPrevious(); } @@ -835,29 +998,32 @@ } } - /** - * Returns a shallow copy of this <tt>LinkedList</tt>. (The elements - * themselves are not cloned.) - * - * @return a shallow copy of this <tt>LinkedList</tt> instance - */ - public Object clone() { - LinkedList<E> clone = null; + @SuppressWarnings("unchecked") + private LinkedList<E> superClone() { try { - clone = (LinkedList<E>) super.clone(); + return (LinkedList<E>) 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<E> clone = superClone(); // Put clone into "virgin" state - clone.header = new Entry<E>(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> e = header.next; e != header; e = e.next) - clone.add(e.element); + for (Node<E> x = first; x != null; x = x.next) + clone.add(x.item); return clone; } @@ -879,8 +1045,8 @@ public Object[] toArray() { Object[] result = new Object[size]; int i = 0; - for (Entry<E> e = header.next; e != header; e = e.next) - result[i++] = e.element; + for (Node<E> x = first; x != null; x = x.next) + result[i++] = x.item; return result; } @@ -894,7 +1060,7 @@ * * <p>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 <tt>null</tt>. + * immediately following the end of the list is set to {@code null}. * (This is useful in determining the length of the list <i>only</i> if * the caller knows that the list does not contain any null elements.) * @@ -903,15 +1069,15 @@ * precise control over the runtime type of the output array, and may, * under certain circumstances, be used to save allocation costs. * - * <p>Suppose <tt>x</tt> is a list known to contain only strings. + * <p>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 <tt>String</tt>: + * allocated array of {@code String}: * * <pre> * String[] y = x.toArray(new String[0]);</pre> * - * Note that <tt>toArray(new Object[0])</tt> is identical in function to - * <tt>toArray()</tt>. + * 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 @@ * this list * @throws NullPointerException if the specified array is null */ + @SuppressWarnings("unchecked") public <T> 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> e = header.next; e != header; e = e.next) - result[i++] = e.element; + for (Node<E> x = first; x != null; x = x.next) + result[i++] = x.item; if (a.length > size) a[size] = null; @@ -940,8 +1107,8 @@ private static final long serialVersionUID = 876323262645176354L; /** - * Save the state of this <tt>LinkedList</tt> 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 @@ 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<E> x = first; x != null; x = x.next) + s.writeObject(x.item); } /** - * Reconstitute this <tt>LinkedList</tt> 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 @@ // Read in size int size = s.readInt(); - // Initialize header - header = new Entry<E>(null, null, null); - header.next = header.previous = header; - // Read in all elements in the proper order. - for (int i=0; i<size; i++) - addBefore((E)s.readObject(), header); + for (int i = 0; i < size; i++) + linkLast((E)s.readObject()); } }
--- a/src/share/classes/java/util/Random.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/Random.java Thu Nov 12 23:04:42 2009 +0000 @@ -50,6 +50,18 @@ * <p> * Many applications will find the method {@link Math#random} simpler to use. * + * <p>Instances of {@code java.util.Random} are threadsafe. + * However, the concurrent use of the same {@code java.util.Random} + * instance across threads may encounter contention and consequent + * poor performance. Consider instead using + * {@link java.util.concurrent.ThreadLocalRandom} in multithreaded + * designs. + * + * <p>Instances of {@code java.util.Random} are not cryptographically + * secure. Consider instead using {@link java.security.SecureRandom} to + * get a cryptographically secure pseudo-random number generator for use + * by security-sensitive applications. + * * @author Frank Yellin * @since 1.0 */
--- a/src/share/classes/java/util/concurrent/ArrayBlockingQueue.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/concurrent/ArrayBlockingQueue.java Thu Nov 12 23:04:42 2009 +0000 @@ -218,8 +218,8 @@ if (capacity < c.size()) throw new IllegalArgumentException(); - for (Iterator<? extends E> it = c.iterator(); it.hasNext();) - add(it.next()); + for (E e : c) + add(e); } /**
--- a/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java Thu Nov 12 23:04:42 2009 +0000 @@ -250,8 +250,8 @@ * of its elements are null */ public ConcurrentLinkedQueue(Collection<? extends E> c) { - for (Iterator<? extends E> it = c.iterator(); it.hasNext();) - add(it.next()); + for (E e : c) + add(e); } // Have to override just to update the javadoc
--- a/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Thu Nov 12 23:04:42 2009 +0000 @@ -895,7 +895,7 @@ if (n != null) { Node<K,V> f = n.next; if (n != b.next) // inconsistent read - break;; + break; Object v = n.value; if (v == null) { // n is deleted n.helpDelete(b, f);
--- a/src/share/classes/java/util/concurrent/CountDownLatch.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/concurrent/CountDownLatch.java Thu Nov 12 23:04:42 2009 +0000 @@ -148,7 +148,8 @@ * * </pre> * - * <p>Memory consistency effects: Actions in a thread prior to calling + * <p>Memory consistency effects: Until the count reaches + * zero, actions in a thread prior to calling * {@code countDown()} * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> * actions following a successful return from a corresponding
--- a/src/share/classes/java/util/concurrent/ExecutorService.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/concurrent/ExecutorService.java Thu Nov 12 23:04:42 2009 +0000 @@ -332,8 +332,8 @@ * @param tasks the collection of tasks * @return the result returned by one of the tasks * @throws InterruptedException if interrupted while waiting - * @throws NullPointerException if tasks or any of its elements - * are <tt>null</tt> + * @throws NullPointerException if tasks or any element task + * subject to execution is <tt>null</tt> * @throws IllegalArgumentException if tasks is empty * @throws ExecutionException if no task successfully completes * @throws RejectedExecutionException if tasks cannot be scheduled @@ -356,8 +356,8 @@ * @param unit the time unit of the timeout argument * @return the result returned by one of the tasks. * @throws InterruptedException if interrupted while waiting - * @throws NullPointerException if tasks, any of its elements, or - * unit are <tt>null</tt> + * @throws NullPointerException if tasks, or unit, or any element + * task subject to execution is <tt>null</tt> * @throws TimeoutException if the given timeout elapses before * any task successfully completes * @throws ExecutionException if no task successfully completes
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/util/concurrent/ForkJoinPool.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,1988 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +/** + * An {@link ExecutorService} for running {@link ForkJoinTask}s. + * A {@code ForkJoinPool} provides the entry point for submissions + * from non-{@code ForkJoinTask}s, as well as management and + * monitoring operations. + * + * <p>A {@code ForkJoinPool} differs from other kinds of {@link + * ExecutorService} mainly by virtue of employing + * <em>work-stealing</em>: all threads in the pool attempt to find and + * execute subtasks created by other active tasks (eventually blocking + * waiting for work if none exist). This enables efficient processing + * when most tasks spawn other subtasks (as do most {@code + * ForkJoinTask}s). A {@code ForkJoinPool} may also be used for mixed + * execution of some plain {@code Runnable}- or {@code Callable}- + * based activities along with {@code ForkJoinTask}s. When setting + * {@linkplain #setAsyncMode async mode}, a {@code ForkJoinPool} may + * also be appropriate for use with fine-grained tasks of any form + * that are never joined. Otherwise, other {@code ExecutorService} + * implementations are typically more appropriate choices. + * + * <p>A {@code ForkJoinPool} is constructed with a given target + * parallelism level; by default, equal to the number of available + * processors. Unless configured otherwise via {@link + * #setMaintainsParallelism}, the pool attempts to maintain this + * number of active (or available) threads by dynamically adding, + * suspending, or resuming internal worker threads, even if some tasks + * are stalled waiting to join others. However, no such adjustments + * are performed in the face of blocked IO or other unmanaged + * synchronization. The nested {@link ManagedBlocker} interface + * enables extension of the kinds of synchronization accommodated. + * The target parallelism level may also be changed dynamically + * ({@link #setParallelism}). The total number of threads may be + * limited using method {@link #setMaximumPoolSize}, in which case it + * may become possible for the activities of a pool to stall due to + * the lack of available threads to process new tasks. + * + * <p>In addition to execution and lifecycle control methods, this + * class provides status check methods (for example + * {@link #getStealCount}) that are intended to aid in developing, + * tuning, and monitoring fork/join applications. Also, method + * {@link #toString} returns indications of pool state in a + * convenient form for informal monitoring. + * + * <p><b>Sample Usage.</b> Normally a single {@code ForkJoinPool} is + * used for all parallel task execution in a program or subsystem. + * Otherwise, use would not usually outweigh the construction and + * bookkeeping overhead of creating a large set of threads. For + * example, a common pool could be used for the {@code SortTasks} + * illustrated in {@link RecursiveAction}. Because {@code + * ForkJoinPool} uses threads in {@linkplain java.lang.Thread#isDaemon + * daemon} mode, there is typically no need to explicitly {@link + * #shutdown} such a pool upon program exit. + * + * <pre> + * static final ForkJoinPool mainPool = new ForkJoinPool(); + * ... + * public void sort(long[] array) { + * mainPool.invoke(new SortTask(array, 0, array.length)); + * } + * </pre> + * + * <p><b>Implementation notes</b>: This implementation restricts the + * maximum number of running threads to 32767. Attempts to create + * pools with greater than the maximum number result in + * {@code IllegalArgumentException}. + * + * <p>This implementation rejects submitted tasks (that is, by throwing + * {@link RejectedExecutionException}) only when the pool is shut down. + * + * @since 1.7 + * @author Doug Lea + */ +public class ForkJoinPool extends AbstractExecutorService { + + /* + * See the extended comments interspersed below for design, + * rationale, and walkthroughs. + */ + + /** Mask for packing and unpacking shorts */ + private static final int shortMask = 0xffff; + + /** Max pool size -- must be a power of two minus 1 */ + private static final int MAX_THREADS = 0x7FFF; + + /** + * Factory for creating new {@link ForkJoinWorkerThread}s. + * A {@code ForkJoinWorkerThreadFactory} must be defined and used + * for {@code ForkJoinWorkerThread} subclasses that extend base + * functionality or initialize threads with different contexts. + */ + public static interface ForkJoinWorkerThreadFactory { + /** + * Returns a new worker thread operating in the given pool. + * + * @param pool the pool this thread works in + * @throws NullPointerException if the pool is null + */ + public ForkJoinWorkerThread newThread(ForkJoinPool pool); + } + + /** + * Default ForkJoinWorkerThreadFactory implementation; creates a + * new ForkJoinWorkerThread. + */ + static class DefaultForkJoinWorkerThreadFactory + implements ForkJoinWorkerThreadFactory { + public ForkJoinWorkerThread newThread(ForkJoinPool pool) { + try { + return new ForkJoinWorkerThread(pool); + } catch (OutOfMemoryError oom) { + return null; + } + } + } + + /** + * Creates a new ForkJoinWorkerThread. This factory is used unless + * overridden in ForkJoinPool constructors. + */ + public static final ForkJoinWorkerThreadFactory + defaultForkJoinWorkerThreadFactory = + new DefaultForkJoinWorkerThreadFactory(); + + /** + * Permission required for callers of methods that may start or + * kill threads. + */ + private static final RuntimePermission modifyThreadPermission = + new RuntimePermission("modifyThread"); + + /** + * If there is a security manager, makes sure caller has + * permission to modify threads. + */ + private static void checkPermission() { + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkPermission(modifyThreadPermission); + } + + /** + * Generator for assigning sequence numbers as pool names. + */ + private static final AtomicInteger poolNumberGenerator = + new AtomicInteger(); + + /** + * Array holding all worker threads in the pool. Initialized upon + * first use. Array size must be a power of two. Updates and + * replacements are protected by workerLock, but it is always kept + * in a consistent enough state to be randomly accessed without + * locking by workers performing work-stealing. + */ + volatile ForkJoinWorkerThread[] workers; + + /** + * Lock protecting access to workers. + */ + private final ReentrantLock workerLock; + + /** + * Condition for awaitTermination. + */ + private final Condition termination; + + /** + * The uncaught exception handler used when any worker + * abruptly terminates + */ + private Thread.UncaughtExceptionHandler ueh; + + /** + * Creation factory for worker threads. + */ + private final ForkJoinWorkerThreadFactory factory; + + /** + * Head of stack of threads that were created to maintain + * parallelism when other threads blocked, but have since + * suspended when the parallelism level rose. + */ + private volatile WaitQueueNode spareStack; + + /** + * Sum of per-thread steal counts, updated only when threads are + * idle or terminating. + */ + private final AtomicLong stealCount; + + /** + * Queue for external submissions. + */ + private final LinkedTransferQueue<ForkJoinTask<?>> submissionQueue; + + /** + * Head of Treiber stack for barrier sync. See below for explanation. + */ + private volatile WaitQueueNode syncStack; + + /** + * The count for event barrier + */ + private volatile long eventCount; + + /** + * Pool number, just for assigning useful names to worker threads + */ + private final int poolNumber; + + /** + * The maximum allowed pool size + */ + private volatile int maxPoolSize; + + /** + * The desired parallelism level, updated only under workerLock. + */ + private volatile int parallelism; + + /** + * True if use local fifo, not default lifo, for local polling + */ + private volatile boolean locallyFifo; + + /** + * Holds number of total (i.e., created and not yet terminated) + * and running (i.e., not blocked on joins or other managed sync) + * threads, packed into one int to ensure consistent snapshot when + * making decisions about creating and suspending spare + * threads. Updated only by CAS. Note: CASes in + * updateRunningCount and preJoin assume that running active count + * is in low word, so need to be modified if this changes. + */ + private volatile int workerCounts; + + private static int totalCountOf(int s) { return s >>> 16; } + private static int runningCountOf(int s) { return s & shortMask; } + private static int workerCountsFor(int t, int r) { return (t << 16) + r; } + + /** + * Adds delta (which may be negative) to running count. This must + * be called before (with negative arg) and after (with positive) + * any managed synchronization (i.e., mainly, joins). + * + * @param delta the number to add + */ + final void updateRunningCount(int delta) { + int s; + do {} while (!casWorkerCounts(s = workerCounts, s + delta)); + } + + /** + * Adds delta (which may be negative) to both total and running + * count. This must be called upon creation and termination of + * worker threads. + * + * @param delta the number to add + */ + private void updateWorkerCount(int delta) { + int d = delta + (delta << 16); // add to both lo and hi parts + int s; + do {} while (!casWorkerCounts(s = workerCounts, s + d)); + } + + /** + * Lifecycle control. High word contains runState, low word + * contains the number of workers that are (probably) executing + * tasks. This value is atomically incremented before a worker + * gets a task to run, and decremented when worker has no tasks + * and cannot find any. These two fields are bundled together to + * support correct termination triggering. Note: activeCount + * CAS'es cheat by assuming active count is in low word, so need + * to be modified if this changes + */ + private volatile int runControl; + + // RunState values. Order among values matters + private static final int RUNNING = 0; + private static final int SHUTDOWN = 1; + private static final int TERMINATING = 2; + private static final int TERMINATED = 3; + + private static int runStateOf(int c) { return c >>> 16; } + private static int activeCountOf(int c) { return c & shortMask; } + private static int runControlFor(int r, int a) { return (r << 16) + a; } + + /** + * Tries incrementing active count; fails on contention. + * Called by workers before/during executing tasks. + * + * @return true on success + */ + final boolean tryIncrementActiveCount() { + int c = runControl; + return casRunControl(c, c+1); + } + + /** + * Tries decrementing active count; fails on contention. + * Possibly triggers termination on success. + * Called by workers when they can't find tasks. + * + * @return true on success + */ + final boolean tryDecrementActiveCount() { + int c = runControl; + int nextc = c - 1; + if (!casRunControl(c, nextc)) + return false; + if (canTerminateOnShutdown(nextc)) + terminateOnShutdown(); + return true; + } + + /** + * Returns {@code true} if argument represents zero active count + * and nonzero runstate, which is the triggering condition for + * terminating on shutdown. + */ + private static boolean canTerminateOnShutdown(int c) { + // i.e. least bit is nonzero runState bit + return ((c & -c) >>> 16) != 0; + } + + /** + * Transition run state to at least the given state. Return true + * if not already at least given state. + */ + private boolean transitionRunStateTo(int state) { + for (;;) { + int c = runControl; + if (runStateOf(c) >= state) + return false; + if (casRunControl(c, runControlFor(state, activeCountOf(c)))) + return true; + } + } + + /** + * Controls whether to add spares to maintain parallelism + */ + private volatile boolean maintainsParallelism; + + // Constructors + + /** + * Creates a {@code ForkJoinPool} with parallelism equal to {@link + * java.lang.Runtime#availableProcessors}, and using the {@linkplain + * #defaultForkJoinWorkerThreadFactory default thread factory}. + * + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public ForkJoinPool() { + this(Runtime.getRuntime().availableProcessors(), + defaultForkJoinWorkerThreadFactory); + } + + /** + * Creates a {@code ForkJoinPool} with the indicated parallelism + * level and using the {@linkplain + * #defaultForkJoinWorkerThreadFactory default thread factory}. + * + * @param parallelism the parallelism level + * @throws IllegalArgumentException if parallelism less than or + * equal to zero, or greater than implementation limit + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public ForkJoinPool(int parallelism) { + this(parallelism, defaultForkJoinWorkerThreadFactory); + } + + /** + * Creates a {@code ForkJoinPool} with parallelism equal to {@link + * java.lang.Runtime#availableProcessors}, and using the given + * thread factory. + * + * @param factory the factory for creating new threads + * @throws NullPointerException if the factory is null + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public ForkJoinPool(ForkJoinWorkerThreadFactory factory) { + this(Runtime.getRuntime().availableProcessors(), factory); + } + + /** + * Creates a {@code ForkJoinPool} with the given parallelism and + * thread factory. + * + * @param parallelism the parallelism level + * @param factory the factory for creating new threads + * @throws IllegalArgumentException if parallelism less than or + * equal to zero, or greater than implementation limit + * @throws NullPointerException if the factory is null + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public ForkJoinPool(int parallelism, ForkJoinWorkerThreadFactory factory) { + if (parallelism <= 0 || parallelism > MAX_THREADS) + throw new IllegalArgumentException(); + if (factory == null) + throw new NullPointerException(); + checkPermission(); + this.factory = factory; + this.parallelism = parallelism; + this.maxPoolSize = MAX_THREADS; + this.maintainsParallelism = true; + this.poolNumber = poolNumberGenerator.incrementAndGet(); + this.workerLock = new ReentrantLock(); + this.termination = workerLock.newCondition(); + this.stealCount = new AtomicLong(); + this.submissionQueue = new LinkedTransferQueue<ForkJoinTask<?>>(); + // worker array and workers are lazily constructed + } + + /** + * Creates a new worker thread using factory. + * + * @param index the index to assign worker + * @return new worker, or null if factory failed + */ + private ForkJoinWorkerThread createWorker(int index) { + Thread.UncaughtExceptionHandler h = ueh; + ForkJoinWorkerThread w = factory.newThread(this); + if (w != null) { + w.poolIndex = index; + w.setDaemon(true); + w.setAsyncMode(locallyFifo); + w.setName("ForkJoinPool-" + poolNumber + "-worker-" + index); + if (h != null) + w.setUncaughtExceptionHandler(h); + } + return w; + } + + /** + * Returns a good size for worker array given pool size. + * Currently requires size to be a power of two. + */ + private static int arraySizeFor(int poolSize) { + if (poolSize <= 1) + return 1; + // See Hackers Delight, sec 3.2 + int c = poolSize >= MAX_THREADS ? MAX_THREADS : (poolSize - 1); + c |= c >>> 1; + c |= c >>> 2; + c |= c >>> 4; + c |= c >>> 8; + c |= c >>> 16; + return c + 1; + } + + /** + * Creates or resizes array if necessary to hold newLength. + * Call only under exclusion. + * + * @return the array + */ + private ForkJoinWorkerThread[] ensureWorkerArrayCapacity(int newLength) { + ForkJoinWorkerThread[] ws = workers; + if (ws == null) + return workers = new ForkJoinWorkerThread[arraySizeFor(newLength)]; + else if (newLength > ws.length) + return workers = Arrays.copyOf(ws, arraySizeFor(newLength)); + else + return ws; + } + + /** + * Tries to shrink workers into smaller array after one or more terminate. + */ + private void tryShrinkWorkerArray() { + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + int len = ws.length; + int last = len - 1; + while (last >= 0 && ws[last] == null) + --last; + int newLength = arraySizeFor(last+1); + if (newLength < len) + workers = Arrays.copyOf(ws, newLength); + } + } + + /** + * Initializes workers if necessary. + */ + final void ensureWorkerInitialization() { + ForkJoinWorkerThread[] ws = workers; + if (ws == null) { + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + ws = workers; + if (ws == null) { + int ps = parallelism; + ws = ensureWorkerArrayCapacity(ps); + for (int i = 0; i < ps; ++i) { + ForkJoinWorkerThread w = createWorker(i); + if (w != null) { + ws[i] = w; + w.start(); + updateWorkerCount(1); + } + } + } + } finally { + lock.unlock(); + } + } + } + + /** + * Worker creation and startup for threads added via setParallelism. + */ + private void createAndStartAddedWorkers() { + resumeAllSpares(); // Allow spares to convert to nonspare + int ps = parallelism; + ForkJoinWorkerThread[] ws = ensureWorkerArrayCapacity(ps); + int len = ws.length; + // Sweep through slots, to keep lowest indices most populated + int k = 0; + while (k < len) { + if (ws[k] != null) { + ++k; + continue; + } + int s = workerCounts; + int tc = totalCountOf(s); + int rc = runningCountOf(s); + if (rc >= ps || tc >= ps) + break; + if (casWorkerCounts (s, workerCountsFor(tc+1, rc+1))) { + ForkJoinWorkerThread w = createWorker(k); + if (w != null) { + ws[k++] = w; + w.start(); + } + else { + updateWorkerCount(-1); // back out on failed creation + break; + } + } + } + } + + // Execution methods + + /** + * Common code for execute, invoke and submit + */ + private <T> void doSubmit(ForkJoinTask<T> task) { + if (task == null) + throw new NullPointerException(); + if (isShutdown()) + throw new RejectedExecutionException(); + if (workers == null) + ensureWorkerInitialization(); + submissionQueue.offer(task); + signalIdleWorkers(); + } + + /** + * Performs the given task, returning its result upon completion. + * + * @param task the task + * @return the task's result + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public <T> T invoke(ForkJoinTask<T> task) { + doSubmit(task); + return task.join(); + } + + /** + * Arranges for (asynchronous) execution of the given task. + * + * @param task the task + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public void execute(ForkJoinTask<?> task) { + doSubmit(task); + } + + // AbstractExecutorService methods + + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public void execute(Runnable task) { + ForkJoinTask<?> job; + if (task instanceof ForkJoinTask<?>) // avoid re-wrap + job = (ForkJoinTask<?>) task; + else + job = ForkJoinTask.adapt(task, null); + doSubmit(job); + } + + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public <T> ForkJoinTask<T> submit(Callable<T> task) { + ForkJoinTask<T> job = ForkJoinTask.adapt(task); + doSubmit(job); + return job; + } + + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public <T> ForkJoinTask<T> submit(Runnable task, T result) { + ForkJoinTask<T> job = ForkJoinTask.adapt(task, result); + doSubmit(job); + return job; + } + + /** + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public ForkJoinTask<?> submit(Runnable task) { + ForkJoinTask<?> job; + if (task instanceof ForkJoinTask<?>) // avoid re-wrap + job = (ForkJoinTask<?>) task; + else + job = ForkJoinTask.adapt(task, null); + doSubmit(job); + return job; + } + + /** + * Submits a ForkJoinTask for execution. + * + * @param task the task to submit + * @return the task + * @throws NullPointerException if the task is null + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + */ + public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) { + doSubmit(task); + return task; + } + + + /** + * @throws NullPointerException {@inheritDoc} + * @throws RejectedExecutionException {@inheritDoc} + */ + public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) { + ArrayList<ForkJoinTask<T>> forkJoinTasks = + new ArrayList<ForkJoinTask<T>>(tasks.size()); + for (Callable<T> task : tasks) + forkJoinTasks.add(ForkJoinTask.adapt(task)); + invoke(new InvokeAll<T>(forkJoinTasks)); + + @SuppressWarnings({"unchecked", "rawtypes"}) + List<Future<T>> futures = (List<Future<T>>) (List) forkJoinTasks; + return futures; + } + + static final class InvokeAll<T> extends RecursiveAction { + final ArrayList<ForkJoinTask<T>> tasks; + InvokeAll(ArrayList<ForkJoinTask<T>> tasks) { this.tasks = tasks; } + public void compute() { + try { invokeAll(tasks); } + catch (Exception ignore) {} + } + private static final long serialVersionUID = -7914297376763021607L; + } + + // Configuration and status settings and queries + + /** + * Returns the factory used for constructing new workers. + * + * @return the factory used for constructing new workers + */ + public ForkJoinWorkerThreadFactory getFactory() { + return factory; + } + + /** + * Returns the handler for internal worker threads that terminate + * due to unrecoverable errors encountered while executing tasks. + * + * @return the handler, or {@code null} if none + */ + public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() { + Thread.UncaughtExceptionHandler h; + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + h = ueh; + } finally { + lock.unlock(); + } + return h; + } + + /** + * Sets the handler for internal worker threads that terminate due + * to unrecoverable errors encountered while executing tasks. + * Unless set, the current default or ThreadGroup handler is used + * as handler. + * + * @param h the new handler + * @return the old handler, or {@code null} if none + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public Thread.UncaughtExceptionHandler + setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler h) { + checkPermission(); + Thread.UncaughtExceptionHandler old = null; + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + old = ueh; + ueh = h; + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + for (int i = 0; i < ws.length; ++i) { + ForkJoinWorkerThread w = ws[i]; + if (w != null) + w.setUncaughtExceptionHandler(h); + } + } + } finally { + lock.unlock(); + } + return old; + } + + + /** + * Sets the target parallelism level of this pool. + * + * @param parallelism the target parallelism + * @throws IllegalArgumentException if parallelism less than or + * equal to zero or greater than maximum size bounds + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public void setParallelism(int parallelism) { + checkPermission(); + if (parallelism <= 0 || parallelism > maxPoolSize) + throw new IllegalArgumentException(); + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + if (isProcessingTasks()) { + int p = this.parallelism; + this.parallelism = parallelism; + if (parallelism > p) + createAndStartAddedWorkers(); + else + trimSpares(); + } + } finally { + lock.unlock(); + } + signalIdleWorkers(); + } + + /** + * Returns the targeted parallelism level of this pool. + * + * @return the targeted parallelism level of this pool + */ + public int getParallelism() { + return parallelism; + } + + /** + * Returns the number of worker threads that have started but not + * yet terminated. This result returned by this method may differ + * from {@link #getParallelism} when threads are created to + * maintain parallelism when others are cooperatively blocked. + * + * @return the number of worker threads + */ + public int getPoolSize() { + return totalCountOf(workerCounts); + } + + /** + * Returns the maximum number of threads allowed to exist in the + * pool. Unless set using {@link #setMaximumPoolSize}, the + * maximum is an implementation-defined value designed only to + * prevent runaway growth. + * + * @return the maximum + */ + public int getMaximumPoolSize() { + return maxPoolSize; + } + + /** + * Sets the maximum number of threads allowed to exist in the + * pool. The given value should normally be greater than or equal + * to the {@link #getParallelism parallelism} level. Setting this + * value has no effect on current pool size. It controls + * construction of new threads. + * + * @throws IllegalArgumentException if negative or greater than + * internal implementation limit + */ + public void setMaximumPoolSize(int newMax) { + if (newMax < 0 || newMax > MAX_THREADS) + throw new IllegalArgumentException(); + maxPoolSize = newMax; + } + + + /** + * Returns {@code true} if this pool dynamically maintains its + * target parallelism level. If false, new threads are added only + * to avoid possible starvation. This setting is by default true. + * + * @return {@code true} if maintains parallelism + */ + public boolean getMaintainsParallelism() { + return maintainsParallelism; + } + + /** + * Sets whether this pool dynamically maintains its target + * parallelism level. If false, new threads are added only to + * avoid possible starvation. + * + * @param enable {@code true} to maintain parallelism + */ + public void setMaintainsParallelism(boolean enable) { + maintainsParallelism = enable; + } + + /** + * Establishes local first-in-first-out scheduling mode for forked + * tasks that are never joined. This mode may be more appropriate + * than default locally stack-based mode in applications in which + * worker threads only process asynchronous tasks. This method is + * designed to be invoked only when the pool is quiescent, and + * typically only before any tasks are submitted. The effects of + * invocations at other times may be unpredictable. + * + * @param async if {@code true}, use locally FIFO scheduling + * @return the previous mode + * @see #getAsyncMode + */ + public boolean setAsyncMode(boolean async) { + boolean oldMode = locallyFifo; + locallyFifo = async; + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + for (int i = 0; i < ws.length; ++i) { + ForkJoinWorkerThread t = ws[i]; + if (t != null) + t.setAsyncMode(async); + } + } + return oldMode; + } + + /** + * Returns {@code true} if this pool uses local first-in-first-out + * scheduling mode for forked tasks that are never joined. + * + * @return {@code true} if this pool uses async mode + * @see #setAsyncMode + */ + public boolean getAsyncMode() { + return locallyFifo; + } + + /** + * Returns an estimate of the number of worker threads that are + * not blocked waiting to join tasks or for other managed + * synchronization. + * + * @return the number of worker threads + */ + public int getRunningThreadCount() { + return runningCountOf(workerCounts); + } + + /** + * Returns an estimate of the number of threads that are currently + * stealing or executing tasks. This method may overestimate the + * number of active threads. + * + * @return the number of active threads + */ + public int getActiveThreadCount() { + return activeCountOf(runControl); + } + + /** + * Returns an estimate of the number of threads that are currently + * idle waiting for tasks. This method may underestimate the + * number of idle threads. + * + * @return the number of idle threads + */ + final int getIdleThreadCount() { + int c = runningCountOf(workerCounts) - activeCountOf(runControl); + return (c <= 0) ? 0 : c; + } + + /** + * Returns {@code true} if all worker threads are currently idle. + * An idle worker is one that cannot obtain a task to execute + * because none are available to steal from other threads, and + * there are no pending submissions to the pool. This method is + * conservative; it might not return {@code true} immediately upon + * idleness of all threads, but will eventually become true if + * threads remain inactive. + * + * @return {@code true} if all threads are currently idle + */ + public boolean isQuiescent() { + return activeCountOf(runControl) == 0; + } + + /** + * Returns an estimate of the total number of tasks stolen from + * one thread's work queue by another. The reported value + * underestimates the actual total number of steals when the pool + * is not quiescent. This value may be useful for monitoring and + * tuning fork/join programs: in general, steal counts should be + * high enough to keep threads busy, but low enough to avoid + * overhead and contention across threads. + * + * @return the number of steals + */ + public long getStealCount() { + return stealCount.get(); + } + + /** + * Accumulates steal count from a worker. + * Call only when worker known to be idle. + */ + private void updateStealCount(ForkJoinWorkerThread w) { + int sc = w.getAndClearStealCount(); + if (sc != 0) + stealCount.addAndGet(sc); + } + + /** + * Returns an estimate of the total number of tasks currently held + * in queues by worker threads (but not including tasks submitted + * to the pool that have not begun executing). This value is only + * an approximation, obtained by iterating across all threads in + * the pool. This method may be useful for tuning task + * granularities. + * + * @return the number of queued tasks + */ + public long getQueuedTaskCount() { + long count = 0; + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + for (int i = 0; i < ws.length; ++i) { + ForkJoinWorkerThread t = ws[i]; + if (t != null) + count += t.getQueueSize(); + } + } + return count; + } + + /** + * Returns an estimate of the number of tasks submitted to this + * pool that have not yet begun executing. This method takes time + * proportional to the number of submissions. + * + * @return the number of queued submissions + */ + public int getQueuedSubmissionCount() { + return submissionQueue.size(); + } + + /** + * Returns {@code true} if there are any tasks submitted to this + * pool that have not yet begun executing. + * + * @return {@code true} if there are any queued submissions + */ + public boolean hasQueuedSubmissions() { + return !submissionQueue.isEmpty(); + } + + /** + * Removes and returns the next unexecuted submission if one is + * available. This method may be useful in extensions to this + * class that re-assign work in systems with multiple pools. + * + * @return the next submission, or {@code null} if none + */ + protected ForkJoinTask<?> pollSubmission() { + return submissionQueue.poll(); + } + + /** + * Removes all available unexecuted submitted and forked tasks + * from scheduling queues and adds them to the given collection, + * without altering their execution status. These may include + * artificially generated or wrapped tasks. This method is + * designed to be invoked only when the pool is known to be + * quiescent. Invocations at other times may not remove all + * tasks. A failure encountered while attempting to add elements + * to collection {@code c} may result in elements being in + * neither, either or both collections when the associated + * exception is thrown. The behavior of this operation is + * undefined if the specified collection is modified while the + * operation is in progress. + * + * @param c the collection to transfer elements into + * @return the number of elements transferred + */ + protected int drainTasksTo(Collection<? super ForkJoinTask<?>> c) { + int n = submissionQueue.drainTo(c); + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + for (int i = 0; i < ws.length; ++i) { + ForkJoinWorkerThread w = ws[i]; + if (w != null) + n += w.drainTasksTo(c); + } + } + return n; + } + + /** + * Returns a string identifying this pool, as well as its state, + * including indications of run state, parallelism level, and + * worker and task counts. + * + * @return a string identifying this pool, as well as its state + */ + public String toString() { + int ps = parallelism; + int wc = workerCounts; + int rc = runControl; + long st = getStealCount(); + long qt = getQueuedTaskCount(); + long qs = getQueuedSubmissionCount(); + return super.toString() + + "[" + runStateToString(runStateOf(rc)) + + ", parallelism = " + ps + + ", size = " + totalCountOf(wc) + + ", active = " + activeCountOf(rc) + + ", running = " + runningCountOf(wc) + + ", steals = " + st + + ", tasks = " + qt + + ", submissions = " + qs + + "]"; + } + + private static String runStateToString(int rs) { + switch(rs) { + case RUNNING: return "Running"; + case SHUTDOWN: return "Shutting down"; + case TERMINATING: return "Terminating"; + case TERMINATED: return "Terminated"; + default: throw new Error("Unknown run state"); + } + } + + // lifecycle control + + /** + * Initiates an orderly shutdown in which previously submitted + * tasks are executed, but no new tasks will be accepted. + * Invocation has no additional effect if already shut down. + * Tasks that are in the process of being submitted concurrently + * during the course of this method may or may not be rejected. + * + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public void shutdown() { + checkPermission(); + transitionRunStateTo(SHUTDOWN); + if (canTerminateOnShutdown(runControl)) { + if (workers == null) { // shutting down before workers created + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + if (workers == null) { + terminate(); + transitionRunStateTo(TERMINATED); + termination.signalAll(); + } + } finally { + lock.unlock(); + } + } + terminateOnShutdown(); + } + } + + /** + * Attempts to cancel and/or stop all tasks, and reject all + * subsequently submitted tasks. Tasks that are in the process of + * being submitted or executed concurrently during the course of + * this method may or may not be rejected. This method cancels + * both existing and unexecuted tasks, in order to permit + * termination in the presence of task dependencies. So the method + * always returns an empty list (unlike the case for some other + * Executors). + * + * @return an empty list + * @throws SecurityException if a security manager exists and + * the caller is not permitted to modify threads + * because it does not hold {@link + * java.lang.RuntimePermission}{@code ("modifyThread")} + */ + public List<Runnable> shutdownNow() { + checkPermission(); + terminate(); + return Collections.emptyList(); + } + + /** + * Returns {@code true} if all tasks have completed following shut down. + * + * @return {@code true} if all tasks have completed following shut down + */ + public boolean isTerminated() { + return runStateOf(runControl) == TERMINATED; + } + + /** + * Returns {@code true} if the process of termination has + * commenced but not yet completed. This method may be useful for + * debugging. A return of {@code true} reported a sufficient + * period after shutdown may indicate that submitted tasks have + * ignored or suppressed interruption, causing this executor not + * to properly terminate. + * + * @return {@code true} if terminating but not yet terminated + */ + public boolean isTerminating() { + return runStateOf(runControl) == TERMINATING; + } + + /** + * Returns {@code true} if this pool has been shut down. + * + * @return {@code true} if this pool has been shut down + */ + public boolean isShutdown() { + return runStateOf(runControl) >= SHUTDOWN; + } + + /** + * Returns true if pool is not terminating or terminated. + * Used internally to suppress execution when terminating. + */ + final boolean isProcessingTasks() { + return runStateOf(runControl) < TERMINATING; + } + + /** + * Blocks until all tasks have completed execution after a shutdown + * request, or the timeout occurs, or the current thread is + * interrupted, whichever happens first. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return {@code true} if this executor terminated and + * {@code false} if the timeout elapsed before termination + * @throws InterruptedException if interrupted while waiting + */ + public boolean awaitTermination(long timeout, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + for (;;) { + if (isTerminated()) + return true; + if (nanos <= 0) + return false; + nanos = termination.awaitNanos(nanos); + } + } finally { + lock.unlock(); + } + } + + // Shutdown and termination support + + /** + * Callback from terminating worker. Nulls out the corresponding + * workers slot, and if terminating, tries to terminate; else + * tries to shrink workers array. + * + * @param w the worker + */ + final void workerTerminated(ForkJoinWorkerThread w) { + updateStealCount(w); + updateWorkerCount(-1); + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + int idx = w.poolIndex; + if (idx >= 0 && idx < ws.length && ws[idx] == w) + ws[idx] = null; + if (totalCountOf(workerCounts) == 0) { + terminate(); // no-op if already terminating + transitionRunStateTo(TERMINATED); + termination.signalAll(); + } + else if (isProcessingTasks()) { + tryShrinkWorkerArray(); + tryResumeSpare(true); // allow replacement + } + } + } finally { + lock.unlock(); + } + signalIdleWorkers(); + } + + /** + * Initiates termination. + */ + private void terminate() { + if (transitionRunStateTo(TERMINATING)) { + stopAllWorkers(); + resumeAllSpares(); + signalIdleWorkers(); + cancelQueuedSubmissions(); + cancelQueuedWorkerTasks(); + interruptUnterminatedWorkers(); + signalIdleWorkers(); // resignal after interrupt + } + } + + /** + * Possibly terminates when on shutdown state. + */ + private void terminateOnShutdown() { + if (!hasQueuedSubmissions() && canTerminateOnShutdown(runControl)) + terminate(); + } + + /** + * Clears out and cancels submissions. + */ + private void cancelQueuedSubmissions() { + ForkJoinTask<?> task; + while ((task = pollSubmission()) != null) + task.cancel(false); + } + + /** + * Cleans out worker queues. + */ + private void cancelQueuedWorkerTasks() { + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + for (int i = 0; i < ws.length; ++i) { + ForkJoinWorkerThread t = ws[i]; + if (t != null) + t.cancelTasks(); + } + } + } finally { + lock.unlock(); + } + } + + /** + * Sets each worker's status to terminating. Requires lock to avoid + * conflicts with add/remove. + */ + private void stopAllWorkers() { + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + for (int i = 0; i < ws.length; ++i) { + ForkJoinWorkerThread t = ws[i]; + if (t != null) + t.shutdownNow(); + } + } + } finally { + lock.unlock(); + } + } + + /** + * Interrupts all unterminated workers. This is not required for + * sake of internal control, but may help unstick user code during + * shutdown. + */ + private void interruptUnterminatedWorkers() { + final ReentrantLock lock = this.workerLock; + lock.lock(); + try { + ForkJoinWorkerThread[] ws = workers; + if (ws != null) { + for (int i = 0; i < ws.length; ++i) { + ForkJoinWorkerThread t = ws[i]; + if (t != null && !t.isTerminated()) { + try { + t.interrupt(); + } catch (SecurityException ignore) { + } + } + } + } + } finally { + lock.unlock(); + } + } + + + /* + * Nodes for event barrier to manage idle threads. Queue nodes + * are basic Treiber stack nodes, also used for spare stack. + * + * The event barrier has an event count and a wait queue (actually + * a Treiber stack). Workers are enabled to look for work when + * the eventCount is incremented. If they fail to find work, they + * may wait for next count. Upon release, threads help others wake + * up. + * + * Synchronization events occur only in enough contexts to + * maintain overall liveness: + * + * - Submission of a new task to the pool + * - Resizes or other changes to the workers array + * - pool termination + * - A worker pushing a task on an empty queue + * + * The case of pushing a task occurs often enough, and is heavy + * enough compared to simple stack pushes, to require special + * handling: Method signalWork returns without advancing count if + * the queue appears to be empty. This would ordinarily result in + * races causing some queued waiters not to be woken up. To avoid + * this, the first worker enqueued in method sync (see + * syncIsReleasable) rescans for tasks after being enqueued, and + * helps signal if any are found. This works well because the + * worker has nothing better to do, and so might as well help + * alleviate the overhead and contention on the threads actually + * doing work. Also, since event counts increments on task + * availability exist to maintain liveness (rather than to force + * refreshes etc), it is OK for callers to exit early if + * contending with another signaller. + */ + static final class WaitQueueNode { + WaitQueueNode next; // only written before enqueued + volatile ForkJoinWorkerThread thread; // nulled to cancel wait + final long count; // unused for spare stack + + WaitQueueNode(long c, ForkJoinWorkerThread w) { + count = c; + thread = w; + } + + /** + * Wakes up waiter, returning false if known to already + */ + boolean signal() { + ForkJoinWorkerThread t = thread; + if (t == null) + return false; + thread = null; + LockSupport.unpark(t); + return true; + } + + /** + * Awaits release on sync. + */ + void awaitSyncRelease(ForkJoinPool p) { + while (thread != null && !p.syncIsReleasable(this)) + LockSupport.park(this); + } + + /** + * Awaits resumption as spare. + */ + void awaitSpareRelease() { + while (thread != null) { + if (!Thread.interrupted()) + LockSupport.park(this); + } + } + } + + /** + * Ensures that no thread is waiting for count to advance from the + * current value of eventCount read on entry to this method, by + * releasing waiting threads if necessary. + * + * @return the count + */ + final long ensureSync() { + long c = eventCount; + WaitQueueNode q; + while ((q = syncStack) != null && q.count < c) { + if (casBarrierStack(q, null)) { + do { + q.signal(); + } while ((q = q.next) != null); + break; + } + } + return c; + } + + /** + * Increments event count and releases waiting threads. + */ + private void signalIdleWorkers() { + long c; + do {} while (!casEventCount(c = eventCount, c+1)); + ensureSync(); + } + + /** + * Signals threads waiting to poll a task. Because method sync + * rechecks availability, it is OK to only proceed if queue + * appears to be non-empty, and OK to skip under contention to + * increment count (since some other thread succeeded). + */ + final void signalWork() { + long c; + WaitQueueNode q; + if (syncStack != null && + casEventCount(c = eventCount, c+1) && + (((q = syncStack) != null && q.count <= c) && + (!casBarrierStack(q, q.next) || !q.signal()))) + ensureSync(); + } + + /** + * Waits until event count advances from last value held by + * caller, or if excess threads, caller is resumed as spare, or + * caller or pool is terminating. Updates caller's event on exit. + * + * @param w the calling worker thread + */ + final void sync(ForkJoinWorkerThread w) { + updateStealCount(w); // Transfer w's count while it is idle + + while (!w.isShutdown() && isProcessingTasks() && !suspendIfSpare(w)) { + long prev = w.lastEventCount; + WaitQueueNode node = null; + WaitQueueNode h; + while (eventCount == prev && + ((h = syncStack) == null || h.count == prev)) { + if (node == null) + node = new WaitQueueNode(prev, w); + if (casBarrierStack(node.next = h, node)) { + node.awaitSyncRelease(this); + break; + } + } + long ec = ensureSync(); + if (ec != prev) { + w.lastEventCount = ec; + break; + } + } + } + + /** + * Returns {@code true} if worker waiting on sync can proceed: + * - on signal (thread == null) + * - on event count advance (winning race to notify vs signaller) + * - on interrupt + * - if the first queued node, we find work available + * If node was not signalled and event count not advanced on exit, + * then we also help advance event count. + * + * @return {@code true} if node can be released + */ + final boolean syncIsReleasable(WaitQueueNode node) { + long prev = node.count; + if (!Thread.interrupted() && node.thread != null && + (node.next != null || + !ForkJoinWorkerThread.hasQueuedTasks(workers)) && + eventCount == prev) + return false; + if (node.thread != null) { + node.thread = null; + long ec = eventCount; + if (prev <= ec) // help signal + casEventCount(ec, ec+1); + } + return true; + } + + /** + * Returns {@code true} if a new sync event occurred since last + * call to sync or this method, if so, updating caller's count. + */ + final boolean hasNewSyncEvent(ForkJoinWorkerThread w) { + long lc = w.lastEventCount; + long ec = ensureSync(); + if (ec == lc) + return false; + w.lastEventCount = ec; + return true; + } + + // Parallelism maintenance + + /** + * Decrements running count; if too low, adds spare. + * + * Conceptually, all we need to do here is add or resume a + * spare thread when one is about to block (and remove or + * suspend it later when unblocked -- see suspendIfSpare). + * However, implementing this idea requires coping with + * several problems: we have imperfect information about the + * states of threads. Some count updates can and usually do + * lag run state changes, despite arrangements to keep them + * accurate (for example, when possible, updating counts + * before signalling or resuming), especially when running on + * dynamic JVMs that don't optimize the infrequent paths that + * update counts. Generating too many threads can make these + * problems become worse, because excess threads are more + * likely to be context-switched with others, slowing them all + * down, especially if there is no work available, so all are + * busy scanning or idling. Also, excess spare threads can + * only be suspended or removed when they are idle, not + * immediately when they aren't needed. So adding threads will + * raise parallelism level for longer than necessary. Also, + * FJ applications often encounter highly transient peaks when + * many threads are blocked joining, but for less time than it + * takes to create or resume spares. + * + * @param joinMe if non-null, return early if done + * @param maintainParallelism if true, try to stay within + * target counts, else create only to avoid starvation + * @return true if joinMe known to be done + */ + final boolean preJoin(ForkJoinTask<?> joinMe, + boolean maintainParallelism) { + maintainParallelism &= maintainsParallelism; // overrride + boolean dec = false; // true when running count decremented + while (spareStack == null || !tryResumeSpare(dec)) { + int counts = workerCounts; + if (dec || (dec = casWorkerCounts(counts, --counts))) { + if (!needSpare(counts, maintainParallelism)) + break; + if (joinMe.status < 0) + return true; + if (tryAddSpare(counts)) + break; + } + } + return false; + } + + /** + * Same idea as preJoin + */ + final boolean preBlock(ManagedBlocker blocker, + boolean maintainParallelism) { + maintainParallelism &= maintainsParallelism; + boolean dec = false; + while (spareStack == null || !tryResumeSpare(dec)) { + int counts = workerCounts; + if (dec || (dec = casWorkerCounts(counts, --counts))) { + if (!needSpare(counts, maintainParallelism)) + break; + if (blocker.isReleasable()) + return true; + if (tryAddSpare(counts)) + break; + } + } + return false; + } + + /** + * Returns {@code true} if a spare thread appears to be needed. + * If maintaining parallelism, returns true when the deficit in + * running threads is more than the surplus of total threads, and + * there is apparently some work to do. This self-limiting rule + * means that the more threads that have already been added, the + * less parallelism we will tolerate before adding another. + * + * @param counts current worker counts + * @param maintainParallelism try to maintain parallelism + */ + private boolean needSpare(int counts, boolean maintainParallelism) { + int ps = parallelism; + int rc = runningCountOf(counts); + int tc = totalCountOf(counts); + int runningDeficit = ps - rc; + int totalSurplus = tc - ps; + return (tc < maxPoolSize && + (rc == 0 || totalSurplus < 0 || + (maintainParallelism && + runningDeficit > totalSurplus && + ForkJoinWorkerThread.hasQueuedTasks(workers)))); + } + + /** + * Adds a spare worker if lock available and no more than the + * expected numbers of threads exist. + * + * @return true if successful + */ + private boolean tryAddSpare(int expectedCounts) { + final ReentrantLock lock = this.workerLock; + int expectedRunning = runningCountOf(expectedCounts); + int expectedTotal = totalCountOf(expectedCounts); + boolean success = false; + boolean locked = false; + // confirm counts while locking; CAS after obtaining lock + try { + for (;;) { + int s = workerCounts; + int tc = totalCountOf(s); + int rc = runningCountOf(s); + if (rc > expectedRunning || tc > expectedTotal) + break; + if (!locked && !(locked = lock.tryLock())) + break; + if (casWorkerCounts(s, workerCountsFor(tc+1, rc+1))) { + createAndStartSpare(tc); + success = true; + break; + } + } + } finally { + if (locked) + lock.unlock(); + } + return success; + } + + /** + * Adds the kth spare worker. On entry, pool counts are already + * adjusted to reflect addition. + */ + private void createAndStartSpare(int k) { + ForkJoinWorkerThread w = null; + ForkJoinWorkerThread[] ws = ensureWorkerArrayCapacity(k + 1); + int len = ws.length; + // Probably, we can place at slot k. If not, find empty slot + if (k < len && ws[k] != null) { + for (k = 0; k < len && ws[k] != null; ++k) + ; + } + if (k < len && isProcessingTasks() && (w = createWorker(k)) != null) { + ws[k] = w; + w.start(); + } + else + updateWorkerCount(-1); // adjust on failure + signalIdleWorkers(); + } + + /** + * Suspends calling thread w if there are excess threads. Called + * only from sync. Spares are enqueued in a Treiber stack using + * the same WaitQueueNodes as barriers. They are resumed mainly + * in preJoin, but are also woken on pool events that require all + * threads to check run state. + * + * @param w the caller + */ + private boolean suspendIfSpare(ForkJoinWorkerThread w) { + WaitQueueNode node = null; + int s; + while (parallelism < runningCountOf(s = workerCounts)) { + if (node == null) + node = new WaitQueueNode(0, w); + if (casWorkerCounts(s, s-1)) { // representation-dependent + // push onto stack + do {} while (!casSpareStack(node.next = spareStack, node)); + // block until released by resumeSpare + node.awaitSpareRelease(); + return true; + } + } + return false; + } + + /** + * Tries to pop and resume a spare thread. + * + * @param updateCount if true, increment running count on success + * @return true if successful + */ + private boolean tryResumeSpare(boolean updateCount) { + WaitQueueNode q; + while ((q = spareStack) != null) { + if (casSpareStack(q, q.next)) { + if (updateCount) + updateRunningCount(1); + q.signal(); + return true; + } + } + return false; + } + + /** + * Pops and resumes all spare threads. Same idea as ensureSync. + * + * @return true if any spares released + */ + private boolean resumeAllSpares() { + WaitQueueNode q; + while ( (q = spareStack) != null) { + if (casSpareStack(q, null)) { + do { + updateRunningCount(1); + q.signal(); + } while ((q = q.next) != null); + return true; + } + } + return false; + } + + /** + * Pops and shuts down excessive spare threads. Call only while + * holding lock. This is not guaranteed to eliminate all excess + * threads, only those suspended as spares, which are the ones + * unlikely to be needed in the future. + */ + private void trimSpares() { + int surplus = totalCountOf(workerCounts) - parallelism; + WaitQueueNode q; + while (surplus > 0 && (q = spareStack) != null) { + if (casSpareStack(q, null)) { + do { + updateRunningCount(1); + ForkJoinWorkerThread w = q.thread; + if (w != null && surplus > 0 && + runningCountOf(workerCounts) > 0 && w.shutdown()) + --surplus; + q.signal(); + } while ((q = q.next) != null); + } + } + } + + /** + * Interface for extending managed parallelism for tasks running + * in {@link ForkJoinPool}s. + * + * <p>A {@code ManagedBlocker} provides two methods. + * Method {@code isReleasable} must return {@code true} if + * blocking is not necessary. Method {@code block} blocks the + * current thread if necessary (perhaps internally invoking + * {@code isReleasable} before actually blocking). + * + * <p>For example, here is a ManagedBlocker based on a + * ReentrantLock: + * <pre> {@code + * class ManagedLocker implements ManagedBlocker { + * final ReentrantLock lock; + * boolean hasLock = false; + * ManagedLocker(ReentrantLock lock) { this.lock = lock; } + * public boolean block() { + * if (!hasLock) + * lock.lock(); + * return true; + * } + * public boolean isReleasable() { + * return hasLock || (hasLock = lock.tryLock()); + * } + * }}</pre> + */ + public static interface ManagedBlocker { + /** + * Possibly blocks the current thread, for example waiting for + * a lock or condition. + * + * @return {@code true} if no additional blocking is necessary + * (i.e., if isReleasable would return true) + * @throws InterruptedException if interrupted while waiting + * (the method is not required to do so, but is allowed to) + */ + boolean block() throws InterruptedException; + + /** + * Returns {@code true} if blocking is unnecessary. + */ + boolean isReleasable(); + } + + /** + * Blocks in accord with the given blocker. If the current thread + * is a {@link ForkJoinWorkerThread}, this method possibly + * arranges for a spare thread to be activated if necessary to + * ensure parallelism while the current thread is blocked. + * + * <p>If {@code maintainParallelism} is {@code true} and the pool + * supports it ({@link #getMaintainsParallelism}), this method + * attempts to maintain the pool's nominal parallelism. Otherwise + * it activates a thread only if necessary to avoid complete + * starvation. This option may be preferable when blockages use + * timeouts, or are almost always brief. + * + * <p>If the caller is not a {@link ForkJoinTask}, this method is + * behaviorally equivalent to + * <pre> {@code + * while (!blocker.isReleasable()) + * if (blocker.block()) + * return; + * }</pre> + * + * If the caller is a {@code ForkJoinTask}, then the pool may + * first be expanded to ensure parallelism, and later adjusted. + * + * @param blocker the blocker + * @param maintainParallelism if {@code true} and supported by + * this pool, attempt to maintain the pool's nominal parallelism; + * otherwise activate a thread only if necessary to avoid + * complete starvation. + * @throws InterruptedException if blocker.block did so + */ + public static void managedBlock(ManagedBlocker blocker, + boolean maintainParallelism) + throws InterruptedException { + Thread t = Thread.currentThread(); + ForkJoinPool pool = ((t instanceof ForkJoinWorkerThread) ? + ((ForkJoinWorkerThread) t).pool : null); + if (!blocker.isReleasable()) { + try { + if (pool == null || + !pool.preBlock(blocker, maintainParallelism)) + awaitBlocker(blocker); + } finally { + if (pool != null) + pool.updateRunningCount(1); + } + } + } + + private static void awaitBlocker(ManagedBlocker blocker) + throws InterruptedException { + do {} while (!blocker.isReleasable() && !blocker.block()); + } + + // AbstractExecutorService overrides. These rely on undocumented + // fact that ForkJoinTask.adapt returns ForkJoinTasks that also + // implement RunnableFuture. + + protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { + return (RunnableFuture<T>) ForkJoinTask.adapt(runnable, value); + } + + protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { + return (RunnableFuture<T>) ForkJoinTask.adapt(callable); + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + private static final long eventCountOffset = + objectFieldOffset("eventCount", ForkJoinPool.class); + private static final long workerCountsOffset = + objectFieldOffset("workerCounts", ForkJoinPool.class); + private static final long runControlOffset = + objectFieldOffset("runControl", ForkJoinPool.class); + private static final long syncStackOffset = + objectFieldOffset("syncStack",ForkJoinPool.class); + private static final long spareStackOffset = + objectFieldOffset("spareStack", ForkJoinPool.class); + + private boolean casEventCount(long cmp, long val) { + return UNSAFE.compareAndSwapLong(this, eventCountOffset, cmp, val); + } + private boolean casWorkerCounts(int cmp, int val) { + return UNSAFE.compareAndSwapInt(this, workerCountsOffset, cmp, val); + } + private boolean casRunControl(int cmp, int val) { + return UNSAFE.compareAndSwapInt(this, runControlOffset, cmp, val); + } + private boolean casSpareStack(WaitQueueNode cmp, WaitQueueNode val) { + return UNSAFE.compareAndSwapObject(this, spareStackOffset, cmp, val); + } + private boolean casBarrierStack(WaitQueueNode cmp, WaitQueueNode val) { + return UNSAFE.compareAndSwapObject(this, syncStackOffset, cmp, val); + } + + private static long objectFieldOffset(String field, Class<?> klazz) { + try { + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/util/concurrent/ForkJoinTask.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,1292 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.RandomAccess; +import java.util.Map; +import java.util.WeakHashMap; + +/** + * Abstract base class for tasks that run within a {@link ForkJoinPool}. + * A {@code ForkJoinTask} is a thread-like entity that is much + * lighter weight than a normal thread. Huge numbers of tasks and + * subtasks may be hosted by a small number of actual threads in a + * ForkJoinPool, at the price of some usage limitations. + * + * <p>A "main" {@code ForkJoinTask} begins execution when submitted + * to a {@link ForkJoinPool}. Once started, it will usually in turn + * start other subtasks. As indicated by the name of this class, + * many programs using {@code ForkJoinTask} employ only methods + * {@link #fork} and {@link #join}, or derivatives such as {@link + * #invokeAll}. However, this class also provides a number of other + * methods that can come into play in advanced usages, as well as + * extension mechanics that allow support of new forms of fork/join + * processing. + * + * <p>A {@code ForkJoinTask} is a lightweight form of {@link Future}. + * The efficiency of {@code ForkJoinTask}s stems from a set of + * restrictions (that are only partially statically enforceable) + * reflecting their intended use as computational tasks calculating + * pure functions or operating on purely isolated objects. The + * primary coordination mechanisms are {@link #fork}, that arranges + * asynchronous execution, and {@link #join}, that doesn't proceed + * until the task's result has been computed. Computations should + * avoid {@code synchronized} methods or blocks, and should minimize + * other blocking synchronization apart from joining other tasks or + * using synchronizers such as Phasers that are advertised to + * cooperate with fork/join scheduling. Tasks should also not perform + * blocking IO, and should ideally access variables that are + * completely independent of those accessed by other running + * tasks. Minor breaches of these restrictions, for example using + * shared output streams, may be tolerable in practice, but frequent + * use may result in poor performance, and the potential to + * indefinitely stall if the number of threads not waiting for IO or + * other external synchronization becomes exhausted. This usage + * restriction is in part enforced by not permitting checked + * exceptions such as {@code IOExceptions} to be thrown. However, + * computations may still encounter unchecked exceptions, that are + * rethrown to callers attempting to join them. These exceptions may + * additionally include {@link RejectedExecutionException} stemming + * from internal resource exhaustion, such as failure to allocate + * internal task queues. + * + * <p>The primary method for awaiting completion and extracting + * results of a task is {@link #join}, but there are several variants: + * The {@link Future#get} methods support interruptible and/or timed + * waits for completion and report results using {@code Future} + * conventions. Method {@link #helpJoin} enables callers to actively + * execute other tasks while awaiting joins, which is sometimes more + * efficient but only applies when all subtasks are known to be + * strictly tree-structured. Method {@link #invoke} is semantically + * equivalent to {@code fork(); join()} but always attempts to begin + * execution in the current thread. The "<em>quiet</em>" forms of + * these methods do not extract results or report exceptions. These + * may be useful when a set of tasks are being executed, and you need + * to delay processing of results or exceptions until all complete. + * Method {@code invokeAll} (available in multiple versions) + * performs the most common form of parallel invocation: forking a set + * of tasks and joining them all. + * + * <p>The execution status of tasks may be queried at several levels + * of detail: {@link #isDone} is true if a task completed in any way + * (including the case where a task was cancelled without executing); + * {@link #isCompletedNormally} is true if a task completed without + * cancellation or encountering an exception; {@link #isCancelled} is + * true if the task was cancelled (in which case {@link #getException} + * returns a {@link java.util.concurrent.CancellationException}); and + * {@link #isCompletedAbnormally} is true if a task was either + * cancelled or encountered an exception, in which case {@link + * #getException} will return either the encountered exception or + * {@link java.util.concurrent.CancellationException}. + * + * <p>The ForkJoinTask class is not usually directly subclassed. + * Instead, you subclass one of the abstract classes that support a + * particular style of fork/join processing, typically {@link + * RecursiveAction} for computations that do not return results, or + * {@link RecursiveTask} for those that do. Normally, a concrete + * ForkJoinTask subclass declares fields comprising its parameters, + * established in a constructor, and then defines a {@code compute} + * method that somehow uses the control methods supplied by this base + * class. While these methods have {@code public} access (to allow + * instances of different task subclasses to call each other's + * methods), some of them may only be called from within other + * ForkJoinTasks (as may be determined using method {@link + * #inForkJoinPool}). Attempts to invoke them in other contexts + * result in exceptions or errors, possibly including + * ClassCastException. + * + * <p>Most base support methods are {@code final}, to prevent + * overriding of implementations that are intrinsically tied to the + * underlying lightweight task scheduling framework. Developers + * creating new basic styles of fork/join processing should minimally + * implement {@code protected} methods {@link #exec}, {@link + * #setRawResult}, and {@link #getRawResult}, while also introducing + * an abstract computational method that can be implemented in its + * subclasses, possibly relying on other {@code protected} methods + * provided by this class. + * + * <p>ForkJoinTasks should perform relatively small amounts of + * computation. Large tasks should be split into smaller subtasks, + * usually via recursive decomposition. As a very rough rule of thumb, + * a task should perform more than 100 and less than 10000 basic + * computational steps. If tasks are too big, then parallelism cannot + * improve throughput. If too small, then memory and internal task + * maintenance overhead may overwhelm processing. + * + * <p>This class provides {@code adapt} methods for {@link Runnable} + * and {@link Callable}, that may be of use when mixing execution of + * {@code ForkJoinTasks} with other kinds of tasks. When all tasks + * are of this form, consider using a pool in + * {@linkplain ForkJoinPool#setAsyncMode async mode}. + * + * <p>ForkJoinTasks are {@code Serializable}, which enables them to be + * used in extensions such as remote execution frameworks. It is + * sensible to serialize tasks only before or after, but not during, + * execution. Serialization is not relied on during execution itself. + * + * @since 1.7 + * @author Doug Lea + */ +public abstract class ForkJoinTask<V> implements Future<V>, Serializable { + + /** + * Run control status bits packed into a single int to minimize + * footprint and to ensure atomicity (via CAS). Status is + * initially zero, and takes on nonnegative values until + * completed, upon which status holds COMPLETED. CANCELLED, or + * EXCEPTIONAL, which use the top 3 bits. Tasks undergoing + * blocking waits by other threads have SIGNAL_MASK bits set -- + * bit 15 for external (nonFJ) waits, and the rest a count of + * waiting FJ threads. (This representation relies on + * ForkJoinPool max thread limits). Completion of a stolen task + * with SIGNAL_MASK bits set awakens waiter via notifyAll. Even + * though suboptimal for some purposes, we use basic builtin + * wait/notify to take advantage of "monitor inflation" in JVMs + * that we would otherwise need to emulate to avoid adding further + * per-task bookkeeping overhead. Note that bits 16-28 are + * currently unused. Also value 0x80000000 is available as spare + * completion value. + */ + volatile int status; // accessed directly by pool and workers + + static final int COMPLETION_MASK = 0xe0000000; + static final int NORMAL = 0xe0000000; // == mask + static final int CANCELLED = 0xc0000000; + static final int EXCEPTIONAL = 0xa0000000; + static final int SIGNAL_MASK = 0x0000ffff; + static final int INTERNAL_SIGNAL_MASK = 0x00007fff; + static final int EXTERNAL_SIGNAL = 0x00008000; // top bit of low word + + /** + * Table of exceptions thrown by tasks, to enable reporting by + * callers. Because exceptions are rare, we don't directly keep + * them with task objects, but instead use a weak ref table. Note + * that cancellation exceptions don't appear in the table, but are + * instead recorded as status values. + * TODO: Use ConcurrentReferenceHashMap + */ + static final Map<ForkJoinTask<?>, Throwable> exceptionMap = + Collections.synchronizedMap + (new WeakHashMap<ForkJoinTask<?>, Throwable>()); + + // within-package utilities + + /** + * Gets current worker thread, or null if not a worker thread. + */ + static ForkJoinWorkerThread getWorker() { + Thread t = Thread.currentThread(); + return ((t instanceof ForkJoinWorkerThread) ? + (ForkJoinWorkerThread) t : null); + } + + final boolean casStatus(int cmp, int val) { + return UNSAFE.compareAndSwapInt(this, statusOffset, cmp, val); + } + + /** + * Workaround for not being able to rethrow unchecked exceptions. + */ + static void rethrowException(Throwable ex) { + if (ex != null) + UNSAFE.throwException(ex); + } + + // Setting completion status + + /** + * Marks completion and wakes up threads waiting to join this task. + * + * @param completion one of NORMAL, CANCELLED, EXCEPTIONAL + */ + final void setCompletion(int completion) { + ForkJoinPool pool = getPool(); + if (pool != null) { + int s; // Clear signal bits while setting completion status + do {} while ((s = status) >= 0 && !casStatus(s, completion)); + + if ((s & SIGNAL_MASK) != 0) { + if ((s &= INTERNAL_SIGNAL_MASK) != 0) + pool.updateRunningCount(s); + synchronized (this) { notifyAll(); } + } + } + else + externallySetCompletion(completion); + } + + /** + * Version of setCompletion for non-FJ threads. Leaves signal + * bits for unblocked threads to adjust, and always notifies. + */ + private void externallySetCompletion(int completion) { + int s; + do {} while ((s = status) >= 0 && + !casStatus(s, (s & SIGNAL_MASK) | completion)); + synchronized (this) { notifyAll(); } + } + + /** + * Sets status to indicate normal completion. + */ + final void setNormalCompletion() { + // Try typical fast case -- single CAS, no signal, not already done. + // Manually expand casStatus to improve chances of inlining it + if (!UNSAFE.compareAndSwapInt(this, statusOffset, 0, NORMAL)) + setCompletion(NORMAL); + } + + // internal waiting and notification + + /** + * Performs the actual monitor wait for awaitDone. + */ + private void doAwaitDone() { + // Minimize lock bias and in/de-flation effects by maximizing + // chances of waiting inside sync + try { + while (status >= 0) + synchronized (this) { if (status >= 0) wait(); } + } catch (InterruptedException ie) { + onInterruptedWait(); + } + } + + /** + * Performs the actual timed monitor wait for awaitDone. + */ + private void doAwaitDone(long startTime, long nanos) { + synchronized (this) { + try { + while (status >= 0) { + long nt = nanos - (System.nanoTime() - startTime); + if (nt <= 0) + break; + wait(nt / 1000000, (int) (nt % 1000000)); + } + } catch (InterruptedException ie) { + onInterruptedWait(); + } + } + } + + // Awaiting completion + + /** + * Sets status to indicate there is joiner, then waits for join, + * surrounded with pool notifications. + * + * @return status upon exit + */ + private int awaitDone(ForkJoinWorkerThread w, + boolean maintainParallelism) { + ForkJoinPool pool = (w == null) ? null : w.pool; + int s; + while ((s = status) >= 0) { + if (casStatus(s, (pool == null) ? s|EXTERNAL_SIGNAL : s+1)) { + if (pool == null || !pool.preJoin(this, maintainParallelism)) + doAwaitDone(); + if (((s = status) & INTERNAL_SIGNAL_MASK) != 0) + adjustPoolCountsOnUnblock(pool); + break; + } + } + return s; + } + + /** + * Timed version of awaitDone + * + * @return status upon exit + */ + private int awaitDone(ForkJoinWorkerThread w, long nanos) { + ForkJoinPool pool = (w == null) ? null : w.pool; + int s; + while ((s = status) >= 0) { + if (casStatus(s, (pool == null) ? s|EXTERNAL_SIGNAL : s+1)) { + long startTime = System.nanoTime(); + if (pool == null || !pool.preJoin(this, false)) + doAwaitDone(startTime, nanos); + if ((s = status) >= 0) { + adjustPoolCountsOnCancelledWait(pool); + s = status; + } + if (s < 0 && (s & INTERNAL_SIGNAL_MASK) != 0) + adjustPoolCountsOnUnblock(pool); + break; + } + } + return s; + } + + /** + * Notifies pool that thread is unblocked. Called by signalled + * threads when woken by non-FJ threads (which is atypical). + */ + private void adjustPoolCountsOnUnblock(ForkJoinPool pool) { + int s; + do {} while ((s = status) < 0 && !casStatus(s, s & COMPLETION_MASK)); + if (pool != null && (s &= INTERNAL_SIGNAL_MASK) != 0) + pool.updateRunningCount(s); + } + + /** + * Notifies pool to adjust counts on cancelled or timed out wait. + */ + private void adjustPoolCountsOnCancelledWait(ForkJoinPool pool) { + if (pool != null) { + int s; + while ((s = status) >= 0 && (s & INTERNAL_SIGNAL_MASK) != 0) { + if (casStatus(s, s - 1)) { + pool.updateRunningCount(1); + break; + } + } + } + } + + /** + * Handles interruptions during waits. + */ + private void onInterruptedWait() { + ForkJoinWorkerThread w = getWorker(); + if (w == null) + Thread.currentThread().interrupt(); // re-interrupt + else if (w.isTerminating()) + cancelIgnoringExceptions(); + // else if FJworker, ignore interrupt + } + + // Recording and reporting exceptions + + private void setDoneExceptionally(Throwable rex) { + exceptionMap.put(this, rex); + setCompletion(EXCEPTIONAL); + } + + /** + * Throws the exception associated with status s. + * + * @throws the exception + */ + private void reportException(int s) { + if ((s &= COMPLETION_MASK) < NORMAL) { + if (s == CANCELLED) + throw new CancellationException(); + else + rethrowException(exceptionMap.get(this)); + } + } + + /** + * Returns result or throws exception using j.u.c.Future conventions. + * Only call when {@code isDone} known to be true or thread known + * to be interrupted. + */ + private V reportFutureResult() + throws InterruptedException, ExecutionException { + if (Thread.interrupted()) + throw new InterruptedException(); + int s = status & COMPLETION_MASK; + if (s < NORMAL) { + Throwable ex; + if (s == CANCELLED) + throw new CancellationException(); + if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null) + throw new ExecutionException(ex); + } + return getRawResult(); + } + + /** + * Returns result or throws exception using j.u.c.Future conventions + * with timeouts. + */ + private V reportTimedFutureResult() + throws InterruptedException, ExecutionException, TimeoutException { + if (Thread.interrupted()) + throw new InterruptedException(); + Throwable ex; + int s = status & COMPLETION_MASK; + if (s == NORMAL) + return getRawResult(); + else if (s == CANCELLED) + throw new CancellationException(); + else if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null) + throw new ExecutionException(ex); + else + throw new TimeoutException(); + } + + // internal execution methods + + /** + * Calls exec, recording completion, and rethrowing exception if + * encountered. Caller should normally check status before calling. + * + * @return true if completed normally + */ + private boolean tryExec() { + try { // try block must contain only call to exec + if (!exec()) + return false; + } catch (Throwable rex) { + setDoneExceptionally(rex); + rethrowException(rex); + return false; // not reached + } + setNormalCompletion(); + return true; + } + + /** + * Main execution method used by worker threads. Invokes + * base computation unless already complete. + */ + final void quietlyExec() { + if (status >= 0) { + try { + if (!exec()) + return; + } catch (Throwable rex) { + setDoneExceptionally(rex); + return; + } + setNormalCompletion(); + } + } + + /** + * Calls exec(), recording but not rethrowing exception. + * Caller should normally check status before calling. + * + * @return true if completed normally + */ + private boolean tryQuietlyInvoke() { + try { + if (!exec()) + return false; + } catch (Throwable rex) { + setDoneExceptionally(rex); + return false; + } + setNormalCompletion(); + return true; + } + + /** + * Cancels, ignoring any exceptions it throws. + */ + final void cancelIgnoringExceptions() { + try { + cancel(false); + } catch (Throwable ignore) { + } + } + + /** + * Main implementation of helpJoin + */ + private int busyJoin(ForkJoinWorkerThread w) { + int s; + ForkJoinTask<?> t; + while ((s = status) >= 0 && (t = w.scanWhileJoining(this)) != null) + t.quietlyExec(); + return (s >= 0) ? awaitDone(w, false) : s; // block if no work + } + + // public methods + + /** + * Arranges to asynchronously execute this task. While it is not + * necessarily enforced, it is a usage error to fork a task more + * than once unless it has completed and been reinitialized. + * Subsequent modifications to the state of this task or any data + * it operates on are not necessarily consistently observable by + * any thread other than the one executing it unless preceded by a + * call to {@link #join} or related methods, or a call to {@link + * #isDone} returning {@code true}. + * + * <p>This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return {@code this}, to simplify usage + */ + public final ForkJoinTask<V> fork() { + ((ForkJoinWorkerThread) Thread.currentThread()) + .pushTask(this); + return this; + } + + /** + * Returns the result of the computation when it {@link #isDone is done}. + * This method differs from {@link #get()} in that + * abnormal completion results in {@code RuntimeException} or + * {@code Error}, not {@code ExecutionException}. + * + * @return the computed result + */ + public final V join() { + ForkJoinWorkerThread w = getWorker(); + if (w == null || status < 0 || !w.unpushTask(this) || !tryExec()) + reportException(awaitDone(w, true)); + return getRawResult(); + } + + /** + * Commences performing this task, awaits its completion if + * necessary, and return its result, or throws an (unchecked) + * exception if the underlying computation did so. + * + * @return the computed result + */ + public final V invoke() { + if (status >= 0 && tryExec()) + return getRawResult(); + else + return join(); + } + + /** + * Forks the given tasks, returning when {@code isDone} holds for + * each task or an (unchecked) exception is encountered, in which + * case the exception is rethrown. If either task encounters an + * exception, the other one may be, but is not guaranteed to be, + * cancelled. If both tasks throw an exception, then this method + * throws one of them. The individual status of each task may be + * checked using {@link #getException()} and related methods. + * + * <p>This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @param t1 the first task + * @param t2 the second task + * @throws NullPointerException if any task is null + */ + public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2) { + t2.fork(); + t1.invoke(); + t2.join(); + } + + /** + * Forks the given tasks, returning when {@code isDone} holds for + * each task or an (unchecked) exception is encountered, in which + * case the exception is rethrown. If any task encounters an + * exception, others may be, but are not guaranteed to be, + * cancelled. If more than one task encounters an exception, then + * this method throws any one of these exceptions. The individual + * status of each task may be checked using {@link #getException()} + * and related methods. + * + * <p>This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @param tasks the tasks + * @throws NullPointerException if any task is null + */ + public static void invokeAll(ForkJoinTask<?>... tasks) { + Throwable ex = null; + int last = tasks.length - 1; + for (int i = last; i >= 0; --i) { + ForkJoinTask<?> t = tasks[i]; + if (t == null) { + if (ex == null) + ex = new NullPointerException(); + } + else if (i != 0) + t.fork(); + else { + t.quietlyInvoke(); + if (ex == null) + ex = t.getException(); + } + } + for (int i = 1; i <= last; ++i) { + ForkJoinTask<?> t = tasks[i]; + if (t != null) { + if (ex != null) + t.cancel(false); + else { + t.quietlyJoin(); + if (ex == null) + ex = t.getException(); + } + } + } + if (ex != null) + rethrowException(ex); + } + + /** + * Forks all tasks in the specified collection, returning when + * {@code isDone} holds for each task or an (unchecked) exception + * is encountered. If any task encounters an exception, others + * may be, but are not guaranteed to be, cancelled. If more than + * one task encounters an exception, then this method throws any + * one of these exceptions. The individual status of each task + * may be checked using {@link #getException()} and related + * methods. The behavior of this operation is undefined if the + * specified collection is modified while the operation is in + * progress. + * + * <p>This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @param tasks the collection of tasks + * @return the tasks argument, to simplify usage + * @throws NullPointerException if tasks or any element are null + */ + public static <T extends ForkJoinTask<?>> Collection<T> invokeAll(Collection<T> tasks) { + if (!(tasks instanceof RandomAccess) || !(tasks instanceof List<?>)) { + invokeAll(tasks.toArray(new ForkJoinTask<?>[tasks.size()])); + return tasks; + } + @SuppressWarnings("unchecked") + List<? extends ForkJoinTask<?>> ts = + (List<? extends ForkJoinTask<?>>) tasks; + Throwable ex = null; + int last = ts.size() - 1; + for (int i = last; i >= 0; --i) { + ForkJoinTask<?> t = ts.get(i); + if (t == null) { + if (ex == null) + ex = new NullPointerException(); + } + else if (i != 0) + t.fork(); + else { + t.quietlyInvoke(); + if (ex == null) + ex = t.getException(); + } + } + for (int i = 1; i <= last; ++i) { + ForkJoinTask<?> t = ts.get(i); + if (t != null) { + if (ex != null) + t.cancel(false); + else { + t.quietlyJoin(); + if (ex == null) + ex = t.getException(); + } + } + } + if (ex != null) + rethrowException(ex); + return tasks; + } + + /** + * Attempts to cancel execution of this task. This attempt will + * fail if the task has already completed, has already been + * cancelled, or could not be cancelled for some other reason. If + * successful, and this task has not started when cancel is + * called, execution of this task is suppressed, {@link + * #isCancelled} will report true, and {@link #join} will result + * in a {@code CancellationException} being thrown. + * + * <p>This method may be overridden in subclasses, but if so, must + * still ensure that these minimal properties hold. In particular, + * the {@code cancel} method itself must not throw exceptions. + * + * <p>This method is designed to be invoked by <em>other</em> + * tasks. To terminate the current task, you can just return or + * throw an unchecked exception from its computation method, or + * invoke {@link #completeExceptionally}. + * + * @param mayInterruptIfRunning this value is ignored in the + * default implementation because tasks are not + * cancelled via interruption + * + * @return {@code true} if this task is now cancelled + */ + public boolean cancel(boolean mayInterruptIfRunning) { + setCompletion(CANCELLED); + return (status & COMPLETION_MASK) == CANCELLED; + } + + public final boolean isDone() { + return status < 0; + } + + public final boolean isCancelled() { + return (status & COMPLETION_MASK) == CANCELLED; + } + + /** + * Returns {@code true} if this task threw an exception or was cancelled. + * + * @return {@code true} if this task threw an exception or was cancelled + */ + public final boolean isCompletedAbnormally() { + return (status & COMPLETION_MASK) < NORMAL; + } + + /** + * Returns {@code true} if this task completed without throwing an + * exception and was not cancelled. + * + * @return {@code true} if this task completed without throwing an + * exception and was not cancelled + */ + public final boolean isCompletedNormally() { + return (status & COMPLETION_MASK) == NORMAL; + } + + /** + * Returns the exception thrown by the base computation, or a + * {@code CancellationException} if cancelled, or {@code null} if + * none or if the method has not yet completed. + * + * @return the exception, or {@code null} if none + */ + public final Throwable getException() { + int s = status & COMPLETION_MASK; + return ((s >= NORMAL) ? null : + (s == CANCELLED) ? new CancellationException() : + exceptionMap.get(this)); + } + + /** + * Completes this task abnormally, and if not already aborted or + * cancelled, causes it to throw the given exception upon + * {@code join} and related operations. This method may be used + * to induce exceptions in asynchronous tasks, or to force + * completion of tasks that would not otherwise complete. Its use + * in other situations is discouraged. This method is + * overridable, but overridden versions must invoke {@code super} + * implementation to maintain guarantees. + * + * @param ex the exception to throw. If this exception is not a + * {@code RuntimeException} or {@code Error}, the actual exception + * thrown will be a {@code RuntimeException} with cause {@code ex}. + */ + public void completeExceptionally(Throwable ex) { + setDoneExceptionally((ex instanceof RuntimeException) || + (ex instanceof Error) ? ex : + new RuntimeException(ex)); + } + + /** + * Completes this task, and if not already aborted or cancelled, + * returning a {@code null} result upon {@code join} and related + * operations. This method may be used to provide results for + * asynchronous tasks, or to provide alternative handling for + * tasks that would not otherwise complete normally. Its use in + * other situations is discouraged. This method is + * overridable, but overridden versions must invoke {@code super} + * implementation to maintain guarantees. + * + * @param value the result value for this task + */ + public void complete(V value) { + try { + setRawResult(value); + } catch (Throwable rex) { + setDoneExceptionally(rex); + return; + } + setNormalCompletion(); + } + + public final V get() throws InterruptedException, ExecutionException { + ForkJoinWorkerThread w = getWorker(); + if (w == null || status < 0 || !w.unpushTask(this) || !tryQuietlyInvoke()) + awaitDone(w, true); + return reportFutureResult(); + } + + public final V get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + long nanos = unit.toNanos(timeout); + ForkJoinWorkerThread w = getWorker(); + if (w == null || status < 0 || !w.unpushTask(this) || !tryQuietlyInvoke()) + awaitDone(w, nanos); + return reportTimedFutureResult(); + } + + /** + * Possibly executes other tasks until this task {@link #isDone is + * done}, then returns the result of the computation. This method + * may be more efficient than {@code join}, but is only applicable + * when there are no potential dependencies between continuation + * of the current task and that of any other task that might be + * executed while helping. (This usually holds for pure + * divide-and-conquer tasks). + * + * <p>This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return the computed result + */ + public final V helpJoin() { + ForkJoinWorkerThread w = (ForkJoinWorkerThread) Thread.currentThread(); + if (status < 0 || !w.unpushTask(this) || !tryExec()) + reportException(busyJoin(w)); + return getRawResult(); + } + + /** + * Possibly executes other tasks until this task {@link #isDone is + * done}. This method may be useful when processing collections + * of tasks when some have been cancelled or otherwise known to + * have aborted. + * + * <p>This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + */ + public final void quietlyHelpJoin() { + if (status >= 0) { + ForkJoinWorkerThread w = + (ForkJoinWorkerThread) Thread.currentThread(); + if (!w.unpushTask(this) || !tryQuietlyInvoke()) + busyJoin(w); + } + } + + /** + * Joins this task, without returning its result or throwing an + * exception. This method may be useful when processing + * collections of tasks when some have been cancelled or otherwise + * known to have aborted. + */ + public final void quietlyJoin() { + if (status >= 0) { + ForkJoinWorkerThread w = getWorker(); + if (w == null || !w.unpushTask(this) || !tryQuietlyInvoke()) + awaitDone(w, true); + } + } + + /** + * Commences performing this task and awaits its completion if + * necessary, without returning its result or throwing an + * exception. This method may be useful when processing + * collections of tasks when some have been cancelled or otherwise + * known to have aborted. + */ + public final void quietlyInvoke() { + if (status >= 0 && !tryQuietlyInvoke()) + quietlyJoin(); + } + + /** + * Possibly executes tasks until the pool hosting the current task + * {@link ForkJoinPool#isQuiescent is quiescent}. This method may + * be of use in designs in which many tasks are forked, but none + * are explicitly joined, instead executing them until all are + * processed. + * + * <p>This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + */ + public static void helpQuiesce() { + ((ForkJoinWorkerThread) Thread.currentThread()) + .helpQuiescePool(); + } + + /** + * Resets the internal bookkeeping state of this task, allowing a + * subsequent {@code fork}. This method allows repeated reuse of + * this task, but only if reuse occurs when this task has either + * never been forked, or has been forked, then completed and all + * outstanding joins of this task have also completed. Effects + * under any other usage conditions are not guaranteed. + * This method may be useful when executing + * pre-constructed trees of subtasks in loops. + */ + public void reinitialize() { + if ((status & COMPLETION_MASK) == EXCEPTIONAL) + exceptionMap.remove(this); + status = 0; + } + + /** + * Returns the pool hosting the current task execution, or null + * if this task is executing outside of any ForkJoinPool. + * + * @see #inForkJoinPool + * @return the pool, or {@code null} if none + */ + public static ForkJoinPool getPool() { + Thread t = Thread.currentThread(); + return (t instanceof ForkJoinWorkerThread) ? + ((ForkJoinWorkerThread) t).pool : null; + } + + /** + * Returns {@code true} if the current thread is executing as a + * ForkJoinPool computation. + * + * @return {@code true} if the current thread is executing as a + * ForkJoinPool computation, or false otherwise + */ + public static boolean inForkJoinPool() { + return Thread.currentThread() instanceof ForkJoinWorkerThread; + } + + /** + * Tries to unschedule this task for execution. This method will + * typically succeed if this task is the most recently forked task + * by the current thread, and has not commenced executing in + * another thread. This method may be useful when arranging + * alternative local processing of tasks that could have been, but + * were not, stolen. + * + * <p>This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return {@code true} if unforked + */ + public boolean tryUnfork() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .unpushTask(this); + } + + /** + * Returns an estimate of the number of tasks that have been + * forked by the current worker thread but not yet executed. This + * value may be useful for heuristic decisions about whether to + * fork other tasks. + * + * <p>This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return the number of tasks + */ + public static int getQueuedTaskCount() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .getQueueSize(); + } + + /** + * Returns an estimate of how many more locally queued tasks are + * held by the current worker thread than there are other worker + * threads that might steal them. This value may be useful for + * heuristic decisions about whether to fork other tasks. In many + * usages of ForkJoinTasks, at steady state, each worker should + * aim to maintain a small constant surplus (for example, 3) of + * tasks, and to process computations locally if this threshold is + * exceeded. + * + * <p>This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return the surplus number of tasks, which may be negative + */ + public static int getSurplusQueuedTaskCount() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .getEstimatedSurplusTaskCount(); + } + + // Extension methods + + /** + * Returns the result that would be returned by {@link #join}, even + * if this task completed abnormally, or {@code null} if this task + * is not known to have been completed. This method is designed + * to aid debugging, as well as to support extensions. Its use in + * any other context is discouraged. + * + * @return the result, or {@code null} if not completed + */ + public abstract V getRawResult(); + + /** + * Forces the given value to be returned as a result. This method + * is designed to support extensions, and should not in general be + * called otherwise. + * + * @param value the value + */ + protected abstract void setRawResult(V value); + + /** + * Immediately performs the base action of this task. This method + * is designed to support extensions, and should not in general be + * called otherwise. The return value controls whether this task + * is considered to be done normally. It may return false in + * asynchronous actions that require explicit invocations of + * {@link #complete} to become joinable. It may also throw an + * (unchecked) exception to indicate abnormal exit. + * + * @return {@code true} if completed normally + */ + protected abstract boolean exec(); + + /** + * Returns, but does not unschedule or execute, a task queued by + * the current thread but not yet executed, if one is immediately + * available. There is no guarantee that this task will actually + * be polled or executed next. Conversely, this method may return + * null even if a task exists but cannot be accessed without + * contention with other threads. This method is designed + * primarily to support extensions, and is unlikely to be useful + * otherwise. + * + * <p>This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return the next task, or {@code null} if none are available + */ + protected static ForkJoinTask<?> peekNextLocalTask() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .peekTask(); + } + + /** + * Unschedules and returns, without executing, the next task + * queued by the current thread but not yet executed. This method + * is designed primarily to support extensions, and is unlikely to + * be useful otherwise. + * + * <p>This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return the next task, or {@code null} if none are available + */ + protected static ForkJoinTask<?> pollNextLocalTask() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .pollLocalTask(); + } + + /** + * Unschedules and returns, without executing, the next task + * queued by the current thread but not yet executed, if one is + * available, or if not available, a task that was forked by some + * other thread, if available. Availability may be transient, so a + * {@code null} result does not necessarily imply quiescence + * of the pool this task is operating in. This method is designed + * primarily to support extensions, and is unlikely to be useful + * otherwise. + * + * <p>This method may be invoked only from within {@code + * ForkJoinTask} computations (as may be determined using method + * {@link #inForkJoinPool}). Attempts to invoke in other contexts + * result in exceptions or errors, possibly including {@code + * ClassCastException}. + * + * @return a task, or {@code null} if none are available + */ + protected static ForkJoinTask<?> pollTask() { + return ((ForkJoinWorkerThread) Thread.currentThread()) + .pollTask(); + } + + /** + * Adaptor for Runnables. This implements RunnableFuture + * to be compliant with AbstractExecutorService constraints + * when used in ForkJoinPool. + */ + static final class AdaptedRunnable<T> extends ForkJoinTask<T> + implements RunnableFuture<T> { + final Runnable runnable; + final T resultOnCompletion; + T result; + AdaptedRunnable(Runnable runnable, T result) { + if (runnable == null) throw new NullPointerException(); + this.runnable = runnable; + this.resultOnCompletion = result; + } + public T getRawResult() { return result; } + public void setRawResult(T v) { result = v; } + public boolean exec() { + runnable.run(); + result = resultOnCompletion; + return true; + } + public void run() { invoke(); } + private static final long serialVersionUID = 5232453952276885070L; + } + + /** + * Adaptor for Callables + */ + static final class AdaptedCallable<T> extends ForkJoinTask<T> + implements RunnableFuture<T> { + final Callable<? extends T> callable; + T result; + AdaptedCallable(Callable<? extends T> callable) { + if (callable == null) throw new NullPointerException(); + this.callable = callable; + } + public T getRawResult() { return result; } + public void setRawResult(T v) { result = v; } + public boolean exec() { + try { + result = callable.call(); + return true; + } catch (Error err) { + throw err; + } catch (RuntimeException rex) { + throw rex; + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + public void run() { invoke(); } + private static final long serialVersionUID = 2838392045355241008L; + } + + /** + * Returns a new {@code ForkJoinTask} that performs the {@code run} + * method of the given {@code Runnable} as its action, and returns + * a null result upon {@link #join}. + * + * @param runnable the runnable action + * @return the task + */ + public static ForkJoinTask<?> adapt(Runnable runnable) { + return new AdaptedRunnable<Void>(runnable, null); + } + + /** + * Returns a new {@code ForkJoinTask} that performs the {@code run} + * method of the given {@code Runnable} as its action, and returns + * the given result upon {@link #join}. + * + * @param runnable the runnable action + * @param result the result upon completion + * @return the task + */ + public static <T> ForkJoinTask<T> adapt(Runnable runnable, T result) { + return new AdaptedRunnable<T>(runnable, result); + } + + /** + * Returns a new {@code ForkJoinTask} that performs the {@code call} + * method of the given {@code Callable} as its action, and returns + * its result upon {@link #join}, translating any checked exceptions + * encountered into {@code RuntimeException}. + * + * @param callable the callable action + * @return the task + */ + public static <T> ForkJoinTask<T> adapt(Callable<? extends T> callable) { + return new AdaptedCallable<T>(callable); + } + + // Serialization support + + private static final long serialVersionUID = -7721805057305804111L; + + /** + * Saves the state to a stream. + * + * @serialData the current run status and the exception thrown + * during execution, or {@code null} if none + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + s.writeObject(getException()); + } + + /** + * Reconstitutes the instance from a stream. + * + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + status &= ~INTERNAL_SIGNAL_MASK; // clear internal signal counts + status |= EXTERNAL_SIGNAL; // conservatively set external signal + Object ex = s.readObject(); + if (ex != null) + setDoneExceptionally((Throwable) ex); + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + private static final long statusOffset = + objectFieldOffset("status", ForkJoinTask.class); + + private static long objectFieldOffset(String field, Class<?> klazz) { + try { + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,827 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.Collection; + +/** + * A thread managed by a {@link ForkJoinPool}. This class is + * subclassable solely for the sake of adding functionality -- there + * are no overridable methods dealing with scheduling or execution. + * However, you can override initialization and termination methods + * surrounding the main task processing loop. If you do create such a + * subclass, you will also need to supply a custom {@link + * ForkJoinPool.ForkJoinWorkerThreadFactory} to use it in a {@code + * ForkJoinPool}. + * + * @since 1.7 + * @author Doug Lea + */ +public class ForkJoinWorkerThread extends Thread { + /* + * Algorithm overview: + * + * 1. Work-Stealing: Work-stealing queues are special forms of + * Deques that support only three of the four possible + * end-operations -- push, pop, and deq (aka steal), and only do + * so under the constraints that push and pop are called only from + * the owning thread, while deq may be called from other threads. + * (If you are unfamiliar with them, you probably want to read + * Herlihy and Shavit's book "The Art of Multiprocessor + * programming", chapter 16 describing these in more detail before + * proceeding.) The main work-stealing queue design is roughly + * similar to "Dynamic Circular Work-Stealing Deque" by David + * Chase and Yossi Lev, SPAA 2005 + * (http://research.sun.com/scalable/pubs/index.html). The main + * difference ultimately stems from gc requirements that we null + * out taken slots as soon as we can, to maintain as small a + * footprint as possible even in programs generating huge numbers + * of tasks. To accomplish this, we shift the CAS arbitrating pop + * vs deq (steal) from being on the indices ("base" and "sp") to + * the slots themselves (mainly via method "casSlotNull()"). So, + * both a successful pop and deq mainly entail CAS'ing a non-null + * slot to null. Because we rely on CASes of references, we do + * not need tag bits on base or sp. They are simple ints as used + * in any circular array-based queue (see for example ArrayDeque). + * Updates to the indices must still be ordered in a way that + * guarantees that (sp - base) > 0 means the queue is empty, but + * otherwise may err on the side of possibly making the queue + * appear nonempty when a push, pop, or deq have not fully + * committed. Note that this means that the deq operation, + * considered individually, is not wait-free. One thief cannot + * successfully continue until another in-progress one (or, if + * previously empty, a push) completes. However, in the + * aggregate, we ensure at least probabilistic + * non-blockingness. If an attempted steal fails, a thief always + * chooses a different random victim target to try next. So, in + * order for one thief to progress, it suffices for any + * in-progress deq or new push on any empty queue to complete. One + * reason this works well here is that apparently-nonempty often + * means soon-to-be-stealable, which gives threads a chance to + * activate if necessary before stealing (see below). + * + * This approach also enables support for "async mode" where local + * task processing is in FIFO, not LIFO order; simply by using a + * version of deq rather than pop when locallyFifo is true (as set + * by the ForkJoinPool). This allows use in message-passing + * frameworks in which tasks are never joined. + * + * Efficient implementation of this approach currently relies on + * an uncomfortable amount of "Unsafe" mechanics. To maintain + * correct orderings, reads and writes of variable base require + * volatile ordering. Variable sp does not require volatile write + * but needs cheaper store-ordering on writes. Because they are + * protected by volatile base reads, reads of the queue array and + * its slots do not need volatile load semantics, but writes (in + * push) require store order and CASes (in pop and deq) require + * (volatile) CAS semantics. (See "Idempotent work stealing" by + * Michael, Saraswat, and Vechev, PPoPP 2009 + * http://portal.acm.org/citation.cfm?id=1504186 for an algorithm + * with similar properties, but without support for nulling + * slots.) Since these combinations aren't supported using + * ordinary volatiles, the only way to accomplish these + * efficiently is to use direct Unsafe calls. (Using external + * AtomicIntegers and AtomicReferenceArrays for the indices and + * array is significantly slower because of memory locality and + * indirection effects.) + * + * Further, performance on most platforms is very sensitive to + * placement and sizing of the (resizable) queue array. Even + * though these queues don't usually become all that big, the + * initial size must be large enough to counteract cache + * contention effects across multiple queues (especially in the + * presence of GC cardmarking). Also, to improve thread-locality, + * queues are currently initialized immediately after the thread + * gets the initial signal to start processing tasks. However, + * all queue-related methods except pushTask are written in a way + * that allows them to instead be lazily allocated and/or disposed + * of when empty. All together, these low-level implementation + * choices produce as much as a factor of 4 performance + * improvement compared to naive implementations, and enable the + * processing of billions of tasks per second, sometimes at the + * expense of ugliness. + * + * 2. Run control: The primary run control is based on a global + * counter (activeCount) held by the pool. It uses an algorithm + * similar to that in Herlihy and Shavit section 17.6 to cause + * threads to eventually block when all threads declare they are + * inactive. For this to work, threads must be declared active + * when executing tasks, and before stealing a task. They must be + * inactive before blocking on the Pool Barrier (awaiting a new + * submission or other Pool event). In between, there is some free + * play which we take advantage of to avoid contention and rapid + * flickering of the global activeCount: If inactive, we activate + * only if a victim queue appears to be nonempty (see above). + * Similarly, a thread tries to inactivate only after a full scan + * of other threads. The net effect is that contention on + * activeCount is rarely a measurable performance issue. (There + * are also a few other cases where we scan for work rather than + * retry/block upon contention.) + * + * 3. Selection control. We maintain policy of always choosing to + * run local tasks rather than stealing, and always trying to + * steal tasks before trying to run a new submission. All steals + * are currently performed in randomly-chosen deq-order. It may be + * worthwhile to bias these with locality / anti-locality + * information, but doing this well probably requires more + * lower-level information from JVMs than currently provided. + */ + + /** + * Capacity of work-stealing queue array upon initialization. + * Must be a power of two. Initial size must be at least 2, but is + * padded to minimize cache effects. + */ + private static final int INITIAL_QUEUE_CAPACITY = 1 << 13; + + /** + * Maximum work-stealing queue array size. Must be less than or + * equal to 1 << 28 to ensure lack of index wraparound. (This + * is less than usual bounds, because we need leftshift by 3 + * to be in int range). + */ + private static final int MAXIMUM_QUEUE_CAPACITY = 1 << 28; + + /** + * The pool this thread works in. Accessed directly by ForkJoinTask. + */ + final ForkJoinPool pool; + + /** + * The work-stealing queue array. Size must be a power of two. + * Initialized when thread starts, to improve memory locality. + */ + private ForkJoinTask<?>[] queue; + + /** + * Index (mod queue.length) of next queue slot to push to or pop + * from. It is written only by owner thread, via ordered store. + * Both sp and base are allowed to wrap around on overflow, but + * (sp - base) still estimates size. + */ + private volatile int sp; + + /** + * Index (mod queue.length) of least valid queue slot, which is + * always the next position to steal from if nonempty. + */ + private volatile int base; + + /** + * Activity status. When true, this worker is considered active. + * Must be false upon construction. It must be true when executing + * tasks, and BEFORE stealing a task. It must be false before + * calling pool.sync. + */ + private boolean active; + + /** + * Run state of this worker. Supports simple versions of the usual + * shutdown/shutdownNow control. + */ + private volatile int runState; + + /** + * Seed for random number generator for choosing steal victims. + * Uses Marsaglia xorshift. Must be nonzero upon initialization. + */ + private int seed; + + /** + * Number of steals, transferred to pool when idle + */ + private int stealCount; + + /** + * Index of this worker in pool array. Set once by pool before + * running, and accessed directly by pool during cleanup etc. + */ + int poolIndex; + + /** + * The last barrier event waited for. Accessed in pool callback + * methods, but only by current thread. + */ + long lastEventCount; + + /** + * True if use local fifo, not default lifo, for local polling + */ + private boolean locallyFifo; + + /** + * Creates a ForkJoinWorkerThread operating in the given pool. + * + * @param pool the pool this thread works in + * @throws NullPointerException if pool is null + */ + protected ForkJoinWorkerThread(ForkJoinPool pool) { + if (pool == null) throw new NullPointerException(); + this.pool = pool; + // Note: poolIndex is set by pool during construction + // Remaining initialization is deferred to onStart + } + + // Public access methods + + /** + * Returns the pool hosting this thread. + * + * @return the pool + */ + public ForkJoinPool getPool() { + return pool; + } + + /** + * Returns the index number of this thread in its pool. The + * returned value ranges from zero to the maximum number of + * threads (minus one) that have ever been created in the pool. + * This method may be useful for applications that track status or + * collect results per-worker rather than per-task. + * + * @return the index number + */ + public int getPoolIndex() { + return poolIndex; + } + + /** + * Establishes local first-in-first-out scheduling mode for forked + * tasks that are never joined. + * + * @param async if true, use locally FIFO scheduling + */ + void setAsyncMode(boolean async) { + locallyFifo = async; + } + + // Runstate management + + // Runstate values. Order matters + private static final int RUNNING = 0; + private static final int SHUTDOWN = 1; + private static final int TERMINATING = 2; + private static final int TERMINATED = 3; + + final boolean isShutdown() { return runState >= SHUTDOWN; } + final boolean isTerminating() { return runState >= TERMINATING; } + final boolean isTerminated() { return runState == TERMINATED; } + final boolean shutdown() { return transitionRunStateTo(SHUTDOWN); } + final boolean shutdownNow() { return transitionRunStateTo(TERMINATING); } + + /** + * Transitions to at least the given state. + * + * @return {@code true} if not already at least at given state + */ + private boolean transitionRunStateTo(int state) { + for (;;) { + int s = runState; + if (s >= state) + return false; + if (UNSAFE.compareAndSwapInt(this, runStateOffset, s, state)) + return true; + } + } + + /** + * Tries to set status to active; fails on contention. + */ + private boolean tryActivate() { + if (!active) { + if (!pool.tryIncrementActiveCount()) + return false; + active = true; + } + return true; + } + + /** + * Tries to set status to inactive; fails on contention. + */ + private boolean tryInactivate() { + if (active) { + if (!pool.tryDecrementActiveCount()) + return false; + active = false; + } + return true; + } + + /** + * Computes next value for random victim probe. Scans don't + * require a very high quality generator, but also not a crummy + * one. Marsaglia xor-shift is cheap and works well. + */ + private static int xorShift(int r) { + r ^= (r << 13); + r ^= (r >>> 17); + return r ^ (r << 5); + } + + // Lifecycle methods + + /** + * This method is required to be public, but should never be + * called explicitly. It performs the main run loop to execute + * ForkJoinTasks. + */ + public void run() { + Throwable exception = null; + try { + onStart(); + pool.sync(this); // await first pool event + mainLoop(); + } catch (Throwable ex) { + exception = ex; + } finally { + onTermination(exception); + } + } + + /** + * Executes tasks until shut down. + */ + private void mainLoop() { + while (!isShutdown()) { + ForkJoinTask<?> t = pollTask(); + if (t != null || (t = pollSubmission()) != null) + t.quietlyExec(); + else if (tryInactivate()) + pool.sync(this); + } + } + + /** + * Initializes internal state after construction but before + * processing any tasks. If you override this method, you must + * invoke super.onStart() at the beginning of the method. + * Initialization requires care: Most fields must have legal + * default values, to ensure that attempted accesses from other + * threads work correctly even before this thread starts + * processing tasks. + */ + protected void onStart() { + // Allocate while starting to improve chances of thread-local + // isolation + queue = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY]; + // Initial value of seed need not be especially random but + // should differ across workers and must be nonzero + int p = poolIndex + 1; + seed = p + (p << 8) + (p << 16) + (p << 24); // spread bits + } + + /** + * Performs cleanup associated with termination of this worker + * thread. If you override this method, you must invoke + * {@code super.onTermination} at the end of the overridden method. + * + * @param exception the exception causing this thread to abort due + * to an unrecoverable error, or {@code null} if completed normally + */ + protected void onTermination(Throwable exception) { + // Execute remaining local tasks unless aborting or terminating + while (exception == null && pool.isProcessingTasks() && base != sp) { + try { + ForkJoinTask<?> t = popTask(); + if (t != null) + t.quietlyExec(); + } catch (Throwable ex) { + exception = ex; + } + } + // Cancel other tasks, transition status, notify pool, and + // propagate exception to uncaught exception handler + try { + do {} while (!tryInactivate()); // ensure inactive + cancelTasks(); + runState = TERMINATED; + pool.workerTerminated(this); + } catch (Throwable ex) { // Shouldn't ever happen + if (exception == null) // but if so, at least rethrown + exception = ex; + } finally { + if (exception != null) + ForkJoinTask.rethrowException(exception); + } + } + + // Intrinsics-based support for queue operations. + + private static long slotOffset(int i) { + return ((long) i << qShift) + qBase; + } + + /** + * Adds in store-order the given task at given slot of q to null. + * Caller must ensure q is non-null and index is in range. + */ + private static void setSlot(ForkJoinTask<?>[] q, int i, + ForkJoinTask<?> t) { + UNSAFE.putOrderedObject(q, slotOffset(i), t); + } + + /** + * CAS given slot of q to null. Caller must ensure q is non-null + * and index is in range. + */ + private static boolean casSlotNull(ForkJoinTask<?>[] q, int i, + ForkJoinTask<?> t) { + return UNSAFE.compareAndSwapObject(q, slotOffset(i), t, null); + } + + /** + * Sets sp in store-order. + */ + private void storeSp(int s) { + UNSAFE.putOrderedInt(this, spOffset, s); + } + + // Main queue methods + + /** + * Pushes a task. Called only by current thread. + * + * @param t the task. Caller must ensure non-null. + */ + final void pushTask(ForkJoinTask<?> t) { + ForkJoinTask<?>[] q = queue; + int mask = q.length - 1; + int s = sp; + setSlot(q, s & mask, t); + storeSp(++s); + if ((s -= base) == 1) + pool.signalWork(); + else if (s >= mask) + growQueue(); + } + + /** + * Tries to take a task from the base of the queue, failing if + * either empty or contended. + * + * @return a task, or null if none or contended + */ + final ForkJoinTask<?> deqTask() { + ForkJoinTask<?> t; + ForkJoinTask<?>[] q; + int i; + int b; + if (sp != (b = base) && + (q = queue) != null && // must read q after b + (t = q[i = (q.length - 1) & b]) != null && + casSlotNull(q, i, t)) { + base = b + 1; + return t; + } + return null; + } + + /** + * Tries to take a task from the base of own queue, activating if + * necessary, failing only if empty. Called only by current thread. + * + * @return a task, or null if none + */ + final ForkJoinTask<?> locallyDeqTask() { + int b; + while (sp != (b = base)) { + if (tryActivate()) { + ForkJoinTask<?>[] q = queue; + int i = (q.length - 1) & b; + ForkJoinTask<?> t = q[i]; + if (t != null && casSlotNull(q, i, t)) { + base = b + 1; + return t; + } + } + } + return null; + } + + /** + * Returns a popped task, or null if empty. Ensures active status + * if non-null. Called only by current thread. + */ + final ForkJoinTask<?> popTask() { + int s = sp; + while (s != base) { + if (tryActivate()) { + ForkJoinTask<?>[] q = queue; + int mask = q.length - 1; + int i = (s - 1) & mask; + ForkJoinTask<?> t = q[i]; + if (t == null || !casSlotNull(q, i, t)) + break; + storeSp(s - 1); + return t; + } + } + return null; + } + + /** + * Specialized version of popTask to pop only if + * topmost element is the given task. Called only + * by current thread while active. + * + * @param t the task. Caller must ensure non-null. + */ + final boolean unpushTask(ForkJoinTask<?> t) { + ForkJoinTask<?>[] q = queue; + int mask = q.length - 1; + int s = sp - 1; + if (casSlotNull(q, s & mask, t)) { + storeSp(s); + return true; + } + return false; + } + + /** + * Returns next task or null if empty or contended + */ + final ForkJoinTask<?> peekTask() { + ForkJoinTask<?>[] q = queue; + if (q == null) + return null; + int mask = q.length - 1; + int i = locallyFifo ? base : (sp - 1); + return q[i & mask]; + } + + /** + * Doubles queue array size. Transfers elements by emulating + * steals (deqs) from old array and placing, oldest first, into + * new array. + */ + private void growQueue() { + ForkJoinTask<?>[] oldQ = queue; + int oldSize = oldQ.length; + int newSize = oldSize << 1; + if (newSize > MAXIMUM_QUEUE_CAPACITY) + throw new RejectedExecutionException("Queue capacity exceeded"); + ForkJoinTask<?>[] newQ = queue = new ForkJoinTask<?>[newSize]; + + int b = base; + int bf = b + oldSize; + int oldMask = oldSize - 1; + int newMask = newSize - 1; + do { + int oldIndex = b & oldMask; + ForkJoinTask<?> t = oldQ[oldIndex]; + if (t != null && !casSlotNull(oldQ, oldIndex, t)) + t = null; + setSlot(newQ, b & newMask, t); + } while (++b != bf); + pool.signalWork(); + } + + /** + * Tries to steal a task from another worker. Starts at a random + * index of workers array, and probes workers until finding one + * with non-empty queue or finding that all are empty. It + * randomly selects the first n probes. If these are empty, it + * resorts to a full circular traversal, which is necessary to + * accurately set active status by caller. Also restarts if pool + * events occurred since last scan, which forces refresh of + * workers array, in case barrier was associated with resize. + * + * This method must be both fast and quiet -- usually avoiding + * memory accesses that could disrupt cache sharing etc other than + * those needed to check for and take tasks. This accounts for, + * among other things, updating random seed in place without + * storing it until exit. + * + * @return a task, or null if none found + */ + private ForkJoinTask<?> scan() { + ForkJoinTask<?> t = null; + int r = seed; // extract once to keep scan quiet + ForkJoinWorkerThread[] ws; // refreshed on outer loop + int mask; // must be power 2 minus 1 and > 0 + outer:do { + if ((ws = pool.workers) != null && (mask = ws.length - 1) > 0) { + int idx = r; + int probes = ~mask; // use random index while negative + for (;;) { + r = xorShift(r); // update random seed + ForkJoinWorkerThread v = ws[mask & idx]; + if (v == null || v.sp == v.base) { + if (probes <= mask) + idx = (probes++ < 0) ? r : (idx + 1); + else + break; + } + else if (!tryActivate() || (t = v.deqTask()) == null) + continue outer; // restart on contention + else + break outer; + } + } + } while (pool.hasNewSyncEvent(this)); // retry on pool events + seed = r; + return t; + } + + /** + * Gets and removes a local or stolen task. + * + * @return a task, if available + */ + final ForkJoinTask<?> pollTask() { + ForkJoinTask<?> t = locallyFifo ? locallyDeqTask() : popTask(); + if (t == null && (t = scan()) != null) + ++stealCount; + return t; + } + + /** + * Gets a local task. + * + * @return a task, if available + */ + final ForkJoinTask<?> pollLocalTask() { + return locallyFifo ? locallyDeqTask() : popTask(); + } + + /** + * Returns a pool submission, if one exists, activating first. + * + * @return a submission, if available + */ + private ForkJoinTask<?> pollSubmission() { + ForkJoinPool p = pool; + while (p.hasQueuedSubmissions()) { + ForkJoinTask<?> t; + if (tryActivate() && (t = p.pollSubmission()) != null) + return t; + } + return null; + } + + // Methods accessed only by Pool + + /** + * Removes and cancels all tasks in queue. Can be called from any + * thread. + */ + final void cancelTasks() { + ForkJoinTask<?> t; + while (base != sp && (t = deqTask()) != null) + t.cancelIgnoringExceptions(); + } + + /** + * Drains tasks to given collection c. + * + * @return the number of tasks drained + */ + final int drainTasksTo(Collection<? super ForkJoinTask<?>> c) { + int n = 0; + ForkJoinTask<?> t; + while (base != sp && (t = deqTask()) != null) { + c.add(t); + ++n; + } + return n; + } + + /** + * Gets and clears steal count for accumulation by pool. Called + * only when known to be idle (in pool.sync and termination). + */ + final int getAndClearStealCount() { + int sc = stealCount; + stealCount = 0; + return sc; + } + + /** + * Returns {@code true} if at least one worker in the given array + * appears to have at least one queued task. + * + * @param ws array of workers + */ + static boolean hasQueuedTasks(ForkJoinWorkerThread[] ws) { + if (ws != null) { + int len = ws.length; + for (int j = 0; j < 2; ++j) { // need two passes for clean sweep + for (int i = 0; i < len; ++i) { + ForkJoinWorkerThread w = ws[i]; + if (w != null && w.sp != w.base) + return true; + } + } + } + return false; + } + + // Support methods for ForkJoinTask + + /** + * Returns an estimate of the number of tasks in the queue. + */ + final int getQueueSize() { + // suppress momentarily negative values + return Math.max(0, sp - base); + } + + /** + * Returns an estimate of the number of tasks, offset by a + * function of number of idle workers. + */ + final int getEstimatedSurplusTaskCount() { + // The halving approximates weighting idle vs non-idle workers + return (sp - base) - (pool.getIdleThreadCount() >>> 1); + } + + /** + * Scans, returning early if joinMe done. + */ + final ForkJoinTask<?> scanWhileJoining(ForkJoinTask<?> joinMe) { + ForkJoinTask<?> t = pollTask(); + if (t != null && joinMe.status < 0 && sp == base) { + pushTask(t); // unsteal if done and this task would be stealable + t = null; + } + return t; + } + + /** + * Runs tasks until {@code pool.isQuiescent()}. + */ + final void helpQuiescePool() { + for (;;) { + ForkJoinTask<?> t = pollTask(); + if (t != null) + t.quietlyExec(); + else if (tryInactivate() && pool.isQuiescent()) + break; + } + do {} while (!tryActivate()); // re-activate on exit + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + private static final long spOffset = + objectFieldOffset("sp", ForkJoinWorkerThread.class); + private static final long runStateOffset = + objectFieldOffset("runState", ForkJoinWorkerThread.class); + private static final long qBase; + private static final int qShift; + + static { + qBase = UNSAFE.arrayBaseOffset(ForkJoinTask[].class); + int s = UNSAFE.arrayIndexScale(ForkJoinTask[].class); + if ((s & (s-1)) != 0) + throw new Error("data type scale not a power of two"); + qShift = 31 - Integer.numberOfLeadingZeros(s); + } + + private static long objectFieldOffset(String field, Class<?> klazz) { + try { + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/util/concurrent/LinkedTransferQueue.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,1270 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.AbstractQueue; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; +import java.util.concurrent.locks.LockSupport; +/** + * An unbounded {@link TransferQueue} based on linked nodes. + * This queue orders elements FIFO (first-in-first-out) with respect + * to any given producer. The <em>head</em> of the queue is that + * element that has been on the queue the longest time for some + * producer. The <em>tail</em> of the queue is that element that has + * been on the queue the shortest time for some producer. + * + * <p>Beware that, unlike in most collections, the {@code size} + * method is <em>NOT</em> a constant-time operation. Because of the + * asynchronous nature of these queues, determining the current number + * of elements requires a traversal of the elements. + * + * <p>This class and its iterator implement all of the + * <em>optional</em> methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + * <p>Memory consistency effects: As with other concurrent + * collections, actions in a thread prior to placing an object into a + * {@code LinkedTransferQueue} + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> + * actions subsequent to the access or removal of that element from + * the {@code LinkedTransferQueue} in another thread. + * + * <p>This class is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.7 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public class LinkedTransferQueue<E> extends AbstractQueue<E> + implements TransferQueue<E>, java.io.Serializable { + private static final long serialVersionUID = -3223113410248163686L; + + /* + * *** Overview of Dual Queues with Slack *** + * + * Dual Queues, introduced by Scherer and Scott + * (http://www.cs.rice.edu/~wns1/papers/2004-DISC-DDS.pdf) are + * (linked) queues in which nodes may represent either data or + * requests. When a thread tries to enqueue a data node, but + * encounters a request node, it instead "matches" and removes it; + * and vice versa for enqueuing requests. Blocking Dual Queues + * arrange that threads enqueuing unmatched requests block until + * other threads provide the match. Dual Synchronous Queues (see + * Scherer, Lea, & Scott + * http://www.cs.rochester.edu/u/scott/papers/2009_Scherer_CACM_SSQ.pdf) + * additionally arrange that threads enqueuing unmatched data also + * block. Dual Transfer Queues support all of these modes, as + * dictated by callers. + * + * A FIFO dual queue may be implemented using a variation of the + * Michael & Scott (M&S) lock-free queue algorithm + * (http://www.cs.rochester.edu/u/scott/papers/1996_PODC_queues.pdf). + * It maintains two pointer fields, "head", pointing to a + * (matched) node that in turn points to the first actual + * (unmatched) queue node (or null if empty); and "tail" that + * points to the last node on the queue (or again null if + * empty). For example, here is a possible queue with four data + * elements: + * + * head tail + * | | + * v v + * M -> U -> U -> U -> U + * + * The M&S queue algorithm is known to be prone to scalability and + * overhead limitations when maintaining (via CAS) these head and + * tail pointers. This has led to the development of + * contention-reducing variants such as elimination arrays (see + * Moir et al http://portal.acm.org/citation.cfm?id=1074013) and + * optimistic back pointers (see Ladan-Mozes & Shavit + * http://people.csail.mit.edu/edya/publications/OptimisticFIFOQueue-journal.pdf). + * However, the nature of dual queues enables a simpler tactic for + * improving M&S-style implementations when dual-ness is needed. + * + * In a dual queue, each node must atomically maintain its match + * status. While there are other possible variants, we implement + * this here as: for a data-mode node, matching entails CASing an + * "item" field from a non-null data value to null upon match, and + * vice-versa for request nodes, CASing from null to a data + * value. (Note that the linearization properties of this style of + * queue are easy to verify -- elements are made available by + * linking, and unavailable by matching.) Compared to plain M&S + * queues, this property of dual queues requires one additional + * successful atomic operation per enq/deq pair. But it also + * enables lower cost variants of queue maintenance mechanics. (A + * variation of this idea applies even for non-dual queues that + * support deletion of interior elements, such as + * j.u.c.ConcurrentLinkedQueue.) + * + * Once a node is matched, its match status can never again + * change. We may thus arrange that the linked list of them + * contain a prefix of zero or more matched nodes, followed by a + * suffix of zero or more unmatched nodes. (Note that we allow + * both the prefix and suffix to be zero length, which in turn + * means that we do not use a dummy header.) If we were not + * concerned with either time or space efficiency, we could + * correctly perform enqueue and dequeue operations by traversing + * from a pointer to the initial node; CASing the item of the + * first unmatched node on match and CASing the next field of the + * trailing node on appends. (Plus some special-casing when + * initially empty). While this would be a terrible idea in + * itself, it does have the benefit of not requiring ANY atomic + * updates on head/tail fields. + * + * We introduce here an approach that lies between the extremes of + * never versus always updating queue (head and tail) pointers. + * This offers a tradeoff between sometimes requiring extra + * traversal steps to locate the first and/or last unmatched + * nodes, versus the reduced overhead and contention of fewer + * updates to queue pointers. For example, a possible snapshot of + * a queue is: + * + * head tail + * | | + * v v + * M -> M -> U -> U -> U -> U + * + * The best value for this "slack" (the targeted maximum distance + * between the value of "head" and the first unmatched node, and + * similarly for "tail") is an empirical matter. We have found + * that using very small constants in the range of 1-3 work best + * over a range of platforms. Larger values introduce increasing + * costs of cache misses and risks of long traversal chains, while + * smaller values increase CAS contention and overhead. + * + * Dual queues with slack differ from plain M&S dual queues by + * virtue of only sometimes updating head or tail pointers when + * matching, appending, or even traversing nodes; in order to + * maintain a targeted slack. The idea of "sometimes" may be + * operationalized in several ways. The simplest is to use a + * per-operation counter incremented on each traversal step, and + * to try (via CAS) to update the associated queue pointer + * whenever the count exceeds a threshold. Another, that requires + * more overhead, is to use random number generators to update + * with a given probability per traversal step. + * + * In any strategy along these lines, because CASes updating + * fields may fail, the actual slack may exceed targeted + * slack. However, they may be retried at any time to maintain + * targets. Even when using very small slack values, this + * approach works well for dual queues because it allows all + * operations up to the point of matching or appending an item + * (hence potentially allowing progress by another thread) to be + * read-only, thus not introducing any further contention. As + * described below, we implement this by performing slack + * maintenance retries only after these points. + * + * As an accompaniment to such techniques, traversal overhead can + * be further reduced without increasing contention of head + * pointer updates: Threads may sometimes shortcut the "next" link + * path from the current "head" node to be closer to the currently + * known first unmatched node, and similarly for tail. Again, this + * may be triggered with using thresholds or randomization. + * + * These ideas must be further extended to avoid unbounded amounts + * of costly-to-reclaim garbage caused by the sequential "next" + * links of nodes starting at old forgotten head nodes: As first + * described in detail by Boehm + * (http://portal.acm.org/citation.cfm?doid=503272.503282) if a GC + * delays noticing that any arbitrarily old node has become + * garbage, all newer dead nodes will also be unreclaimed. + * (Similar issues arise in non-GC environments.) To cope with + * this in our implementation, upon CASing to advance the head + * pointer, we set the "next" link of the previous head to point + * only to itself; thus limiting the length of connected dead lists. + * (We also take similar care to wipe out possibly garbage + * retaining values held in other Node fields.) However, doing so + * adds some further complexity to traversal: If any "next" + * pointer links to itself, it indicates that the current thread + * has lagged behind a head-update, and so the traversal must + * continue from the "head". Traversals trying to find the + * current tail starting from "tail" may also encounter + * self-links, in which case they also continue at "head". + * + * It is tempting in slack-based scheme to not even use CAS for + * updates (similarly to Ladan-Mozes & Shavit). However, this + * cannot be done for head updates under the above link-forgetting + * mechanics because an update may leave head at a detached node. + * And while direct writes are possible for tail updates, they + * increase the risk of long retraversals, and hence long garbage + * chains, which can be much more costly than is worthwhile + * considering that the cost difference of performing a CAS vs + * write is smaller when they are not triggered on each operation + * (especially considering that writes and CASes equally require + * additional GC bookkeeping ("write barriers") that are sometimes + * more costly than the writes themselves because of contention). + * + * Removal of interior nodes (due to timed out or interrupted + * waits, or calls to remove(x) or Iterator.remove) can use a + * scheme roughly similar to that described in Scherer, Lea, and + * Scott's SynchronousQueue. Given a predecessor, we can unsplice + * any node except the (actual) tail of the queue. To avoid + * build-up of cancelled trailing nodes, upon a request to remove + * a trailing node, it is placed in field "cleanMe" to be + * unspliced upon the next call to unsplice any other node. + * Situations needing such mechanics are not common but do occur + * in practice; for example when an unbounded series of short + * timed calls to poll repeatedly time out but never otherwise + * fall off the list because of an untimed call to take at the + * front of the queue. Note that maintaining field cleanMe does + * not otherwise much impact garbage retention even if never + * cleared by some other call because the held node will + * eventually either directly or indirectly lead to a self-link + * once off the list. + * + * *** Overview of implementation *** + * + * We use a threshold-based approach to updates, with a slack + * threshold of two -- that is, we update head/tail when the + * current pointer appears to be two or more steps away from the + * first/last node. The slack value is hard-wired: a path greater + * than one is naturally implemented by checking equality of + * traversal pointers except when the list has only one element, + * in which case we keep slack threshold at one. Avoiding tracking + * explicit counts across method calls slightly simplifies an + * already-messy implementation. Using randomization would + * probably work better if there were a low-quality dirt-cheap + * per-thread one available, but even ThreadLocalRandom is too + * heavy for these purposes. + * + * With such a small slack threshold value, it is rarely + * worthwhile to augment this with path short-circuiting; i.e., + * unsplicing nodes between head and the first unmatched node, or + * similarly for tail, rather than advancing head or tail + * proper. However, it is used (in awaitMatch) immediately before + * a waiting thread starts to block, as a final bit of helping at + * a point when contention with others is extremely unlikely + * (since if other threads that could release it are operating, + * then the current thread wouldn't be blocking). + * + * We allow both the head and tail fields to be null before any + * nodes are enqueued; initializing upon first append. This + * simplifies some other logic, as well as providing more + * efficient explicit control paths instead of letting JVMs insert + * implicit NullPointerExceptions when they are null. While not + * currently fully implemented, we also leave open the possibility + * of re-nulling these fields when empty (which is complicated to + * arrange, for little benefit.) + * + * All enqueue/dequeue operations are handled by the single method + * "xfer" with parameters indicating whether to act as some form + * of offer, put, poll, take, or transfer (each possibly with + * timeout). The relative complexity of using one monolithic + * method outweighs the code bulk and maintenance problems of + * using separate methods for each case. + * + * Operation consists of up to three phases. The first is + * implemented within method xfer, the second in tryAppend, and + * the third in method awaitMatch. + * + * 1. Try to match an existing node + * + * Starting at head, skip already-matched nodes until finding + * an unmatched node of opposite mode, if one exists, in which + * case matching it and returning, also if necessary updating + * head to one past the matched node (or the node itself if the + * list has no other unmatched nodes). If the CAS misses, then + * a loop retries advancing head by two steps until either + * success or the slack is at most two. By requiring that each + * attempt advances head by two (if applicable), we ensure that + * the slack does not grow without bound. Traversals also check + * if the initial head is now off-list, in which case they + * start at the new head. + * + * If no candidates are found and the call was untimed + * poll/offer, (argument "how" is NOW) return. + * + * 2. Try to append a new node (method tryAppend) + * + * Starting at current tail pointer, find the actual last node + * and try to append a new node (or if head was null, establish + * the first node). Nodes can be appended only if their + * predecessors are either already matched or are of the same + * mode. If we detect otherwise, then a new node with opposite + * mode must have been appended during traversal, so we must + * restart at phase 1. The traversal and update steps are + * otherwise similar to phase 1: Retrying upon CAS misses and + * checking for staleness. In particular, if a self-link is + * encountered, then we can safely jump to a node on the list + * by continuing the traversal at current head. + * + * On successful append, if the call was ASYNC, return. + * + * 3. Await match or cancellation (method awaitMatch) + * + * Wait for another thread to match node; instead cancelling if + * the current thread was interrupted or the wait timed out. On + * multiprocessors, we use front-of-queue spinning: If a node + * appears to be the first unmatched node in the queue, it + * spins a bit before blocking. In either case, before blocking + * it tries to unsplice any nodes between the current "head" + * and the first unmatched node. + * + * Front-of-queue spinning vastly improves performance of + * heavily contended queues. And so long as it is relatively + * brief and "quiet", spinning does not much impact performance + * of less-contended queues. During spins threads check their + * interrupt status and generate a thread-local random number + * to decide to occasionally perform a Thread.yield. While + * yield has underdefined specs, we assume that might it help, + * and will not hurt in limiting impact of spinning on busy + * systems. We also use smaller (1/2) spins for nodes that are + * not known to be front but whose predecessors have not + * blocked -- these "chained" spins avoid artifacts of + * front-of-queue rules which otherwise lead to alternating + * nodes spinning vs blocking. Further, front threads that + * represent phase changes (from data to request node or vice + * versa) compared to their predecessors receive additional + * chained spins, reflecting longer paths typically required to + * unblock threads during phase changes. + */ + + /** True if on multiprocessor */ + private static final boolean MP = + Runtime.getRuntime().availableProcessors() > 1; + + /** + * The number of times to spin (with randomly interspersed calls + * to Thread.yield) on multiprocessor before blocking when a node + * is apparently the first waiter in the queue. See above for + * explanation. Must be a power of two. The value is empirically + * derived -- it works pretty well across a variety of processors, + * numbers of CPUs, and OSes. + */ + private static final int FRONT_SPINS = 1 << 7; + + /** + * The number of times to spin before blocking when a node is + * preceded by another node that is apparently spinning. Also + * serves as an increment to FRONT_SPINS on phase changes, and as + * base average frequency for yielding during spins. Must be a + * power of two. + */ + private static final int CHAINED_SPINS = FRONT_SPINS >>> 1; + + /** + * Queue nodes. Uses Object, not E, for items to allow forgetting + * them after use. Relies heavily on Unsafe mechanics to minimize + * unnecessary ordering constraints: Writes that intrinsically + * precede or follow CASes use simple relaxed forms. Other + * cleanups use releasing/lazy writes. + */ + static final class Node { + final boolean isData; // false if this is a request node + volatile Object item; // initially non-null if isData; CASed to match + volatile Node next; + volatile Thread waiter; // null until waiting + + // CAS methods for fields + final boolean casNext(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val); + } + + final boolean casItem(Object cmp, Object val) { + // assert cmp == null || cmp.getClass() != Node.class; + return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val); + } + + /** + * Creates a new node. Uses relaxed write because item can only + * be seen if followed by CAS. + */ + Node(Object item, boolean isData) { + UNSAFE.putObject(this, itemOffset, item); // relaxed write + this.isData = isData; + } + + /** + * Links node to itself to avoid garbage retention. Called + * only after CASing head field, so uses relaxed write. + */ + final void forgetNext() { + UNSAFE.putObject(this, nextOffset, this); + } + + /** + * Sets item to self (using a releasing/lazy write) and waiter + * to null, to avoid garbage retention after extracting or + * cancelling. + */ + final void forgetContents() { + UNSAFE.putOrderedObject(this, itemOffset, this); + UNSAFE.putOrderedObject(this, waiterOffset, null); + } + + /** + * Returns true if this node has been matched, including the + * case of artificial matches due to cancellation. + */ + final boolean isMatched() { + Object x = item; + return (x == this) || ((x == null) == isData); + } + + /** + * Returns true if this is an unmatched request node. + */ + final boolean isUnmatchedRequest() { + return !isData && item == null; + } + + /** + * Returns true if a node with the given mode cannot be + * appended to this node because this node is unmatched and + * has opposite data mode. + */ + final boolean cannotPrecede(boolean haveData) { + boolean d = isData; + Object x; + return d != haveData && (x = item) != this && (x != null) == d; + } + + /** + * Tries to artificially match a data node -- used by remove. + */ + final boolean tryMatchData() { + // assert isData; + Object x = item; + if (x != null && x != this && casItem(x, null)) { + LockSupport.unpark(waiter); + return true; + } + return false; + } + + // Unsafe mechanics + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + private static final long nextOffset = + objectFieldOffset(UNSAFE, "next", Node.class); + private static final long itemOffset = + objectFieldOffset(UNSAFE, "item", Node.class); + private static final long waiterOffset = + objectFieldOffset(UNSAFE, "waiter", Node.class); + + private static final long serialVersionUID = -3375979862319811754L; + } + + /** head of the queue; null until first enqueue */ + transient volatile Node head; + + /** predecessor of dangling unspliceable node */ + private transient volatile Node cleanMe; // decl here reduces contention + + /** tail of the queue; null until first append */ + private transient volatile Node tail; + + // CAS methods for fields + private boolean casTail(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val); + } + + private boolean casHead(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); + } + + private boolean casCleanMe(Node cmp, Node val) { + return UNSAFE.compareAndSwapObject(this, cleanMeOffset, cmp, val); + } + + /* + * Possible values for "how" argument in xfer method. + */ + private static final int NOW = 0; // for untimed poll, tryTransfer + private static final int ASYNC = 1; // for offer, put, add + private static final int SYNC = 2; // for transfer, take + private static final int TIMED = 3; // for timed poll, tryTransfer + + @SuppressWarnings("unchecked") + static <E> E cast(Object item) { + // assert item == null || item.getClass() != Node.class; + return (E) item; + } + + /** + * Implements all queuing methods. See above for explanation. + * + * @param e the item or null for take + * @param haveData true if this is a put, else a take + * @param how NOW, ASYNC, SYNC, or TIMED + * @param nanos timeout in nanosecs, used only if mode is TIMED + * @return an item if matched, else e + * @throws NullPointerException if haveData mode but e is null + */ + private E xfer(E e, boolean haveData, int how, long nanos) { + if (haveData && (e == null)) + throw new NullPointerException(); + Node s = null; // the node to append, if needed + + retry: for (;;) { // restart on append race + + for (Node h = head, p = h; p != null;) { // find & match first node + boolean isData = p.isData; + Object item = p.item; + if (item != p && (item != null) == isData) { // unmatched + if (isData == haveData) // can't match + break; + if (p.casItem(item, e)) { // match + for (Node q = p; q != h;) { + Node n = q.next; // update head by 2 + if (n != null) // unless singleton + q = n; + if (head == h && casHead(h, q)) { + h.forgetNext(); + break; + } // advance and retry + if ((h = head) == null || + (q = h.next) == null || !q.isMatched()) + break; // unless slack < 2 + } + LockSupport.unpark(p.waiter); + return this.<E>cast(item); + } + } + Node n = p.next; + p = (p != n) ? n : (h = head); // Use head if p offlist + } + + if (how != NOW) { // No matches available + if (s == null) + s = new Node(e, haveData); + Node pred = tryAppend(s, haveData); + if (pred == null) + continue retry; // lost race vs opposite mode + if (how != ASYNC) + return awaitMatch(s, pred, e, (how == TIMED), nanos); + } + return e; // not waiting + } + } + + /** + * Tries to append node s as tail. + * + * @param s the node to append + * @param haveData true if appending in data mode + * @return null on failure due to losing race with append in + * different mode, else s's predecessor, or s itself if no + * predecessor + */ + private Node tryAppend(Node s, boolean haveData) { + for (Node t = tail, p = t;;) { // move p to last node and append + Node n, u; // temps for reads of next & tail + if (p == null && (p = head) == null) { + if (casHead(null, s)) + return s; // initialize + } + else if (p.cannotPrecede(haveData)) + return null; // lost race vs opposite mode + else if ((n = p.next) != null) // not last; keep traversing + p = p != t && t != (u = tail) ? (t = u) : // stale tail + (p != n) ? n : null; // restart if off list + else if (!p.casNext(null, s)) + p = p.next; // re-read on CAS failure + else { + if (p != t) { // update if slack now >= 2 + while ((tail != t || !casTail(t, s)) && + (t = tail) != null && + (s = t.next) != null && // advance and retry + (s = s.next) != null && s != t); + } + return p; + } + } + } + + /** + * Spins/yields/blocks until node s is matched or caller gives up. + * + * @param s the waiting node + * @param pred the predecessor of s, or s itself if it has no + * predecessor, or null if unknown (the null case does not occur + * in any current calls but may in possible future extensions) + * @param e the comparison value for checking match + * @param timed if true, wait only until timeout elapses + * @param nanos timeout in nanosecs, used only if timed is true + * @return matched item, or e if unmatched on interrupt or timeout + */ + private E awaitMatch(Node s, Node pred, E e, boolean timed, long nanos) { + long lastTime = timed ? System.nanoTime() : 0L; + Thread w = Thread.currentThread(); + int spins = -1; // initialized after first item and cancel checks + ThreadLocalRandom randomYields = null; // bound if needed + + for (;;) { + Object item = s.item; + if (item != e) { // matched + // assert item != s; + s.forgetContents(); // avoid garbage + return this.<E>cast(item); + } + if ((w.isInterrupted() || (timed && nanos <= 0)) && + s.casItem(e, s)) { // cancel + unsplice(pred, s); + return e; + } + + if (spins < 0) { // establish spins at/near front + if ((spins = spinsFor(pred, s.isData)) > 0) + randomYields = ThreadLocalRandom.current(); + } + else if (spins > 0) { // spin + if (--spins == 0) + shortenHeadPath(); // reduce slack before blocking + else if (randomYields.nextInt(CHAINED_SPINS) == 0) + Thread.yield(); // occasionally yield + } + else if (s.waiter == null) { + s.waiter = w; // request unpark then recheck + } + else if (timed) { + long now = System.nanoTime(); + if ((nanos -= now - lastTime) > 0) + LockSupport.parkNanos(this, nanos); + lastTime = now; + } + else { + LockSupport.park(this); + s.waiter = null; + spins = -1; // spin if front upon wakeup + } + } + } + + /** + * Returns spin/yield value for a node with given predecessor and + * data mode. See above for explanation. + */ + private static int spinsFor(Node pred, boolean haveData) { + if (MP && pred != null) { + if (pred.isData != haveData) // phase change + return FRONT_SPINS + CHAINED_SPINS; + if (pred.isMatched()) // probably at front + return FRONT_SPINS; + if (pred.waiter == null) // pred apparently spinning + return CHAINED_SPINS; + } + return 0; + } + + /** + * Tries (once) to unsplice nodes between head and first unmatched + * or trailing node; failing on contention. + */ + private void shortenHeadPath() { + Node h, hn, p, q; + if ((p = h = head) != null && h.isMatched() && + (q = hn = h.next) != null) { + Node n; + while ((n = q.next) != q) { + if (n == null || !q.isMatched()) { + if (hn != q && h.next == hn) + h.casNext(hn, q); + break; + } + p = q; + q = n; + } + } + } + + /* -------------- Traversal methods -------------- */ + + /** + * Returns the successor of p, or the head node if p.next has been + * linked to self, which will only be true if traversing with a + * stale pointer that is now off the list. + */ + final Node succ(Node p) { + Node next = p.next; + return (p == next) ? head : next; + } + + /** + * Returns the first unmatched node of the given mode, or null if + * none. Used by methods isEmpty, hasWaitingConsumer. + */ + private Node firstOfMode(boolean isData) { + for (Node p = head; p != null; p = succ(p)) { + if (!p.isMatched()) + return (p.isData == isData) ? p : null; + } + return null; + } + + /** + * Returns the item in the first unmatched node with isData; or + * null if none. Used by peek. + */ + private E firstDataItem() { + for (Node p = head; p != null; p = succ(p)) { + Object item = p.item; + if (p.isData) { + if (item != null && item != p) + return this.<E>cast(item); + } + else if (item == null) + return null; + } + return null; + } + + /** + * Traverses and counts unmatched nodes of the given mode. + * Used by methods size and getWaitingConsumerCount. + */ + private int countOfMode(boolean data) { + int count = 0; + for (Node p = head; p != null; ) { + if (!p.isMatched()) { + if (p.isData != data) + return 0; + if (++count == Integer.MAX_VALUE) // saturated + break; + } + Node n = p.next; + if (n != p) + p = n; + else { + count = 0; + p = head; + } + } + return count; + } + + final class Itr implements Iterator<E> { + private Node nextNode; // next node to return item for + private E nextItem; // the corresponding item + private Node lastRet; // last returned node, to support remove + private Node lastPred; // predecessor to unlink lastRet + + /** + * Moves to next node after prev, or first node if prev null. + */ + private void advance(Node prev) { + lastPred = lastRet; + lastRet = prev; + for (Node p = (prev == null) ? head : succ(prev); + p != null; p = succ(p)) { + Object item = p.item; + if (p.isData) { + if (item != null && item != p) { + nextItem = LinkedTransferQueue.this.<E>cast(item); + nextNode = p; + return; + } + } + else if (item == null) + break; + } + nextNode = null; + } + + Itr() { + advance(null); + } + + public final boolean hasNext() { + return nextNode != null; + } + + public final E next() { + Node p = nextNode; + if (p == null) throw new NoSuchElementException(); + E e = nextItem; + advance(p); + return e; + } + + public final void remove() { + Node p = lastRet; + if (p == null) throw new IllegalStateException(); + findAndRemoveDataNode(lastPred, p); + } + } + + /* -------------- Removal methods -------------- */ + + /** + * Unsplices (now or later) the given deleted/cancelled node with + * the given predecessor. + * + * @param pred predecessor of node to be unspliced + * @param s the node to be unspliced + */ + private void unsplice(Node pred, Node s) { + s.forgetContents(); // clear unneeded fields + /* + * At any given time, exactly one node on list cannot be + * unlinked -- the last inserted node. To accommodate this, if + * we cannot unlink s, we save its predecessor as "cleanMe", + * processing the previously saved version first. Because only + * one node in the list can have a null next, at least one of + * node s or the node previously saved can always be + * processed, so this always terminates. + */ + if (pred != null && pred != s) { + while (pred.next == s) { + Node oldpred = (cleanMe == null) ? null : reclean(); + Node n = s.next; + if (n != null) { + if (n != s) + pred.casNext(s, n); + break; + } + if (oldpred == pred || // Already saved + ((oldpred == null || oldpred.next == s) && + casCleanMe(oldpred, pred))) { + break; + } + } + } + } + + /** + * Tries to unsplice the deleted/cancelled node held in cleanMe + * that was previously uncleanable because it was at tail. + * + * @return current cleanMe node (or null) + */ + private Node reclean() { + /* + * cleanMe is, or at one time was, predecessor of a cancelled + * node s that was the tail so could not be unspliced. If it + * is no longer the tail, try to unsplice if necessary and + * make cleanMe slot available. This differs from similar + * code in unsplice() because we must check that pred still + * points to a matched node that can be unspliced -- if not, + * we can (must) clear cleanMe without unsplicing. This can + * loop only due to contention. + */ + Node pred; + while ((pred = cleanMe) != null) { + Node s = pred.next; + Node n; + if (s == null || s == pred || !s.isMatched()) + casCleanMe(pred, null); // already gone + else if ((n = s.next) != null) { + if (n != s) + pred.casNext(s, n); + casCleanMe(pred, null); + } + else + break; + } + return pred; + } + + /** + * Main implementation of Iterator.remove(). Finds + * and unsplices the given data node. + * + * @param possiblePred possible predecessor of s + * @param s the node to remove + */ + final void findAndRemoveDataNode(Node possiblePred, Node s) { + // assert s.isData; + if (s.tryMatchData()) { + if (possiblePred != null && possiblePred.next == s) + unsplice(possiblePred, s); // was actual predecessor + else { + for (Node pred = null, p = head; p != null; ) { + if (p == s) { + unsplice(pred, p); + break; + } + if (p.isUnmatchedRequest()) + break; + pred = p; + if ((p = p.next) == pred) { // stale + pred = null; + p = head; + } + } + } + } + } + + /** + * Main implementation of remove(Object) + */ + private boolean findAndRemove(Object e) { + if (e != null) { + for (Node pred = null, p = head; p != null; ) { + Object item = p.item; + if (p.isData) { + if (item != null && item != p && e.equals(item) && + p.tryMatchData()) { + unsplice(pred, p); + return true; + } + } + else if (item == null) + break; + pred = p; + if ((p = p.next) == pred) { // stale + pred = null; + p = head; + } + } + } + return false; + } + + + /** + * Creates an initially empty {@code LinkedTransferQueue}. + */ + public LinkedTransferQueue() { + } + + /** + * Creates a {@code LinkedTransferQueue} + * initially containing the elements of the given collection, + * added in traversal order of the collection's iterator. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public LinkedTransferQueue(Collection<? extends E> c) { + this(); + addAll(c); + } + + /** + * Inserts the specified element at the tail of this queue. + * As the queue is unbounded, this method will never block. + * + * @throws NullPointerException if the specified element is null + */ + public void put(E e) { + xfer(e, true, ASYNC, 0); + } + + /** + * Inserts the specified element at the tail of this queue. + * As the queue is unbounded, this method will never block or + * return {@code false}. + * + * @return {@code true} (as specified by + * {@link BlockingQueue#offer(Object,long,TimeUnit) BlockingQueue.offer}) + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e, long timeout, TimeUnit unit) { + xfer(e, true, ASYNC, 0); + return true; + } + + /** + * Inserts the specified element at the tail of this queue. + * As the queue is unbounded, this method will never return {@code false}. + * + * @return {@code true} (as specified by + * {@link BlockingQueue#offer(Object) BlockingQueue.offer}) + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + xfer(e, true, ASYNC, 0); + return true; + } + + /** + * Inserts the specified element at the tail of this queue. + * As the queue is unbounded, this method will never throw + * {@link IllegalStateException} or return {@code false}. + * + * @return {@code true} (as specified by {@link Collection#add}) + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + xfer(e, true, ASYNC, 0); + return true; + } + + /** + * Transfers the element to a waiting consumer immediately, if possible. + * + * <p>More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * otherwise returning {@code false} without enqueuing the element. + * + * @throws NullPointerException if the specified element is null + */ + public boolean tryTransfer(E e) { + return xfer(e, true, NOW, 0) == null; + } + + /** + * Transfers the element to a consumer, waiting if necessary to do so. + * + * <p>More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * else inserts the specified element at the tail of this queue + * and waits until the element is received by a consumer. + * + * @throws NullPointerException if the specified element is null + */ + public void transfer(E e) throws InterruptedException { + if (xfer(e, true, SYNC, 0) != null) { + Thread.interrupted(); // failure possible only due to interrupt + throw new InterruptedException(); + } + } + + /** + * Transfers the element to a consumer if it is possible to do so + * before the timeout elapses. + * + * <p>More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * else inserts the specified element at the tail of this queue + * and waits until the element is received by a consumer, + * returning {@code false} if the specified wait time elapses + * before the element can be transferred. + * + * @throws NullPointerException if the specified element is null + */ + public boolean tryTransfer(E e, long timeout, TimeUnit unit) + throws InterruptedException { + if (xfer(e, true, TIMED, unit.toNanos(timeout)) == null) + return true; + if (!Thread.interrupted()) + return false; + throw new InterruptedException(); + } + + public E take() throws InterruptedException { + E e = xfer(null, false, SYNC, 0); + if (e != null) + return e; + Thread.interrupted(); + throw new InterruptedException(); + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + E e = xfer(null, false, TIMED, unit.toNanos(timeout)); + if (e != null || !Thread.interrupted()) + return e; + throw new InterruptedException(); + } + + public E poll() { + return xfer(null, false, NOW, 0); + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + int n = 0; + E e; + while ( (e = poll()) != null) { + c.add(e); + ++n; + } + return n; + } + + /** + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + int n = 0; + E e; + while (n < maxElements && (e = poll()) != null) { + c.add(e); + ++n; + } + return n; + } + + /** + * Returns an iterator over the elements in this queue in proper + * sequence, from head to tail. + * + * <p>The returned iterator is a "weakly consistent" iterator that + * will never throw + * {@link ConcurrentModificationException ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed + * to) reflect any modifications subsequent to construction. + * + * @return an iterator over the elements in this queue in proper sequence + */ + public Iterator<E> iterator() { + return new Itr(); + } + + public E peek() { + return firstDataItem(); + } + + /** + * Returns {@code true} if this queue contains no elements. + * + * @return {@code true} if this queue contains no elements + */ + public boolean isEmpty() { + return firstOfMode(true) == null; + } + + public boolean hasWaitingConsumer() { + return firstOfMode(false) != null; + } + + /** + * Returns the number of elements in this queue. If this queue + * contains more than {@code Integer.MAX_VALUE} elements, returns + * {@code Integer.MAX_VALUE}. + * + * <p>Beware that, unlike in most collections, this method is + * <em>NOT</em> a constant-time operation. Because of the + * asynchronous nature of these queues, determining the current + * number of elements requires an O(n) traversal. + * + * @return the number of elements in this queue + */ + public int size() { + return countOfMode(true); + } + + public int getWaitingConsumerCount() { + return countOfMode(false); + } + + /** + * Removes a single instance of the specified element from this queue, + * if it is present. More formally, removes an element {@code e} such + * that {@code o.equals(e)}, if this queue contains one or more such + * elements. + * Returns {@code true} if this queue contained the specified element + * (or equivalently, if this queue changed as a result of the call). + * + * @param o element to be removed from this queue, if present + * @return {@code true} if this queue changed as a result of the call + */ + public boolean remove(Object o) { + return findAndRemove(o); + } + + /** + * Always returns {@code Integer.MAX_VALUE} because a + * {@code LinkedTransferQueue} is not capacity constrained. + * + * @return {@code Integer.MAX_VALUE} (as specified by + * {@link BlockingQueue#remainingCapacity()}) + */ + public int remainingCapacity() { + return Integer.MAX_VALUE; + } + + /** + * Saves the state to a stream (that is, serializes it). + * + * @serialData All of the elements (each an {@code E}) in + * the proper order, followed by a null + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + for (E e : this) + s.writeObject(e); + // Use trailing null as sentinel + s.writeObject(null); + } + + /** + * Reconstitutes the Queue instance from a stream (that is, + * deserializes it). + * + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + for (;;) { + @SuppressWarnings("unchecked") E item = (E) s.readObject(); + if (item == null) + break; + else + offer(item); + } + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + private static final long headOffset = + objectFieldOffset(UNSAFE, "head", LinkedTransferQueue.class); + private static final long tailOffset = + objectFieldOffset(UNSAFE, "tail", LinkedTransferQueue.class); + private static final long cleanMeOffset = + objectFieldOffset(UNSAFE, "cleanMe", LinkedTransferQueue.class); + + static long objectFieldOffset(sun.misc.Unsafe UNSAFE, + String field, Class<?> klazz) { + try { + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/util/concurrent/Phaser.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,1042 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.LockSupport; + +/** + * A reusable synchronization barrier, similar in functionality to + * {@link java.util.concurrent.CyclicBarrier CyclicBarrier} and + * {@link java.util.concurrent.CountDownLatch CountDownLatch} + * but supporting more flexible usage. + * + * <p> <b>Registration.</b> Unlike the case for other barriers, the + * number of parties <em>registered</em> to synchronize on a phaser + * may vary over time. Tasks may be registered at any time (using + * methods {@link #register}, {@link #bulkRegister}, or forms of + * constructors establishing initial numbers of parties), and + * optionally deregistered upon any arrival (using {@link + * #arriveAndDeregister}). As is the case with most basic + * synchronization constructs, registration and deregistration affect + * only internal counts; they do not establish any further internal + * bookkeeping, so tasks cannot query whether they are registered. + * (However, you can introduce such bookkeeping by subclassing this + * class.) + * + * <p> <b>Synchronization.</b> Like a {@code CyclicBarrier}, a {@code + * Phaser} may be repeatedly awaited. Method {@link + * #arriveAndAwaitAdvance} has effect analogous to {@link + * java.util.concurrent.CyclicBarrier#await CyclicBarrier.await}. Each + * generation of a {@code Phaser} has an associated phase number. The + * phase number starts at zero, and advances when all parties arrive + * at the barrier, wrapping around to zero after reaching {@code + * Integer.MAX_VALUE}. The use of phase numbers enables independent + * control of actions upon arrival at a barrier and upon awaiting + * others, via two kinds of methods that may be invoked by any + * registered party: + * + * <ul> + * + * <li> <b>Arrival.</b> Methods {@link #arrive} and + * {@link #arriveAndDeregister} record arrival at a + * barrier. These methods do not block, but return an associated + * <em>arrival phase number</em>; that is, the phase number of + * the barrier to which the arrival applied. When the final + * party for a given phase arrives, an optional barrier action + * is performed and the phase advances. Barrier actions, + * performed by the party triggering a phase advance, are + * arranged by overriding method {@link #onAdvance(int, int)}, + * which also controls termination. Overriding this method is + * similar to, but more flexible than, providing a barrier + * action to a {@code CyclicBarrier}. + * + * <li> <b>Waiting.</b> Method {@link #awaitAdvance} requires an + * argument indicating an arrival phase number, and returns when + * the barrier advances to (or is already at) a different phase. + * Unlike similar constructions using {@code CyclicBarrier}, + * method {@code awaitAdvance} continues to wait even if the + * waiting thread is interrupted. Interruptible and timeout + * versions are also available, but exceptions encountered while + * tasks wait interruptibly or with timeout do not change the + * state of the barrier. If necessary, you can perform any + * associated recovery within handlers of those exceptions, + * often after invoking {@code forceTermination}. Phasers may + * also be used by tasks executing in a {@link ForkJoinPool}, + * which will ensure sufficient parallelism to execute tasks + * when others are blocked waiting for a phase to advance. + * + * </ul> + * + * <p> <b>Termination.</b> A {@code Phaser} may enter a + * <em>termination</em> state in which all synchronization methods + * immediately return without updating phaser state or waiting for + * advance, and indicating (via a negative phase value) that execution + * is complete. Termination is triggered when an invocation of {@code + * onAdvance} returns {@code true}. As illustrated below, when + * phasers control actions with a fixed number of iterations, it is + * often convenient to override this method to cause termination when + * the current phase number reaches a threshold. Method {@link + * #forceTermination} is also available to abruptly release waiting + * threads and allow them to terminate. + * + * <p> <b>Tiering.</b> Phasers may be <em>tiered</em> (i.e., arranged + * in tree structures) to reduce contention. Phasers with large + * numbers of parties that would otherwise experience heavy + * synchronization contention costs may instead be set up so that + * groups of sub-phasers share a common parent. This may greatly + * increase throughput even though it incurs greater per-operation + * overhead. + * + * <p><b>Monitoring.</b> While synchronization methods may be invoked + * only by registered parties, the current state of a phaser may be + * monitored by any caller. At any given moment there are {@link + * #getRegisteredParties} parties in total, of which {@link + * #getArrivedParties} have arrived at the current phase ({@link + * #getPhase}). When the remaining ({@link #getUnarrivedParties}) + * parties arrive, the phase advances. The values returned by these + * methods may reflect transient states and so are not in general + * useful for synchronization control. Method {@link #toString} + * returns snapshots of these state queries in a form convenient for + * informal monitoring. + * + * <p><b>Sample usages:</b> + * + * <p>A {@code Phaser} may be used instead of a {@code CountDownLatch} + * to control a one-shot action serving a variable number of + * parties. The typical idiom is for the method setting this up to + * first register, then start the actions, then deregister, as in: + * + * <pre> {@code + * void runTasks(List<Runnable> tasks) { + * final Phaser phaser = new Phaser(1); // "1" to register self + * // create and start threads + * for (Runnable task : tasks) { + * phaser.register(); + * new Thread() { + * public void run() { + * phaser.arriveAndAwaitAdvance(); // await all creation + * task.run(); + * } + * }.start(); + * } + * + * // allow threads to start and deregister self + * phaser.arriveAndDeregister(); + * }}</pre> + * + * <p>One way to cause a set of threads to repeatedly perform actions + * for a given number of iterations is to override {@code onAdvance}: + * + * <pre> {@code + * void startTasks(List<Runnable> tasks, final int iterations) { + * final Phaser phaser = new Phaser() { + * protected boolean onAdvance(int phase, int registeredParties) { + * return phase >= iterations || registeredParties == 0; + * } + * }; + * phaser.register(); + * for (final Runnable task : tasks) { + * phaser.register(); + * new Thread() { + * public void run() { + * do { + * task.run(); + * phaser.arriveAndAwaitAdvance(); + * } while (!phaser.isTerminated()); + * } + * }.start(); + * } + * phaser.arriveAndDeregister(); // deregister self, don't wait + * }}</pre> + * + * If the main task must later await termination, it + * may re-register and then execute a similar loop: + * <pre> {@code + * // ... + * phaser.register(); + * while (!phaser.isTerminated()) + * phaser.arriveAndAwaitAdvance();}</pre> + * + * <p>Related constructions may be used to await particular phase numbers + * in contexts where you are sure that the phase will never wrap around + * {@code Integer.MAX_VALUE}. For example: + * + * <pre> {@code + * void awaitPhase(Phaser phaser, int phase) { + * int p = phaser.register(); // assumes caller not already registered + * while (p < phase) { + * if (phaser.isTerminated()) + * // ... deal with unexpected termination + * else + * p = phaser.arriveAndAwaitAdvance(); + * } + * phaser.arriveAndDeregister(); + * }}</pre> + * + * + * <p>To create a set of tasks using a tree of phasers, + * you could use code of the following form, assuming a + * Task class with a constructor accepting a phaser that + * it registers for upon construction: + * + * <pre> {@code + * void build(Task[] actions, int lo, int hi, Phaser ph) { + * if (hi - lo > TASKS_PER_PHASER) { + * for (int i = lo; i < hi; i += TASKS_PER_PHASER) { + * int j = Math.min(i + TASKS_PER_PHASER, hi); + * build(actions, i, j, new Phaser(ph)); + * } + * } else { + * for (int i = lo; i < hi; ++i) + * actions[i] = new Task(ph); + * // assumes new Task(ph) performs ph.register() + * } + * } + * // .. initially called, for n tasks via + * build(new Task[n], 0, n, new Phaser());}</pre> + * + * The best value of {@code TASKS_PER_PHASER} depends mainly on + * expected barrier synchronization rates. A value as low as four may + * be appropriate for extremely small per-barrier task bodies (thus + * high rates), or up to hundreds for extremely large ones. + * + * </pre> + * + * <p><b>Implementation notes</b>: This implementation restricts the + * maximum number of parties to 65535. Attempts to register additional + * parties result in {@code IllegalStateException}. However, you can and + * should create tiered phasers to accommodate arbitrarily large sets + * of participants. + * + * @since 1.7 + * @author Doug Lea + */ +public class Phaser { + /* + * This class implements an extension of X10 "clocks". Thanks to + * Vijay Saraswat for the idea, and to Vivek Sarkar for + * enhancements to extend functionality. + */ + + /** + * Barrier state representation. Conceptually, a barrier contains + * four values: + * + * * parties -- the number of parties to wait (16 bits) + * * unarrived -- the number of parties yet to hit barrier (16 bits) + * * phase -- the generation of the barrier (31 bits) + * * terminated -- set if barrier is terminated (1 bit) + * + * However, to efficiently maintain atomicity, these values are + * packed into a single (atomic) long. Termination uses the sign + * bit of 32 bit representation of phase, so phase is set to -1 on + * termination. Good performance relies on keeping state decoding + * and encoding simple, and keeping race windows short. + * + * Note: there are some cheats in arrive() that rely on unarrived + * count being lowest 16 bits. + */ + private volatile long state; + + private static final int ushortMask = 0xffff; + private static final int phaseMask = 0x7fffffff; + + private static int unarrivedOf(long s) { + return (int) (s & ushortMask); + } + + private static int partiesOf(long s) { + return ((int) s) >>> 16; + } + + private static int phaseOf(long s) { + return (int) (s >>> 32); + } + + private static int arrivedOf(long s) { + return partiesOf(s) - unarrivedOf(s); + } + + private static long stateFor(int phase, int parties, int unarrived) { + return ((((long) phase) << 32) | (((long) parties) << 16) | + (long) unarrived); + } + + private static long trippedStateFor(int phase, int parties) { + long lp = (long) parties; + return (((long) phase) << 32) | (lp << 16) | lp; + } + + /** + * Returns message string for bad bounds exceptions. + */ + private static String badBounds(int parties, int unarrived) { + return ("Attempt to set " + unarrived + + " unarrived of " + parties + " parties"); + } + + /** + * The parent of this phaser, or null if none + */ + private final Phaser parent; + + /** + * The root of phaser tree. Equals this if not in a tree. Used to + * support faster state push-down. + */ + private final Phaser root; + + // Wait queues + + /** + * Heads of Treiber stacks for waiting threads. To eliminate + * contention while releasing some threads while adding others, we + * use two of them, alternating across even and odd phases. + */ + private final AtomicReference<QNode> evenQ = new AtomicReference<QNode>(); + private final AtomicReference<QNode> oddQ = new AtomicReference<QNode>(); + + private AtomicReference<QNode> queueFor(int phase) { + return ((phase & 1) == 0) ? evenQ : oddQ; + } + + /** + * Returns current state, first resolving lagged propagation from + * root if necessary. + */ + private long getReconciledState() { + return (parent == null) ? state : reconcileState(); + } + + /** + * Recursively resolves state. + */ + private long reconcileState() { + Phaser p = parent; + long s = state; + if (p != null) { + while (unarrivedOf(s) == 0 && phaseOf(s) != phaseOf(root.state)) { + long parentState = p.getReconciledState(); + int parentPhase = phaseOf(parentState); + int phase = phaseOf(s = state); + if (phase != parentPhase) { + long next = trippedStateFor(parentPhase, partiesOf(s)); + if (casState(s, next)) { + releaseWaiters(phase); + s = next; + } + } + } + } + return s; + } + + /** + * Creates a new phaser without any initially registered parties, + * initial phase number 0, and no parent. Any thread using this + * phaser will need to first register for it. + */ + public Phaser() { + this(null); + } + + /** + * Creates a new phaser with the given numbers of registered + * unarrived parties, initial phase number 0, and no parent. + * + * @param parties the number of parties required to trip barrier + * @throws IllegalArgumentException if parties less than zero + * or greater than the maximum number of parties supported + */ + public Phaser(int parties) { + this(null, parties); + } + + /** + * Creates a new phaser with the given parent, without any + * initially registered parties. If parent is non-null this phaser + * is registered with the parent and its initial phase number is + * the same as that of parent phaser. + * + * @param parent the parent phaser + */ + public Phaser(Phaser parent) { + int phase = 0; + this.parent = parent; + if (parent != null) { + this.root = parent.root; + phase = parent.register(); + } + else + this.root = this; + this.state = trippedStateFor(phase, 0); + } + + /** + * Creates a new phaser with the given parent and numbers of + * registered unarrived parties. If parent is non-null, this phaser + * is registered with the parent and its initial phase number is + * the same as that of parent phaser. + * + * @param parent the parent phaser + * @param parties the number of parties required to trip barrier + * @throws IllegalArgumentException if parties less than zero + * or greater than the maximum number of parties supported + */ + public Phaser(Phaser parent, int parties) { + if (parties < 0 || parties > ushortMask) + throw new IllegalArgumentException("Illegal number of parties"); + int phase = 0; + this.parent = parent; + if (parent != null) { + this.root = parent.root; + phase = parent.register(); + } + else + this.root = this; + this.state = trippedStateFor(phase, parties); + } + + /** + * Adds a new unarrived party to this phaser. + * + * @return the arrival phase number to which this registration applied + * @throws IllegalStateException if attempting to register more + * than the maximum supported number of parties + */ + public int register() { + return doRegister(1); + } + + /** + * Adds the given number of new unarrived parties to this phaser. + * + * @param parties the number of parties required to trip barrier + * @return the arrival phase number to which this registration applied + * @throws IllegalStateException if attempting to register more + * than the maximum supported number of parties + */ + public int bulkRegister(int parties) { + if (parties < 0) + throw new IllegalArgumentException(); + if (parties == 0) + return getPhase(); + return doRegister(parties); + } + + /** + * Shared code for register, bulkRegister + */ + private int doRegister(int registrations) { + int phase; + for (;;) { + long s = getReconciledState(); + phase = phaseOf(s); + int unarrived = unarrivedOf(s) + registrations; + int parties = partiesOf(s) + registrations; + if (phase < 0) + break; + if (parties > ushortMask || unarrived > ushortMask) + throw new IllegalStateException(badBounds(parties, unarrived)); + if (phase == phaseOf(root.state) && + casState(s, stateFor(phase, parties, unarrived))) + break; + } + return phase; + } + + /** + * Arrives at the barrier, but does not wait for others. (You can + * in turn wait for others via {@link #awaitAdvance}). It is an + * unenforced usage error for an unregistered party to invoke this + * method. + * + * @return the arrival phase number, or a negative value if terminated + * @throws IllegalStateException if not terminated and the number + * of unarrived parties would become negative + */ + public int arrive() { + int phase; + for (;;) { + long s = state; + phase = phaseOf(s); + if (phase < 0) + break; + int parties = partiesOf(s); + int unarrived = unarrivedOf(s) - 1; + if (unarrived > 0) { // Not the last arrival + if (casState(s, s - 1)) // s-1 adds one arrival + break; + } + else if (unarrived == 0) { // the last arrival + Phaser par = parent; + if (par == null) { // directly trip + if (casState + (s, + trippedStateFor(onAdvance(phase, parties) ? -1 : + ((phase + 1) & phaseMask), parties))) { + releaseWaiters(phase); + break; + } + } + else { // cascade to parent + if (casState(s, s - 1)) { // zeroes unarrived + par.arrive(); + reconcileState(); + break; + } + } + } + else if (phase != phaseOf(root.state)) // or if unreconciled + reconcileState(); + else + throw new IllegalStateException(badBounds(parties, unarrived)); + } + return phase; + } + + /** + * Arrives at the barrier and deregisters from it without waiting + * for others. Deregistration reduces the number of parties + * required to trip the barrier in future phases. If this phaser + * has a parent, and deregistration causes this phaser to have + * zero parties, this phaser also arrives at and is deregistered + * from its parent. It is an unenforced usage error for an + * unregistered party to invoke this method. + * + * @return the arrival phase number, or a negative value if terminated + * @throws IllegalStateException if not terminated and the number + * of registered or unarrived parties would become negative + */ + public int arriveAndDeregister() { + // similar code to arrive, but too different to merge + Phaser par = parent; + int phase; + for (;;) { + long s = state; + phase = phaseOf(s); + if (phase < 0) + break; + int parties = partiesOf(s) - 1; + int unarrived = unarrivedOf(s) - 1; + if (parties >= 0) { + if (unarrived > 0 || (unarrived == 0 && par != null)) { + if (casState + (s, + stateFor(phase, parties, unarrived))) { + if (unarrived == 0) { + par.arriveAndDeregister(); + reconcileState(); + } + break; + } + continue; + } + if (unarrived == 0) { + if (casState + (s, + trippedStateFor(onAdvance(phase, parties) ? -1 : + ((phase + 1) & phaseMask), parties))) { + releaseWaiters(phase); + break; + } + continue; + } + if (par != null && phase != phaseOf(root.state)) { + reconcileState(); + continue; + } + } + throw new IllegalStateException(badBounds(parties, unarrived)); + } + return phase; + } + + /** + * Arrives at the barrier and awaits others. Equivalent in effect + * to {@code awaitAdvance(arrive())}. If you need to await with + * interruption or timeout, you can arrange this with an analogous + * construction using one of the other forms of the awaitAdvance + * method. If instead you need to deregister upon arrival use + * {@code arriveAndDeregister}. It is an unenforced usage error + * for an unregistered party to invoke this method. + * + * @return the arrival phase number, or a negative number if terminated + * @throws IllegalStateException if not terminated and the number + * of unarrived parties would become negative + */ + public int arriveAndAwaitAdvance() { + return awaitAdvance(arrive()); + } + + /** + * Awaits the phase of the barrier to advance from the given phase + * value, returning immediately if the current phase of the + * barrier is not equal to the given phase value or this barrier + * is terminated. It is an unenforced usage error for an + * unregistered party to invoke this method. + * + * @param phase an arrival phase number, or negative value if + * terminated; this argument is normally the value returned by a + * previous call to {@code arrive} or its variants + * @return the next arrival phase number, or a negative value + * if terminated or argument is negative + */ + public int awaitAdvance(int phase) { + if (phase < 0) + return phase; + long s = getReconciledState(); + int p = phaseOf(s); + if (p != phase) + return p; + if (unarrivedOf(s) == 0 && parent != null) + parent.awaitAdvance(phase); + // Fall here even if parent waited, to reconcile and help release + return untimedWait(phase); + } + + /** + * Awaits the phase of the barrier to advance from the given phase + * value, throwing {@code InterruptedException} if interrupted + * while waiting, or returning immediately if the current phase of + * the barrier is not equal to the given phase value or this + * barrier is terminated. It is an unenforced usage error for an + * unregistered party to invoke this method. + * + * @param phase an arrival phase number, or negative value if + * terminated; this argument is normally the value returned by a + * previous call to {@code arrive} or its variants + * @return the next arrival phase number, or a negative value + * if terminated or argument is negative + * @throws InterruptedException if thread interrupted while waiting + */ + public int awaitAdvanceInterruptibly(int phase) + throws InterruptedException { + if (phase < 0) + return phase; + long s = getReconciledState(); + int p = phaseOf(s); + if (p != phase) + return p; + if (unarrivedOf(s) == 0 && parent != null) + parent.awaitAdvanceInterruptibly(phase); + return interruptibleWait(phase); + } + + /** + * Awaits the phase of the barrier to advance from the given phase + * value or the given timeout to elapse, throwing {@code + * InterruptedException} if interrupted while waiting, or + * returning immediately if the current phase of the barrier is + * not equal to the given phase value or this barrier is + * terminated. It is an unenforced usage error for an + * unregistered party to invoke this method. + * + * @param phase an arrival phase number, or negative value if + * terminated; this argument is normally the value returned by a + * previous call to {@code arrive} or its variants + * @param timeout how long to wait before giving up, in units of + * {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code timeout} parameter + * @return the next arrival phase number, or a negative value + * if terminated or argument is negative + * @throws InterruptedException if thread interrupted while waiting + * @throws TimeoutException if timed out while waiting + */ + public int awaitAdvanceInterruptibly(int phase, + long timeout, TimeUnit unit) + throws InterruptedException, TimeoutException { + if (phase < 0) + return phase; + long s = getReconciledState(); + int p = phaseOf(s); + if (p != phase) + return p; + if (unarrivedOf(s) == 0 && parent != null) + parent.awaitAdvanceInterruptibly(phase, timeout, unit); + return timedWait(phase, unit.toNanos(timeout)); + } + + /** + * Forces this barrier to enter termination state. Counts of + * arrived and registered parties are unaffected. If this phaser + * has a parent, it too is terminated. This method may be useful + * for coordinating recovery after one or more tasks encounter + * unexpected exceptions. + */ + public void forceTermination() { + for (;;) { + long s = getReconciledState(); + int phase = phaseOf(s); + int parties = partiesOf(s); + int unarrived = unarrivedOf(s); + if (phase < 0 || + casState(s, stateFor(-1, parties, unarrived))) { + releaseWaiters(0); + releaseWaiters(1); + if (parent != null) + parent.forceTermination(); + return; + } + } + } + + /** + * Returns the current phase number. The maximum phase number is + * {@code Integer.MAX_VALUE}, after which it restarts at + * zero. Upon termination, the phase number is negative. + * + * @return the phase number, or a negative value if terminated + */ + public final int getPhase() { + return phaseOf(getReconciledState()); + } + + /** + * Returns the number of parties registered at this barrier. + * + * @return the number of parties + */ + public int getRegisteredParties() { + return partiesOf(state); + } + + /** + * Returns the number of registered parties that have arrived at + * the current phase of this barrier. + * + * @return the number of arrived parties + */ + public int getArrivedParties() { + return arrivedOf(state); + } + + /** + * Returns the number of registered parties that have not yet + * arrived at the current phase of this barrier. + * + * @return the number of unarrived parties + */ + public int getUnarrivedParties() { + return unarrivedOf(state); + } + + /** + * Returns the parent of this phaser, or {@code null} if none. + * + * @return the parent of this phaser, or {@code null} if none + */ + public Phaser getParent() { + return parent; + } + + /** + * Returns the root ancestor of this phaser, which is the same as + * this phaser if it has no parent. + * + * @return the root ancestor of this phaser + */ + public Phaser getRoot() { + return root; + } + + /** + * Returns {@code true} if this barrier has been terminated. + * + * @return {@code true} if this barrier has been terminated + */ + public boolean isTerminated() { + return getPhase() < 0; + } + + /** + * Overridable method to perform an action upon impending phase + * advance, and to control termination. This method is invoked + * upon arrival of the party tripping the barrier (when all other + * waiting parties are dormant). If this method returns {@code + * true}, then, rather than advance the phase number, this barrier + * will be set to a final termination state, and subsequent calls + * to {@link #isTerminated} will return true. Any (unchecked) + * Exception or Error thrown by an invocation of this method is + * propagated to the party attempting to trip the barrier, in + * which case no advance occurs. + * + * <p>The arguments to this method provide the state of the phaser + * prevailing for the current transition. (When called from within + * an implementation of {@code onAdvance} the values returned by + * methods such as {@code getPhase} may or may not reliably + * indicate the state to which this transition applies.) + * + * <p>The default version returns {@code true} when the number of + * registered parties is zero. Normally, overrides that arrange + * termination for other reasons should also preserve this + * property. + * + * <p>You may override this method to perform an action with side + * effects visible to participating tasks, but it is only sensible + * to do so in designs where all parties register before any + * arrive, and all {@link #awaitAdvance} at each phase. + * Otherwise, you cannot ensure lack of interference from other + * parties during the invocation of this method. Additionally, + * method {@code onAdvance} may be invoked more than once per + * transition if registrations are intermixed with arrivals. + * + * @param phase the phase number on entering the barrier + * @param registeredParties the current number of registered parties + * @return {@code true} if this barrier should terminate + */ + protected boolean onAdvance(int phase, int registeredParties) { + return registeredParties <= 0; + } + + /** + * Returns a string identifying this phaser, as well as its + * state. The state, in brackets, includes the String {@code + * "phase = "} followed by the phase number, {@code "parties = "} + * followed by the number of registered parties, and {@code + * "arrived = "} followed by the number of arrived parties. + * + * @return a string identifying this barrier, as well as its state + */ + public String toString() { + long s = getReconciledState(); + return super.toString() + + "[phase = " + phaseOf(s) + + " parties = " + partiesOf(s) + + " arrived = " + arrivedOf(s) + "]"; + } + + // methods for waiting + + /** + * Wait nodes for Treiber stack representing wait queue + */ + static final class QNode implements ForkJoinPool.ManagedBlocker { + final Phaser phaser; + final int phase; + final long startTime; + final long nanos; + final boolean timed; + final boolean interruptible; + volatile boolean wasInterrupted = false; + volatile Thread thread; // nulled to cancel wait + QNode next; + QNode(Phaser phaser, int phase, boolean interruptible, + boolean timed, long startTime, long nanos) { + this.phaser = phaser; + this.phase = phase; + this.timed = timed; + this.interruptible = interruptible; + this.startTime = startTime; + this.nanos = nanos; + thread = Thread.currentThread(); + } + public boolean isReleasable() { + return (thread == null || + phaser.getPhase() != phase || + (interruptible && wasInterrupted) || + (timed && (nanos - (System.nanoTime() - startTime)) <= 0)); + } + public boolean block() { + if (Thread.interrupted()) { + wasInterrupted = true; + if (interruptible) + return true; + } + if (!timed) + LockSupport.park(this); + else { + long waitTime = nanos - (System.nanoTime() - startTime); + if (waitTime <= 0) + return true; + LockSupport.parkNanos(this, waitTime); + } + return isReleasable(); + } + void signal() { + Thread t = thread; + if (t != null) { + thread = null; + LockSupport.unpark(t); + } + } + boolean doWait() { + if (thread != null) { + try { + ForkJoinPool.managedBlock(this, false); + } catch (InterruptedException ie) { + } + } + return wasInterrupted; + } + + } + + /** + * Removes and signals waiting threads from wait queue. + */ + private void releaseWaiters(int phase) { + AtomicReference<QNode> head = queueFor(phase); + QNode q; + while ((q = head.get()) != null) { + if (head.compareAndSet(q, q.next)) + q.signal(); + } + } + + /** + * Tries to enqueue given node in the appropriate wait queue. + * + * @return true if successful + */ + private boolean tryEnqueue(QNode node) { + AtomicReference<QNode> head = queueFor(node.phase); + return head.compareAndSet(node.next = head.get(), node); + } + + /** + * Enqueues node and waits unless aborted or signalled. + * + * @return current phase + */ + private int untimedWait(int phase) { + QNode node = null; + boolean queued = false; + boolean interrupted = false; + int p; + while ((p = getPhase()) == phase) { + if (Thread.interrupted()) + interrupted = true; + else if (node == null) + node = new QNode(this, phase, false, false, 0, 0); + else if (!queued) + queued = tryEnqueue(node); + else + interrupted = node.doWait(); + } + if (node != null) + node.thread = null; + releaseWaiters(phase); + if (interrupted) + Thread.currentThread().interrupt(); + return p; + } + + /** + * Interruptible version + * @return current phase + */ + private int interruptibleWait(int phase) throws InterruptedException { + QNode node = null; + boolean queued = false; + boolean interrupted = false; + int p; + while ((p = getPhase()) == phase && !interrupted) { + if (Thread.interrupted()) + interrupted = true; + else if (node == null) + node = new QNode(this, phase, true, false, 0, 0); + else if (!queued) + queued = tryEnqueue(node); + else + interrupted = node.doWait(); + } + if (node != null) + node.thread = null; + if (p != phase || (p = getPhase()) != phase) + releaseWaiters(phase); + if (interrupted) + throw new InterruptedException(); + return p; + } + + /** + * Timeout version. + * @return current phase + */ + private int timedWait(int phase, long nanos) + throws InterruptedException, TimeoutException { + long startTime = System.nanoTime(); + QNode node = null; + boolean queued = false; + boolean interrupted = false; + int p; + while ((p = getPhase()) == phase && !interrupted) { + if (Thread.interrupted()) + interrupted = true; + else if (nanos - (System.nanoTime() - startTime) <= 0) + break; + else if (node == null) + node = new QNode(this, phase, true, true, startTime, nanos); + else if (!queued) + queued = tryEnqueue(node); + else + interrupted = node.doWait(); + } + if (node != null) + node.thread = null; + if (p != phase || (p = getPhase()) != phase) + releaseWaiters(phase); + if (interrupted) + throw new InterruptedException(); + if (p == phase) + throw new TimeoutException(); + return p; + } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + private static final long stateOffset = + objectFieldOffset("state", Phaser.class); + + private final boolean casState(long cmp, long val) { + return UNSAFE.compareAndSwapLong(this, stateOffset, cmp, val); + } + + private static long objectFieldOffset(String field, Class<?> klazz) { + try { + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/util/concurrent/RecursiveAction.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,179 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A recursive resultless {@link ForkJoinTask}. This class + * establishes conventions to parameterize resultless actions as + * {@code Void} {@code ForkJoinTask}s. Because {@code null} is the + * only valid value of type {@code Void}, methods such as join always + * return {@code null} upon completion. + * + * <p><b>Sample Usages.</b> Here is a sketch of a ForkJoin sort that + * sorts a given {@code long[]} array: + * + * <pre> {@code + * class SortTask extends RecursiveAction { + * final long[] array; final int lo; final int hi; + * SortTask(long[] array, int lo, int hi) { + * this.array = array; this.lo = lo; this.hi = hi; + * } + * protected void compute() { + * if (hi - lo < THRESHOLD) + * sequentiallySort(array, lo, hi); + * else { + * int mid = (lo + hi) >>> 1; + * invokeAll(new SortTask(array, lo, mid), + * new SortTask(array, mid, hi)); + * merge(array, lo, hi); + * } + * } + * }}</pre> + * + * You could then sort {@code anArray} by creating {@code new + * SortTask(anArray, 0, anArray.length-1) } and invoking it in a + * ForkJoinPool. As a more concrete simple example, the following + * task increments each element of an array: + * <pre> {@code + * class IncrementTask extends RecursiveAction { + * final long[] array; final int lo; final int hi; + * IncrementTask(long[] array, int lo, int hi) { + * this.array = array; this.lo = lo; this.hi = hi; + * } + * protected void compute() { + * if (hi - lo < THRESHOLD) { + * for (int i = lo; i < hi; ++i) + * array[i]++; + * } + * else { + * int mid = (lo + hi) >>> 1; + * invokeAll(new IncrementTask(array, lo, mid), + * new IncrementTask(array, mid, hi)); + * } + * } + * }}</pre> + * + * <p>The following example illustrates some refinements and idioms + * that may lead to better performance: RecursiveActions need not be + * fully recursive, so long as they maintain the basic + * divide-and-conquer approach. Here is a class that sums the squares + * of each element of a double array, by subdividing out only the + * right-hand-sides of repeated divisions by two, and keeping track of + * them with a chain of {@code next} references. It uses a dynamic + * threshold based on method {@code getSurplusQueuedTaskCount}, but + * counterbalances potential excess partitioning by directly + * performing leaf actions on unstolen tasks rather than further + * subdividing. + * + * <pre> {@code + * double sumOfSquares(ForkJoinPool pool, double[] array) { + * int n = array.length; + * Applyer a = new Applyer(array, 0, n, null); + * pool.invoke(a); + * return a.result; + * } + * + * class Applyer extends RecursiveAction { + * final double[] array; + * final int lo, hi; + * double result; + * Applyer next; // keeps track of right-hand-side tasks + * Applyer(double[] array, int lo, int hi, Applyer next) { + * this.array = array; this.lo = lo; this.hi = hi; + * this.next = next; + * } + * + * double atLeaf(int l, int h) { + * double sum = 0; + * for (int i = l; i < h; ++i) // perform leftmost base step + * sum += array[i] * array[i]; + * return sum; + * } + * + * protected void compute() { + * int l = lo; + * int h = hi; + * Applyer right = null; + * while (h - l > 1 && getSurplusQueuedTaskCount() <= 3) { + * int mid = (l + h) >>> 1; + * right = new Applyer(array, mid, h, right); + * right.fork(); + * h = mid; + * } + * double sum = atLeaf(l, h); + * while (right != null) { + * if (right.tryUnfork()) // directly calculate if not stolen + * sum += right.atLeaf(right.lo, right.hi); + * else { + * right.helpJoin(); + * sum += right.result; + * } + * right = right.next; + * } + * result = sum; + * } + * }}</pre> + * + * @since 1.7 + * @author Doug Lea + */ +public abstract class RecursiveAction extends ForkJoinTask<Void> { + private static final long serialVersionUID = 5232453952276485070L; + + /** + * The main computation performed by this task. + */ + protected abstract void compute(); + + /** + * Always returns null. + */ + public final Void getRawResult() { return null; } + + /** + * Requires null completion value. + */ + protected final void setRawResult(Void mustBeNull) { } + + /** + * Implements execution conventions for RecursiveActions. + */ + protected final boolean exec() { + compute(); + return true; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/util/concurrent/RecursiveTask.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,97 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A recursive result-bearing {@link ForkJoinTask}. + * + * <p>For a classic example, here is a task computing Fibonacci numbers: + * + * <pre> {@code + * class Fibonacci extends RecursiveTask<Integer> { + * final int n; + * Fibonacci(int n) { this.n = n; } + * Integer compute() { + * if (n <= 1) + * return n; + * Fibonacci f1 = new Fibonacci(n - 1); + * f1.fork(); + * Fibonacci f2 = new Fibonacci(n - 2); + * return f2.compute() + f1.join(); + * } + * }}</pre> + * + * However, besides being a dumb way to compute Fibonacci functions + * (there is a simple fast linear algorithm that you'd use in + * practice), this is likely to perform poorly because the smallest + * subtasks are too small to be worthwhile splitting up. Instead, as + * is the case for nearly all fork/join applications, you'd pick some + * minimum granularity size (for example 10 here) for which you always + * sequentially solve rather than subdividing. + * + * @since 1.7 + * @author Doug Lea + */ +public abstract class RecursiveTask<V> extends ForkJoinTask<V> { + private static final long serialVersionUID = 5232453952276485270L; + + /** + * The result of the computation. + */ + V result; + + /** + * The main computation performed by this task. + */ + protected abstract V compute(); + + public final V getRawResult() { + return result; + } + + protected final void setRawResult(V value) { + result = value; + } + + /** + * Implements execution conventions for RecursiveTask. + */ + protected final boolean exec() { + result = compute(); + return true; + } + +}
--- a/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java Thu Nov 12 23:04:42 2009 +0000 @@ -61,6 +61,14 @@ * causes tasks to be immediately removed from the work queue at * time of cancellation. * + * <p>Successive executions of a task scheduled via + * <code>scheduleAtFixedRate</code> or + * <code>scheduleWithFixedDelay</code> do not overlap. While different + * executions may be performed by different threads, the effects of + * prior executions <a + * href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> + * those of subsequent ones. + * * <p>While this class inherits from {@link ThreadPoolExecutor}, a few * of the inherited tuning methods are not useful for it. In * particular, because it acts as a fixed-sized pool using
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/util/concurrent/ThreadLocalRandom.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,228 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +import java.util.Random; + +/** + * A random number generator isolated to the current thread. Like the + * global {@link java.util.Random} generator used by the {@link + * java.lang.Math} class, a {@code ThreadLocalRandom} is initialized + * with an internally generated seed that may not otherwise be + * modified. When applicable, use of {@code ThreadLocalRandom} rather + * than shared {@code Random} objects in concurrent programs will + * typically encounter much less overhead and contention. Use of + * {@code ThreadLocalRandom} is particularly appropriate when multiple + * tasks (for example, each a {@link ForkJoinTask}) use random numbers + * in parallel in thread pools. + * + * <p>Usages of this class should typically be of the form: + * {@code ThreadLocalRandom.current().nextX(...)} (where + * {@code X} is {@code Int}, {@code Long}, etc). + * When all usages are of this form, it is never possible to + * accidently share a {@code ThreadLocalRandom} across multiple threads. + * + * <p>This class also provides additional commonly used bounded random + * generation methods. + * + * @since 1.7 + * @author Doug Lea + */ +public class ThreadLocalRandom extends Random { + // same constants as Random, but must be redeclared because private + private final static long multiplier = 0x5DEECE66DL; + private final static long addend = 0xBL; + private final static long mask = (1L << 48) - 1; + + /** + * The random seed. We can't use super.seed. + */ + private long rnd; + + /** + * Initialization flag to permit the first and only allowed call + * to setSeed (inside Random constructor) to succeed. We can't + * allow others since it would cause setting seed in one part of a + * program to unintentionally impact other usages by the thread. + */ + boolean initialized; + + // Padding to help avoid memory contention among seed updates in + // different TLRs in the common case that they are located near + // each other. + private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; + + /** + * The actual ThreadLocal + */ + private static final ThreadLocal<ThreadLocalRandom> localRandom = + new ThreadLocal<ThreadLocalRandom>() { + protected ThreadLocalRandom initialValue() { + return new ThreadLocalRandom(); + } + }; + + + /** + * Constructor called only by localRandom.initialValue. + * We rely on the fact that the superclass no-arg constructor + * invokes setSeed exactly once to initialize. + */ + ThreadLocalRandom() { + super(); + } + + /** + * Returns the current thread's {@code ThreadLocalRandom}. + * + * @return the current thread's {@code ThreadLocalRandom} + */ + public static ThreadLocalRandom current() { + return localRandom.get(); + } + + /** + * Throws {@code UnsupportedOperationException}. Setting seeds in + * this generator is not supported. + * + * @throws UnsupportedOperationException always + */ + public void setSeed(long seed) { + if (initialized) + throw new UnsupportedOperationException(); + initialized = true; + rnd = (seed ^ multiplier) & mask; + } + + protected int next(int bits) { + rnd = (rnd * multiplier + addend) & mask; + return (int) (rnd >>> (48-bits)); + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @throws IllegalArgumentException if least greater than or equal + * to bound + * @return the next value + */ + public int nextInt(int least, int bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextInt(bound - least) + least; + } + + /** + * Returns a pseudorandom, uniformly distributed value + * between 0 (inclusive) and the specified value (exclusive). + * + * @param n the bound on the random number to be returned. Must be + * positive. + * @return the next value + * @throws IllegalArgumentException if n is not positive + */ + public long nextLong(long n) { + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + // Divide n by two until small enough for nextInt. On each + // iteration (at most 31 of them but usually much less), + // randomly choose both whether to include high bit in result + // (offset) and whether to continue with the lower vs upper + // half (which makes a difference only if odd). + long offset = 0; + while (n >= Integer.MAX_VALUE) { + int bits = next(2); + long half = n >>> 1; + long nextn = ((bits & 2) == 0) ? half : n - half; + if ((bits & 1) == 0) + offset += n - nextn; + n = nextn; + } + return offset + nextInt((int) n); + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @return the next value + * @throws IllegalArgumentException if least greater than or equal + * to bound + */ + public long nextLong(long least, long bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextLong(bound - least) + least; + } + + /** + * Returns a pseudorandom, uniformly distributed {@code double} value + * between 0 (inclusive) and the specified value (exclusive). + * + * @param n the bound on the random number to be returned. Must be + * positive. + * @return the next value + * @throws IllegalArgumentException if n is not positive + */ + public double nextDouble(double n) { + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + return nextDouble() * n; + } + + /** + * Returns a pseudorandom, uniformly distributed value between the + * given least value (inclusive) and bound (exclusive). + * + * @param least the least value returned + * @param bound the upper bound (exclusive) + * @return the next value + * @throws IllegalArgumentException if least greater than or equal + * to bound + */ + public double nextDouble(double least, double bound) { + if (least >= bound) + throw new IllegalArgumentException(); + return nextDouble() * (bound - least) + least; + } + + private static final long serialVersionUID = -5851777807851030925L; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/util/concurrent/TransferQueue.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,161 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +package java.util.concurrent; + +/** + * A {@link BlockingQueue} in which producers may wait for consumers + * to receive elements. A {@code TransferQueue} may be useful for + * example in message passing applications in which producers + * sometimes (using method {@link #transfer}) await receipt of + * elements by consumers invoking {@code take} or {@code poll}, while + * at other times enqueue elements (via method {@code put}) without + * waiting for receipt. + * {@linkplain #tryTransfer(Object) Non-blocking} and + * {@linkplain #tryTransfer(Object,long,TimeUnit) time-out} versions of + * {@code tryTransfer} are also available. + * A {@code TransferQueue} may also be queried, via {@link + * #hasWaitingConsumer}, whether there are any threads waiting for + * items, which is a converse analogy to a {@code peek} operation. + * + * <p>Like other blocking queues, a {@code TransferQueue} may be + * capacity bounded. If so, an attempted transfer operation may + * initially block waiting for available space, and/or subsequently + * block waiting for reception by a consumer. Note that in a queue + * with zero capacity, such as {@link SynchronousQueue}, {@code put} + * and {@code transfer} are effectively synonymous. + * + * <p>This interface is a member of the + * <a href="{@docRoot}/../technotes/guides/collections/index.html"> + * Java Collections Framework</a>. + * + * @since 1.7 + * @author Doug Lea + * @param <E> the type of elements held in this collection + */ +public interface TransferQueue<E> extends BlockingQueue<E> { + /** + * Transfers the element to a waiting consumer immediately, if possible. + * + * <p>More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * otherwise returning {@code false} without enqueuing the element. + * + * @param e the element to transfer + * @return {@code true} if the element was transferred, else + * {@code false} + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + boolean tryTransfer(E e); + + /** + * Transfers the element to a consumer, waiting if necessary to do so. + * + * <p>More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * else waits until the element is received by a consumer. + * + * @param e the element to transfer + * @throws InterruptedException if interrupted while waiting, + * in which case the element is not left enqueued + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + void transfer(E e) throws InterruptedException; + + /** + * Transfers the element to a consumer if it is possible to do so + * before the timeout elapses. + * + * <p>More precisely, transfers the specified element immediately + * if there exists a consumer already waiting to receive it (in + * {@link #take} or timed {@link #poll(long,TimeUnit) poll}), + * else waits until the element is received by a consumer, + * returning {@code false} if the specified wait time elapses + * before the element can be transferred. + * + * @param e the element to transfer + * @param timeout how long to wait before giving up, in units of + * {@code unit} + * @param unit a {@code TimeUnit} determining how to interpret the + * {@code timeout} parameter + * @return {@code true} if successful, or {@code false} if + * the specified waiting time elapses before completion, + * in which case the element is not left enqueued + * @throws InterruptedException if interrupted while waiting, + * in which case the element is not left enqueued + * @throws ClassCastException if the class of the specified element + * prevents it from being added to this queue + * @throws NullPointerException if the specified element is null + * @throws IllegalArgumentException if some property of the specified + * element prevents it from being added to this queue + */ + boolean tryTransfer(E e, long timeout, TimeUnit unit) + throws InterruptedException; + + /** + * Returns {@code true} if there is at least one consumer waiting + * to receive an element via {@link #take} or + * timed {@link #poll(long,TimeUnit) poll}. + * The return value represents a momentary state of affairs. + * + * @return {@code true} if there is at least one waiting consumer + */ + boolean hasWaitingConsumer(); + + /** + * Returns an estimate of the number of consumers waiting to + * receive elements via {@link #take} or timed + * {@link #poll(long,TimeUnit) poll}. The return value is an + * approximation of a momentary state of affairs, that may be + * inaccurate if consumers have completed or given up waiting. + * The value may be useful for monitoring and heuristics, but + * not for synchronization control. Implementations of this + * method are likely to be noticeably slower than those for + * {@link #hasWaitingConsumer}. + * + * @return the number of consumers waiting to receive elements + */ + int getWaitingConsumerCount(); +}
--- a/src/share/classes/java/util/concurrent/locks/Condition.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/concurrent/locks/Condition.java Thu Nov 12 23:04:42 2009 +0000 @@ -170,8 +170,8 @@ * <p>As interruption generally implies cancellation, and checks for * interruption are often infrequent, an implementation can favor responding * to an interrupt over normal method return. This is true even if it can be - * shown that the interrupt occurred after another action may have unblocked - * the thread. An implementation should document this behavior. + * shown that the interrupt occurred after another action that may have + * unblocked the thread. An implementation should document this behavior. * * @since 1.5 * @author Doug Lea
--- a/src/share/classes/java/util/concurrent/package-info.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/java/util/concurrent/package-info.java Thu Nov 12 23:04:42 2009 +0000 @@ -92,6 +92,13 @@ * assists in coordinating the processing of groups of * asynchronous tasks. * + * <p>Class {@link java.util.concurrent.ForkJoinPool} provides an + * Executor primarily designed for processing instances of {@link + * java.util.concurrent.ForkJoinTask} and its subclasses. These + * classes employ a work-stealing scheduler that attains high + * throughput for tasks conforming to restrictions that often hold in + * computation-intensive parallel processing. + * * <h2>Queues</h2> * * The {@link java.util.concurrent.ConcurrentLinkedQueue} class @@ -110,6 +117,12 @@ * for producer-consumer, messaging, parallel tasking, and * related concurrent designs. * + * <p> Extended interface {@link java.util.concurrent.TransferQueue}, + * and implementation {@link java.util.concurrent.LinkedTransferQueue} + * introduce a synchronous {@code transfer} method (along with related + * features) in which a producer may optionally block awaiting its + * consumer. + * * <p>The {@link java.util.concurrent.BlockingDeque} interface * extends {@code BlockingQueue} to support both FIFO and LIFO * (stack-based) operations. @@ -136,15 +149,28 @@ * * <h2>Synchronizers</h2> * - * Four classes aid common special-purpose synchronization idioms. - * {@link java.util.concurrent.Semaphore} is a classic concurrency tool. - * {@link java.util.concurrent.CountDownLatch} is a very simple yet very - * common utility for blocking until a given number of signals, events, - * or conditions hold. A {@link java.util.concurrent.CyclicBarrier} is a - * resettable multiway synchronization point useful in some styles of - * parallel programming. An {@link java.util.concurrent.Exchanger} allows - * two threads to exchange objects at a rendezvous point, and is useful - * in several pipeline designs. + * Five classes aid common special-purpose synchronization idioms. + * <ul> + * + * <li>{@link java.util.concurrent.Semaphore} is a classic concurrency tool. + * + * <li>{@link java.util.concurrent.CountDownLatch} is a very simple yet + * very common utility for blocking until a given number of signals, + * events, or conditions hold. + * + * <li>A {@link java.util.concurrent.CyclicBarrier} is a resettable + * multiway synchronization point useful in some styles of parallel + * programming. + * + * <li>A {@link java.util.concurrent.Phaser} provides + * a more flexible form of barrier that may be used to control phased + * computation among multiple threads. + * + * <li>An {@link java.util.concurrent.Exchanger} allows two threads to + * exchange objects at a rendezvous point, and is useful in several + * pipeline designs. + * + * </ul> * * <h2>Concurrent Collections</h2> * @@ -259,7 +285,8 @@ * in each thread <i>happen-before</i> those subsequent to the * corresponding {@code exchange()} in another thread. * - * <li>Actions prior to calling {@code CyclicBarrier.await} + * <li>Actions prior to calling {@code CyclicBarrier.await} and + * {@code Phaser.awaitAdvance} (as well as its variants) * <i>happen-before</i> actions performed by the barrier action, and * actions performed by the barrier action <i>happen-before</i> actions * subsequent to a successful return from the corresponding {@code await}
--- a/src/share/classes/javax/swing/ToolTipManager.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/ToolTipManager.java Thu Nov 12 23:04:42 2009 +0000 @@ -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 @@ -27,10 +27,7 @@ package javax.swing; import java.awt.event.*; -import java.applet.*; import java.awt.*; -import java.io.Serializable; -import sun.swing.UIAction; /** * Manages all the <code>ToolTips</code> in the system. @@ -60,7 +57,7 @@ JComponent insideComponent; MouseEvent mouseEvent; boolean showImmediately; - final static ToolTipManager sharedInstance = new ToolTipManager(); + private static final Object TOOL_TIP_MANAGER_KEY = new Object(); transient Popup tipWindow; /** The Window tip is being displayed in. This will be non-null if * the Window tip is in differs from that of insideComponent's Window. @@ -345,7 +342,13 @@ * @return a shared <code>ToolTipManager</code> object */ public static ToolTipManager sharedInstance() { - return sharedInstance; + Object value = SwingUtilities.appContextGet(TOOL_TIP_MANAGER_KEY); + if (value instanceof ToolTipManager) { + return (ToolTipManager) value; + } + ToolTipManager manager = new ToolTipManager(); + SwingUtilities.appContextPut(TOOL_TIP_MANAGER_KEY, manager); + return manager; } // add keylistener here to trigger tip for access
--- a/src/share/classes/javax/swing/UIManager.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/UIManager.java Thu Nov 12 23:04:42 2009 +0000 @@ -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 @@ -197,6 +197,8 @@ Vector<LookAndFeel> auxLookAndFeels = null; SwingPropertyChangeSupport changeSupport; + LookAndFeelInfo[] installedLAFs; + UIDefaults getLookAndFeelDefaults() { return tables[0]; } void setLookAndFeelDefaults(UIDefaults x) { tables[0] = x; } @@ -227,18 +229,6 @@ */ private static final Object classLock = new Object(); - - /* Cache the last referenced LAFState to improve performance - * when accessing it. The cache is based on last thread rather - * than last AppContext because of the cost of looking up the - * AppContext each time. Since most Swing UI work is on the - * EventDispatchThread, this hits often enough to justify the - * overhead. (4193032) - */ - private static Thread currentLAFStateThread = null; - private static LAFState currentLAFState = null; - - /** * Return the <code>LAFState</code> object, lazily create one if necessary. * All access to the <code>LAFState</code> fields is done via this method, @@ -248,13 +238,6 @@ * </pre> */ private static LAFState getLAFState() { - // First check whether we're running on the same thread as - // the last request. - Thread thisThread = Thread.currentThread(); - if (thisThread == currentLAFStateThread) { - return currentLAFState; - } - LAFState rv = (LAFState)SwingUtilities.appContextGet( SwingUtilities2.LAF_STATE_KEY); if (rv == null) { @@ -268,10 +251,6 @@ } } } - - currentLAFStateThread = thisThread; - currentLAFState = rv; - return rv; } @@ -431,7 +410,10 @@ */ public static LookAndFeelInfo[] getInstalledLookAndFeels() { maybeInitialize(); - LookAndFeelInfo[] ilafs = installedLAFs; + LookAndFeelInfo[] ilafs = getLAFState().installedLAFs; + if (ilafs == null) { + ilafs = installedLAFs; + } LookAndFeelInfo[] rv = new LookAndFeelInfo[ilafs.length]; System.arraycopy(ilafs, 0, rv, 0, ilafs.length); return rv; @@ -453,9 +435,10 @@ public static void setInstalledLookAndFeels(LookAndFeelInfo[] infos) throws SecurityException { + maybeInitialize(); LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length]; System.arraycopy(infos, 0, newInfos, 0, infos.length); - installedLAFs = newInfos; + getLAFState().installedLAFs = newInfos; } @@ -1307,10 +1290,11 @@ } } - installedLAFs = new LookAndFeelInfo[ilafs.size()]; + LookAndFeelInfo[] installedLAFs = new LookAndFeelInfo[ilafs.size()]; for(int i = 0; i < ilafs.size(); i++) { installedLAFs[i] = ilafs.elementAt(i); } + getLAFState().installedLAFs = installedLAFs; }
--- a/src/share/classes/javax/swing/plaf/basic/BasicButtonUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/plaf/basic/BasicButtonUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -26,6 +26,8 @@ package javax.swing.plaf.basic; import sun.swing.SwingUtilities2; +import sun.awt.AppContext; + import java.awt.*; import java.awt.event.*; import java.io.Serializable; @@ -44,9 +46,6 @@ * @author Jeff Dinkins */ public class BasicButtonUI extends ButtonUI{ - // Shared UI object - private final static BasicButtonUI buttonUI = new BasicButtonUI(); - // Visual constants // NOTE: This is not used or set any where. Were we allowed to remove // fields, this would be removed. @@ -61,10 +60,19 @@ private final static String propertyPrefix = "Button" + "."; + private static final Object BASIC_BUTTON_UI_KEY = new Object(); + // ******************************** // Create PLAF // ******************************** public static ComponentUI createUI(JComponent c) { + AppContext appContext = AppContext.getAppContext(); + BasicButtonUI buttonUI = + (BasicButtonUI) appContext.get(BASIC_BUTTON_UI_KEY); + if (buttonUI == null) { + buttonUI = new BasicButtonUI(); + appContext.put(BASIC_BUTTON_UI_KEY, buttonUI); + } return buttonUI; }
--- a/src/share/classes/javax/swing/plaf/basic/BasicCheckBoxUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/plaf/basic/BasicCheckBoxUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -25,6 +25,8 @@ package javax.swing.plaf.basic; +import sun.awt.AppContext; + import javax.swing.*; import java.awt.*; @@ -49,7 +51,7 @@ */ public class BasicCheckBoxUI extends BasicRadioButtonUI { - private final static BasicCheckBoxUI checkboxUI = new BasicCheckBoxUI(); + private static final Object BASIC_CHECK_BOX_UI_KEY = new Object(); private final static String propertyPrefix = "CheckBox" + "."; @@ -57,6 +59,13 @@ // Create PLAF // ******************************** public static ComponentUI createUI(JComponent b) { + AppContext appContext = AppContext.getAppContext(); + BasicCheckBoxUI checkboxUI = + (BasicCheckBoxUI) appContext.get(BASIC_CHECK_BOX_UI_KEY); + if (checkboxUI == null) { + checkboxUI = new BasicCheckBoxUI(); + appContext.put(BASIC_CHECK_BOX_UI_KEY, checkboxUI); + } return checkboxUI; }
--- a/src/share/classes/javax/swing/plaf/basic/BasicLabelUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/plaf/basic/BasicLabelUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -28,6 +28,8 @@ import sun.swing.SwingUtilities2; import sun.swing.DefaultLookup; import sun.swing.UIAction; +import sun.awt.AppContext; + import javax.swing.*; import javax.swing.plaf.*; import javax.swing.text.View; @@ -63,7 +65,7 @@ * name in defaults table under the key "LabelUI". */ protected static BasicLabelUI labelUI = new BasicLabelUI(); - private final static BasicLabelUI SAFE_BASIC_LABEL_UI = new BasicLabelUI(); + private static final Object BASIC_LABEL_UI_KEY = new Object(); private Rectangle paintIconR = new Rectangle(); private Rectangle paintTextR = new Rectangle(); @@ -394,10 +396,16 @@ public static ComponentUI createUI(JComponent c) { if (System.getSecurityManager() != null) { - return SAFE_BASIC_LABEL_UI; - } else { - return labelUI; + AppContext appContext = AppContext.getAppContext(); + BasicLabelUI safeBasicLabelUI = + (BasicLabelUI) appContext.get(BASIC_LABEL_UI_KEY); + if (safeBasicLabelUI == null) { + safeBasicLabelUI = new BasicLabelUI(); + appContext.put(BASIC_LABEL_UI_KEY, safeBasicLabelUI); + } + return safeBasicLabelUI; } + return labelUI; } public void propertyChange(PropertyChangeEvent e) {
--- a/src/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -32,6 +32,7 @@ import javax.swing.plaf.*; import javax.swing.text.View; import sun.swing.SwingUtilities2; +import sun.awt.AppContext; /** @@ -41,7 +42,7 @@ */ public class BasicRadioButtonUI extends BasicToggleButtonUI { - private final static BasicRadioButtonUI radioButtonUI = new BasicRadioButtonUI(); + private static final Object BASIC_RADIO_BUTTON_UI_KEY = new Object(); protected Icon icon; @@ -53,6 +54,13 @@ // Create PLAF // ******************************** public static ComponentUI createUI(JComponent b) { + AppContext appContext = AppContext.getAppContext(); + BasicRadioButtonUI radioButtonUI = + (BasicRadioButtonUI) appContext.get(BASIC_RADIO_BUTTON_UI_KEY); + if (radioButtonUI == null) { + radioButtonUI = new BasicRadioButtonUI(); + appContext.put(BASIC_RADIO_BUTTON_UI_KEY, radioButtonUI); + } return radioButtonUI; }
--- a/src/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -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 @@ -31,14 +31,12 @@ import sun.swing.UIAction; import javax.swing.*; import javax.swing.border.Border; -import javax.swing.event.*; import java.awt.*; import java.awt.event.*; import java.awt.peer.ComponentPeer; import java.awt.peer.LightweightPeer; import java.beans.*; import java.util.*; -import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.SplitPaneUI; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; @@ -106,13 +104,13 @@ * Keys to use for forward focus traversal when the JComponent is * managing focus. */ - private static Set<KeyStroke> managingFocusForwardTraversalKeys; + private Set<KeyStroke> managingFocusForwardTraversalKeys; /** * Keys to use for backward focus traversal when the JComponent is * managing focus. */ - private static Set<KeyStroke> managingFocusBackwardTraversalKeys; + private Set<KeyStroke> managingFocusBackwardTraversalKeys; /** @@ -675,7 +673,7 @@ * @return increment via keyboard methods. */ int getKeyboardMoveIncrement() { - return KEYBOARD_DIVIDER_MOVE_OFFSET; + return 3; } /**
--- a/src/share/classes/javax/swing/plaf/basic/BasicToggleButtonUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/plaf/basic/BasicToggleButtonUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -25,6 +25,8 @@ package javax.swing.plaf.basic; +import sun.awt.AppContext; + import java.awt.*; import java.awt.event.*; @@ -43,7 +45,7 @@ */ public class BasicToggleButtonUI extends BasicButtonUI { - private final static BasicToggleButtonUI toggleButtonUI = new BasicToggleButtonUI(); + private static final Object BASIC_TOGGLE_BUTTON_UI_KEY = new Object(); private final static String propertyPrefix = "ToggleButton" + "."; @@ -51,6 +53,13 @@ // Create PLAF // ******************************** public static ComponentUI createUI(JComponent b) { + AppContext appContext = AppContext.getAppContext(); + BasicToggleButtonUI toggleButtonUI = + (BasicToggleButtonUI) appContext.get(BASIC_TOGGLE_BUTTON_UI_KEY); + if (toggleButtonUI == null) { + toggleButtonUI = new BasicToggleButtonUI(); + appContext.put(BASIC_TOGGLE_BUTTON_UI_KEY, toggleButtonUI); + } return toggleButtonUI; }
--- a/src/share/classes/javax/swing/plaf/metal/MetalBumps.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/plaf/metal/MetalBumps.java Thu Nov 12 23:04:42 2009 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-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 @@ -28,8 +28,9 @@ import java.awt.*; import java.awt.image.*; import javax.swing.*; -import java.io.*; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import sun.awt.AppContext; /** * Implements the bumps used throughout the Metal Look and Feel. @@ -49,19 +50,9 @@ protected Color shadowColor; protected Color backColor; - protected static Vector<BumpBuffer> buffers = new Vector<BumpBuffer>(); + private static final Object METAL_BUMPS = new Object(); protected BumpBuffer buffer; - public MetalBumps( Dimension bumpArea ) { - this( bumpArea.width, bumpArea.height ); - } - - public MetalBumps( int width, int height ) { - this(width, height, MetalLookAndFeel.getPrimaryControlHighlight(), - MetalLookAndFeel.getPrimaryControlDarkShadow(), - MetalLookAndFeel.getPrimaryControlShadow()); - } - /** * Creates MetalBumps of the specified size with the specified colors. * If <code>newBackColor</code> is null, the background will be @@ -73,26 +64,22 @@ setBumpColors( newTopColor, newShadowColor, newBackColor ); } - private BumpBuffer getBuffer(GraphicsConfiguration gc, Color aTopColor, - Color aShadowColor, Color aBackColor) { - if (buffer != null && buffer.hasSameConfiguration( - gc, aTopColor, aShadowColor, aBackColor)) { - return buffer; + private static BumpBuffer createBuffer(GraphicsConfiguration gc, + Color topColor, Color shadowColor, Color backColor) { + AppContext context = AppContext.getAppContext(); + List<BumpBuffer> buffers = (List<BumpBuffer>) context.get(METAL_BUMPS); + if (buffers == null) { + buffers = new ArrayList<BumpBuffer>(); + context.put(METAL_BUMPS, buffers); } - BumpBuffer result = null; - - for (BumpBuffer aBuffer : buffers) { - if ( aBuffer.hasSameConfiguration(gc, aTopColor, aShadowColor, - aBackColor)) { - result = aBuffer; - break; + for (BumpBuffer buffer : buffers) { + if (buffer.hasSameConfiguration(gc, topColor, shadowColor, backColor)) { + return buffer; } } - if (result == null) { - result = new BumpBuffer(gc, topColor, shadowColor, backColor); - buffers.addElement(result); - } - return result; + BumpBuffer buffer = new BumpBuffer(gc, topColor, shadowColor, backColor); + buffers.add(buffer); + return buffer; } public void setBumpArea( Dimension bumpArea ) { @@ -119,10 +106,12 @@ GraphicsConfiguration gc = (g instanceof Graphics2D) ? ((Graphics2D) g).getDeviceConfiguration() : null; - buffer = getBuffer(gc, topColor, shadowColor, backColor); + if ((buffer == null) || !buffer.hasSameConfiguration(gc, topColor, shadowColor, backColor)) { + buffer = createBuffer(gc, topColor, shadowColor, backColor); + } - int bufferWidth = buffer.getImageSize().width; - int bufferHeight = buffer.getImageSize().height; + int bufferWidth = BumpBuffer.IMAGE_SIZE; + int bufferHeight = BumpBuffer.IMAGE_SIZE; int iconWidth = getIconWidth(); int iconHeight = getIconHeight(); int x2 = x + iconWidth; @@ -155,7 +144,6 @@ class BumpBuffer { static final int IMAGE_SIZE = 64; - static Dimension imageSize = new Dimension( IMAGE_SIZE, IMAGE_SIZE ); transient Image image; Color topColor; @@ -197,10 +185,6 @@ return image; } - public Dimension getImageSize() { - return imageSize; - } - /** * Paints the bumps into the current image. */
--- a/src/share/classes/javax/swing/plaf/metal/MetalButtonUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/plaf/metal/MetalButtonUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -26,6 +26,8 @@ package javax.swing.plaf.metal; import sun.swing.SwingUtilities2; +import sun.awt.AppContext; + import javax.swing.*; import javax.swing.border.*; import javax.swing.plaf.basic.*; @@ -49,19 +51,25 @@ * @author Tom Santos */ public class MetalButtonUI extends BasicButtonUI { - - private final static MetalButtonUI metalButtonUI = new MetalButtonUI(); - // NOTE: These are not really needed, but at this point we can't pull // them. Their values are updated purely for historical reasons. protected Color focusColor; protected Color selectColor; protected Color disabledTextColor; + private static final Object METAL_BUTTON_UI_KEY = new Object(); + // ******************************** // Create PLAF // ******************************** public static ComponentUI createUI(JComponent c) { + AppContext appContext = AppContext.getAppContext(); + MetalButtonUI metalButtonUI = + (MetalButtonUI) appContext.get(METAL_BUTTON_UI_KEY); + if (metalButtonUI == null) { + metalButtonUI = new MetalButtonUI(); + appContext.put(METAL_BUTTON_UI_KEY, metalButtonUI); + } return metalButtonUI; }
--- a/src/share/classes/javax/swing/plaf/metal/MetalCheckBoxUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/plaf/metal/MetalCheckBoxUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -25,6 +25,8 @@ package javax.swing.plaf.metal; +import sun.awt.AppContext; + import javax.swing.*; import javax.swing.plaf.basic.BasicCheckBoxUI; @@ -55,7 +57,7 @@ // of BasicCheckBoxUI because we want to pick up all the // painting changes made in MetalRadioButtonUI. - private final static MetalCheckBoxUI checkboxUI = new MetalCheckBoxUI(); + private static final Object METAL_CHECK_BOX_UI_KEY = new Object(); private final static String propertyPrefix = "CheckBox" + "."; @@ -65,6 +67,13 @@ // Create PlAF // ******************************** public static ComponentUI createUI(JComponent b) { + AppContext appContext = AppContext.getAppContext(); + MetalCheckBoxUI checkboxUI = + (MetalCheckBoxUI) appContext.get(METAL_CHECK_BOX_UI_KEY); + if (checkboxUI == null) { + checkboxUI = new MetalCheckBoxUI(); + appContext.put(METAL_CHECK_BOX_UI_KEY, checkboxUI); + } return checkboxUI; }
--- a/src/share/classes/javax/swing/plaf/metal/MetalInternalFrameUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/plaf/metal/MetalInternalFrameUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-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 @@ -31,10 +31,8 @@ import javax.swing.event.*; import javax.swing.border.*; import javax.swing.plaf.basic.*; -import java.util.EventListener; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; -import java.beans.PropertyVetoException; import javax.swing.plaf.*; /** @@ -51,7 +49,7 @@ private static final Border handyEmptyBorder = new EmptyBorder(0,0,0,0); protected static String IS_PALETTE = "JInternalFrame.isPalette"; - + private static String IS_PALETTE_KEY = "JInternalFrame.isPalette"; private static String FRAME_TYPE = "JInternalFrame.frameType"; private static String NORMAL_FRAME = "normal"; private static String PALETTE_FRAME = "palette"; @@ -68,7 +66,7 @@ public void installUI(JComponent c) { super.installUI(c); - Object paletteProp = c.getClientProperty( IS_PALETTE ); + Object paletteProp = c.getClientProperty(IS_PALETTE_KEY); if ( paletteProp != null ) { setPalette( ((Boolean)paletteProp).booleanValue() ); } @@ -187,7 +185,7 @@ ui.setFrameType( (String) e.getNewValue() ); } } - else if ( name.equals( IS_PALETTE ) ) + else if ( name.equals(IS_PALETTE_KEY) ) { if ( e.getNewValue() != null ) {
--- a/src/share/classes/javax/swing/plaf/metal/MetalLabelUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/plaf/metal/MetalLabelUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -26,6 +26,8 @@ package javax.swing.plaf.metal; import sun.swing.SwingUtilities2; +import sun.awt.AppContext; + import javax.swing.*; import javax.swing.plaf.*; import javax.swing.plaf.basic.*; @@ -51,15 +53,21 @@ * name in defaults table under the key "LabelUI". */ protected static MetalLabelUI metalLabelUI = new MetalLabelUI(); - private final static MetalLabelUI SAFE_METAL_LABEL_UI = new MetalLabelUI(); + private static final Object METAL_LABEL_UI_KEY = new Object(); public static ComponentUI createUI(JComponent c) { if (System.getSecurityManager() != null) { - return SAFE_METAL_LABEL_UI; - } else { - return metalLabelUI; + AppContext appContext = AppContext.getAppContext(); + MetalLabelUI safeMetalLabelUI = + (MetalLabelUI) appContext.get(METAL_LABEL_UI_KEY); + if (safeMetalLabelUI == null) { + safeMetalLabelUI = new MetalLabelUI(); + appContext.put(METAL_LABEL_UI_KEY, safeMetalLabelUI); + } + return safeMetalLabelUI; } + return metalLabelUI; } /**
--- a/src/share/classes/javax/swing/plaf/metal/MetalRadioButtonUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/plaf/metal/MetalRadioButtonUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -26,6 +26,8 @@ package javax.swing.plaf.metal; import sun.swing.SwingUtilities2; +import sun.awt.AppContext; + import java.awt.*; import java.awt.event.*; import javax.swing.*; @@ -53,7 +55,7 @@ */ public class MetalRadioButtonUI extends BasicRadioButtonUI { - private static final MetalRadioButtonUI metalRadioButtonUI = new MetalRadioButtonUI(); + private static final Object METAL_RADIO_BUTTON_UI_KEY = new Object(); protected Color focusColor; protected Color selectColor; @@ -65,6 +67,13 @@ // Create PlAF // ******************************** public static ComponentUI createUI(JComponent c) { + AppContext appContext = AppContext.getAppContext(); + MetalRadioButtonUI metalRadioButtonUI = + (MetalRadioButtonUI) appContext.get(METAL_RADIO_BUTTON_UI_KEY); + if (metalRadioButtonUI == null) { + metalRadioButtonUI = new MetalRadioButtonUI(); + appContext.put(METAL_RADIO_BUTTON_UI_KEY, metalRadioButtonUI); + } return metalRadioButtonUI; }
--- a/src/share/classes/javax/swing/plaf/metal/MetalSliderUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/plaf/metal/MetalSliderUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-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 @@ -54,12 +54,13 @@ protected final int TICK_BUFFER = 4; protected boolean filledSlider = false; - // NOTE: these next three variables are currently unused. + // NOTE: these next five variables are currently unused. protected static Color thumbColor; protected static Color highlightColor; protected static Color darkShadowColor; protected static int trackWidth; protected static int tickLength; + private int safeLength; /** * A default horizontal thumb <code>Icon</code>. This field might not be @@ -107,7 +108,7 @@ public void installUI( JComponent c ) { trackWidth = ((Integer)UIManager.get( "Slider.trackWidth" )).intValue(); - tickLength = ((Integer)UIManager.get( "Slider.majorTickLength" )).intValue(); + tickLength = safeLength = ((Integer)UIManager.get( "Slider.majorTickLength" )).intValue(); horizThumbIcon = SAFE_HORIZ_THUMB_ICON = UIManager.getIcon( "Slider.horizontalThumbIcon" ); vertThumbIcon = SAFE_VERT_THUMB_ICON = @@ -477,8 +478,8 @@ * determine the tick area rectangle. */ public int getTickLength() { - return slider.getOrientation() == JSlider.HORIZONTAL ? tickLength + TICK_BUFFER + 1 : - tickLength + TICK_BUFFER + 3; + return slider.getOrientation() == JSlider.HORIZONTAL ? safeLength + TICK_BUFFER + 1 : + safeLength + TICK_BUFFER + 3; } /** @@ -523,22 +524,22 @@ protected void paintMinorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) { g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() ); - g.drawLine( x, TICK_BUFFER, x, TICK_BUFFER + (tickLength / 2) ); + g.drawLine( x, TICK_BUFFER, x, TICK_BUFFER + (safeLength / 2) ); } protected void paintMajorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) { g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() ); - g.drawLine( x, TICK_BUFFER , x, TICK_BUFFER + (tickLength - 1) ); + g.drawLine( x, TICK_BUFFER , x, TICK_BUFFER + (safeLength - 1) ); } protected void paintMinorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) { g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() ); if (MetalUtils.isLeftToRight(slider)) { - g.drawLine( TICK_BUFFER, y, TICK_BUFFER + (tickLength / 2), y ); + g.drawLine( TICK_BUFFER, y, TICK_BUFFER + (safeLength / 2), y ); } else { - g.drawLine( 0, y, tickLength/2, y ); + g.drawLine( 0, y, safeLength/2, y ); } } @@ -546,10 +547,10 @@ g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() ); if (MetalUtils.isLeftToRight(slider)) { - g.drawLine( TICK_BUFFER, y, TICK_BUFFER + tickLength, y ); + g.drawLine( TICK_BUFFER, y, TICK_BUFFER + safeLength, y ); } else { - g.drawLine( 0, y, tickLength, y ); + g.drawLine( 0, y, safeLength, y ); } } }
--- a/src/share/classes/javax/swing/plaf/metal/MetalToggleButtonUI.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/javax/swing/plaf/metal/MetalToggleButtonUI.java Thu Nov 12 23:04:42 2009 +0000 @@ -26,6 +26,8 @@ package javax.swing.plaf.metal; import sun.swing.SwingUtilities2; +import sun.awt.AppContext; + import java.awt.*; import java.awt.event.*; import java.lang.ref.*; @@ -55,7 +57,7 @@ */ public class MetalToggleButtonUI extends BasicToggleButtonUI { - private static final MetalToggleButtonUI metalToggleButtonUI = new MetalToggleButtonUI(); + private static final Object METAL_TOGGLE_BUTTON_UI_KEY = new Object(); protected Color focusColor; protected Color selectColor; @@ -67,6 +69,13 @@ // Create PLAF // ******************************** public static ComponentUI createUI(JComponent b) { + AppContext appContext = AppContext.getAppContext(); + MetalToggleButtonUI metalToggleButtonUI = + (MetalToggleButtonUI) appContext.get(METAL_TOGGLE_BUTTON_UI_KEY); + if (metalToggleButtonUI == null) { + metalToggleButtonUI = new MetalToggleButtonUI(); + appContext.put(METAL_TOGGLE_BUTTON_UI_KEY, metalToggleButtonUI); + } return metalToggleButtonUI; }
--- a/src/share/classes/sun/applet/AppletClassLoader.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/sun/applet/AppletClassLoader.java Thu Nov 12 23:04:42 2009 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 1995-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-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 @@ -51,6 +51,7 @@ import java.security.PermissionCollection; import sun.awt.AppContext; import sun.awt.SunToolkit; +import sun.misc.IOUtils; import sun.net.www.ParseUtil; import sun.security.util.SecurityConstants; @@ -331,36 +332,7 @@ byte[] b; try { - if (len != -1) { - // Read exactly len bytes from the input stream - b = new byte[len]; - while (len > 0) { - int n = in.read(b, b.length - len, len); - if (n == -1) { - throw new IOException("unexpected EOF"); - } - len -= n; - } - } else { - // Read until end of stream is reached - use 8K buffer - // to speed up performance [stanleyh] - b = new byte[8192]; - int total = 0; - while ((len = in.read(b, total, b.length - total)) != -1) { - total += len; - if (total >= b.length) { - byte[] tmp = new byte[total * 2]; - System.arraycopy(b, 0, tmp, 0, total); - b = tmp; - } - } - // Trim array to correct size, if necessary - if (total != b.length) { - byte[] tmp = new byte[total]; - System.arraycopy(b, 0, tmp, 0, total); - b = tmp; - } - } + b = IOUtils.readFully(in, len, true); } finally { in.close(); }
--- a/src/share/classes/sun/awt/image/ImageRepresentation.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/sun/awt/image/ImageRepresentation.java Thu Nov 12 23:04:42 2009 +0000 @@ -336,10 +336,6 @@ public native void setICMpixels(int x, int y, int w, int h, int[] lut, byte[] pix, int off, int scansize, IntegerComponentRaster ict); - - public native void setBytePixels(int x, int y, int w, int h, byte[] pix, - int off, int scansize, - ByteComponentRaster bct, int chanOff); public native int setDiffICM(int x, int y, int w, int h, int[] lut, int transPix, int numLut, IndexColorModel icm, byte[] pix, int off, int scansize, @@ -450,27 +446,17 @@ (biRaster instanceof ByteComponentRaster) && (biRaster.getNumDataElements() == 1)){ ByteComponentRaster bt = (ByteComponentRaster) biRaster; - if (w*h > 200) { - if (off == 0 && scansize == w) { - bt.putByteData(x, y, w, h, pix); - } - else { - byte[] bpix = new byte[w]; - poff = off; - for (int yoff=y; yoff < y+h; yoff++) { - System.arraycopy(pix, poff, bpix, 0, w); - bt.putByteData(x, yoff, w, 1, bpix); - poff += scansize; - } - } + if (off == 0 && scansize == w) { + bt.putByteData(x, y, w, h, pix); } else { - // Only is faster if #pixels - // Note that setBytePixels modifies the raster directly - // so we must mark it as changed afterwards - setBytePixels(x, y, w, h, pix, off, scansize, bt, - bt.getDataOffset(0)); - bt.markDirty(); + byte[] bpix = new byte[w]; + poff = off; + for (int yoff=y; yoff < y+h; yoff++) { + System.arraycopy(pix, poff, bpix, 0, w); + bt.putByteData(x, yoff, w, 1, bpix); + poff += scansize; + } } } else {
--- a/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java Thu Nov 12 23:04:42 2009 +0000 @@ -26,9 +26,9 @@ package sun.dyn.anon; import java.io.IOException; -import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import sun.misc.IOUtils; /** * Anonymous class loader. Will load any valid classfile, producing @@ -285,13 +285,6 @@ if (contentLength < 0) throw new IOException("invalid content length "+contentLength); - byte[] classFile = new byte[contentLength]; - InputStream tcs = connection.getInputStream(); - for (int fill = 0, nr; fill < classFile.length; fill += nr) { - nr = tcs.read(classFile, fill, classFile.length - fill); - if (nr < 0) - throw new IOException("premature end of file"); - } - return classFile; + return IOUtils.readFully(connection.getInputStream(), contentLength, true); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/misc/IOUtils.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,80 @@ +/* + * 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. + */ + +/** + * IOUtils: A collection of IO-related public static methods. + */ + +package sun.misc; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; + +public class IOUtils { + + /** + * Read up to <code>length</code> of bytes from <code>in</code> + * until EOF is detected. + * @param in input stream, must not be null + * @param length number of bytes to read, -1 or Integer.MAX_VALUE means + * read as much as possible + * @param readAll if true, an EOFException will be thrown if not enough + * bytes are read. Ignored when length is -1 or Integer.MAX_VALUE + * @return bytes read + * @throws IOException Any IO error or a premature EOF is detected + */ + public static byte[] readFully(InputStream is, int length, boolean readAll) + throws IOException { + byte[] output = {}; + if (length == -1) length = Integer.MAX_VALUE; + int pos = 0; + while (pos < length) { + int bytesToRead; + if (pos >= output.length) { // Only expand when there's no room + bytesToRead = Math.min(length - pos, output.length + 1024); + if (output.length < pos + bytesToRead) { + output = Arrays.copyOf(output, pos + bytesToRead); + } + } else { + bytesToRead = output.length - pos; + } + int cc = is.read(output, pos, bytesToRead); + if (cc < 0) { + if (readAll && length != Integer.MAX_VALUE) { + throw new EOFException("Detect premature EOF"); + } else { + if (output.length != pos) { + output = Arrays.copyOf(output, pos); + } + break; + } + } + pos += cc; + } + return output; + } +}
--- a/src/share/classes/sun/misc/Resource.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/sun/misc/Resource.java Thu Nov 12 23:04:42 2009 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-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,14 +25,15 @@ package sun.misc; +import java.io.EOFException; import java.net.URL; import java.io.IOException; import java.io.InterruptedIOException; import java.io.InputStream; import java.security.CodeSigner; import java.util.jar.Manifest; -import java.util.jar.Attributes; import java.nio.ByteBuffer; +import java.util.Arrays; import sun.nio.ByteBuffered; /** @@ -105,49 +106,37 @@ } try { - if (len != -1) { - // Read exactly len bytes from the input stream - b = new byte[len]; - while (len > 0) { - int n = 0; - try { - n = in.read(b, b.length - len, len); - } catch (InterruptedIOException iioe) { - Thread.interrupted(); - isInterrupted = true; + b = new byte[0]; + if (len == -1) len = Integer.MAX_VALUE; + int pos = 0; + while (pos < len) { + int bytesToRead; + if (pos >= b.length) { // Only expand when there's no room + bytesToRead = Math.min(len - pos, b.length + 1024); + if (b.length < pos + bytesToRead) { + b = Arrays.copyOf(b, pos + bytesToRead); } - if (n == -1) { - throw new IOException("unexpected EOF"); - } - len -= n; + } else { + bytesToRead = b.length - pos; } - } else { - // Read until end of stream is reached - b = new byte[1024]; - int total = 0; - for (;;) { - len = 0; - try { - len = in.read(b, total, b.length - total); - if (len == -1) - break; - } catch (InterruptedIOException iioe) { - Thread.interrupted(); - isInterrupted = true; - } - total += len; - if (total >= b.length) { - byte[] tmp = new byte[total * 2]; - System.arraycopy(b, 0, tmp, 0, total); - b = tmp; + int cc = 0; + try { + cc = in.read(b, pos, bytesToRead); + } catch (InterruptedIOException iioe) { + Thread.interrupted(); + isInterrupted = true; + } + if (cc < 0) { + if (len != Integer.MAX_VALUE) { + throw new EOFException("Detect premature EOF"); + } else { + if (b.length != pos) { + b = Arrays.copyOf(b, pos); + } + break; } } - // Trim array to correct size, if necessary - if (total != b.length) { - byte[] tmp = new byte[total]; - System.arraycopy(b, 0, tmp, 0, total); - b = tmp; - } + pos += cc; } } finally { try {
--- a/src/share/classes/sun/misc/Version-template.java Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,327 +0,0 @@ -/* - * 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 - * 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 sun.misc; -import java.io.PrintStream; - -public class Version { - - - private static final String launcher_name = - "@@launcher_name@@"; - - private static final String java_version = - "@@java_version@@"; - - private static final String java_runtime_name = - "@@java_runtime_name@@"; - - private static final String java_runtime_version = - "@@java_runtime_version@@"; - - static { - init(); - } - - public static void init() { - System.setProperty("java.version", java_version); - System.setProperty("java.runtime.version", java_runtime_version); - System.setProperty("java.runtime.name", java_runtime_name); - } - - private static boolean versionsInitialized = false; - private static int jvm_major_version = 0; - private static int jvm_minor_version = 0; - private static int jvm_micro_version = 0; - private static int jvm_update_version = 0; - private static int jvm_build_number = 0; - private static String jvm_special_version = null; - private static int jdk_major_version = 0; - private static int jdk_minor_version = 0; - private static int jdk_micro_version = 0; - private static int jdk_update_version = 0; - private static int jdk_build_number = 0; - private static String jdk_special_version = null; - - /** - * In case you were wondering this method is called by java -version. - * Sad that it prints to stderr; would be nicer if default printed on - * stdout. - */ - public static void print() { - print(System.err); - } - - /** - * This is the same as print except that it adds an extra line-feed - * at the end, typically used by the -showversion in the launcher - */ - public static void println() { - print(System.err); - System.err.println(); - } - - /** - * Give a stream, it will print version info on it. - */ - public static void print(PrintStream ps) { - /* First line: platform version. */ - ps.println(launcher_name + " version \"" + java_version + "\""); - - /* Second line: runtime version (ie, libraries). */ - ps.println(java_runtime_name + " (build " + - java_runtime_version + ")"); - - /* Third line: JVM information. */ - String java_vm_name = System.getProperty("java.vm.name"); - String java_vm_version = System.getProperty("java.vm.version"); - String java_vm_info = System.getProperty("java.vm.info"); - ps.println(java_vm_name + " (build " + java_vm_version + ", " + - java_vm_info + ")"); - } - - - /** - * Returns the major version of the running JVM if it's 1.6 or newer - * or any RE VM build. It will return 0 if it's an internal 1.5 or - * 1.4.x build. - * - * @since 1.6 - */ - public static synchronized int jvmMajorVersion() { - if (!versionsInitialized) { - initVersions(); - } - return jvm_major_version; - } - - /** - * Returns the minor version of the running JVM if it's 1.6 or newer - * or any RE VM build. It will return 0 if it's an internal 1.5 or - * 1.4.x build. - * @since 1.6 - */ - public static synchronized int jvmMinorVersion() { - if (!versionsInitialized) { - initVersions(); - } - return jvm_minor_version; - } - - - /** - * Returns the micro version of the running JVM if it's 1.6 or newer - * or any RE VM build. It will return 0 if it's an internal 1.5 or - * 1.4.x build. - * @since 1.6 - */ - public static synchronized int jvmMicroVersion() { - if (!versionsInitialized) { - initVersions(); - } - return jvm_micro_version; - } - - /** - * Returns the update release version of the running JVM if it's - * a RE build. It will return 0 if it's an internal build. - * @since 1.6 - */ - public static synchronized int jvmUpdateVersion() { - if (!versionsInitialized) { - initVersions(); - } - return jvm_update_version; - } - - public static synchronized String jvmSpecialVersion() { - if (!versionsInitialized) { - initVersions(); - } - if (jvm_special_version == null) { - jvm_special_version = getJvmSpecialVersion(); - } - return jvm_special_version; - } - public static native String getJvmSpecialVersion(); - - /** - * Returns the build number of the running JVM if it's a RE build - * It will return 0 if it's an internal build. - * @since 1.6 - */ - public static synchronized int jvmBuildNumber() { - if (!versionsInitialized) { - initVersions(); - } - return jvm_build_number; - } - - /** - * Returns the major version of the running JDK. - * - * @since 1.6 - */ - public static synchronized int jdkMajorVersion() { - if (!versionsInitialized) { - initVersions(); - } - return jdk_major_version; - } - - /** - * Returns the minor version of the running JDK. - * @since 1.6 - */ - public static synchronized int jdkMinorVersion() { - if (!versionsInitialized) { - initVersions(); - } - return jdk_minor_version; - } - - /** - * Returns the micro version of the running JDK. - * @since 1.6 - */ - public static synchronized int jdkMicroVersion() { - if (!versionsInitialized) { - initVersions(); - } - return jdk_micro_version; - } - - /** - * Returns the update release version of the running JDK if it's - * a RE build. It will return 0 if it's an internal build. - * @since 1.6 - */ - public static synchronized int jdkUpdateVersion() { - if (!versionsInitialized) { - initVersions(); - } - return jdk_update_version; - } - - public static synchronized String jdkSpecialVersion() { - if (!versionsInitialized) { - initVersions(); - } - if (jdk_special_version == null) { - jdk_special_version = getJdkSpecialVersion(); - } - return jdk_special_version; - } - public static native String getJdkSpecialVersion(); - - /** - * Returns the build number of the running JDK if it's a RE build - * It will return 0 if it's an internal build. - * @since 1.6 - */ - public static synchronized int jdkBuildNumber() { - if (!versionsInitialized) { - initVersions(); - } - return jdk_build_number; - } - - // true if JVM exports the version info including the capabilities - private static boolean jvmVersionInfoAvailable; - private static synchronized void initVersions() { - if (versionsInitialized) { - return; - } - jvmVersionInfoAvailable = getJvmVersionInfo(); - if (!jvmVersionInfoAvailable) { - // parse java.vm.version for older JVM before the - // new JVM_GetVersionInfo is added. - // valid format of the version string is: - // n.n.n[_uu[c]][-<identifer>]-bxx - CharSequence cs = System.getProperty("java.vm.version"); - if (cs.length() >= 5 && - Character.isDigit(cs.charAt(0)) && cs.charAt(1) == '.' && - Character.isDigit(cs.charAt(2)) && cs.charAt(3) == '.' && - Character.isDigit(cs.charAt(4))) { - jvm_major_version = Character.digit(cs.charAt(0), 10); - jvm_minor_version = Character.digit(cs.charAt(2), 10); - jvm_micro_version = Character.digit(cs.charAt(4), 10); - cs = cs.subSequence(5, cs.length()); - if (cs.charAt(0) == '_' && cs.length() >= 3 && - Character.isDigit(cs.charAt(1)) && - Character.isDigit(cs.charAt(2))) { - int nextChar = 3; - try { - String uu = cs.subSequence(1, 3).toString(); - jvm_update_version = Integer.valueOf(uu).intValue(); - if (cs.length() >= 4) { - char c = cs.charAt(3); - if (c >= 'a' && c <= 'z') { - jvm_special_version = Character.toString(c); - nextChar++; - } - } - } catch (NumberFormatException e) { - // not conforming to the naming convention - return; - } - cs = cs.subSequence(nextChar, cs.length()); - } - if (cs.charAt(0) == '-') { - // skip the first character - // valid format: <identifier>-bxx or bxx - // non-product VM will have -debug|-release appended - cs = cs.subSequence(1, cs.length()); - String[] res = cs.toString().split("-"); - for (String s : res) { - if (s.charAt(0) == 'b' && s.length() == 3 && - Character.isDigit(s.charAt(1)) && - Character.isDigit(s.charAt(2))) { - jvm_build_number = - Integer.valueOf(s.substring(1, 3)).intValue(); - break; - } - } - } - } - } - getJdkVersionInfo(); - versionsInitialized = true; - } - - // Gets the JVM version info if available and sets the jvm_*_version fields - // and its capabilities. - // - // Return false if not available which implies an old VM (Tiger or before). - private static native boolean getJvmVersionInfo(); - private static native void getJdkVersionInfo(); - -} - -// Help Emacs a little because this file doesn't end in .java. -// -// Local Variables: *** -// mode: java *** -// End: ***
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/misc/Version.java.template Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,327 @@ +/* + * 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 + * 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 sun.misc; +import java.io.PrintStream; + +public class Version { + + + private static final String launcher_name = + "@@launcher_name@@"; + + private static final String java_version = + "@@java_version@@"; + + private static final String java_runtime_name = + "@@java_runtime_name@@"; + + private static final String java_runtime_version = + "@@java_runtime_version@@"; + + static { + init(); + } + + public static void init() { + System.setProperty("java.version", java_version); + System.setProperty("java.runtime.version", java_runtime_version); + System.setProperty("java.runtime.name", java_runtime_name); + } + + private static boolean versionsInitialized = false; + private static int jvm_major_version = 0; + private static int jvm_minor_version = 0; + private static int jvm_micro_version = 0; + private static int jvm_update_version = 0; + private static int jvm_build_number = 0; + private static String jvm_special_version = null; + private static int jdk_major_version = 0; + private static int jdk_minor_version = 0; + private static int jdk_micro_version = 0; + private static int jdk_update_version = 0; + private static int jdk_build_number = 0; + private static String jdk_special_version = null; + + /** + * In case you were wondering this method is called by java -version. + * Sad that it prints to stderr; would be nicer if default printed on + * stdout. + */ + public static void print() { + print(System.err); + } + + /** + * This is the same as print except that it adds an extra line-feed + * at the end, typically used by the -showversion in the launcher + */ + public static void println() { + print(System.err); + System.err.println(); + } + + /** + * Give a stream, it will print version info on it. + */ + public static void print(PrintStream ps) { + /* First line: platform version. */ + ps.println(launcher_name + " version \"" + java_version + "\""); + + /* Second line: runtime version (ie, libraries). */ + ps.println(java_runtime_name + " (build " + + java_runtime_version + ")"); + + /* Third line: JVM information. */ + String java_vm_name = System.getProperty("java.vm.name"); + String java_vm_version = System.getProperty("java.vm.version"); + String java_vm_info = System.getProperty("java.vm.info"); + ps.println(java_vm_name + " (build " + java_vm_version + ", " + + java_vm_info + ")"); + } + + + /** + * Returns the major version of the running JVM if it's 1.6 or newer + * or any RE VM build. It will return 0 if it's an internal 1.5 or + * 1.4.x build. + * + * @since 1.6 + */ + public static synchronized int jvmMajorVersion() { + if (!versionsInitialized) { + initVersions(); + } + return jvm_major_version; + } + + /** + * Returns the minor version of the running JVM if it's 1.6 or newer + * or any RE VM build. It will return 0 if it's an internal 1.5 or + * 1.4.x build. + * @since 1.6 + */ + public static synchronized int jvmMinorVersion() { + if (!versionsInitialized) { + initVersions(); + } + return jvm_minor_version; + } + + + /** + * Returns the micro version of the running JVM if it's 1.6 or newer + * or any RE VM build. It will return 0 if it's an internal 1.5 or + * 1.4.x build. + * @since 1.6 + */ + public static synchronized int jvmMicroVersion() { + if (!versionsInitialized) { + initVersions(); + } + return jvm_micro_version; + } + + /** + * Returns the update release version of the running JVM if it's + * a RE build. It will return 0 if it's an internal build. + * @since 1.6 + */ + public static synchronized int jvmUpdateVersion() { + if (!versionsInitialized) { + initVersions(); + } + return jvm_update_version; + } + + public static synchronized String jvmSpecialVersion() { + if (!versionsInitialized) { + initVersions(); + } + if (jvm_special_version == null) { + jvm_special_version = getJvmSpecialVersion(); + } + return jvm_special_version; + } + public static native String getJvmSpecialVersion(); + + /** + * Returns the build number of the running JVM if it's a RE build + * It will return 0 if it's an internal build. + * @since 1.6 + */ + public static synchronized int jvmBuildNumber() { + if (!versionsInitialized) { + initVersions(); + } + return jvm_build_number; + } + + /** + * Returns the major version of the running JDK. + * + * @since 1.6 + */ + public static synchronized int jdkMajorVersion() { + if (!versionsInitialized) { + initVersions(); + } + return jdk_major_version; + } + + /** + * Returns the minor version of the running JDK. + * @since 1.6 + */ + public static synchronized int jdkMinorVersion() { + if (!versionsInitialized) { + initVersions(); + } + return jdk_minor_version; + } + + /** + * Returns the micro version of the running JDK. + * @since 1.6 + */ + public static synchronized int jdkMicroVersion() { + if (!versionsInitialized) { + initVersions(); + } + return jdk_micro_version; + } + + /** + * Returns the update release version of the running JDK if it's + * a RE build. It will return 0 if it's an internal build. + * @since 1.6 + */ + public static synchronized int jdkUpdateVersion() { + if (!versionsInitialized) { + initVersions(); + } + return jdk_update_version; + } + + public static synchronized String jdkSpecialVersion() { + if (!versionsInitialized) { + initVersions(); + } + if (jdk_special_version == null) { + jdk_special_version = getJdkSpecialVersion(); + } + return jdk_special_version; + } + public static native String getJdkSpecialVersion(); + + /** + * Returns the build number of the running JDK if it's a RE build + * It will return 0 if it's an internal build. + * @since 1.6 + */ + public static synchronized int jdkBuildNumber() { + if (!versionsInitialized) { + initVersions(); + } + return jdk_build_number; + } + + // true if JVM exports the version info including the capabilities + private static boolean jvmVersionInfoAvailable; + private static synchronized void initVersions() { + if (versionsInitialized) { + return; + } + jvmVersionInfoAvailable = getJvmVersionInfo(); + if (!jvmVersionInfoAvailable) { + // parse java.vm.version for older JVM before the + // new JVM_GetVersionInfo is added. + // valid format of the version string is: + // n.n.n[_uu[c]][-<identifer>]-bxx + CharSequence cs = System.getProperty("java.vm.version"); + if (cs.length() >= 5 && + Character.isDigit(cs.charAt(0)) && cs.charAt(1) == '.' && + Character.isDigit(cs.charAt(2)) && cs.charAt(3) == '.' && + Character.isDigit(cs.charAt(4))) { + jvm_major_version = Character.digit(cs.charAt(0), 10); + jvm_minor_version = Character.digit(cs.charAt(2), 10); + jvm_micro_version = Character.digit(cs.charAt(4), 10); + cs = cs.subSequence(5, cs.length()); + if (cs.charAt(0) == '_' && cs.length() >= 3 && + Character.isDigit(cs.charAt(1)) && + Character.isDigit(cs.charAt(2))) { + int nextChar = 3; + try { + String uu = cs.subSequence(1, 3).toString(); + jvm_update_version = Integer.valueOf(uu).intValue(); + if (cs.length() >= 4) { + char c = cs.charAt(3); + if (c >= 'a' && c <= 'z') { + jvm_special_version = Character.toString(c); + nextChar++; + } + } + } catch (NumberFormatException e) { + // not conforming to the naming convention + return; + } + cs = cs.subSequence(nextChar, cs.length()); + } + if (cs.charAt(0) == '-') { + // skip the first character + // valid format: <identifier>-bxx or bxx + // non-product VM will have -debug|-release appended + cs = cs.subSequence(1, cs.length()); + String[] res = cs.toString().split("-"); + for (String s : res) { + if (s.charAt(0) == 'b' && s.length() == 3 && + Character.isDigit(s.charAt(1)) && + Character.isDigit(s.charAt(2))) { + jvm_build_number = + Integer.valueOf(s.substring(1, 3)).intValue(); + break; + } + } + } + } + } + getJdkVersionInfo(); + versionsInitialized = true; + } + + // Gets the JVM version info if available and sets the jvm_*_version fields + // and its capabilities. + // + // Return false if not available which implies an old VM (Tiger or before). + private static native boolean getJvmVersionInfo(); + private static native void getJdkVersionInfo(); + +} + +// Help Emacs a little because this file doesn't end in .java. +// +// Local Variables: *** +// mode: java *** +// End: ***
--- a/src/share/classes/sun/reflect/misc/MethodUtil.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/sun/reflect/misc/MethodUtil.java Thu Nov 12 23:04:42 2009 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-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 @@ -44,6 +44,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; +import sun.misc.IOUtils; import sun.net.www.ParseUtil; import sun.security.util.SecurityConstants; @@ -373,34 +374,7 @@ byte[] b; try { - if (len != -1) { - // Read exactly len bytes from the input stream - b = new byte[len]; - while (len > 0) { - int n = in.read(b, b.length - len, len); - if (n == -1) { - throw new IOException("unexpected EOF"); - } - len -= n; - } - } else { - b = new byte[8192]; - int total = 0; - while ((len = in.read(b, total, b.length - total)) != -1) { - total += len; - if (total >= b.length) { - byte[] tmp = new byte[total * 2]; - System.arraycopy(b, 0, tmp, 0, total); - b = tmp; - } - } - // Trim array to correct size, if necessary - if (total != b.length) { - byte[] tmp = new byte[total]; - System.arraycopy(b, 0, tmp, 0, total); - b = tmp; - } - } + b = IOUtils.readFully(in, len, true); } finally { in.close(); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java Thu Nov 12 23:04:42 2009 +0000 @@ -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 sun.security.provider.certpath; + +import java.util.Set; +import java.util.Collection; +import java.util.Locale; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.security.cert.X509CRL; +import java.security.cert.CertPathValidatorException; +import java.security.cert.PKIXCertPathChecker; + +import sun.security.x509.AlgorithmId; + +/** + * AlgorithmChecker is a <code>PKIXCertPathChecker</code> that checks that + * the signature algorithm of the specified certificate is not disabled. + * + * @author Xuelei Fan + */ +final public class AlgorithmChecker extends PKIXCertPathChecker { + + // the disabled algorithms + private static final String[] disabledAlgorithms = new String[] {"md2"}; + + // singleton instance + static final AlgorithmChecker INSTANCE = new AlgorithmChecker(); + + /** + * Default Constructor + */ + private AlgorithmChecker() { + // do nothing + } + + /** + * Return a AlgorithmChecker instance. + */ + static AlgorithmChecker getInstance() { + return INSTANCE; + } + + /** + * Initializes the internal state of the checker from parameters + * specified in the constructor. + */ + public void init(boolean forward) throws CertPathValidatorException { + // do nothing + } + + public boolean isForwardCheckingSupported() { + return false; + } + + public Set<String> getSupportedExtensions() { + return null; + } + + /** + * Checks the signature algorithm of the specified certificate. + */ + public void check(Certificate cert, Collection<String> unresolvedCritExts) + throws CertPathValidatorException { + check(cert); + } + + public static void check(Certificate cert) + throws CertPathValidatorException { + X509Certificate xcert = (X509Certificate)cert; + check(xcert.getSigAlgName()); + } + + static void check(AlgorithmId aid) throws CertPathValidatorException { + check(aid.getName()); + } + + static void check(X509CRL crl) throws CertPathValidatorException { + check(crl.getSigAlgName()); + } + + private static void check(String algName) + throws CertPathValidatorException { + + String lowerCaseAlgName = algName.toLowerCase(Locale.ENGLISH); + + for (String disabled : disabledAlgorithms) { + // checking the signature algorithm name + if (lowerCaseAlgName.indexOf(disabled) != -1) { + throw new CertPathValidatorException( + "algorithm check failed: " + algName + " is disabled"); + } + } + } + +}
--- a/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java Thu Nov 12 23:04:42 2009 +0000 @@ -289,6 +289,16 @@ X500Name certIssuer = (X500Name) certImpl.getIssuerDN(); X500Name crlIssuer = (X500Name) crlImpl.getIssuerDN(); + // check the crl signature algorithm + try { + AlgorithmChecker.check(crl); + } catch (CertPathValidatorException cpve) { + if (debug != null) { + debug.println("CRL signature algorithm check failed: " + cpve); + } + return false; + } + // if crlIssuer is set, verify that it matches the issuer of the // CRL and the CRL contains an IDP extension with the indirectCRL // boolean asserted. Otherwise, verify that the CRL issuer matches the
--- a/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java Thu Nov 12 23:04:42 2009 +0000 @@ -719,6 +719,11 @@ /* we don't perform any validation of the trusted cert */ if (!isTrustedCert) { /* + * check that the signature algorithm is not disabled. + */ + AlgorithmChecker.check(cert); + + /* * Check CRITICAL private extensions for user checkers that * support forward checking (forwardCheckers) and remove * ones we know how to check.
--- a/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java Thu Nov 12 23:04:42 2009 +0000 @@ -275,6 +275,7 @@ int certPathLen = certList.size(); basicChecker = new BasicChecker(anchor, testDate, sigProvider, false); + AlgorithmChecker algorithmChecker= AlgorithmChecker.getInstance(); KeyChecker keyChecker = new KeyChecker(certPathLen, pkixParam.getTargetCertConstraints()); ConstraintsChecker constraintsChecker = @@ -291,6 +292,7 @@ ArrayList<PKIXCertPathChecker> certPathCheckers = new ArrayList<PKIXCertPathChecker>(); // add standard checkers that we will be using + certPathCheckers.add(algorithmChecker); certPathCheckers.add(keyChecker); certPathCheckers.add(constraintsChecker); certPathCheckers.add(policyChecker);
--- a/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java Thu Nov 12 23:04:42 2009 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 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 @@ -347,6 +347,9 @@ return; } + /* check that the signature algorithm is not disabled. */ + AlgorithmChecker.check(cert); + /* * check for looping - abort a loop if * ((we encounter the same certificate twice) AND
--- a/src/share/classes/sun/security/timestamp/HttpTimestamper.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/sun/security/timestamp/HttpTimestamper.java Thu Nov 12 23:04:42 2009 +0000 @@ -34,6 +34,7 @@ import java.util.Set; import java.util.Arrays; +import sun.misc.IOUtils; import sun.security.pkcs.*; /** @@ -142,25 +143,7 @@ int total = 0; int contentLength = connection.getContentLength(); - if (contentLength != -1) { - replyBuffer = new byte[contentLength]; - } else { - replyBuffer = new byte[2048]; - contentLength = Integer.MAX_VALUE; - } - - while (total < contentLength) { - int count = input.read(replyBuffer, total, - replyBuffer.length - total); - if (count < 0) - break; - - total += count; - if (total >= replyBuffer.length && total < contentLength) { - replyBuffer = Arrays.copyOf(replyBuffer, total * 2); - } - } - replyBuffer = Arrays.copyOf(replyBuffer, total); + replyBuffer = IOUtils.readFully(input, contentLength, false); if (DEBUG) { System.out.println("received timestamp response (length=" +
--- a/src/share/classes/sun/security/util/DerValue.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/sun/security/util/DerValue.java Thu Nov 12 23:04:42 2009 +0000 @@ -28,6 +28,7 @@ import java.io.*; import java.math.BigInteger; import java.util.Date; +import sun.misc.IOUtils; /** * Represents a single DER-encoded value. DER encoding rules are a subset @@ -382,12 +383,8 @@ if (fullyBuffered && in.available() != length) throw new IOException("extra data given to DerValue constructor"); - byte[] bytes = new byte[length]; + byte[] bytes = IOUtils.readFully(in, length, true); - // n.b. readFully not needed in normal fullyBuffered case - DataInputStream dis = new DataInputStream(in); - - dis.readFully(bytes); buffer = new DerInputBuffer(bytes); return new DerInputStream(buffer); }
--- a/src/share/classes/sun/security/validator/SimpleValidator.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/sun/security/validator/SimpleValidator.java Thu Nov 12 23:04:42 2009 +0000 @@ -40,6 +40,8 @@ import sun.security.util.DerOutputStream; import sun.security.util.ObjectIdentifier; +import sun.security.provider.certpath.AlgorithmChecker; + /** * A simple validator implementation. It is based on code from the JSSE * X509TrustManagerImpl. This implementation is designed for compatibility with @@ -134,6 +136,13 @@ X509Certificate issuerCert = chain[i + 1]; X509Certificate cert = chain[i]; + // check certificate algorithm + try { + AlgorithmChecker.check(cert); + } catch (CertPathValidatorException cpve) { + throw new ValidatorException + (ValidatorException.T_ALGORITHM_DISABLED, cert, cpve); + } // no validity check for code signing certs if ((variant.equals(VAR_CODE_SIGNING) == false)
--- a/src/share/classes/sun/security/validator/ValidatorException.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/sun/security/validator/ValidatorException.java Thu Nov 12 23:04:42 2009 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-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 @@ -55,6 +55,9 @@ public final static Object T_NAME_CHAINING = "Certificate chaining error"; + public final static Object T_ALGORITHM_DISABLED = + "Certificate signature algorithm disabled"; + private Object type; private X509Certificate cert;
--- a/src/share/classes/sun/text/bidi/BidiBase.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/sun/text/bidi/BidiBase.java Thu Nov 12 23:04:42 2009 +0000 @@ -52,10 +52,11 @@ package sun.text.bidi; -import java.awt.font.TextAttribute; -import java.awt.font.NumericShaper; import java.io.IOException; import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; import java.text.AttributedCharacterIterator; import java.text.Bidi; import java.util.Arrays; @@ -2689,12 +2690,13 @@ public void setPara(AttributedCharacterIterator paragraph) { byte paraLvl; - Boolean runDirection = (Boolean) paragraph.getAttribute(TextAttribute.RUN_DIRECTION); - NumericShaper shaper = (NumericShaper) paragraph.getAttribute(TextAttribute.NUMERIC_SHAPING); + Boolean runDirection = + (Boolean) paragraph.getAttribute(TextAttributeConstants.RUN_DIRECTION); + Object shaper = paragraph.getAttribute(TextAttributeConstants.NUMERIC_SHAPING); if (runDirection == null) { paraLvl = INTERNAL_LEVEL_DEFAULT_LTR; } else { - paraLvl = (runDirection.equals(TextAttribute.RUN_DIRECTION_LTR)) ? + paraLvl = (runDirection.equals(TextAttributeConstants.RUN_DIRECTION_LTR)) ? (byte)Bidi.DIRECTION_LEFT_TO_RIGHT : (byte)Bidi.DIRECTION_RIGHT_TO_LEFT; } @@ -2706,7 +2708,8 @@ char ch = paragraph.first(); while (ch != AttributedCharacterIterator.DONE) { txt[i] = ch; - Integer embedding = (Integer) paragraph.getAttribute(TextAttribute.BIDI_EMBEDDING); + Integer embedding = + (Integer) paragraph.getAttribute(TextAttributeConstants.BIDI_EMBEDDING); if (embedding != null) { byte level = embedding.byteValue(); if (level == 0) { @@ -2724,7 +2727,7 @@ } if (shaper != null) { - shaper.shape(txt, 0, len); + NumericShapings.shape(shaper, txt, 0, len); } setPara(txt, paraLvl, lvls); } @@ -3441,4 +3444,106 @@ return buf.toString(); } + /** + * A class that provides access to constants defined by + * java.awt.font.TextAttribute without creating a static dependency. + */ + private static class TextAttributeConstants { + private static final Class<?> clazz = getClass("java.awt.font.TextAttribute"); + + /** + * TextAttribute instances (or a fake Attribute type if + * java.awt.font.TextAttribute is not present) + */ + static final AttributedCharacterIterator.Attribute RUN_DIRECTION = + getTextAttribute("RUN_DIRECTION"); + static final Boolean RUN_DIRECTION_LTR = + (Boolean)getStaticField(clazz, "RUN_DIRECTION_LTR"); + static final AttributedCharacterIterator.Attribute NUMERIC_SHAPING = + getTextAttribute("NUMERIC_SHAPING"); + static final AttributedCharacterIterator.Attribute BIDI_EMBEDDING = + getTextAttribute("BIDI_EMBEDDING"); + + private static Class<?> getClass(String name) { + try { + return Class.forName(name, true, null); + } catch (ClassNotFoundException e) { + return null; + } + } + + private static Object getStaticField(Class<?> clazz, String name) { + if (clazz == null) { + // fake attribute + return new AttributedCharacterIterator.Attribute(name) { }; + } else { + try { + Field f = clazz.getField(name); + return f.get(null); + } catch (NoSuchFieldException x) { + throw new AssertionError(x); + } catch (IllegalAccessException x) { + throw new AssertionError(x); + } + } + } + + private static AttributedCharacterIterator.Attribute + getTextAttribute(String name) + { + return (AttributedCharacterIterator.Attribute)getStaticField(clazz, name); + } + } + + /** + * A class that provides access to java.awt.font.NumericShaping without + * creating a static dependency. + */ + private static class NumericShapings { + private static final Class<?> clazz = + getClass("java.awt.font.NumericShaper"); + private static final Method shapeMethod = + getMethod(clazz, "shape", char[].class, int.class, int.class); + + private static Class<?> getClass(String name) { + try { + return Class.forName(name, true, null); + } catch (ClassNotFoundException e) { + return null; + } + } + + private static Method getMethod(Class<?> clazz, + String name, + Class<?>... paramTypes) + { + if (clazz != null) { + try { + return clazz.getMethod(name, paramTypes); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } else { + return null; + } + } + + /** + * Invokes NumericShaping shape(text,start,count) method. + */ + static void shape(Object shaper, char[] text, int start, int count) { + if (shapeMethod == null) + throw new AssertionError("Should not get here"); + try { + shapeMethod.invoke(shaper, text, start, count); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof RuntimeException) + throw (RuntimeException)cause; + throw new AssertionError(e); + } catch (IllegalAccessException iae) { + throw new AssertionError(iae); + } + } + } }
--- a/src/share/classes/sun/tools/jconsole/Version-template.java Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * Copyright 2004-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 - * 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 sun.tools.jconsole; - -import java.io.PrintStream; - -public class Version { - private static final String jconsole_version = - "@@jconsole_version@@"; - - public static void print(PrintStream ps) { - printFullVersion(ps); - - ps.println(Resources.getText("Name and Build", - System.getProperty("java.runtime.name"), - System.getProperty("java.runtime.version"))); - - ps.println(Resources.getText("Name Build and Mode", - System.getProperty("java.vm.name"), - System.getProperty("java.vm.version"), - System.getProperty("java.vm.info"))); - - } - - public static void printFullVersion(PrintStream ps) { - ps.println(Resources.getText("JConsole version", jconsole_version)); - } - - static String getVersion() { - return jconsole_version; - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/tools/jconsole/Version.java.template Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright 2004-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 + * 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 sun.tools.jconsole; + +import java.io.PrintStream; + +public class Version { + private static final String jconsole_version = + "@@jconsole_version@@"; + + public static void print(PrintStream ps) { + printFullVersion(ps); + + ps.println(Resources.getText("Name and Build", + System.getProperty("java.runtime.name"), + System.getProperty("java.runtime.version"))); + + ps.println(Resources.getText("Name Build and Mode", + System.getProperty("java.vm.name"), + System.getProperty("java.vm.version"), + System.getProperty("java.vm.info"))); + + } + + public static void printFullVersion(PrintStream ps) { + ps.println(Resources.getText("JConsole version", jconsole_version)); + } + + static String getVersion() { + return jconsole_version; + } +}
--- a/src/share/classes/sun/util/calendar/ZoneInfoFile.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/classes/sun/util/calendar/ZoneInfoFile.java Thu Nov 12 23:04:42 2009 +0000 @@ -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 @@ -472,6 +472,18 @@ private static Map<String, ZoneInfo> zoneInfoObjects = null; + private static final String ziDir; + static { + String zi = (String) AccessController.doPrivileged( + new sun.security.action.GetPropertyAction("java.home")) + + File.separator + "lib" + File.separator + "zi"; + try { + zi = new File(zi).getCanonicalPath(); + } catch (Exception e) { + } + ziDir = zi; + } + /** * Converts the given time zone ID to a platform dependent path * name. For example, "America/Los_Angeles" is converted to @@ -576,20 +588,7 @@ return null; } - int index; - for (index = 0; index < JAVAZI_LABEL.length; index++) { - if (buf[index] != JAVAZI_LABEL[index]) { - System.err.println("ZoneInfo: wrong magic number: " + id); - return null; - } - } - - if (buf[index++] > JAVAZI_VERSION) { - System.err.println("ZoneInfo: incompatible version (" - + buf[index - 1] + "): " + id); - return null; - } - + int index = 0; int filesize = buf.length; int rawOffset = 0; int dstSavings = 0; @@ -600,6 +599,18 @@ int[] simpleTimeZoneParams = null; try { + for (index = 0; index < JAVAZI_LABEL.length; index++) { + if (buf[index] != JAVAZI_LABEL[index]) { + System.err.println("ZoneInfo: wrong magic number: " + id); + return null; + } + } + if (buf[index++] > JAVAZI_VERSION) { + System.err.println("ZoneInfo: incompatible version (" + + buf[index - 1] + "): " + id); + return null; + } + while (index < filesize) { byte tag = buf[index++]; int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); @@ -1017,30 +1028,33 @@ * Reads the specified file under <java.home>/lib/zi into a buffer. * @return the buffer, or null if any I/O error occurred. */ - private static byte[] readZoneInfoFile(String fileName) { + private static byte[] readZoneInfoFile(final String fileName) { byte[] buffer = null; try { - String homeDir = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("java.home")); - final String fname = homeDir + File.separator + "lib" + File.separator - + "zi" + File.separator + fileName; buffer = (byte[]) AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws IOException { - File file = new File(fname); - if (!file.canRead()) { + File file = new File(ziDir, fileName); + if (!file.exists() || !file.isFile()) { return null; } - int filesize = (int)file.length(); - byte[] buf = new byte[filesize]; - - FileInputStream fis = new FileInputStream(file); - - if (fis.read(buf) != filesize) { - fis.close(); - throw new IOException("read error on " + fname); + file = file.getCanonicalFile(); + String path = file.getCanonicalPath(); + byte[] buf = null; + if (path != null && path.startsWith(ziDir)) { + int filesize = (int)file.length(); + if (filesize > 0) { + FileInputStream fis = new FileInputStream(file); + buf = new byte[filesize]; + try { + if (fis.read(buf) != filesize) { + throw new IOException("read error on " + fileName); + } + } finally { + fis.close(); + } + } } - fis.close(); return buf; } });
--- a/src/share/native/com/sun/media/sound/SoundDefs.h Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/native/com/sun/media/sound/SoundDefs.h Thu Nov 12 23:04:42 2009 +0000 @@ -38,6 +38,7 @@ #define X_SPARCV9 3 #define X_IA64 4 #define X_AMD64 5 +#define X_ZERO 6 // ********************************** // Make sure you set X_PLATFORM and X_ARCH defines correctly.
--- a/src/share/native/sun/awt/image/awt_ImageRep.c Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/native/sun/awt/image/awt_ImageRep.c Thu Nov 12 23:04:42 2009 +0000 @@ -142,84 +142,6 @@ } -JNIEXPORT void JNICALL -Java_sun_awt_image_ImageRepresentation_setBytePixels(JNIEnv *env, jclass cls, - jint x, jint y, jint w, - jint h, jbyteArray jpix, - jint off, jint scansize, - jobject jbct, - jint chanOffs) -{ - int sStride; - int pixelStride; - jobject jdata; - unsigned char *srcData; - unsigned char *dstData; - unsigned char *dataP; - unsigned char *pixP; - int i; - int j; - - - if (JNU_IsNull(env, jpix)) { - JNU_ThrowNullPointerException(env, "NullPointerException"); - return; - } - - sStride = (*env)->GetIntField(env, jbct, g_BCRscanstrID); - pixelStride = (*env)->GetIntField(env, jbct, g_BCRpixstrID); - jdata = (*env)->GetObjectField(env, jbct, g_BCRdataID); - - srcData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jpix, - NULL); - if (srcData == NULL) { - /* out of memory error already thrown */ - return; - } - - dstData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jdata, - NULL); - if (dstData == NULL) { - /* out of memory error already thrown */ - (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); - return; - } - - dataP = dstData + chanOffs + y*sStride + x*pixelStride; - pixP = srcData + off; - if (pixelStride == 1) { - if (sStride == scansize && scansize == w) { - memcpy(dataP, pixP, w*h); - } - else { - for (i=0; i < h; i++) { - memcpy(dataP, pixP, w); - dataP += sStride; - pixP += scansize; - } - } - } - else { - unsigned char *ydataP = dataP; - unsigned char *ypixP = pixP; - - for (i=0; i < h; i++) { - dataP = ydataP; - pixP = ypixP; - for (j=0; j < w; j++) { - *dataP = *pixP++; - dataP += pixelStride; - } - ydataP += sStride; - ypixP += scansize; - } - } - - (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT); - (*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, JNI_ABORT); - -} - JNIEXPORT jint JNICALL Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls, jint x, jint y, jint w, @@ -266,6 +188,13 @@ jnewlut = (*env)->GetObjectField(env, jicm, g_ICMrgbID); mapSize = (*env)->GetIntField(env, jicm, g_ICMmapSizeID); + if (numLut < 0 || numLut > 256 || mapSize < 0 || mapSize > 256) { + /* Ether old or new ICM has a palette that exceeds capacity + of byte data type, so we have to convert the image data + to default representation. + */ + return 0; + } srcLUT = (unsigned int *) (*env)->GetPrimitiveArrayCritical(env, jlut, NULL); if (srcLUT == NULL) {
--- a/src/share/native/sun/awt/image/jpeg/imageioJPEG.c Thu Nov 12 23:00:23 2009 +0000 +++ b/src/share/native/sun/awt/image/jpeg/imageioJPEG.c Thu Nov 12 23:04:42 2009 +0000 @@ -676,6 +676,10 @@ #ifdef DEBUG_IIO_JPEG printf("in setQTables, qlen = %d, write is %d\n", qlen, write); #endif + if (qlen > NUM_QUANT_TBLS) { + /* Ignore extra qunterization tables. */ + qlen = NUM_QUANT_TBLS; + } for (i = 0; i < qlen; i++) { table = (*env)->GetObjectArrayElement(env, qtables, i); qdata = (*env)->GetObjectField(env, table, JPEGQTable_tableID); @@ -727,6 +731,11 @@ hlensBody = (*env)->GetShortArrayElements(env, huffLens, NULL); + if (hlensLen > 16) { + /* Ignore extra elements of bits array. Only 16 elements can be + stored. 0-th element is not used. (see jpeglib.h, line 107) */ + hlensLen = 16; + } for (i = 1; i <= hlensLen; i++) { huff_ptr->bits[i] = (UINT8)hlensBody[i-1]; } @@ -743,6 +752,11 @@ huffValues, NULL); + if (hvalsLen > 256) { + /* Ignore extra elements of hufval array. Only 256 elements + can be stored. (see jpeglib.h, line 109) */ + hlensLen = 256; + } for (i = 0; i < hvalsLen; i++) { huff_ptr->huffval[i] = (UINT8)hvalsBody[i]; } @@ -763,6 +777,11 @@ j_compress_ptr comp; j_decompress_ptr decomp; jsize hlen = (*env)->GetArrayLength(env, DCHuffmanTables); + + if (hlen > NUM_HUFF_TBLS) { + /* Ignore extra DC huffman tables. */ + hlen = NUM_HUFF_TBLS; + } for (i = 0; i < hlen; i++) { if (cinfo->is_decompressor) { decomp = (j_decompress_ptr) cinfo; @@ -784,6 +803,10 @@ huff_ptr->sent_table = !write; } hlen = (*env)->GetArrayLength(env, ACHuffmanTables); + if (hlen > NUM_HUFF_TBLS) { + /* Ignore extra AC huffman tables. */ + hlen = NUM_HUFF_TBLS; + } for (i = 0; i < hlen; i++) { if (cinfo->is_decompressor) { decomp = (j_decompress_ptr) cinfo; @@ -1833,6 +1856,13 @@ return JNI_FALSE; } + if (stepX > cinfo->image_width) { + stepX = cinfo->image_width; + } + if (stepY > cinfo->image_height) { + stepY = cinfo->image_height; + } + /* * First get the source bands array and copy it to our local array * so we don't have to worry about pinning and unpinning it again.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/solaris/bin/ergo_zero.c Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +#include "ergo.h" + + +/* Methods for solaris-sparc and linux-sparc: these are easy. */ + +/* Ask the OS how many processors there are. */ +static unsigned long +physical_processors(void) { + const unsigned long sys_processors = sysconf(_SC_NPROCESSORS_CONF); + + JLI_TraceLauncher("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors); + return sys_processors; +} + +/* The sparc version of the "server-class" predicate. */ +jboolean +ServerClassMachineImpl(void) { + jboolean result = JNI_FALSE; + /* How big is a server class machine? */ + const unsigned long server_processors = 2UL; + const uint64_t server_memory = 2UL * GB; + const uint64_t actual_memory = physical_memory(); + + /* Is this a server class machine? */ + if (actual_memory >= server_memory) { + const unsigned long actual_processors = physical_processors(); + if (actual_processors >= server_processors) { + result = JNI_TRUE; + } + } + JLI_TraceLauncher("unix_" LIBARCHNAME "_ServerClassMachine: %s\n", + (result == JNI_TRUE ? "JNI_TRUE" : "JNI_FALSE")); + return result; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/solaris/bin/zero/jvm.cfg Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,39 @@ +# Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# +# +# List of JVMs that can be used as an option to java, javac, etc. +# Order is important -- first in this list is the default JVM. +# NOTE that this both this file and its format are UNSUPPORTED and +# WILL GO AWAY in a future release. +# +# You may also select a JVM in an arbitrary location with the +# "-XXaltjvm=<jvm_dir>" option, but that too is unsupported +# and may not be available in a future release. +# +-server KNOWN +-client IGNORE +-hotspot ERROR +-classic WARN +-native ERROR +-green ERROR
--- a/src/solaris/classes/java/util/prefs/FileSystemPreferences.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/solaris/classes/java/util/prefs/FileSystemPreferences.java Thu Nov 12 23:04:42 2009 +0000 @@ -26,12 +26,12 @@ package java.util.prefs; import java.util.*; import java.io.*; -import java.util.logging.Logger; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedExceptionAction; import java.security.PrivilegedActionException; +import sun.util.logging.PlatformLogger; /** * Preferences implementation for Unix. Preferences are stored in the file @@ -61,8 +61,8 @@ * Returns logger for error messages. Backing store exceptions are logged at * WARNING level. */ - private static Logger getLogger() { - return Logger.getLogger("java.util.prefs"); + private static PlatformLogger getLogger() { + return PlatformLogger.getLogger("java.util.prefs"); } /**
--- a/src/solaris/classes/sun/awt/X11GraphicsDevice.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/solaris/classes/sun/awt/X11GraphicsDevice.java Thu Nov 12 23:04:42 2009 +0000 @@ -134,7 +134,7 @@ makeConfigurations(); } } - return configs; + return configs.clone(); } private void makeConfigurations() {
--- a/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java Thu Nov 12 23:04:42 2009 +0000 @@ -28,6 +28,7 @@ import java.io.IOException; import java.util.LinkedList; import java.util.HashSet; +import java.util.Iterator; /** * Manipulates a native array of epoll_event structs on Linux: @@ -200,12 +201,9 @@ void release(SelChImpl channel) { synchronized (updateList) { // flush any pending updates - int i = 0; - while (i < updateList.size()) { - if (updateList.get(i).channel == channel) { - updateList.remove(i); - } else { - i++; + for (Iterator<Updator> it = updateList.iterator(); it.hasNext();) { + if (it.next().channel == channel) { + it.remove(); } }
--- a/src/windows/classes/sun/awt/Win32GraphicsDevice.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/windows/classes/sun/awt/Win32GraphicsDevice.java Thu Nov 12 23:04:42 2009 +0000 @@ -165,7 +165,7 @@ if (defaultConfig != null) { configs = new GraphicsConfiguration[1]; configs[0] = defaultConfig; - return configs; + return configs.clone(); } } @@ -196,7 +196,7 @@ configs = new GraphicsConfiguration[v.size()]; v.copyInto(configs); } - return configs; + return configs.clone(); } /**
--- a/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java Thu Nov 12 23:00:23 2009 +0000 +++ b/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java Thu Nov 12 23:04:42 2009 +0000 @@ -429,7 +429,7 @@ if (defaultConfig != null) { configs = new GraphicsConfiguration[1]; configs[0] = defaultConfig; - return configs; + return configs.clone(); } } }
--- a/test/Makefile Thu Nov 12 23:00:23 2009 +0000 +++ b/test/Makefile Thu Nov 12 23:04:42 2009 +0000 @@ -1,5 +1,5 @@ # -# Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 1995-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 @@ -27,83 +27,141 @@ # Makefile to run various jdk tests # -# Get OS/ARCH specifics -OSNAME = $(shell uname -s) +# Empty these to get rid of some default rules +.SUFFIXES: +.SUFFIXES: .java +CO= +GET= + +# Utilities used +AWK = awk +CAT = cat +CD = cd +CHMOD = chmod +CP = cp +CUT = cut +ECHO = echo +EGREP = egrep +EXPAND = expand +EXPR = expr +KILL = /usr/bin/kill +MKDIR = mkdir +NOHUP = nohup +PWD = pwd +SED = sed +SLEEP = sleep +SORT = sort +TEE = tee +UNAME = uname +UNIQ = uniq +WC = wc +XHOST = xhost +ZIP = zip + +# Get OS name from uname +UNAME_S := $(shell $(UNAME) -s) # Commands to run on paths to make mixed paths for java on windows -GETMIXEDPATH=echo +GETMIXEDPATH=$(ECHO) # Location of developer shared files SLASH_JAVA = /java # Platform specific settings -ifeq ($(OSNAME), SunOS) - PLATFORM = solaris - ARCH = $(shell uname -p) - ifeq ($(ARCH), i386) - ARCH=i586 - endif +ifeq ($(UNAME_S), SunOS) + OS_NAME = solaris + OS_ARCH := $(shell $(UNAME) -p) + OS_VERSION := $(shell $(UNAME) -r) +endif +ifeq ($(UNAME_S), Linux) + OS_NAME = linux + OS_ARCH := $(shell $(UNAME) -m) + OS_VERSION := $(shell $(UNAME) -r) endif -ifeq ($(OSNAME), Linux) - PLATFORM = linux - ARCH = $(shell uname -m) - ifeq ($(ARCH), i386) - ARCH=i586 +ifndef OS_NAME + ifneq ($(PROCESSOR_IDENTIFIER), ) + OS_NAME = windows + SLASH_JAVA = J: + # A variety of ways to say X64 arch :^( + OS_ARCH:=$(word 1, $(PROCESSOR_IDENTIFIER)) + EXESUFFIX = .exe + # These need to be different depending on MKS or CYGWIN + ifeq ($(findstring cygdrive,$(shell ($(CD) C:/ && $(PWD)))), ) + GETMIXEDPATH = dosname -s + OS_VERSION := $(shell $(UNAME) -r) + else + GETMIXEDPATH = cygpath -m -s + OS_VERSION := $(shell $(UNAME) -s | $(CUT) -d'-' -f2) + endif endif endif -# Cannot trust uname output -ifneq ($(PROCESSOR_IDENTIFIER), ) - PLATFORM = windows - SLASH_JAVA = J: - # A variety of ways to say X64 arch :^( - PROC_ARCH:=$(word 1, $(PROCESSOR_IDENTIFIER)) - PROC_ARCH:=$(subst x86,X86,$(PROC_ARCH)) - PROC_ARCH:=$(subst x64,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst AMD64,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst amd64,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst EM64T,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst em64t,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst intel64,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst Intel64,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst INTEL64,X64,$(PROC_ARCH)) - PROC_ARCH:=$(subst ia64,IA64,$(PROC_ARCH)) - ifeq ($(PROC_ARCH),IA64) - ARCH = ia64 +# Only want major and minor numbers from os version +OS_VERSION := $(shell $(ECHO) "$(OS_VERSION)" | $(CUT) -d'.' -f1,2) + +# Try and use names i586, x64, and ia64 consistently +OS_ARCH:=$(subst X64,x64,$(OS_ARCH)) +OS_ARCH:=$(subst AMD64,x64,$(OS_ARCH)) +OS_ARCH:=$(subst amd64,x64,$(OS_ARCH)) +OS_ARCH:=$(subst x86_64,x64,$(OS_ARCH)) +OS_ARCH:=$(subst EM64T,x64,$(OS_ARCH)) +OS_ARCH:=$(subst em64t,x64,$(OS_ARCH)) +OS_ARCH:=$(subst intel64,x64,$(OS_ARCH)) +OS_ARCH:=$(subst Intel64,x64,$(OS_ARCH)) +OS_ARCH:=$(subst INTEL64,x64,$(OS_ARCH)) +OS_ARCH:=$(subst IA64,ia64,$(OS_ARCH)) +OS_ARCH:=$(subst X86,i586,$(OS_ARCH)) +OS_ARCH:=$(subst x86,i586,$(OS_ARCH)) +OS_ARCH:=$(subst i386,i586,$(OS_ARCH)) +OS_ARCH:=$(subst i486,i586,$(OS_ARCH)) +OS_ARCH:=$(subst i686,i586,$(OS_ARCH)) + +# Check for ARCH_DATA_MODEL, adjust OS_ARCH accordingly +ifndef ARCH_DATA_MODEL + ARCH_DATA_MODEL=32 +endif +ARCH_DATA_MODEL_ERROR= \ + ARCH_DATA_MODEL=$(ARCH_DATA_MODEL) cannot be used with $(OS_NAME)-$(ARCH) +ifeq ($(ARCH_DATA_MODEL),64) + ifeq ($(OS_NAME)-$(OS_ARCH),solaris-i586) + OS_ARCH=x64 + endif + ifeq ($(OS_NAME)-$(OS_ARCH),solaris-sparc) + OS_ARCH=sparcv9 + endif + ifeq ($(OS_ARCH),i586) + x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") + endif + ifeq ($(OS_ARCH),sparc) + x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") + endif +else + ifeq ($(ARCH_DATA_MODEL),32) + ifeq ($(OS_ARCH),x64) + x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") + endif + ifeq ($(OS_ARCH),ia64) + x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") + endif + ifeq ($(OS_ARCH),sparcv9) + x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") + endif else - ifeq ($(PROC_ARCH),X64) - ARCH = x64 - else - ARCH = i586 - endif - endif - EXESUFFIX = .exe - # These need to be different depending on MKS or CYGWIN - ifeq ($(findstring cygdrive,$(shell (cd C:/ && pwd))), ) - GETMIXEDPATH=dosname -s - else - GETMIXEDPATH=cygpath -m -s + x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") endif endif -# Utilities used -CD = cd -CP = cp -ECHO = echo -MKDIR = mkdir -ZIP = zip - # Root of this test area (important to use full paths in some places) -TEST_ROOT := $(shell pwd) +TEST_ROOT := $(shell $(PWD)) # Root of all test results ifdef ALT_OUTPUTDIR ABS_OUTPUTDIR = $(ALT_OUTPUTDIR) else - ABS_OUTPUTDIR = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH) + ABS_OUTPUTDIR = $(TEST_ROOT)/../build/$(OS_NAME)-$(OS_ARCH) endif ABS_BUILD_ROOT = $(ABS_OUTPUTDIR) -ABS_TEST_OUTPUT_DIR := $(ABS_BUILD_ROOT)/testoutput +ABS_TEST_OUTPUT_DIR := $(ABS_BUILD_ROOT)/testoutput/$(UNIQUE_DIR) # Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test) ifndef PRODUCT_HOME @@ -114,13 +172,14 @@ if [ -d $(ABS_JDK_IMAGE) ] ; then \ $(ECHO) "$(ABS_JDK_IMAGE)"; \ else \ - $(ECHO) "$(ABS_BUILD_ROOT)" ; \ + $(ECHO) "$(ABS_BUILD_ROOT)"; \ fi) PRODUCT_HOME := $(PRODUCT_HOME) endif # Expect JPRT to set JPRT_PRODUCT_ARGS (e.g. -server etc.) # Should be passed into 'java' only. +# Could include: -d64 -server -client OR any java option ifdef JPRT_PRODUCT_ARGS JAVA_ARGS = $(JPRT_PRODUCT_ARGS) endif @@ -131,18 +190,131 @@ JAVA_VM_ARGS = $(JPRT_PRODUCT_VM_ARGS) endif +# Check JAVA_ARGS arguments based on ARCH_DATA_MODEL etc. +ifeq ($(OS_NAME),solaris) + D64_ERROR_MESSAGE=Mismatch between ARCH_DATA_MODEL=$(ARCH_DATA_MODEL) and use of -d64 in JAVA_ARGS=$(JAVA_ARGS) + ifeq ($(ARCH_DATA_MODEL),32) + ifneq ($(findstring -d64,$(JAVA_ARGS)),) + x:=$(warning "WARNING: $(D64_ERROR_MESSAGE)") + endif + endif + ifeq ($(ARCH_DATA_MODEL),64) + ifeq ($(findstring -d64,$(JAVA_ARGS)),) + x:=$(warning "WARNING: $(D64_ERROR_MESSAGE)") + endif + endif +endif + # Expect JPRT to set JPRT_ARCHIVE_BUNDLE (path to zip bundle for results) ARCHIVE_BUNDLE = $(ABS_TEST_OUTPUT_DIR)/ARCHIVE_BUNDLE.zip ifdef JPRT_ARCHIVE_BUNDLE ARCHIVE_BUNDLE = $(JPRT_ARCHIVE_BUNDLE) endif +# DISPLAY settings for virtual frame buffer +START_XVFB = start-Xvfb.sh +NOHUP_OUTPUT = $(ABS_TEST_OUTPUT_DIR)/start-Xvfb.nohup-output.txt +DISPLAY_PID_FILE=$(ABS_TEST_OUTPUT_DIR)/xvfb-display-number.txt +DISPLAY_SLEEP_TIME=10 +DISPLAY_MAX_SLEEPS=10 +ifeq ($(OS_NAME),solaris) + VIRTUAL_FRAME_BUFFER = true +endif +ifeq ($(OS_NAME),linux) + VIRTUAL_FRAME_BUFFER = true +endif + +# Does not work yet, display dies as soon as it gets used. :^( +VIRTUAL_FRAME_BUFFER = false + +# Are we using a VIRTUAL_FRAME_BUFFER (Xvfb) +ifeq ($(VIRTUAL_FRAME_BUFFER),true) + + PREP_DISPLAY = \ + $(CP) $(START_XVFB) $(ABS_TEST_OUTPUT_DIR); \ + $(CHMOD) a+x $(ABS_TEST_OUTPUT_DIR)/$(START_XVFB); \ + ( $(CD) $(ABS_TEST_OUTPUT_DIR) && \ + $(NOHUP) $(ABS_TEST_OUTPUT_DIR)/$(START_XVFB) $(DISPLAY_PID_FILE) > $(NOHUP_OUTPUT) 2>&1 && \ + $(SLEEP) $(DISPLAY_SLEEP_TIME) ) & \ + count=1; \ + while [ ! -s $(DISPLAY_PID_FILE) ] ; do \ + $(ECHO) "Sleeping $(DISPLAY_SLEEP_TIME) more seconds, DISPLAY not ready"; \ + $(SLEEP) $(DISPLAY_SLEEP_TIME); \ + count=`$(EXPR) $${count} '+' 1`; \ + if [ $${count} -gt $(DISPLAY_MAX_SLEEPS) ] ; then \ + $(ECHO) "ERROR: DISPLAY not ready, giving up on DISPLAY"; \ + exit 9; \ + fi; \ + done ; \ + DISPLAY=":`$(CAT) $(DISPLAY_PID_FILE)`"; \ + export DISPLAY; \ + $(CAT) $(NOHUP_OUTPUT); \ + $(ECHO) "Prepared DISPLAY=$${DISPLAY}"; \ + $(XHOST) || \ + ( $(ECHO) "ERROR: No display" ; exit 8) + + KILL_DISPLAY = \ + ( \ + DISPLAY=":`$(CAT) $(DISPLAY_PID_FILE)`"; \ + export DISPLAY; \ + if [ -s "$(DISPLAY_PID_FILE)" ] ; then \ + $(KILL) `$(CAT) $(DISPLAY_PID_FILE)` > /dev/null 2>&1; \ + $(KILL) -9 `$(CAT) $(DISPLAY_PID_FILE)` > /dev/null 2>&1; \ + fi; \ + $(ECHO) "Killed DISPLAY=$${DISPLAY}"; \ + ) + +else + + PREP_DISPLAY = $(ECHO) "VIRTUAL_FRAME_BUFFER=$(VIRTUAL_FRAME_BUFFER)" + KILL_DISPLAY = $(ECHO) "VIRTUAL_FRAME_BUFFER=$(VIRTUAL_FRAME_BUFFER)" + +endif + # How to create the test bundle (pass or fail, we want to create this) # Follow command with ";$(BUNDLE_UP_AND_EXIT)", so it always gets executed. ZIP_UP_RESULTS = ( $(MKDIR) -p `dirname $(ARCHIVE_BUNDLE)` \ && $(CD) $(ABS_TEST_OUTPUT_DIR) \ && $(ZIP) -q -r $(ARCHIVE_BUNDLE) . ) -BUNDLE_UP_AND_EXIT = ( exitCode=$$? && $(ZIP_UP_RESULTS) && exit $${exitCode} ) +SUMMARY_TXT = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTreport/text/summary.txt +STATS_TXT_NAME = Stats.txt +STATS_TXT = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/$(STATS_TXT_NAME) +RUNLIST = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/runlist.txt +PASSLIST = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/passlist.txt +FAILLIST = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/faillist.txt +BUNDLE_UP_AND_EXIT = \ +( \ + exitCode=$$? && \ + _summary="$(SUMMARY_TXT)"; \ + $(RM) -f $(STATS_TXT) $(RUNLIST) $(PASSLIST) $(FAILLIST); \ + if [ -r "$${_summary}" ] ; then \ + $(ECHO) "Summary: $${_summary}" > $(STATS_TXT); \ + $(EXPAND) $${_summary} | $(EGREP) -v ' Not run\.' > $(RUNLIST); \ + $(EGREP) ' Passed\.' $(RUNLIST) \ + | $(EGREP) -v ' Error\.' \ + | $(EGREP) -v ' Failed\.' > $(PASSLIST); \ + ( $(EGREP) ' Failed\.' $(RUNLIST); \ + $(EGREP) ' Error\.' $(RUNLIST); \ + $(EGREP) -v ' Passed\.' $(RUNLIST) ) \ + | $(SORT) | $(UNIQ) > $(FAILLIST); \ + if [ $${exitCode} != 0 -o -s $(FAILLIST) ] ; then \ + $(EXPAND) $(FAILLIST) \ + | $(CUT) -d' ' -f1 \ + | $(SED) -e 's@^@FAILED: @' >> $(STATS_TXT); \ + fi; \ + runc="`$(CAT) $(RUNLIST) | $(WC) -l | $(AWK) '{print $$1;}'`"; \ + passc="`$(CAT) $(PASSLIST) | $(WC) -l | $(AWK) '{print $$1;}'`"; \ + failc="`$(CAT) $(FAILLIST) | $(WC) -l | $(AWK) '{print $$1;}'`"; \ + exclc="`$(CAT) $(EXCLUDELIST) | $(WC) -l | $(AWK) '{print $$1;}'`"; \ + $(ECHO) "TEST STATS: run=$${runc} pass=$${passc} fail=$${failc} excluded=$${exclc}" \ + >> $(STATS_TXT); \ + else \ + $(ECHO) "Missing file: $${_summary}" >> $(STATS_TXT); \ + fi; \ + $(CAT) $(STATS_TXT); \ + $(ZIP_UP_RESULTS) && $(KILL_DISPLAY) && \ + exit $${exitCode} \ +) ################################################################ @@ -172,32 +344,239 @@ # Expect JPRT to set TESTDIRS to the jtreg test dirs ifndef TESTDIRS - TESTDIRS = demo/jvmti/gctest demo/jvmti/hprof + TESTDIRS = demo +endif + +# Samevm settings (default is false) +ifndef USE_JTREG_SAMEVM + USE_JTREG_SAMEVM=false +endif +# With samevm, you cannot use -javaoptions? +ifeq ($(USE_JTREG_SAMEVM),true) + EXTRA_JTREG_OPTIONS += -samevm $(JAVA_ARGS) $(JAVA_ARGS:%=-vmoption:%) + JTREG_TEST_OPTIONS = $(JAVA_VM_ARGS:%=-vmoption:%) +else + JTREG_TEST_OPTIONS = $(JAVA_ARGS:%=-javaoptions:%) $(JAVA_VM_ARGS:%=-vmoption:%) +endif + +# Some tests annoy me and fail frequently +PROBLEM_LIST=ProblemList.txt +EXCLUDELIST=$(ABS_TEST_OUTPUT_DIR)/excludelist.txt + +# Create exclude list for this platform and arch +ifdef NO_EXCLUDES +$(EXCLUDELIST): $(PROBLEM_LIST) $(TESTDIRS) + @$(ECHO) "NOTHING_EXCLUDED" > $@ +else +$(EXCLUDELIST): $(PROBLEM_LIST) $(TESTDIRS) + @$(RM) $@ $@.temp1 $@.temp2 + @( ( $(EGREP) -- '$(OS_NAME)-all' $< ) ;\ + ( $(EGREP) -- '$(OS_NAME)-$(OS_ARCH)' $< ) ;\ + ( $(EGREP) -- '$(OS_NAME)-$(OS_VERSION)' $< ) ;\ + ( $(EGREP) -- 'generic-$(OS_ARCH)' $< ) ;\ + ( $(EGREP) -- 'generic-all' $< ) ;\ + ( $(ECHO) "#") ;\ + ) | $(SED) -e 's@^[\ ]*@@' \ + | $(EGREP) -v '^#' > $@.temp1 + @for tdir in $(TESTDIRS) ; do \ + ( ( $(CAT) $@.temp1 | $(EGREP) "^$${tdir}" ) ; $(ECHO) "#" ) >> $@.temp2 ; \ + done + @$(ECHO) "# at least one line" >> $@.temp2 + @( $(EGREP) -v '^#' $@.temp2 ; true ) > $@ + @$(ECHO) "Excluding list contains `$(EXPAND) $@ | $(WC) -l` items" endif +# Running batches of tests with or without samevm +define RunSamevmBatch +$(ECHO) "Running tests in samevm mode: $?" +$(MAKE) TESTDIRS="$?" USE_JTREG_SAMEVM=true UNIQUE_DIR=$@ jtreg_tests +endef +define RunOthervmBatch +$(ECHO) "Running tests in othervm mode: $?" +$(MAKE) TESTDIRS="$?" USE_JTREG_SAMEVM=false UNIQUE_DIR=$@ jtreg_tests +endef +define SummaryInfo +$(ECHO) "Summary for: $?" +$(CAT) $(?:%=$(ABS_TEST_OUTPUT_DIR)/%/$(STATS_TXT_NAME)) +endef + +# ------------------------------------------------------------------ + +# Batches of tests (somewhat arbitrary assigments to jdk_* targets) +JDK_ALL_TARGETS = + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has problems, and doesn't help performance as much as others. +JDK_ALL_TARGETS += jdk_awt +jdk_awt: com/sun/awt java/awt sun/awt + $(call RunOthervmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_beans1 +jdk_beans1: java/beans/beancontext java/beans/PropertyChangeSupport \ + java/beans/Introspector java/beans/Performance \ + java/beans/VetoableChangeSupport java/beans/Statement + $(call RunSamevmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests +JDK_ALL_TARGETS += jdk_beans2 +jdk_beans2: java/beans/Beans java/beans/EventHandler java/beans/XMLDecoder \ + java/beans/PropertyEditor + $(call RunOthervmBatch) +JDK_ALL_TARGETS += jdk_beans3 +jdk_beans3: java/beans/XMLEncoder + $(call RunOthervmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_io +jdk_io: java/io + $(call RunSamevmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_lang +jdk_lang: java/lang + $(call RunSamevmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests +JDK_ALL_TARGETS += jdk_management1 +jdk_management1: javax/management + $(call RunOthervmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests +JDK_ALL_TARGETS += jdk_management2 +jdk_management2: com/sun/jmx com/sun/management sun/management + $(call RunOthervmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_math +jdk_math: java/math + $(call RunSamevmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_misc +jdk_misc: demo javax/imageio javax/naming javax/print javax/script \ + javax/smartcardio javax/sound com/sun/java com/sun/jndi \ + com/sun/org sun/misc sun/pisces + $(call RunSamevmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_net +jdk_net: com/sun/net java/net sun/net + $(call RunSamevmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_nio1 +jdk_nio1: java/nio/file + $(call RunSamevmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests +JDK_ALL_TARGETS += jdk_nio2 +jdk_nio2: java/nio/Buffer java/nio/ByteOrder \ + java/nio/channels java/nio/BufferPoolMXBean java/nio/MappedByteBuffer + $(call RunOthervmBatch) +JDK_ALL_TARGETS += jdk_nio3 +jdk_nio3: com/sun/nio sun/nio + $(call RunOthervmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests +JDK_ALL_TARGETS += jdk_rmi +jdk_rmi: java/rmi javax/rmi sun/rmi + $(call RunOthervmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_security1 +jdk_security1: java/security + $(call RunSamevmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests +JDK_ALL_TARGETS += jdk_security2 +jdk_security2: javax/crypto com/sun/crypto + $(call RunOthervmBatch) +JDK_ALL_TARGETS += jdk_security3 +jdk_security3: com/sun/security lib/security javax/security sun/security + $(call RunOthervmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has problems, and doesn't help performance as much as others. +JDK_ALL_TARGETS += jdk_swing +jdk_swing: javax/swing sun/java2d + $(call RunOthervmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_text +jdk_text: java/text sun/text + $(call RunSamevmBatch) + +# Stable othervm testruns (minus items from PROBLEM_LIST) +# Using samevm has serious problems with these tests +JDK_ALL_TARGETS += jdk_tools1 +jdk_tools1: com/sun/jdi + $(call RunOthervmBatch) +JDK_ALL_TARGETS += jdk_tools2 +jdk_tools2: com/sun/tools sun/jvmstat sun/tools tools vm com/sun/servicetag com/sun/tracing + $(call RunOthervmBatch) + +# Stable samevm testruns (minus items from PROBLEM_LIST) +JDK_ALL_TARGETS += jdk_util +jdk_util: java/util sun/util + $(call RunSamevmBatch) + +# ------------------------------------------------------------------ + +# Run all tests +jdk_all: $(filter-out jdk_awt jdk_rmi jdk_swing, $(JDK_ALL_TARGETS)) + @$(SummaryInfo) + +# These are all phony targets +PHONY_LIST += $(JDK_ALL_TARGETS) + +# ------------------------------------------------------------------ + # Default JTREG to run (win32 script works for everybody) JTREG = $(JT_HOME)/win32/bin/jtreg +# Add any extra options (samevm etc.) +JTREG_BASIC_OPTIONS += $(EXTRA_JTREG_OPTIONS) +# Only run automatic tests +JTREG_BASIC_OPTIONS += -a +# Report details on all failed or error tests, times too +JTREG_BASIC_OPTIONS += -v:fail,error,time +# Retain all files for failing tests +JTREG_BASIC_OPTIONS += -retain:fail,error +# Ignore tests are not run and completely silent about it +JTREG_BASIC_OPTIONS += -ignore:quiet +# Multiple by 2 the timeout numbers +JTREG_BASIC_OPTIONS += -timeoutFactor:2 +# Boost the max memory for jtreg to avoid gc thrashing +JTREG_BASIC_OPTIONS += -J-Xmx512m -jtreg_tests: prep $(JT_HOME) $(PRODUCT_HOME) $(JTREG) - $(RM) $(JTREG).orig - cp $(JTREG) $(JTREG).orig - $(RM) $(JTREG) - sed -e 's@-J\*@-J-*@' $(JTREG).orig > $(JTREG) - chmod a+x $(JTREG) - ( JT_HOME=$(shell $(GETMIXEDPATH) "$(JT_HOME)"); \ - export JT_HOME; \ - $(shell $(GETMIXEDPATH) "$(JTREG)") \ - -a -v:fail,error \ - -ignore:quiet \ - -timeoutFactor:2 \ - $(EXTRA_JTREG_OPTIONS) \ - -r:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTreport \ - -w:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTwork \ - -jdk:$(shell $(GETMIXEDPATH) "$(PRODUCT_HOME)") \ - $(JAVA_ARGS:%=-javaoptions:%) \ - $(JAVA_VM_ARGS:%=-vmoption:%) \ - $(TESTDIRS) \ - ) ; $(BUNDLE_UP_AND_EXIT) +# Make sure jtreg exists +$(JTREG): $(JT_HOME) + +# Run jtreg +jtreg_tests: prep $(PRODUCT_HOME) $(JTREG) $(EXCLUDELIST) + @$(EXPAND) $(EXCLUDELIST) \ + | $(CUT) -d' ' -f1 \ + | $(SED) -e 's@^@Excluding: @' + ( \ + ( JT_HOME=$(shell $(GETMIXEDPATH) "$(JT_HOME)"); \ + export JT_HOME; \ + $(PREP_DISPLAY) && \ + $(shell $(GETMIXEDPATH) "$(JTREG)") \ + $(JTREG_BASIC_OPTIONS) \ + -r:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTreport \ + -w:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)")/JTwork \ + -jdk:$(shell $(GETMIXEDPATH) "$(PRODUCT_HOME)") \ + -exclude:$(shell $(GETMIXEDPATH) "$(EXCLUDELIST)") \ + $(JTREG_TEST_OPTIONS) \ + $(TESTDIRS) \ + ) ; $(BUNDLE_UP_AND_EXIT) \ + ) 2>&1 | $(TEE) $(ABS_TEST_OUTPUT_DIR)/output.txt PHONY_LIST += jtreg_tests
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/ProblemList.txt Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,1211 @@ +########################################################################### +# +# 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. +# +########################################################################### +# +# List of tests that should not be run by test/Makefile, for various reasons: +# 1. Does not run with jtreg -samevm mode +# 2. Causes problems in jtreg -samevm mode for jtreg or tests that follow it +# 3. The test is too slow or consumes too many system resources +# 4. The test fails when run on any official build systems +# +# It is possible that a test being on this list is a mistake, and that some +# other test in samevm mode caused tests to fail, mistakes happen. +# +# Tests marked @ignore are not run by test/Makefile, but harmless to be listed. +# +# Tests that explicitly state "@run main/othervm ...", and are not listed here, +# will be run in the same batch as the samevm tests. +# +# Shell tests are othervm by default. +# +# List items are testnames followed by labels, all MUST BE commented +# as to why they are here and use a label: +# generic-all Problems on all platforms +# generic-ARCH Where ARCH is one of: sparc, sparcv9, x64, i586, etc. +# OSNAME-all Where OSNAME is one of: solaris, linux, windows +# OSNAME-ARCH Specific on to one OSNAME and ARCH, e.g. solaris-x64 +# OSNAME-REV Specific on to one OSNAME and REV, e.g. solaris-5.8 +# +# More than one label is allowed but must be on the same line. +# +############################################################################# +# +# Running the tests: +# cd test && make JT_HOME=jtreg_home PRODUCT_HOME=jdk_home jdk_all +# Or instead of jdk_all, use any of the jdk_* targets. +# +# Samevm Notes: +# * Although some tests may have only been seen to fail on some platforms, +# they might be flagged as 'generic-all' because the problem they have +# could cause hidden slowdowns on other platforms. +# Most samevm problems will be generic-all, but windows usually dislikes +# them the most. +# Address already in use or connection errors indicate a generic port issue. +# (this is not necessarily a samevm issue, but an issue for running the tests +# on shared machines, two people or two test runs will collide). +# * Samevm problem (windows in particular) is not closing all input/output +# * Samevm problem when a test calls setSecurityManager() +# * Samevm problem with setHttps*() is used? (not exactly sure here) +# * Samevm problem when stuffing system properties with non Strings or anything +# * Samevm problem when changing vm settings, or registering any vm actions +# * Samevm problems with deleteOnExit(), if it must happen at end of test +# * Samevm problems with URLClassLoader? (no details here) +# * Samevm problems with dependence on predictable GC or finalizations +# +# Any of the above problems may mean the test needs to be flagged as "othervm". +# +############################################################################# +# +# Fixing the tests: +# +# Some tests just may need to be run with "othervm", and that can easily be +# done my adding a @run line (or modifying any existing @run): +# @run main/othervm NameOfMainClass +# Make sure this @run follows any use of @library. +# Otherwise, if the test is a samevm possibility, make sure the test is +# cleaning up after itself, closing all streams, deleting temp files, etc. +# +# Keep in mind that the bug could be in many places, and even different per +# platform, it could be a bug in any one of: +# - the testcase +# - the jdk (jdk classes, native code, or hotspot) +# - the native compiler +# - the javac compiler +# - the OS (depends on what the testcase does) +# +# If you managed to really fix one of these tests, here is how you can +# remove tests from this list: +# 1. Make sure test passes on all platforms with samevm, or mark it othervm +# 2. Make sure test passes on all platforms when run with it's entire group +# 3. Make sure both VMs are tested, -server and -client, if possible +# 4. Make sure you try the -d64 option on Solaris +# 5. Use a tool like JPRT or something to verify these results +# 6. Delete lines in this file, include the changes with your test changes +# +# You may need to repeat your testing 2 or even 3 times to verify good +# results, some of these samevm failures are not very predictable. +# +############################################################################# + +############################################################################ + +# jdk_awt + +# None of the awt tests are using samevm, might not be worth the effort due +# to the vm overhead not being enough to make a difference. +# In general, the awt tests are problematic with or without samevm, and there +# are issues with using a Xvfb display. + +# Fails on solaris sparc, timedout? in othervm mode +java/awt/event/MouseEvent/AcceptExtraButton/AcceptExtraButton.java generic-all + +# Causes hang in samevm mode??? Solaris 11 i586 +java/awt/FullScreen/SetFSWindow/FSFrame.java generic-all + +# Fails on solaris 11 i586, -client, in othervm mode not sure why +java/awt/Component/PrintAllXcheckJNI/PrintAllXcheckJNI.java generic-all +java/awt/Focus/CloseDialogActivateOwnerTest/CloseDialogActivateOwnerTest.java generic-all +java/awt/FontClass/FontAccess.java generic-all +java/awt/Mixing/HWDisappear.java generic-all +java/awt/Mixing/MixingInHwPanel.java generic-all +java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html generic-all +java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java generic-all +java/awt/Toolkit/SecurityTest/SecurityTest2.java generic-all +java/awt/image/mlib/MlibOpsTest.java generic-all + +# Fails on windows, othervm mode, various errors +java/awt/Focus/NonFocusableWindowTest/NonfocusableOwnerTest.java generic-all +java/awt/Focus/OwnedWindowFocusIMECrashTest/OwnedWindowFocusIMECrashTest.java generic-all +java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java generic-all +java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Standard.java generic-all +java/awt/event/KeyEvent/KeyTyped/CtrlASCII.html generic-all +java/awt/font/Threads/FontThread.java generic-all +java/awt/print/PrinterJob/PrtException.java generic-all + +# Fails with windows X64, othervm, -server +com/sun/awt/Translucency/WindowOpacity.java generic-all +java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java generic-all +java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.html generic-all +java/awt/Focus/AppletInitialFocusTest/AppletInitialFocusTest1.html generic-all +java/awt/Focus/FocusEmbeddedFrameTest/FocusEmbeddedFrameTest.java generic-all +java/awt/Frame/LayoutOnMaximizeTest/LayoutOnMaximizeTest.java generic-all +java/awt/FullScreen/TranslucentWindow/TranslucentWindow.java generic-all +java/awt/Mixing/MixingOnShrinkingHWButton.java generic-all +java/awt/Mouse/MouseModifiersUnitTest/ExtraButtonDrag.java generic-all + +############################################################################ + +# jdk_beans + +# A large set of the beans tests set the security manager, which would seem +# to indicate that a large number of them should be "othervm", yet are all +# very small tests and could greatly benefit from a samevm test run. +# So a large batch of beans tests are currently run with othervm mode. + +# Linux, some kind of problems with X11 display +java/beans/PropertyChangeSupport/Test4682386.java generic-all +java/beans/PropertyChangeSupport/TestSynchronization.java generic-all +java/beans/Statement/Test4653179.java generic-all + +# Runs REALLY slow on Solaris sparc for some reason, both -client and -server +java/beans/XMLEncoder/Test4625418.java solaris-sparc + +# Problems with samevm and setting security manager (speculation partially) +java/beans/Beans/Test4080522.java generic-all +java/beans/EventHandler/Test6277246.java generic-all +java/beans/EventHandler/Test6277266.java generic-all +java/beans/Introspector/Test6277246.java generic-all +java/beans/Introspector/4168475/Test4168475.java generic-all +java/beans/Introspector/4520754/Test4520754.java generic-all +java/beans/Introspector/6380849/TestBeanInfo.java generic-all +java/beans/Introspector/Test4144543.java generic-all + +# Failed to call method solaris-sparc??? +java/beans/EventHandler/Test6788531.java generic-all + +# Jar or class not found??? +java/beans/XMLEncoder/6329581/Test6329581.java generic-all + +############################################################################ + +# jdk_io + +# Many of these tests have a tendency to leave input streams open, which +# will cause following tests to be failures when used in samevm mode. + +# Should be othervm, or corrected for samevm, fails with samevm: +java/io/BufferedReader/BigMark.java generic-all +java/io/BufferedReader/ReadLineSync.java generic-all + +# One of these is leaving "a.ser" file open, windows samevm +java/io/Serializable/duplicateSerialFields/Setup.java generic-all +java/io/Serializable/duplicateSerialFields/Test.java generic-all + +# One of these leaving foo.ser open, windows samevm problem +java/io/Serializable/enum/constantSubclasses/Read.java generic-all +java/io/Serializable/enum/constantSubclasses/Write.java generic-all +java/io/Serializable/enum/missingConstant/Read.java generic-all +java/io/Serializable/enum/missingConstant/Write.java generic-all + +# This is leaving subtest1.tmp open, windows samevm problem +java/io/Serializable/oldTests/AnnotateClass.java generic-all + +# One or more of these leave a piotest* file open, windows samevm +java/io/Serializable/oldTests/ArrayFields.java generic-all +java/io/Serializable/oldTests/ArraysOfArrays.java generic-all +java/io/Serializable/oldTests/BinaryTree.java generic-all +java/io/Serializable/oldTests/CircularList.java generic-all +java/io/Serializable/oldTests/SerializeWithException.java generic-all +java/io/Serializable/oldTests/SimpleArrays.java generic-all +java/io/Serializable/oldTests/WritePrimitive.java generic-all + +# Missing close on file 0.ser, windows samevm +java/io/Serializable/enum/badResolve/Read.java generic-all +java/io/Serializable/enum/badResolve/Write.java generic-all + +# One of these tests is leaving parents.ser open, windows samevm +java/io/Serializable/parents/EvolvedClass.java generic-all +java/io/Serializable/parents/OriginalClass.java generic-all + +# One of these tests is leaving file foo.ser and/or bar.ser open, windows samevm +java/io/Serializable/fieldTypeString/Read.java generic-all +java/io/Serializable/fieldTypeString/Write.java generic-all + +# One of these tests is leaving tmp.ser file open, windows samevm +java/io/Serializable/ClassCastExceptionDetail/Read.java generic-all +java/io/Serializable/ClassCastExceptionDetail/Write.java generic-all +java/io/Serializable/GetField/Read.java generic-all +java/io/Serializable/GetField/Read2.java generic-all +java/io/Serializable/GetField/Write.java generic-all +java/io/Serializable/PutField/Read.java generic-all +java/io/Serializable/PutField/Read2.java generic-all +java/io/Serializable/PutField/Write.java generic-all +java/io/Serializable/PutField/Write2.java generic-all +java/io/Serializable/arraySuidConflict/Read.java generic-all +java/io/Serializable/arraySuidConflict/Write.java generic-all +java/io/Serializable/backRefCNFException/Read.java generic-all +java/io/Serializable/backRefCNFException/Write.java generic-all +java/io/Serializable/class/Test.java generic-all +java/io/Serializable/evolution/AddedExternField/ReadAddedField.java generic-all +java/io/Serializable/evolution/AddedExternField/WriteAddedField.java generic-all +java/io/Serializable/evolution/AddedExternField/run.sh generic-all +java/io/Serializable/evolution/AddedField/ReadAddedField.java generic-all +java/io/Serializable/evolution/AddedField/WriteAddedField.java generic-all +java/io/Serializable/evolution/AddedSuperClass/ReadAddedSuperClass.java generic-all +java/io/Serializable/evolution/AddedSuperClass/ReadAddedSuperClass2.java generic-all +java/io/Serializable/evolution/AddedSuperClass/WriteAddedSuperClass.java generic-all +java/io/Serializable/proxy/skipMissing/Read.java generic-all +java/io/Serializable/proxy/skipMissing/Write.java generic-all +java/io/Serializable/readObjectNoData/Read.java generic-all +java/io/Serializable/readObjectNoData/Write.java generic-all +java/io/Serializable/skipWriteObject/Read.java generic-all +java/io/Serializable/skipWriteObject/Write.java generic-all +java/io/Serializable/skippedObjCNFException/Read.java generic-all +java/io/Serializable/skippedObjCNFException/Write.java generic-all +java/io/Serializable/stopCustomDeserialization/Read.java generic-all +java/io/Serializable/stopCustomDeserialization/Write.java generic-all +java/io/Serializable/unresolvedClassDesc/Read.java generic-all +java/io/Serializable/unresolvedClassDesc/Write.java generic-all +java/io/Serializable/unshared/Read.java generic-all +java/io/Serializable/unshared/Write.java generic-all +java/io/Serializable/wrongReturnTypes/Read.java generic-all +java/io/Serializable/wrongReturnTypes/Write.java generic-all + +# Windows samevm issues? triggers other tests to fail, missing close() on f.txt? +java/io/DataInputStream/OpsAfterClose.java generic-all + +# Windows 32bit samevm failure: RuntimeException: File.getFreeSpace() failed +java/io/File/MaxPathLength.java generic-all + +# Should be othervm, or corrected for samevm, fails with samevm: +java/io/File/DeleteOnExit.java generic-all +java/io/File/DeleteOnExitLong.java generic-all +java/io/File/DeleteOnExitNPE.java generic-all +java/io/File/IsHidden.java generic-all +java/io/FileDescriptor/FileChannelFDTest.java generic-all +java/io/FileDescriptor/Finalize.java generic-all +java/io/FileInputStream/FinalizeShdCallClose.java generic-all + +# Known to cause samevm issues on windows, other tests fail, missing close()? +java/io/FileInputStream/OpsAfterClose.java generic-all + +# Should be othervm, or corrected for samevm, fails with samevm: +java/io/FileOutputStream/FinalizeShdCallClose.java generic-all + +# Known to cause samevm issues on windows, other tests fail, missing close()? +java/io/FileOutputStream/OpsAfterClose.java generic-all + +# Windows samevm issues? triggers other tests to fail, missing close() on f.txt? +java/io/InputStream/OpsAfterClose.java generic-all + +# Missing close() on x.ReadBounds file? Windows samevm issues +java/io/InputStream/ReadParams.java generic-all + +# Known to cause samevm issues on windows, other tests fail, missing close()? +java/io/InputStreamReader/GrowAfterEOF.java generic-all + +# Should be othervm, or corrected for samevm, fails with samevm: +java/io/ObjectInputStream/ResolveProxyClass.java generic-all + +# Not doing a close() on x.ParameterCheck file? windows samevm cascade error +java/io/RandomAccessFile/ParameterCheck.java generic-all + +# Not doing a close on x.ReadLine file? windows cascade samevm problems +java/io/RandomAccessFile/ReadLine.java generic-all + +# Not doing close on file input x.WriteByteChars, windows samevm problems +java/io/RandomAccessFile/WriteBytesChars.java generic-all + +# Not doing close on file input x.WriteUTF, windows samevm problems +java/io/RandomAccessFile/WriteUTF.java generic-all + +# Possibly, not doing a close() on input.txt, windows samevm issues. +java/io/RandomAccessFile/skipBytes/SkipBytes.java generic-all +java/io/readBytes/MemoryLeak.java generic-all +java/io/readBytes/ReadBytesBounds.java generic-all + +# Missing close on fields.ser, windows samevm +java/io/Serializable/checkModifiers/CheckModifiers.java generic-all + +# Should be othervm, or corrected for samevm, fails with samevm: +java/io/Serializable/auditStreamSubclass/AuditStreamSubclass.java generic-all +java/io/Serializable/proxy/Basic.java generic-all + +# Possibly not doing a close() on input.txt, windows samevm issues. +java/io/StreamTokenizer/Comment.java generic-all + +############################################################################ + +# jdk_lang + +# Some of these tests (like java/lang/management) may just need to be marked +# othervm, but that is partially speculation. + +# Times out on solaris 10 sparc +java/lang/ClassLoader/Assert.java generic-all + +# Fedora 9 X64, RuntimeException: MyThread expected to be blocked on lock, but got null +java/lang/management/ThreadMXBean/ThreadStateTest.java generic-all + +# RuntimeException: Uptime of the JVM is more than 30 minutes (32 minutes). +java/lang/management/RuntimeMXBean/UpTime.java generic-all + +# Times out on solaris sparc occasionally, in samevm mode +java/lang/Runtime/exec/ExecWithDir.java generic-all +java/lang/ProcessBuilder/Basic.java generic-all + +# Solaris sparc, samevm, java.lang.Exception: Read from closed pipe hangs +java/lang/Runtime/exec/SleepyCat.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/lang/annotation/ParameterAnnotations.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/lang/ClassLoader/defineClass/DefineClassByteBuffer.java generic-all +java/lang/ClassLoader/findSystemClass/Loader.java generic-all + +# Fedora 9 32bit, -client, samevm, Error while cleaning up threads after test +java/lang/management/ThreadMXBean/Locks.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/lang/management/ClassLoadingMXBean/LoadCounts.java generic-all +java/lang/management/ManagementFactory/MBeanServerMXBeanUnsupportedTest.java generic-all +java/lang/management/ManagementFactory/MXBeanProxyTest.java generic-all +java/lang/management/ManagementFactory/ThreadMXBeanProxy.java generic-all +java/lang/management/MemoryMXBean/CollectionUsageThreshold.java generic-all +java/lang/management/MemoryMXBean/GetMBeanInfo.java generic-all +java/lang/management/MemoryMXBean/LowMemoryTest.java generic-all +java/lang/management/MemoryMXBean/MemoryManagement.java generic-all +java/lang/management/MemoryMXBean/MemoryTest.java generic-all +java/lang/management/MemoryMXBean/Pending.java generic-all + +# Problematic on all platforms (even as othervm) +java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java generic-all + +# Causes jtreg exit samevm issues due to non-String object in system properties +java/lang/management/RuntimeMXBean/GetSystemProperties.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/lang/management/RuntimeMXBean/PropertiesTest.java generic-all +java/lang/management/ThreadMXBean/AllThreadIds.java generic-all +java/lang/management/ThreadMXBean/EnableTest.java generic-all +java/lang/management/ThreadMXBean/FindMonitorDeadlock.java generic-all +java/lang/management/ThreadMXBean/LockingThread.java generic-all +java/lang/management/ThreadMXBean/MonitorDeadlock.java generic-all +java/lang/management/ThreadMXBean/MyOwnSynchronizer.java generic-all +java/lang/management/ThreadMXBean/SharedSynchronizer.java generic-all +java/lang/management/ThreadMXBean/SynchronizerLockingThread.java generic-all +java/lang/management/ThreadMXBean/ThreadCounts.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/lang/reflect/Proxy/Boxing.java generic-all +java/lang/reflect/Proxy/ClassRestrictions.java generic-all +java/lang/reflect/Proxy/returnTypes/Test.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/lang/Runtime/exec/LotsOfOutput.java generic-all +java/lang/System/ExitFinalizersAndJIT.java generic-all +java/lang/System/finalization/FinThreads.java generic-all +java/lang/System/IgnoreNullSecurityManager.java generic-all +java/lang/Thread/GenerifyStackTraces.java generic-all +java/lang/Thread/StackTraces.java generic-all +java/lang/ThreadGroup/Daemon.java generic-all +java/lang/ThreadGroup/NullThreadName.java generic-all + +# Times out on solaris sparc -server +java/lang/ThreadLocal/MemoryLeak.java solaris-all + +# Windows X64, RuntimeException: MyThread expected to have RUNNABLE but got WAITING +java/lang/Thread/ThreadStateTest.java generic-all + +# Timeout on windows 64bit +java/lang/ClassLoader/deadlock/TestCrossDelegate.sh generic-all + +############################################################################ + +# jdk_management + +# Solaris 10 sparc, NPE from org.omg.stub.javax.management.remote.rmi._RMIConnectionImpl_Tie._invoke +javax/management/remote/mandatory/threads/ExecutorTest.java generic-all + +# Linux 32bit Fedora 9, IllegalStateException +javax/management/monitor/RuntimeExceptionTest.java generic-all + +# Problems with rmi connection, othervm +javax/management/remote/mandatory/subjectDelegation/SubjectDelegation2Test.java generic-all + +# Fails with port already in use +sun/management/jmxremote/bootstrap/SSLConfigFilePermissionTest.sh generic-all + +# Fails with port already in use +sun/management/jmxremote/bootstrap/RmiRegistrySslTest.sh generic-all + +# Windows, connection can't last that long +javax/management/eventService/LeaseTest.java generic-all + +# Linux othervm, X64, java.lang.Exception: Failed: ratio=102.4027795593753 +javax/management/remote/mandatory/notif/ListenerScaleTest.java generic-all + +# Windows run seems to have triggered a hotspot gc error (see 6801625) +com/sun/management/HotSpotDiagnosticMXBean/DumpHeap.sh generic-all + +# rmi problem? othervm, java.lang.reflect.UndeclaredThrowableException +javax/management/remote/mandatory/subjectDelegation/SubjectDelegation3Test.java generic-all + +# Linux Fedora 9 32bit NPE in rmi server somehere??? othervm +javax/management/remote/mandatory/notif/NotificationBufferDeadlockTest.java generic-all + +# Times out on solaris sparc, with othervm +javax/management/eventService/AddRemoveListenerTest.java generic-all + +# Linux i586 and x64 -server, timed out waiting for threads to expire? othervm +javax/management/eventService/EventClientThreadTest.java generic-all + +# Linux i586 -server, Expected to receive 20, but got 21, othervm +# Fails on Linux X64 -server 20!=21 +javax/management/eventService/FetchingTest.java generic-all + +# NPE on windows 2000 i586 -client and -server +javax/management/eventService/CustomForwarderTest.java windows-all + +# Windows i586 failure, callback did not complete +javax/management/eventService/LeaseManagerDeadlockTest.java windows-all + +# Port already in use +sun/management/jmxremote/bootstrap/LocalManagementTest.sh generic-all + +# Failed to initialize connector (also overflowing jtreg io buffers) +sun/management/jmxremote/bootstrap/RmiBootstrapTest.sh generic-all +sun/management/jmxremote/bootstrap/RmiSslBootstrapTest.sh generic-all + +# Windows X64, java.lang.IllegalStateException +javax/management/monitor/AttributeArbitraryDataTypeTest.java generic-all + +############################################################################ + +# jdk_math + +# Problems with rounding add failures on solaris-sparcv9 and -server +java/math/BigDecimal/AddTests.java solaris-sparcv9 + +# Problems on windows with samevm, missing inputstream close()? +# Also times out on solaris-sparcv9 -server +java/math/BigInteger/BigIntegerTest.java generic-all + +# Should be samevm? But seems problematic with samevm on windows +java/math/BigInteger/ModPow65537.java generic-all + +############################################################################ + +# jdk_misc + +# On Windows com.sun.java.swing.plaf.gtk does not exist, always fails there +com/sun/java/swing/plaf/gtk/Test6635110.java windows-all + +# Need to be marked othervm, or changed to be samevm safe +com/sun/jndi/ldap/ReadTimeoutTest.java generic-all +com/sun/jndi/rmi/registry/RegistryContext/UnbindIdempotent.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +com/sun/org/apache/xml/internal/security/transforms/ClassLoaderTest.java generic-all + +# Solaris sparc and others, exception in initializer +javax/imageio/CachePremissionsTest/CachePermissionsTest.java generic-all + +# Leaves file rgba_* open, fails with windows samevm +javax/imageio/plugins/png/PngOutputTypeTest.java generic-all + +# Suspect test.png file is left open, windows samevm problems +javax/imageio/plugins/png/ITXtTest.java generic-all + +# Solaris sparc and others, failed to compile testcase +javax/imageio/metadata/DOML3Node.java generic-all + +# One of these tests is leaving file IMGP1001.JPG open, windows samevm +javax/imageio/plugins/jpeg/ConcurrentReadingTest.java generic-all +javax/imageio/plugins/jpeg/ReadingInterruptionTest.java generic-all + +# One of these files is missing a close on writer_* files, windows samevm +javax/imageio/plugins/jpeg/ConcurrentWritingTest.java generic-all +javax/imageio/plugins/jpeg/WritingInterruptionTest.java generic-all + +# Leaving file test.jpg open, windows samevm +javax/imageio/plugins/jpeg/ReadAsGrayTest.java generic-all + +# Missing close on file wbmp*, windows samevm +javax/imageio/plugins/wbmp/CanDecodeTest.java generic-all + +# Exclude all javax/print tests, even if they passed, they may need samevm work + +# Times out on solaris-sparc, sparcv9, x64 -server, some on i586 -client +javax/print/attribute/autosense/PrintAutoSenseData.java generic-all +javax/print/attribute/Chroma.java generic-all +javax/print/attribute/CollateAttr.java generic-all +javax/print/attribute/PSCopiesFlavorTest.java generic-all +javax/print/LookupServices.java generic-all +javax/print/TestRaceCond.java generic-all + +# These tests really require a printer (might all be windows only tests?) +javax/print/CheckDupFlavor.java generic-all +javax/print/PrintSE/PrintSE.sh generic-all +javax/print/attribute/ChromaticityValues.java generic-all +javax/print/attribute/GetCopiesSupported.java generic-all +javax/print/attribute/SidesPageRangesTest.java generic-all +javax/print/attribute/SupportedPrintableAreas.java generic-all + +# Only print test left, excluding just because all print tests have been +javax/print/attribute/MediaMappingsTest.java generic-all + +############################################################################ + +# jdk_net + +# Suspect many of these tests auffer from using fixed ports, no concrete +# evidence. + +# Fails on OpenSolaris, BindException unexpected +java/net/BindException/Test.java generic-all + +# Fails on OpenSolaris, times out +java/net/MulticastSocket/SetOutgoingIf.java generic-all + +# Timed out on Solaris 10 X86. +com/sun/net/httpserver/Test3.java generic-all + +# Exception in test on windows +com/sun/net/httpserver/bugs/B6373555.java windows-all + +# One of these pollutes the samevm on Linux, too many open files, kills jtreg +com/sun/net/httpserver/bugs/B6339483.java generic-all +com/sun/net/httpserver/bugs/B6341616.java generic-all + +# Suspects in cascading samevm problem, solaris 11 i586 (needs othervm?) +# Suspect use of setHttps*()? +com/sun/net/httpserver/SelCacheTest.java generic-all +com/sun/net/httpserver/Test1.java generic-all +com/sun/net/httpserver/Test12.java generic-all +com/sun/net/httpserver/Test13.java generic-all +com/sun/net/httpserver/Test6a.java generic-all +com/sun/net/httpserver/Test7a.java generic-all +com/sun/net/httpserver/Test8a.java generic-all +com/sun/net/httpserver/Test9.java generic-all +com/sun/net/httpserver/Test9a.java generic-all + +# 10,000 connections, fails on Linux and makes tests&jtreg fail with samevm +com/sun/net/httpserver/bugs/B6361557.java generic-all + +# Address already in use with samevm? Always? Solaris sparc, probably ports +java/net/Authenticator/B4933582.sh generic-all +java/net/DatagramSocket/SendSize.java generic-all + +# Solaris 11: exception wrong address??? +java/net/Inet6Address/B6558853.java generic-all + +# Not closing stream on file i6a1, windows samevm problem +java/net/Inet6Address/serialize/Serialize.java generic-all + +# Linux x64 fails "network unreachable"? +java/net/ipv6tests/TcpTest.java generic-all + +# Linux i586, fails with unexpected output +java/net/MulticastSocket/NoLoopbackPackets.java linux-i586 + +# Times out on windows x64, fails with samevm on solaris 11 i586 +java/net/ServerSocket/AcceptCauseFileDescriptorLeak.java generic-all + +# Address already in use +java/net/DatagramSocket/DatagramTimeout.java generic-all + +# Fails on windows, takes too long and fails +# Solaris 10 sparcv9, samevm, java.lang.Exception: Takes too long. Dead lock +java/net/Socket/DeadlockTest.java generic-all + +# Linux i586 address already in use or connection error, samevm issues +java/net/Socket/AccurateTimeout.java generic-all +java/net/Socket/asyncClose/BrokenPipe.java generic-all +java/net/Socket/CloseAvailable.java generic-all +java/net/Socket/FDClose.java generic-all + +# Linux X64 address already in use, samevm issues +java/net/Socket/LingerTest.java generic-all +java/net/Socket/LinkLocal.java generic-all +java/net/Socket/NullHost.java generic-all +java/net/Socket/ProxyCons.java generic-all +java/net/Socket/ReadTimeout.java generic-all + +# Linux X64 address already in use, samevm issues +java/net/Socket/SetReceiveBufferSize.java generic-all + +# Linux i586 address already in use or connection error, samevm issues +java/net/Socket/setReuseAddress/Basic.java generic-all +java/net/Socket/setReuseAddress/Restart.java generic-all + +# Linux X64 address already in use, samevm issues +java/net/Socket/SetSoLinger.java generic-all + +# Address already in use, windows samevm +java/net/Socket/Timeout.java generic-all + +# Linux X64 address already in use, samevm issues +java/net/Socket/ShutdownBoth.java generic-all +java/net/Socket/SoTimeout.java generic-all +java/net/Socket/TestClose.java generic-all +java/net/Socket/UrgentDataTest.java generic-all +java/net/SocketInputStream/SocketClosedException.java generic-all +java/net/SocketInputStream/SocketTimeout.java generic-all + +# Linux i586, address already in use or timeout, samevm issues +java/net/URLConnection/B5052093.java generic-all +java/net/URLConnection/contentHandler/UserContentHandler.java generic-all +java/net/URLConnection/DisconnectAfterEOF.java generic-all +java/net/URLConnection/HandleContentTypeWithAttrs.java generic-all +java/net/URLConnection/Responses.java generic-all +java/net/URLConnection/TimeoutTest.java generic-all +java/net/URLConnection/ZeroContentLength.java generic-all + +# Solaris 11 i586 fails with samevm, not sure why +java/net/Authenticator/B4769350.java generic-all +java/net/HttpURLConnection/HttpResponseCode.java generic-all +java/net/ResponseCache/B6181108.java generic-all +java/net/ResponseCache/ResponseCacheTest.java generic-all +java/net/URL/GetContent.java generic-all +java/net/URL/TestIPv6Addresses.java generic-all +java/net/URLClassLoader/HttpTest.java generic-all +java/net/URLConnection/HttpContinueStackOverflow.java generic-all +java/net/URLConnection/Redirect307Test.java generic-all +java/net/URLConnection/RedirectLimit.java generic-all +java/net/URLConnection/ResendPostBody.java generic-all +java/net/URL/OpenStream.java generic-all +java/net/URLClassLoader/ClassLoad.java generic-all +java/net/URLConnection/SetIfModifiedSince.java generic-all +java/net/URLConnection/URLConnectionHeaders.java generic-all + +# Linux i586 Connection refused or address already in use, samevm issues +sun/net/ftp/B6427768.java generic-all +sun/net/ftp/FtpGetContent.java generic-all +sun/net/ftp/FtpURL.java generic-all + +# Failed on solaris 10 i586, Exception: should have gotten HttpRetryException? +sun/net/www/http/ChunkedOutputStream/Test.java generic-all + +# Trouble cleaning up threads in samevm mode on solaris 11 i586 +sun/net/www/http/HttpClient/ProxyTest.java generic-all +sun/net/www/http/ChunkedInputStream/ChunkedEncodingTest.java generic-all +sun/net/www/http/ChunkedInputStream/ChunkedEncodingWithProgressMonitorTest.java generic-all +sun/net/www/http/HttpClient/B6726695.java generic-all +sun/net/www/http/HttpClient/MultiThreadTest.java generic-all +sun/net/www/http/KeepAliveCache/KeepAliveTimerThread.java generic-all + +# Connection refused, windows samevm +sun/net/www/protocol/http/DigestTest.java generic-all + +############################################################################ + +# jdk_nio + +# Suspect many of these tests auffer from using fixed ports, no concrete +# evidence. + +# Fails on OpenSolaris, IllegalStateException: Cannot add or remove addresses +# from a channel that is bound to the wildcard address +com/sun/nio/sctp/SctpChannel/Bind.java generic-all + +# Failed on OpenSolaris, java.lang.AssertionError: Unknown event type +com/sun/nio/sctp/SctpChannel/Receive.java generic-all + +# Triggers a hotspot crash on Fedora 9 32bit -server and Windows X64 samevm +sun/nio/cs/TestUTF8.java generic-all + +# Solaris sparc, socket timeout +java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh generic-all + +# Runtime exception on windows X64, samevm mode +java/nio/channels/Selector/WakeupNow.java generic-all + +# Occasional errors, solarix x86, address already in use, othervm mode +java/nio/channels/Selector/SelectorTest.java generic-all + +# Fails on Linux Fedora 9 X64 +sun/nio/cs/FindDecoderBugs.java generic-all + +# Solaris 11 gave assert error and "connection refused", samevm issues? +com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java generic-all + +# Fails with othervm on solaris 11 i586 +com/sun/nio/sctp/SctpChannel/CommUp.java generic-all +com/sun/nio/sctp/SctpChannel/Connect.java generic-all +com/sun/nio/sctp/SctpMultiChannel/Branch.java generic-all +com/sun/nio/sctp/SctpMultiChannel/Send.java generic-all +com/sun/nio/sctp/SctpMultiChannel/SocketOptionTests.java generic-all + +# Linux 64bit failures. too many files open +java/nio/channels/Selector/HelperSlowToDie.java generic-all + +# Timeouts etc. on Window +java/nio/channels/AsyncCloseAndInterrupt.java windows-all + +# Gets java.lang.ExceptionInInitializerError on windows: (Windows 2000 only?) +java/nio/channels/AsynchronousChannelGroup/Basic.java windows-5.0 +java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java windows-5.0 +java/nio/channels/AsynchronousChannelGroup/Identity.java windows-5.0 +java/nio/channels/AsynchronousChannelGroup/Restart.java windows-5.0 +java/nio/channels/AsynchronousDatagramChannel/Basic.java windows-5.0 +java/nio/channels/AsynchronousFileChannel/Lock.java windows-5.0 +java/nio/channels/AsynchronousServerSocketChannel/Basic.java windows-5.0 +java/nio/channels/AsynchronousServerSocketChannel/WithSecurityManager.java windows-5.0 +java/nio/channels/AsynchronousSocketChannel/Basic.java windows-5.0 +java/nio/channels/AsynchronousSocketChannel/DieBeforeComplete.java windows-5.0 +java/nio/channels/AsynchronousSocketChannel/Leaky.java windows-5.0 +java/nio/channels/AsynchronousSocketChannel/StressLoopback.java windows-5.0 +java/nio/channels/Channels/Basic2.java windows-5.0 + +# Solaris sparc timeout +java/nio/channels/DatagramChannel/Connect.java generic-all + +# Solaris i586 timeouts +java/nio/channels/DatagramChannel/EmptyBuffer.java solaris-all + +# Failed loopback connection? On windows 32bit? +# Considered a stress test, can consume all resources. +java/nio/channels/Selector/LotsOfChannels.java generic-all + +# Solaris sparcv9, just fails with exception +java/nio/channels/Selector/OpRead.java solaris-sparc + +# Windows i586 client, crashed hotspot? Unpredictable +# Considered a stress test, can consume all resources. +java/nio/channels/Selector/RegAfterPreClose.java generic-all + +# Solaris i586, cannot assign address, samevm issues +java/nio/channels/Selector/SelectorLimit.java generic-all + +# Socket timeout windows X64 +java/nio/channels/ServerSocketChannel/AdaptServerSocket.java windows-all + +# Timeouts etc. on Window +java/nio/channels/SocketChannel/ConnectState.java windows-all +java/nio/channels/SocketChannel/FinishConnect.java windows-all + +# Need to be marked othervm, or changed to be samevm safe +java/nio/channels/SocketChannel/OpenLeak.java generic-all + +# Gets java.net.BindException alot (static port number?) +java/nio/channels/SocketChannel/VectorIO.java generic-all + +# Solaris i586 java.net.BindExceptions +java/nio/channels/SocketChannel/VectorParams.java solaris-all + +# Linux i586 address already in use, samevm issues +java/nio/channels/SocketChannel/Write.java generic-all + +# Fails on all platforms due to overlap of JDK jar file contents: +sun/nio/cs/Test4200310.sh generic-all + +# Depends on motif packages that do not exist all the time: +sun/nio/cs/TestX11CNS.java generic-all + +############################################################################ + +# jdk_rmi + +# Port already in use, fails on sparc, othervm +java/rmi/reliability/benchmark/runRmiBench.sh generic-all + +# Already in use port issues? othervm solaris +java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java generic-all +java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java generic-all + +# Address already in use, othervm mode, solaris +java/rmi/activation/Activatable/elucidateNoSuchMethod/ElucidateNoSuchMethod.java generic-all +java/rmi/activation/Activatable/forceLogSnapshot/ForceLogSnapshot.java generic-all + +# Registry already running on port, solaris +java/rmi/Naming/legalRegistryNames/LegalRegistryNames.java generic-all + +# Fails on Linux 32 and 64bit -server?, impl not garbage collected??? +java/rmi/transport/pinLastArguments/PinLastArguments.java generic-all + +# Times out on solaris sparc +java/rmi/server/RemoteServer/AddrInUse.java generic-all + +# Connection error on Windows i586 -server +# Also connection errors in othervm on Solaris 10 sparc, same port??? +sun/rmi/transport/tcp/DeadCachedConnection.java generic-all + +# Connection errors in othervm on Solaris 10 sparc, same port??? +java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java generic-all +java/rmi/activation/Activatable/checkAnnotations/CheckAnnotations.java generic-all +java/rmi/activation/Activatable/checkImplClassLoader/CheckImplClassLoader.java generic-all +java/rmi/activation/Activatable/checkRegisterInLog/CheckRegisterInLog.java generic-all +java/rmi/activation/Activatable/createPrivateActivable/CreatePrivateActivatable.java generic-all +java/rmi/activation/Activatable/downloadParameterClass/DownloadParameterClass.java generic-all +java/rmi/activation/Activatable/extLoadedImpl/ext.sh generic-all +java/rmi/activation/Activatable/inactiveGroup/InactiveGroup.java generic-all +java/rmi/activation/Activatable/lookupActivationSystem/LookupActivationSystem.java generic-all +java/rmi/activation/Activatable/nestedActivate/NestedActivate.java generic-all +java/rmi/activation/Activatable/restartCrashedService/RestartCrashedService.java generic-all +java/rmi/activation/Activatable/restartLatecomer/RestartLatecomer.java generic-all +java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java generic-all +java/rmi/activation/Activatable/unregisterInactive/UnregisterInactive.java generic-all +java/rmi/activation/ActivateFailedException/activateFails/ActivateFails.java generic-all +java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java generic-all +java/rmi/activation/ActivationSystem/activeGroup/IdempotentActiveGroup.java generic-all +java/rmi/reliability/juicer/AppleUserImpl.java generic-all +java/rmi/server/RMISocketFactory/useSocketFactory/unicast/UseCustomSocketFactory.java generic-all +java/rmi/server/UnicastRemoteObject/keepAliveDuringCall/KeepAliveDuringCall.java generic-all +java/rmi/transport/handshakeTimeout/HandshakeTimeout.java generic-all +java/rmi/activation/Activatable/restartService/RestartService.java generic-all +java/rmi/activation/ActivationSystem/modifyDescriptor/ModifyDescriptor.java generic-all +java/rmi/activation/ActivationSystem/stubClassesPermitted/StubClassesPermitted.java generic-all +java/rmi/activation/ActivationSystem/unregisterGroup/UnregisterGroup.java generic-all +java/rmi/activation/CommandEnvironment/SetChildEnv.java generic-all +java/rmi/registry/classPathCodebase/ClassPathCodebase.java generic-all +java/rmi/registry/reexport/Reexport.java generic-all +java/rmi/server/Unreferenced/finiteGCLatency/FiniteGCLatency.java generic-all +java/rmi/server/Unreferenced/leaseCheckInterval/LeaseCheckInterval.java generic-all +java/rmi/server/Unreferenced/unreferencedContext/UnreferencedContext.java generic-all +java/rmi/server/useCustomRef/UseCustomRef.java generic-all +java/rmi/transport/checkFQDN/CheckFQDN.java generic-all +java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java generic-all +java/rmi/server/RMISocketFactory/useSocketFactory/activatable/UseCustomSocketFactory.java generic-all +java/rmi/server/RMISocketFactory/useSocketFactory/registry/UseCustomSocketFactory.java generic-all +java/rmi/server/UnicastRemoteObject/unexportObject/UnexportLeak.java generic-all + +############################################################################ + +# jdk_security + +# Run too slow on Solaris 10 sparc +sun/security/ssl/com/sun/net/ssl/internal/ssl/InputRecord/SSLSocketTimeoutNulls.java solaris-sparc +sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/ClientTimeout.java solaris-sparc +sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/ServerTimeout.java solaris-sparc +sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/ReadTimeout.java solaris-sparc +sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/NotifyHandshakeTest.sh solaris-sparc +sun/security/tools/keytool/AltProviderPath.sh solaris-sparc + +# Solaris 10 sparc, passed/failed confusion? java.security.ProviderException: update() failed +sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/AsyncSSLSocketClose.java generic-all + +# Seem really slow on Solaris sparc, being excluded just for timing reasons +sun/security/tools/jarsigner/AlgOptions.sh solaris-sparc +sun/security/tools/jarsigner/nameclash.sh solaris-sparc +sun/security/krb5/auto/basic.sh solaris-sparc +sun/security/provider/PolicyFile/getinstance/getinstance.sh solaris-sparc +sun/security/tools/jarsigner/samename.sh solaris-sparc + +# Timed out, Solaris 10 64bit sparcv9 +com/sun/crypto/provider/Cipher/DES/PaddingTest.java generic-all + +# Othervm, sparc, NoRouteToHostException: Cannot assign requested address +sun/security/ssl/javax/net/ssl/NewAPIs/SessionCacheSizeTests.java generic-all + +# ProviderException: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_DEVICE_ERROR +# Does not seem to run on windows machines? dll missing? +sun/security/pkcs11/rsa/TestKeyPairGenerator.java generic-all + +# Times out on windows X64, othervm mode +# Solaris sparc and sparcv9 -server, timeout +sun/security/ssl/javax/net/ssl/NewAPIs/SessionTimeOutTests.java generic-all + +# Failed on solaris 10 sparc, othervm mode, "js.jks: No such file or directory" +# Also, cannot verify signature on solaris i586 -server +sun/security/tools/jarsigner/concise_jarsigner.sh generic-all + +# Various failures on Linux Fedora 9 X64, othervm mode +lib/security/cacerts/VerifyCACerts.java generic-all +sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/TestAllSuites.java generic-all +sun/security/ssl/sanity/ciphersuites/CheckCipherSuites.java generic-all +sun/security/tools/jarsigner/oldsig.sh generic-all + +# Various failures on Linux Fedora 9 X64, othervm mode +# Does not seem to run on windows machines? dll missing? +sun/security/ssl/sanity/interop/ClientJSSEServerJSSE.java generic-all + +# Linux i586 -server, buffer too short to hold shared secret? +com/sun/crypto/provider/KeyAgreement/DHKeyAgreement2.java generic-all + +# Solaris sparcv9: Failed to parse input emptysubject.jks: No such file or directory +sun/security/tools/keytool/emptysubject.sh generic-all + +# Timeout on solaris-sparcv9 or exception thrown +com/sun/crypto/provider/Cipher/RSA/TestOAEP_KAT.java solaris-all + +# File 6535697.test input stream left open? windows samevm +java/security/cert/CertificateFactory/openssl/OpenSSLCert.java generic-all + +# Leaving file open: SerialVersion.current, windows samevm +java/security/BasicPermission/SerialVersion.java generic-all + +# Solaris 11 i586, these all fail with samevm, need to be othervm??? +java/security/BasicPermission/NullOrEmptyName.java generic-all + +# Suspect missing close() on file PermClass.current, windows samevm cascade +java/security/BasicPermission/PermClass.java generic-all + +# Solaris 11 i586, these all fail with samevm, need to be othervm??? +java/security/KeyPairGenerator/Failover.java generic-all +java/security/Provider/DefaultPKCS11.java generic-all +java/security/SecureClassLoader/DefineClassByteBuffer.java generic-all +java/security/SecureRandom/GetAlgorithm.java generic-all +java/security/Security/removing/RemoveProviders.java generic-all +java/security/Signature/ByteBuffers.java generic-all +java/security/Signature/NONEwithRSA.java generic-all +java/security/Signature/SignWithOutputBuffer.java generic-all +java/security/Signature/TestInitSignWithMyOwnRandom.java generic-all +java/security/UnresolvedPermission/AccessorMethods.java generic-all +java/security/UnresolvedPermission/Equals.java generic-all + +# Do not seem to run on windows machines? dll missing? +sun/security/krb5/auto/IgnoreChannelBinding.java windows-all + +# Fails on OpenSolaris, missing classes, slow on Solaris sparc +sun/security/ec/TestEC.java generic-all + +# Problems with windows x64 +sun/security/mscapi/IsSunMSCAPIAvailable.sh windows-x64 +sun/security/mscapi/RSAEncryptDecrypt.sh windows-x64 + +# Do not seem to run on windows machines? dll missing? +sun/security/pkcs11/Cipher/ReinitCipher.java windows-all +sun/security/pkcs11/Cipher/TestRSACipher.java windows-all +sun/security/pkcs11/Cipher/TestRSACipherWrap.java windows-all +sun/security/pkcs11/Cipher/TestSymmCiphers.java windows-all +sun/security/pkcs11/Cipher/TestSymmCiphersNoPad.java windows-all + +# Do not seem to run on windows machines? dll missing? +sun/security/pkcs11/ec/ReadCertificates.java windows-all +sun/security/pkcs11/ec/ReadPKCS12.java windows-all +sun/security/pkcs11/ec/TestCurves.java windows-all +sun/security/pkcs11/ec/TestECDH.java windows-all +sun/security/pkcs11/ec/TestECDSA.java windows-all +sun/security/pkcs11/ec/TestECGenSpec.java windows-all +sun/security/pkcs11/ec/TestKeyFactory.java windows-all +sun/security/pkcs11/fips/TrustManagerTest.java windows-all + +# Do not seem to run on windows machines? dll missing? +sun/security/pkcs11/KeyAgreement/TestShort.java windows-all +sun/security/pkcs11/KeyGenerator/DESParity.java windows-all + +# Exception in test solaris-sparc -client -server, no windows +sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java windows-all solaris-all + +# Do not seem to run on windows machines? dll missing? +sun/security/pkcs11/KeyStore/Basic.sh windows-all +sun/security/pkcs11/KeyStore/ClientAuth.sh windows-all + +# Solaris sparc client, fails to compile? +sun/security/pkcs11/KeyStore/SecretKeysBasic.sh solaris-all + +# Do not seem to run on windows machines? dll missing? +sun/security/pkcs11/Mac/ReinitMac.java windows-all +sun/security/pkcs11/MessageDigest/ByteBuffers.java windows-all +sun/security/pkcs11/MessageDigest/DigestKAT.java windows-all +sun/security/pkcs11/MessageDigest/ReinitDigest.java windows-all +sun/security/pkcs11/Provider/ConfigQuotedString.sh windows-all +sun/security/pkcs11/Provider/Login.sh windows-all +sun/security/pkcs11/rsa/KeyWrap.java windows-all +sun/security/pkcs11/rsa/TestCACerts.java windows-all +sun/security/pkcs11/rsa/TestKeyFactory.java windows-all +sun/security/pkcs11/rsa/TestSignatures.java windows-all +sun/security/pkcs11/SampleTest.java windows-all +sun/security/pkcs11/Secmod/AddPrivateKey.java windows-all +sun/security/pkcs11/Secmod/AddTrustedCert.java windows-all +sun/security/pkcs11/Secmod/Crypto.java windows-all +sun/security/pkcs11/Secmod/GetPrivateKey.java windows-all +sun/security/pkcs11/Secmod/JksSetPrivateKey.java windows-all +sun/security/pkcs11/Secmod/TrustAnchors.java windows-all +sun/security/pkcs11/SecureRandom/Basic.java windows-all +sun/security/pkcs11/Serialize/SerializeProvider.java windows-all +sun/security/pkcs11/Signature/ByteBuffers.java windows-all +sun/security/pkcs11/Signature/ReinitSignature.java windows-all +sun/security/pkcs11/Signature/TestDSA.java windows-all +sun/security/pkcs11/tls/TestKeyMaterial.java windows-all +sun/security/pkcs11/tls/TestMasterSecret.java windows-all +sun/security/pkcs11/tls/TestPremaster.java windows-all +sun/security/pkcs11/tls/TestPRF.java windows-all + +# Fails on OpenSolaris java.net.BindException: Address already in use +sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java generic-all + +# Timeout on solaris-sparcv9 or ArrayIndexOutOfBoundsException? +sun/security/rsa/TestKeyPairGeneratorLength.java solaris-all +sun/security/rsa/TestSignatures.java solaris-all + +# Timeout on solaris-sparc and i586 and x64, -client and -server +sun/security/ssl/com/sun/net/ssl/internal/ssl/InputRecord/InterruptedIO.java solaris-all + +# Do not seem to run on windows machines? dll missing? +sun/security/tools/jarsigner/emptymanifest.sh windows-all + +# Files does not exist or no encoding? solaris-sparcv9 +sun/security/tools/keytool/importreadall.sh solaris-all +sun/security/tools/keytool/selfissued.sh solaris-all + +############################################################################ + +# jdk_swing (not using samevm) + +# Fails on solaris 10 sparc, throws RuntimeException that just says "failed" +javax/swing/JLabel/6501991/bug6501991.java generic-all + +# Fails on solaris 11 i586, with othervm +javax/swing/JFileChooser/6570445/bug6570445.java generic-all +javax/swing/JFileChooser/6738668/bug6738668.java generic-all +javax/swing/JPopupMenu/6675802/bug6675802.java generic-all +javax/swing/system/6799345/TestShutdown.java generic-all + +############################################################################ + +# jdk_text + +# Linux x64 occasional errors, no details +java/text/Bidi/Bug6665028.java linux-x64 + +############################################################################ + +# jdk_tools + +# Some of the tools tests kind of require "othervm" or if they don't will +# always be firing up another VM anyway due to the nature of tools testing. +# So most if not all tools tests are now being run with "othervm" mode. +# Some of these tools tests have a tendency to use fixed ports, bad idea. + +# Solaris 10 client x86, java.lang.IndexOutOfBoundsException resumer Interrupted +com/sun/jdi/SimulResumerTest.java generic-all + +# Output of jps differs from expected output. +# Invalid argument count on solaris-sparc and x64 +sun/tools/jstatd/jstatdPort.sh generic-all + +# othervm mode, Could not synchronize with target +sun/tools/jps/jps-l_1.sh generic-all +sun/tools/jps/jps-l_2.sh generic-all +sun/tools/jps/jps-lm.sh generic-all +sun/tools/jps/jps-Vvml_2.sh generic-all +sun/tools/jps/jps-m_2.sh generic-all + +# Server name error, port 2098 problem? +sun/tools/jstatd/jstatdServerName.sh generic-all + +# Solaris, handshake failed, othervm mode +com/sun/jdi/RedefineException.sh generic-all + +# These tests fail on solaris sparc, all the time +com/sun/servicetag/DeleteServiceTag.java generic-all +com/sun/servicetag/DuplicateNotFound.java generic-all +com/sun/servicetag/FindServiceTags.java generic-all +com/sun/servicetag/InstanceUrnCheck.java generic-all +com/sun/servicetag/InvalidRegistrationData.java generic-all +com/sun/servicetag/InvalidServiceTag.java generic-all +com/sun/servicetag/JavaServiceTagTest.java generic-all +com/sun/servicetag/JavaServiceTagTest1.java generic-all +com/sun/servicetag/NewRegistrationData.java generic-all +com/sun/servicetag/SystemRegistryTest.java generic-all +com/sun/servicetag/TestLoadFromXML.java generic-all +com/sun/servicetag/UpdateServiceTagTest.java generic-all +com/sun/servicetag/ValidRegistrationData.java generic-all + +# Problems on windows, jmap.exe hangs? +com/sun/tools/attach/BasicTests.sh windows-all + +# Fails on Solaris 10 sparc, in othervm mode, throws unexpected exception +sun/jvmstat/monitor/MonitoredVm/CR6672135.java generic-all + +# Unexpected Monitor Exception, solaris sparc -client +sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.sh generic-all + +# Probably should be samevm, but seem to cause errors even in othervm at times +sun/tools/jhat/HatHeapDump1Test.java generic-all + +# Problems on windows, jmap.exe hangs? (these run jmap) +sun/tools/jmap/Basic.sh windows-all + +# Invalid argument count on solaris-sparc and x64 +sun/tools/jstatd/jstatdDefaults.sh solaris-all + +# Solaris sparcv9, jps output does not match, x64 different +sun/tools/jstatd/jstatdExternalRegistry.sh solaris-all + +# Probably should be samevm, but seem to cause errors even in othervm at times +sun/tools/native2ascii/NativeErrors.java generic-all + +# Solaris 10 sparc 32bit -client, java.lang.AssertionError: Some tests failed +tools/jar/JarEntryTime.java generic-all + +# Times out on sparc? +tools/launcher/VersionCheck.java generic-all + +# These tests fail on solaris sparc, all the time +tools/jar/ChangeDir.java generic-all + +# Cannot write jar +# Also, possible problems on windows, jmap.exe hangs? +tools/jar/index/MetaInf.java windows-all + +############################################################################ + +# jdk_util + +# Assert error, failures, on Linux Fedora 9 -server +# Windows samevm failure, assert error "Passed = 134, failed = 2" +java/util/Arrays/ArrayObjectMethods.java generic-all + +# Windows 2000, -client, samevm, java.lang.Error: Completed != 2 +java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java generic-all + +# Windows X64, Executor Stuck samevm mode: +java/util/concurrent/FutureTask/BlockingTaskExecutor.java generic-all + +# Problems on windows, jmap.exe hangs? (these run jmap), fails on Solaris 10 x86 +java/util/concurrent/locks/Lock/TimedAcquireLeak.java generic-all + +# Solaris sparc client, some failures, "1 not equal to 3"? +# also Linux problems with samevm mode, -server linux i586? 1 not equal to 3? +java/util/concurrent/Executors/AutoShutdown.java generic-all + +# Fails on solaris-sparc -server (Set not equal to copy. 1) +java/util/EnumSet/EnumSetBash.java solaris-sparc + +# Failing to close an input stream? "foo", triggers samevm windows failures +java/util/Formatter/Constructors.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/util/Locale/Bug4175998Test.java generic-all +java/util/Locale/Bug4184873Test.java generic-all +java/util/Locale/LocaleTest.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/util/logging/GetGlobalTest.java generic-all +java/util/logging/LoggerSubclass.java generic-all +java/util/logging/LoggingDeadlock.java generic-all +java/util/logging/LoggingDeadlock2.java generic-all +java/util/logging/LoggingMXBeanTest.java generic-all +java/util/logging/LoggingMXBeanTest2.java generic-all +java/util/logging/LoggingNIOChange.java generic-all +java/util/logging/ParentLoggersTest.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/util/ResourceBundle/Bug4168625Test.java generic-all +java/util/ResourceBundle/Bug6359330.java generic-all +java/util/ResourceBundle/TestBug4179766.java generic-all + +# Need to be marked othervm, or changed to be samevm safe +java/util/WeakHashMap/GCDuringIteration.java generic-all + +# Possible missing input stream close()? Causes samevm issues on windows +java/util/zip/InfoZip.java generic-all + +# Missing a close() on file Test0.zip? windows samevm cascade problem +java/util/zip/ZipFile/Comment.java generic-all + +# Suspect missing close() on bad*.zip files, windows cascade errors with samevm +java/util/zip/ZipFile/CorruptedZipFiles.java generic-all + +# Should be samevm but causes problems with samevm, no details: +java/util/zip/ZipFile/ManyEntries.java generic-all + +############################################################################ +
--- a/test/demo/jvmti/DemoRun.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/demo/jvmti/DemoRun.java Thu Nov 12 23:04:42 2009 +0000 @@ -145,7 +145,7 @@ */ int nvm_options = 0; if ( vm_options != null ) nvm_options = vm_options.length; - String cmd[] = new String[1 + (d64?1:0) + 5 + nvm_options]; + String cmd[] = new String[1 + (d64?1:0) + 7 + nvm_options]; String cmdLine; int exitStatus; int i,j; @@ -154,6 +154,10 @@ cmdLine = ""; cmdLine += (cmd[i++] = java); cmdLine += " "; + cmdLine += (cmd[i++] = "-cp"); + cmdLine += " "; + cmdLine += (cmd[i++] = cdir); + cmdLine += " "; cmdLine += (cmd[i++] = "-Dtest.classes=" + cdir); if ( d64 ) { cmdLine += " ";
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/awt/GraphicsDevice/CloneConfigsTest.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,118 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6822057 + * + * @summary Test verifies that list of supported graphics configurations + * can not be changed via modification of elements of an array + * returned by getConfiguration() method. + * + * @run main CloneConfigsTest + * @run main/othervm -Dsun.java2d.opengl=True CloneConfigsTest + * @run main/othervm -Dsun.java2d.d3d=true CloneConfigsTest + * @run main/othervm -Dsun.java2d.noddraw=true CloneConfigsTest + */ + +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; + +public class CloneConfigsTest { + + public static void main(String[] args) { + GraphicsEnvironment env = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + + GraphicsDevice[] devices = env.getScreenDevices(); + + GraphicsConfiguration c = new TestConfig(); + + for (GraphicsDevice gd : devices) { + System.out.println("Device: " + gd); + + GraphicsConfiguration[] configs = gd.getConfigurations(); + + for (int i = 0; i < configs.length; i++) { + GraphicsConfiguration gc = configs[i]; + System.out.println("\tConfig: " + gc); + + configs[i] = c; + } + + // verify whether array of configs was modified + configs = gd.getConfigurations(); + for (GraphicsConfiguration gc : configs) { + if (gc == c) { + throw new RuntimeException("Test failed."); + } + } + System.out.println("Test passed."); + } + } + + private static class TestConfig extends GraphicsConfiguration { + + @Override + public GraphicsDevice getDevice() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BufferedImage createCompatibleImage(int width, int height) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ColorModel getColorModel() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ColorModel getColorModel(int transparency) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public AffineTransform getDefaultTransform() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public AffineTransform getNormalizingTransform() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Rectangle getBounds() { + throw new UnsupportedOperationException("Not supported yet."); + } + + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ClassLoader/UninitializedParent.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,68 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6636650 + * @summary Uninitialized class loaders should not be a parent of other + * class loaders. + */ + + +import java.net.*; + +public class UninitializedParent { + private static ClassLoader loader; + public static void main(String[] args) throws Exception { + System.setSecurityManager(new SecurityManager()); + + // Create an uninitialized class loader + try { + new ClassLoader(null) { + @Override + protected void finalize() { + loader = this; + } + }; + } catch (SecurityException exc) { + // Expected + } + System.gc(); + System.runFinalization(); + + // if 'loader' isn't null, need to ensure that it can't be used as + // parent + if (loader != null) { + try { + // Create a class loader with 'loader' being the parent + URLClassLoader child = URLClassLoader.newInstance + (new URL[0], loader); + throw new RuntimeException("Test Failed!"); + } catch (SecurityException se) { + System.out.println("Test Passed: Exception thrown"); + } + } else { + System.out.println("Test Passed: Loader is null"); + } + } +}
--- a/test/java/nio/Buffer/Basic-X.java Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,869 +0,0 @@ -/* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -/* Type-specific source code for unit test - * - * Regenerate the BasicX classes via genBasic.sh whenever this file changes. - * We check in the generated source files so that the test tree can be used - * independently of the rest of the source tree. - */ - -#warn This file is preprocessed before being compiled - -import java.nio.*; -import java.lang.reflect.Method; - - -public class Basic$Type$ - extends Basic -{ - - private static void relGet($Type$Buffer b) { - int n = b.capacity(); - $type$ v; - for (int i = 0; i < n; i++) - ck(b, (long)b.get(), (long)(($type$)ic(i))); - b.rewind(); - } - - private static void relGet($Type$Buffer b, int start) { - int n = b.remaining(); - $type$ v; - for (int i = start; i < n; i++) - ck(b, (long)b.get(), (long)(($type$)ic(i))); - b.rewind(); - } - - private static void absGet($Type$Buffer b) { - int n = b.capacity(); - $type$ v; - for (int i = 0; i < n; i++) - ck(b, (long)b.get(), (long)(($type$)ic(i))); - b.rewind(); - } - - private static void bulkGet($Type$Buffer b) { - int n = b.capacity(); - $type$[] a = new $type$[n + 7]; - b.get(a, 7, n); - for (int i = 0; i < n; i++) - ck(b, (long)a[i + 7], (long)(($type$)ic(i))); - } - - private static void relPut($Type$Buffer b) { - int n = b.capacity(); - b.clear(); - for (int i = 0; i < n; i++) - b.put(($type$)ic(i)); - b.flip(); - } - - private static void absPut($Type$Buffer b) { - int n = b.capacity(); - b.clear(); - for (int i = 0; i < n; i++) - b.put(i, ($type$)ic(i)); - b.limit(n); - b.position(0); - } - - private static void bulkPutArray($Type$Buffer b) { - int n = b.capacity(); - b.clear(); - $type$[] a = new $type$[n + 7]; - for (int i = 0; i < n; i++) - a[i + 7] = ($type$)ic(i); - b.put(a, 7, n); - b.flip(); - } - - private static void bulkPutBuffer($Type$Buffer b) { - int n = b.capacity(); - b.clear(); - $Type$Buffer c = $Type$Buffer.allocate(n + 7); - c.position(7); - for (int i = 0; i < n; i++) - c.put(($type$)ic(i)); - c.flip(); - c.position(7); - b.put(c); - b.flip(); - } - - //6231529 - private static void callReset($Type$Buffer b) { - b.position(0); - b.mark(); - - b.duplicate().reset(); - b.asReadOnlyBuffer().reset(); - } - -#if[byte] -#else[byte] - // 6221101-6234263 - - private static void putBuffer() { - final int cap = 10; - - $Type$Buffer direct1 = ByteBuffer.allocateDirect(cap).as$Type$Buffer(); - $Type$Buffer nondirect1 = ByteBuffer.allocate(cap).as$Type$Buffer(); - direct1.put(nondirect1); - - $Type$Buffer direct2 = ByteBuffer.allocateDirect(cap).as$Type$Buffer(); - $Type$Buffer nondirect2 = ByteBuffer.allocate(cap).as$Type$Buffer(); - nondirect2.put(direct2); - - $Type$Buffer direct3 = ByteBuffer.allocateDirect(cap).as$Type$Buffer(); - $Type$Buffer direct4 = ByteBuffer.allocateDirect(cap).as$Type$Buffer(); - direct3.put(direct4); - - $Type$Buffer nondirect3 = ByteBuffer.allocate(cap).as$Type$Buffer(); - $Type$Buffer nondirect4 = ByteBuffer.allocate(cap).as$Type$Buffer(); - nondirect3.put(nondirect4); - } -#end[byte] - -#if[char] - - private static void bulkPutString($Type$Buffer b) { - int n = b.capacity(); - b.clear(); - StringBuffer sb = new StringBuffer(n + 7); - sb.append("1234567"); - for (int i = 0; i < n; i++) - sb.append((char)ic(i)); - b.put(sb.toString(), 7, 7 + n); - b.flip(); - } - -#end[char] - - private static void checkSlice($Type$Buffer b, $Type$Buffer slice) { - ck(slice, 0, slice.position()); - ck(slice, b.remaining(), slice.limit()); - ck(slice, b.remaining(), slice.capacity()); - if (b.isDirect() != slice.isDirect()) - fail("Lost direction", slice); - if (b.isReadOnly() != slice.isReadOnly()) - fail("Lost read-only", slice); - } - -#if[byte] - - private static void checkBytes(ByteBuffer b, byte[] bs) { - int n = bs.length; - int p = b.position(); - byte v; - if (b.order() == ByteOrder.BIG_ENDIAN) { - for (int i = 0; i < n; i++) - ck(b, b.get(), bs[i]); - } else { - for (int i = n - 1; i >= 0; i--) - ck(b, b.get(), bs[i]); - } - b.position(p); - } - - private static void compact(Buffer b) { - try { - Class<?> cl = b.getClass(); - Method m = cl.getDeclaredMethod("compact"); - m.setAccessible(true); - m.invoke(b); - } catch (Exception e) { - fail(e.getMessage(), b); - } - } - - private static void checkInvalidMarkException(final Buffer b) { - tryCatch(b, InvalidMarkException.class, new Runnable() { - public void run() { - b.mark(); - compact(b); - b.reset(); - }}); - } - - private static void testViews(int level, ByteBuffer b, boolean direct) { - - ShortBuffer sb = b.asShortBuffer(); - BasicShort.test(level, sb, direct); - checkBytes(b, new byte[] { 0, (byte)ic(0) }); - checkInvalidMarkException(sb); - - CharBuffer cb = b.asCharBuffer(); - BasicChar.test(level, cb, direct); - checkBytes(b, new byte[] { 0, (byte)ic(0) }); - checkInvalidMarkException(cb); - - IntBuffer ib = b.asIntBuffer(); - BasicInt.test(level, ib, direct); - checkBytes(b, new byte[] { 0, 0, 0, (byte)ic(0) }); - checkInvalidMarkException(ib); - - LongBuffer lb = b.asLongBuffer(); - BasicLong.test(level, lb, direct); - checkBytes(b, new byte[] { 0, 0, 0, 0, 0, 0, 0, (byte)ic(0) }); - checkInvalidMarkException(lb); - - FloatBuffer fb = b.asFloatBuffer(); - BasicFloat.test(level, fb, direct); - checkBytes(b, new byte[] { 0x42, (byte)0xc2, 0, 0 }); - checkInvalidMarkException(fb); - - DoubleBuffer db = b.asDoubleBuffer(); - BasicDouble.test(level, db, direct); - checkBytes(b, new byte[] { 0x40, 0x58, 0x40, 0, 0, 0, 0, 0 }); - checkInvalidMarkException(db); - } - - private static void testHet(int level, ByteBuffer b) { - - int p = b.position(); - b.limit(b.capacity()); - show(level, b); - out.print(" put:"); - - b.putChar((char)1); - b.putChar((char)Character.MAX_VALUE); - out.print(" char"); - - b.putShort((short)1); - b.putShort((short)Short.MAX_VALUE); - out.print(" short"); - - b.putInt(1); - b.putInt(Integer.MAX_VALUE); - out.print(" int"); - - b.putLong((long)1); - b.putLong((long)Long.MAX_VALUE); - out.print(" long"); - - b.putFloat((float)1); - b.putFloat((float)Float.MIN_VALUE); - b.putFloat((float)Float.MAX_VALUE); - out.print(" float"); - - b.putDouble((double)1); - b.putDouble((double)Double.MIN_VALUE); - b.putDouble((double)Double.MAX_VALUE); - out.print(" double"); - - out.println(); - b.limit(b.position()); - b.position(p); - show(level, b); - out.print(" get:"); - - ck(b, b.getChar(), 1); - ck(b, b.getChar(), Character.MAX_VALUE); - out.print(" char"); - - ck(b, b.getShort(), 1); - ck(b, b.getShort(), Short.MAX_VALUE); - out.print(" short"); - - ck(b, b.getInt(), 1); - ck(b, b.getInt(), Integer.MAX_VALUE); - out.print(" int"); - - ck(b, b.getLong(), 1); - ck(b, b.getLong(), Long.MAX_VALUE); - out.print(" long"); - - ck(b, (long)b.getFloat(), 1); - ck(b, (long)b.getFloat(), (long)Float.MIN_VALUE); - ck(b, (long)b.getFloat(), (long)Float.MAX_VALUE); - out.print(" float"); - - ck(b, (long)b.getDouble(), 1); - ck(b, (long)b.getDouble(), (long)Double.MIN_VALUE); - ck(b, (long)b.getDouble(), (long)Double.MAX_VALUE); - out.print(" double"); - - out.println(); - - } - -#end[byte] - - private static void tryCatch(Buffer b, Class ex, Runnable thunk) { - boolean caught = false; - try { - thunk.run(); - } catch (Throwable x) { - if (ex.isAssignableFrom(x.getClass())) { - caught = true; - } else { - fail(x.getMessage() + " not expected"); - } - } - if (!caught) - fail(ex.getName() + " not thrown", b); - } - - private static void tryCatch($type$ [] t, Class ex, Runnable thunk) { - tryCatch($Type$Buffer.wrap(t), ex, thunk); - } - - public static void test(int level, final $Type$Buffer b, boolean direct) { - - show(level, b); - - if (direct != b.isDirect()) - fail("Wrong direction", b); - - // Gets and puts - - relPut(b); - relGet(b); - absGet(b); - bulkGet(b); - - absPut(b); - relGet(b); - absGet(b); - bulkGet(b); - - bulkPutArray(b); - relGet(b); - - bulkPutBuffer(b); - relGet(b); - -#if[char] - - bulkPutString(b); - relGet(b); - b.position(1); - b.limit(7); - ck(b, b.toString().equals("bcdefg")); - - // CharSequence ops - - b.position(2); - ck(b, b.charAt(1), 'd'); - CharBuffer c = b.subSequence(1, 4); - ck(c, c.capacity(), b.capacity()); - ck(c, c.position(), b.position()+1); - ck(c, c.limit(), b.position()+4); - ck(c, b.subSequence(1, 4).toString().equals("def")); - - // 4938424 - b.position(4); - ck(b, b.charAt(1), 'f'); - ck(b, b.subSequence(1, 3).toString().equals("fg")); - -#end[char] - - // Compact - - relPut(b); - b.position(13); - b.compact(); - b.flip(); - relGet(b, 13); - - // Exceptions - - relPut(b); - b.limit(b.capacity() / 2); - b.position(b.limit()); - - tryCatch(b, BufferUnderflowException.class, new Runnable() { - public void run() { - b.get(); - }}); - - tryCatch(b, BufferOverflowException.class, new Runnable() { - public void run() { - b.put(($type$)42); - }}); - - // The index must be non-negative and lesss than the buffer's limit. - tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - b.get(b.limit()); - }}); - tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - b.get(-1); - }}); - - tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - b.put(b.limit(), ($type$)42); - }}); - - tryCatch(b, InvalidMarkException.class, new Runnable() { - public void run() { - b.position(0); - b.mark(); - b.compact(); - b.reset(); - }}); - - // Values - - b.clear(); - b.put(($type$)0); - b.put(($type$)-1); - b.put(($type$)1); - b.put($Fulltype$.MAX_VALUE); - b.put($Fulltype$.MIN_VALUE); -#if[float] - b.put(-Float.MAX_VALUE); - b.put(-Float.MIN_VALUE); - b.put(Float.NEGATIVE_INFINITY); - b.put(Float.POSITIVE_INFINITY); - b.put(Float.NaN); - b.put(0.91697687f); // Changes value if incorrectly swapped -#end[float] -#if[double] - b.put(-Double.MAX_VALUE); - b.put(-Double.MIN_VALUE); - b.put(Double.NEGATIVE_INFINITY); - b.put(Double.POSITIVE_INFINITY); - b.put(Double.NaN); - b.put(0.5121609353879392); // Changes value if incorrectly swapped -#end[double] - - $type$ v; - b.flip(); - ck(b, b.get(), 0); - ck(b, b.get(), ($type$)-1); - ck(b, b.get(), 1); - ck(b, b.get(), $Fulltype$.MAX_VALUE); - ck(b, b.get(), $Fulltype$.MIN_VALUE); - -#if[float] - ck(b, b.get(), -Float.MAX_VALUE); - ck(b, b.get(), -Float.MIN_VALUE); - ck(b, b.get(), Float.NEGATIVE_INFINITY); - ck(b, b.get(), Float.POSITIVE_INFINITY); - if (Float.floatToRawIntBits(v = b.get()) != Float.floatToRawIntBits(Float.NaN)) - fail(b, (long)Float.NaN, (long)v); - ck(b, b.get(), 0.91697687f); -#end[float] -#if[double] - ck(b, b.get(), -Double.MAX_VALUE); - ck(b, b.get(), -Double.MIN_VALUE); - ck(b, b.get(), Double.NEGATIVE_INFINITY); - ck(b, b.get(), Double.POSITIVE_INFINITY); - if (Double.doubleToRawLongBits(v = b.get()) - != Double.doubleToRawLongBits(Double.NaN)) - fail(b, (long)Double.NaN, (long)v); - ck(b, b.get(), 0.5121609353879392); -#end[double] - - - // Comparison - b.rewind(); - $Type$Buffer b2 = $Type$Buffer.allocate(b.capacity()); - b2.put(b); - b2.flip(); - b.position(2); - b2.position(2); - if (!b.equals(b2)) { - for (int i = 2; i < b.limit(); i++) { - $type$ x = b.get(i); - $type$ y = b2.get(i); - if (x != y -#if[double] - || Double.compare(x, y) != 0 -#end[double] -#if[float] - || Float.compare(x, y) != 0 -#end[float] - ) - out.println("[" + i + "] " + x + " != " + y); - } - fail("Identical buffers not equal", b, b2); - } - if (b.compareTo(b2) != 0) - fail("Comparison to identical buffer != 0", b, b2); - - b.limit(b.limit() + 1); - b.position(b.limit() - 1); - b.put(($type$)99); - b.rewind(); - b2.rewind(); - if (b.equals(b2)) - fail("Non-identical buffers equal", b, b2); - if (b.compareTo(b2) <= 0) - fail("Comparison to shorter buffer <= 0", b, b2); - b.limit(b.limit() - 1); - - b.put(2, ($type$)42); - if (b.equals(b2)) - fail("Non-identical buffers equal", b, b2); - if (b.compareTo(b2) <= 0) - fail("Comparison to lesser buffer <= 0", b, b2); - - // Sub, dup - - relPut(b); - relGet(b.duplicate()); - b.position(13); - relGet(b.duplicate(), 13); - relGet(b.duplicate().slice(), 13); - relGet(b.slice(), 13); - relGet(b.slice().duplicate(), 13); - - // Slice - - b.position(5); - $Type$Buffer sb = b.slice(); - checkSlice(b, sb); - b.position(0); - $Type$Buffer sb2 = sb.slice(); - checkSlice(sb, sb2); - - if (!sb.equals(sb2)) - fail("Sliced slices do not match", sb, sb2); - if ((sb.hasArray()) && (sb.arrayOffset() != sb2.arrayOffset())) - fail("Array offsets do not match: " - + sb.arrayOffset() + " != " + sb2.arrayOffset(), sb, sb2); - -#if[byte] - - // Views - - b.clear(); - b.order(ByteOrder.BIG_ENDIAN); - testViews(level + 1, b, direct); - - for (int i = 1; i <= 9; i++) { - b.position(i); - show(level + 1, b); - testViews(level + 2, b, direct); - } - - b.position(0); - b.order(ByteOrder.LITTLE_ENDIAN); - testViews(level + 1, b, direct); - - // Heterogeneous accessors - - b.order(ByteOrder.BIG_ENDIAN); - for (int i = 0; i <= 9; i++) { - b.position(i); - testHet(level + 1, b); - } - b.order(ByteOrder.LITTLE_ENDIAN); - b.position(3); - testHet(level + 1, b); - -#end[byte] - - // Read-only views - - b.rewind(); - final $Type$Buffer rb = b.asReadOnlyBuffer(); - if (!b.equals(rb)) - fail("Buffer not equal to read-only view", b, rb); - show(level + 1, rb); - - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - relPut(rb); - }}); - - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - absPut(rb); - }}); - - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - bulkPutArray(rb); - }}); - - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - bulkPutBuffer(rb); - }}); - - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - rb.compact(); - }}); - -#if[byte] - - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - rb.putChar((char)1); - }}); - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - rb.putChar(0, (char)1); - }}); - - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - rb.putShort((short)1); - }}); - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - rb.putShort(0, (short)1); - }}); - - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - rb.putInt(1); - }}); - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - rb.putInt(0, 1); - }}); - - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - rb.putLong((long)1); - }}); - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - rb.putLong(0, (long)1); - }}); - - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - rb.putFloat((float)1); - }}); - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - rb.putFloat(0, (float)1); - }}); - - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - rb.putDouble((double)1); - }}); - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - rb.putDouble(0, (double)1); - }}); - -#end[byte] - - if (rb.getClass().getName().startsWith("java.nio.Heap")) { - - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - rb.array(); - }}); - - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - rb.arrayOffset(); - }}); - - if (rb.hasArray()) - fail("Read-only heap buffer's backing array is accessible", - rb); - - } - - // Bulk puts from read-only buffers - - b.clear(); - rb.rewind(); - b.put(rb); - -#if[byte] - // For byte buffers, test both the direct and non-direct cases - $Type$Buffer ob - = (b.isDirect() - ? $Type$Buffer.allocate(rb.capacity()) - : $Type$Buffer.allocateDirect(rb.capacity())); - rb.rewind(); - ob.put(rb); -#end[byte] - - relPut(b); // Required by testViews - - } - -#if[char] - - private static void testStr() { - final String s = "abcdefghijklm"; - int start = 3; - int end = 9; - final CharBuffer b = CharBuffer.wrap(s, start, end); - show(0, b); - ck(b, b.toString().equals(s.substring(start, end))); - ck(b, b.toString().equals("defghi")); - ck(b, b.isReadOnly()); - tryCatch(b, ReadOnlyBufferException.class, new Runnable() { - public void run() { - b.put('x'); - }}); - ck(b, start, b.position()); - ck(b, end, b.limit()); - ck(b, s.length(), b.capacity()); - b.position(6); - ck(b, b.subSequence(0,3).toString().equals("ghi")); - - // The index, relative to the position, must be non-negative and - // smaller than remaining(). - tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - b.charAt(-1); - }}); - tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - b.charAt(b.remaining()); - }}); - - // The index must be non-negative and less than the buffer's limit. - tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - b.get(b.limit()); - }}); - tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - b.get(-1); - }}); - - // The start must be non-negative and no larger than remaining(). - tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - b.subSequence(-1, b.remaining()); - }}); - tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - b.subSequence(b.remaining() + 1, b.remaining()); - }}); - - // The end must be no smaller than start and no larger than - // remaining(). - tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - b.subSequence(2, 1); - }}); - tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - b.subSequence(0, b.remaining() + 1); - }}); - - // The offset must be non-negative and no larger than <array.length>. - tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - $Type$Buffer.wrap(s, -1, s.length()); - }}); - tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - $Type$Buffer.wrap(s, s.length() + 1, s.length()); - }}); - tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - $Type$Buffer.wrap(s, 1, 0); - }}); - tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - $Type$Buffer.wrap(s, 0, s.length() + 1); - }}); - } - -#end[char] - - public static void test(final $type$ [] ba) { - int offset = 47; - int length = 900; - final $Type$Buffer b = $Type$Buffer.wrap(ba, offset, length); - show(0, b); - ck(b, b.capacity(), ba.length); - ck(b, b.position(), offset); - ck(b, b.limit(), offset + length); - - // The offset must be non-negative and no larger than <array.length>. - tryCatch(ba, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - $Type$Buffer.wrap(ba, -1, ba.length); - }}); - tryCatch(ba, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - $Type$Buffer.wrap(ba, ba.length + 1, ba.length); - }}); - tryCatch(ba, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - $Type$Buffer.wrap(ba, 0, -1); - }}); - tryCatch(ba, IndexOutOfBoundsException.class, new Runnable() { - public void run() { - $Type$Buffer.wrap(ba, 0, ba.length + 1); - }}); - - // A NullPointerException will be thrown if the array is null. - tryCatch(ba, NullPointerException.class, new Runnable() { - public void run() { - $Type$Buffer.wrap(($type$ []) null, 0, 5); - }}); - tryCatch(ba, NullPointerException.class, new Runnable() { - public void run() { - $Type$Buffer.wrap(($type$ []) null); - }}); - } - - private static void testAllocate() { - // An IllegalArgumentException will be thrown for negative capacities. - tryCatch((Buffer) null, IllegalArgumentException.class, new Runnable() { - public void run() { - $Type$Buffer.allocate(-1); - }}); -#if[byte] - tryCatch((Buffer) null, IllegalArgumentException.class, new Runnable() { - public void run() { - $Type$Buffer.allocateDirect(-1); - }}); -#end[byte] - } - - public static void test() { - testAllocate(); - test(0, $Type$Buffer.allocate(7 * 1024), false); - test(0, $Type$Buffer.wrap(new $type$[7 * 1024], 0, 7 * 1024), false); - test(new $type$[1024]); -#if[byte] - $Type$Buffer b = $Type$Buffer.allocateDirect(7 * 1024); - for (b.position(0); b.position() < b.limit(); ) - ck(b, b.get(), 0); - test(0, b, true); -#end[byte] -#if[char] - testStr(); -#end[char] - - callReset($Type$Buffer.allocate(10)); - -#if[byte] -#else[byte] - putBuffer(); -#end[byte] - } - -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/nio/Buffer/Basic-X.java.template Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,869 @@ +/* + * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* Type-specific source code for unit test + * + * Regenerate the BasicX classes via genBasic.sh whenever this file changes. + * We check in the generated source files so that the test tree can be used + * independently of the rest of the source tree. + */ + +#warn This file is preprocessed before being compiled + +import java.nio.*; +import java.lang.reflect.Method; + + +public class Basic$Type$ + extends Basic +{ + + private static void relGet($Type$Buffer b) { + int n = b.capacity(); + $type$ v; + for (int i = 0; i < n; i++) + ck(b, (long)b.get(), (long)(($type$)ic(i))); + b.rewind(); + } + + private static void relGet($Type$Buffer b, int start) { + int n = b.remaining(); + $type$ v; + for (int i = start; i < n; i++) + ck(b, (long)b.get(), (long)(($type$)ic(i))); + b.rewind(); + } + + private static void absGet($Type$Buffer b) { + int n = b.capacity(); + $type$ v; + for (int i = 0; i < n; i++) + ck(b, (long)b.get(), (long)(($type$)ic(i))); + b.rewind(); + } + + private static void bulkGet($Type$Buffer b) { + int n = b.capacity(); + $type$[] a = new $type$[n + 7]; + b.get(a, 7, n); + for (int i = 0; i < n; i++) + ck(b, (long)a[i + 7], (long)(($type$)ic(i))); + } + + private static void relPut($Type$Buffer b) { + int n = b.capacity(); + b.clear(); + for (int i = 0; i < n; i++) + b.put(($type$)ic(i)); + b.flip(); + } + + private static void absPut($Type$Buffer b) { + int n = b.capacity(); + b.clear(); + for (int i = 0; i < n; i++) + b.put(i, ($type$)ic(i)); + b.limit(n); + b.position(0); + } + + private static void bulkPutArray($Type$Buffer b) { + int n = b.capacity(); + b.clear(); + $type$[] a = new $type$[n + 7]; + for (int i = 0; i < n; i++) + a[i + 7] = ($type$)ic(i); + b.put(a, 7, n); + b.flip(); + } + + private static void bulkPutBuffer($Type$Buffer b) { + int n = b.capacity(); + b.clear(); + $Type$Buffer c = $Type$Buffer.allocate(n + 7); + c.position(7); + for (int i = 0; i < n; i++) + c.put(($type$)ic(i)); + c.flip(); + c.position(7); + b.put(c); + b.flip(); + } + + //6231529 + private static void callReset($Type$Buffer b) { + b.position(0); + b.mark(); + + b.duplicate().reset(); + b.asReadOnlyBuffer().reset(); + } + +#if[byte] +#else[byte] + // 6221101-6234263 + + private static void putBuffer() { + final int cap = 10; + + $Type$Buffer direct1 = ByteBuffer.allocateDirect(cap).as$Type$Buffer(); + $Type$Buffer nondirect1 = ByteBuffer.allocate(cap).as$Type$Buffer(); + direct1.put(nondirect1); + + $Type$Buffer direct2 = ByteBuffer.allocateDirect(cap).as$Type$Buffer(); + $Type$Buffer nondirect2 = ByteBuffer.allocate(cap).as$Type$Buffer(); + nondirect2.put(direct2); + + $Type$Buffer direct3 = ByteBuffer.allocateDirect(cap).as$Type$Buffer(); + $Type$Buffer direct4 = ByteBuffer.allocateDirect(cap).as$Type$Buffer(); + direct3.put(direct4); + + $Type$Buffer nondirect3 = ByteBuffer.allocate(cap).as$Type$Buffer(); + $Type$Buffer nondirect4 = ByteBuffer.allocate(cap).as$Type$Buffer(); + nondirect3.put(nondirect4); + } +#end[byte] + +#if[char] + + private static void bulkPutString($Type$Buffer b) { + int n = b.capacity(); + b.clear(); + StringBuffer sb = new StringBuffer(n + 7); + sb.append("1234567"); + for (int i = 0; i < n; i++) + sb.append((char)ic(i)); + b.put(sb.toString(), 7, 7 + n); + b.flip(); + } + +#end[char] + + private static void checkSlice($Type$Buffer b, $Type$Buffer slice) { + ck(slice, 0, slice.position()); + ck(slice, b.remaining(), slice.limit()); + ck(slice, b.remaining(), slice.capacity()); + if (b.isDirect() != slice.isDirect()) + fail("Lost direction", slice); + if (b.isReadOnly() != slice.isReadOnly()) + fail("Lost read-only", slice); + } + +#if[byte] + + private static void checkBytes(ByteBuffer b, byte[] bs) { + int n = bs.length; + int p = b.position(); + byte v; + if (b.order() == ByteOrder.BIG_ENDIAN) { + for (int i = 0; i < n; i++) + ck(b, b.get(), bs[i]); + } else { + for (int i = n - 1; i >= 0; i--) + ck(b, b.get(), bs[i]); + } + b.position(p); + } + + private static void compact(Buffer b) { + try { + Class<?> cl = b.getClass(); + Method m = cl.getDeclaredMethod("compact"); + m.setAccessible(true); + m.invoke(b); + } catch (Exception e) { + fail(e.getMessage(), b); + } + } + + private static void checkInvalidMarkException(final Buffer b) { + tryCatch(b, InvalidMarkException.class, new Runnable() { + public void run() { + b.mark(); + compact(b); + b.reset(); + }}); + } + + private static void testViews(int level, ByteBuffer b, boolean direct) { + + ShortBuffer sb = b.asShortBuffer(); + BasicShort.test(level, sb, direct); + checkBytes(b, new byte[] { 0, (byte)ic(0) }); + checkInvalidMarkException(sb); + + CharBuffer cb = b.asCharBuffer(); + BasicChar.test(level, cb, direct); + checkBytes(b, new byte[] { 0, (byte)ic(0) }); + checkInvalidMarkException(cb); + + IntBuffer ib = b.asIntBuffer(); + BasicInt.test(level, ib, direct); + checkBytes(b, new byte[] { 0, 0, 0, (byte)ic(0) }); + checkInvalidMarkException(ib); + + LongBuffer lb = b.asLongBuffer(); + BasicLong.test(level, lb, direct); + checkBytes(b, new byte[] { 0, 0, 0, 0, 0, 0, 0, (byte)ic(0) }); + checkInvalidMarkException(lb); + + FloatBuffer fb = b.asFloatBuffer(); + BasicFloat.test(level, fb, direct); + checkBytes(b, new byte[] { 0x42, (byte)0xc2, 0, 0 }); + checkInvalidMarkException(fb); + + DoubleBuffer db = b.asDoubleBuffer(); + BasicDouble.test(level, db, direct); + checkBytes(b, new byte[] { 0x40, 0x58, 0x40, 0, 0, 0, 0, 0 }); + checkInvalidMarkException(db); + } + + private static void testHet(int level, ByteBuffer b) { + + int p = b.position(); + b.limit(b.capacity()); + show(level, b); + out.print(" put:"); + + b.putChar((char)1); + b.putChar((char)Character.MAX_VALUE); + out.print(" char"); + + b.putShort((short)1); + b.putShort((short)Short.MAX_VALUE); + out.print(" short"); + + b.putInt(1); + b.putInt(Integer.MAX_VALUE); + out.print(" int"); + + b.putLong((long)1); + b.putLong((long)Long.MAX_VALUE); + out.print(" long"); + + b.putFloat((float)1); + b.putFloat((float)Float.MIN_VALUE); + b.putFloat((float)Float.MAX_VALUE); + out.print(" float"); + + b.putDouble((double)1); + b.putDouble((double)Double.MIN_VALUE); + b.putDouble((double)Double.MAX_VALUE); + out.print(" double"); + + out.println(); + b.limit(b.position()); + b.position(p); + show(level, b); + out.print(" get:"); + + ck(b, b.getChar(), 1); + ck(b, b.getChar(), Character.MAX_VALUE); + out.print(" char"); + + ck(b, b.getShort(), 1); + ck(b, b.getShort(), Short.MAX_VALUE); + out.print(" short"); + + ck(b, b.getInt(), 1); + ck(b, b.getInt(), Integer.MAX_VALUE); + out.print(" int"); + + ck(b, b.getLong(), 1); + ck(b, b.getLong(), Long.MAX_VALUE); + out.print(" long"); + + ck(b, (long)b.getFloat(), 1); + ck(b, (long)b.getFloat(), (long)Float.MIN_VALUE); + ck(b, (long)b.getFloat(), (long)Float.MAX_VALUE); + out.print(" float"); + + ck(b, (long)b.getDouble(), 1); + ck(b, (long)b.getDouble(), (long)Double.MIN_VALUE); + ck(b, (long)b.getDouble(), (long)Double.MAX_VALUE); + out.print(" double"); + + out.println(); + + } + +#end[byte] + + private static void tryCatch(Buffer b, Class ex, Runnable thunk) { + boolean caught = false; + try { + thunk.run(); + } catch (Throwable x) { + if (ex.isAssignableFrom(x.getClass())) { + caught = true; + } else { + fail(x.getMessage() + " not expected"); + } + } + if (!caught) + fail(ex.getName() + " not thrown", b); + } + + private static void tryCatch($type$ [] t, Class ex, Runnable thunk) { + tryCatch($Type$Buffer.wrap(t), ex, thunk); + } + + public static void test(int level, final $Type$Buffer b, boolean direct) { + + show(level, b); + + if (direct != b.isDirect()) + fail("Wrong direction", b); + + // Gets and puts + + relPut(b); + relGet(b); + absGet(b); + bulkGet(b); + + absPut(b); + relGet(b); + absGet(b); + bulkGet(b); + + bulkPutArray(b); + relGet(b); + + bulkPutBuffer(b); + relGet(b); + +#if[char] + + bulkPutString(b); + relGet(b); + b.position(1); + b.limit(7); + ck(b, b.toString().equals("bcdefg")); + + // CharSequence ops + + b.position(2); + ck(b, b.charAt(1), 'd'); + CharBuffer c = b.subSequence(1, 4); + ck(c, c.capacity(), b.capacity()); + ck(c, c.position(), b.position()+1); + ck(c, c.limit(), b.position()+4); + ck(c, b.subSequence(1, 4).toString().equals("def")); + + // 4938424 + b.position(4); + ck(b, b.charAt(1), 'f'); + ck(b, b.subSequence(1, 3).toString().equals("fg")); + +#end[char] + + // Compact + + relPut(b); + b.position(13); + b.compact(); + b.flip(); + relGet(b, 13); + + // Exceptions + + relPut(b); + b.limit(b.capacity() / 2); + b.position(b.limit()); + + tryCatch(b, BufferUnderflowException.class, new Runnable() { + public void run() { + b.get(); + }}); + + tryCatch(b, BufferOverflowException.class, new Runnable() { + public void run() { + b.put(($type$)42); + }}); + + // The index must be non-negative and lesss than the buffer's limit. + tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + b.get(b.limit()); + }}); + tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + b.get(-1); + }}); + + tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + b.put(b.limit(), ($type$)42); + }}); + + tryCatch(b, InvalidMarkException.class, new Runnable() { + public void run() { + b.position(0); + b.mark(); + b.compact(); + b.reset(); + }}); + + // Values + + b.clear(); + b.put(($type$)0); + b.put(($type$)-1); + b.put(($type$)1); + b.put($Fulltype$.MAX_VALUE); + b.put($Fulltype$.MIN_VALUE); +#if[float] + b.put(-Float.MAX_VALUE); + b.put(-Float.MIN_VALUE); + b.put(Float.NEGATIVE_INFINITY); + b.put(Float.POSITIVE_INFINITY); + b.put(Float.NaN); + b.put(0.91697687f); // Changes value if incorrectly swapped +#end[float] +#if[double] + b.put(-Double.MAX_VALUE); + b.put(-Double.MIN_VALUE); + b.put(Double.NEGATIVE_INFINITY); + b.put(Double.POSITIVE_INFINITY); + b.put(Double.NaN); + b.put(0.5121609353879392); // Changes value if incorrectly swapped +#end[double] + + $type$ v; + b.flip(); + ck(b, b.get(), 0); + ck(b, b.get(), ($type$)-1); + ck(b, b.get(), 1); + ck(b, b.get(), $Fulltype$.MAX_VALUE); + ck(b, b.get(), $Fulltype$.MIN_VALUE); + +#if[float] + ck(b, b.get(), -Float.MAX_VALUE); + ck(b, b.get(), -Float.MIN_VALUE); + ck(b, b.get(), Float.NEGATIVE_INFINITY); + ck(b, b.get(), Float.POSITIVE_INFINITY); + if (Float.floatToRawIntBits(v = b.get()) != Float.floatToRawIntBits(Float.NaN)) + fail(b, (long)Float.NaN, (long)v); + ck(b, b.get(), 0.91697687f); +#end[float] +#if[double] + ck(b, b.get(), -Double.MAX_VALUE); + ck(b, b.get(), -Double.MIN_VALUE); + ck(b, b.get(), Double.NEGATIVE_INFINITY); + ck(b, b.get(), Double.POSITIVE_INFINITY); + if (Double.doubleToRawLongBits(v = b.get()) + != Double.doubleToRawLongBits(Double.NaN)) + fail(b, (long)Double.NaN, (long)v); + ck(b, b.get(), 0.5121609353879392); +#end[double] + + + // Comparison + b.rewind(); + $Type$Buffer b2 = $Type$Buffer.allocate(b.capacity()); + b2.put(b); + b2.flip(); + b.position(2); + b2.position(2); + if (!b.equals(b2)) { + for (int i = 2; i < b.limit(); i++) { + $type$ x = b.get(i); + $type$ y = b2.get(i); + if (x != y +#if[double] + || Double.compare(x, y) != 0 +#end[double] +#if[float] + || Float.compare(x, y) != 0 +#end[float] + ) + out.println("[" + i + "] " + x + " != " + y); + } + fail("Identical buffers not equal", b, b2); + } + if (b.compareTo(b2) != 0) + fail("Comparison to identical buffer != 0", b, b2); + + b.limit(b.limit() + 1); + b.position(b.limit() - 1); + b.put(($type$)99); + b.rewind(); + b2.rewind(); + if (b.equals(b2)) + fail("Non-identical buffers equal", b, b2); + if (b.compareTo(b2) <= 0) + fail("Comparison to shorter buffer <= 0", b, b2); + b.limit(b.limit() - 1); + + b.put(2, ($type$)42); + if (b.equals(b2)) + fail("Non-identical buffers equal", b, b2); + if (b.compareTo(b2) <= 0) + fail("Comparison to lesser buffer <= 0", b, b2); + + // Sub, dup + + relPut(b); + relGet(b.duplicate()); + b.position(13); + relGet(b.duplicate(), 13); + relGet(b.duplicate().slice(), 13); + relGet(b.slice(), 13); + relGet(b.slice().duplicate(), 13); + + // Slice + + b.position(5); + $Type$Buffer sb = b.slice(); + checkSlice(b, sb); + b.position(0); + $Type$Buffer sb2 = sb.slice(); + checkSlice(sb, sb2); + + if (!sb.equals(sb2)) + fail("Sliced slices do not match", sb, sb2); + if ((sb.hasArray()) && (sb.arrayOffset() != sb2.arrayOffset())) + fail("Array offsets do not match: " + + sb.arrayOffset() + " != " + sb2.arrayOffset(), sb, sb2); + +#if[byte] + + // Views + + b.clear(); + b.order(ByteOrder.BIG_ENDIAN); + testViews(level + 1, b, direct); + + for (int i = 1; i <= 9; i++) { + b.position(i); + show(level + 1, b); + testViews(level + 2, b, direct); + } + + b.position(0); + b.order(ByteOrder.LITTLE_ENDIAN); + testViews(level + 1, b, direct); + + // Heterogeneous accessors + + b.order(ByteOrder.BIG_ENDIAN); + for (int i = 0; i <= 9; i++) { + b.position(i); + testHet(level + 1, b); + } + b.order(ByteOrder.LITTLE_ENDIAN); + b.position(3); + testHet(level + 1, b); + +#end[byte] + + // Read-only views + + b.rewind(); + final $Type$Buffer rb = b.asReadOnlyBuffer(); + if (!b.equals(rb)) + fail("Buffer not equal to read-only view", b, rb); + show(level + 1, rb); + + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + relPut(rb); + }}); + + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + absPut(rb); + }}); + + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + bulkPutArray(rb); + }}); + + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + bulkPutBuffer(rb); + }}); + + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + rb.compact(); + }}); + +#if[byte] + + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + rb.putChar((char)1); + }}); + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + rb.putChar(0, (char)1); + }}); + + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + rb.putShort((short)1); + }}); + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + rb.putShort(0, (short)1); + }}); + + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + rb.putInt(1); + }}); + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + rb.putInt(0, 1); + }}); + + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + rb.putLong((long)1); + }}); + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + rb.putLong(0, (long)1); + }}); + + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + rb.putFloat((float)1); + }}); + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + rb.putFloat(0, (float)1); + }}); + + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + rb.putDouble((double)1); + }}); + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + rb.putDouble(0, (double)1); + }}); + +#end[byte] + + if (rb.getClass().getName().startsWith("java.nio.Heap")) { + + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + rb.array(); + }}); + + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + rb.arrayOffset(); + }}); + + if (rb.hasArray()) + fail("Read-only heap buffer's backing array is accessible", + rb); + + } + + // Bulk puts from read-only buffers + + b.clear(); + rb.rewind(); + b.put(rb); + +#if[byte] + // For byte buffers, test both the direct and non-direct cases + $Type$Buffer ob + = (b.isDirect() + ? $Type$Buffer.allocate(rb.capacity()) + : $Type$Buffer.allocateDirect(rb.capacity())); + rb.rewind(); + ob.put(rb); +#end[byte] + + relPut(b); // Required by testViews + + } + +#if[char] + + private static void testStr() { + final String s = "abcdefghijklm"; + int start = 3; + int end = 9; + final CharBuffer b = CharBuffer.wrap(s, start, end); + show(0, b); + ck(b, b.toString().equals(s.substring(start, end))); + ck(b, b.toString().equals("defghi")); + ck(b, b.isReadOnly()); + tryCatch(b, ReadOnlyBufferException.class, new Runnable() { + public void run() { + b.put('x'); + }}); + ck(b, start, b.position()); + ck(b, end, b.limit()); + ck(b, s.length(), b.capacity()); + b.position(6); + ck(b, b.subSequence(0,3).toString().equals("ghi")); + + // The index, relative to the position, must be non-negative and + // smaller than remaining(). + tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + b.charAt(-1); + }}); + tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + b.charAt(b.remaining()); + }}); + + // The index must be non-negative and less than the buffer's limit. + tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + b.get(b.limit()); + }}); + tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + b.get(-1); + }}); + + // The start must be non-negative and no larger than remaining(). + tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + b.subSequence(-1, b.remaining()); + }}); + tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + b.subSequence(b.remaining() + 1, b.remaining()); + }}); + + // The end must be no smaller than start and no larger than + // remaining(). + tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + b.subSequence(2, 1); + }}); + tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + b.subSequence(0, b.remaining() + 1); + }}); + + // The offset must be non-negative and no larger than <array.length>. + tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + $Type$Buffer.wrap(s, -1, s.length()); + }}); + tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + $Type$Buffer.wrap(s, s.length() + 1, s.length()); + }}); + tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + $Type$Buffer.wrap(s, 1, 0); + }}); + tryCatch(b, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + $Type$Buffer.wrap(s, 0, s.length() + 1); + }}); + } + +#end[char] + + public static void test(final $type$ [] ba) { + int offset = 47; + int length = 900; + final $Type$Buffer b = $Type$Buffer.wrap(ba, offset, length); + show(0, b); + ck(b, b.capacity(), ba.length); + ck(b, b.position(), offset); + ck(b, b.limit(), offset + length); + + // The offset must be non-negative and no larger than <array.length>. + tryCatch(ba, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + $Type$Buffer.wrap(ba, -1, ba.length); + }}); + tryCatch(ba, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + $Type$Buffer.wrap(ba, ba.length + 1, ba.length); + }}); + tryCatch(ba, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + $Type$Buffer.wrap(ba, 0, -1); + }}); + tryCatch(ba, IndexOutOfBoundsException.class, new Runnable() { + public void run() { + $Type$Buffer.wrap(ba, 0, ba.length + 1); + }}); + + // A NullPointerException will be thrown if the array is null. + tryCatch(ba, NullPointerException.class, new Runnable() { + public void run() { + $Type$Buffer.wrap(($type$ []) null, 0, 5); + }}); + tryCatch(ba, NullPointerException.class, new Runnable() { + public void run() { + $Type$Buffer.wrap(($type$ []) null); + }}); + } + + private static void testAllocate() { + // An IllegalArgumentException will be thrown for negative capacities. + tryCatch((Buffer) null, IllegalArgumentException.class, new Runnable() { + public void run() { + $Type$Buffer.allocate(-1); + }}); +#if[byte] + tryCatch((Buffer) null, IllegalArgumentException.class, new Runnable() { + public void run() { + $Type$Buffer.allocateDirect(-1); + }}); +#end[byte] + } + + public static void test() { + testAllocate(); + test(0, $Type$Buffer.allocate(7 * 1024), false); + test(0, $Type$Buffer.wrap(new $type$[7 * 1024], 0, 7 * 1024), false); + test(new $type$[1024]); +#if[byte] + $Type$Buffer b = $Type$Buffer.allocateDirect(7 * 1024); + for (b.position(0); b.position() < b.limit(); ) + ck(b, b.get(), 0); + test(0, b, true); +#end[byte] +#if[char] + testStr(); +#end[char] + + callReset($Type$Buffer.allocate(10)); + +#if[byte] +#else[byte] + putBuffer(); +#end[byte] + } + +}
--- a/test/java/nio/Buffer/CopyDirect-X-Memory.java Thu Nov 12 23:00:23 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -#warn This file is preprocessed before being compiled - -import java.nio.*; - -public class CopyDirect$Type$Memory - extends CopyDirectMemory -{ - private static void init($Type$Buffer b) { - int n = b.capacity(); - b.clear(); - for (int i = 0; i < n; i++) - b.put(i, ($type$)ic(i)); - b.limit(n); - b.position(0); - } - - private static void init($type$ [] a) { - for (int i = 0; i < a.length; i++) - a[i] = ($type$)ic(i + 1); - } - - public static void test() { -#if[byte] - ByteBuffer b = ByteBuffer.allocateDirect(1024 * 1024 + 1024); -#else[byte] - ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024 + 1024); - $Type$Buffer b = bb.as$Type$Buffer(); -#end[byte] - init(b); - $type$ [] a = new $type$[b.capacity()]; - init(a); - - // copyFrom$Type$Array (a -> b) - b.put(a); - for (int i = 0; i < a.length; i++) - ck(b, b.get(i), ($type$)ic(i + 1)); - - // copyTo$Type$Array (b -> a) - init(b); - init(a); - b.get(a); - for (int i = 0; i < a.length; i++) - if (a[i] != b.get(i)) - fail("Copy failed at " + i + ": '" - + a[i] + "' != '" + b.get(i) + "'"); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/nio/Buffer/CopyDirect-X-Memory.java.template Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,70 @@ +/* + * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#warn This file is preprocessed before being compiled + +import java.nio.*; + +public class CopyDirect$Type$Memory + extends CopyDirectMemory +{ + private static void init($Type$Buffer b) { + int n = b.capacity(); + b.clear(); + for (int i = 0; i < n; i++) + b.put(i, ($type$)ic(i)); + b.limit(n); + b.position(0); + } + + private static void init($type$ [] a) { + for (int i = 0; i < a.length; i++) + a[i] = ($type$)ic(i + 1); + } + + public static void test() { +#if[byte] + ByteBuffer b = ByteBuffer.allocateDirect(1024 * 1024 + 1024); +#else[byte] + ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024 + 1024); + $Type$Buffer b = bb.as$Type$Buffer(); +#end[byte] + init(b); + $type$ [] a = new $type$[b.capacity()]; + init(a); + + // copyFrom$Type$Array (a -> b) + b.put(a); + for (int i = 0; i < a.length; i++) + ck(b, b.get(i), ($type$)ic(i + 1)); + + // copyTo$Type$Array (b -> a) + init(b); + init(a); + b.get(a); + for (int i = 0; i < a.length; i++) + if (a[i] != b.get(i)) + fail("Copy failed at " + i + ": '" + + a[i] + "' != '" + b.get(i) + "'"); + } +}
--- a/test/java/nio/Buffer/genBasic.sh Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/nio/Buffer/genBasic.sh Thu Nov 12 23:04:42 2009 +0000 @@ -26,7 +26,7 @@ javac -d . ../../../../make/tools/src/build/tools/spp/Spp.java gen() { - java build.tools.spp.Spp -K$1 -Dtype=$1 -DType=$2 -DFulltype=$3 <Basic-X.java >Basic$2.java + java build.tools.spp.Spp -K$1 -Dtype=$1 -DType=$2 -DFulltype=$3 <Basic-X.java.template >Basic$2.java } gen byte Byte Byte
--- a/test/java/nio/Buffer/genCopyDirectMemory.sh Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/nio/Buffer/genCopyDirectMemory.sh Thu Nov 12 23:04:42 2009 +0000 @@ -26,7 +26,7 @@ javac -d . ../../../../make/tools/src/build/tools/spp/Spp.java > Spp.java gen() { - java build.tools.spp.Spp -K$1 -Dtype=$1 -DType=$2 -DFulltype=$3<CopyDirect-X-Memory.java >CopyDirect$2Memory.java + java build.tools.spp.Spp -K$1 -Dtype=$1 -DType=$2 -DFulltype=$3<CopyDirect-X-Memory.java.template >CopyDirect$2Memory.java } gen byte Byte Byte
--- a/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java Thu Nov 12 23:04:42 2009 +0000 @@ -34,7 +34,7 @@ public class Unbounded { // number of concurrent completion handlers - static final int CONCURRENCY_COUNT = 512; + static final int CONCURRENCY_COUNT = 256; public static void main(String[] args) throws Exception { // all accepted connections are added to a queue
--- a/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java Thu Nov 12 23:04:42 2009 +0000 @@ -73,22 +73,22 @@ List<InetAddress> addrs = Collections.list(nif.getInetAddresses()); for (InetAddress addr: addrs) { - if (addr instanceof Inet4Address) { - List<InetAddress> list = ip4Interfaces.get(nif); - if (list == null) { - list = new LinkedList<InetAddress>(); + if (!addr.isAnyLocalAddress()) { + if (addr instanceof Inet4Address) { + List<InetAddress> list = ip4Interfaces.get(nif); + if (list == null) { + list = new LinkedList<InetAddress>(); + } + list.add(addr); + ip4Interfaces.put(nif, list); + } else if (addr instanceof Inet6Address) { + List<InetAddress> list = ip6Interfaces.get(nif); + if (list == null) { + list = new LinkedList<InetAddress>(); + } + list.add(addr); + ip6Interfaces.put(nif, list); } - list.add(addr); - ip4Interfaces.put(nif, list); - } - if (addr instanceof Inet6Address) { - List<InetAddress> list = ip6Interfaces.get(nif); - if (list == null) { - list = new LinkedList<InetAddress>(); - } - list.add(addr); - ip6Interfaces.put(nif, list); - } } }
--- a/test/java/nio/channels/FileChannel/Transfer.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/nio/channels/FileChannel/Transfer.java Thu Nov 12 23:04:42 2009 +0000 @@ -25,6 +25,7 @@ * @bug 4434723 4482726 4559072 4638365 4795550 5081340 5103988 6253145 * @summary Test FileChannel.transferFrom and transferTo * @library .. + * @run main/timeout=180 Transfer */ import java.io.*;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/nio/channels/Selector/LotsOfCancels.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,292 @@ +/* + * Copyright 2009 Google Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Reproduces O(N^2) behavior of JDK6/7 select() call. This happens when + * a selector has many unprocessed updates to its interest set (e.g. adding + * OP_READ on a bunch of newly accepted sockets). The O(N^2) is triggered + * by cancelling a number of selection keys (or just closing a few sockets). + * In this case, select() will first go through the list of cancelled keys + * and try to deregister them. That deregistration is O(N^2) over the list + * of unprocessed updates to the interest set. + * + * <p> This O(N^2) behavior is a BUG in JVM and should be fixed. + * + * <p> The test first creates initCount connections, and adds them + * to the server epoll set. It then creates massCount connections, + * registers interest (causing updateList to be populated with massCount*2 + * elements), but does not add them to epoll set (that would've cleared + * updateList). The test then closes initCount connections, thus populating + * deregistration queue. The subsequent call to selectNow() will first process + * deregistration queue, performing O(N^2) over updateList size, + * equal to massCount * 2. + * + * <p> Note that connect rate is artificially slowed down to compensate + * for what I believe is a Linux bug, where too high of a connection rate + * ends up in SYN's being dropped and then slow retransmits. + * + * @author Igor Chernyshev + */ +public class LotsOfCancels { + + static long testStartTime; + + public static void main(String[] args) throws Exception { + // the final select should run in less than 1000ms. + runTest(500, 2700, 1000); + } + + static void log(String msg) { + System.out.println(getLogPrefix() + msg); + } + + static String getLogPrefix() { + return durationMillis(testStartTime) + ": "; + } + + /** + * Returns the elapsed time since startNanos, in milliseconds. + * @param startNanos the start time; this must be a value returned + * by {@link System.nanoTime} + */ + static long durationMillis(long startNanos) { + return (System.nanoTime() - startNanos) / (1000L * 1000L); + } + + static void runTest(int initCount, int massCount, int maxSelectTime) + throws Exception { + testStartTime = System.nanoTime(); + + InetSocketAddress address = new InetSocketAddress("127.0.0.1", 7359); + + // Create server channel, add it to selector and run epoll_ctl. + log("Setting up server"); + Selector serverSelector = Selector.open(); + ServerSocketChannel server = ServerSocketChannel.open(); + server.configureBlocking(false); + server.socket().bind(address, 5000); + server.register(serverSelector, SelectionKey.OP_ACCEPT); + serverSelector.selectNow(); + + log("Setting up client"); + ClientThread client = new ClientThread(address); + client.start(); + Thread.sleep(100); + + // Set up initial set of client sockets. + log("Starting initial client connections"); + client.connectClients(initCount); + Thread.sleep(500); // Wait for client connections to arrive + + // Accept all initial client sockets, add to selector and run + // epoll_ctl. + log("Accepting initial connections"); + List<SocketChannel> serverChannels1 = + acceptAndAddAll(serverSelector, server, initCount); + if (serverChannels1.size() != initCount) { + throw new Exception("Accepted " + serverChannels1.size() + + " instead of " + initCount); + } + serverSelector.selectNow(); + + // Set up mass set of client sockets. + log("Requesting mass client connections"); + client.connectClients(massCount); + Thread.sleep(500); // Wait for client connections to arrive + + // Accept all mass client sockets, add to selector and do NOT + // run epoll_ctl. + log("Accepting mass connections"); + List<SocketChannel> serverChannels2 = + acceptAndAddAll(serverSelector, server, massCount); + if (serverChannels2.size() != massCount) { + throw new Exception("Accepted " + serverChannels2.size() + + " instead of " + massCount); + } + + // Close initial set of sockets. + log("Closing initial connections"); + closeAll(serverChannels1); + + // Now get the timing of select() call. + log("Running the final select call"); + long startTime = System.nanoTime(); + serverSelector.selectNow(); + long duration = durationMillis(startTime); + log("Init count = " + initCount + + ", mass count = " + massCount + + ", duration = " + duration + "ms"); + + if (duration > maxSelectTime) { + System.out.println + ("\n\n\n\n\nFAILURE: The final selectNow() took " + + duration + "ms " + + "- seems like O(N^2) bug is still here\n\n"); + System.exit(1); + } + } + + static List<SocketChannel> acceptAndAddAll(Selector selector, + ServerSocketChannel server, + int expected) + throws Exception { + int retryCount = 0; + int acceptCount = 0; + List<SocketChannel> channels = new ArrayList<SocketChannel>(); + while (channels.size() < expected) { + SocketChannel channel = server.accept(); + if (channel == null) { + log("accept() returned null " + + "after accepting " + acceptCount + " more connections"); + acceptCount = 0; + if (retryCount < 10) { + // See if more new sockets got stacked behind. + retryCount++; + Thread.sleep(500); + continue; + } + break; + } + retryCount = 0; + acceptCount++; + channel.configureBlocking(false); + channel.register(selector, SelectionKey.OP_READ); + channels.add(channel); + } + // Cause an additional updateList entry per channel. + for (SocketChannel channel : channels) { + channel.register(selector, SelectionKey.OP_WRITE); + } + return channels; + } + + static void closeAll(List<SocketChannel> channels) + throws Exception { + for (SocketChannel channel : channels) { + channel.close(); + } + } + + static class ClientThread extends Thread { + private final SocketAddress address; + private final Selector selector; + private int connectionsNeeded; + private int totalCreated; + + ClientThread(SocketAddress address) throws Exception { + this.address = address; + selector = Selector.open(); + setDaemon(true); + } + + void connectClients(int count) throws Exception { + synchronized (this) { + connectionsNeeded += count; + } + selector.wakeup(); + } + + @Override + public void run() { + try { + handleClients(); + } catch (Throwable e) { + e.printStackTrace(); + System.exit(1); + } + } + + private void handleClients() throws Exception { + int selectCount = 0; + while (true) { + int createdCount = 0; + synchronized (this) { + if (connectionsNeeded > 0) { + + while (connectionsNeeded > 0 && createdCount < 20) { + connectionsNeeded--; + createdCount++; + totalCreated++; + + SocketChannel channel = SocketChannel.open(); + channel.configureBlocking(false); + channel.connect(address); + if (!channel.finishConnect()) { + channel.register(selector, + SelectionKey.OP_CONNECT); + } + } + + log("Started total of " + + totalCreated + " client connections"); + Thread.sleep(200); + } + } + + if (createdCount > 0) { + selector.selectNow(); + } else { + selectCount++; + long startTime = System.nanoTime(); + selector.select(); + long duration = durationMillis(startTime); + log("Exited clientSelector.select(), loop #" + + selectCount + ", duration = " + duration + "ms"); + } + + int keyCount = -1; + Iterator<SelectionKey> keys = + selector.selectedKeys().iterator(); + while (keys.hasNext()) { + SelectionKey key = keys.next(); + synchronized (key) { + keyCount++; + keys.remove(); + if (!key.isValid()) { + log("Ignoring client key #" + keyCount); + continue; + } + int readyOps = key.readyOps(); + if (readyOps == SelectionKey.OP_CONNECT) { + key.interestOps(0); + ((SocketChannel) key.channel()).finishConnect(); + } else { + log("readyOps() on client key #" + keyCount + + " returned " + readyOps); + } + } + } + } + } + } +}
--- a/test/java/nio/file/Path/CopyAndMove.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/nio/file/Path/CopyAndMove.java Thu Nov 12 23:04:42 2009 +0000 @@ -25,6 +25,8 @@ * @bug 4313887 6838333 * @summary Unit test for java.nio.file.Path copyTo/moveTo methods * @library .. + * @build CopyAndMove + * @run main/othervm CopyAndMove */ import java.nio.ByteBuffer;
--- a/test/java/nio/file/Path/Links.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/nio/file/Path/Links.java Thu Nov 12 23:04:42 2009 +0000 @@ -26,6 +26,8 @@ * @summary Unit test for java.nio.file.Path createSymbolicLink, * readSymbolicLink, and createLink methods * @library .. + * @build Links + * @run main/othervm Links */ import java.nio.file.*;
--- a/test/java/util/Arrays/Sorting.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/Arrays/Sorting.java Thu Nov 12 23:04:42 2009 +0000 @@ -23,11 +23,14 @@ /* * @test - * @bug 6880672 6896573 + * @bug 6880672 6896573 6899694 * @summary Exercise Arrays.sort * @build Sorting * @run main Sorting -shortrun - * @author Vladimir Yaroslavskiy, Josh Bloch, Jon Bentley + * + * @author Vladimir Yaroslavskiy + * @author Jon Bentley + * @author Josh Bloch */ import java.util.Arrays; @@ -35,59 +38,300 @@ import java.io.PrintStream; public class Sorting { - static final PrintStream out = System.out; - static final PrintStream err = System.err; + private static final PrintStream out = System.out; + private static final PrintStream err = System.err; + + // Array lengths used in a long run (default) + private static final int[] LONG_RUN_LENGTHS = { + 1, 2, 3, 5, 8, 13, 21, 34, 55, 100, 1000, 10000, 100000, 1000000}; - // array lengths used in a long run (default) - static final int[] LONG_RUN = { - 0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 100, 1000, 10000, 100000, 1000000}; + // Array lengths used in a short run + private static final int[] SHORT_RUN_LENGTHS = { 1, 2, 3, 21, 55, 1000, 10000 }; - // array lengths used in a short run - static final int[] SHORT_RUN = {0, 1, 2, 3, 21, 55, 1000, 10000, 500000}; + // Random initial values used in a long run (default) + private static final long[] LONG_RUN_RANDOMS = {666, 0xC0FFEE, 999}; + + // Random initial values used in a short run + private static final long[] SHORT_RUN_RANDOMS = {666}; public static void main(String[] args) { - boolean shortRun = false; - if (args.length > 0 && args[0].equals("-shortrun")) - shortRun = true; + boolean shortRun = args.length > 0 && args[0].equals("-shortrun"); + long start = System.currentTimeMillis(); + + if (shortRun) { + testAndCheck(SHORT_RUN_LENGTHS, SHORT_RUN_RANDOMS); + } else { + testAndCheck(LONG_RUN_LENGTHS, LONG_RUN_RANDOMS); + } + long end = System.currentTimeMillis(); + + out.format("PASS in %d sec.\n", Math.round((end - start) / 1E3)); + } - long start = System.nanoTime(); + private static void testAndCheck(int[] lengths, long[] randoms) { + for (long random : randoms) { + reset(random); + + for (int len : lengths) { + testAndCheckWithCheckSum(len, random); + } + reset(random); + + for (int len : lengths) { + testAndCheckWithScrambling(len, random); + } + reset(random); + + for (int len : lengths) { + testAndCheckFloat(len, random); + } + reset(random); - testAndCheck((shortRun) ? SHORT_RUN : LONG_RUN); + for (int len : lengths) { + testAndCheckDouble(len, random); + } + reset(random); + + for (int len : lengths) { + testAndCheckRange(len, random); + } + reset(random); + + for (int len : lengths) { + testAndCheckSubArray(len, random); + } + } + } + + private static void testAndCheckSubArray(int len, long random) { + int[] golden = new int[len]; - long end = System.nanoTime(); + for (int m = 1; m < len / 2; m *= 2) { + int fromIndex = m; + int toIndex = len - m; + + prepareSubArray(golden, fromIndex, toIndex, m); + int[] test = golden.clone(); + for (TypeConverter converter : TypeConverter.values()) { + out.println("Test #6: " + converter + + " len = " + len + ", m = " + m); + Object convertedGolden = converter.convert(golden); + Object convertedTest = converter.convert(test); + + // outArr(test); + sortSubArray(convertedTest, fromIndex, toIndex); + // outArr(test); + checkSubArray(convertedTest, fromIndex, toIndex, m); + } + } out.println(); - out.format("PASS in %ds%n", Math.round((end - start) / 1e9)); } - static void testAndCheck(int[] lengths) { - for (int len : lengths) { - out.println(); - ArrayBuilder.reset(); - int[] golden = new int[len]; + private static void testAndCheckRange(int len, long random) { + int[] golden = new int[len]; + + for (int m = 1; m < 2 * len; m *= 2) { + for (int i = 1; i <= len; i++) { + golden[i - 1] = i % m + m % i; + } + for (TypeConverter converter : TypeConverter.values()) { + out.println("Test #5: " + converter + + ", len = " + len + ", m = " + m); + Object convertedGolden = converter.convert(golden); + sortRange(convertedGolden, m); + sortEmpty(convertedGolden); + } + } + out.println(); + } + + private static void testAndCheckWithCheckSum(int len, long random) { + int[] golden = new int[len]; + + for (int m = 1; m < 2 * len; m *= 2) { + for (UnsortedBuilder builder : UnsortedBuilder.values()) { + builder.build(golden, m); + int[] test = golden.clone(); + + for (TypeConverter converter : TypeConverter.values()) { + out.println("Test #1: " + converter + " " + builder + + "random = " + random + ", len = " + len + + ", m = " + m); + Object convertedGolden = converter.convert(golden); + Object convertedTest = converter.convert(test); + sort(convertedTest); + checkWithCheckSum(convertedTest, convertedGolden); + } + } + } + out.println(); + } + + private static void testAndCheckWithScrambling(int len, long random) { + int[] golden = new int[len]; - for (int m = 1; m < 2 * len; m *= 2) { - for (ArrayBuilder builder : ArrayBuilder.values()) { - builder.build(golden, m); - int[] test = golden.clone(); + for (int m = 1; m <= 7; m++) { + if (m > len) { + break; + } + for (SortedBuilder builder : SortedBuilder.values()) { + builder.build(golden, m); + int[] test = golden.clone(); + scramble(test); + + for (TypeConverter converter : TypeConverter.values()) { + out.println("Test #2: " + converter + " " + builder + + "random = " + random + ", len = " + len + + ", m = " + m); + Object convertedGolden = converter.convert(golden); + Object convertedTest = converter.convert(test); + sort(convertedTest); + compare(convertedTest, convertedGolden); + } + } + } + out.println(); + } - for (Converter converter : Converter.values()) { - out.println("Test: " + converter + " " + builder + - "len = " + len + ", m = " + m); - Object convertedGolden = converter.convert(golden); - Object convertedTest = converter.convert(test); - sort(convertedTest); - checkWithCheckSum(convertedTest, convertedGolden); + private static void testAndCheckFloat(int len, long random) { + float[] golden = new float[len]; + final int MAX = 10; + boolean newLine = false; + + for (int a = 0; a <= MAX; a++) { + for (int g = 0; g <= MAX; g++) { + for (int z = 0; z <= MAX; z++) { + for (int n = 0; n <= MAX; n++) { + for (int p = 0; p <= MAX; p++) { + if (a + g + z + n + p > len) { + continue; + } + if (a + g + z + n + p < len) { + continue; + } + for (FloatBuilder builder : FloatBuilder.values()) { + out.println("Test #3: random = " + random + + ", len = " + len + ", a = " + a + ", g = " + g + + ", z = " + z + ", n = " + n + ", p = " + p); + builder.build(golden, a, g, z, n, p); + float[] test = golden.clone(); + scramble(test); + // outArr(test); + sort(test); + // outArr(test); + compare(test, golden, a, n, g); + } + newLine = true; + } } } } } + if (newLine) { + out.println(); + } + } + + private static void testAndCheckDouble(int len, long random) { + double[] golden = new double[len]; + final int MAX = 10; + boolean newLine = false; + + for (int a = 0; a <= MAX; a++) { + for (int g = 0; g <= MAX; g++) { + for (int z = 0; z <= MAX; z++) { + for (int n = 0; n <= MAX; n++) { + for (int p = 0; p <= MAX; p++) { + if (a + g + z + n + p > len) { + continue; + } + if (a + g + z + n + p < len) { + continue; + } + for (DoubleBuilder builder : DoubleBuilder.values()) { + out.println("Test #4: random = " + random + + ", len = " + len + ", a = " + a + ", g = " + g + + ", z = " + z + ", n = " + n + ", p = " + p); + builder.build(golden, a, g, z, n, p); + double[] test = golden.clone(); + scramble(test); + // outArr(test); + sort(test); + // outArr(test); + compare(test, golden, a, n, g); + } + newLine = true; + } + } + } + } + } + if (newLine) { + out.println(); + } } - static enum Converter { + private static void prepareSubArray(int[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + a[i] = 0xBABA; + } + + for (int i = fromIndex; i < toIndex; i++) { + a[i] = -i + m; + } + + for (int i = toIndex; i < a.length; i++) { + a[i] = 0xDEDA; + } + } + + private static void scramble(int[] a) { + int length = a.length; + + for (int i = 0; i < length * 7; i++) { + swap(a, ourRandom.nextInt(length), ourRandom.nextInt(length)); + } + } + + private static void scramble(float[] a) { + int length = a.length; + + for (int i = 0; i < length * 7; i++) { + swap(a, ourRandom.nextInt(length), ourRandom.nextInt(length)); + } + } + + private static void scramble(double[] a) { + int length = a.length; + + for (int i = 0; i < length * 7; i++) { + swap(a, ourRandom.nextInt(length), ourRandom.nextInt(length)); + } + } + + private static void swap(int[] a, int i, int j) { + int t = a[i]; + a[i] = a[j]; + a[j] = t; + } + + private static void swap(float[] a, int i, int j) { + float t = a[i]; + a[i] = a[j]; + a[j] = t; + } + + private static void swap(double[] a, int i, int j) { + double t = a[i]; + a[i] = a[j]; + a[j] = t; + } + + private static enum TypeConverter { INT { Object convert(int[] a) { - return a; + return a.clone(); } }, LONG { @@ -95,7 +339,7 @@ long[] b = new long[a.length]; for (int i = 0; i < a.length; i++) { - b[i] = (int) a[i]; + b[i] = (long) a[i]; } return b; } @@ -163,7 +407,161 @@ } } - static enum ArrayBuilder { + private static enum FloatBuilder { + SIMPLE { + void build(float[] x, int a, int g, int z, int n, int p) { + int fromIndex = 0; + float negativeValue = -ourRandom.nextFloat(); + float positiveValue = ourRandom.nextFloat(); + + writeValue(x, negativeValue, fromIndex, n); + fromIndex += n; + + writeValue(x, -0.0f, fromIndex, g); + fromIndex += g; + + writeValue(x, 0.0f, fromIndex, z); + fromIndex += z; + + writeValue(x, positiveValue, fromIndex, p); + fromIndex += p; + + writeValue(x, Float.NaN, fromIndex, a); + } + }; + + abstract void build(float[] x, int a, int g, int z, int n, int p); + } + + private static enum DoubleBuilder { + SIMPLE { + void build(double[] x, int a, int g, int z, int n, int p) { + int fromIndex = 0; + double negativeValue = -ourRandom.nextFloat(); + double positiveValue = ourRandom.nextFloat(); + + writeValue(x, negativeValue, fromIndex, n); + fromIndex += n; + + writeValue(x, -0.0d, fromIndex, g); + fromIndex += g; + + writeValue(x, 0.0d, fromIndex, z); + fromIndex += z; + + writeValue(x, positiveValue, fromIndex, p); + fromIndex += p; + + writeValue(x, Double.NaN, fromIndex, a); + } + }; + + abstract void build(double[] x, int a, int g, int z, int n, int p); + } + + private static void writeValue(float[] a, float value, int fromIndex, int count) { + for (int i = fromIndex; i < fromIndex + count; i++) { + a[i] = value; + } + } + + private static void compare(float[] a, float[] b, int numNaN, int numNeg, int numNegZero) { + for (int i = a.length - numNaN; i < a.length; i++) { + if (a[i] == a[i]) { + failed("On position " + i + " must be NaN instead of " + a[i]); + } + } + final int NEGATIVE_ZERO = Float.floatToIntBits(-0.0f); + + for (int i = numNeg; i < numNeg + numNegZero; i++) { + if (NEGATIVE_ZERO != Float.floatToIntBits(a[i])) { + failed("On position " + i + " must be -0.0f instead of " + a[i]); + } + } + for (int i = 0; i < a.length - numNaN; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + + private static void writeValue(double[] a, double value, int fromIndex, int count) { + for (int i = fromIndex; i < fromIndex + count; i++) { + a[i] = value; + } + } + + private static void compare(double[] a, double[] b, int numNaN, int numNeg, int numNegZero) { + for (int i = a.length - numNaN; i < a.length; i++) { + if (a[i] == a[i]) { + failed("On position " + i + " must be NaN instead of " + a[i]); + } + } + final long NEGATIVE_ZERO = Double.doubleToLongBits(-0.0d); + + for (int i = numNeg; i < numNeg + numNegZero; i++) { + if (NEGATIVE_ZERO != Double.doubleToLongBits(a[i])) { + failed("On position " + i + " must be -0.0d instead of " + a[i]); + } + } + for (int i = 0; i < a.length - numNaN; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + + private static enum SortedBuilder { + REPEATED { + void build(int[] a, int m) { + int period = a.length / m; + int i = 0; + int k = 0; + + while (true) { + for (int t = 1; t <= period; t++) { + if (i >= a.length) { + return; + } + a[i++] = k; + } + if (i >= a.length) { + return; + } + k++; + } + } + }, + + ORGAN_PIPES { + void build(int[] a, int m) { + int i = 0; + int k = m; + + while (true) { + for (int t = 1; t <= m; t++) { + if (i >= a.length) { + return; + } + a[i++] = k; + } + } + } + }; + + abstract void build(int[] a, int m); + + @Override public String toString() { + String name = name(); + + for (int i = name.length(); i < 12; i++) { + name += " "; + } + return name; + } + } + + private static enum UnsortedBuilder { RANDOM { void build(int[] a, int m) { for (int i = 0; i < a.length; i++) { @@ -268,41 +666,53 @@ abstract void build(int[] a, int m); - static void reset() { - ourRandom = new Random(666); - ourFirst = 0; - ourSecond = 0; - } - @Override public String toString() { String name = name(); + for (int i = name.length(); i < 12; i++) { name += " "; } return name; } - - private static int ourFirst; - private static int ourSecond; - private static Random ourRandom = new Random(666); } - static void checkWithCheckSum(Object test, Object golden) { + private static void compare(Object test, Object golden) { + if (test instanceof int[]) { + compare((int[]) test, (int[]) golden); + } else if (test instanceof long[]) { + compare((long[]) test, (long[]) golden); + } else if (test instanceof short[]) { + compare((short[]) test, (short[]) golden); + } else if (test instanceof byte[]) { + compare((byte[]) test, (byte[]) golden); + } else if (test instanceof char[]) { + compare((char[]) test, (char[]) golden); + } else if (test instanceof float[]) { + compare((float[]) test, (float[]) golden); + } else if (test instanceof double[]) { + compare((double[]) test, (double[]) golden); + } else { + failed("Unknow type of array: " + test + " of class " + + test.getClass().getName()); + } + } + + private static void checkWithCheckSum(Object test, Object golden) { checkSorted(test); checkCheckSum(test, golden); } - static void failed(String message) { - err.format("***FAILED: %s%%n", message); + private static void failed(String message) { + err.format("\n*** FAILED: %s\n\n", message); throw new RuntimeException("Test failed - see log file for details"); } - static void failed(int index, String value1, String value2) { + private static void failed(int index, String value1, String value2) { failed("Array is not sorted at " + index + "-th position: " + value1 + " and " + value2); } - static void checkSorted(Object object) { + private static void checkSorted(Object object) { if (object instanceof int[]) { checkSorted((int[]) object); } else if (object instanceof long[]) { @@ -323,31 +733,63 @@ } } - static void checkSorted(int[] a) { - for (int i = 0; i < a.length - 1; i++) { - if (a[i] > a[i + 1]) { - failed(i, "" + a[i], "" + a[i + 1]); + private static void compare(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + + private static void compare(long[] a, long[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + + private static void compare(short[] a, short[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); } } } - static void checkSorted(long[] a) { - for (int i = 0; i < a.length - 1; i++) { - if (a[i] > a[i + 1]) { - failed(i, "" + a[i], "" + a[i + 1]); + private static void compare(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + + private static void compare(char[] a, char[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); } } } - static void checkSorted(short[] a) { - for (int i = 0; i < a.length - 1; i++) { - if (a[i] > a[i + 1]) { - failed(i, "" + a[i], "" + a[i + 1]); + private static void compare(float[] a, float[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); } } } - static void checkSorted(byte[] a) { + private static void compare(double[] a, double[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + failed(i, "" + a[i], "" + b[i]); + } + } + } + + private static void checkSorted(int[] a) { for (int i = 0; i < a.length - 1; i++) { if (a[i] > a[i + 1]) { failed(i, "" + a[i], "" + a[i + 1]); @@ -355,7 +797,7 @@ } } - static void checkSorted(char[] a) { + private static void checkSorted(long[] a) { for (int i = 0; i < a.length - 1; i++) { if (a[i] > a[i + 1]) { failed(i, "" + a[i], "" + a[i + 1]); @@ -363,7 +805,15 @@ } } - static void checkSorted(float[] a) { + private static void checkSorted(short[] a) { + for (int i = 0; i < a.length - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + } + + private static void checkSorted(byte[] a) { for (int i = 0; i < a.length - 1; i++) { if (a[i] > a[i + 1]) { failed(i, "" + a[i], "" + a[i + 1]); @@ -371,7 +821,15 @@ } } - static void checkSorted(double[] a) { + private static void checkSorted(char[] a) { + for (int i = 0; i < a.length - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + } + + private static void checkSorted(float[] a) { for (int i = 0; i < a.length - 1; i++) { if (a[i] > a[i + 1]) { failed(i, "" + a[i], "" + a[i + 1]); @@ -379,13 +837,21 @@ } } - static void checkCheckSum(Object test, Object golden) { + private static void checkSorted(double[] a) { + for (int i = 0; i < a.length - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + } + + private static void checkCheckSum(Object test, Object golden) { if (checkSum(test) != checkSum(golden)) { failed("Original and sorted arrays seems not identical"); } } - static int checkSum(Object object) { + private static int checkSum(Object object) { if (object instanceof int[]) { return checkSum((int[]) object); } else if (object instanceof long[]) { @@ -407,70 +873,70 @@ } } - static int checkSum(int[] a) { - int checkSum = 0; + private static int checkSum(int[] a) { + int checkXorSum = 0; for (int e : a) { - checkSum ^= e; // xor + checkXorSum ^= e; } - return checkSum; + return checkXorSum; } - static int checkSum(long[] a) { - long checkSum = 0; + private static int checkSum(long[] a) { + long checkXorSum = 0; for (long e : a) { - checkSum ^= e; // xor + checkXorSum ^= e; } - return (int) checkSum; + return (int) checkXorSum; } - static int checkSum(short[] a) { - short checkSum = 0; + private static int checkSum(short[] a) { + short checkXorSum = 0; for (short e : a) { - checkSum ^= e; // xor + checkXorSum ^= e; } - return (int) checkSum; + return (int) checkXorSum; } - static int checkSum(byte[] a) { - byte checkSum = 0; + private static int checkSum(byte[] a) { + byte checkXorSum = 0; for (byte e : a) { - checkSum ^= e; // xor + checkXorSum ^= e; } - return (int) checkSum; + return (int) checkXorSum; } - static int checkSum(char[] a) { - char checkSum = 0; + private static int checkSum(char[] a) { + char checkXorSum = 0; for (char e : a) { - checkSum ^= e; // xor + checkXorSum ^= e; } - return (int) checkSum; + return (int) checkXorSum; } - static int checkSum(float[] a) { - int checkSum = 0; + private static int checkSum(float[] a) { + int checkXorSum = 0; for (float e : a) { - checkSum ^= (int) e; // xor + checkXorSum ^= (int) e; } - return checkSum; + return checkXorSum; } - static int checkSum(double[] a) { - int checkSum = 0; + private static int checkSum(double[] a) { + int checkXorSum = 0; for (double e : a) { - checkSum ^= (int) e; // xor + checkXorSum ^= (int) e; } - return checkSum; + return checkXorSum; } - static void sort(Object object) { + private static void sort(Object object) { if (object instanceof int[]) { Arrays.sort((int[]) object); } else if (object instanceof long[]) { @@ -490,4 +956,485 @@ object.getClass().getName()); } } + + private static void sortSubArray(Object object, int fromIndex, int toIndex) { + if (object instanceof int[]) { + Arrays.sort((int[]) object, fromIndex, toIndex); + } else if (object instanceof long[]) { + Arrays.sort((long[]) object, fromIndex, toIndex); + } else if (object instanceof short[]) { + Arrays.sort((short[]) object, fromIndex, toIndex); + } else if (object instanceof byte[]) { + Arrays.sort((byte[]) object, fromIndex, toIndex); + } else if (object instanceof char[]) { + Arrays.sort((char[]) object, fromIndex, toIndex); + } else if (object instanceof float[]) { + Arrays.sort((float[]) object, fromIndex, toIndex); + } else if (object instanceof double[]) { + Arrays.sort((double[]) object, fromIndex, toIndex); + } else { + failed("Unknow type of array: " + object + " of class " + + object.getClass().getName()); + } + } + + private static void checkSubArray(Object object, int fromIndex, int toIndex, int m) { + if (object instanceof int[]) { + checkSubArray((int[]) object, fromIndex, toIndex, m); + } else if (object instanceof long[]) { + checkSubArray((long[]) object, fromIndex, toIndex, m); + } else if (object instanceof short[]) { + checkSubArray((short[]) object, fromIndex, toIndex, m); + } else if (object instanceof byte[]) { + checkSubArray((byte[]) object, fromIndex, toIndex, m); + } else if (object instanceof char[]) { + checkSubArray((char[]) object, fromIndex, toIndex, m); + } else if (object instanceof float[]) { + checkSubArray((float[]) object, fromIndex, toIndex, m); + } else if (object instanceof double[]) { + checkSubArray((double[]) object, fromIndex, toIndex, m); + } else { + failed("Unknow type of array: " + object + " of class " + + object.getClass().getName()); + } + } + + private static void checkSubArray(int[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + if (a[i] != 0xBABA) { + failed("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + 0xBABA); + } + } + + for (int i = fromIndex; i < toIndex - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + + for (int i = toIndex; i < a.length; i++) { + if (a[i] != 0xDEDA) { + failed("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + 0xDEDA); + } + } + } + + private static void checkSubArray(byte[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + if (a[i] != (byte) 0xBABA) { + failed("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + 0xBABA); + } + } + + for (int i = fromIndex; i < toIndex - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + + for (int i = toIndex; i < a.length; i++) { + if (a[i] != (byte) 0xDEDA) { + failed("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + 0xDEDA); + } + } + } + + private static void checkSubArray(long[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + if (a[i] != (long) 0xBABA) { + failed("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + 0xBABA); + } + } + + for (int i = fromIndex; i < toIndex - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + + for (int i = toIndex; i < a.length; i++) { + if (a[i] != (long) 0xDEDA) { + failed("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + 0xDEDA); + } + } + } + + private static void checkSubArray(char[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + if (a[i] != (char) 0xBABA) { + failed("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + 0xBABA); + } + } + + for (int i = fromIndex; i < toIndex - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + + for (int i = toIndex; i < a.length; i++) { + if (a[i] != (char) 0xDEDA) { + failed("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + 0xDEDA); + } + } + } + + private static void checkSubArray(short[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + if (a[i] != (short) 0xBABA) { + failed("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + 0xBABA); + } + } + + for (int i = fromIndex; i < toIndex - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + + for (int i = toIndex; i < a.length; i++) { + if (a[i] != (short) 0xDEDA) { + failed("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + 0xDEDA); + } + } + } + + private static void checkSubArray(float[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + if (a[i] != (float) 0xBABA) { + failed("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + 0xBABA); + } + } + + for (int i = fromIndex; i < toIndex - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + + for (int i = toIndex; i < a.length; i++) { + if (a[i] != (float) 0xDEDA) { + failed("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + 0xDEDA); + } + } + } + + private static void checkSubArray(double[] a, int fromIndex, int toIndex, int m) { + for (int i = 0; i < fromIndex; i++) { + if (a[i] != (double) 0xBABA) { + failed("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + 0xBABA); + } + } + + for (int i = fromIndex; i < toIndex - 1; i++) { + if (a[i] > a[i + 1]) { + failed(i, "" + a[i], "" + a[i + 1]); + } + } + + for (int i = toIndex; i < a.length; i++) { + if (a[i] != (double) 0xDEDA) { + failed("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + 0xDEDA); + } + } + } + + private static void sortRange(Object object, int m) { + if (object instanceof int[]) { + sortRange((int[]) object, m); + } else if (object instanceof long[]) { + sortRange((long[]) object, m); + } else if (object instanceof short[]) { + sortRange((short[]) object, m); + } else if (object instanceof byte[]) { + sortRange((byte[]) object, m); + } else if (object instanceof char[]) { + sortRange((char[]) object, m); + } else if (object instanceof float[]) { + sortRange((float[]) object, m); + } else if (object instanceof double[]) { + sortRange((double[]) object, m); + } else { + failed("Unknow type of array: " + object + " of class " + + object.getClass().getName()); + } + } + + private static void sortEmpty(Object object) { + if (object instanceof int[]) { + Arrays.sort(new int [] {}); + } else if (object instanceof long[]) { + Arrays.sort(new long [] {}); + } else if (object instanceof short[]) { + Arrays.sort(new short [] {}); + } else if (object instanceof byte[]) { + Arrays.sort(new byte [] {}); + } else if (object instanceof char[]) { + Arrays.sort(new char [] {}); + } else if (object instanceof float[]) { + Arrays.sort(new float [] {}); + } else if (object instanceof double[]) { + Arrays.sort(new double [] {}); + } else { + failed("Unknow type of array: " + object + " of class " + + object.getClass().getName()); + } + } + + private static void sortRange(int[] a, int m) { + try { + Arrays.sort(a, m + 1, m); + + failed("Sort does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + + " toIndex = " + m); + } + catch (IllegalArgumentException iae) { + try { + Arrays.sort(a, -m, a.length); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: fromIndex = " + (-m)); + } + catch (ArrayIndexOutOfBoundsException aoe) { + try { + Arrays.sort(a, 0, a.length + m); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: toIndex = " + (a.length + m)); + } + catch (ArrayIndexOutOfBoundsException aie) { + return; + } + } + } + } + + private static void sortRange(long[] a, int m) { + try { + Arrays.sort(a, m + 1, m); + + failed("Sort does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + + " toIndex = " + m); + } + catch (IllegalArgumentException iae) { + try { + Arrays.sort(a, -m, a.length); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: fromIndex = " + (-m)); + } + catch (ArrayIndexOutOfBoundsException aoe) { + try { + Arrays.sort(a, 0, a.length + m); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: toIndex = " + (a.length + m)); + } + catch (ArrayIndexOutOfBoundsException aie) { + return; + } + } + } + } + + private static void sortRange(byte[] a, int m) { + try { + Arrays.sort(a, m + 1, m); + + failed("Sort does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + + " toIndex = " + m); + } + catch (IllegalArgumentException iae) { + try { + Arrays.sort(a, -m, a.length); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: fromIndex = " + (-m)); + } + catch (ArrayIndexOutOfBoundsException aoe) { + try { + Arrays.sort(a, 0, a.length + m); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: toIndex = " + (a.length + m)); + } + catch (ArrayIndexOutOfBoundsException aie) { + return; + } + } + } + } + + private static void sortRange(short[] a, int m) { + try { + Arrays.sort(a, m + 1, m); + + failed("Sort does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + + " toIndex = " + m); + } + catch (IllegalArgumentException iae) { + try { + Arrays.sort(a, -m, a.length); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: fromIndex = " + (-m)); + } + catch (ArrayIndexOutOfBoundsException aoe) { + try { + Arrays.sort(a, 0, a.length + m); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: toIndex = " + (a.length + m)); + } + catch (ArrayIndexOutOfBoundsException aie) { + return; + } + } + } + } + + private static void sortRange(char[] a, int m) { + try { + Arrays.sort(a, m + 1, m); + + failed("Sort does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + + " toIndex = " + m); + } + catch (IllegalArgumentException iae) { + try { + Arrays.sort(a, -m, a.length); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: fromIndex = " + (-m)); + } + catch (ArrayIndexOutOfBoundsException aoe) { + try { + Arrays.sort(a, 0, a.length + m); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: toIndex = " + (a.length + m)); + } + catch (ArrayIndexOutOfBoundsException aie) { + return; + } + } + } + } + + private static void sortRange(float[] a, int m) { + try { + Arrays.sort(a, m + 1, m); + + failed("Sort does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + + " toIndex = " + m); + } + catch (IllegalArgumentException iae) { + try { + Arrays.sort(a, -m, a.length); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: fromIndex = " + (-m)); + } + catch (ArrayIndexOutOfBoundsException aoe) { + try { + Arrays.sort(a, 0, a.length + m); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: toIndex = " + (a.length + m)); + } + catch (ArrayIndexOutOfBoundsException aie) { + return; + } + } + } + } + + private static void sortRange(double[] a, int m) { + try { + Arrays.sort(a, m + 1, m); + + failed("Sort does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + + " toIndex = " + m); + } + catch (IllegalArgumentException iae) { + try { + Arrays.sort(a, -m, a.length); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: fromIndex = " + (-m)); + } + catch (ArrayIndexOutOfBoundsException aoe) { + try { + Arrays.sort(a, 0, a.length + m); + + failed("Sort does not throw ArrayIndexOutOfBoundsException " + + " as expected: toIndex = " + (a.length + m)); + } + catch (ArrayIndexOutOfBoundsException aie) { + return; + } + } + } + } + + private static void prepareRandom(int[] a) { + for (int i = 0; i < a.length; i++) { + a[i] = ourRandom.nextInt(); + } + } + + private static void reset(long seed) { + ourRandom = new Random(seed); + ourFirst = 0; + ourSecond = 0; + } + + private static void outArr(int[] a) { + for (int i = 0; i < a.length; i++) { + out.print(a[i] + " "); + } + out.println(); + out.println(); + } + + private static void outArr(float[] a) { + for (int i = 0; i < a.length; i++) { + out.print(a[i] + " "); + } + out.println(); + out.println(); + } + + private static void outArr(double[] a) { + for (int i = 0; i < a.length; i++) { + out.print(a[i] + " "); + } + out.println(); + out.println(); + } + + private static int ourFirst; + private static int ourSecond; + private static Random ourRandom; }
--- a/test/java/util/Collection/BiggernYours.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/Collection/BiggernYours.java Thu Nov 12 23:04:42 2009 +0000 @@ -178,10 +178,10 @@ new ConcurrentLinkedQueue() { public int size() {return randomize(super.size());}}); -// testCollections( -// new LinkedTransferQueue(), -// new LinkedTransferQueue() { -// public int size() {return randomize(super.size());}}); + testCollections( + new LinkedTransferQueue(), + new LinkedTransferQueue() { + public int size() {return randomize(super.size());}}); testCollections( new LinkedBlockingQueue(),
--- a/test/java/util/Collection/IteratorAtEnd.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/Collection/IteratorAtEnd.java Thu Nov 12 23:04:42 2009 +0000 @@ -49,7 +49,7 @@ testCollection(new LinkedBlockingQueue()); testCollection(new ArrayBlockingQueue(100)); testCollection(new ConcurrentLinkedQueue()); -// testCollection(new LinkedTransferQueue()); + testCollection(new LinkedTransferQueue()); testMap(new HashMap()); testMap(new Hashtable());
--- a/test/java/util/Collection/MOAT.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/Collection/MOAT.java Thu Nov 12 23:04:42 2009 +0000 @@ -76,7 +76,7 @@ testCollection(new LinkedBlockingQueue<Integer>(20)); testCollection(new LinkedBlockingDeque<Integer>(20)); testCollection(new ConcurrentLinkedQueue<Integer>()); -// testCollection(new LinkedTransferQueue<Integer>()); + testCollection(new LinkedTransferQueue<Integer>()); testCollection(new ConcurrentSkipListSet<Integer>()); testCollection(Arrays.asList(new Integer(42))); testCollection(Arrays.asList(1,2,3)); @@ -421,8 +421,11 @@ private static void testQueue(Queue<Integer> q) { q.clear(); - for (int i = 0; i < 5; i++) + for (int i = 0; i < 5; i++) { + testQueueAddRemove(q, null); + testQueueAddRemove(q, 537); q.add(i); + } equal(q.size(), 5); checkFunctionalInvariants(q); q.poll(); @@ -435,6 +438,216 @@ } } + private static void testQueueAddRemove(final Queue<Integer> q, + final Integer e) { + final List<Integer> originalContents = new ArrayList<Integer>(q); + final boolean isEmpty = q.isEmpty(); + final boolean isList = (q instanceof List); + final List asList = isList ? (List) q : null; + check(!q.contains(e)); + try { + q.add(e); + } catch (NullPointerException npe) { + check(e == null); + return; // Null elements not supported + } + check(q.contains(e)); + check(q.remove(e)); + check(!q.contains(e)); + equal(new ArrayList<Integer>(q), originalContents); + + if (q instanceof Deque<?>) { + final Deque<Integer> deq = (Deque<Integer>) q; + final List<Integer> singleton = Collections.singletonList(e); + + // insert, query, remove element at head + if (isEmpty) { + THROWS(NoSuchElementException.class, + new Fun(){void f(){ deq.getFirst(); }}, + new Fun(){void f(){ deq.element(); }}, + new Fun(){void f(){ deq.iterator().next(); }}); + check(deq.peekFirst() == null); + check(deq.peek() == null); + } else { + check(deq.getFirst() != e); + check(deq.element() != e); + check(deq.iterator().next() != e); + check(deq.peekFirst() != e); + check(deq.peek() != e); + } + check(!deq.contains(e)); + check(!deq.removeFirstOccurrence(e)); + check(!deq.removeLastOccurrence(e)); + if (isList) { + check(asList.indexOf(e) == -1); + check(asList.lastIndexOf(e) == -1); + } + switch (rnd.nextInt(isList ? 4 : 3)) { + case 0: deq.addFirst(e); break; + case 1: check(deq.offerFirst(e)); break; + case 2: deq.push(e); break; + case 3: asList.add(0, e); break; + default: throw new AssertionError(); + } + check(deq.peekFirst() == e); + check(deq.getFirst() == e); + check(deq.element() == e); + check(deq.peek() == e); + check(deq.iterator().next() == e); + check(deq.contains(e)); + if (isList) { + check(asList.get(0) == e); + check(asList.indexOf(e) == 0); + check(asList.lastIndexOf(e) == 0); + check(asList.subList(0, 1).equals(singleton)); + } + switch (rnd.nextInt(isList ? 11 : 9)) { + case 0: check(deq.pollFirst() == e); break; + case 1: check(deq.removeFirst() == e); break; + case 2: check(deq.remove() == e); break; + case 3: check(deq.pop() == e); break; + case 4: check(deq.removeFirstOccurrence(e)); break; + case 5: check(deq.removeLastOccurrence(e)); break; + case 6: check(deq.remove(e)); break; + case 7: check(deq.removeAll(singleton)); break; + case 8: Iterator it = deq.iterator(); it.next(); it.remove(); break; + case 9: asList.remove(0); break; + case 10: asList.subList(0, 1).clear(); break; + default: throw new AssertionError(); + } + if (isEmpty) { + THROWS(NoSuchElementException.class, + new Fun(){void f(){ deq.getFirst(); }}, + new Fun(){void f(){ deq.element(); }}, + new Fun(){void f(){ deq.iterator().next(); }}); + check(deq.peekFirst() == null); + check(deq.peek() == null); + } else { + check(deq.getFirst() != e); + check(deq.element() != e); + check(deq.iterator().next() != e); + check(deq.peekFirst() != e); + check(deq.peek() != e); + } + check(!deq.contains(e)); + check(!deq.removeFirstOccurrence(e)); + check(!deq.removeLastOccurrence(e)); + if (isList) { + check(isEmpty || asList.get(0) != e); + check(asList.indexOf(e) == -1); + check(asList.lastIndexOf(e) == -1); + } + equal(new ArrayList<Integer>(deq), originalContents); + + // insert, query, remove element at tail + if (isEmpty) { + check(deq.peekLast() == null); + THROWS(NoSuchElementException.class, + new Fun(){void f(){ deq.getLast(); }}); + } else { + check(deq.peekLast() != e); + check(deq.getLast() != e); + } + switch (rnd.nextInt(isList ? 6 : 4)) { + case 0: deq.addLast(e); break; + case 1: check(deq.offerLast(e)); break; + case 2: check(deq.add(e)); break; + case 3: deq.addAll(singleton); break; + case 4: asList.addAll(deq.size(), singleton); break; + case 5: asList.add(deq.size(), e); break; + default: throw new AssertionError(); + } + check(deq.peekLast() == e); + check(deq.getLast() == e); + check(deq.contains(e)); + if (isList) { + ListIterator it = asList.listIterator(asList.size()); + check(it.previous() == e); + check(asList.get(asList.size() - 1) == e); + check(asList.indexOf(e) == asList.size() - 1); + check(asList.lastIndexOf(e) == asList.size() - 1); + int size = asList.size(); + check(asList.subList(size - 1, size).equals(singleton)); + } + switch (rnd.nextInt(isList ? 8 : 6)) { + case 0: check(deq.pollLast() == e); break; + case 1: check(deq.removeLast() == e); break; + case 2: check(deq.removeFirstOccurrence(e)); break; + case 3: check(deq.removeLastOccurrence(e)); break; + case 4: check(deq.remove(e)); break; + case 5: check(deq.removeAll(singleton)); break; + case 6: asList.remove(asList.size() - 1); break; + case 7: + ListIterator it = asList.listIterator(asList.size()); + it.previous(); + it.remove(); + break; + default: throw new AssertionError(); + } + if (isEmpty) { + check(deq.peekLast() == null); + THROWS(NoSuchElementException.class, + new Fun(){void f(){ deq.getLast(); }}); + } else { + check(deq.peekLast() != e); + check(deq.getLast() != e); + } + check(!deq.contains(e)); + equal(new ArrayList<Integer>(deq), originalContents); + + // Test operations on empty deque + switch (rnd.nextInt(isList ? 4 : 2)) { + case 0: deq.clear(); break; + case 1: + Iterator it = deq.iterator(); + while (it.hasNext()) { + it.next(); + it.remove(); + } + break; + case 2: asList.subList(0, asList.size()).clear(); break; + case 3: + ListIterator lit = asList.listIterator(asList.size()); + while (lit.hasPrevious()) { + lit.previous(); + lit.remove(); + } + break; + default: throw new AssertionError(); + } + testEmptyCollection(deq); + check(!deq.iterator().hasNext()); + if (isList) { + check(!asList.listIterator().hasPrevious()); + THROWS(NoSuchElementException.class, + new Fun(){void f(){ asList.listIterator().previous(); }}); + } + THROWS(NoSuchElementException.class, + new Fun(){void f(){ deq.iterator().next(); }}, + new Fun(){void f(){ deq.element(); }}, + new Fun(){void f(){ deq.getFirst(); }}, + new Fun(){void f(){ deq.getLast(); }}, + new Fun(){void f(){ deq.pop(); }}, + new Fun(){void f(){ deq.remove(); }}, + new Fun(){void f(){ deq.removeFirst(); }}, + new Fun(){void f(){ deq.removeLast(); }}); + + check(deq.poll() == null); + check(deq.pollFirst() == null); + check(deq.pollLast() == null); + check(deq.peek() == null); + check(deq.peekFirst() == null); + check(deq.peekLast() == null); + check(!deq.removeFirstOccurrence(e)); + check(!deq.removeLastOccurrence(e)); + + check(deq.addAll(originalContents) == !isEmpty); + equal(new ArrayList<Integer>(deq), originalContents); + check(!deq.addAll(Collections.<Integer>emptyList())); + equal(new ArrayList<Integer>(deq), originalContents); + } + } + private static void testQueueIteratorRemove(Queue<Integer> q) { System.err.printf("testQueueIteratorRemove %s%n", q.getClass().getSimpleName());
--- a/test/java/util/Collections/CheckedNull.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/Collections/CheckedNull.java Thu Nov 12 23:04:42 2009 +0000 @@ -52,7 +52,7 @@ testMap(Collections.checkedMap( new HashMap<String, String>(), - String.class, String.class));; + String.class, String.class)); } ClassCastException cce(F f) {
--- a/test/java/util/Collections/RacingCollections.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/Collections/RacingCollections.java Thu Nov 12 23:04:42 2009 +0000 @@ -234,7 +234,7 @@ List<Queue<Integer>> list = new ArrayList<Queue<Integer>>(newConcurrentDeques()); list.add(new LinkedBlockingQueue<Integer>(10)); -// list.add(new LinkedTransferQueue<Integer>()); + list.add(new LinkedTransferQueue<Integer>()); return list; }
--- a/test/java/util/PriorityQueue/RemoveContains.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/PriorityQueue/RemoveContains.java Thu Nov 12 23:04:42 2009 +0000 @@ -69,7 +69,7 @@ test(new ArrayBlockingQueue<String>(10)); test(new LinkedBlockingQueue<String>(10)); test(new LinkedBlockingDeque<String>(10)); -// test(new LinkedTransferQueue<String>()); + test(new LinkedTransferQueue<String>()); test(new ArrayDeque<String>(10)); System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
--- a/test/java/util/concurrent/BlockingQueue/CancelledProducerConsumerLoops.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/concurrent/BlockingQueue/CancelledProducerConsumerLoops.java Thu Nov 12 23:04:42 2009 +0000 @@ -119,12 +119,36 @@ } } + static final class LTQasSQ<T> extends LinkedTransferQueue<T> { + LTQasSQ() { super(); } + public void put(T x) { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + private final static long serialVersionUID = 42; + } + + static final class HalfSyncLTQ<T> extends LinkedTransferQueue<T> { + HalfSyncLTQ() { super(); } + public void put(T x) { + if (ThreadLocalRandom.current().nextBoolean()) + super.put(x); + else { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + } + private final static long serialVersionUID = 42; + } + static void oneTest(int pairs, int iters) throws Exception { oneRun(new ArrayBlockingQueue<Integer>(CAPACITY), pairs, iters); oneRun(new LinkedBlockingQueue<Integer>(CAPACITY), pairs, iters); oneRun(new LinkedBlockingDeque<Integer>(CAPACITY), pairs, iters); -// oneRun(new LinkedTransferQueue<Integer>(), pairs, iters); + oneRun(new LinkedTransferQueue<Integer>(), pairs, iters); + oneRun(new LTQasSQ<Integer>(), pairs, iters); + oneRun(new HalfSyncLTQ<Integer>(), pairs, iters); oneRun(new SynchronousQueue<Integer>(), pairs, iters / 8); /* PriorityBlockingQueue is unbounded
--- a/test/java/util/concurrent/BlockingQueue/LastElement.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/concurrent/BlockingQueue/LastElement.java Thu Nov 12 23:04:42 2009 +0000 @@ -37,7 +37,7 @@ testQueue(new LinkedBlockingDeque<Integer>()); testQueue(new ArrayBlockingQueue<Integer>(10, true)); testQueue(new ArrayBlockingQueue<Integer>(10, false)); -// testQueue(new LinkedTransferQueue<Integer>()); + testQueue(new LinkedTransferQueue<Integer>()); System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new Exception("Some tests failed");
--- a/test/java/util/concurrent/BlockingQueue/MultipleProducersSingleConsumerLoops.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/concurrent/BlockingQueue/MultipleProducersSingleConsumerLoops.java Thu Nov 12 23:04:42 2009 +0000 @@ -87,11 +87,35 @@ throw new Error(); } + static final class LTQasSQ<T> extends LinkedTransferQueue<T> { + LTQasSQ() { super(); } + public void put(T x) { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + private final static long serialVersionUID = 42; + } + + static final class HalfSyncLTQ<T> extends LinkedTransferQueue<T> { + HalfSyncLTQ() { super(); } + public void put(T x) { + if (ThreadLocalRandom.current().nextBoolean()) + super.put(x); + else { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + } + private final static long serialVersionUID = 42; + } + static void oneTest(int producers, int iters) throws Exception { oneRun(new ArrayBlockingQueue<Integer>(CAPACITY), producers, iters); oneRun(new LinkedBlockingQueue<Integer>(CAPACITY), producers, iters); oneRun(new LinkedBlockingDeque<Integer>(CAPACITY), producers, iters); -// oneRun(new LinkedTransferQueue<Integer>(), producers, iters); + oneRun(new LinkedTransferQueue<Integer>(), producers, iters); + oneRun(new LTQasSQ<Integer>(), producers, iters); + oneRun(new HalfSyncLTQ<Integer>(), producers, iters); // Don't run PBQ since can legitimately run out of memory // if (print)
--- a/test/java/util/concurrent/BlockingQueue/OfferDrainToLoops.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/concurrent/BlockingQueue/OfferDrainToLoops.java Thu Nov 12 23:04:42 2009 +0000 @@ -63,12 +63,11 @@ test(new LinkedBlockingDeque()); test(new LinkedBlockingDeque(2000)); test(new ArrayBlockingQueue(2000)); -// test(new LinkedTransferQueue()); + test(new LinkedTransferQueue()); } Random getRandom() { - return new Random(); - // return ThreadLocalRandom.current(); + return ThreadLocalRandom.current(); } void test(final BlockingQueue q) throws Throwable {
--- a/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java Thu Nov 12 23:04:42 2009 +0000 @@ -46,7 +46,7 @@ public static void main(String[] args) throws InterruptedException { final BlockingQueue[] qs = { new LinkedBlockingQueue(10), -// new LinkedTransferQueue(), + new LinkedTransferQueue(), new ArrayBlockingQueue(10), new SynchronousQueue(), new SynchronousQueue(true),
--- a/test/java/util/concurrent/BlockingQueue/ProducerConsumerLoops.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/concurrent/BlockingQueue/ProducerConsumerLoops.java Thu Nov 12 23:04:42 2009 +0000 @@ -87,11 +87,35 @@ throw new Error(); } + static final class LTQasSQ<T> extends LinkedTransferQueue<T> { + LTQasSQ() { super(); } + public void put(T x) { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + private final static long serialVersionUID = 42; + } + + static final class HalfSyncLTQ<T> extends LinkedTransferQueue<T> { + HalfSyncLTQ() { super(); } + public void put(T x) { + if (ThreadLocalRandom.current().nextBoolean()) + super.put(x); + else { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + } + private final static long serialVersionUID = 42; + } + static void oneTest(int pairs, int iters) throws Exception { oneRun(new ArrayBlockingQueue<Integer>(CAPACITY), pairs, iters); oneRun(new LinkedBlockingQueue<Integer>(CAPACITY), pairs, iters); oneRun(new LinkedBlockingDeque<Integer>(CAPACITY), pairs, iters); -// oneRun(new LinkedTransferQueue<Integer>(), pairs, iters); + oneRun(new LinkedTransferQueue<Integer>(), pairs, iters); + oneRun(new LTQasSQ<Integer>(), pairs, iters); + oneRun(new HalfSyncLTQ<Integer>(), pairs, iters); oneRun(new PriorityBlockingQueue<Integer>(), pairs, iters); oneRun(new SynchronousQueue<Integer>(), pairs, iters);
--- a/test/java/util/concurrent/BlockingQueue/SingleProducerMultipleConsumerLoops.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/concurrent/BlockingQueue/SingleProducerMultipleConsumerLoops.java Thu Nov 12 23:04:42 2009 +0000 @@ -73,11 +73,35 @@ throw new Error(); } + static final class LTQasSQ<T> extends LinkedTransferQueue<T> { + LTQasSQ() { super(); } + public void put(T x) { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + private final static long serialVersionUID = 42; + } + + static final class HalfSyncLTQ<T> extends LinkedTransferQueue<T> { + HalfSyncLTQ() { super(); } + public void put(T x) { + if (ThreadLocalRandom.current().nextBoolean()) + super.put(x); + else { + try { super.transfer(x); } + catch (InterruptedException ex) { throw new Error(); } + } + } + private final static long serialVersionUID = 42; + } + static void oneTest(int consumers, int iters) throws Exception { oneRun(new ArrayBlockingQueue<Integer>(CAPACITY), consumers, iters); oneRun(new LinkedBlockingQueue<Integer>(CAPACITY), consumers, iters); oneRun(new LinkedBlockingDeque<Integer>(CAPACITY), consumers, iters); -// oneRun(new LinkedTransferQueue<Integer>(), consumers, iters); + oneRun(new LinkedTransferQueue<Integer>(), consumers, iters); + oneRun(new LTQasSQ<Integer>(), consumers, iters); + oneRun(new HalfSyncLTQ<Integer>(), consumers, iters); oneRun(new PriorityBlockingQueue<Integer>(), consumers, iters); oneRun(new SynchronousQueue<Integer>(), consumers, iters); if (print)
--- a/test/java/util/concurrent/ConcurrentQueues/ConcurrentQueueLoops.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/concurrent/ConcurrentQueues/ConcurrentQueueLoops.java Thu Nov 12 23:04:42 2009 +0000 @@ -60,7 +60,7 @@ //queues.add(new ArrayBlockingQueue<Integer>(count, true)); queues.add(new LinkedBlockingQueue<Integer>()); queues.add(new LinkedBlockingDeque<Integer>()); -// queues.add(new LinkedTransferQueue<Integer>()); + queues.add(new LinkedTransferQueue<Integer>()); // Following additional implementations are available from: // http://gee.cs.oswego.edu/dl/concurrency-interest/index.html
--- a/test/java/util/concurrent/ConcurrentQueues/GCRetention.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/concurrent/ConcurrentQueues/GCRetention.java Thu Nov 12 23:04:42 2009 +0000 @@ -43,7 +43,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.LinkedBlockingQueue; -// import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.PriorityBlockingQueue; import java.util.LinkedList; import java.util.PriorityQueue; @@ -70,7 +70,7 @@ queues.add(new PriorityBlockingQueue<Boolean>()); queues.add(new PriorityQueue<Boolean>()); queues.add(new LinkedList<Boolean>()); -// queues.add(new LinkedTransferQueue<Boolean>()); + queues.add(new LinkedTransferQueue<Boolean>()); // Following additional implementations are available from: // http://gee.cs.oswego.edu/dl/concurrency-interest/index.html
--- a/test/java/util/concurrent/ConcurrentQueues/IteratorWeakConsistency.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/concurrent/ConcurrentQueues/IteratorWeakConsistency.java Thu Nov 12 23:04:42 2009 +0000 @@ -49,7 +49,7 @@ test(new LinkedBlockingDeque()); test(new LinkedBlockingDeque(20)); test(new ConcurrentLinkedQueue()); -// test(new LinkedTransferQueue()); + test(new LinkedTransferQueue()); // Other concurrent queues (e.g. ArrayBlockingQueue) do not // currently have weakly consistent iterators. // test(new ArrayBlockingQueue(20));
--- a/test/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java Thu Nov 12 23:04:42 2009 +0000 @@ -56,12 +56,11 @@ testQueue(new ArrayBlockingQueue(10)); testQueue(new PriorityBlockingQueue(10)); testQueue(new ConcurrentLinkedQueue()); -// testQueue(new LinkedTransferQueue()); + testQueue(new LinkedTransferQueue()); } Random getRandom() { - return new Random(); - // return ThreadLocalRandom.current(); + return ThreadLocalRandom.current(); } void testQueue(final Queue q) throws Throwable {
--- a/test/java/util/concurrent/ConcurrentQueues/RemovePollRace.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/concurrent/ConcurrentQueues/RemovePollRace.java Thu Nov 12 23:04:42 2009 +0000 @@ -45,7 +45,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.LinkedBlockingQueue; -// import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.atomic.AtomicLong; import java.util.ArrayList; import java.util.Collection; @@ -67,7 +67,7 @@ queues.add(new ArrayBlockingQueue<Boolean>(count, true)); queues.add(new LinkedBlockingQueue<Boolean>()); queues.add(new LinkedBlockingDeque<Boolean>()); -// queues.add(new LinkedTransferQueue<Boolean>()); + queues.add(new LinkedTransferQueue<Boolean>()); // Following additional implementations are available from: // http://gee.cs.oswego.edu/dl/concurrency-interest/index.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/concurrent/Phaser/Arrive.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,94 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +/* + * @test + * @bug 6445158 + * @summary tests for Phaser.arrive() + */ + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Phaser; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicInteger; + +public class Arrive { + void test(String[] args) throws Throwable { + final int n = ThreadLocalRandom.current().nextInt(1, 10); + final int nthreads = n*3/2; + final Phaser startingGate = new Phaser(nthreads); + final Phaser phaser = new Phaser(n); + final List<Thread> threads = new ArrayList<Thread>(); + final AtomicInteger count0 = new AtomicInteger(0); + final AtomicInteger count1 = new AtomicInteger(0); + final Runnable task = new Runnable() { public void run() { + equal(startingGate.getPhase(), 0); + startingGate.arriveAndAwaitAdvance(); + equal(startingGate.getPhase(), 1); + int phase = phaser.arrive(); + if (phase == 0) + count0.getAndIncrement(); + else if (phase == 1) + count1.getAndIncrement(); + else + fail(); + }}; + for (int i = 0; i < nthreads; i++) + threads.add(new Thread(task)); + for (Thread thread : threads) + thread.start(); + for (Thread thread : threads) + thread.join(); + equal(count0.get(), n); + equal(count1.get(), nthreads-n); + equal(phaser.getPhase(), 1); + } + + //--------------------- Infrastructure --------------------------- + volatile int passed = 0, failed = 0; + void pass() {passed++;} + void fail() {failed++; Thread.dumpStack();} + void fail(String msg) {System.err.println(msg); fail();} + void unexpected(Throwable t) {failed++; t.printStackTrace();} + void check(boolean cond) {if (cond) pass(); else fail();} + void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + new Arrive().instanceMain(args);} + public void instanceMain(String[] args) throws Throwable { + try {test(args);} catch (Throwable t) {unexpected(t);} + System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/concurrent/Phaser/Basic.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,407 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +/* + * @test + * @bug 6445158 + * @summary Basic tests for Phaser + * @author Chris Hegarty + */ + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.concurrent.Phaser; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; +import static java.util.concurrent.TimeUnit.*; + +public class Basic { + + private static void checkTerminated(final Phaser phaser) { + check(phaser.isTerminated()); + int unarriverParties = phaser.getUnarrivedParties(); + int registeredParties = phaser.getRegisteredParties(); + equal(phaser.arrive(), -1); + equal(phaser.arriveAndDeregister(), -1); + equal(phaser.arriveAndAwaitAdvance(), -1); + equal(phaser.bulkRegister(10), -1); + equal(phaser.getPhase(), -1); + equal(phaser.register(), -1); + try { + equal(phaser.awaitAdvanceInterruptibly(0), -1); + equal(phaser.awaitAdvanceInterruptibly(0, 10, SECONDS), -1); + } catch (Exception ie) { + unexpected(ie); + } + equal(phaser.getUnarrivedParties(), unarriverParties); + equal(phaser.getRegisteredParties(), registeredParties); + } + + private static void checkResult(Arriver a, Class<? extends Throwable> c) { + Throwable t = a.result(); + if (! ((t == null && c == null) || (c != null && c.isInstance(t)))) { + // t.printStackTrace(); + fail("Mismatch in thread " + + a.getName() + ": " + + t + ", " + + (c == null ? "<null>" : c.getName())); + } else { + pass(); + } + } + + //---------------------------------------------------------------- + // Mechanism to get all test threads into "running" mode. + //---------------------------------------------------------------- + private static Phaser atTheStartingGate = new Phaser(3); + + private static void toTheStartingGate() { + try { + boolean expectNextPhase = false; + if (atTheStartingGate.getUnarrivedParties() == 1) { + expectNextPhase = true; + } + int phase = atTheStartingGate.getPhase(); + equal(phase, atTheStartingGate.arrive()); + int AwaitPhase = atTheStartingGate.awaitAdvanceInterruptibly(phase, + 10, + SECONDS); + if (expectNextPhase) check(AwaitPhase == (phase + 1)); + + pass(); + } catch (Throwable t) { + unexpected(t); + // reset(atTheStartingGate); + throw new Error(t); + } + } + + //---------------------------------------------------------------- + // Convenience methods for creating threads that call arrive, + // awaitAdvance, arriveAndAwaitAdvance, awaitAdvanceInterruptibly + //---------------------------------------------------------------- + private static abstract class Arriver extends Thread { + static AtomicInteger count = new AtomicInteger(1); + + Arriver() { + this("Arriver"); + } + + Arriver(String name) { + this.setName(name + ":" + count.getAndIncrement()); + this.setDaemon(true); + } + + private volatile Throwable result; + private volatile int phase; + protected void result(Throwable result) { this.result = result; } + public Throwable result() { return this.result; } + protected void phase(int phase) { this.phase = phase; } + public int phase() { return this.phase; } + } + + private static abstract class Awaiter extends Arriver { + Awaiter() { super("Awaiter"); } + Awaiter(String name) { super(name); } + } + + private static Arriver arriver(final Phaser phaser) { + return new Arriver() { public void run() { + toTheStartingGate(); + + try { phase(phaser.arrive()); } + catch (Throwable result) { result(result); }}}; + } + + private static AtomicInteger cycleArriveAwaitAdvance = new AtomicInteger(1); + + private static Awaiter awaiter(final Phaser phaser) { + return new Awaiter() { public void run() { + toTheStartingGate(); + + try { + if (cycleArriveAwaitAdvance.getAndIncrement() % 2 == 0) + phase(phaser.awaitAdvance(phaser.arrive())); + else + phase(phaser.arriveAndAwaitAdvance()); + } catch (Throwable result) { result(result); }}}; + } + + private static Awaiter awaiter(final Phaser phaser, + final long timeout, + final TimeUnit unit) { + return new Awaiter("InterruptibleWaiter") { public void run() { + toTheStartingGate(); + + try { + if (timeout < 0) + phase(phaser.awaitAdvanceInterruptibly(phaser.arrive())); + else + phase(phaser.awaitAdvanceInterruptibly(phaser.arrive(), + timeout, + unit)); + } catch (Throwable result) { result(result); }}}; + } + + // Returns an infinite lazy list of all possible arriver/awaiter combinations. + private static Iterator<Arriver> arriverIterator(final Phaser phaser) { + return new Iterator<Arriver>() { + int i = 0; + public boolean hasNext() { return true; } + public Arriver next() { + switch ((i++)&7) { + case 0: case 4: + return arriver(phaser); + case 1: case 5: + return awaiter(phaser); + case 2: case 6: case 7: + return awaiter(phaser, -1, SECONDS); + default: + return awaiter(phaser, 10, SECONDS); }} + public void remove() {throw new UnsupportedOperationException();}}; + } + + // Returns an infinite lazy list of all possible awaiter only combinations. + private static Iterator<Awaiter> awaiterIterator(final Phaser phaser) { + return new Iterator<Awaiter>() { + int i = 0; + public boolean hasNext() { return true; } + public Awaiter next() { + switch ((i++)&7) { + case 1: case 4: case 7: + return awaiter(phaser); + case 2: case 5: + return awaiter(phaser, -1, SECONDS); + default: + return awaiter(phaser, 10, SECONDS); }} + public void remove() {throw new UnsupportedOperationException();}}; + } + + private static void realMain(String[] args) throws Throwable { + + Thread.currentThread().setName("mainThread"); + + //---------------------------------------------------------------- + // Normal use + //---------------------------------------------------------------- + try { + Phaser phaser = new Phaser(3); + equal(phaser.getRegisteredParties(), 3); + equal(phaser.getArrivedParties(), 0); + equal(phaser.getPhase(), 0); + check(phaser.getRoot().equals(phaser)); + equal(phaser.getParent(), null); + check(!phaser.isTerminated()); + + Iterator<Arriver> arrivers = arriverIterator(phaser); + int phase = 0; + for (int i = 0; i < 10; i++) { + equal(phaser.getPhase(), phase++); + Arriver a1 = arrivers.next(); a1.start(); + Arriver a2 = arrivers.next(); a2.start(); + toTheStartingGate(); + phaser.arriveAndAwaitAdvance(); + a1.join(); + a2.join(); + checkResult(a1, null); + checkResult(a2, null); + check(!phaser.isTerminated()); + equal(phaser.getRegisteredParties(), 3); + equal(phaser.getArrivedParties(), 0); + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // One thread interrupted + //---------------------------------------------------------------- + try { + Phaser phaser = new Phaser(3); + Iterator<Arriver> arrivers = arriverIterator(phaser); + int phase = phaser.getPhase(); + for (int i = 0; i < 4; i++) { + check(phaser.getPhase() == phase); + Awaiter a1 = awaiter(phaser, 10, SECONDS); a1.start(); + Arriver a2 = arrivers.next(); a2.start(); + toTheStartingGate(); + a1.interrupt(); + a1.join(); + phaser.arriveAndAwaitAdvance(); + a2.join(); + checkResult(a1, InterruptedException.class); + checkResult(a2, null); + check(!phaser.isTerminated()); + equal(phaser.getRegisteredParties(), 3); + equal(phaser.getArrivedParties(), 0); + phase++; + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // Phaser is terminated while threads are waiting + //---------------------------------------------------------------- + try { + Phaser phaser = new Phaser(3); + Iterator<Awaiter> awaiters = awaiterIterator(phaser); + for (int i = 0; i < 4; i++) { + Arriver a1 = awaiters.next(); a1.start(); + Arriver a2 = awaiters.next(); a2.start(); + toTheStartingGate(); + while (phaser.getArrivedParties() < 2) Thread.yield(); + phaser.forceTermination(); + a1.join(); + a2.join(); + check(a1.phase == -1); + check(a2.phase == -1); + int arrivedParties = phaser.getArrivedParties(); + checkTerminated(phaser); + equal(phaser.getArrivedParties(), arrivedParties); + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // Adds new unarrived parties to this phaser + //---------------------------------------------------------------- + try { + Phaser phaser = new Phaser(1); + Iterator<Arriver> arrivers = arriverIterator(phaser); + LinkedList<Arriver> arriverList = new LinkedList<Arriver>(); + int phase = phaser.getPhase(); + for (int i = 1; i < 5; i++) { + atTheStartingGate = new Phaser(1+(3*i)); + check(phaser.getPhase() == phase); + // register 3 more + phaser.register(); phaser.register(); phaser.register(); + for (int z=0; z<(3*i); z++) { + arriverList.add(arrivers.next()); + } + for (Arriver arriver : arriverList) + arriver.start(); + + toTheStartingGate(); + phaser.arriveAndAwaitAdvance(); + + for (Arriver arriver : arriverList) { + arriver.join(); + checkResult(arriver, null); + } + equal(phaser.getRegisteredParties(), 1 + (3*i)); + equal(phaser.getArrivedParties(), 0); + arriverList.clear(); + phase++; + } + atTheStartingGate = new Phaser(3); + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // One thread timed out + //---------------------------------------------------------------- + try { + Phaser phaser = new Phaser(3); + Iterator<Arriver> arrivers = arriverIterator(phaser); + for (long timeout : new long[] { 0L, 5L }) { + for (int i = 0; i < 2; i++) { + Awaiter a1 = awaiter(phaser, timeout, SECONDS); a1.start(); + Arriver a2 = arrivers.next(); a2.start(); + toTheStartingGate(); + a1.join(); + checkResult(a1, TimeoutException.class); + phaser.arrive(); + a2.join(); + checkResult(a2, null); + check(!phaser.isTerminated()); + } + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // Barrier action completed normally + //---------------------------------------------------------------- + try { + final AtomicInteger count = new AtomicInteger(0); + final Phaser[] kludge = new Phaser[1]; + Phaser phaser = new Phaser(3) { + @Override + protected boolean onAdvance(int phase, int registeredParties) { + int countPhase = count.getAndIncrement(); + equal(countPhase, phase); + equal(kludge[0].getPhase(), phase); + equal(kludge[0].getRegisteredParties(), registeredParties); + if (phase >= 3) + return true; // terminate + + return false; + } + }; + kludge[0] = phaser; + equal(phaser.getRegisteredParties(), 3); + Iterator<Awaiter> awaiters = awaiterIterator(phaser); + for (int i = 0; i < 4; i++) { + Awaiter a1 = awaiters.next(); a1.start(); + Awaiter a2 = awaiters.next(); a2.start(); + toTheStartingGate(); + while (phaser.getArrivedParties() < 2) Thread.yield(); + phaser.arrive(); + a1.join(); + a2.join(); + checkResult(a1, null); + checkResult(a2, null); + equal(count.get(), i+1); + if (i < 3) { + check(!phaser.isTerminated()); + equal(phaser.getRegisteredParties(), 3); + equal(phaser.getArrivedParties(), 0); + equal(phaser.getUnarrivedParties(), 3); + equal(phaser.getPhase(), count.get()); + } else + checkTerminated(phaser); + } + } catch (Throwable t) { unexpected(t); } + + } + + //--------------------- Infrastructure --------------------------- + static volatile int passed = 0, failed = 0; + static void pass() {passed++;} + static void fail() {failed++; Thread.dumpStack();} + static void fail(String msg) {System.out.println(msg); fail();} + static void unexpected(Throwable t) {failed++; t.printStackTrace();} + static void check(boolean cond) {if (cond) pass(); else fail();} + static void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + try {realMain(args);} catch (Throwable t) {unexpected(t);} + System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +}
--- a/test/java/util/concurrent/ScheduledThreadPoolExecutor/DelayOverflow.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/concurrent/ScheduledThreadPoolExecutor/DelayOverflow.java Thu Nov 12 23:04:42 2009 +0000 @@ -21,6 +21,17 @@ */ /* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +/* * @test * @bug 6725789 * @summary Check for long overflow in task time comparison.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/concurrent/forkjoin/Integrate.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,265 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +/* + * @test + * @bug 6865571 + * @summary Numerical Integration using fork/join + * @run main Integrate reps=1 forkPolicy=dynamic + * @run main Integrate reps=1 forkPolicy=serial + * @run main Integrate reps=1 forkPolicy=fork + */ + +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.RecursiveAction; + +/** + * Sample program using Gaussian Quadrature for numerical integration. + * This version uses a simplified hardwired function. Inspired by a + * <A href="http://www.cs.uga.edu/~dkl/filaments/dist.html"> + * Filaments</A> demo program. + */ +public final class Integrate { + + static final double errorTolerance = 1.0e-11; + /** for time conversion */ + static final long NPS = (1000L * 1000 * 1000); + + static final int SERIAL = -1; + static final int DYNAMIC = 0; + static final int FORK = 1; + + // the function to integrate + static double computeFunction(double x) { + return (x * x + 1.0) * x; + } + + static final double start = 0.0; + static final double end = 1536.0; + /* + * The number of recursive calls for + * integrate from start to end. + * (Empirically determined) + */ + static final int calls = 263479047; + + static String keywordValue(String[] args, String keyword) { + for (String arg : args) + if (arg.startsWith(keyword)) + return arg.substring(keyword.length() + 1); + return null; + } + + static int intArg(String[] args, String keyword, int defaultValue) { + String val = keywordValue(args, keyword); + return (val == null) ? defaultValue : Integer.parseInt(val); + } + + static int policyArg(String[] args, String keyword, int defaultPolicy) { + String val = keywordValue(args, keyword); + if (val == null) return defaultPolicy; + if (val.equals("dynamic")) return DYNAMIC; + if (val.equals("serial")) return SERIAL; + if (val.equals("fork")) return FORK; + throw new Error(); + } + + /** + * Usage: Integrate [procs=N] [reps=N] forkPolicy=serial|dynamic|fork + */ + public static void main(String[] args) throws Exception { + final int procs = intArg(args, "procs", + Runtime.getRuntime().availableProcessors()); + final int forkPolicy = policyArg(args, "forkPolicy", DYNAMIC); + + ForkJoinPool g = new ForkJoinPool(procs); + System.out.println("Integrating from " + start + " to " + end + + " forkPolicy = " + forkPolicy); + long lastTime = System.nanoTime(); + + for (int reps = intArg(args, "reps", 10); reps > 0; reps--) { + double a; + if (forkPolicy == SERIAL) + a = SQuad.computeArea(g, start, end); + else if (forkPolicy == FORK) + a = FQuad.computeArea(g, start, end); + else + a = DQuad.computeArea(g, start, end); + long now = System.nanoTime(); + double s = (double) (now - lastTime) / NPS; + lastTime = now; + System.out.printf("Calls/sec: %12d", (long) (calls / s)); + System.out.printf(" Time: %7.3f", s); + System.out.printf(" Area: %12.1f", a); + System.out.println(); + } + System.out.println(g); + g.shutdown(); + } + + + // Sequential version + static final class SQuad extends RecursiveAction { + static double computeArea(ForkJoinPool pool, double l, double r) { + SQuad q = new SQuad(l, r, 0); + pool.invoke(q); + return q.area; + } + + final double left; // lower bound + final double right; // upper bound + double area; + + SQuad(double l, double r, double a) { + this.left = l; this.right = r; this.area = a; + } + + public final void compute() { + double l = left; + double r = right; + area = recEval(l, r, (l * l + 1.0) * l, (r * r + 1.0) * r, area); + } + + static final double recEval(double l, double r, double fl, + double fr, double a) { + double h = (r - l) * 0.5; + double c = l + h; + double fc = (c * c + 1.0) * c; + double hh = h * 0.5; + double al = (fl + fc) * hh; + double ar = (fr + fc) * hh; + double alr = al + ar; + if (Math.abs(alr - a) <= errorTolerance) + return alr; + else + return recEval(c, r, fc, fr, ar) + recEval(l, c, fl, fc, al); + } + + } + + //.................................... + + // ForkJoin version + static final class FQuad extends RecursiveAction { + static double computeArea(ForkJoinPool pool, double l, double r) { + FQuad q = new FQuad(l, r, 0); + pool.invoke(q); + return q.area; + } + + final double left; // lower bound + final double right; // upper bound + double area; + + FQuad(double l, double r, double a) { + this.left = l; this.right = r; this.area = a; + } + + public final void compute() { + double l = left; + double r = right; + area = recEval(l, r, (l * l + 1.0) * l, (r * r + 1.0) * r, area); + } + + static final double recEval(double l, double r, double fl, + double fr, double a) { + double h = (r - l) * 0.5; + double c = l + h; + double fc = (c * c + 1.0) * c; + double hh = h * 0.5; + double al = (fl + fc) * hh; + double ar = (fr + fc) * hh; + double alr = al + ar; + if (Math.abs(alr - a) <= errorTolerance) + return alr; + FQuad q = new FQuad(l, c, al); + q.fork(); + ar = recEval(c, r, fc, fr, ar); + if (!q.tryUnfork()) { + q.quietlyHelpJoin(); + return ar + q.area; + } + return ar + recEval(l, c, fl, fc, al); + } + + } + + // ........................... + + // Version using on-demand Fork + static final class DQuad extends RecursiveAction { + static double computeArea(ForkJoinPool pool, double l, double r) { + DQuad q = new DQuad(l, r, 0); + pool.invoke(q); + return q.area; + } + + final double left; // lower bound + final double right; // upper bound + double area; + + DQuad(double l, double r, double a) { + this.left = l; this.right = r; this.area = a; + } + + public final void compute() { + double l = left; + double r = right; + area = recEval(l, r, (l * l + 1.0) * l, (r * r + 1.0) * r, area); + } + + static final double recEval(double l, double r, double fl, + double fr, double a) { + double h = (r - l) * 0.5; + double c = l + h; + double fc = (c * c + 1.0) * c; + double hh = h * 0.5; + double al = (fl + fc) * hh; + double ar = (fr + fc) * hh; + double alr = al + ar; + if (Math.abs(alr - a) <= errorTolerance) + return alr; + DQuad q = null; + if (getSurplusQueuedTaskCount() <= 3) + (q = new DQuad(l, c, al)).fork(); + ar = recEval(c, r, fc, fr, ar); + if (q != null && !q.tryUnfork()) { + q.quietlyHelpJoin(); + return ar + q.area; + } + return ar + recEval(l, c, fl, fc, al); + } + + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/concurrent/forkjoin/NQueensCS.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,174 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +/* + * @test + * @bug 6865571 + * @summary Solve NQueens using fork/join + * @run main NQueensCS maxBoardSize=11 reps=1 + * @run main NQueensCS maxBoardSize=11 reps=1 procs=8 + */ + +import java.util.Arrays; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.RecursiveAction; + +public class NQueensCS extends RecursiveAction { + + static long lastStealCount; + static int boardSize; + + static final int[] expectedSolutions = new int[] { + 0, 1, 0, 0, 2, 10, 4, 40, 92, 352, 724, 2680, 14200, + 73712, 365596, 2279184, 14772512, 95815104, 666090624 + }; // see http://www.durangobill.com/N_Queens.html + + static String keywordValue(String[] args, String keyword) { + for (String arg : args) + if (arg.startsWith(keyword)) + return arg.substring(keyword.length() + 1); + return null; + } + + static int intArg(String[] args, String keyword, int defaultValue) { + String val = keywordValue(args, keyword); + return (val == null) ? defaultValue : Integer.parseInt(val); + } + + /** for time conversion */ + static final long NPS = (1000L * 1000L * 1000L); + + /** + * Usage: NQueensCS [minBoardSize=N] [maxBoardSize=N] [procs=N] [reps=N] + */ + public static void main(String[] args) throws Exception { + // Board sizes too small: hard to measure well. + // Board sizes too large: take too long to run. + final int minBoardSize = intArg(args, "minBoardSize", 8); + final int maxBoardSize = intArg(args, "maxBoardSize", 15); + + final int procs = intArg(args, "procs", 0); + + for (int reps = intArg(args, "reps", 10); reps > 0; reps--) { + ForkJoinPool g = (procs == 0) ? + new ForkJoinPool() : + new ForkJoinPool(procs); + lastStealCount = g.getStealCount(); + for (int i = minBoardSize; i <= maxBoardSize; i++) + test(g, i); + System.out.println(g); + g.shutdown(); + } + } + + static void test(ForkJoinPool g, int i) throws Exception { + boardSize = i; + int ps = g.getParallelism(); + long start = System.nanoTime(); + NQueensCS task = new NQueensCS(new int[0]); + g.invoke(task); + int solutions = task.solutions; + long time = System.nanoTime() - start; + double secs = (double) time / NPS; + if (solutions != expectedSolutions[i]) + throw new Error(); + System.out.printf("NQueensCS %3d", i); + System.out.printf(" Time: %7.3f", secs); + long sc = g.getStealCount(); + long ns = sc - lastStealCount; + lastStealCount = sc; + System.out.printf(" Steals/t: %5d", ns/ps); + System.out.println(); + } + + // Boards are represented as arrays where each cell + // holds the column number of the queen in that row + + final int[] sofar; + NQueensCS nextSubtask; // to link subtasks + int solutions; + NQueensCS(int[] a) { + this.sofar = a; + } + + public final void compute() { + NQueensCS subtasks; + int bs = boardSize; + if (sofar.length >= bs) + solutions = 1; + else if ((subtasks = explore(sofar, bs)) != null) + solutions = processSubtasks(subtasks); + } + + private static NQueensCS explore(int[] array, int bs) { + int row = array.length; + NQueensCS s = null; // subtask list + outer: + for (int q = 0; q < bs; ++q) { + for (int i = 0; i < row; i++) { + int p = array[i]; + if (q == p || q == p - (row - i) || q == p + (row - i)) + continue outer; // attacked + } + NQueensCS first = s; // lag forks to ensure 1 kept + if (first != null) + first.fork(); + int[] next = Arrays.copyOf(array, row+1); + next[row] = q; + NQueensCS subtask = new NQueensCS(next); + subtask.nextSubtask = first; + s = subtask; + } + return s; + } + + private static int processSubtasks(NQueensCS s) { + // Always run first the task held instead of forked + s.compute(); + int ns = s.solutions; + s = s.nextSubtask; + // Then the unstolen ones + while (s != null && s.tryUnfork()) { + s.compute(); + ns += s.solutions; + s = s.nextSubtask; + } + // Then wait for the stolen ones + while (s != null) { + s.join(); + ns += s.solutions; + s = s.nextSubtask; + } + return ns; + } +}
--- a/test/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java Thu Nov 12 23:04:42 2009 +0000 @@ -115,7 +115,7 @@ finally { lock.unlock(); } - if (completed != 2) + if (c != 2) throw new Error("Completed != 2"); int r = result; if (r == 0) // avoid overoptimization
--- a/test/java/util/concurrent/locks/ReentrantReadWriteLock/RWMap.java Thu Nov 12 23:00:23 2009 +0000 +++ b/test/java/util/concurrent/locks/ReentrantReadWriteLock/RWMap.java Thu Nov 12 23:04:42 2009 +0000 @@ -30,6 +30,7 @@ * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ + import java.util.*; import java.util.concurrent.*; import java.util.concurrent.locks.*;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/swing/Security/6657138/ComponentTest.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,76 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657138 + * @summary Verifies that buttons and labels work well after the fix for 6657138 + * @author Alexander Potochkin + */ + +import sun.awt.SunToolkit; + +import javax.swing.*; +import java.awt.*; + +public class ComponentTest extends JFrame { + private static JFrame frame; + + public ComponentTest() { + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setLayout(new FlowLayout()); + add(new JButton("JButton")); + add(new JToggleButton("JToggleButton")); + add(new JCheckBox("JCheckBox")); + add(new JRadioButton("JRadioButton")); + add(new JLabel("JLabel")); + pack(); + setLocationRelativeTo(null); + } + + + public static void main(String[] args) throws Exception { + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame = new ComponentTest(); + frame.setVisible(true); + } + }); + toolkit.realSync(); + UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels(); + for (final UIManager.LookAndFeelInfo laf : lafs) { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (Exception e) { + new RuntimeException(e); + } + SwingUtilities.updateComponentTreeUI(frame); + } + }); + toolkit.realSync(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/swing/Security/6657138/bug6657138.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,103 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657138 + * @summary Verifies that buttons and labels don't share their ui's across appContexts + * @author Alexander Potochkin + */ + +import sun.awt.SunToolkit; + +import javax.swing.*; +import javax.swing.plaf.ButtonUI; +import javax.swing.plaf.ComponentUI; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class bug6657138 implements Runnable { + + private static Map<JComponent, Map<String, ComponentUI>> componentMap = + Collections.synchronizedMap( + new HashMap<JComponent, Map<String, ComponentUI>>()); + + public void run() { + SunToolkit.createNewAppContext(); + try { + testUIMap(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void testUIMap() throws Exception { + UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels(); + Set<JComponent> components = componentMap.keySet(); + for (JComponent c : components) { + Map<String, ComponentUI> uiMap = componentMap.get(c); + + for (UIManager.LookAndFeelInfo laf : lafs) { + if ("Nimbus".equals(laf.getName())) { + // for some unclear reasons + // Nimbus ui delegate for a button is null + // when this method is called from the new AppContext + continue; + } + String className = laf.getClassName(); + UIManager.setLookAndFeel(className); + ComponentUI ui = UIManager.getUI(c); + if (ui == null) { + throw new RuntimeException("UI is null for " + c); + } + if (ui == uiMap.get(laf.getName())) { + throw new RuntimeException( + "Two AppContexts share the same UI delegate! \n" + + c + "\n" + ui); + } + uiMap.put(laf.getName(), ui); + } + } + } + + public static void main(String[] args) throws Exception { + componentMap.put(new JButton("JButton"), + new HashMap<String, ComponentUI>()); + componentMap.put(new JToggleButton("JToggleButton"), + new HashMap<String, ComponentUI>()); + componentMap.put(new JRadioButton("JRadioButton"), + new HashMap<String, ComponentUI>()); + componentMap.put(new JCheckBox("JCheckBox"), + new HashMap<String, ComponentUI>()); + componentMap.put(new JCheckBox("JLabel"), + new HashMap<String, ComponentUI>()); + testUIMap(); + ThreadGroup group = new ThreadGroup("6657138"); + Thread thread = new Thread(group, new bug6657138()); + thread.start(); + thread.join(); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/swing/ToolTipManager/Test6657026.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,74 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657026 + * @summary Tests shared ToolTipManager in different application contexts + * @author Sergey Malenkov + */ + +import sun.awt.SunToolkit; +import javax.swing.ToolTipManager; + +public class Test6657026 implements Runnable { + + private static final int DISMISS = 4000; + private static final int INITIAL = 750; + private static final int RESHOW = 500; + + public static void main(String[] args) throws InterruptedException { + ToolTipManager manager = ToolTipManager.sharedInstance(); + if (DISMISS != manager.getDismissDelay()) { + throw new Error("unexpected dismiss delay"); + } + if (INITIAL != manager.getInitialDelay()) { + throw new Error("unexpected initial delay"); + } + if (RESHOW != manager.getReshowDelay()) { + throw new Error("unexpected reshow delay"); + } + manager.setDismissDelay(DISMISS + 1); + manager.setInitialDelay(INITIAL + 1); + manager.setReshowDelay(RESHOW + 1); + + ThreadGroup group = new ThreadGroup("$$$"); + Thread thread = new Thread(group, new Test6657026()); + thread.start(); + thread.join(); + } + + public void run() { + SunToolkit.createNewAppContext(); + ToolTipManager manager = ToolTipManager.sharedInstance(); + if (DISMISS != manager.getDismissDelay()) { + throw new Error("shared dismiss delay"); + } + if (INITIAL != manager.getInitialDelay()) { + throw new Error("shared initial delay"); + } + if (RESHOW != manager.getReshowDelay()) { + throw new Error("shared reshow delay"); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/swing/UIManager/Test6657026.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,59 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657026 + * @summary Tests shared UIManager in different application contexts + * @author Sergey Malenkov + */ + +import sun.awt.SunToolkit; + +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; + +public class Test6657026 implements Runnable { + + public static void main(String[] args) throws Exception { + if (UIManager.getInstalledLookAndFeels().length == 0) { + throw new Error("unexpected amount of look&feels"); + } + UIManager.setInstalledLookAndFeels(new LookAndFeelInfo[0]); + if (UIManager.getInstalledLookAndFeels().length != 0) { + throw new Error("unexpected amount of look&feels"); + } + + ThreadGroup group = new ThreadGroup("$$$"); + Thread thread = new Thread(group, new Test6657026()); + thread.start(); + thread.join(); + } + + public void run() { + SunToolkit.createNewAppContext(); + if (UIManager.getInstalledLookAndFeels().length == 0) { + throw new Error("shared look&feels"); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/swing/plaf/basic/BasicSplitPaneUI/Test6657026.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,82 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657026 + * @summary Tests shared BasicSplitPaneUI in different application contexts + * @author Sergey Malenkov + */ + +import sun.awt.SunToolkit; + +import java.awt.event.ActionEvent; +import java.util.Set; +import javax.swing.JSplitPane; +import javax.swing.plaf.basic.BasicSplitPaneUI; + +public class Test6657026 extends BasicSplitPaneUI implements Runnable { + + public static void main(String[] args) throws InterruptedException { + if (new JSplitPane().getFocusTraversalKeys(0).isEmpty()){ + throw new Error("unexpected traversal keys"); + } + new JSplitPane() { + public void setFocusTraversalKeys(int id, Set keystrokes) { + keystrokes.clear(); + super.setFocusTraversalKeys(id, keystrokes); + } + }; + if (new JSplitPane().getFocusTraversalKeys(0).isEmpty()) { + throw new Error("shared traversal keys"); + } + KEYBOARD_DIVIDER_MOVE_OFFSET = -KEYBOARD_DIVIDER_MOVE_OFFSET; + + ThreadGroup group = new ThreadGroup("$$$"); + Thread thread = new Thread(group, new Test6657026()); + thread.start(); + thread.join(); + } + + public void run() { + SunToolkit.createNewAppContext(); + if (new JSplitPane().getFocusTraversalKeys(0).isEmpty()) { + throw new Error("shared traversal keys"); + } + JSplitPane pane = new JSplitPane(); + pane.setUI(this); + + createFocusListener().focusGained(null); // allows actions + test(pane, "positiveIncrement", 3); + test(pane, "negativeIncrement", 0); + } + + private static void test(JSplitPane pane, String action, int expected) { + ActionEvent event = new ActionEvent(pane, expected, action); + pane.getActionMap().get(action).actionPerformed(event); + int actual = pane.getDividerLocation(); + if (actual != expected) { + throw new Error(actual + ", but expected " + expected); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/swing/plaf/metal/MetalBorders/Test6657026.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,91 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657026 + * @summary Tests constancy of borders + * @author Sergey Malenkov + */ + +import java.awt.Insets; +import javax.swing.border.Border; +import javax.swing.plaf.metal.MetalBorders.ButtonBorder; +import javax.swing.plaf.metal.MetalBorders.MenuBarBorder; +import javax.swing.plaf.metal.MetalBorders.MenuItemBorder; +import javax.swing.plaf.metal.MetalBorders.PopupMenuBorder; + +public class Test6657026 { + + private static final Insets NEGATIVE = new Insets(Integer.MIN_VALUE, + Integer.MIN_VALUE, + Integer.MIN_VALUE, + Integer.MIN_VALUE); + + public static void main(String[] args) { + new ButtonBorder() {{borderInsets = NEGATIVE;}}; + new MenuBarBorder() {{borderInsets = NEGATIVE;}}; + new MenuItemBorder() {{borderInsets = NEGATIVE;}}; + new PopupMenuBorder() {{borderInsets = NEGATIVE;}}; + + test(create("ButtonBorder")); + test(create("MenuBarBorder")); + test(create("MenuItemBorder")); + test(create("PopupMenuBorder")); + + test(create("Flush3DBorder")); + test(create("InternalFrameBorder")); + // NOT USED: test(create("FrameBorder")); + // NOT USED: test(create("DialogBorder")); + test(create("PaletteBorder")); + test(create("OptionDialogBorder")); + test(create("ScrollPaneBorder")); + } + + private static Border create(String name) { + try { + name = "javax.swing.plaf.metal.MetalBorders$" + name; + return (Border) Class.forName(name).newInstance(); + } + catch (Exception exception) { + throw new Error("unexpected exception", exception); + } + } + + private static void test(Border border) { + Insets actual = border.getBorderInsets(null); + if (NEGATIVE.equals(actual)) { + throw new Error("unexpected insets in " + border.getClass()); + } + Insets expected = (Insets) actual.clone(); + // modify + actual.top++; + actual.left++; + actual.right++; + actual.bottom++; + // validate + if (!expected.equals(border.getBorderInsets(null))) { + throw new Error("shared insets in " + border.getClass()); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/swing/plaf/metal/MetalBumps/Test6657026.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,238 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657026 + * @summary Tests shared MetalBumps in different application contexts + * @author Sergey Malenkov + */ + +import sun.awt.SunToolkit; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.image.BufferedImage; +import java.awt.image.ImageObserver; +import java.text.AttributedCharacterIterator; +import javax.swing.Icon; +import javax.swing.plaf.metal.MetalBorders.ToolBarBorder; + +public class Test6657026 extends ToolBarBorder implements Runnable { + + public static void main(String[] args) throws Exception { + new Test6657026().test(); + + ThreadGroup group = new ThreadGroup("$$$"); + Thread thread = new Thread(group, new Test6657026()); + thread.start(); + thread.join(); + } + + public void run() { + SunToolkit.createNewAppContext(); + test(); + } + + private void test() { + MyGraphics mg = new MyGraphics(); + Icon icon = bumps; + icon.paintIcon(mg.component, mg, 0, 0); + if (mg.image != null) { + boolean failed = true; + int value = mg.image.getRGB(0, 0); + for (int x = 0; x < mg.image.getWidth(); x++) { + for (int y = 0; y < mg.image.getHeight(); y++) { + int current = mg.image.getRGB(x, y); + if (current != value) { + mg.image.setRGB(x, y, value); + failed = false; + } + + } + } + if (failed) { + throw new Error("shared metal bumps"); + } + } + } + + private static class MyGraphics extends Graphics { + + private final Component component = new Component() {}; + private BufferedImage image; + + public Graphics create() { + return null; // TODO: check + } + + public void translate(int x, int y) { + // TODO: check + } + + public Color getColor() { + return null; // TODO: check + } + + public void setColor(Color color) { + // TODO: check + } + + public void setPaintMode() { + // TODO: check + } + + public void setXORMode(Color c1) { + // TODO: check + } + + public Font getFont() { + return null; // TODO: check + } + + public void setFont(Font font) { + // TODO: check + } + + public FontMetrics getFontMetrics(Font font) { + return null; // TODO: check + } + + public Rectangle getClipBounds() { + return null; // TODO: check + } + + public void clipRect(int x, int y, int width, int height) { + // TODO: check + } + + public void setClip(int x, int y, int width, int height) { + // TODO: check + } + + public Shape getClip() { + return null; // TODO: check + } + + public void setClip(Shape clip) { + // TODO: check + } + + public void copyArea(int x, int y, int width, int height, int dx, int dy) { + // TODO: check + } + + public void drawLine(int x1, int y1, int x2, int y2) { + // TODO: check + } + + public void fillRect(int x, int y, int width, int height) { + // TODO: check + } + + public void clearRect(int x, int y, int width, int height) { + // TODO: check + } + + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { + // TODO: check + } + + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { + // TODO: check + } + + public void drawOval(int x, int y, int width, int height) { + // TODO: check + } + + public void fillOval(int x, int y, int width, int height) { + // TODO: check + } + + public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + // TODO: check + } + + public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + // TODO: check + } + + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { + // TODO: check + } + + public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { + // TODO: check + } + + public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { + // TODO: check + } + + public void drawString(String str, int x, int y) { + // TODO: check + } + + public void drawString(AttributedCharacterIterator iterator, int x, int y) { + // TODO: check + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) { + return false; // TODO: check + } + + public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { + return false; // TODO: check + } + + public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { + return false; // TODO: check + } + + public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { + return false; // TODO: check + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) { + if (img instanceof BufferedImage) { + this.image = (BufferedImage) img; + } + return false; // TODO: check + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) { + return false; // TODO: check + } + + public void dispose() { + // TODO: check + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/swing/plaf/metal/MetalInternalFrameUI/Test6657026.java Thu Nov 12 23:04:42 2009 +0000 @@ -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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657026 + * @summary Tests shared MetalInternalFrameUI in different application contexts + * @author Sergey Malenkov + */ + +import sun.awt.SunToolkit; + +import javax.swing.JInternalFrame; +import javax.swing.JPanel; +import javax.swing.UIManager; +import javax.swing.plaf.metal.MetalInternalFrameUI; +import javax.swing.plaf.metal.MetalLookAndFeel; + +public class Test6657026 extends MetalInternalFrameUI implements Runnable { + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel(new MetalLookAndFeel()); + + ThreadGroup group = new ThreadGroup("$$$"); + Thread thread = new Thread(group, new Test6657026()); + thread.start(); + thread.join(); + + new JInternalFrame().setContentPane(new JPanel()); + } + + public Test6657026() { + super(null); + } + + public void run() { + SunToolkit.createNewAppContext(); + IS_PALETTE = JInternalFrame.CONTENT_PANE_PROPERTY; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/swing/plaf/metal/MetalSliderUI/Test6657026.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,67 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6657026 + * @summary Tests shared MetalSliderUI in different application contexts + * @author Sergey Malenkov + */ + +import sun.awt.SunToolkit; + +import javax.swing.JSlider; +import javax.swing.UIManager; +import javax.swing.plaf.metal.MetalLookAndFeel; +import javax.swing.plaf.metal.MetalSliderUI; + +public class Test6657026 extends MetalSliderUI implements Runnable { + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel(new MetalLookAndFeel()); + JSlider slider = new JSlider(); + test(slider); + + ThreadGroup group = new ThreadGroup("$$$"); + Thread thread = new Thread(group, new Test6657026()); + thread.start(); + thread.join(); + + test(slider); + } + + public void run() { + SunToolkit.createNewAppContext(); + JSlider slider = new JSlider(); + test(slider); + tickLength = -10000; + } + + private static void test(JSlider slider) { + MetalSliderUI ui = (MetalSliderUI) slider.getUI(); + int actual = ui.getTickLength(); + if (actual != 11) { + throw new Error(actual + ", but expected 11"); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/start-Xvfb.sh Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,87 @@ +#!/bin/sh -f +# +# 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. +# + +# +# Original Author: Tim Bell +# +usage() { + echo "Starts up an Xvfb dummy X server with fvwm2 window manager" + echo " usage:" + echo " ${0} display_number_file" + echo " display_number_file gets display number when it's ready" + exit + } +# +currentDir=`pwd` +rm -f $1 +DD=":$$" +DISPLAY=${DD} +export DISPLAY +cd /tmp +# +if [ ! -x "/usr/bin/X11/Xvfb" ]; then + # We have Solaris-flavored X windows, and the /usr/openwin Xvfb is + # a simple wrapper script around the Xsun server. Massage the + # arguments: server number must be first; others are slightly + # different. + # + # Also the default Visual Class (DirectColor) triggers an awt bug + # (probably 4131533/6505852) and some tests will loop endlessly + # when they hit the display. The workaround is: + # 1) Ask for PseudoColor instead. + # 2) Omit 32-bit depth. + /usr/bin/nohup /usr/openwin/bin/Xvfb ${DISPLAY} -dev vfb screen 0 1280x1024x24 pixdepths 8 16 24 defclass PseudoColor > ${currentDir}/nohup.$$ 2>&1 & +else + # Linux... + /usr/bin/nohup /usr/bin/X11/Xvfb -fbdir ${currentDir} -pixdepths 8 16 24 32 ${DISPLAY} > ${currentDir}/nohup.$$ 2>&1 & +fi +WM="/usr/bin/X11/fvwm2" +if [ ! -x ${WM} ] ; then + WM="/opt/sfw/bin/fvwm2" +fi +# +# Wait for Xvfb to initialize: +sleep 5 +# +if [ -x "${WM}" ]; then +# 2 JCK tests require a window manager +# mwm fails (key name errors) and twm fails (hangs), +# but fvwm2 works well. + /usr/bin/nohup ${WM} -display ${DISPLAY} -replace -f /dev/null > ${currentDir}/nohup.$$ 2>&1 & +else + echo "Error: ${WM} not found" + exit 1 +fi +# +# Wait some more to see if the xhost command gets through: +sleep 10 +# Allow access to all - this is a brute force approach, +# but I do not see how it could be a security problem... +DISPLAY="${DD}" xhost + +# +echo "Virtual frame buffer started on ${DISPLAY}" +echo "$$" > $1 +wait
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,442 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * + * @bug 6861062 + * @summary Disable MD2 support + * + * @run main/othervm CPBuilder trustAnchor_SHA1withRSA_1024 0 true + * @run main/othervm CPBuilder trustAnchor_SHA1withRSA_512 0 true + * @run main/othervm CPBuilder intermediate_SHA1withRSA_1024_1024 1 true + * @run main/othervm CPBuilder intermediate_SHA1withRSA_1024_512 1 true + * @run main/othervm CPBuilder intermediate_SHA1withRSA_512_1024 1 true + * @run main/othervm CPBuilder intermediate_SHA1withRSA_512_512 1 true + * @run main/othervm CPBuilder intermediate_MD2withRSA_1024_1024 1 false + * @run main/othervm CPBuilder intermediate_MD2withRSA_1024_512 1 false + * @run main/othervm CPBuilder endentiry_SHA1withRSA_1024_1024 2 true + * @run main/othervm CPBuilder endentiry_SHA1withRSA_1024_512 2 true + * @run main/othervm CPBuilder endentiry_SHA1withRSA_512_1024 2 true + * @run main/othervm CPBuilder endentiry_SHA1withRSA_512_512 2 true + * @run main/othervm CPBuilder endentiry_MD2withRSA_1024_1024 2 false + * @run main/othervm CPBuilder endentiry_MD2withRSA_1024_512 2 false + * + * @author Xuelei Fan + */ + +import java.io.*; +import java.net.SocketException; +import java.util.*; +import java.security.Security; +import java.security.cert.*; +import sun.security.util.DerInputStream; + +public class CPBuilder { + + // SHA1withRSA 1024 + static String trustAnchor_SHA1withRSA_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICPjCCAaegAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQC8UdC863pFk1Rvd7xUYd60+e9KsLhb6SqOfU42ZA715FcH\n" + + "E1TRvQPmYzAnHcO04TrWZQtO6E+E2RCmeBnetBvIMVka688QkO14wnrIrf2tRodd\n" + + "rZNZEBzkX+zyXCRo9tKEUDFf9Qze7Ilbb+Zzm9CUfu4M1Oz6iQcXRx7aM0jEAQID\n" + + "AQABo4GJMIGGMB0GA1UdDgQWBBTn0C+xmZY/BTab4W9gBp3dGa7WgjBHBgNVHSME\n" + + "QDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEwHzELMAkGA1UEBhMCVVMxEDAO\n" + + "BgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQw\n" + + "DQYJKoZIhvcNAQEFBQADgYEAiCXL2Yp4ruyRXAIJ8zBEaPC9oV2agqgbSbly2z8z\n" + + "Ik5SeSRysP+GHBpb8uNyANJnQKv+T0GrJiTLMBjKCOiJl6xzk3EZ2wbQB6G/SQ9+\n" + + "UWcsXSC8oGSEPpkj5In/9/UbuUIfT9H8jmdyLNKQvlqgq6kyfnskME7ptGgT95Hc\n" + + "tas=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 + static String trustAnchor_SHA1withRSA_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIBuTCCAWOgAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMFwwDQYJKoZIhvcNAQEB\n" + + "BQADSwAwSAJBAM0Kn4ieCdCHsrm78ZMMN4jQEEEqACAMKB7O8j9g4gfz2oAfmHwv\n" + + "7JH/hZ0Xen1zUmBbwe+e2J5D/4Fisp9Bn98CAwEAAaOBiTCBhjAdBgNVHQ4EFgQU\n" + + "g4Kwd47hdNQBp8grZsRJ5XvhvxAwRwYDVR0jBEAwPoAUg4Kwd47hdNQBp8grZsRJ\n" + + "5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlggEAMA8G\n" + + "A1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0GCSqGSIb3DQEBBQUAA0EAn77b\n" + + "FJx+HvyRvjZYCzMjnUct3Ql4iLOkURYDh93J5TXi/l9ajvAMEuwzYj0qZ+Ktm/ia\n" + + "U5r+8B9nzx+j2Zh3kw==\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 1024 + static String intermediate_SHA1withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICUDCCAbmgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDhaFw0yOTA0MjMwMTExNDha\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADgYEAHze3wAcIe84zNOoN\n" + + "P8l9EmlVVoU30z3LB3hxq3m/dC/4gE5Z9Z8EG1wJw4qaxlTZ4dif12nbTTdofVhb\n" + + "Bd4syjo6fcUA4q7sfg9TFpoHQ+Ap7PgjK99moMKdMy50Xy8s6FPvaVkF89s66Z6y\n" + + "e4q7TSwe6QevGOZaL5N/iy2XGEs=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 512 + static String intermediate_SHA1withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDzCCAbmgAwIBAgIBAzANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADQQCYNmdkONfuk07XjRze\n" + + "WQyq2cfdae4uIdyUfa2rpgYMtSXuQW3/XrQGiz4G6WBXA2wo7folOOpAKYgvHPrm\n" + + "w6Dd\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 1024 + static String intermediate_SHA1withRSA_512_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDDCCAXWgAwIBAgIBBDANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV\n" + + "lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA\n" + + "AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw\n" + + "PoAU59AvsZmWPwU2m+FvYAad3Rmu1oKhI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + + "VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAE2VOlw5ySLT3gUzKCYEga4QPaSrf6lHHPi2g48LscEY\n" + + "h9qQXh4nuIVugReBIEf6N49RdT+M2cgRJo4sZ3ukYLGQzxNuttL5nPSuuvrAR1oG\n" + + "LUyzOWcUpKHbVHi6zlTt79RvTKZvLcduLutmtPtLJcM9PdiAI1wEooSgxTwZtB/Z\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 512 + static String intermediate_SHA1withRSA_512_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIByzCCAXWgAwIBAgIBBTANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV\n" + + "lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA\n" + + "AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw\n" + + "PoAUg4Kwd47hdNQBp8grZsRJ5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + + "VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G\n" + + "CSqGSIb3DQEBBQUAA0EAoCf0Zu559qcB4xPpzqkVsYiyW49S4Yc0mmQXb1yoQgLx\n" + + "O+DCkjG5d14+t1MsnkhB2izoQUMxQ3vDc1YnA/tEpw==\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 1024 + static String intermediate_MD2withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICUDCCAbmgAwIBAgIBBjANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADgYEAPtEjwbWuC5kc4DPc\n" + + "Ttf/wdbD8ZCdAWzcc3XF9q1TlvwVMNk6mbfM05y6ZVsztKTkwZ4EcvFu/yIqw1EB\n" + + "E1zlXQCaWXT3/ZMbqYZV4+mx+RUl8spUCb1tda25jnTg3mTOzB1iztm4gy903EMd\n" + + "m8omKDKeCgcw5dR4ITQYvyxe1as=\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 512 + static String intermediate_MD2withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDzCCAbmgAwIBAgIBBzANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADQQBHok1v6xymtpB7N9xy\n" + + "0OmDT27uhmzlP0eOzJvXVxj3Oi9TLQJgCUJ9122MzfRAs1E1uJTtvuu+UmI80NQx\n" + + "KQdp\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 1024 + static String endentiry_SHA1withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICNzCCAaCgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTBaFw0yOTA0MjMwMTExNTBaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBTfWD9mRTppcUAlUqGuu/R5t8CB5jANBgkqhkiG\n" + + "9w0BAQUFAAOBgQAOfIeasDg91CR3jGfuAEVKwncM1OPFmniAUcdPm74cCAyJ90Me\n" + + "dhUElWPGoAuXGfiyZlOlGUYWqEroe/dnkmnotJjLWR+MA4ZyX3O1YI8T4W3deWcC\n" + + "J4WMCF7mp17SaYYKX9F0AxwNJFpUkbB41IkTxPr0MmzB1871/pbY8dLAvA==\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 512 + static String endentiry_SHA1withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB9jCCAaCgAwIBAgIBAzANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTBaFw0yOTA0MjMwMTExNTBaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBQ3QIeJNg+2PK+k/ZrrLqaGxnpTjTANBgkqhkiG\n" + + "9w0BAQUFAANBADV6X+ea0ftEKXy7yKNAbdIp35893T6AVwbdclomPkeOs86OtoTG\n" + + "1BIzWSK9QE7W6Wbf63e2RdcqoLK+DxsuwUg=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 1024 + static String endentiry_SHA1withRSA_512_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB8zCCAVygAwIBAgIBBDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTBcMA0GCSqGSIb3\n" + + "DQEBAQUAA0sAMEgCQQCpfQzhld7w2JhW/aRaLkmrLrc/QAsQE+J4DXioXaajsWPo\n" + + "uMmYmuiQolb6OIY/LcivSubKM3G5PkAWoovUPIWLAgMBAAGjTzBNMAsGA1UdDwQE\n" + + "AwID6DAdBgNVHQ4EFgQUFWuXLkf4Ji57H9ISycgWi982TUIwHwYDVR0jBBgwFoAU\n" + + "31g/ZkU6aXFAJVKhrrv0ebfAgeYwDQYJKoZIhvcNAQEFBQADgYEAUyW8PrEdbzLu\n" + + "B+h6UemBOJ024rYq90hJE/5wUEKPvxZ9vPEUgl+io6cGhL3cLfxfh6z5xtEGp4Tb\n" + + "NB0Ye3Qi01FBiNDY8s3rQRrmel6VysU8u+0Oi2jmQY6vZXn/zXN5rrTLITCaSicG\n" + + "dOMv1xLM83Ee432WWlDwKOUxhzDGpWc=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 512 + static String endentiry_SHA1withRSA_512_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIBsjCCAVygAwIBAgIBBTANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTBcMA0GCSqGSIb3\n" + + "DQEBAQUAA0sAMEgCQQCpfQzhld7w2JhW/aRaLkmrLrc/QAsQE+J4DXioXaajsWPo\n" + + "uMmYmuiQolb6OIY/LcivSubKM3G5PkAWoovUPIWLAgMBAAGjTzBNMAsGA1UdDwQE\n" + + "AwID6DAdBgNVHQ4EFgQUFWuXLkf4Ji57H9ISycgWi982TUIwHwYDVR0jBBgwFoAU\n" + + "N0CHiTYPtjyvpP2a6y6mhsZ6U40wDQYJKoZIhvcNAQEFBQADQQBG4grtrVEHick0\n" + + "z/6Lcl/MGyHT0c8KTXE0AMVXG1NRjAicAmYno/yDaJ9OmfymObKZKV9fF7yCW/N/\n" + + "TMU6m7N0\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 1024 + static String endentiry_MD2withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICNzCCAaCgAwIBAgIBBjANBgkqhkiG9w0BAQIFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBTfWD9mRTppcUAlUqGuu/R5t8CB5jANBgkqhkiG\n" + + "9w0BAQIFAAOBgQBxKsFf8NNQcXjDoKJJSG4Rk6ikcrhiGYuUI32+XHvs6hnav1Zc\n" + + "aJUpy7J4gMj/MnysMh/4AF9+m6zEEjuisXKUbYZhgtJxz+ukGSo163mJ8QJiAlRb\n" + + "Iwsy81r08mlSCR6jx2YhDAUxJIPC92R5Vb4CEutB7tWTwwz7vIHq330erA==\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 512 + static String endentiry_MD2withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB9jCCAaCgAwIBAgIBBzANBgkqhkiG9w0BAQIFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBQ3QIeJNg+2PK+k/ZrrLqaGxnpTjTANBgkqhkiG\n" + + "9w0BAQIFAANBAIX63Ypi9P71RnC/pcMbhD+wekRFsTzU593X3MC7tyBJtEXwvAZG\n" + + "iMxXF5A+ohlr7/CrkV7ZTL8PLxnJdY5Y8rQ=\n" + + "-----END CERTIFICATE-----"; + + static HashMap<String, String> certmap = new HashMap<String, String>(); + static { + certmap.put("trustAnchor_SHA1withRSA_1024", + trustAnchor_SHA1withRSA_1024); + certmap.put("trustAnchor_SHA1withRSA_512", + trustAnchor_SHA1withRSA_512); + certmap.put("intermediate_SHA1withRSA_1024_1024", + intermediate_SHA1withRSA_1024_1024); + certmap.put("intermediate_SHA1withRSA_1024_512", + intermediate_SHA1withRSA_1024_512); + certmap.put("intermediate_SHA1withRSA_512_1024", + intermediate_SHA1withRSA_512_1024); + certmap.put("intermediate_SHA1withRSA_512_512", + intermediate_SHA1withRSA_512_512); + certmap.put("intermediate_MD2withRSA_1024_1024", + intermediate_MD2withRSA_1024_1024); + certmap.put("intermediate_MD2withRSA_1024_512", + intermediate_MD2withRSA_1024_512); + certmap.put("endentiry_SHA1withRSA_1024_1024", + endentiry_SHA1withRSA_1024_1024); + certmap.put("endentiry_SHA1withRSA_1024_512", + endentiry_SHA1withRSA_1024_512); + certmap.put("endentiry_SHA1withRSA_512_1024", + endentiry_SHA1withRSA_512_1024); + certmap.put("endentiry_SHA1withRSA_512_512", + endentiry_SHA1withRSA_512_512); + certmap.put("endentiry_MD2withRSA_1024_1024", + endentiry_MD2withRSA_1024_1024); + certmap.put("endentiry_MD2withRSA_1024_512", + endentiry_MD2withRSA_1024_512); + } + + private static Set<TrustAnchor> generateTrustAnchors() + throws CertificateException { + // generate certificate from cert string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + HashSet<TrustAnchor> anchors = new HashSet<TrustAnchor>(); + + ByteArrayInputStream is = + new ByteArrayInputStream(trustAnchor_SHA1withRSA_1024.getBytes()); + Certificate cert = cf.generateCertificate(is); + TrustAnchor anchor = new TrustAnchor((X509Certificate)cert, null); + anchors.add(anchor); + + is = new ByteArrayInputStream(trustAnchor_SHA1withRSA_512.getBytes()); + cert = cf.generateCertificate(is); + anchor = new TrustAnchor((X509Certificate)cert, null); + anchors.add(anchor); + + return anchors; + } + + private static CertStore generateCertificateStore() throws Exception { + Collection entries = new HashSet(); + + // generate certificate from certificate string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + for (String key : certmap.keySet()) { + String certStr = certmap.get(key); + ByteArrayInputStream is = + new ByteArrayInputStream(certStr.getBytes());; + Certificate cert = cf.generateCertificate(is); + entries.add(cert); + } + + return CertStore.getInstance("Collection", + new CollectionCertStoreParameters(entries)); + } + + private static X509CertSelector generateSelector(String name) + throws Exception { + X509CertSelector selector = new X509CertSelector(); + + String certStr = certmap.get(name); + if (certStr == null) { + return null; + } + + // generate certificate from certificate string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + ByteArrayInputStream is = new ByteArrayInputStream(certStr.getBytes()); + X509Certificate target = (X509Certificate)cf.generateCertificate(is); + + selector.setCertificate(target); + + return selector; + } + + private static boolean match(String name, Certificate cert) + throws Exception { + X509CertSelector selector = new X509CertSelector(); + + String certStr = certmap.get(name); + if (certStr == null) { + return false; + } + + // generate certificate from certificate string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + ByteArrayInputStream is = new ByteArrayInputStream(certStr.getBytes()); + X509Certificate target = (X509Certificate)cf.generateCertificate(is); + + return target.equals(cert); + } + + public static void main(String args[]) throws Exception { + + CertPathBuilder builder = CertPathBuilder.getInstance("PKIX"); + + X509CertSelector selector = generateSelector(args[0]); + if (selector == null) { + // no target certificate, ignore it + return; + } + + Set<TrustAnchor> anchors = generateTrustAnchors(); + CertStore certs = generateCertificateStore(); + + PKIXBuilderParameters params = + new PKIXBuilderParameters(anchors, selector); + params.addCertStore(certs); + params.setRevocationEnabled(false); + params.setDate(new Date(109, 9, 1)); // 2009-09-01 + + boolean success = Boolean.valueOf(args[2]); + try { + PKIXCertPathBuilderResult result = + (PKIXCertPathBuilderResult)builder.build(params); + if (!success) { + throw new Exception("expected algorithm disabled exception"); + } + + int length = Integer.parseInt(args[1]); + List<? extends Certificate> path = + result.getCertPath().getCertificates(); + if (length != path.size()) { + throw new Exception("unexpected certification path length"); + } + + if (!path.isEmpty()) { // the target is not a trust anchor + if (!match(args[0], path.get(0))) { + throw new Exception("unexpected certificate"); + } + } + } catch (CertPathBuilderException cpbe) { + if (success) { + throw new Exception("unexpected exception"); + } else { + System.out.println("Get the expected exception " + cpbe); + } + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorEndEntity.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,363 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * + * @bug 6861062 + * @summary Disable MD2 support + * + * @author Xuelei Fan + */ + +import java.io.*; +import java.net.SocketException; +import java.util.*; +import java.security.Security; +import java.security.cert.*; + +public class CPValidatorEndEntity { + + // SHA1withRSA 1024 + static String trustAnchor_SHA1withRSA_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICPjCCAaegAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQC8UdC863pFk1Rvd7xUYd60+e9KsLhb6SqOfU42ZA715FcH\n" + + "E1TRvQPmYzAnHcO04TrWZQtO6E+E2RCmeBnetBvIMVka688QkO14wnrIrf2tRodd\n" + + "rZNZEBzkX+zyXCRo9tKEUDFf9Qze7Ilbb+Zzm9CUfu4M1Oz6iQcXRx7aM0jEAQID\n" + + "AQABo4GJMIGGMB0GA1UdDgQWBBTn0C+xmZY/BTab4W9gBp3dGa7WgjBHBgNVHSME\n" + + "QDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEwHzELMAkGA1UEBhMCVVMxEDAO\n" + + "BgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQw\n" + + "DQYJKoZIhvcNAQEFBQADgYEAiCXL2Yp4ruyRXAIJ8zBEaPC9oV2agqgbSbly2z8z\n" + + "Ik5SeSRysP+GHBpb8uNyANJnQKv+T0GrJiTLMBjKCOiJl6xzk3EZ2wbQB6G/SQ9+\n" + + "UWcsXSC8oGSEPpkj5In/9/UbuUIfT9H8jmdyLNKQvlqgq6kyfnskME7ptGgT95Hc\n" + + "tas=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 + static String trustAnchor_SHA1withRSA_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIBuTCCAWOgAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMFwwDQYJKoZIhvcNAQEB\n" + + "BQADSwAwSAJBAM0Kn4ieCdCHsrm78ZMMN4jQEEEqACAMKB7O8j9g4gfz2oAfmHwv\n" + + "7JH/hZ0Xen1zUmBbwe+e2J5D/4Fisp9Bn98CAwEAAaOBiTCBhjAdBgNVHQ4EFgQU\n" + + "g4Kwd47hdNQBp8grZsRJ5XvhvxAwRwYDVR0jBEAwPoAUg4Kwd47hdNQBp8grZsRJ\n" + + "5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlggEAMA8G\n" + + "A1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0GCSqGSIb3DQEBBQUAA0EAn77b\n" + + "FJx+HvyRvjZYCzMjnUct3Ql4iLOkURYDh93J5TXi/l9ajvAMEuwzYj0qZ+Ktm/ia\n" + + "U5r+8B9nzx+j2Zh3kw==\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 1024 + static String intermediate_SHA1withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICUDCCAbmgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDhaFw0yOTA0MjMwMTExNDha\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADgYEAHze3wAcIe84zNOoN\n" + + "P8l9EmlVVoU30z3LB3hxq3m/dC/4gE5Z9Z8EG1wJw4qaxlTZ4dif12nbTTdofVhb\n" + + "Bd4syjo6fcUA4q7sfg9TFpoHQ+Ap7PgjK99moMKdMy50Xy8s6FPvaVkF89s66Z6y\n" + + "e4q7TSwe6QevGOZaL5N/iy2XGEs=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 512 + static String intermediate_SHA1withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDzCCAbmgAwIBAgIBAzANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADQQCYNmdkONfuk07XjRze\n" + + "WQyq2cfdae4uIdyUfa2rpgYMtSXuQW3/XrQGiz4G6WBXA2wo7folOOpAKYgvHPrm\n" + + "w6Dd\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 1024 + static String intermediate_SHA1withRSA_512_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDDCCAXWgAwIBAgIBBDANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV\n" + + "lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA\n" + + "AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw\n" + + "PoAU59AvsZmWPwU2m+FvYAad3Rmu1oKhI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + + "VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAE2VOlw5ySLT3gUzKCYEga4QPaSrf6lHHPi2g48LscEY\n" + + "h9qQXh4nuIVugReBIEf6N49RdT+M2cgRJo4sZ3ukYLGQzxNuttL5nPSuuvrAR1oG\n" + + "LUyzOWcUpKHbVHi6zlTt79RvTKZvLcduLutmtPtLJcM9PdiAI1wEooSgxTwZtB/Z\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 512 + static String intermediate_SHA1withRSA_512_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIByzCCAXWgAwIBAgIBBTANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV\n" + + "lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA\n" + + "AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw\n" + + "PoAUg4Kwd47hdNQBp8grZsRJ5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + + "VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G\n" + + "CSqGSIb3DQEBBQUAA0EAoCf0Zu559qcB4xPpzqkVsYiyW49S4Yc0mmQXb1yoQgLx\n" + + "O+DCkjG5d14+t1MsnkhB2izoQUMxQ3vDc1YnA/tEpw==\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 1024 + static String intermediate_MD2withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICUDCCAbmgAwIBAgIBBjANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADgYEAPtEjwbWuC5kc4DPc\n" + + "Ttf/wdbD8ZCdAWzcc3XF9q1TlvwVMNk6mbfM05y6ZVsztKTkwZ4EcvFu/yIqw1EB\n" + + "E1zlXQCaWXT3/ZMbqYZV4+mx+RUl8spUCb1tda25jnTg3mTOzB1iztm4gy903EMd\n" + + "m8omKDKeCgcw5dR4ITQYvyxe1as=\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 512 + static String intermediate_MD2withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDzCCAbmgAwIBAgIBBzANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADQQBHok1v6xymtpB7N9xy\n" + + "0OmDT27uhmzlP0eOzJvXVxj3Oi9TLQJgCUJ9122MzfRAs1E1uJTtvuu+UmI80NQx\n" + + "KQdp\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 1024 + static String endentiry_SHA1withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICNzCCAaCgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTBaFw0yOTA0MjMwMTExNTBaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBTfWD9mRTppcUAlUqGuu/R5t8CB5jANBgkqhkiG\n" + + "9w0BAQUFAAOBgQAOfIeasDg91CR3jGfuAEVKwncM1OPFmniAUcdPm74cCAyJ90Me\n" + + "dhUElWPGoAuXGfiyZlOlGUYWqEroe/dnkmnotJjLWR+MA4ZyX3O1YI8T4W3deWcC\n" + + "J4WMCF7mp17SaYYKX9F0AxwNJFpUkbB41IkTxPr0MmzB1871/pbY8dLAvA==\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 512 + static String endentiry_SHA1withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB9jCCAaCgAwIBAgIBAzANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTBaFw0yOTA0MjMwMTExNTBaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBQ3QIeJNg+2PK+k/ZrrLqaGxnpTjTANBgkqhkiG\n" + + "9w0BAQUFAANBADV6X+ea0ftEKXy7yKNAbdIp35893T6AVwbdclomPkeOs86OtoTG\n" + + "1BIzWSK9QE7W6Wbf63e2RdcqoLK+DxsuwUg=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 1024 + static String endentiry_SHA1withRSA_512_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB8zCCAVygAwIBAgIBBDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTBcMA0GCSqGSIb3\n" + + "DQEBAQUAA0sAMEgCQQCpfQzhld7w2JhW/aRaLkmrLrc/QAsQE+J4DXioXaajsWPo\n" + + "uMmYmuiQolb6OIY/LcivSubKM3G5PkAWoovUPIWLAgMBAAGjTzBNMAsGA1UdDwQE\n" + + "AwID6DAdBgNVHQ4EFgQUFWuXLkf4Ji57H9ISycgWi982TUIwHwYDVR0jBBgwFoAU\n" + + "31g/ZkU6aXFAJVKhrrv0ebfAgeYwDQYJKoZIhvcNAQEFBQADgYEAUyW8PrEdbzLu\n" + + "B+h6UemBOJ024rYq90hJE/5wUEKPvxZ9vPEUgl+io6cGhL3cLfxfh6z5xtEGp4Tb\n" + + "NB0Ye3Qi01FBiNDY8s3rQRrmel6VysU8u+0Oi2jmQY6vZXn/zXN5rrTLITCaSicG\n" + + "dOMv1xLM83Ee432WWlDwKOUxhzDGpWc=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 512 + static String endentiry_SHA1withRSA_512_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIBsjCCAVygAwIBAgIBBTANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTBcMA0GCSqGSIb3\n" + + "DQEBAQUAA0sAMEgCQQCpfQzhld7w2JhW/aRaLkmrLrc/QAsQE+J4DXioXaajsWPo\n" + + "uMmYmuiQolb6OIY/LcivSubKM3G5PkAWoovUPIWLAgMBAAGjTzBNMAsGA1UdDwQE\n" + + "AwID6DAdBgNVHQ4EFgQUFWuXLkf4Ji57H9ISycgWi982TUIwHwYDVR0jBBgwFoAU\n" + + "N0CHiTYPtjyvpP2a6y6mhsZ6U40wDQYJKoZIhvcNAQEFBQADQQBG4grtrVEHick0\n" + + "z/6Lcl/MGyHT0c8KTXE0AMVXG1NRjAicAmYno/yDaJ9OmfymObKZKV9fF7yCW/N/\n" + + "TMU6m7N0\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 1024 + static String endentiry_MD2withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICNzCCAaCgAwIBAgIBBjANBgkqhkiG9w0BAQIFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBTfWD9mRTppcUAlUqGuu/R5t8CB5jANBgkqhkiG\n" + + "9w0BAQIFAAOBgQBxKsFf8NNQcXjDoKJJSG4Rk6ikcrhiGYuUI32+XHvs6hnav1Zc\n" + + "aJUpy7J4gMj/MnysMh/4AF9+m6zEEjuisXKUbYZhgtJxz+ukGSo163mJ8QJiAlRb\n" + + "Iwsy81r08mlSCR6jx2YhDAUxJIPC92R5Vb4CEutB7tWTwwz7vIHq330erA==\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 512 + static String endentiry_MD2withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB9jCCAaCgAwIBAgIBBzANBgkqhkiG9w0BAQIFADAxMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx\n" + + "NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt\n" + + "cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG\n" + + "9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt\n" + + "vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v\n" + + "z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6\n" + + "c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07\n" + + "OorBleV92TAfBgNVHSMEGDAWgBQ3QIeJNg+2PK+k/ZrrLqaGxnpTjTANBgkqhkiG\n" + + "9w0BAQIFAANBAIX63Ypi9P71RnC/pcMbhD+wekRFsTzU593X3MC7tyBJtEXwvAZG\n" + + "iMxXF5A+ohlr7/CrkV7ZTL8PLxnJdY5Y8rQ=\n" + + "-----END CERTIFICATE-----"; + + private static CertPath generateCertificatePath(String castr, + String eestr) throws CertificateException { + // generate certificate from cert strings + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + ByteArrayInputStream is; + + is = new ByteArrayInputStream(castr.getBytes()); + Certificate cacert = cf.generateCertificate(is); + + is = new ByteArrayInputStream(eestr.getBytes()); + Certificate eecert = cf.generateCertificate(is); + + // generate certification path + List<Certificate> list = Arrays.asList(new Certificate[] { + eecert, cacert}); + + return cf.generateCertPath(list); + } + + private static Set<TrustAnchor> generateTrustAnchors() + throws CertificateException { + // generate certificate from cert string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + HashSet<TrustAnchor> anchors = new HashSet<TrustAnchor>(); + + ByteArrayInputStream is = + new ByteArrayInputStream(trustAnchor_SHA1withRSA_1024.getBytes()); + Certificate cert = cf.generateCertificate(is); + TrustAnchor anchor = new TrustAnchor((X509Certificate)cert, null); + anchors.add(anchor); + + is = new ByteArrayInputStream(trustAnchor_SHA1withRSA_512.getBytes()); + cert = cf.generateCertificate(is); + anchor = new TrustAnchor((X509Certificate)cert, null); + anchors.add(anchor); + + return anchors; + } + + public static void main(String args[]) throws Exception { + try { + validate(endentiry_SHA1withRSA_1024_1024, + intermediate_SHA1withRSA_1024_1024); + validate(endentiry_SHA1withRSA_1024_512, + intermediate_SHA1withRSA_512_1024); + validate(endentiry_SHA1withRSA_512_1024, + intermediate_SHA1withRSA_1024_1024); + validate(endentiry_SHA1withRSA_512_512, + intermediate_SHA1withRSA_512_1024); + } catch (CertPathValidatorException cpve) { + throw new Exception( + "unexpect exception, it is valid cert", cpve); + } + + try { + validate(endentiry_MD2withRSA_1024_1024, + intermediate_SHA1withRSA_1024_1024); + throw new Exception("expected algorithm disabled exception"); + } catch (CertPathValidatorException cpve) { + System.out.println("Get the expected exception " + cpve); + } + + try { + validate(endentiry_MD2withRSA_1024_512, + intermediate_SHA1withRSA_512_1024); + throw new Exception("expected algorithm disabled exception"); + } catch (CertPathValidatorException cpve) { + System.out.println("Get the expected exception " + cpve); + } + } + + private static void validate(String eecert, String cacert) + throws CertPathValidatorException, Exception { + + CertPath path = generateCertificatePath(cacert, eecert); + Set<TrustAnchor> anchors = generateTrustAnchors(); + + PKIXParameters params = new PKIXParameters(anchors); + + // disable certificate revocation checking + params.setRevocationEnabled(false); + + // set the validation time + params.setDate(new Date(109, 9, 1)); // 2009-09-01 + + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + + validator.validate(path, params); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorIntermediate.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,256 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * + * @bug 6861062 + * @summary Disable MD2 support + * + * @author Xuelei Fan + */ + +import java.io.*; +import java.net.SocketException; +import java.util.*; +import java.security.Security; +import java.security.cert.*; + +public class CPValidatorIntermediate { + + // SHA1withRSA 1024 + static String trustAnchor_SHA1withRSA_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICPjCCAaegAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQC8UdC863pFk1Rvd7xUYd60+e9KsLhb6SqOfU42ZA715FcH\n" + + "E1TRvQPmYzAnHcO04TrWZQtO6E+E2RCmeBnetBvIMVka688QkO14wnrIrf2tRodd\n" + + "rZNZEBzkX+zyXCRo9tKEUDFf9Qze7Ilbb+Zzm9CUfu4M1Oz6iQcXRx7aM0jEAQID\n" + + "AQABo4GJMIGGMB0GA1UdDgQWBBTn0C+xmZY/BTab4W9gBp3dGa7WgjBHBgNVHSME\n" + + "QDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEwHzELMAkGA1UEBhMCVVMxEDAO\n" + + "BgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQw\n" + + "DQYJKoZIhvcNAQEFBQADgYEAiCXL2Yp4ruyRXAIJ8zBEaPC9oV2agqgbSbly2z8z\n" + + "Ik5SeSRysP+GHBpb8uNyANJnQKv+T0GrJiTLMBjKCOiJl6xzk3EZ2wbQB6G/SQ9+\n" + + "UWcsXSC8oGSEPpkj5In/9/UbuUIfT9H8jmdyLNKQvlqgq6kyfnskME7ptGgT95Hc\n" + + "tas=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 + static String trustAnchor_SHA1withRSA_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIBuTCCAWOgAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMFwwDQYJKoZIhvcNAQEB\n" + + "BQADSwAwSAJBAM0Kn4ieCdCHsrm78ZMMN4jQEEEqACAMKB7O8j9g4gfz2oAfmHwv\n" + + "7JH/hZ0Xen1zUmBbwe+e2J5D/4Fisp9Bn98CAwEAAaOBiTCBhjAdBgNVHQ4EFgQU\n" + + "g4Kwd47hdNQBp8grZsRJ5XvhvxAwRwYDVR0jBEAwPoAUg4Kwd47hdNQBp8grZsRJ\n" + + "5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlggEAMA8G\n" + + "A1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0GCSqGSIb3DQEBBQUAA0EAn77b\n" + + "FJx+HvyRvjZYCzMjnUct3Ql4iLOkURYDh93J5TXi/l9ajvAMEuwzYj0qZ+Ktm/ia\n" + + "U5r+8B9nzx+j2Zh3kw==\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 1024 + static String intermediate_SHA1withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICUDCCAbmgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDhaFw0yOTA0MjMwMTExNDha\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADgYEAHze3wAcIe84zNOoN\n" + + "P8l9EmlVVoU30z3LB3hxq3m/dC/4gE5Z9Z8EG1wJw4qaxlTZ4dif12nbTTdofVhb\n" + + "Bd4syjo6fcUA4q7sfg9TFpoHQ+Ap7PgjK99moMKdMy50Xy8s6FPvaVkF89s66Z6y\n" + + "e4q7TSwe6QevGOZaL5N/iy2XGEs=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 1024 signed with RSA 512 + static String intermediate_SHA1withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDzCCAbmgAwIBAgIBAzANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADQQCYNmdkONfuk07XjRze\n" + + "WQyq2cfdae4uIdyUfa2rpgYMtSXuQW3/XrQGiz4G6WBXA2wo7folOOpAKYgvHPrm\n" + + "w6Dd\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 1024 + static String intermediate_SHA1withRSA_512_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDDCCAXWgAwIBAgIBBDANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV\n" + + "lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA\n" + + "AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw\n" + + "PoAU59AvsZmWPwU2m+FvYAad3Rmu1oKhI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + + "VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAE2VOlw5ySLT3gUzKCYEga4QPaSrf6lHHPi2g48LscEY\n" + + "h9qQXh4nuIVugReBIEf6N49RdT+M2cgRJo4sZ3ukYLGQzxNuttL5nPSuuvrAR1oG\n" + + "LUyzOWcUpKHbVHi6zlTt79RvTKZvLcduLutmtPtLJcM9PdiAI1wEooSgxTwZtB/Z\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 signed with RSA 512 + static String intermediate_SHA1withRSA_512_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIByzCCAXWgAwIBAgIBBTANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV\n" + + "lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA\n" + + "AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw\n" + + "PoAUg4Kwd47hdNQBp8grZsRJ5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" + + "VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G\n" + + "CSqGSIb3DQEBBQUAA0EAoCf0Zu559qcB4xPpzqkVsYiyW49S4Yc0mmQXb1yoQgLx\n" + + "O+DCkjG5d14+t1MsnkhB2izoQUMxQ3vDc1YnA/tEpw==\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 1024 + static String intermediate_MD2withRSA_1024_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICUDCCAbmgAwIBAgIBBjANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADgYEAPtEjwbWuC5kc4DPc\n" + + "Ttf/wdbD8ZCdAWzcc3XF9q1TlvwVMNk6mbfM05y6ZVsztKTkwZ4EcvFu/yIqw1EB\n" + + "E1zlXQCaWXT3/ZMbqYZV4+mx+RUl8spUCb1tda25jnTg3mTOzB1iztm4gy903EMd\n" + + "m8omKDKeCgcw5dR4ITQYvyxe1as=\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 1024 signed with RSA 512 + static String intermediate_MD2withRSA_1024_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICDzCCAbmgAwIBAgIBBzANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla\n" + + "MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz\n" + + "cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8\n" + + "BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg\n" + + "bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82\n" + + "AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl\n" + + "UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw\n" + + "HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw\n" + + "AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADQQBHok1v6xymtpB7N9xy\n" + + "0OmDT27uhmzlP0eOzJvXVxj3Oi9TLQJgCUJ9122MzfRAs1E1uJTtvuu+UmI80NQx\n" + + "KQdp\n" + + "-----END CERTIFICATE-----"; + + private static CertPath generateCertificatePath(String certStr) + throws CertificateException { + // generate certificate from cert strings + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + ByteArrayInputStream is; + + is = new ByteArrayInputStream(certStr.getBytes()); + Certificate cert = cf.generateCertificate(is); + + // generate certification path + List<Certificate> list = Arrays.asList(new Certificate[] {cert}); + + return cf.generateCertPath(list); + } + + private static Set<TrustAnchor> generateTrustAnchors() + throws CertificateException { + // generate certificate from cert string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + HashSet<TrustAnchor> anchors = new HashSet<TrustAnchor>(); + + ByteArrayInputStream is = + new ByteArrayInputStream(trustAnchor_SHA1withRSA_1024.getBytes()); + Certificate cert = cf.generateCertificate(is); + TrustAnchor anchor = new TrustAnchor((X509Certificate)cert, null); + anchors.add(anchor); + + is = new ByteArrayInputStream(trustAnchor_SHA1withRSA_512.getBytes()); + cert = cf.generateCertificate(is); + anchor = new TrustAnchor((X509Certificate)cert, null); + anchors.add(anchor); + + return anchors; + } + + public static void main(String args[]) throws Exception { + try { + validate(intermediate_SHA1withRSA_1024_1024); + validate(intermediate_SHA1withRSA_1024_512); + validate(intermediate_SHA1withRSA_512_1024); + validate(intermediate_SHA1withRSA_512_512); + } catch (CertPathValidatorException cpve) { + throw new Exception( + "unexpect exception, it is valid cert", cpve); + } + + try { + validate(intermediate_MD2withRSA_1024_1024); + throw new Exception("expected algorithm disabled exception"); + } catch (CertPathValidatorException cpve) { + System.out.println("Get the expected exception " + cpve); + } + + try { + validate(intermediate_MD2withRSA_1024_512); + throw new Exception("expected algorithm disabled exception"); + } catch (CertPathValidatorException cpve) { + System.out.println("Get the expected exception " + cpve); + } + } + + private static void validate(String intermediate) + throws CertPathValidatorException, Exception { + + CertPath path = generateCertificatePath(intermediate); + Set<TrustAnchor> anchors = generateTrustAnchors(); + + PKIXParameters params = new PKIXParameters(anchors); + + // disable certificate revocation checking + params.setRevocationEnabled(false); + + // set the validation time + params.setDate(new Date(109, 9, 1)); // 2009-09-01 + + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + + validator.validate(path, params); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,169 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * + * @bug 6861062 + * @summary Disable MD2 support + * + * @author Xuelei Fan + */ + +import java.io.*; +import java.net.SocketException; +import java.util.*; +import java.security.Security; +import java.security.cert.*; + +public class CPValidatorTrustAnchor { + + static String selfSignedCertStr = null; + + // SHA1withRSA 1024 + static String trustAnchor_SHA1withRSA_1024 = + "-----BEGIN CERTIFICATE-----\n" + + "MIICPjCCAaegAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQC8UdC863pFk1Rvd7xUYd60+e9KsLhb6SqOfU42ZA715FcH\n" + + "E1TRvQPmYzAnHcO04TrWZQtO6E+E2RCmeBnetBvIMVka688QkO14wnrIrf2tRodd\n" + + "rZNZEBzkX+zyXCRo9tKEUDFf9Qze7Ilbb+Zzm9CUfu4M1Oz6iQcXRx7aM0jEAQID\n" + + "AQABo4GJMIGGMB0GA1UdDgQWBBTn0C+xmZY/BTab4W9gBp3dGa7WgjBHBgNVHSME\n" + + "QDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEwHzELMAkGA1UEBhMCVVMxEDAO\n" + + "BgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQw\n" + + "DQYJKoZIhvcNAQEFBQADgYEAiCXL2Yp4ruyRXAIJ8zBEaPC9oV2agqgbSbly2z8z\n" + + "Ik5SeSRysP+GHBpb8uNyANJnQKv+T0GrJiTLMBjKCOiJl6xzk3EZ2wbQB6G/SQ9+\n" + + "UWcsXSC8oGSEPpkj5In/9/UbuUIfT9H8jmdyLNKQvlqgq6kyfnskME7ptGgT95Hc\n" + + "tas=\n" + + "-----END CERTIFICATE-----"; + + // SHA1withRSA 512 + static String trustAnchor_SHA1withRSA_512 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIBuTCCAWOgAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMFwwDQYJKoZIhvcNAQEB\n" + + "BQADSwAwSAJBAM0Kn4ieCdCHsrm78ZMMN4jQEEEqACAMKB7O8j9g4gfz2oAfmHwv\n" + + "7JH/hZ0Xen1zUmBbwe+e2J5D/4Fisp9Bn98CAwEAAaOBiTCBhjAdBgNVHQ4EFgQU\n" + + "g4Kwd47hdNQBp8grZsRJ5XvhvxAwRwYDVR0jBEAwPoAUg4Kwd47hdNQBp8grZsRJ\n" + + "5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlggEAMA8G\n" + + "A1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0GCSqGSIb3DQEBBQUAA0EAn77b\n" + + "FJx+HvyRvjZYCzMjnUct3Ql4iLOkURYDh93J5TXi/l9ajvAMEuwzYj0qZ+Ktm/ia\n" + + "U5r+8B9nzx+j2Zh3kw==\n" + + "-----END CERTIFICATE-----"; + + // MD2withRSA 2048 + static String trustAnchor_MD2withRSA_2048 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIDQzCCAiugAwIBAgIBADANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ\n" + + "MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDdaFw0zMDA3MTcwMTExNDda\n" + + "MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIIBIjANBgkqhkiG9w0B\n" + + "AQEFAAOCAQ8AMIIBCgKCAQEArF5pINc5s+aUlmdYlxtAQ3V4TXFnP/XOYHxjfLuX\n" + + "eKO/kh78LMvbDisTPQ2yo9YEawwwbUU40xcuzgi0axXgKveHXYdUmTr0hEapq3rv\n" + + "g/q2EbOjyXvq4qK2RDoVCN8R3wXiytnY2OFALTx6zc2tW4imJ20svdNVtWhv2syj\n" + + "ZTmmRXAeFUbD4qKWAFij0I6pnSgVssvWzeyJUNemym+oiYyaSd7n5j1RNAqUKioo\n" + + "K/T0FOOiuPGMqottgx5YRHa6yapCP5QVWRQ+WBIYJY3Wyq7N+Es20LT6761Pk3to\n" + + "EFCzM7+zqT/c+pC079HOKXz+m2us+HKp5BKWNnbvgaYPOQIDAQABo4GJMIGGMB0G\n" + + "A1UdDgQWBBSrSukJf+mO5LTRasAGD9RRs7SASTBHBgNVHSMEQDA+gBSrSukJf+mO\n" + + "5LTRasAGD9RRs7SASaEjpCEwHzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1w\n" + + "bGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEC\n" + + "BQADggEBAHvsv+DqMJeIW/D+ltkhw37OdMzkMPp4E6Hbp03O3GZ5LfNGczHCb2uL\n" + + "sr5T7e/jaBFn6QfmqbOAYAHJSNq2bNNtTbatnHBLuVx13cfxmwk89Cg/tFeoUdcf\n" + + "m5hzurB6Ub6SsYMOxZHUYp/KxM9x9a7llC1bK3SKXwd4rVDlXh8DOBvdQNr5Q3yq\n" + + "JjY86bSXO14VzNxL/1rqHiszQdPyR/28SBsQVYSi0Zeyc4Yy1ui/cXu1+PWYw3YZ\n" + + "QUPHTnkVdPGwRiUqeZIcps+q+ePlQQmDu5qiLD6d8gsyGyY/RvCHWKO5Y9DuX9hs\n" + + "he/AhCWQx+TQYGLu0liQqLkGZydyRnA=\n" + + "-----END CERTIFICATE-----"; + + private static CertPath generateCertificatePath() + throws CertificateException { + // generate certificate from cert strings + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + ByteArrayInputStream is; + + is = new ByteArrayInputStream(selfSignedCertStr.getBytes()); + Certificate selfSignedCert = cf.generateCertificate(is); + + // generate certification path + List<Certificate> list = Arrays.asList(new Certificate[] { + selfSignedCert}); + + return cf.generateCertPath(list); + } + + private static Set<TrustAnchor> generateTrustAnchors() + throws CertificateException { + // generate certificate from cert string + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + ByteArrayInputStream is = + new ByteArrayInputStream(selfSignedCertStr.getBytes()); + Certificate selfSignedCert = cf.generateCertificate(is); + + // generate a trust anchor + TrustAnchor anchor = + new TrustAnchor((X509Certificate)selfSignedCert, null); + + return Collections.singleton(anchor); + } + + public static void main(String args[]) throws Exception { + try { + validate(trustAnchor_SHA1withRSA_1024); + validate(trustAnchor_SHA1withRSA_512); + } catch (CertPathValidatorException cpve) { + throw new Exception( + "unexpect exception, it is valid cert", cpve); + } + + try { + validate(trustAnchor_MD2withRSA_2048); + throw new Exception("expected algorithm disabled exception"); + } catch (CertPathValidatorException cpve) { + System.out.println("Get the expected exception " + cpve); + } + } + + private static void validate(String trustAnchor) + throws CertPathValidatorException, Exception { + selfSignedCertStr = trustAnchor; + + CertPath path = generateCertificatePath(); + Set<TrustAnchor> anchors = generateTrustAnchors(); + + PKIXParameters params = new PKIXParameters(anchors); + + // disable certificate revocation checking + params.setRevocationEnabled(false); + + // set the validation time + params.setDate(new Date(109, 9, 1)); // 2009-09-01 + + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + + validator.validate(path, params); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/provider/certpath/DisabledAlgorithms/README Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,640 @@ +/* + * 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. + * + * 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. + */ + + Certificates and CRLs + +Here lists the Certificates, which was generated by generate.sh, used in the +test cases. + +The generate.sh depends on openssl, and it should be run under ksh. The +script will create many directories and files, please run it in a +directory outside of JDK workspace. + +1. root certifiate and key (SHA1withRSA 1024, root_cert_sha1_1024.pem) +-----BEGIN CERTIFICATE----- +MIICPjCCAaegAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa +MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQC8UdC863pFk1Rvd7xUYd60+e9KsLhb6SqOfU42ZA715FcH +E1TRvQPmYzAnHcO04TrWZQtO6E+E2RCmeBnetBvIMVka688QkO14wnrIrf2tRodd +rZNZEBzkX+zyXCRo9tKEUDFf9Qze7Ilbb+Zzm9CUfu4M1Oz6iQcXRx7aM0jEAQID +AQABo4GJMIGGMB0GA1UdDgQWBBTn0C+xmZY/BTab4W9gBp3dGa7WgjBHBgNVHSME +QDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEwHzELMAkGA1UEBhMCVVMxEDAO +BgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQw +DQYJKoZIhvcNAQEFBQADgYEAiCXL2Yp4ruyRXAIJ8zBEaPC9oV2agqgbSbly2z8z +Ik5SeSRysP+GHBpb8uNyANJnQKv+T0GrJiTLMBjKCOiJl6xzk3EZ2wbQB6G/SQ9+ +UWcsXSC8oGSEPpkj5In/9/UbuUIfT9H8jmdyLNKQvlqgq6kyfnskME7ptGgT95Hc +tas= +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,DF5249E009A0FD79 + +rc316yLipp/vH0i6rhEbEwZpZ+HfKIXnnp/bIIZv2+4lyGUDWrxN0Hk0TcSgWEKm +dRGI2fsyWjTgaiHwwmusofXPAjB3s0I2rUUAHXk8/sEuiLLTICx2UAL8k6R33CSQ +NKR8t+TluBW3Us71vibWauuMHa5860KiiLWdhkQVLin7m/JBGLtz0zQ0/lZ8CgEm +p7eDupPi8FBClCyVewdpmKjgI2KPI4fVIZLMzLeGcWLaOQPN1ERcFWQ1CS/qjfMb +F4rtpZ+AzCqP75XPhitT2CnZgaVDxHBtAZQVPuKONMdijKphjqiT/Sd86Gx6OEVE +EwwmQya2Q/5aCuH96S00mj00oeIZ7ZtUcVQcch+saJy4vpuxK8pFcEDKmgsvL9+8 +Hho9RUXVUKRH67uA1NjQSK5+syEIj5sJCDcxOda4QGXeIq9ygaZswxF3nfvffrsa +S6IVBXrx0G+Ascu29SHoI+zi3feQszQJIzijHoTTq6FacLHUWzfVuaYa47uaj5qa +VYsMVCzi1eX486o7YKPKWiclNczQN86v5n9+c9uggXY12wSOmnf6BB1Ds+oL8JlU +IZa67lAyg6G9joAb9rTXN2EE5OTArcFuImK8GHse/3wkIPMglBNnfwpvjC1U+vQm +F7iXp+OxnZ5d9sBcrTBEZ9BDlTVlpiZI7EeS1oC8x6DDTdbJR/40Y3wJIDMI9q9T +O5EnyXqbmQziO0Tgal43w6mMTUnhG34kqovwxy03mAOZb3yz/RgWlez9wQmPseiI +2p2fQIjCPbGFNJt3rdyXOW/BRCii0970HEZeov/TVV/A0vUVajNAjA== +-----END RSA PRIVATE KEY----- + +2. root certifiate and key (SHA1withRSA 512, root_cert_sha1_512.pem) +-----BEGIN CERTIFICATE----- +MIIBuTCCAWOgAwIBAgIBADANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDRaFw0zMDA3MTcwMTExNDRa +MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMFwwDQYJKoZIhvcNAQEB +BQADSwAwSAJBAM0Kn4ieCdCHsrm78ZMMN4jQEEEqACAMKB7O8j9g4gfz2oAfmHwv +7JH/hZ0Xen1zUmBbwe+e2J5D/4Fisp9Bn98CAwEAAaOBiTCBhjAdBgNVHQ4EFgQU +g4Kwd47hdNQBp8grZsRJ5XvhvxAwRwYDVR0jBEAwPoAUg4Kwd47hdNQBp8grZsRJ +5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlggEAMA8G +A1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0GCSqGSIb3DQEBBQUAA0EAn77b +FJx+HvyRvjZYCzMjnUct3Ql4iLOkURYDh93J5TXi/l9ajvAMEuwzYj0qZ+Ktm/ia +U5r+8B9nzx+j2Zh3kw== +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,B8BDE38F08C6BB76 + +eJzx2oZE0UXxWpzssSWtKBOCbm3ZXR6iBKX8iKoDUB5SzzmKr+XzxI7kyv92y0pe +rNTuuCWpBsLdlz7h8Ipn4pBDYswGU5F9MQOEgIYx60OvGhZODHGRzJ05FXTeCmmu +LLp6lGW4SWALcd8g/gJUn1/vp7f1VzQ7RwXWBn4/b34RRYtwr3E6nl4Hc2tEI1in +OL+lCdAAyxjGK7KYFHJQK+1E8tYNrer3cejQDcNysGx4o0H123vfp3NtJ6U7LXyi +D21y3zmPueJos8LluJiLRsONcrcI3mIfpPBsO+Yl2EJtzS9V6Aaq/YdPkwPHH6Y5 +lazGMPXq/nffb12fWLL7m5aFb3FNLwWi/qwEynWCEv7Vl/6kLk+aHhjTnYkLvLNH +9maQFn6j0S3wqogRfW9BDbfC3fRHP6+8YjEEmQ0RTfE= +-----END RSA PRIVATE KEY----- + +3. root certifiate and key (MD2withRSA 2048, root_cert_md2_2048.pem) +-----BEGIN CERTIFICATE----- +MIIDQzCCAiugAwIBAgIBADANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDdaFw0zMDA3MTcwMTExNDda +MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEArF5pINc5s+aUlmdYlxtAQ3V4TXFnP/XOYHxjfLuX +eKO/kh78LMvbDisTPQ2yo9YEawwwbUU40xcuzgi0axXgKveHXYdUmTr0hEapq3rv +g/q2EbOjyXvq4qK2RDoVCN8R3wXiytnY2OFALTx6zc2tW4imJ20svdNVtWhv2syj +ZTmmRXAeFUbD4qKWAFij0I6pnSgVssvWzeyJUNemym+oiYyaSd7n5j1RNAqUKioo +K/T0FOOiuPGMqottgx5YRHa6yapCP5QVWRQ+WBIYJY3Wyq7N+Es20LT6761Pk3to +EFCzM7+zqT/c+pC079HOKXz+m2us+HKp5BKWNnbvgaYPOQIDAQABo4GJMIGGMB0G +A1UdDgQWBBSrSukJf+mO5LTRasAGD9RRs7SASTBHBgNVHSMEQDA+gBSrSukJf+mO +5LTRasAGD9RRs7SASaEjpCEwHzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1w +bGWCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEC +BQADggEBAHvsv+DqMJeIW/D+ltkhw37OdMzkMPp4E6Hbp03O3GZ5LfNGczHCb2uL +sr5T7e/jaBFn6QfmqbOAYAHJSNq2bNNtTbatnHBLuVx13cfxmwk89Cg/tFeoUdcf +m5hzurB6Ub6SsYMOxZHUYp/KxM9x9a7llC1bK3SKXwd4rVDlXh8DOBvdQNr5Q3yq +JjY86bSXO14VzNxL/1rqHiszQdPyR/28SBsQVYSi0Zeyc4Yy1ui/cXu1+PWYw3YZ +QUPHTnkVdPGwRiUqeZIcps+q+ePlQQmDu5qiLD6d8gsyGyY/RvCHWKO5Y9DuX9hs +he/AhCWQx+TQYGLu0liQqLkGZydyRnA= +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,3910D329AD49ECFC + +6K0OU3Xrl2H6kz7x7EHXkM0/Wd6jXBBwWsaroUIGnbIMmljJXPfgcuDUu6f5Imk1 +ndoU0GWjxa1QNjteAQQtFoLDP8rienLs0b969OcAxB0EOffQFkEfsfXdyEIgdwkD +ETczwDIyd8Wj62ClydJES3jKB9Nc9kMIlsoZ+h24TyJeeRsHAtMrz+mlOHsUWDQ5 +FyYZelnx+fQ5maD3bura7xLiNl8CvgWz0wt2Wt4djdMGhQ3OWd0/GWweP+2xnL6n +5tDJ5On50+Z5T8Jhx62yg+wQiBKAYnYw6OX3skJwWknuAvYz3Z3e12DHFx6w5EAU +K7lg7fHMqHNirUkJOlYzgJ21ybV4uQmFRNQJwI9h6GVfdZWPEU+Ni42AlNgNYskF +K19dONNNt0Gwkcm2VOYzwYGDyaQW2YIGDk1fbZdVSu/h/lyOC/RmorGWroAbYsyB +/GUIilcLtQHPGI8XuojTS2/UWcKactpceN3UOnQkus3/smViEqqB/NQ/lcozgs0o +7ZG6H6to7w1yb5VR2d7B2bS7MNJt1AsOB5ydAMYIccdHDTI7CfRK6axQ70O/JPnJ +WLY2e41ig2uAWk/3fRb8L6d3keVcN7y4WnkXPbHhulqtxQo78iSQQAf7tDMBxWKx +C5LQW3CxLkHKp6g22SDxl2LjJyu5nDbtIh3Pq+BCoA25uqXC4rPoWwV7EWYv8Z+Y +E6dS98SEa+cDhpllvGzbTKgcP1VqtQbb9VT92UT1mFrklqRuQIxROeCe4wjp5TKo +D2losUDdzpqBHkBNo2I8qZkgybeCvWEq73my2+JG1AAIFFB1kzfBNaBDGiGSuUuS +5peV8156aaLg5pxdieoRJ3Y7eaWN1wH5CnRnafoB+lxSUsQO1a7y2LbpedrKjs+2 +AryPHQw7HLd8IQevmvd7BhJLdvlt+kXzWID/pUsSAYvI7aP4daQJuAt/kwmU27Gd +wqhV8Tjbb84vFGmqGHtb2YbKfUrsPUNOLBF+U4SDAgBhEyhINQZyRDcqqoywO5Dr +sV46nTEfwAgt88KFt2CEhiyvoJbtCj1iMJeAzuljwF4z4RzB1i3TK0MaJYID2rxB +E1vK9EZIssk/NeImN2YCbuqOhU58jtOwYh3ruS+mZQm1APvJF9N4tCCVQsjWC6zY +4eqs7T6VDFH4AaT7b3J3rTsEpWIDUfagetZs5kR9SiWJC7dU7r53gGg4avVyIIHD ++MYCS+auD9/nmVf4iYstVgJFMUJXC2EUOLi0r8KmDkCILl/K3X/W7QwFTnC07gLh +/9HjWFJ0R6cyODzvE8NGPMeuJGUT2F+mA1vaAC/PBGz+61AF0BjWTZ7x2sH+tSPP +/GVEaCgyzrKRX5XX+7DulTcmFj1JNfMmtbDaJa9WnwOI4qszBGrAcYeYTHXR6Yov +Ux/P6RStfa+UwSjo8i3nfdgLk+RXCpN0srMjSmiQx8d5R/kISqXKDtQfS5M6gsoh +ROz+6zZP8Gh8yakr1p4C6JUSiLDYP5qXzxr8bp+oxvpY7anEDAqx21HyExEAu+gy +IrNl75FWqV8BbKxoFfe9LqyDaryXXA8oy6F+4BT/zRrxp+dym9pbd+OZR423BIij +-----END RSA PRIVATE KEY----- + +4. subca certificate and key (SHA1withRSA 1024, root_cert_sha1_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIICUDCCAbmgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDhaFw0yOTA0MjMwMTExNDha +MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz +cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8 +BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg +bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82 +AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl +UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw +HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw +AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADgYEAHze3wAcIe84zNOoN +P8l9EmlVVoU30z3LB3hxq3m/dC/4gE5Z9Z8EG1wJw4qaxlTZ4dif12nbTTdofVhb +Bd4syjo6fcUA4q7sfg9TFpoHQ+Ap7PgjK99moMKdMy50Xy8s6FPvaVkF89s66Z6y +e4q7TSwe6QevGOZaL5N/iy2XGEs= +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,0480E76FD259323B + +npiifBm1mHq1Z9QgAV5T35Xbnea9VnwqYQWNfRRKmpfYSdkQJ0few18YtnfZwh9e +LKCWx+lq1V4yDG4SbxXDq71Dyvx1vZY+w4h+6M1+6KGFG1VDBfN3e5aLgK8EG9pZ +yHZH7iB7HiQXH5q53jL6NUZn55C3XEk1sErpK7R1c0Y8Qp2TGiu+lck3K+zR9GiO +5aJMKbShReB0Nfy3JJNKRFSd95QMTTjbq6iIvhN8O02bo4I4I3HTyD8qyR7ViiHl +FmOukjwn4fjJvK0WYKYUjod8oEiMdR2nr73eOGZBAnEorDGQ8VnnCAleSv74is1k +W7M07UP7EJJq9hSZfeMqk5QivtWrqvWG1SWxpTowKTEAyTn7u5U13k0DiRcsg0WT +4mSMiLOhUNgIWcHElbTQPSVDcVznhNk0dWPDwKoUjp+orCuH+NvHKBAu+hnuip3e +Ji7WGrHXI7QxAr5qr5ogl5x4yH4drIbq9fUea3NTuGPuPyu9fWjOSDmqPRKRMJFR +UxxVFcyrW8iSBV5cvB7M1ADS40y6l4ryYmKjXbsOI4Ci8LJWJ4ZB61WQP7TvPQGS +mNFmTTB2dwbpimr4KjV9j2bA9x0jAsjlcQZ5j1GOeyYCEDGKDJw0XD/zI+j0dpVc +eu8YtuJGTyO1h+HiI3D9LrMuyUxxckvFHKe00+4xMz1hpqVo/kxe6gqf/9ES4M/h +6/NeTzeqyJF2rgxK6KJJdmaKVYI+bvAQ3cKl+RZmgOjx4eig58N5uthqFgU7rQ+e +GM9/y8C9WpPqITcJlY7I/7AkqvYDBwBsH/9mf4g9OUbC1Ah+MX8UIQ== +-----END RSA PRIVATE KEY----- + + +5. subca certificate and key (SHA1withRSA 1024, root_cert_sha1_512.pem signed) +-----BEGIN CERTIFICATE----- +MIICDzCCAbmgAwIBAgIBAzANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla +MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz +cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8 +BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg +bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82 +AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl +UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw +HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw +AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEFBQADQQCYNmdkONfuk07XjRze +WQyq2cfdae4uIdyUfa2rpgYMtSXuQW3/XrQGiz4G6WBXA2wo7folOOpAKYgvHPrm +w6Dd +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,0480E76FD259323B + +npiifBm1mHq1Z9QgAV5T35Xbnea9VnwqYQWNfRRKmpfYSdkQJ0few18YtnfZwh9e +LKCWx+lq1V4yDG4SbxXDq71Dyvx1vZY+w4h+6M1+6KGFG1VDBfN3e5aLgK8EG9pZ +yHZH7iB7HiQXH5q53jL6NUZn55C3XEk1sErpK7R1c0Y8Qp2TGiu+lck3K+zR9GiO +5aJMKbShReB0Nfy3JJNKRFSd95QMTTjbq6iIvhN8O02bo4I4I3HTyD8qyR7ViiHl +FmOukjwn4fjJvK0WYKYUjod8oEiMdR2nr73eOGZBAnEorDGQ8VnnCAleSv74is1k +W7M07UP7EJJq9hSZfeMqk5QivtWrqvWG1SWxpTowKTEAyTn7u5U13k0DiRcsg0WT +4mSMiLOhUNgIWcHElbTQPSVDcVznhNk0dWPDwKoUjp+orCuH+NvHKBAu+hnuip3e +Ji7WGrHXI7QxAr5qr5ogl5x4yH4drIbq9fUea3NTuGPuPyu9fWjOSDmqPRKRMJFR +UxxVFcyrW8iSBV5cvB7M1ADS40y6l4ryYmKjXbsOI4Ci8LJWJ4ZB61WQP7TvPQGS +mNFmTTB2dwbpimr4KjV9j2bA9x0jAsjlcQZ5j1GOeyYCEDGKDJw0XD/zI+j0dpVc +eu8YtuJGTyO1h+HiI3D9LrMuyUxxckvFHKe00+4xMz1hpqVo/kxe6gqf/9ES4M/h +6/NeTzeqyJF2rgxK6KJJdmaKVYI+bvAQ3cKl+RZmgOjx4eig58N5uthqFgU7rQ+e +GM9/y8C9WpPqITcJlY7I/7AkqvYDBwBsH/9mf4g9OUbC1Ah+MX8UIQ== +-----END RSA PRIVATE KEY----- + + +6. subca certificate and key (SHA1withRSA 512, root_cert_sha1_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIICDDCCAXWgAwIBAgIBBDANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla +MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz +cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV +lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA +AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw +PoAU59AvsZmWPwU2m+FvYAad3Rmu1oKhI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD +VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G +CSqGSIb3DQEBBQUAA4GBAE2VOlw5ySLT3gUzKCYEga4QPaSrf6lHHPi2g48LscEY +h9qQXh4nuIVugReBIEf6N49RdT+M2cgRJo4sZ3ukYLGQzxNuttL5nPSuuvrAR1oG +LUyzOWcUpKHbVHi6zlTt79RvTKZvLcduLutmtPtLJcM9PdiAI1wEooSgxTwZtB/Z +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,0A94F7EA4C89CA33 + +tfKdAZVSrpeS/hU4+mGYcGGx3nNqrE+CzDAfLadVuXz5ju5p9oFhLTZj99wK+uHn +prrWmDNOdYKRBJn7h40WV6zi4lR3JgnuYNxH8fxO3PI+HQ9IuvdoTyqUeXTP4Zj1 +BCnr1k1D2WGDXvnh+saq9qRpMKThjK/OF0YmDa07PI5NOBdMA3EmkNYfwib2GfBV +el4FVkfnPQkLGahTh3SC62TzPlnsAgirCeua7ZLPqN3fkZkYbXZd9op2D31n7cBP +zztg0ah8WF4gPOd/BBZeR9XDog5qm/wzyBj0F6ClHRPjpGYhAm2Vw66xOBlGFYI9 +lVmFQzrPcDNlFTybzhl5C6Qy4cPQh+QErDWxljVI52oYYmY/KRmUGGL7hEG8ZGOn +EUgFrEJyAY7w4wpBC5n9SotwyPXhwKQ1uCBq+1zElPw= +-----END RSA PRIVATE KEY----- + +7. subca certificate and key (SHA1withRSA 512, root_cert_sha1_512.pem signed) +-----BEGIN CERTIFICATE----- +MIIByzCCAXWgAwIBAgIBBTANBgkqhkiG9w0BAQUFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla +MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz +cy0xMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKubXYoEHZpZkhzA9XX+NrpqJ4SV +lOMBoL3aWExQpJIgrUaZfbGMBBozIHBJMMayokguHbJvq4QigEgLuhfJNqsCAwEA +AaOBiTCBhjAdBgNVHQ4EFgQUN0CHiTYPtjyvpP2a6y6mhsZ6U40wRwYDVR0jBEAw +PoAUg4Kwd47hdNQBp8grZsRJ5XvhvxChI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD +VQQKEwdFeGFtcGxlggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMA0G +CSqGSIb3DQEBBQUAA0EAoCf0Zu559qcB4xPpzqkVsYiyW49S4Yc0mmQXb1yoQgLx +O+DCkjG5d14+t1MsnkhB2izoQUMxQ3vDc1YnA/tEpw== +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,0A94F7EA4C89CA33 + +tfKdAZVSrpeS/hU4+mGYcGGx3nNqrE+CzDAfLadVuXz5ju5p9oFhLTZj99wK+uHn +prrWmDNOdYKRBJn7h40WV6zi4lR3JgnuYNxH8fxO3PI+HQ9IuvdoTyqUeXTP4Zj1 +BCnr1k1D2WGDXvnh+saq9qRpMKThjK/OF0YmDa07PI5NOBdMA3EmkNYfwib2GfBV +el4FVkfnPQkLGahTh3SC62TzPlnsAgirCeua7ZLPqN3fkZkYbXZd9op2D31n7cBP +zztg0ah8WF4gPOd/BBZeR9XDog5qm/wzyBj0F6ClHRPjpGYhAm2Vw66xOBlGFYI9 +lVmFQzrPcDNlFTybzhl5C6Qy4cPQh+QErDWxljVI52oYYmY/KRmUGGL7hEG8ZGOn +EUgFrEJyAY7w4wpBC5n9SotwyPXhwKQ1uCBq+1zElPw= +-----END RSA PRIVATE KEY----- + +8. subca certificate and key (MD2withRSA 1024, root_cert_sha1_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIICUDCCAbmgAwIBAgIBBjANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla +MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz +cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8 +BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg +bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82 +AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl +UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBTn0C+xmZY/BTab4W9gBp3dGa7WgqEjpCEw +HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw +AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADgYEAPtEjwbWuC5kc4DPc +Ttf/wdbD8ZCdAWzcc3XF9q1TlvwVMNk6mbfM05y6ZVsztKTkwZ4EcvFu/yIqw1EB +E1zlXQCaWXT3/ZMbqYZV4+mx+RUl8spUCb1tda25jnTg3mTOzB1iztm4gy903EMd +m8omKDKeCgcw5dR4ITQYvyxe1as= +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,0480E76FD259323B + +npiifBm1mHq1Z9QgAV5T35Xbnea9VnwqYQWNfRRKmpfYSdkQJ0few18YtnfZwh9e +LKCWx+lq1V4yDG4SbxXDq71Dyvx1vZY+w4h+6M1+6KGFG1VDBfN3e5aLgK8EG9pZ +yHZH7iB7HiQXH5q53jL6NUZn55C3XEk1sErpK7R1c0Y8Qp2TGiu+lck3K+zR9GiO +5aJMKbShReB0Nfy3JJNKRFSd95QMTTjbq6iIvhN8O02bo4I4I3HTyD8qyR7ViiHl +FmOukjwn4fjJvK0WYKYUjod8oEiMdR2nr73eOGZBAnEorDGQ8VnnCAleSv74is1k +W7M07UP7EJJq9hSZfeMqk5QivtWrqvWG1SWxpTowKTEAyTn7u5U13k0DiRcsg0WT +4mSMiLOhUNgIWcHElbTQPSVDcVznhNk0dWPDwKoUjp+orCuH+NvHKBAu+hnuip3e +Ji7WGrHXI7QxAr5qr5ogl5x4yH4drIbq9fUea3NTuGPuPyu9fWjOSDmqPRKRMJFR +UxxVFcyrW8iSBV5cvB7M1ADS40y6l4ryYmKjXbsOI4Ci8LJWJ4ZB61WQP7TvPQGS +mNFmTTB2dwbpimr4KjV9j2bA9x0jAsjlcQZ5j1GOeyYCEDGKDJw0XD/zI+j0dpVc +eu8YtuJGTyO1h+HiI3D9LrMuyUxxckvFHKe00+4xMz1hpqVo/kxe6gqf/9ES4M/h +6/NeTzeqyJF2rgxK6KJJdmaKVYI+bvAQ3cKl+RZmgOjx4eig58N5uthqFgU7rQ+e +GM9/y8C9WpPqITcJlY7I/7AkqvYDBwBsH/9mf4g9OUbC1Ah+MX8UIQ== +-----END RSA PRIVATE KEY----- + + +9. subca certificate and key (MD2withRSA 1024, root_cert_sha1_512.pem signed) +-----BEGIN CERTIFICATE----- +MIICDzCCAbmgAwIBAgIBBzANBgkqhkiG9w0BAQIFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDYwMTExNDlaFw0yOTA0MjMwMTExNDla +MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz +cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVOqnlZspyAEr90ELFaUo8 +BF0O2Kn0yTdUeyiLOth4RA3qxWrjxJq45VmEBjZpEzPHfnp3PhnfmLcLfhoPONFg +bcHzlkj75ZaKCgHoyV456fMBmj348fcoUkH2WdSQ82pmxHOiHqquYNUSTimFIq82 +AayhbKqDmhfx5lJdYNqd5QIDAQABo4GJMIGGMB0GA1UdDgQWBBTfWD9mRTppcUAl +UqGuu/R5t8CB5jBHBgNVHSMEQDA+gBSDgrB3juF01AGnyCtmxEnle+G/EKEjpCEw +HzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4YW1wbGWCAQAwDwYDVR0TAQH/BAUw +AwEB/zALBgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQECBQADQQBHok1v6xymtpB7N9xy +0OmDT27uhmzlP0eOzJvXVxj3Oi9TLQJgCUJ9122MzfRAs1E1uJTtvuu+UmI80NQx +KQdp +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,0480E76FD259323B + +npiifBm1mHq1Z9QgAV5T35Xbnea9VnwqYQWNfRRKmpfYSdkQJ0few18YtnfZwh9e +LKCWx+lq1V4yDG4SbxXDq71Dyvx1vZY+w4h+6M1+6KGFG1VDBfN3e5aLgK8EG9pZ +yHZH7iB7HiQXH5q53jL6NUZn55C3XEk1sErpK7R1c0Y8Qp2TGiu+lck3K+zR9GiO +5aJMKbShReB0Nfy3JJNKRFSd95QMTTjbq6iIvhN8O02bo4I4I3HTyD8qyR7ViiHl +FmOukjwn4fjJvK0WYKYUjod8oEiMdR2nr73eOGZBAnEorDGQ8VnnCAleSv74is1k +W7M07UP7EJJq9hSZfeMqk5QivtWrqvWG1SWxpTowKTEAyTn7u5U13k0DiRcsg0WT +4mSMiLOhUNgIWcHElbTQPSVDcVznhNk0dWPDwKoUjp+orCuH+NvHKBAu+hnuip3e +Ji7WGrHXI7QxAr5qr5ogl5x4yH4drIbq9fUea3NTuGPuPyu9fWjOSDmqPRKRMJFR +UxxVFcyrW8iSBV5cvB7M1ADS40y6l4ryYmKjXbsOI4Ci8LJWJ4ZB61WQP7TvPQGS +mNFmTTB2dwbpimr4KjV9j2bA9x0jAsjlcQZ5j1GOeyYCEDGKDJw0XD/zI+j0dpVc +eu8YtuJGTyO1h+HiI3D9LrMuyUxxckvFHKe00+4xMz1hpqVo/kxe6gqf/9ES4M/h +6/NeTzeqyJF2rgxK6KJJdmaKVYI+bvAQ3cKl+RZmgOjx4eig58N5uthqFgU7rQ+e +GM9/y8C9WpPqITcJlY7I/7AkqvYDBwBsH/9mf4g9OUbC1Ah+MX8UIQ== +-----END RSA PRIVATE KEY----- + + +a. end entity certificate and key + (SHA1withRSA 1024, subca_cert_sha1_1024_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIICNzCCAaCgAwIBAgIBAjANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx +NTBaFw0yOTA0MjMwMTExNTBaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt +cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt +vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v +z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6 +c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07 +OorBleV92TAfBgNVHSMEGDAWgBTfWD9mRTppcUAlUqGuu/R5t8CB5jANBgkqhkiG +9w0BAQUFAAOBgQAOfIeasDg91CR3jGfuAEVKwncM1OPFmniAUcdPm74cCAyJ90Me +dhUElWPGoAuXGfiyZlOlGUYWqEroe/dnkmnotJjLWR+MA4ZyX3O1YI8T4W3deWcC +J4WMCF7mp17SaYYKX9F0AxwNJFpUkbB41IkTxPr0MmzB1871/pbY8dLAvA== +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,1FE5A37B770AF83D + +042bWtt4q0cB8pRuPUlMVncTP/WAz+mmPw3jXI3LFOBZeK6zFEDpI5M9c2JO+rqp +Za5UkYuIg69V7LngriqRynkRGGQp3xASMLr5NVbKHTE/Ol/iIuxKaCkumZmGXB/z +8bxQF5XN4tbKT4s3sWWmmKMicg6MHvySi3QVRG11PHRu/q7CEFPzJKRQ3fpaNcKD +NTBI5F6GP9ENa/eog4WGENjXS0v4Wa3IfaOhjKXrSxjLUqLH0C8g5WWg5IrXXtuI +pgyJ2kkE3Y/ChU7p7R42we6tBZqF5SiL5kFDn86DmHgCslTiZkIoE5i644sp03Sd +XkHyHu0VIeYp3nDwRA7S98837W4F6i1BnXA5f3EaE3rNGjsxK8zL2pvdCcDYbese +ETfba16HMzLXe1b4RSI3gwhlQ2MNKBwvskkQESf/Ew1DskBY0MCYFxo6hIp6LqMo +HAl5kvCwvuYL2jBdQhkKxU+Leu5Ei8Ie9XYNVy4yUeUAMnSUkVaEs/I8z+Mk8oYq +4QWqOc66XLcI13coDoxmv54kye3RjqdmZI8mg/3LCFotwceDuXyD43/vVhoTPEnp +CqXafV2pw4y95skMHmktI2qvSahaM4P6GGXl8HqmP3b+8V5mxMhNtVnuUha2kouw +DLNFUTg1cCLahM5SRolyA/XTGh7JOkJMYWPeJwN7l3K+lBtHHfj6DHtKEjUcyZFd ++Z55pDoAERumB6+BCnt6X2/0kEDV219RmsgxkGTWdFs+M7Y6EYYRtlinH4nqL6UD +eHWitYIatAHOvdHeNrbXN9L5P3tsUB4HzFa46WWtKqRtbCVTuPVZdw== +-----END RSA PRIVATE KEY----- + +b. end entity certificate and key + (SHA1withRSA 1024, subca_cert_sha1_512_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIIB9jCCAaCgAwIBAgIBAzANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx +NTBaFw0yOTA0MjMwMTExNTBaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt +cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt +vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v +z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6 +c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07 +OorBleV92TAfBgNVHSMEGDAWgBQ3QIeJNg+2PK+k/ZrrLqaGxnpTjTANBgkqhkiG +9w0BAQUFAANBADV6X+ea0ftEKXy7yKNAbdIp35893T6AVwbdclomPkeOs86OtoTG +1BIzWSK9QE7W6Wbf63e2RdcqoLK+DxsuwUg= +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,1FE5A37B770AF83D + +042bWtt4q0cB8pRuPUlMVncTP/WAz+mmPw3jXI3LFOBZeK6zFEDpI5M9c2JO+rqp +Za5UkYuIg69V7LngriqRynkRGGQp3xASMLr5NVbKHTE/Ol/iIuxKaCkumZmGXB/z +8bxQF5XN4tbKT4s3sWWmmKMicg6MHvySi3QVRG11PHRu/q7CEFPzJKRQ3fpaNcKD +NTBI5F6GP9ENa/eog4WGENjXS0v4Wa3IfaOhjKXrSxjLUqLH0C8g5WWg5IrXXtuI +pgyJ2kkE3Y/ChU7p7R42we6tBZqF5SiL5kFDn86DmHgCslTiZkIoE5i644sp03Sd +XkHyHu0VIeYp3nDwRA7S98837W4F6i1BnXA5f3EaE3rNGjsxK8zL2pvdCcDYbese +ETfba16HMzLXe1b4RSI3gwhlQ2MNKBwvskkQESf/Ew1DskBY0MCYFxo6hIp6LqMo +HAl5kvCwvuYL2jBdQhkKxU+Leu5Ei8Ie9XYNVy4yUeUAMnSUkVaEs/I8z+Mk8oYq +4QWqOc66XLcI13coDoxmv54kye3RjqdmZI8mg/3LCFotwceDuXyD43/vVhoTPEnp +CqXafV2pw4y95skMHmktI2qvSahaM4P6GGXl8HqmP3b+8V5mxMhNtVnuUha2kouw +DLNFUTg1cCLahM5SRolyA/XTGh7JOkJMYWPeJwN7l3K+lBtHHfj6DHtKEjUcyZFd ++Z55pDoAERumB6+BCnt6X2/0kEDV219RmsgxkGTWdFs+M7Y6EYYRtlinH4nqL6UD +eHWitYIatAHOvdHeNrbXN9L5P3tsUB4HzFa46WWtKqRtbCVTuPVZdw== +-----END RSA PRIVATE KEY----- + +c. end entity certificate and key + (SHA1withRSA 512, subca_cert_sha1_1024_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIIB8zCCAVygAwIBAgIBBDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx +NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt +cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTBcMA0GCSqGSIb3 +DQEBAQUAA0sAMEgCQQCpfQzhld7w2JhW/aRaLkmrLrc/QAsQE+J4DXioXaajsWPo +uMmYmuiQolb6OIY/LcivSubKM3G5PkAWoovUPIWLAgMBAAGjTzBNMAsGA1UdDwQE +AwID6DAdBgNVHQ4EFgQUFWuXLkf4Ji57H9ISycgWi982TUIwHwYDVR0jBBgwFoAU +31g/ZkU6aXFAJVKhrrv0ebfAgeYwDQYJKoZIhvcNAQEFBQADgYEAUyW8PrEdbzLu +B+h6UemBOJ024rYq90hJE/5wUEKPvxZ9vPEUgl+io6cGhL3cLfxfh6z5xtEGp4Tb +NB0Ye3Qi01FBiNDY8s3rQRrmel6VysU8u+0Oi2jmQY6vZXn/zXN5rrTLITCaSicG +dOMv1xLM83Ee432WWlDwKOUxhzDGpWc= +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,153918982D82A26E + +5w5MNd16M1draSfIFAuWNfP3869l9y8vMI1kOcxqsxjeG6YfgKUyu6PEYlj1R7d1 +/+UwVs9RGm3V7AwV4G1Qpnd+jaMLpgPVMP12sHPnslBE4SQe9bAZ+X5i2/5uesHv +bF7OBMqsYW8+Kgsy1Ac0pBx/8yoFYdD3KYFnIP20kV2Xxy4PtQQ6tHJ33dGslTNU +qrcJsyUyYj6wORlb7huuP5Ua8f28Xs/KvnNJG0094kC1WHi3Raf4AoD/rvraVtCQ +5jrK9se8D6su+S3SEW0YndxivbNx3xJu2O72e7lS6yb5ht3U7xNSSWTffIlW1okI +zjscK0iv9S+x452mLIFUgkmriVJLFfjTMRCbhS1J6q9FXLDdre/2O18FO2TvwRIE +6Bwt2utfOAGccRHLsdgcXkv+ngCTCkuCnmh2XZWqmvA= +-----END RSA PRIVATE KEY----- + +d. end entity certificate and key + (SHA1withRSA 512, subca_cert_sha1_512_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIIBsjCCAVygAwIBAgIBBTANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx +NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt +cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTBcMA0GCSqGSIb3 +DQEBAQUAA0sAMEgCQQCpfQzhld7w2JhW/aRaLkmrLrc/QAsQE+J4DXioXaajsWPo +uMmYmuiQolb6OIY/LcivSubKM3G5PkAWoovUPIWLAgMBAAGjTzBNMAsGA1UdDwQE +AwID6DAdBgNVHQ4EFgQUFWuXLkf4Ji57H9ISycgWi982TUIwHwYDVR0jBBgwFoAU +N0CHiTYPtjyvpP2a6y6mhsZ6U40wDQYJKoZIhvcNAQEFBQADQQBG4grtrVEHick0 +z/6Lcl/MGyHT0c8KTXE0AMVXG1NRjAicAmYno/yDaJ9OmfymObKZKV9fF7yCW/N/ +TMU6m7N0 +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,153918982D82A26E + +5w5MNd16M1draSfIFAuWNfP3869l9y8vMI1kOcxqsxjeG6YfgKUyu6PEYlj1R7d1 +/+UwVs9RGm3V7AwV4G1Qpnd+jaMLpgPVMP12sHPnslBE4SQe9bAZ+X5i2/5uesHv +bF7OBMqsYW8+Kgsy1Ac0pBx/8yoFYdD3KYFnIP20kV2Xxy4PtQQ6tHJ33dGslTNU +qrcJsyUyYj6wORlb7huuP5Ua8f28Xs/KvnNJG0094kC1WHi3Raf4AoD/rvraVtCQ +5jrK9se8D6su+S3SEW0YndxivbNx3xJu2O72e7lS6yb5ht3U7xNSSWTffIlW1okI +zjscK0iv9S+x452mLIFUgkmriVJLFfjTMRCbhS1J6q9FXLDdre/2O18FO2TvwRIE +6Bwt2utfOAGccRHLsdgcXkv+ngCTCkuCnmh2XZWqmvA= +-----END RSA PRIVATE KEY----- + +e. end entity certificate and key + (MD2withRSA 1024, subca_cert_sha1_1024_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIICNzCCAaCgAwIBAgIBBjANBgkqhkiG9w0BAQIFADAxMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx +NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt +cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt +vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v +z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6 +c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07 +OorBleV92TAfBgNVHSMEGDAWgBTfWD9mRTppcUAlUqGuu/R5t8CB5jANBgkqhkiG +9w0BAQIFAAOBgQBxKsFf8NNQcXjDoKJJSG4Rk6ikcrhiGYuUI32+XHvs6hnav1Zc +aJUpy7J4gMj/MnysMh/4AF9+m6zEEjuisXKUbYZhgtJxz+ukGSo163mJ8QJiAlRb +Iwsy81r08mlSCR6jx2YhDAUxJIPC92R5Vb4CEutB7tWTwwz7vIHq330erA== +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,1FE5A37B770AF83D + +042bWtt4q0cB8pRuPUlMVncTP/WAz+mmPw3jXI3LFOBZeK6zFEDpI5M9c2JO+rqp +Za5UkYuIg69V7LngriqRynkRGGQp3xASMLr5NVbKHTE/Ol/iIuxKaCkumZmGXB/z +8bxQF5XN4tbKT4s3sWWmmKMicg6MHvySi3QVRG11PHRu/q7CEFPzJKRQ3fpaNcKD +NTBI5F6GP9ENa/eog4WGENjXS0v4Wa3IfaOhjKXrSxjLUqLH0C8g5WWg5IrXXtuI +pgyJ2kkE3Y/ChU7p7R42we6tBZqF5SiL5kFDn86DmHgCslTiZkIoE5i644sp03Sd +XkHyHu0VIeYp3nDwRA7S98837W4F6i1BnXA5f3EaE3rNGjsxK8zL2pvdCcDYbese +ETfba16HMzLXe1b4RSI3gwhlQ2MNKBwvskkQESf/Ew1DskBY0MCYFxo6hIp6LqMo +HAl5kvCwvuYL2jBdQhkKxU+Leu5Ei8Ie9XYNVy4yUeUAMnSUkVaEs/I8z+Mk8oYq +4QWqOc66XLcI13coDoxmv54kye3RjqdmZI8mg/3LCFotwceDuXyD43/vVhoTPEnp +CqXafV2pw4y95skMHmktI2qvSahaM4P6GGXl8HqmP3b+8V5mxMhNtVnuUha2kouw +DLNFUTg1cCLahM5SRolyA/XTGh7JOkJMYWPeJwN7l3K+lBtHHfj6DHtKEjUcyZFd ++Z55pDoAERumB6+BCnt6X2/0kEDV219RmsgxkGTWdFs+M7Y6EYYRtlinH4nqL6UD +eHWitYIatAHOvdHeNrbXN9L5P3tsUB4HzFa46WWtKqRtbCVTuPVZdw== +-----END RSA PRIVATE KEY----- + +f. end entity certificate and key + (MD2withRSA 1024, subca_cert_sha1_512_1024.pem signed) +-----BEGIN CERTIFICATE----- +MIIB9jCCAaCgAwIBAgIBBzANBgkqhkiG9w0BAQIFADAxMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMTAeFw0wOTA4MDYwMTEx +NTFaFw0yOTA0MjMwMTExNTFaMEExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFt +cGxlMRAwDgYDVQQLEwdDbGFzcy0xMQ4wDAYDVQQDEwVBbGljZTCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAy6/2g3rxQzJEvTyOnBcEnZthmAD0AnP6LG8b35jt +vh71LHbF1FhkOT42Rfg20aBfWTMRf+FeOJBXpD4gCNjQA40vy8FaQxgYNAf7ho5v +z6yAEE6SG7YviE+XGcvpQo47w8c6QSQjpBzdw7JxwbVlzUT7pF8x3RnXlGhWnWv6 +c1ECAwEAAaNPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSaXXERsow2Wm/6uT07 +OorBleV92TAfBgNVHSMEGDAWgBQ3QIeJNg+2PK+k/ZrrLqaGxnpTjTANBgkqhkiG +9w0BAQIFAANBAIX63Ypi9P71RnC/pcMbhD+wekRFsTzU593X3MC7tyBJtEXwvAZG +iMxXF5A+ohlr7/CrkV7ZTL8PLxnJdY5Y8rQ= +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,1FE5A37B770AF83D + +042bWtt4q0cB8pRuPUlMVncTP/WAz+mmPw3jXI3LFOBZeK6zFEDpI5M9c2JO+rqp +Za5UkYuIg69V7LngriqRynkRGGQp3xASMLr5NVbKHTE/Ol/iIuxKaCkumZmGXB/z +8bxQF5XN4tbKT4s3sWWmmKMicg6MHvySi3QVRG11PHRu/q7CEFPzJKRQ3fpaNcKD +NTBI5F6GP9ENa/eog4WGENjXS0v4Wa3IfaOhjKXrSxjLUqLH0C8g5WWg5IrXXtuI +pgyJ2kkE3Y/ChU7p7R42we6tBZqF5SiL5kFDn86DmHgCslTiZkIoE5i644sp03Sd +XkHyHu0VIeYp3nDwRA7S98837W4F6i1BnXA5f3EaE3rNGjsxK8zL2pvdCcDYbese +ETfba16HMzLXe1b4RSI3gwhlQ2MNKBwvskkQESf/Ew1DskBY0MCYFxo6hIp6LqMo +HAl5kvCwvuYL2jBdQhkKxU+Leu5Ei8Ie9XYNVy4yUeUAMnSUkVaEs/I8z+Mk8oYq +4QWqOc66XLcI13coDoxmv54kye3RjqdmZI8mg/3LCFotwceDuXyD43/vVhoTPEnp +CqXafV2pw4y95skMHmktI2qvSahaM4P6GGXl8HqmP3b+8V5mxMhNtVnuUha2kouw +DLNFUTg1cCLahM5SRolyA/XTGh7JOkJMYWPeJwN7l3K+lBtHHfj6DHtKEjUcyZFd ++Z55pDoAERumB6+BCnt6X2/0kEDV219RmsgxkGTWdFs+M7Y6EYYRtlinH4nqL6UD +eHWitYIatAHOvdHeNrbXN9L5P3tsUB4HzFa46WWtKqRtbCVTuPVZdw== +-----END RSA PRIVATE KEY----- + +h. root CRL issuer +-----BEGIN CERTIFICATE----- +MIICKzCCAZSgAwIBAgIBCjANBgkqhkiG9w0BAQQFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDgxNjMwNTdaFw0yOTA0MjUxNjMwNTda +MB8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQCy6RoQ6nMdeGJ6ijfjqDu3tDmeGLgnvfBcUKvcsvz9Ji3m +oGnTzECo1oLV+A4/TJxOlak+ZiQ5KVyvfMcXLJeT6dRpXQZ+uc6TT3SkBq94VFzX +qkk08z42JNdk1s5uyW8nRfg7+xntajQVrysoPYNDhu21cPnjDkRiBsIdS7+75QID +AQABo3cwdTAdBgNVHQ4EFgQUGcJU6xWo66kI1QBvlfTQKxxmx9IwRwYDVR0jBEAw +PoAU59AvsZmWPwU2m+FvYAad3Rmu1oKhI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD +VQQKEwdFeGFtcGxlggEAMAsGA1UdDwQEAwIBAjANBgkqhkiG9w0BAQQFAAOBgQBx +uKL59VInPdCi+8JL4B+S5YjlPL4ZOBHTjS0JlNxtjbGZdfs+3E9PUAdqhMJO4vq7 +XD+hGtgZtwSqGaSUYAtpLdoCr7vvPkcrxYTG2Ak+UiTbZhmJeSswKgFaCmjjdMCy +y64UP2DQfn6Zi0wCfeao0m9s3zRLuJpgaQGiSHTQKA== +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,41E4237825CE0148 + +9nbfd7dsaS+fkFYrU1+wTcevjdRLF/j9DUVQh/2bsFlVEYgeL8A+XpvpbXHYBd7H +oBreofDNseibHe4EgISGPK8RymjYutQqPpbHwXd25jlUuUapvvuCj8V6qnhgpqEo +zXL1Nd2c6KZgdySosyWy8JfIBZJ3kwiSkXVwzs8R4bAGrg1VS80GuszvCv8Fzjoc +LuesX6fViE9yFzLsyOvn/W12DKhTXwiXTQYLUupM8zI9Kpozbea52ZIPMJ9HEiaY +JgwNj05w33VxTe/tq3R9vS2Ee6aM4odi6CQEheLsUAnyE0BTsITKzwwTI25WTv25 +W+gwSF3V49a34MojTdlORq5iH0b3rYl7OMdk+99elJSkyQIbVwwOCFrKuSXYXvV7 +s9iMPFUbi+bZ3oP6zM5kVUcH6KyVeYfkuLf2+k1vPlav8/W5v+WfnvUNOBx76Ira +BzVPYmm2V+YFiFL1hugm5Wv+yyx8QcfgXbvhNHoIEj7hh6Ac48FhtqEcBHjuT/gy +7atJJUdOH6hhmD34hkHGnhcDE15ZOczxTLRC9450h5HKsZ0FILRlCBZLmiedycs2 +zqhUpR4jzDG9jKrlDU4ErfMgPLjveZc3/VT3bc+TYfuC8szCaQ5XX1JVcabZ+HQw +pwmA1ONZDVsFzwbJy9+5bgXX+wLD5kaez8EHNDS5PgqgL0UdrWjdRi6e1RwlTDEw +g/d7TZm/iQeL1iUIfkPA1f0ByYIiyd3XQqiQ/Mf1C16lQkhTHDwofFJdL8otT2Ha +dk6fa7lBOnrpbRKUdpJpYfyqHg80BYNPu6BacVXlYqtJtkFK04qHbA== +-----END RSA PRIVATE KEY----- + +i. CRL issued by root CRL issuer +-----BEGIN X509 CRL----- +MIH2MGECAQEwDQYJKoZIhvcNAQEFBQAwHzELMAkGA1UEBhMCVVMxEDAOBgNVBAoT +B0V4YW1wbGUXDTA5MDgwODE2MzU1MFoXDTI4MTAwNzE2MzU1MFqgDjAMMAoGA1Ud +FAQDAgEAMA0GCSqGSIb3DQEBBQUAA4GBAJCd7e25MruuWJP/KmenGC6CR22pQuG+ +XhRaAtpHkNRls8+TfBxm2PtRrXCAcDb68kNLdwvlAlCUwmL6HOx4VB3r+8QRUlDa +T48wVp1ojGU2b2XbPtXiYZBXW6hBsFHGDJM/IAGJPE2PbVYGlBc23A9V9WyPyThi +9XXG1iOTIJ6u +-----END X509 CRL----- + +j. subca CRL issuer +-----BEGIN CERTIFICATE----- +MIICPTCCAaagAwIBAgIBCzANBgkqhkiG9w0BAQQFADAfMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXhhbXBsZTAeFw0wOTA4MDgxNjMwNThaFw0yOTA0MjUxNjMwNTha +MDExCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlMRAwDgYDVQQLEwdDbGFz +cy0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8KICP0bdOZVlR9gZu7TgD +znXgSMER1IQtompgr1mWeZjX4LmRck3/ogHoxwC4RbNPKI3KIihcVdFHw2jgvE0M +mpf2lI50tmhnLitM8P0/q8xUU/KncipADo4hkM5TbpjPeGUBTGLKzGrq7yyT9Uli +Z74rrp1mS59TxcEI2YQMIQIDAQABo3cwdTAdBgNVHQ4EFgQUDGgpD4L8V3aBJPLx +C7diZ0M0wWMwRwYDVR0jBEAwPoAU59AvsZmWPwU2m+FvYAad3Rmu1oKhI6QhMB8x +CzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFeGFtcGxlggEAMAsGA1UdDwQEAwIBAjAN +BgkqhkiG9w0BAQQFAAOBgQCcXqRge5UuW0duf/XnUWP4hrm4Q9EHJaiHZDYxI+WW +Ca3OXdsrpgGi+RSgeMtQzlZ7YAwyYVV91U4BnX6s/97Vp5xbR3wr8Qbx67inM8Lp +Tuo+e0nyTxwlwi9cSyy5MfJ8jfzaD+n8akhV+sx0Mmiv77YlrShP24lod55gJHKC +vQ== +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,16EC4E2C0855BD5C + +dJHcUsnACMhfESAalWrWrfARnUgGhpp3vupjePUiBJ86YmKaNNr6GAwDukg3EJvs +tboO1QQziLSf9pP7gw82Vp5YctEkk7vJVvCcq3QkZAsjNUHf3m3ne2qg8HngufzY +IS/C3EtKuMr3oqa7P8wvMcsBs1G1ga/YqCWoKzowXhybaYPe20fwUNRtgqgdS5Gy +bAzQB9R+Ua2tCaXb3CBYnrczsYFPhjuULr4qbWgHVBWhnkS3OIz71WqcCoXmvD3s +bsjoZRCJUM6Zavyzs0kVGZogiPdr+KUyzjNNsnxle5cEET6nqkYR16UT/Fvemz9Q +szh/y0gCi1nZb6cw5e9BJyF1GlobzxWyMwwY9L4vZNaBNaVRun+6dRWy0svaPuEy +fV/9Y0/la9scyA5yNHz8xud3Njhj2ghyG5Nqbs3N/pPXRVdh7WNFBnc+L/SIBhhB +/Ha9+OZdqyuMf3G+I1+WVADQr8xQP8/yLEvybZYtssjnuCmQSLPDDQFnp2Z3spax ++AT+T4dRimMjf0mZK/NlRJU9PWqMHzsJGBY1A903oAiiHiRFD10z8vyPBigSDF2W +ct6a8WI1prKho6HbMqeIlSPk+HkdCGZedNNbvRlKl4Y56IsHGAhb3wvQ+94049P9 +wu5thK69jNb7ie3YEefAZTb5kD0h+oB8BILOJ5B29C04JdDe6P6hjGKD7x3nRhHM +nyCUMB/fhYpoXdDhz8CeJ77hFt2zFZRstlDctQsDqLkC0AdvlOFsEFqGM4AkBGcV +f6Y+ykNQB3vEWPZsWqVXHB2vQvk00R55tgu+R5JJ45NLG2TqyOp/4A== +-----END RSA PRIVATE KEY----- + +k. CRL issued by subca CRL issuer +-----BEGIN X509 CRL----- +MIIBLTCBlwIBATANBgkqhkiG9w0BAQIFADAxMQswCQYDVQQGEwJVUzEQMA4GA1UE +ChMHRXhhbXBsZTEQMA4GA1UECxMHQ2xhc3MtMRcNMDkwODA4MTYzNTUxWhcNMjgx +MDA3MTYzNTUxWjAiMCACAQIXDTA5MDgwODE2MzU1MFowDDAKBgNVHRUEAwoBBKAO +MAwwCgYDVR0UBAMCAQAwDQYJKoZIhvcNAQECBQADgYEAbIs7ws4/M24NYrIO0XY6 +UVxni0ZoQa+1R7NwU6unr4jFEVD+W/b+JEMfm0RUmpSa7HrUYsw+NycD3m5CD6VJ +U4iuGGeJvHdrYJiPIYkEiFQnhAGOj8oS/nWtPvDKbuBMZI9atKkypby9At8h9URq +1g/KSIM3rd1PYADdcPsok4I= +-----END X509 CRL----- +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/provider/certpath/DisabledAlgorithms/generate.sh Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,255 @@ +# +# 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. +# + +#!/bin/ksh +# +# needs ksh to run the script. +set -e + +OPENSSL=openssl + +# generate a self-signed root certificate +if [ ! -f root/finished ]; then + if [ ! -d root ]; then + mkdir root + fi + + # SHA1withRSA 1024 + ${OPENSSL} req -x509 -newkey rsa:1024 -keyout root/root_key_1024.pem \ + -out root/root_cert_sha1_1024.pem -subj "/C=US/O=Example" \ + -config openssl.cnf -reqexts cert_issuer -days 7650 -sha1 \ + -passin pass:passphrase -passout pass:passphrase + + # SHA1withRSA 512 + ${OPENSSL} req -x509 -newkey rsa:512 -keyout root/root_key_512.pem \ + -out root/root_cert_sha1_512.pem -subj "/C=US/O=Example" \ + -config openssl.cnf -reqexts cert_issuer -days 7650 -sha1 \ + -passin pass:passphrase -passout pass:passphrase + + # MD2withRSA 2048 + ${OPENSSL} req -x509 -newkey rsa:2048 -keyout root/root_key_2048.pem \ + -out root/root_cert_md2_2048.pem -subj "/C=US/O=Example" \ + -config openssl.cnf -reqexts cert_issuer -days 7650 -md2 \ + -passin pass:passphrase -passout pass:passphrase + + openssl req -newkey rsa:1024 -keyout root/root_crlissuer_key.pem \ + -out root/root_crlissuer_req.pem -subj "/C=US/O=Example" -days 7650 \ + -passin pass:passphrase -passout pass:passphrase + + openssl x509 -req -in root/root_crlissuer_req.pem -extfile openssl.cnf \ + -extensions crl_issuer -CA root/root_cert_sha1_1024.pem \ + -CAkey root/root_key_1024.pem -out root/root_crlissuer_cert.pem \ + -CAcreateserial -CAserial root/root_cert.srl -days 7200 \ + -passin pass:passphrase + + touch root/finished +fi + + +# generate subca cert issuer +if [ ! -f subca/finished ]; then + if [ ! -d subca ]; then + mkdir subca + fi + + # RSA 1024 + ${OPENSSL} req -newkey rsa:1024 -keyout subca/subca_key_1024.pem \ + -out subca/subca_req_1024.pem -subj "/C=US/O=Example/OU=Class-1" \ + -days 7650 -passin pass:passphrase -passout pass:passphrase + + # RSA 512 + ${OPENSSL} req -newkey rsa:512 -keyout subca/subca_key_512.pem \ + -out subca/subca_req_512.pem -subj "/C=US/O=Example/OU=Class-1" \ + -days 7650 -passin pass:passphrase -passout pass:passphrase + + # SHA1withRSA 1024 signed with RSA 1024 + ${OPENSSL} x509 -req -in subca/subca_req_1024.pem -extfile openssl.cnf \ + -extensions cert_issuer -CA root/root_cert_sha1_1024.pem \ + -CAkey root/root_key_1024.pem -out subca/subca_cert_sha1_1024_1024.pem \ + -CAcreateserial -sha1 \ + -CAserial root/root_cert.srl -days 7200 -passin pass:passphrase + + # SHA1withRSA 1024 signed with RSA 512 + ${OPENSSL} x509 -req -in subca/subca_req_1024.pem -extfile openssl.cnf \ + -extensions cert_issuer -CA root/root_cert_sha1_512.pem \ + -CAkey root/root_key_512.pem -out subca/subca_cert_sha1_1024_512.pem \ + -CAcreateserial -sha1 \ + -CAserial root/root_cert.srl -days 7200 -passin pass:passphrase + + # SHA1withRSA 512 signed with RSA 1024 + ${OPENSSL} x509 -req -in subca/subca_req_512.pem -extfile openssl.cnf \ + -extensions cert_issuer -CA root/root_cert_sha1_1024.pem \ + -CAkey root/root_key_1024.pem -out subca/subca_cert_sha1_512_1024.pem \ + -CAcreateserial -sha1 \ + -CAserial root/root_cert.srl -days 7200 -passin pass:passphrase + + # SHA1withRSA 512 signed with RSA 512 + ${OPENSSL} x509 -req -in subca/subca_req_512.pem -extfile openssl.cnf \ + -extensions cert_issuer -CA root/root_cert_sha1_512.pem \ + -CAkey root/root_key_512.pem -out subca/subca_cert_sha1_512_512.pem \ + -CAcreateserial -sha1 \ + -CAserial root/root_cert.srl -days 7200 -passin pass:passphrase + + # MD2withRSA 1024 signed with RSA 1024 + ${OPENSSL} x509 -req -in subca/subca_req_1024.pem -extfile openssl.cnf \ + -extensions cert_issuer -CA root/root_cert_sha1_1024.pem \ + -CAkey root/root_key_1024.pem -out subca/subca_cert_md2_1024_1024.pem \ + -CAcreateserial -md2 \ + -CAserial root/root_cert.srl -days 7200 -passin pass:passphrase + + # MD2withRSA 1024 signed with RSA 512 + ${OPENSSL} x509 -req -in subca/subca_req_1024.pem -extfile openssl.cnf \ + -extensions cert_issuer -CA root/root_cert_sha1_512.pem \ + -CAkey root/root_key_512.pem -out subca/subca_cert_md2_1024_512.pem \ + -CAcreateserial -md2 \ + -CAserial root/root_cert.srl -days 7200 -passin pass:passphrase + + openssl req -newkey rsa:1024 -keyout subca/subca_crlissuer_key.pem \ + -out subca/subca_crlissuer_req.pem -subj "/C=US/O=Example/OU=Class-1" \ + -days 7650 -passin pass:passphrase -passout pass:passphrase + + openssl x509 -req -in subca/subca_crlissuer_req.pem -extfile openssl.cnf \ + -extensions crl_issuer -CA root/root_cert_sha1_1024.pem \ + -CAkey root/root_key_1024.pem -out subca/subca_crlissuer_cert.pem \ + -CAcreateserial -CAserial root/root_cert.srl -days 7200 \ + -passin pass:passphrase + + touch subca/finished +fi + + +# generate certifiacte for Alice +if [ ! -f subca/alice/finished ]; then + if [ ! -d subca/alice ]; then + mkdir -p subca/alice + fi + + # RSA 1024 + ${OPENSSL} req -newkey rsa:1024 -keyout subca/alice/alice_key_1024.pem \ + -out subca/alice/alice_req_1024.pem \ + -subj "/C=US/O=Example/OU=Class-1/CN=Alice" -days 7650 \ + -passin pass:passphrase -passout pass:passphrase + + # RSA 512 + ${OPENSSL} req -newkey rsa:512 -keyout subca/alice/alice_key_512.pem \ + -out subca/alice/alice_req_512.pem \ + -subj "/C=US/O=Example/OU=Class-1/CN=Alice" -days 7650 \ + -passin pass:passphrase -passout pass:passphrase + + # SHA1withRSA 1024 signed with RSA 1024 + ${OPENSSL} x509 -req -in subca/alice/alice_req_1024.pem \ + -extfile openssl.cnf -extensions ee_of_subca \ + -CA subca/subca_cert_sha1_1024_1024.pem \ + -CAkey subca/subca_key_1024.pem \ + -out subca/alice/alice_cert_sha1_1024_1024.pem -CAcreateserial -sha1 \ + -CAserial subca/subca_cert.srl -days 7200 -passin pass:passphrase + + # SHA1withRSA 1024 signed with RSA 512 + ${OPENSSL} x509 -req -in subca/alice/alice_req_1024.pem \ + -extfile openssl.cnf -extensions ee_of_subca \ + -CA subca/subca_cert_sha1_512_1024.pem \ + -CAkey subca/subca_key_512.pem \ + -out subca/alice/alice_cert_sha1_1024_512.pem -CAcreateserial -sha1 \ + -CAserial subca/subca_cert.srl -days 7200 -passin pass:passphrase + + # SHA1withRSA 512 signed with RSA 1024 + ${OPENSSL} x509 -req -in subca/alice/alice_req_512.pem \ + -extfile openssl.cnf -extensions ee_of_subca \ + -CA subca/subca_cert_sha1_1024_1024.pem \ + -CAkey subca/subca_key_1024.pem \ + -out subca/alice/alice_cert_sha1_512_1024.pem -CAcreateserial -sha1 \ + -CAserial subca/subca_cert.srl -days 7200 -passin pass:passphrase + + # SHA1withRSA 512 signed with RSA 512 + ${OPENSSL} x509 -req -in subca/alice/alice_req_512.pem \ + -extfile openssl.cnf -extensions ee_of_subca \ + -CA subca/subca_cert_sha1_512_1024.pem \ + -CAkey subca/subca_key_512.pem \ + -out subca/alice/alice_cert_sha1_512_512.pem -CAcreateserial -sha1 \ + -CAserial subca/subca_cert.srl -days 7200 -passin pass:passphrase + + # MD2withRSA 1024 signed with RSA 1024 + ${OPENSSL} x509 -req -in subca/alice/alice_req_1024.pem \ + -extfile openssl.cnf -extensions ee_of_subca \ + -CA subca/subca_cert_sha1_1024_1024.pem \ + -CAkey subca/subca_key_1024.pem \ + -out subca/alice/alice_cert_md2_1024_1024.pem -CAcreateserial -md2 \ + -CAserial subca/subca_cert.srl -days 7200 -passin pass:passphrase + + # MD2withRSA 1024 signed with RSA 512 + ${OPENSSL} x509 -req -in subca/alice/alice_req_1024.pem \ + -extfile openssl.cnf -extensions ee_of_subca \ + -CA subca/subca_cert_sha1_512_1024.pem \ + -CAkey subca/subca_key_512.pem \ + -out subca/alice/alice_cert_md2_1024_512.pem -CAcreateserial -md2 \ + -CAserial subca/subca_cert.srl -days 7200 -passin pass:passphrase + + touch subca/alice/finished +fi + +if [ ! -f root/revoked ]; then + if [ ! -d root ]; then + mkdir root + fi + + if [ ! -f root/index.txt ]; then + touch root/index.txt + echo 00 > root/crlnumber + fi + + openssl ca -gencrl -config openssl.cnf -name ca_top -crldays 7000 -md sha1 \ + -crl_reason superseded -keyfile root/root_crlissuer_key.pem \ + -cert root/root_crlissuer_cert.pem -out root/top_crl.pem \ + -passin pass:passphrase + + touch root/revoked +fi + +if [ ! -f subca/revoked ]; then + if [ ! -d subca ]; then + mkdir subca + fi + + if [ ! -f subca/index.txt ]; then + touch subca/index.txt + echo 00 > subca/crlnumber + fi + + # revoke alice's SHA1withRSA 1024 signed with RSA 1024 + openssl ca -revoke subca/alice/alice_cert_sha1_1024_1024.pem \ + -config openssl.cnf \ + -name ca_subca -crl_reason superseded \ + -keyfile subca/subca_crlissuer_key.pem \ + -cert subca/subca_crlissuer_cert.pem -passin pass:passphrase + + openssl ca -gencrl -config openssl.cnf \ + -name ca_subca -crldays 7000 -md md2 \ + -crl_reason superseded -keyfile subca/subca_crlissuer_key.pem \ + -cert subca/subca_crlissuer_cert.pem \ + -out subca/subca_crl.pem \ + -passin pass:passphrase + + touch subca/revoked +fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/provider/certpath/DisabledAlgorithms/openssl.cnf Thu Nov 12 23:04:42 2009 +0000 @@ -0,0 +1,206 @@ +# +# 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. +# + +# +# OpenSSL configuration file. +# + +HOME = . +RANDFILE = $ENV::HOME/.rnd + +[ ca ] +default_ca = CA_default + +[ CA_default ] +dir = ./top +certs = $dir/certs +crl_dir = $dir/crl +database = $dir/index.txt +unique_subject = no +new_certs_dir = $dir/newcerts +certificate = $dir/cacert.pem +serial = $dir/serial +crlnumber = $dir/crlnumber +crl = $dir/crl.pem +private_key = $dir/private/cakey.pem +RANDFILE = $dir/private/.rand +x509_extensions = v3_ca + +name_opt = ca_default +cert_opt = ca_default + +default_days = 7650 +default_crl_days = 30 +default_md = sha1 +preserve = no + +policy = policy_anything + +[ ca_top ] +dir = ./root +certs = $dir/certs +crl_dir = $dir/crl +database = $dir/index.txt +unique_subject = no +new_certs_dir = $dir/newcerts +certificate = $dir/cacert.pem +serial = $dir/serial +crlnumber = $dir/crlnumber +crl = $dir/crl.pem +private_key = $dir/private/cakey.pem +RANDFILE = $dir/private/.rand + +x509_extensions = v3_ca + +name_opt = ca_default +cert_opt = ca_default + +default_days = 7650 +default_crl_days = 30 +default_md = sha1 +preserve = no + +policy = policy_anything + +[ ca_subca ] +dir = ./subca +certs = $dir/certs +crl_dir = $dir/crl +database = $dir/index.txt +unique_subject = no +new_certs_dir = $dir/newcerts + +certificate = $dir/cacert.pem +serial = $dir/serial +crlnumber = $dir/crlnumber +crl = $dir/crl.pem +private_key = $dir/private/cakey.pem +RANDFILE = $dir/private/.rand + +x509_extensions = usr_cert + +name_opt = ca_default +cert_opt = ca_default + +default_days = 7650 +default_crl_days = 30 +default_md = sha1 +preserve = no + +policy = policy_anything + +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca + +string_mask = nombstr + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = NO +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = A-State + +localityName = Locality Name (eg, city) + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Internet Widgits Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) + +commonName = Common Name (eg, YOUR name) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 +unstructuredName = An optional company name + + +[ usr_cert ] +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer + +[ v3_req ] +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectAltName = email:example@openjdk.net, RID:1.2.3.4:true + +[ v3_ca ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer:always +basicConstraints = critical,CA:true +keyUsage = keyCertSign + +[ cert_issuer ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer:always +basicConstraints = critical,CA:true +keyUsage = keyCertSign + + +[ crl_issuer ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer:always +keyUsage = cRLSign + + +[ crl_ext ] +authorityKeyIdentifier = keyid:always,issuer:always + +[ ee_of_subca ] +keyUsage = nonRepudiation, digitalSignature, keyEncipherment, keyAgreement + +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/util/DerValue/BadValue.java Thu Nov 12 23:04:42 2009 +0000 @@ -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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6864911 + * @summary ASN.1/DER input stream parser needs more work + */ + +import java.io.*; +import sun.security.util.*; +import sun.misc.IOUtils; + +public class BadValue { + + public static void main(String[] args) throws Exception { + + // Test IOUtils.readFully + + // We have 4 bytes + InputStream in = new ByteArrayInputStream(new byte[10]); + byte[] bs = IOUtils.readFully(in, 4, true); + if (bs.length != 4 || in.available() != 6) { + throw new Exception("First read error"); + } + // But only 6 left + bs = IOUtils.readFully(in, 10, false); + if (bs.length != 6 || in.available() != 0) { + throw new Exception("Second read error"); + } + // MAX read as much as it can + in = new ByteArrayInputStream(new byte[10]); + bs = IOUtils.readFully(in, Integer.MAX_VALUE, true); + if (bs.length != 10 || in.available() != 0) { + throw new Exception("Second read error"); + } + // MAX ignore readAll + in = new ByteArrayInputStream(new byte[10]); + bs = IOUtils.readFully(in, Integer.MAX_VALUE, false); + if (bs.length != 10 || in.available() != 0) { + throw new Exception("Second read error"); + } + // 20>10, readAll means failure + in = new ByteArrayInputStream(new byte[10]); + try { + bs = IOUtils.readFully(in, 20, true); + throw new Exception("Third read error"); + } catch (EOFException e) { + // OK + } + int bignum = 10 * 1024 * 1024; + bs = IOUtils.readFully(new SuperSlowStream(bignum), -1, true); + if (bs.length != bignum) { + throw new Exception("Fourth read error"); + } + + // Test DerValue + byte[] input = {0x04, (byte)0x84, 0x40, 0x00, 0x42, 0x46, 0x4b}; + try { + new DerValue(new ByteArrayInputStream(input)); + } catch (IOException ioe) { + // This is OK + } + } +} + +/** + * An InputStream contains a given number of bytes, but only returns one byte + * per read. + */ +class SuperSlowStream extends InputStream { + private int p; + /** + * @param Initial capacity + */ + public SuperSlowStream(int capacity) { + p = capacity; + } + @Override + public int read() throws IOException { + if (p > 0) { + p--; + return 0; + } else { + return -1; + } + } + @Override + public int read(byte b[], int off, int len) throws IOException { + if (len == 0) return 0; + if (p > 0) { + p--; + b[off] = 0; + return 1; + } else { + return -1; + } + } +}