# HG changeset patch # User jwilhelm # Date 1478879076 -3600 # Node ID 95af45781076898add1fbb5a6af12dec97ae18ca # Parent f71b844f33d1c25b65775c26b048157052cca69b# Parent 31f5023200d42185b70c4c00ba5672391e4642d0 Merge diff -r f71b844f33d1 -r 95af45781076 .hgtags --- a/.hgtags Mon Nov 14 11:15:43 2016 +0100 +++ b/.hgtags Fri Nov 11 16:44:36 2016 +0100 @@ -384,3 +384,5 @@ 65477538bec32963dc41153d89c4417eb46c45fc jdk-9+139 0875007901f7d364a08220b052f0c81003e9c8c5 jdk-9+140 9aadd2163b568d76f8969ad2fb404a63733da359 jdk-9+141 +df0e03e3ca0ed1307793017dfc1a054c8726131c jdk-9+142 +d62173b931bf5b6bffc6e80a9060bb2e8b8efc75 jdk-9+143 diff -r f71b844f33d1 -r 95af45781076 .hgtags-top-repo --- a/.hgtags-top-repo Mon Nov 14 11:15:43 2016 +0100 +++ b/.hgtags-top-repo Fri Nov 11 16:44:36 2016 +0100 @@ -384,3 +384,5 @@ 7dcf453eacae79ee86a6bcc75fd0b546fc99b48a jdk-9+139 a5815c6098a241d3a1df64d22b84b3524e4a77df jdk-9+140 f64afae7f1a5608e438585bbf0bc23785e69cba0 jdk-9+141 +2b3e5caafe3594ea507c37675c4d3086f415dc64 jdk-9+142 +1fc62b1c629fb80fdaa639d3b59452a184f0d705 jdk-9+143 diff -r f71b844f33d1 -r 95af45781076 common/autoconf/flags.m4 --- a/common/autoconf/flags.m4 Mon Nov 14 11:15:43 2016 +0100 +++ b/common/autoconf/flags.m4 Fri Nov 11 16:44:36 2016 +0100 @@ -280,7 +280,7 @@ else # Default works for linux, might work on other platforms as well. SHARED_LIBRARY_FLAGS='-shared' - SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$$$ORIGIN[$]1' + SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$ORIGIN[$]1' SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN" SET_SHARED_LIBRARY_NAME='-Wl,-soname=[$]1' SET_SHARED_LIBRARY_MAPFILE='-Wl,-version-script=[$]1' @@ -305,7 +305,7 @@ # Default works for linux, might work on other platforms as well. PICFLAG='-fPIC' SHARED_LIBRARY_FLAGS='-shared' - SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$$$ORIGIN[$]1' + SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$ORIGIN[$]1' SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN" SET_SHARED_LIBRARY_NAME='-Wl,-soname=[$]1' SET_SHARED_LIBRARY_MAPFILE='-Wl,-version-script=[$]1' @@ -315,7 +315,7 @@ C_FLAG_REORDER='-xF' CXX_FLAG_REORDER='-xF' SHARED_LIBRARY_FLAGS="-G" - SET_EXECUTABLE_ORIGIN='-R\$$$$ORIGIN[$]1' + SET_EXECUTABLE_ORIGIN='-R\$$ORIGIN[$]1' SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN" SET_SHARED_LIBRARY_NAME='-h [$]1' SET_SHARED_LIBRARY_MAPFILE='-M[$]1' @@ -759,6 +759,10 @@ # on ppc we don't prevent gcc to omit frame pointer but do prevent strict aliasing $2CFLAGS_JDK="${$2CFLAGS_JDK} -fno-strict-aliasing" ;; + s390 ) + $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -fno-omit-frame-pointer -mbackchain -march=z10" + $2CFLAGS_JDK="${$2CFLAGS_JDK} -fno-strict-aliasing" + ;; * ) $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK -fno-omit-frame-pointer" $2CFLAGS_JDK="${$2CFLAGS_JDK} -fno-strict-aliasing" @@ -940,6 +944,10 @@ # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. $2JVM_CFLAGS="[$]$2JVM_CFLAGS -mcpu=power7 -mtune=power8" fi + elif test "x$OPENJDK_$1_CPU" = xs390x; then + if test "x$OPENJDK_$1_OS" = xlinux; then + $2JVM_CFLAGS="[$]$2JVM_CFLAGS -mbackchain -march=z10" + fi fi if test "x$OPENJDK_$1_CPU_ENDIAN" = xlittle; then @@ -999,6 +1007,7 @@ # Setup some hard coded includes $2COMMON_CCXXFLAGS_JDK="[$]$2COMMON_CCXXFLAGS_JDK \ + -I\$(SUPPORT_OUTPUTDIR)/modules_include/java.base \ -I${JDK_TOPDIR}/src/java.base/share/native/include \ -I${JDK_TOPDIR}/src/java.base/$OPENJDK_$1_OS/native/include \ -I${JDK_TOPDIR}/src/java.base/$OPENJDK_$1_OS_TYPE/native/include \ diff -r f71b844f33d1 -r 95af45781076 common/autoconf/generated-configure.sh --- a/common/autoconf/generated-configure.sh Mon Nov 14 11:15:43 2016 +0100 +++ b/common/autoconf/generated-configure.sh Fri Nov 11 16:44:36 2016 +0100 @@ -5093,7 +5093,7 @@ #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1477108079 +DATE_WHEN_GENERATED=1478524503 ############################################################################### # @@ -49070,7 +49070,7 @@ else # Default works for linux, might work on other platforms as well. SHARED_LIBRARY_FLAGS='-shared' - SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$$$ORIGIN$1' + SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$ORIGIN$1' SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN" SET_SHARED_LIBRARY_NAME='-Wl,-soname=$1' SET_SHARED_LIBRARY_MAPFILE='-Wl,-version-script=$1' @@ -49095,7 +49095,7 @@ # Default works for linux, might work on other platforms as well. PICFLAG='-fPIC' SHARED_LIBRARY_FLAGS='-shared' - SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$$$ORIGIN$1' + SET_EXECUTABLE_ORIGIN='-Wl,-rpath,\$$ORIGIN$1' SET_SHARED_LIBRARY_ORIGIN="-Wl,-z,origin $SET_EXECUTABLE_ORIGIN" SET_SHARED_LIBRARY_NAME='-Wl,-soname=$1' SET_SHARED_LIBRARY_MAPFILE='-Wl,-version-script=$1' @@ -49105,7 +49105,7 @@ C_FLAG_REORDER='-xF' CXX_FLAG_REORDER='-xF' SHARED_LIBRARY_FLAGS="-G" - SET_EXECUTABLE_ORIGIN='-R\$$$$ORIGIN$1' + SET_EXECUTABLE_ORIGIN='-R\$$ORIGIN$1' SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN" SET_SHARED_LIBRARY_NAME='-h $1' SET_SHARED_LIBRARY_MAPFILE='-M$1' @@ -49840,6 +49840,10 @@ # on ppc we don't prevent gcc to omit frame pointer but do prevent strict aliasing CFLAGS_JDK="${CFLAGS_JDK} -fno-strict-aliasing" ;; + s390 ) + COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -fno-omit-frame-pointer -mbackchain -march=z10" + CFLAGS_JDK="${CFLAGS_JDK} -fno-strict-aliasing" + ;; * ) COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -fno-omit-frame-pointer" CFLAGS_JDK="${CFLAGS_JDK} -fno-strict-aliasing" @@ -50122,6 +50126,10 @@ # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. JVM_CFLAGS="$JVM_CFLAGS -mcpu=power7 -mtune=power8" fi + elif test "x$OPENJDK_TARGET_CPU" = xs390x; then + if test "x$OPENJDK_TARGET_OS" = xlinux; then + JVM_CFLAGS="$JVM_CFLAGS -mbackchain -march=z10" + fi fi if test "x$OPENJDK_TARGET_CPU_ENDIAN" = xlittle; then @@ -50270,6 +50278,7 @@ # Setup some hard coded includes COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK \ + -I\$(SUPPORT_OUTPUTDIR)/modules_include/java.base \ -I${JDK_TOPDIR}/src/java.base/share/native/include \ -I${JDK_TOPDIR}/src/java.base/$OPENJDK_TARGET_OS/native/include \ -I${JDK_TOPDIR}/src/java.base/$OPENJDK_TARGET_OS_TYPE/native/include \ @@ -50655,6 +50664,10 @@ # on ppc we don't prevent gcc to omit frame pointer but do prevent strict aliasing OPENJDK_BUILD_CFLAGS_JDK="${OPENJDK_BUILD_CFLAGS_JDK} -fno-strict-aliasing" ;; + s390 ) + OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -fno-omit-frame-pointer -mbackchain -march=z10" + OPENJDK_BUILD_CFLAGS_JDK="${OPENJDK_BUILD_CFLAGS_JDK} -fno-strict-aliasing" + ;; * ) OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK -fno-omit-frame-pointer" OPENJDK_BUILD_CFLAGS_JDK="${OPENJDK_BUILD_CFLAGS_JDK} -fno-strict-aliasing" @@ -50937,6 +50950,10 @@ # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -mcpu=power7 -mtune=power8" fi + elif test "x$OPENJDK_BUILD_CPU" = xs390x; then + if test "x$OPENJDK_BUILD_OS" = xlinux; then + OPENJDK_BUILD_JVM_CFLAGS="$OPENJDK_BUILD_JVM_CFLAGS -mbackchain -march=z10" + fi fi if test "x$OPENJDK_BUILD_CPU_ENDIAN" = xlittle; then @@ -51085,6 +51102,7 @@ # Setup some hard coded includes OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK \ + -I\$(SUPPORT_OUTPUTDIR)/modules_include/java.base \ -I${JDK_TOPDIR}/src/java.base/share/native/include \ -I${JDK_TOPDIR}/src/java.base/$OPENJDK_BUILD_OS/native/include \ -I${JDK_TOPDIR}/src/java.base/$OPENJDK_BUILD_OS_TYPE/native/include \ diff -r f71b844f33d1 -r 95af45781076 common/autoconf/spec.gmk.in --- a/common/autoconf/spec.gmk.in Mon Nov 14 11:15:43 2016 +0100 +++ b/common/autoconf/spec.gmk.in Fri Nov 11 16:44:36 2016 +0100 @@ -265,6 +265,10 @@ BUNDLES_OUTPUTDIR=$(BUILD_OUTPUT)/bundles TESTMAKE_OUTPUTDIR=$(BUILD_OUTPUT)/test-make MAKESUPPORT_OUTPUTDIR=$(BUILD_OUTPUT)/make-support + +# By default, output javadoc directly into image +JAVADOC_OUTPUTDIR = $(DOCS_IMAGE_DIR) + # This does not get overridden in a bootcycle build CONFIGURESUPPORT_OUTPUTDIR:=@CONFIGURESUPPORT_OUTPUTDIR@ BUILDJDK_OUTPUTDIR=$(BUILD_OUTPUT)/buildjdk @@ -784,11 +788,12 @@ SYMBOLS_IMAGE_DIR=$(IMAGES_OUTPUTDIR)/$(SYMBOLS_IMAGE_SUBDIR) # Interim image +INTERIM_JMODS_DIR := $(SUPPORT_OUTPUTDIR)/interim-jmods INTERIM_IMAGE_DIR := $(SUPPORT_OUTPUTDIR)/interim-image # Docs image DOCS_IMAGE_SUBDIR := docs -DOCS_IMAGE_DIR := $(IMAGES_OUTPUTDIR)/$(DOCS_IMAGE_SUBDIR) +DOCS_IMAGE_DIR = $(IMAGES_OUTPUTDIR)/$(DOCS_IMAGE_SUBDIR) # Macosx bundles directory definitions JDK_MACOSX_BUNDLE_SUBDIR=jdk-bundle diff -r f71b844f33d1 -r 95af45781076 corba/.hgtags --- a/corba/.hgtags Mon Nov 14 11:15:43 2016 +0100 +++ b/corba/.hgtags Fri Nov 11 16:44:36 2016 +0100 @@ -384,3 +384,5 @@ 8c9da7fc5b07c606afd571c7012441b77dda83b2 jdk-9+139 9f3fc931bc230f44f2a58d75f7f6360af98bb113 jdk-9+140 b32f998da32b488ec7c4e9dbb3c750841b48e74d jdk-9+141 +408c9c621938ca028e20bced0459f815de47eba8 jdk-9+142 +6211236ef15ec796806357608b1dd1b70c258ece jdk-9+143 diff -r f71b844f33d1 -r 95af45781076 hotspot/.hgtags --- a/hotspot/.hgtags Mon Nov 14 11:15:43 2016 +0100 +++ b/hotspot/.hgtags Fri Nov 11 16:44:36 2016 +0100 @@ -544,3 +544,5 @@ 08492e67bf3226784dab3bf9ae967382ddbc1af5 jdk-9+139 fec31089c2ef5a12dd64f401b0bf2e00f56ee0d0 jdk-9+140 160a00bc6ed0af1fdf8418fc65e6bddbbc0c536d jdk-9+141 +7b48d63dfd6b8e2657288de3d7b1f153dee02d7e jdk-9+142 +d87d5d430c42342f0320ca7f5cbe0cbd1f9d62ba jdk-9+143 diff -r f71b844f33d1 -r 95af45781076 hotspot/make/gensrc/GensrcJvmti.gmk --- a/hotspot/make/gensrc/GensrcJvmti.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/hotspot/make/gensrc/GensrcJvmti.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -135,14 +135,14 @@ # Copy jvmti.h to include dir # The file is the same regardless of jvm variant. Only let one do the copy. -#ifeq ($(JVM_VARIANT), $(firstword $(JVM_VARIANTS))) -# $(eval $(call SetupCopyFiles, COPY_JVMTI_H, \ -# DEST := $(SUPPORT_OUTPUTDIR)/modules_include/java.base, \ -# FILES := $(JVMTI_OUTPUTDIR)/jvmti.h, \ -# )) +ifeq ($(JVM_VARIANT), $(firstword $(JVM_VARIANTS))) + $(eval $(call SetupCopyFiles, COPY_JVMTI_H, \ + DEST := $(SUPPORT_OUTPUTDIR)/modules_include/java.base, \ + FILES := $(JVMTI_OUTPUTDIR)/jvmti.h, \ + )) -# TARGETS += $(COPY_JVMTI_H) -#endif + TARGETS += $(COPY_JVMTI_H) +endif ################################################################################ # Create trace files in gensrc/tracefiles diff -r f71b844f33d1 -r 95af45781076 hotspot/make/symbols/symbols-unix --- a/hotspot/make/symbols/symbols-unix Mon Nov 14 11:15:43 2016 +0100 +++ b/hotspot/make/symbols/symbols-unix Fri Nov 11 16:44:36 2016 +0100 @@ -125,7 +125,6 @@ JVM_GetProtectionDomain JVM_GetSimpleBinaryName JVM_GetStackAccessControlContext -JVM_GetStackTraceElements JVM_GetSystemPackage JVM_GetSystemPackages JVM_GetTemporaryDirectory @@ -135,6 +134,8 @@ JVM_HoldsLock JVM_IHashCode JVM_InitProperties +JVM_InitStackTraceElement +JVM_InitStackTraceElementArray JVM_InternString JVM_Interrupt JVM_InvokeMethod @@ -178,7 +179,6 @@ JVM_StopThread JVM_SupportsCX8 JVM_SuspendThread -JVM_ToStackTraceElement JVM_TotalMemory JVM_UnloadLibrary JVM_WaitForReferencePendingList diff -r f71b844f33d1 -r 95af45781076 hotspot/src/share/vm/classfile/javaClasses.cpp --- a/hotspot/src/share/vm/classfile/javaClasses.cpp Mon Nov 14 11:15:43 2016 +0100 +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Fri Nov 11 16:44:36 2016 +0100 @@ -2175,6 +2175,14 @@ const char* str = holder->external_name(); oop classname = StringTable::intern((char*) str, CHECK); java_lang_StackTraceElement::set_declaringClass(element(), classname); + java_lang_StackTraceElement::set_declaringClassObject(element(), holder->java_mirror()); + + oop loader = holder->class_loader(); + if (loader != NULL) { + oop loader_name = java_lang_ClassLoader::name(loader); + if (loader_name != NULL) + java_lang_StackTraceElement::set_classLoaderName(element(), loader_name); + } // The method can be NULL if the requested class version is gone Symbol* sym = !method.is_null() ? method->name() : holder->constants()->symbol_at(cpref); @@ -3433,6 +3441,7 @@ bool java_lang_ClassLoader::offsets_computed = false; int java_lang_ClassLoader::_loader_data_offset = -1; int java_lang_ClassLoader::parallelCapable_offset = -1; +int java_lang_ClassLoader::name_offset = -1; int java_lang_ClassLoader::unnamedModule_offset = -1; ClassLoaderData** java_lang_ClassLoader::loader_data_addr(oop loader) { @@ -3453,6 +3462,9 @@ compute_optional_offset(parallelCapable_offset, k1, vmSymbols::parallelCapable_name(), vmSymbols::concurrenthashmap_signature()); + compute_offset(name_offset, + k1, vmSymbols::name_name(), vmSymbols::string_signature()); + compute_offset(unnamedModule_offset, k1, vmSymbols::unnamedModule_name(), vmSymbols::module_signature()); @@ -3464,6 +3476,11 @@ return loader->obj_field(parent_offset); } +oop java_lang_ClassLoader::name(oop loader) { + assert(is_instance(loader), "loader must be oop"); + return loader->obj_field(name_offset); +} + bool java_lang_ClassLoader::isAncestor(oop loader, oop cl) { assert(is_instance(loader), "loader must be oop"); assert(cl == NULL || is_instance(cl), "cl argument must be oop"); @@ -3619,12 +3636,14 @@ int java_lang_System::static_out_offset; int java_lang_System::static_err_offset; int java_lang_System::static_security_offset; -int java_lang_StackTraceElement::declaringClass_offset; int java_lang_StackTraceElement::methodName_offset; int java_lang_StackTraceElement::fileName_offset; int java_lang_StackTraceElement::lineNumber_offset; int java_lang_StackTraceElement::moduleName_offset; int java_lang_StackTraceElement::moduleVersion_offset; +int java_lang_StackTraceElement::classLoaderName_offset; +int java_lang_StackTraceElement::declaringClass_offset; +int java_lang_StackTraceElement::classOrLoaderModuleClassName_offset; int java_lang_StackFrameInfo::_declaringClass_offset; int java_lang_StackFrameInfo::_memberName_offset; int java_lang_StackFrameInfo::_bci_offset; @@ -3669,6 +3688,14 @@ element->obj_field_put(moduleVersion_offset, value); } +void java_lang_StackTraceElement::set_classLoaderName(oop element, oop value) { + element->obj_field_put(classLoaderName_offset, value); +} + +void java_lang_StackTraceElement::set_declaringClassObject(oop element, oop value) { + element->obj_field_put(classOrLoaderModuleClassName_offset, value); +} + // Support for java_lang_StackFrameInfo void java_lang_StackFrameInfo::set_declaringClass(oop element, oop value) { element->obj_field_put(_declaringClass_offset, value); @@ -3784,6 +3811,8 @@ java_lang_System::static_security_offset = java_lang_System::hc_static_security_offset * x; // java_lang_StackTraceElement + java_lang_StackTraceElement::classOrLoaderModuleClassName_offset= java_lang_StackTraceElement::hc_classOrLoaderModuleClassName_offset* x + header; + java_lang_StackTraceElement::classLoaderName_offset = java_lang_StackTraceElement::hc_classLoaderName_offset * x + header; java_lang_StackTraceElement::moduleName_offset = java_lang_StackTraceElement::hc_moduleName_offset * x + header; java_lang_StackTraceElement::moduleVersion_offset = java_lang_StackTraceElement::hc_moduleVersion_offset * x + header; java_lang_StackTraceElement::declaringClass_offset = java_lang_StackTraceElement::hc_declaringClass_offset * x + header; @@ -3985,10 +4014,14 @@ // java.lang.StackTraceElement - CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, declaringClass, "Ljava/lang/String;"); - CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, methodName, "Ljava/lang/String;"); - CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, fileName, "Ljava/lang/String;"); - CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, lineNumber, "I"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, classOrLoaderModuleClassName, "Ljava/lang/Object;"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, classLoaderName, "Ljava/lang/String;"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, moduleName, "Ljava/lang/String;"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, moduleVersion, "Ljava/lang/String;"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, declaringClass, "Ljava/lang/String;"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, methodName, "Ljava/lang/String;"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, fileName, "Ljava/lang/String;"); + CHECK_OFFSET("java/lang/StackTraceElement", java_lang_StackTraceElement, lineNumber, "I"); // java.lang.ref.Reference diff -r f71b844f33d1 -r 95af45781076 hotspot/src/share/vm/classfile/javaClasses.hpp --- a/hotspot/src/share/vm/classfile/javaClasses.hpp Mon Nov 14 11:15:43 2016 +0100 +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Fri Nov 11 16:44:36 2016 +0100 @@ -1225,6 +1225,7 @@ static bool offsets_computed; static int parent_offset; static int parallelCapable_offset; + static int name_offset; static int unnamedModule_offset; public: @@ -1234,6 +1235,7 @@ static ClassLoaderData* loader_data(oop loader); static oop parent(oop loader); + static oop name(oop loader); static bool isAncestor(oop loader, oop cl); // Support for parallelCapable field @@ -1291,14 +1293,18 @@ class java_lang_StackTraceElement: AllStatic { private: enum { - hc_moduleName_offset = 0, - hc_moduleVersion_offset = 1, - hc_declaringClass_offset = 2, - hc_methodName_offset = 3, - hc_fileName_offset = 4, - hc_lineNumber_offset = 5 + hc_classOrLoaderModuleClassName_offset = 0, + hc_classLoaderName_offset = 1, + hc_moduleName_offset = 2, + hc_moduleVersion_offset = 3, + hc_declaringClass_offset = 4, + hc_methodName_offset = 5, + hc_fileName_offset = 6, + hc_lineNumber_offset = 7 }; + static int classOrLoaderModuleClassName_offset; + static int classLoaderName_offset; static int moduleName_offset; static int moduleVersion_offset; static int declaringClass_offset; @@ -1307,12 +1313,14 @@ static int lineNumber_offset; // Setters + static void set_classLoaderName(oop element, oop value); static void set_moduleName(oop element, oop value); static void set_moduleVersion(oop element, oop value); static void set_declaringClass(oop element, oop value); static void set_methodName(oop element, oop value); static void set_fileName(oop element, oop value); static void set_lineNumber(oop element, int value); + static void set_declaringClassObject(oop element, oop value); public: // Create an instance of StackTraceElement diff -r f71b844f33d1 -r 95af45781076 hotspot/src/share/vm/prims/jvm.cpp --- a/hotspot/src/share/vm/prims/jvm.cpp Mon Nov 14 11:15:43 2016 +0100 +++ b/hotspot/src/share/vm/prims/jvm.cpp Fri Nov 11 16:44:36 2016 +0100 @@ -503,16 +503,27 @@ JVM_END -JVM_ENTRY(void, JVM_GetStackTraceElements(JNIEnv *env, jobject throwable, jobjectArray stackTrace)) - JVMWrapper("JVM_GetStackTraceElements"); +// java.lang.StackTraceElement ////////////////////////////////////////////// + + +JVM_ENTRY(void, JVM_InitStackTraceElementArray(JNIEnv *env, jobjectArray elements, jobject throwable)) + JVMWrapper("JVM_InitStackTraceElementArray"); Handle exception(THREAD, JNIHandles::resolve(throwable)); - objArrayOop st = objArrayOop(JNIHandles::resolve(stackTrace)); + objArrayOop st = objArrayOop(JNIHandles::resolve(elements)); objArrayHandle stack_trace(THREAD, st); // Fill in the allocated stack trace java_lang_Throwable::get_stack_trace_elements(exception, stack_trace, CHECK); JVM_END +JVM_ENTRY(void, JVM_InitStackTraceElement(JNIEnv* env, jobject element, jobject stackFrameInfo)) + JVMWrapper("JVM_InitStackTraceElement"); + Handle stack_frame_info(THREAD, JNIHandles::resolve_non_null(stackFrameInfo)); + Handle stack_trace_element(THREAD, JNIHandles::resolve_non_null(element)); + java_lang_StackFrameInfo::to_stack_trace_element(stack_frame_info, stack_trace_element, THREAD); +JVM_END + + // java.lang.StackWalker ////////////////////////////////////////////////////// @@ -566,13 +577,6 @@ start_index, frames_array_h, THREAD); JVM_END -JVM_ENTRY(void, JVM_ToStackTraceElement(JNIEnv *env, jobject frame, jobject stack)) - JVMWrapper("JVM_ToStackTraceElement"); - Handle stack_frame_info(THREAD, JNIHandles::resolve_non_null(frame)); - Handle stack_trace_element(THREAD, JNIHandles::resolve_non_null(stack)); - java_lang_StackFrameInfo::to_stack_trace_element(stack_frame_info, stack_trace_element, THREAD); -JVM_END - // java.lang.Object /////////////////////////////////////////////// diff -r f71b844f33d1 -r 95af45781076 hotspot/src/share/vm/prims/jvm.h --- a/hotspot/src/share/vm/prims/jvm.h Mon Nov 14 11:15:43 2016 +0100 +++ b/hotspot/src/share/vm/prims/jvm.h Fri Nov 11 16:44:36 2016 +0100 @@ -189,8 +189,14 @@ JNIEXPORT void JNICALL JVM_FillInStackTrace(JNIEnv *env, jobject throwable); +/* + * java.lang.StackTraceElement + */ JNIEXPORT void JNICALL -JVM_GetStackTraceElements(JNIEnv *env, jobject throwable, jobjectArray elements); +JVM_InitStackTraceElementArray(JNIEnv *env, jobjectArray elements, jobject throwable); + +JNIEXPORT void JNICALL +JVM_InitStackTraceElement(JNIEnv* env, jobject element, jobject stackFrameInfo); /* * java.lang.StackWalker @@ -212,9 +218,6 @@ jint frame_count, jint start_index, jobjectArray frames); -JNIEXPORT void JNICALL -JVM_ToStackTraceElement(JNIEnv* env, jobject frame, jobject stackElement); - /* * java.lang.Thread */ diff -r f71b844f33d1 -r 95af45781076 jaxp/.hgtags --- a/jaxp/.hgtags Mon Nov 14 11:15:43 2016 +0100 +++ b/jaxp/.hgtags Fri Nov 11 16:44:36 2016 +0100 @@ -384,3 +384,5 @@ 8991d71c5316bde259e6a417c1199b008ca3cdf0 jdk-9+139 8d100cb9b04819b5bd09f33c7fd5b8628d1a456f jdk-9+140 037c095ba0c345edbeaaab52fda913a76c3930c0 jdk-9+141 +bdafa0cc34a97a2f8db4847a4efd34b407943591 jdk-9+142 +ce81d03ad7320dca3d673374c1a33bc0efd9136a jdk-9+143 diff -r f71b844f33d1 -r 95af45781076 jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java Fri Nov 11 16:44:36 2016 +0100 @@ -746,42 +746,18 @@ // scan XMLDecl try { if (fEntityScanner.skipString(xmlDecl)) { - fMarkupDepth++; - // NOTE: special case where document starts with a PI - // whose name starts with "xml" (e.g. "xmlfoo") - if (XMLChar.isName(fEntityScanner.peekChar())) { - fStringBuffer.clear(); - fStringBuffer.append("xml"); - while (XMLChar.isName(fEntityScanner.peekChar())) { - fStringBuffer.append((char)fEntityScanner.scanChar(null)); - } - String target = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length); - //this function should fill the data.. and set the fEvent object to this event. - fContentBuffer.clear() ; - scanPIData(target, fContentBuffer); - //REVISIT:where else we can set this value to 'true' - fEntityManager.fCurrentEntity.mayReadChunks = true; - //return PI event since PI was encountered - return XMLEvent.PROCESSING_INSTRUCTION ; + if (fEntityScanner.peekChar() == ' ') { + fMarkupDepth++; + scanXMLDeclOrTextDecl(false); + } else { + // PI, reset position + fEntityManager.fCurrentEntity.position = 0; } - // standard XML declaration - else { - scanXMLDeclOrTextDecl(false); - //REVISIT:where else we can set this value to 'true' - fEntityManager.fCurrentEntity.mayReadChunks = true; - return XMLEvent.START_DOCUMENT; - } - } else{ - //REVISIT:where else we can set this value to 'true' - fEntityManager.fCurrentEntity.mayReadChunks = true; - //In both case return the START_DOCUMENT. ony difference is that first block will - //cosume the XML declaration if any. - return XMLEvent.START_DOCUMENT; } - //START_OF_THE_DOCUMENT - + fEntityManager.fCurrentEntity.mayReadChunks = true; + return XMLEvent.START_DOCUMENT; } diff -r f71b844f33d1 -r 95af45781076 jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java --- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java Fri Nov 11 16:44:36 2016 +0100 @@ -46,7 +46,10 @@ */ public interface XMLEventReader extends Iterator { /** - * Get the next XMLEvent + * Gets the next XMLEvent. The initial event is + * {@link javax.xml.stream.events.StartDocument StartDocument}. + * + * @return the next XMLEvent * @see XMLEvent * @throws XMLStreamException if there is an error with the underlying XML. * @throws java.util.NoSuchElementException iteration has no more elements. @@ -58,12 +61,15 @@ * Returns true if there are more events and false otherwise. * @return true if the event reader has more events, false otherwise */ + @Override public boolean hasNext(); /** * Check the next XMLEvent without reading it from the stream. * Returns null if the stream is at EOF or has no more XMLEvents. * A call to peek() will be equal to the next return of next(). + * + * @return the next XMLEvent * @see XMLEvent * @throws XMLStreamException */ @@ -73,6 +79,8 @@ * Reads the content of a text-only element. Precondition: * the current event is START_ELEMENT. Postcondition: * The current event is the corresponding END_ELEMENT. + * + * @return the text of the element * @throws XMLStreamException if the current event is not a START_ELEMENT * or if a non text element is encountered */ @@ -85,6 +93,8 @@ * be used when processing element-only content because * the parser is not able to recognize ignorable whitespace if * the DTD is missing or not interpreted. + * + * @return a START_ELEMENT or END_ELEMENT * @throws XMLStreamException if anything other than space characters are encountered */ public XMLEvent nextTag() throws XMLStreamException; diff -r f71b844f33d1 -r 95af45781076 jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java --- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java Fri Nov 11 16:44:36 2016 +0100 @@ -28,7 +28,6 @@ package javax.xml.stream; -import java.io.Reader; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; @@ -37,19 +36,26 @@ * It is designed to be the lowest level and most efficient way to * read XML data. * - *

The XMLStreamReader is designed to iterate over XML using + *

+ * The XMLStreamReader is designed to iterate over XML using * next() and hasNext(). The data can be accessed using methods such as getEventType(), * getNamespaceURI(), getLocalName() and getText(); * - *

The next() method causes the reader to read the next parse event. - * The next() method returns an integer which identifies the type of event just read. - *

The event type can be determined using getEventType(). - *

Parsing events are defined as the XML Declaration, a DTD, + *

+ * An XMLStreamReader instance is created with an initial event type START_DOCUMENT. + * At any moment in time, it has a current event that the methods of the interface + * access and may load the next event through the {@link #next() next()} method. + * The current event type can be determined by {@link #getEventType getEventType()}, and + * the next returned by the {@link #next() next()} method. + * + *

+ * Parsing events are defined as the XML Declaration, a DTD, * start tag, character data, white space, end tag, comment, * or processing instruction. An attribute or namespace event may be encountered * at the root level of a document as the result of a query operation. * - *

For XML 1.0 compliance an XML processor must pass the + *

+ * For XML 1.0 compliance an XML processor must pass the * identifiers of declared unparsed entities, notation declarations and their * associated identifiers to the application. This information is * provided through the property API on this interface. @@ -63,7 +69,8 @@ * These properties can only be accessed during a DTD event and * are defined to return null if the information is not available. * - *

The following table describes which methods are valid in what state. + *

+ * The following table describes which methods are valid in what state. * If a method is called in an invalid state the method will throw a * java.lang.IllegalStateException. * @@ -502,8 +509,10 @@ // public void recycle() throws XMLStreamException; /** - * Returns an integer code that indicates the type - * of the event the cursor is pointing to. + * Returns an integer code that indicates the type of the event the cursor is + * pointing to. The initial event type is {@link #START_DOCUMENT}. + * + * @return the type of the current event */ public int getEventType(); @@ -590,6 +599,8 @@ /** * Returns the offset into the text character array where the first * character (of this text event) is stored. + * + * @return the starting position of the text in the character array * @throws java.lang.IllegalStateException if this state is not * a valid text state. */ @@ -598,6 +609,8 @@ /** * Returns the length of the sequence of characters for this * Text event within the text character array. + * + * @return the length of the text * @throws java.lang.IllegalStateException if this state is not * a valid text state. */ @@ -610,9 +623,11 @@ public String getEncoding(); /** - * Return true if the current event has text, false otherwise + * Return a boolean indicating whether the current event has text. * The following events have text: * CHARACTERS,DTD ,ENTITY_REFERENCE, COMMENT, SPACE + * + * @return true if the event has text, false otherwise */ public boolean hasText(); @@ -623,6 +638,7 @@ * location and null for the publicId and systemId. * The location information is only valid until next() is * called. + * @return the location of the cursor */ public Location getLocation(); @@ -647,8 +663,10 @@ public String getLocalName(); /** - * returns true if the current event has a name (is a START_ELEMENT or END_ELEMENT) - * returns false otherwise + * returns a boolean indicating whether the current event has a name + * (is a START_ELEMENT or END_ELEMENT). + * + * @return true if the event has a name, false otherwise */ public boolean hasName(); diff -r f71b844f33d1 -r 95af45781076 jaxp/test/javax/xml/jaxp/functional/javax/xml/parsers/ptests/SAXParserTest.java --- a/jaxp/test/javax/xml/jaxp/functional/javax/xml/parsers/ptests/SAXParserTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/parsers/ptests/SAXParserTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -24,20 +24,16 @@ package javax.xml.parsers.ptests; import static javax.xml.parsers.ptests.ParserTestConst.XML_DIR; -import static jaxp.library.JAXPTestUtilities.USER_DIR; import static jaxp.library.JAXPTestUtilities.tryRunWithTmpPermission; import java.io.File; import java.io.FileInputStream; -import java.io.FilePermission; import java.io.IOException; import java.util.PropertyPermission; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; -import jaxp.library.JAXPTestUtilities; - import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @@ -189,8 +185,7 @@ */ @Test(expectedExceptions = { SAXException.class, IOException.class }, dataProvider = "parser-provider") public void testParse09(SAXParser saxparser) throws Exception { - JAXPTestUtilities.tryRunWithTmpPermission(() -> saxparser.parse(" ", new DefaultHandler()), - new FilePermission(USER_DIR + " ", "read")); + saxparser.parse("no-such-file", new DefaultHandler()); } /** diff -r f71b844f33d1 -r 95af45781076 jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogInvalidPathTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogInvalidPathTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package catalog; + +import javax.xml.catalog.CatalogFeatures; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/* + * @test + * @bug 8151154 + * @run testng/othervm catalog.CatalogInvalidPathTest + * @summary Verifies that the CatalogFeatures' builder throws + * IllegalArgumentException on invalid file inputs. + * This test was splitted from CatalogTest.java due to + * JDK-8168968, it has to only run without SecurityManager + * because an ACE will be thrown for invalid path. + */ +public class CatalogInvalidPathTest { + /* + DataProvider: for testing the verification of file paths by + the CatalogFeatures builder + */ + @DataProvider(name = "invalidPaths") + public Object[][] getFiles() { + return new Object[][]{ + {null}, + {""}, + {"file:a/b\\c"}, + {"file:/../../.."}, + {"c:/te:t"}, + {"c:/te?t"}, + {"c/te*t"}, + {"in|valid.txt"}, + {"shema:invalid.txt"}, + }; + } + + @Test(dataProvider = "invalidPaths", expectedExceptions = IllegalArgumentException.class) + public void testFileInput(String file) { + CatalogFeatures features = CatalogFeatures.builder() + .with(CatalogFeatures.Feature.FILES, file) + .build(); + } +} diff -r f71b844f33d1 -r 95af45781076 jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java --- a/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -23,18 +23,16 @@ package catalog; import static jaxp.library.JAXPTestUtilities.clearSystemProperty; -import static jaxp.library.JAXPTestUtilities.getSystemProperty; import static jaxp.library.JAXPTestUtilities.setSystemProperty; import java.io.File; import java.io.FileInputStream; -import java.io.FilePermission; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.io.StringWriter; import java.nio.file.Paths; -import java.util.PropertyPermission; + import javax.xml.XMLConstants; import javax.xml.catalog.Catalog; import javax.xml.catalog.CatalogException; @@ -57,7 +55,6 @@ import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; -import jaxp.library.JAXPTestUtilities; import org.testng.Assert; import org.testng.annotations.BeforeClass; @@ -73,7 +70,7 @@ /* * @test - * @bug 8081248 8144966 8146606 8146237 8151154 8150969 8151162 8152527 8154220 8163232 + * @bug 8081248 8144966 8146606 8146237 8150969 8151162 8152527 8154220 8163232 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest * @run testng/othervm -DrunSecMngr=true catalog.CatalogTest * @run testng/othervm catalog.CatalogTest @@ -459,21 +456,6 @@ Catalog catalog = CatalogManager.catalog(features, catalogFile); } - /** - * @bug 8151154 - * Verifies that the CatalogFeatures' builder throws IllegalArgumentException - * on invalid file inputs. - * @param file the file path - */ - @Test(dataProvider = "invalidPaths", expectedExceptions = IllegalArgumentException.class) - public void testFileInput(String file) { - JAXPTestUtilities.runWithTmpPermission(() -> { - CatalogFeatures features = CatalogFeatures.builder() - .with(CatalogFeatures.Feature.FILES, file) - .build(); - }, new FilePermission("/../../..", "read"), new FilePermission("c:\\te:t", "read"), - new FilePermission("c:\\te?t", "read"), new PropertyPermission("user.dir", "read")); - } /** * @bug 8146237 @@ -736,24 +718,6 @@ }; } - /* - DataProvider: for testing the verification of file paths by - the CatalogFeatures builder - */ - @DataProvider(name = "invalidPaths") - public Object[][] getFiles() { - return new Object[][]{ - {null}, - {""}, - {"file:a/b\\c"}, - {"file:/../../.."}, - {"c:/te:t"}, - {"c:/te?t"}, - {"c/te*t"}, - {"in|valid.txt"}, - {"shema:invalid.txt"}, - }; - } /* DataProvider: provides test name, expected string, the catalog, and XML diff -r f71b844f33d1 -r 95af45781076 jaxp/test/javax/xml/jaxp/unittest/stream/XMLStreamReaderTest/BugTest.java --- a/jaxp/test/javax/xml/jaxp/unittest/stream/XMLStreamReaderTest/BugTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jaxp/test/javax/xml/jaxp/unittest/stream/XMLStreamReaderTest/BugTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. 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 @@ -24,17 +24,20 @@ package stream.XMLStreamReaderTest; import java.io.StringReader; +import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamReader; import org.testng.Assert; +import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; /* * @test + * @bug 8069098 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest * @run testng/othervm -DrunSecMngr=true stream.XMLStreamReaderTest.BugTest * @run testng/othervm stream.XMLStreamReaderTest.BugTest @@ -43,11 +46,70 @@ @Listeners({jaxp.library.BasePolicy.class}) public class BugTest { - @Test - public static void test1() throws Exception { - XMLInputFactory xif = XMLInputFactory.newInstance(); // new - // com.sun.xml.stream.ZephyrParserFactory(); - XMLStreamReader r = xif.createXMLStreamReader(new StringReader("")); - Assert.assertEquals(XMLStreamConstants.START_DOCUMENT, r.getEventType()); + /** + * Verifies that the initial event of an XMLStreamReader instance is + * START_DOCUMENT. + * + * @param xml the xml input + * @param type1 the type of the 1st event + * @param type2 the type of the 2nd event + * @throws Exception if the test fails to run properly + */ + @Test(dataProvider = "xmls") + public static void test1(String xml, int type1, int type2) throws Exception { + XMLInputFactory factory = XMLInputFactory.newFactory(); + + XMLStreamReader reader = factory.createXMLStreamReader(new StringReader(xml)); + int type1stEvent = reader.getEventType(); + int type2ndEvent = reader.next(); + System.out.println("First event: " + type1stEvent); + System.out.println("2nd event: " + type2ndEvent); + Assert.assertEquals(type1, type1stEvent); + Assert.assertEquals(type2, type2ndEvent); + } + + + /** + * Verifies that the initial event of an XMLEventReader instance is + * START_DOCUMENT. XMLEventReader depends on XMLStreamReader. + * + * @param xml the xml input + * @param type1 the type of the 1st event + * @param type2 the type of the 2nd event + * @throws Exception if the test fails to run properly + */ + @Test(dataProvider = "xmls") + public static void test2(String xml, int type1, int type2) throws Exception { + XMLInputFactory factory = XMLInputFactory.newFactory(); + + XMLEventReader reader = factory.createXMLEventReader(new StringReader(xml)); + int type1stEvent = reader.nextEvent().getEventType(); + int type2ndEvent = reader.nextEvent().getEventType(); + System.out.println("First event: " + type1stEvent); + System.out.println("2nd event: " + type2ndEvent); + Assert.assertEquals(type1, type1stEvent); + Assert.assertEquals(type2, type2ndEvent); + } + + /* + DataProvider: for testing beginning event type + Data: xml, 1st event type, 2nd event type + */ + @DataProvider(name = "xmls") + public Object[][] getXMLs() { + + return new Object[][]{ + {"", + XMLStreamConstants.START_DOCUMENT, XMLStreamConstants.START_ELEMENT}, + {"", + XMLStreamConstants.START_DOCUMENT, XMLStreamConstants.START_ELEMENT}, + {"" + + "" + + "", + XMLStreamConstants.START_DOCUMENT, XMLStreamConstants.PROCESSING_INSTRUCTION}, + {"" + + "", + XMLStreamConstants.START_DOCUMENT, XMLStreamConstants.PROCESSING_INSTRUCTION}, + }; } } diff -r f71b844f33d1 -r 95af45781076 jaxws/.hgtags --- a/jaxws/.hgtags Mon Nov 14 11:15:43 2016 +0100 +++ b/jaxws/.hgtags Fri Nov 11 16:44:36 2016 +0100 @@ -387,3 +387,5 @@ 7a7aadf3c4500cc273c889aa1172d4fe3844bb6b jdk-9+139 9004617323fe99cbe4fad48f373cb2ed4fc50aa6 jdk-9+140 b2c18f755228d1d19a86cd7d5fa1abb6b1495dfb jdk-9+141 +59101416d90160cfcb4f45dfbccaec15e2c27a29 jdk-9+142 +1c988e708a06257119d54d8a57e99e3b0f37ff18 jdk-9+143 diff -r f71b844f33d1 -r 95af45781076 jdk/.hgtags --- a/jdk/.hgtags Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/.hgtags Fri Nov 11 16:44:36 2016 +0100 @@ -384,3 +384,5 @@ 5518ac2f2ead5e594bd983f2047178136aafdfd0 jdk-9+139 e93b7ea559759f036c9f69fd2ddaf47bb4e98385 jdk-9+140 8d752af5f61d41f226adf2cda72a20faa9ad620a jdk-9+141 +6ce43dd8e954b452f330dd7a412df5107f7e1923 jdk-9+142 +8dbc8594f9d5149bf1c22221272284609408227a jdk-9+143 diff -r f71b844f33d1 -r 95af45781076 jdk/make/GenerateClasslist.gmk --- a/jdk/make/GenerateClasslist.gmk Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -# -# Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -################################################################################ -# Generate classlist -################################################################################ - -default: all - -include $(SPEC) -include MakeBase.gmk -include Tools.gmk -include JarArchive.gmk - -################################################################################ -# Create a jar with our generator class. Using a jar is intentional since it -# will load more classes - -$(eval $(call SetupJarArchive, CLASSLIST_JAR, \ - SRCS := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes, \ - INCLUDES := build/tools/classlist, \ - JAR := $(SUPPORT_OUTPUTDIR)/classlist.jar, \ -)) - -TARGETS += $(CLASSLIST_JAR) - -################################################################################ - -CLASSLIST_FILE := $(SUPPORT_OUTPUTDIR)/classlist/classlist - -JLI_TRACE_FILE := $(SUPPORT_OUTPUTDIR)/classlist/jli_trace.out - -# If an external buildjdk has been supplied, we don't build a separate interim -# image, so just use the external build jdk instead. -ifeq ($(EXTERNAL_BUILDJDK), true) - INTERIM_IMAGE_DIR := $(BUILD_JDK) -endif - -$(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXE_SUFFIX) $(CLASSLIST_JAR) - $(call MakeDir, $(@D)) - $(call LogInfo, Generating lib/classlist) - $(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@ \ - -Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true \ - -cp $(SUPPORT_OUTPUTDIR)/classlist.jar \ - build.tools.classlist.HelloClasslist \ - $(LOG_DEBUG) 2>&1 > $(JLI_TRACE_FILE) - -TARGETS += $(CLASSLIST_FILE) - -################################################################################ - -all: $(TARGETS) diff -r f71b844f33d1 -r 95af45781076 jdk/make/copy/Copy-java.base.gmk --- a/jdk/make/copy/Copy-java.base.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/make/copy/Copy-java.base.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -33,7 +33,6 @@ # TARGETS += \ $(INCLUDE_DST_DIR)/jni.h \ - $(INCLUDE_DST_DIR)/jvmti.h \ $(INCLUDE_DST_DIR)/jvmticmlr.h \ $(INCLUDE_DST_DIR)/classfile_constants.h \ $(INCLUDE_DST_OS_DIR)/jni_md.h \ diff -r f71b844f33d1 -r 95af45781076 jdk/make/data/tzdata/VERSION --- a/jdk/make/data/tzdata/VERSION Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/make/data/tzdata/VERSION Fri Nov 11 16:44:36 2016 +0100 @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2016g +tzdata2016h diff -r f71b844f33d1 -r 95af45781076 jdk/make/data/tzdata/asia --- a/jdk/make/data/tzdata/asia Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/make/data/tzdata/asia Fri Nov 11 16:44:36 2016 +0100 @@ -2567,11 +2567,6 @@ # From Paul Eggert (2015-03-03): # http://www.timeanddate.com/time/change/west-bank/ramallah?year=2014 # says that the fall 2014 transition was Oct 23 at 24:00. -# For future dates, guess the last Friday in March at 24:00 through -# the first Friday on or after October 21 at 00:00. This is consistent with -# the predictions in today's editions of the following URLs: -# http://www.timeanddate.com/time/change/gaza-strip/gaza -# http://www.timeanddate.com/time/change/west-bank/hebron # From Hannah Kreitem (2016-03-09): # http://www.palestinecabinet.gov.ps/WebSite/ar/ViewDetails?ID=31728 @@ -2581,7 +2576,21 @@ # # From Paul Eggert (2016-03-12): # Predict spring transitions on March's last Saturday at 01:00 from now on. -# Leave fall predictions alone for now. + +# From Sharef Mustafa (2016-10-19): +# [T]he Palestinian cabinet decision (Mar 8th 2016) published on +# http://www.palestinecabinet.gov.ps/WebSite/Upload/Decree/GOV_17/16032016134830.pdf +# states that summer time will end on Oct 29th at 01:00. +# +# From Tim Parenti (2016-10-19): +# Predict fall transitions on October's last Saturday at 01:00 from now on. +# This is consistent with the 2016 transition as well as our spring +# predictions. +# +# From Paul Eggert (2016-10-19): +# It's also consistent with predictions in the following URLs today: +# http://www.timeanddate.com/time/change/gaza-strip/gaza +# http://www.timeanddate.com/time/change/west-bank/hebron # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule EgyptAsia 1957 only - May 10 0:00 1:00 S @@ -2610,9 +2619,10 @@ Rule Palestine 2012 2014 - Mar lastThu 24:00 1:00 S Rule Palestine 2012 only - Sep 21 1:00 0 - Rule Palestine 2013 only - Sep Fri>=21 0:00 0 - -Rule Palestine 2014 max - Oct Fri>=21 0:00 0 - +Rule Palestine 2014 2015 - Oct Fri>=21 0:00 0 - Rule Palestine 2015 only - Mar lastFri 24:00 1:00 S Rule Palestine 2016 max - Mar lastSat 1:00 1:00 S +Rule Palestine 2016 max - Oct lastSat 1:00 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Gaza 2:17:52 - LMT 1900 Oct @@ -2762,45 +2772,31 @@ # People who live in regions under Tamil control can use [TZ='Asia/Kolkata'], # as that zone has agreed with the Tamil areas since our cutoff date of 1970. -# From K Sethu (2006-04-25): -# I think the abbreviation LKT originated from the world of computers at -# the time of or subsequent to the time zone changes by SL Government -# twice in 1996 and probably SL Government or its standardization -# agencies never declared an abbreviation as a national standard. -# -# I recollect before the recent change the government announcements -# mentioning it as simply changing Sri Lanka Standard Time or Sri Lanka -# Time and no mention was made about the abbreviation. +# From Sadika Sumanapala (2016-10-19): +# According to http://www.sltime.org (maintained by Measurement Units, +# Standards & Services Department, Sri Lanka) abbreviation for Sri Lanka +# standard time is SLST. # -# If we look at Sri Lanka Department of Government's "Official News -# Website of Sri Lanka" ... http://www.news.lk/ we can see that they -# use SLT as abbreviation in time stamp at the beginning of each news -# item.... -# -# Within Sri Lanka I think LKT is well known among computer users and -# administrators. In my opinion SLT may not be a good choice because the -# nation's largest telcom / internet operator Sri Lanka Telcom is well -# known by that abbreviation - simply as SLT (there IP domains are -# slt.lk and sltnet.lk). -# -# But if indeed our government has adopted SLT as standard abbreviation -# (that we have not known so far) then it is better that it be used for -# all computers. - -# From Paul Eggert (2006-04-25): -# One possibility is that we wait for a bit for the dust to settle down -# and then see what people actually say in practice. +# From Paul Eggert (2016-10-18): +# "SLST" seems to be reasonably recent and rarely-used outside time +# zone nerd sources. I searched Google News and found three uses of +# it in the International Business Times of India in February and +# March of this year when discussing cricket match times, but nothing +# since then (though there has been a lot of cricket) and nothing in +# other English-language news sources. Our old abbreviation "LKT" is +# even worse. For now, let's use a numeric abbreviation; we can +# switch to "SLST" if it catches on. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Colombo 5:19:24 - LMT 1880 5:19:32 - MMT 1906 # Moratuwa Mean Time - 5:30 - IST 1942 Jan 5 - 5:30 0:30 IHST 1942 Sep - 5:30 1:00 IST 1945 Oct 16 2:00 - 5:30 - IST 1996 May 25 0:00 - 6:30 - LKT 1996 Oct 26 0:30 - 6:00 - LKT 2006 Apr 15 0:30 - 5:30 - IST + 5:30 - +0530 1942 Jan 5 + 5:30 0:30 +0530/+06 1942 Sep + 5:30 1:00 +0530/+0630 1945 Oct 16 2:00 + 5:30 - +0530 1996 May 25 0:00 + 6:30 - +0630 1996 Oct 26 0:30 + 6:00 - +06 2006 Apr 15 0:30 + 5:30 - +0530 # Syria # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S diff -r f71b844f33d1 -r 95af45781076 jdk/make/data/tzdata/australasia --- a/jdk/make/data/tzdata/australasia Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/make/data/tzdata/australasia Fri Nov 11 16:44:36 2016 +0100 @@ -373,7 +373,13 @@ # commencing at 2.00 am on Sunday 1st November, 2015 and ending at # 3.00 am on Sunday 17th January, 2016. -# From Paul Eggert (2015-09-01): +# From Raymond Kumar (2016-10-04): +# http://www.fiji.gov.fj/Media-Center/Press-Releases/DAYLIGHT-SAVING-STARTS-ON-6th-NOVEMBER,-2016.aspx +# "Fiji's daylight savings will begin on Sunday, 6 November 2016, when +# clocks go forward an hour at 2am to 3am.... Daylight Saving will +# end at 3.00am on Sunday 15th January 2017." + +# From Paul Eggert (2016-10-03): # For now, guess DST from 02:00 the first Sunday in November to # 03:00 the third Sunday in January. Although ad hoc, it matches # transitions since late 2014 and seems more likely to match future diff -r f71b844f33d1 -r 95af45781076 jdk/make/data/tzdata/europe --- a/jdk/make/data/tzdata/europe Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/make/data/tzdata/europe Fri Nov 11 16:44:36 2016 +0100 @@ -1931,7 +1931,7 @@ # Amsterdam mean time. # The data entries before 1945 are taken from -# http://www.phys.uu.nl/~vgent/wettijd/wettijd.htm +# http://www.staff.science.uu.nl/~gent0113/idl/idl.htm # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Neth 1916 only - May 1 0:00 1:00 NST # Netherlands Summer Time @@ -3450,22 +3450,24 @@ # Turkey -# From Amar Devegowda (2007-01-03): -# The time zone rules for Istanbul, Turkey have not been changed for years now. -# ... The latest rules are available at: -# http://www.timeanddate.com/worldclock/timezone.html?n=107 -# From Steffen Thorsen (2007-01-03): -# I have been able to find press records back to 1996 which all say that -# DST started 01:00 local time and end at 02:00 local time. I am not sure -# what happened before that. One example for each year from 1996 to 2001: -# http://newspot.byegm.gov.tr/arsiv/1996/21/N4.htm -# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING97/03/97X03X25.TXT -# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING98/03/98X03X02.HTM -# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING99/10/99X10X26.HTM#%2016 -# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING2000/03/00X03X06.HTM#%2021 -# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING2001/03/23x03x01.HTM#%2027 -# From Paul Eggert (2007-01-03): -# Prefer the above source to Shanks & Pottenger for time stamps after 1990. +# From Kıvanç Yazan (2016-09-25): +# 1) For 1986-2006, DST started at 01:00 local and ended at 02:00 local, with +# no exceptions. +# 2) 1994's lastSun was overridden with Mar 20 ... +# Here are official papers: +# http://www.resmigazete.gov.tr/arsiv/19032.pdf - page 2 for 1986 +# http://www.resmigazete.gov.tr/arsiv/19400.pdf - page 4 for 1987 +# http://www.resmigazete.gov.tr/arsiv/19752.pdf - page 15 for 1988 +# http://www.resmigazete.gov.tr/arsiv/20102.pdf - page 6 for 1989 +# http://www.resmigazete.gov.tr/arsiv/20464.pdf - page 1 for 1990 - 1992 +# http://www.resmigazete.gov.tr/arsiv/21531.pdf - page 15 for 1993 - 1995 +# http://www.resmigazete.gov.tr/arsiv/21879.pdf - page 1 for overriding 1994 +# http://www.resmigazete.gov.tr/arsiv/22588.pdf - page 1 for 1996, 1997 +# http://www.resmigazete.gov.tr/arsiv/23286.pdf - page 10 for 1998 - 2000 +# http://www.resmigazete.gov.tr/eskiler/2001/03/20010324.htm#2 - for 2001 +# http://www.resmigazete.gov.tr/eskiler/2002/03/20020316.htm#2 - for 2002-2006 +# From Paul Eggert (2016-09-25): +# Prefer the above sources to Shanks & Pottenger for time stamps after 1985. # From Steffen Thorsen (2007-03-09): # Starting 2007 though, it seems that they are adopting EU's 1:00 UTC @@ -3574,10 +3576,10 @@ Rule Turkey 1983 only - Oct 2 0:00 0 - Rule Turkey 1985 only - Apr 20 0:00 1:00 S Rule Turkey 1985 only - Sep 28 0:00 0 - -Rule Turkey 1986 1990 - Mar lastSun 2:00s 1:00 S -Rule Turkey 1986 1990 - Sep lastSun 2:00s 0 - -Rule Turkey 1991 2006 - Mar lastSun 1:00s 1:00 S -Rule Turkey 1991 1995 - Sep lastSun 1:00s 0 - +Rule Turkey 1986 1993 - Mar lastSun 1:00s 1:00 S +Rule Turkey 1986 1995 - Sep lastSun 1:00s 0 - +Rule Turkey 1994 only - Mar 20 1:00s 1:00 S +Rule Turkey 1995 2006 - Mar lastSun 1:00s 1:00 S Rule Turkey 1996 2006 - Oct lastSun 1:00s 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Europe/Istanbul 1:55:52 - LMT 1880 diff -r f71b844f33d1 -r 95af45781076 jdk/make/data/tzdata/northamerica --- a/jdk/make/data/tzdata/northamerica Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/make/data/tzdata/northamerica Fri Nov 11 16:44:36 2016 +0100 @@ -47,8 +47,32 @@ # was the result of his proposals at the Convention of Railroad Trunk Lines # in New York City (1869-10). His 1870 proposal was based on Washington, DC, # but in 1872-05 he moved the proposed origin to Greenwich. -# His proposal was adopted by the railroads on 1883-11-18 at 12:00, -# and the most of the country soon followed suit. + +# From Paul Eggert (2016-09-21): +# Dowd's proposal left many details unresolved, such as where to draw +# lines between time zones. The key individual who made time zones +# work in the US was William Frederick Allen - railway engineer, +# managing editor of the Travelers' Guide, and secretary of the +# General Time Convention, a railway standardization group. Allen +# spent months in dialogs with scientific and railway leaders, +# developed a workable plan to institute time zones, and presented it +# to the General Time Convention on 1883-04-11, saying that his plan +# meant "local time would be practically abolished" - a plus for +# railway scheduling. By the next convention on 1883-10-11 nearly all +# railroads had agreed and it took effect on 1883-11-18 at 12:00. +# That Sunday was called the "day of two noons", as the eastern parts +# of the new zones observed noon twice. Allen witnessed the +# transition in New York City, writing: +# +# I heard the bells of St. Paul's strike on the old time. Four +# minutes later, obedient to the electrical signal from the Naval +# Observatory ... the time-ball made its rapid descent, the chimes +# of old Trinity rang twelve measured strokes, and local time was +# abandoned, probably forever. +# +# Most of the US soon followed suit. See: +# Bartky IR. The adoption of standard time. Technol Cult 1989 Jan;30(1):25-56. +# http://dx.doi.org/10.2307/3105430 # From Paul Eggert (2005-04-16): # That 1883 transition occurred at 12:00 new time, not at 12:00 old time. diff -r f71b844f33d1 -r 95af45781076 jdk/make/gendata/GendataBreakIterator.gmk --- a/jdk/make/gendata/GendataBreakIterator.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/make/gendata/GendataBreakIterator.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -55,7 +55,6 @@ $(eval $(call SetupJavaCompilation,BUILD_BREAKITERATOR_LD, \ SETUP := GENERATE_OLDBYTECODE, \ SRC := $(JDK_TOPDIR)/src/jdk.localedata/share/classes, \ - INCLUDES := $(TEXT_PKG_LD), \ INCLUDE_FILES := \ $(TEXT_PKG_LD)/BreakIteratorRules_th.java \ $(TEXT_PKG_LD)/BreakIteratorInfo_th.java, \ diff -r f71b844f33d1 -r 95af45781076 jdk/make/mapfiles/libjava/mapfile-vers --- a/jdk/make/mapfiles/libjava/mapfile-vers Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/make/mapfiles/libjava/mapfile-vers Fri Nov 11 16:44:36 2016 +0100 @@ -140,7 +140,6 @@ Java_java_lang_Double_doubleToRawLongBits; Java_java_lang_Float_intBitsToFloat; Java_java_lang_Float_floatToRawIntBits; - Java_java_lang_StackFrameInfo_toStackTraceElement0; Java_java_lang_StackStreamFactory_checkStackWalkModes; Java_java_lang_StackStreamFactory_00024AbstractStackWalker_callStackWalk; Java_java_lang_StackStreamFactory_00024AbstractStackWalker_fetchStackFrames; @@ -215,6 +214,8 @@ Java_java_lang_SecurityManager_currentLoadedClass0; Java_java_lang_SecurityManager_getClassContext; Java_java_lang_Shutdown_halt0; + Java_java_lang_StackTraceElement_initStackTraceElement; + Java_java_lang_StackTraceElement_initStackTraceElements; Java_java_lang_String_intern; Java_java_lang_StringCoding_err; Java_java_lang_StringUTF16_isBigEndian; @@ -227,7 +228,6 @@ Java_java_lang_System_setOut0; Java_java_lang_Thread_registerNatives; Java_java_lang_Throwable_fillInStackTrace; - Java_java_lang_Throwable_getStackTraceElements; Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2; Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2; Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2; diff -r f71b844f33d1 -r 95af45781076 jdk/make/mapfiles/libjava/reorder-sparc --- a/jdk/make/mapfiles/libjava/reorder-sparc Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/make/mapfiles/libjava/reorder-sparc Fri Nov 11 16:44:36 2016 +0100 @@ -78,7 +78,7 @@ text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess; text: .text%Java_java_lang_reflect_Array_newArray; -text: .text%Java_java_lang_Throwable_getStackTraceElements; +text: .text%Java_java_lang_StackTraceElement_initStackTraceElements; text: .text%throwFileNotFoundException; text: .text%JNU_NotifyAll; # Test LoadFrame diff -r f71b844f33d1 -r 95af45781076 jdk/make/mapfiles/libjava/reorder-sparcv9 --- a/jdk/make/mapfiles/libjava/reorder-sparcv9 Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/make/mapfiles/libjava/reorder-sparcv9 Fri Nov 11 16:44:36 2016 +0100 @@ -74,7 +74,7 @@ text: .text%JNU_GetEnv; text: .text%Java_java_io_UnixFileSystem_checkAccess; text: .text%Java_java_lang_reflect_Array_newArray; -text: .text%Java_java_lang_Throwable_getStackTraceElements; +text: .text%Java_java_lang_StackTraceElement_initStackTraceElements; text: .text%throwFileNotFoundException: OUTPUTDIR/io_util.o; text: .text%JNU_NotifyAll; # Test LoadFrame diff -r f71b844f33d1 -r 95af45781076 jdk/make/mapfiles/libjava/reorder-x86 --- a/jdk/make/mapfiles/libjava/reorder-x86 Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/make/mapfiles/libjava/reorder-x86 Fri Nov 11 16:44:36 2016 +0100 @@ -78,7 +78,7 @@ text: .text%Java_sun_reflect_NativeMethodAccessorImpl_invoke0; text: .text%Java_java_io_FileInputStream_available; text: .text%Java_java_lang_reflect_Array_newArray; -text: .text%Java_java_lang_Throwable_getStackTraceElements; +text: .text%Java_java_lang_StackTraceElement_initStackTraceElements; text: .text%Java_java_lang_System_identityHashCode; text: .text%JNU_NotifyAll; # Test LoadFrame diff -r f71b844f33d1 -r 95af45781076 jdk/make/mapfiles/libsplashscreen/mapfile-vers --- a/jdk/make/mapfiles/libsplashscreen/mapfile-vers Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/make/mapfiles/libsplashscreen/mapfile-vers Fri Nov 11 16:44:36 2016 +0100 @@ -44,6 +44,7 @@ SplashSetFileJarName; SplashSetScaleFactor; SplashGetScaledImageName; + SplashGetScaledImgNameMaxPstfixLen; local: *; }; diff -r f71b844f33d1 -r 95af45781076 jdk/make/rmic/Rmic-java.rmi.gmk --- a/jdk/make/rmic/Rmic-java.rmi.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/make/rmic/Rmic-java.rmi.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -33,7 +33,7 @@ # $(eval $(call SetupRMICompilation,RMI_12, \ - CLASSES := sun.rmi.server.Activation$$$$ActivationSystemImpl \ + CLASSES := sun.rmi.server.Activation$$ActivationSystemImpl \ java.rmi.activation.ActivationGroup, \ CLASSES_DIR := $(CLASSES_DIR)/java.rmi, \ STUB_CLASSES_DIR := $(STUB_CLASSES_DIR)/java.rmi, \ diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/io/File.java --- a/jdk/src/java.base/share/classes/java/io/File.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/io/File.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2016, Oracle and/or its affiliates. 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 @@ -1907,16 +1907,10 @@ throws IOException { long n = random.nextLong(); - if (n == Long.MIN_VALUE) { - n = 0; // corner case - } else { - n = Math.abs(n); - } // Use only the file name from the supplied prefix prefix = (new File(prefix)).getName(); - - String name = prefix + Long.toString(n) + suffix; + String name = prefix + Long.toUnsignedString(n) + suffix; File f = new File(dir, name); if (!name.equals(f.getName()) || f.isInvalid()) { if (System.getSecurityManager() != null) diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/io/FileInputStream.java --- a/jdk/src/java.base/share/classes/java/io/FileInputStream.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/io/FileInputStream.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2016, Oracle and/or its affiliates. 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 @@ -26,7 +26,6 @@ package java.io; import java.nio.channels.FileChannel; -import java.util.concurrent.atomic.AtomicBoolean; import sun.nio.ch.FileChannelImpl; @@ -60,7 +59,9 @@ private volatile FileChannel channel; - private final AtomicBoolean closed = new AtomicBoolean(false); + private final Object closeLock = new Object(); + + private volatile boolean closed; /** * Creates a FileInputStream by @@ -313,14 +314,21 @@ * @spec JSR-51 */ public void close() throws IOException { - if (!closed.compareAndSet(false, true)) { - // if compareAndSet() returns false closed was already true + if (closed) { return; } + synchronized (closeLock) { + if (closed) { + return; + } + closed = true; + } FileChannel fc = channel; if (fc != null) { - fc.close(); + // possible race with getChannel(), benign since + // FileChannel.close is final and idempotent + fc.close(); } fd.closeAll(new Closeable() { @@ -370,8 +378,10 @@ fc = this.channel; if (fc == null) { this.channel = fc = FileChannelImpl.open(fd, path, true, false, this); - if (closed.get()) { + if (closed) { try { + // possible race with close(), benign since + // FileChannel.close is final and idempotent fc.close(); } catch (IOException ioe) { throw new InternalError(ioe); // should not happen diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/io/FileOutputStream.java --- a/jdk/src/java.base/share/classes/java/io/FileOutputStream.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/io/FileOutputStream.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2016, Oracle and/or its affiliates. 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 @@ -26,7 +26,6 @@ package java.io; import java.nio.channels.FileChannel; -import java.util.concurrent.atomic.AtomicBoolean; import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.JavaIOFileDescriptorAccess; import sun.nio.ch.FileChannelImpl; @@ -77,7 +76,9 @@ */ private final String path; - private final AtomicBoolean closed = new AtomicBoolean(false); + private final Object closeLock = new Object(); + + private volatile boolean closed; /** * Creates a file output stream to write to the file with the @@ -341,14 +342,21 @@ * @spec JSR-51 */ public void close() throws IOException { - if (!closed.compareAndSet(false, true)) { - // if compareAndSet() returns false closed was already true + if (closed) { return; } + synchronized (closeLock) { + if (closed) { + return; + } + closed = true; + } FileChannel fc = channel; if (fc != null) { - fc.close(); + // possible race with getChannel(), benign since + // FileChannel.close is final and idempotent + fc.close(); } fd.closeAll(new Closeable() { @@ -399,8 +407,10 @@ fc = this.channel; if (fc == null) { this.channel = fc = FileChannelImpl.open(fd, path, false, true, this); - if (closed.get()) { + if (closed) { try { + // possible race with close(), benign since + // FileChannel.close is final and idempotent fc.close(); } catch (IOException ioe) { throw new InternalError(ioe); // should not happen diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/io/FilePermission.java --- a/jdk/src/java.base/share/classes/java/io/FilePermission.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/io/FilePermission.java Fri Nov 11 16:44:36 2016 +0100 @@ -173,6 +173,7 @@ private transient Path npath; // normalized dir path. private transient Path npath2; // alternative normalized dir path. private transient boolean allFiles; // whether this is <> + private transient boolean invalid; // whether input path is invalid // static Strings used by init(int mask) private static final char RECURSIVE_CHAR = '-'; @@ -218,11 +219,12 @@ * A private constructor like a clone, only npath2 is not touched. * @param input */ - private FilePermission(FilePermission input) { - super(input.getName()); + private FilePermission(String name, FilePermission input) { + super(name); this.npath = input.npath; this.actions = input.actions; this.allFiles = input.allFiles; + this.invalid = input.invalid; this.recursive = input.recursive; this.directory = input.directory; this.cpath = input.cpath; @@ -255,7 +257,12 @@ if (input.npath2 == null && !input.allFiles) { Path npath2 = altPath(input.npath); if (npath2 != null) { - FilePermission np = new FilePermission(input); + // Please note the name of the new permission is + // different than the original so that when one is + // added to a FilePermissionCollection it will not + // be merged with the original one. + FilePermission np = new FilePermission( + input.getName()+"#plus", input); np.npath2 = npath2; return np; } @@ -266,7 +273,9 @@ if (!input.allFiles) { Path npath2 = altPath(input.npath); if (npath2 != null) { - FilePermission np = new FilePermission(input); + // New name, see above. + FilePermission np = new FilePermission( + input.getName()+"#using", input); np.npath = npath2; return np; } @@ -318,11 +327,12 @@ // Windows. Some JDK codes generate such illegal names. npath = builtInFS.getPath(new File(name).getPath()) .normalize(); + invalid = false; } catch (InvalidPathException ipe) { // Still invalid. For compatibility reason, accept it // but make this permission useless. npath = builtInFS.getPath("-u-s-e-l-e-s-s-"); - this.mask = NONE; + invalid = true; } // lastName should always be non-null now @@ -540,6 +550,12 @@ */ boolean impliesIgnoreMask(FilePermission that) { if (FilePermCompat.nb) { + if (this == that) { + return true; + } + if (this.invalid || that.invalid) { + return false; + } if (allFiles) { return true; } @@ -687,9 +703,13 @@ FilePermission that = (FilePermission) obj; if (FilePermCompat.nb) { + if (this.invalid || that.invalid) { + return false; + } return (this.mask == that.mask) && (this.allFiles == that.allFiles) && this.npath.equals(that.npath) && + Objects.equals(npath2, that.npath2) && (this.directory == that.directory) && (this.recursive == that.recursive); } else { @@ -708,7 +728,8 @@ @Override public int hashCode() { if (FilePermCompat.nb) { - return Objects.hash(mask, allFiles, directory, recursive, npath); + return Objects.hash( + mask, allFiles, directory, recursive, npath, npath2, invalid); } else { return 0; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/lang/Class.java --- a/jdk/src/java.base/share/classes/java/lang/Class.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/Class.java Fri Nov 11 16:44:36 2016 +0100 @@ -485,7 +485,7 @@ * can be replaced by * *

{@code
-     * clazz.getConstructor().newInstance()
+     * clazz.getDeclaredConstructor().newInstance()
      * }
* * The latter sequence of calls is inferred to be able to throw diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/lang/ClassLoader.java --- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Fri Nov 11 16:44:36 2016 +0100 @@ -104,9 +104,9 @@ * class or resource itself. * *

Class loaders that support concurrent loading of classes are known as - * parallel capable class loaders and are required to register - * themselves at their class initialization time by invoking the - * {@link + * {@linkplain #isParallelCapable() parallel capable} class loaders and + * are required to register themselves at their class initialization time by + * invoking the {@link * #registerAsParallelCapable ClassLoader.registerAsParallelCapable} * method. Note that the ClassLoader class is registered as parallel * capable by default. However, its subclasses still need to register themselves @@ -222,6 +222,9 @@ // must be added *after* it. private final ClassLoader parent; + // class loader name + private final String name; + // the unnamed module for this ClassLoader private final Module unnamedModule; @@ -331,6 +334,14 @@ } private static Void checkCreateClassLoader() { + return checkCreateClassLoader(null); + } + + private static Void checkCreateClassLoader(String name) { + if (name != null && name.isEmpty()) { + throw new IllegalArgumentException("name must be non-empty or null"); + } + SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkCreateClassLoader(); @@ -338,7 +349,8 @@ return null; } - private ClassLoader(Void unused, ClassLoader parent) { + private ClassLoader(Void unused, String name, ClassLoader parent) { + this.name = name; this.parent = parent; this.unnamedModule = SharedSecrets.getJavaLangReflectModuleAccess() @@ -356,6 +368,27 @@ } /** + * Creates a new class loader of the specified name and using the + * specified parent class loader for delegation. + * + * @param name class loader name; or {@code null} if not named + * @param parent the parent class loader + * + * @throws IllegalArgumentException if the given name is empty. + * + * @throws SecurityException + * If a security manager exists and its + * {@link SecurityManager#checkCreateClassLoader()} + * method doesn't allow creation of a new class loader. + * + * @since 9 + */ + protected ClassLoader(String name, ClassLoader parent) { + this(checkCreateClassLoader(name), name, parent); + } + + + /** * Creates a new class loader using the specified parent class loader for * delegation. * @@ -375,9 +408,10 @@ * @since 1.2 */ protected ClassLoader(ClassLoader parent) { - this(checkCreateClassLoader(), parent); + this(checkCreateClassLoader(), null, parent); } + /** * Creates a new class loader using the ClassLoader returned by * the method {@link #getSystemClassLoader() @@ -394,7 +428,31 @@ * of a new class loader. */ protected ClassLoader() { - this(checkCreateClassLoader(), getSystemClassLoader()); + this(checkCreateClassLoader(), null, getSystemClassLoader()); + } + + + /** + * Returns the name of this class loader or {@code null} if + * this class loader is not named. + * + * @apiNote This method is non-final for compatibility. If this + * method is overridden, this method must return the same name + * as specified when this class loader was instantiated. + * + * @return name of this class loader; or {@code null} if + * this class loader is not named. + * + * @since 9 + */ + public String getName() { + return name; + } + + // package-private used by StackTraceElement to avoid + // calling the overrideable getName method + final String name() { + return name; } // -- Class -- @@ -1437,7 +1495,7 @@ } /** - * Registers the caller as parallel capable. + * Registers the caller as {@linkplain #isParallelCapable() parallel capable}. * The registration succeeds if and only if all of the following * conditions are met: *

    @@ -1448,8 +1506,10 @@ *

    Note that once a class loader is registered as parallel capable, there * is no way to change it back.

    * - * @return true if the caller is successfully registered as - * parallel capable and false if otherwise. + * @return {@code true} if the caller is successfully registered as + * parallel capable and {@code false} if otherwise. + * + * @see #isParallelCapable() * * @since 1.7 */ @@ -1461,6 +1521,22 @@ } /** + * Returns {@code true} if this class loader is + * {@linkplain #registerAsParallelCapable parallel capable}, otherwise + * {@code false}. + * + * @return {@code true} if this class loader is parallel capable, + * otherwise {@code false}. + * + * @see #registerAsParallelCapable() + * + * @since 9 + */ + public final boolean isParallelCapable() { + return ParallelLoaders.isRegistered(this.getClass()); + } + + /** * Find a resource of the specified name from the search path used to load * classes. This method locates the resource through the system class * loader (see {@link #getSystemClassLoader()}). @@ -1610,6 +1686,9 @@ * platform classes are visible to * the platform class loader. * + * @implNote The name of the builtin platform class loader is + * {@code "platform"}. + * * @return The platform {@code ClassLoader}. * * @throws SecurityException @@ -1663,6 +1742,16 @@ * this method during startup should take care not to cache the return * value until the system is fully initialized. * + *

    The name of the built-in system class loader is {@code "app"}. + * The class path used by the built-in system class loader is determined + * by the system property "{@code java.class.path}" during early + * initialization of the VM. If the system property is not defined, + * or its value is an empty string, then there is no class path + * when the initial module is a module on the application module path, + * i.e. a named module. If the initial module is not on + * the application module path then the class path defaults to + * the current working directory. + * * @return The system ClassLoader for delegation * * @throws SecurityException diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java --- a/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java Fri Nov 11 16:44:36 2016 +0100 @@ -112,11 +112,6 @@ return toStackTraceElement().toString(); } - /** - * Fill in the fields of the given StackTraceElement - */ - private native void toStackTraceElement0(StackTraceElement ste); - @Override public StackTraceElement toStackTraceElement() { StackTraceElement s = ste; @@ -124,9 +119,7 @@ synchronized (this) { s = ste; if (s == null) { - s = new StackTraceElement(); - toStackTraceElement0(s); - ste = s; + ste = s = StackTraceElement.of(this); } } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/lang/StackTraceElement.java --- a/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java Fri Nov 11 16:44:36 2016 +0100 @@ -25,7 +25,18 @@ package java.lang; +import jdk.internal.loader.BuiltinClassLoader; +import jdk.internal.misc.SharedSecrets; +import jdk.internal.misc.VM; +import jdk.internal.module.ModuleHashes; + +import java.lang.module.ModuleDescriptor.Version; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.util.HashSet; import java.util.Objects; +import java.util.Optional; +import java.util.Set; /** * An element in a stack trace, as returned by {@link @@ -40,7 +51,15 @@ * @author Josh Bloch */ public final class StackTraceElement implements java.io.Serializable { - // Normally initialized by VM (public constructor added in 1.5) + // This field is set to the compacted String representation used + // by StackTraceElement::toString and stored in serial form. + // + // This field is of Object type. VM initially sets this field to + // the Class object of the declaring class to build the compacted string. + private Object classOrLoaderModuleClassName; + + // Normally initialized by VM + private String classLoaderName; private String moduleName; private String moduleVersion; private String declaringClass; @@ -72,19 +91,22 @@ */ public StackTraceElement(String declaringClass, String methodName, String fileName, int lineNumber) { - this(null, null, declaringClass, methodName, fileName, lineNumber); + this(null, null, null, declaringClass, methodName, fileName, lineNumber); } /** * Creates a stack trace element representing the specified execution * point. * + * @param classLoaderName the class loader name if the class loader of + * the class containing the execution point represented by + * the stack trace is named; otherwise {@code null} * @param moduleName the module name if the class containing the * execution point represented by the stack trace is in a named - * module; can be {@code null} + * module; otherwise {@code null} * @param moduleVersion the module version if the class containing the * execution point represented by the stack trace is in a named - * module that has a version; can be {@code null} + * module that has a version; otherwise {@code null} * @param declaringClass the fully qualified name of the class containing * the execution point represented by the stack trace element * @param methodName the name of the method containing the execution point @@ -97,26 +119,30 @@ * a negative number if this information is unavailable. A value * of -2 indicates that the method containing the execution point * is a native method + * * @throws NullPointerException if {@code declaringClass} is {@code null} * or {@code methodName} is {@code null} + * * @since 9 */ - public StackTraceElement(String moduleName, String moduleVersion, + public StackTraceElement(String classLoaderName, + String moduleName, String moduleVersion, String declaringClass, String methodName, String fileName, int lineNumber) { - this.moduleName = moduleName; - this.moduleVersion = moduleVersion; - this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null"); - this.methodName = Objects.requireNonNull(methodName, "Method name is null"); - this.fileName = fileName; - this.lineNumber = lineNumber; + this.classLoaderName = classLoaderName; + this.moduleName = moduleName; + this.moduleVersion = moduleVersion; + this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null"); + this.methodName = Objects.requireNonNull(methodName, "Method name is null"); + this.fileName = fileName; + this.lineNumber = lineNumber; } - - /** - * Creates an empty stack frame element to be filled in by Throwable. + /* + * Private constructor for the factory methods to create StackTraceElement + * for Throwable and StackFrameInfo */ - StackTraceElement() { } + private StackTraceElement() {} /** * Returns the name of the source file containing the execution point @@ -178,6 +204,21 @@ } /** + * Returns the name of the class loader of the class containing the + * execution point represented by this stack trace element. + * + * @return the name of the class loader of the class containing the execution + * point represented by this stack trace element; {@code null} + * if the class loader is not named. + * + * @since 9 + * @see java.lang.ClassLoader#getName() + */ + public String getClassLoaderName() { + return classLoaderName; + } + + /** * Returns the fully qualified name of the class containing the * execution point represented by this stack trace element. * @@ -220,38 +261,83 @@ * examples may be regarded as typical: *

    - * If the execution point is not in a named module, {@code "my.module@9.0/"} - * will be omitted from the above. + * + *

    The first example shows a stack trace element consisting of + * three elements, each separated by {@code "/"} followed with + * the source file name and the line number of the source line + * containing the execution point. + * + * The first element "{@code com.foo.loader}" is + * the name of the class loader. The second element "{@code foo@9.0}" + * is the module name and version. The third element is the method + * containing the execution point; "{@code com.foo.Main"}" is the + * fully-qualified class name and "{@code run}" is the name of the method. + * "{@code Main.java}" is the source file name and "{@code 101}" is + * the line number. + * + *

    If a class is defined in an unnamed module + * then the second element is omitted as shown in + * "{@code com.foo.loader//com.foo.bar.App.run(App.java:12)}". + * + * If the class loader is a + * built-in class loader or is not named then the first element + * and its following {@code "/"} are omitted as shown in + * "{@code acme@2.1/org.acme.Lib.test(Lib.java:80)}". + * If the first element is omitted and the module is an unnamed module, + * the second element and its following {@code "/"} are also omitted + * as shown in "{@code MyClass.mash(MyClass.java:9)}". * * @see Throwable#printStackTrace() */ public String toString() { - String mid = ""; - if (moduleName != null) { - mid = moduleName; - if (moduleVersion != null) - mid += "@" + moduleVersion; - mid += "/"; + String s = buildLoaderModuleClassName(); + if (s == null) { + // all elements will be included + s = ""; + if (classLoaderName != null && !classLoaderName.isEmpty()) { + s += classLoaderName + "/"; + } + if (moduleName != null && !moduleName.isEmpty()) { + s += moduleName; + + if (moduleVersion != null && !moduleVersion.isEmpty()) { + s += "@" + moduleVersion; + } + } + s = s.isEmpty() ? declaringClass : s + "/" + declaringClass; } - return getClassName() + "." + methodName + "(" + mid + + + return s + "." + methodName + "(" + (isNativeMethod() ? "Native Method)" : (fileName != null && lineNumber >= 0 ? fileName + ":" + lineNumber + ")" : @@ -264,12 +350,14 @@ * point as this instance. Two stack trace elements {@code a} and * {@code b} are equal if and only if: *

    {@code
    -     *     equals(a.getFileName(), b.getFileName()) &&
    -     *     a.getLineNumber() == b.getLineNumber()) &&
    +     *     equals(a.getClassLoaderName(), b.getClassLoaderName()) &&
          *     equals(a.getModuleName(), b.getModuleName()) &&
          *     equals(a.getModuleVersion(), b.getModuleVersion()) &&
          *     equals(a.getClassName(), b.getClassName()) &&
          *     equals(a.getMethodName(), b.getMethodName())
    +     *     equals(a.getFileName(), b.getFileName()) &&
    +     *     a.getLineNumber() == b.getLineNumber()
    +     *
          * }
    * where {@code equals} has the semantics of {@link * java.util.Objects#equals(Object, Object) Objects.equals}. @@ -285,9 +373,10 @@ if (!(obj instanceof StackTraceElement)) return false; StackTraceElement e = (StackTraceElement)obj; - return e.declaringClass.equals(declaringClass) && + return Objects.equals(classLoaderName, e.classLoaderName) && Objects.equals(moduleName, e.moduleName) && Objects.equals(moduleVersion, e.moduleVersion) && + e.declaringClass.equals(declaringClass) && e.lineNumber == lineNumber && Objects.equals(methodName, e.methodName) && Objects.equals(fileName, e.fileName); @@ -298,6 +387,7 @@ */ public int hashCode() { int result = 31*declaringClass.hashCode() + methodName.hashCode(); + result = 31*result + Objects.hashCode(classLoaderName); result = 31*result + Objects.hashCode(moduleName); result = 31*result + Objects.hashCode(moduleVersion); result = 31*result + Objects.hashCode(fileName); @@ -305,5 +395,157 @@ return result; } + + /** + * Build the compacted String representation to be returned by + * toString method from the declaring Class object. + */ + synchronized String buildLoaderModuleClassName() { + if (classOrLoaderModuleClassName == null) + return null; + + if (classOrLoaderModuleClassName instanceof Class) { + Class cls = (Class)classOrLoaderModuleClassName; + classOrLoaderModuleClassName = toLoaderModuleClassName(cls); + } + return (String)classOrLoaderModuleClassName; + } + + /** + * Returns // string + * representation of the given class. + *

    + * If the module is a non-upgradeable JDK module then omit + * its version string. + *

    + * If the loader has no name, or if the loader is one of the built-in + * loaders (`boot`, `platform`, or `app`) then drop the first element + * (`/`). + *

    + * If the first element has been dropped and the module is unnamed + * then drop the second element (`/`). + *

    + * If the first element is not dropped and the module is unnamed + * then drop ``. + */ + private static String toLoaderModuleClassName(Class cls) { + ClassLoader loader = cls.getClassLoader0(); + Module m = cls.getModule(); + + // First element - class loader name + // Call package-private ClassLoader::name method + String s = ""; + if (loader != null && loader.name() != null && + !(loader instanceof BuiltinClassLoader)) { + s = loader.name() + "/"; + } + + // Second element - module name and version + if (m != null && m.isNamed()) { + s += m.getName(); + // Include version if it is a user module or upgradeable module + // + // If it is JDK non-upgradeable module which is recorded + // in the hashes in java.base, omit the version. + if (!isHashedInJavaBase(m)) { + Optional ov = m.getDescriptor().version(); + if (ov.isPresent()) { + String version = "@" + ov.get().toString(); + s += version; + } + } + } + + // fully-qualified class name + return s.isEmpty() ? cls.getName() : s + "/" + cls.getName(); + } + + /** + * Returns true if the module is hashed with java.base. + *

    + * This method returns false when running on the exploded image + * since JDK modules are not hashed. They have no Version attribute + * and so "@" part will be omitted anyway. + */ + private static boolean isHashedInJavaBase(Module m) { + // return true if module system is not initialized as the code + // must be in java.base + if (!VM.isModuleSystemInited()) + return true; + + return Layer.boot() == m.getLayer() && HashedModules.contains(m); + } + + /* + * Finds JDK non-upgradeable modules, i.e. the modules that are + * included in the hashes in java.base. + */ + private static class HashedModules { + static Set HASHED_MODULES = hashedModules(); + + static Set hashedModules() { + Module javaBase = Layer.boot().findModule("java.base").get(); + Optional ohashes = + SharedSecrets.getJavaLangModuleAccess() + .hashes(javaBase.getDescriptor()); + + if (ohashes.isPresent()) { + Set names = new HashSet<>(ohashes.get().names()); + names.add("java.base"); + return names; + } + + return Set.of(); + } + + static boolean contains(Module m) { + return HASHED_MODULES.contains(m.getName()); + } + } + + + /* + * Returns an array of StackTraceElements of the given depth + * filled from the backtrace of a given Throwable. + */ + static StackTraceElement[] of(Throwable x, int depth) { + StackTraceElement[] stackTrace = new StackTraceElement[depth]; + for (int i = 0; i < depth; i++) { + stackTrace[i] = new StackTraceElement(); + } + + // VM to fill in StackTraceElement + initStackTraceElements(stackTrace, x); + + // ensure the proper StackTraceElement initialization + for (StackTraceElement ste : stackTrace) { + ste.buildLoaderModuleClassName(); + } + return stackTrace; + } + + /* + * Returns a StackTraceElement from a given StackFrameInfo. + */ + static StackTraceElement of(StackFrameInfo sfi) { + StackTraceElement ste = new StackTraceElement(); + initStackTraceElement(ste, sfi); + + ste.buildLoaderModuleClassName(); + return ste; + } + + /* + * Sets the given stack trace elements with the backtrace + * of the given Throwable. + */ + private static native void initStackTraceElements(StackTraceElement[] elements, + Throwable x); + /* + * Sets the given stack trace element with the given StackFrameInfo + */ + private static native void initStackTraceElement(StackTraceElement element, + StackFrameInfo sfi); + private static final long serialVersionUID = 6992337162326171013L; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/lang/Throwable.java --- a/jdk/src/java.base/share/classes/java/lang/Throwable.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/Throwable.java Fri Nov 11 16:44:36 2016 +0100 @@ -24,7 +24,6 @@ */ package java.lang; -import jdk.internal.misc.VM; import java.io.*; import java.util.*; @@ -826,11 +825,7 @@ // backtrace if this is the first call to this method if (stackTrace == UNASSIGNED_STACK || (stackTrace == null && backtrace != null) /* Out of protocol state */) { - stackTrace = new StackTraceElement[depth]; - for (int i = 0; i < depth; i++) { - stackTrace[i] = new StackTraceElement(); - } - getStackTraceElements(stackTrace); + stackTrace = StackTraceElement.of(this, depth); } else if (stackTrace == null) { return UNASSIGNED_STACK; } @@ -882,13 +877,6 @@ } /** - * Gets the stack trace elements. - * @param elements - * @throws IndexOutOfBoundsException if {@code elements.length != depth } - */ - private native void getStackTraceElements(StackTraceElement[] elements); - - /** * Reads a {@code Throwable} from a stream, enforcing * well-formedness constraints on fields. Null entries and * self-pointers are not allowed in the list of {@code diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Fri Nov 11 16:44:36 2016 +0100 @@ -5347,7 +5347,7 @@ * {@code (V T A...)} must have at least one {@code A} type, and the default iterator * handle parameter is adjusted to accept the leading {@code A} type, as if by * the {@link MethodHandle#asType asType} conversion method. - * The leading {@code A} type must be {@code Iterable} or a subtype thereof, or an array type. + * The leading {@code A} type must be {@code Iterable} or a subtype thereof. * This conversion step, done at loop construction time, must not throw a {@code WrongMethodTypeException}. * *

    @@ -5374,7 +5374,8 @@ * V iteratedLoop(A... a...) { * Iterator it = iterator(a...); * V v = init(a...); - * for (T t : it) { + * while (it.hasNext()) { + * T t = it.next(); * v = body(v, t, a...); * } * return v; @@ -5483,49 +5484,59 @@ Objects.requireNonNull(body); MethodType bodyType = body.type(); Class returnType = bodyType.returnType(); - List> innerList = bodyType.parameterList(); + List> internalParamList = bodyType.parameterList(); // strip leading V value if present int vsize = (returnType == void.class ? 0 : 1); - if (vsize != 0 && (innerList.size() == 0 || innerList.get(0) != returnType)) { + if (vsize != 0 && (internalParamList.size() == 0 || internalParamList.get(0) != returnType)) { // argument list has no "V" => error MethodType expected = bodyType.insertParameterTypes(0, returnType); throw misMatchedTypes("body function", bodyType, expected); - } else if (innerList.size() <= vsize) { + } else if (internalParamList.size() <= vsize) { // missing T type => error MethodType expected = bodyType.insertParameterTypes(vsize, Object.class); throw misMatchedTypes("body function", bodyType, expected); } - //Class elementType = innerList.get(vsize); // do not need this - List> outerList = innerList.subList(vsize + 1, innerList.size()); - if (outerList.isEmpty()) { - // special case; take lists from iterator handle - outerList = ((iterator != null) - ? iterator.type().parameterList() - : Arrays.asList(Iterable.class)); - innerList = bodyType.insertParameterTypes(vsize + 1, outerList).parameterList(); - } + List> externalParamList = internalParamList.subList(vsize + 1, internalParamList.size()); + Class iterableType = null; if (iterator != null) { + // special case; if the body handle only declares V and T then + // the external parameter list is obtained from iterator handle + if (externalParamList.isEmpty()) { + externalParamList = iterator.type().parameterList(); + } MethodType itype = iterator.type(); if (!Iterator.class.isAssignableFrom(itype.returnType())) { throw newIllegalArgumentException("iteratedLoop first argument must have Iterator return type"); } - if (!itype.effectivelyIdenticalParameters(0, outerList)) { - MethodType expected = methodType(itype.returnType(), outerList); + if (!itype.effectivelyIdenticalParameters(0, externalParamList)) { + MethodType expected = methodType(itype.returnType(), externalParamList); throw misMatchedTypes("iterator parameters", itype, expected); } + } else { + if (externalParamList.isEmpty()) { + // special case; if the iterator handle is null and the body handle + // only declares V and T then the external parameter list consists + // of Iterable + externalParamList = Arrays.asList(Iterable.class); + iterableType = Iterable.class; + } else { + // special case; if the iterator handle is null and the external + // parameter list is not empty then the first parameter must be + // assignable to Iterable + iterableType = externalParamList.get(0); + if (!Iterable.class.isAssignableFrom(iterableType)) { + throw newIllegalArgumentException( + "inferred first loop argument must inherit from Iterable: " + iterableType); + } + } } if (init != null) { MethodType initType = init.type(); if (initType.returnType() != returnType || - !initType.effectivelyIdenticalParameters(0, outerList)) { - throw misMatchedTypes("loop initializer", initType, methodType(returnType, outerList)); + !initType.effectivelyIdenticalParameters(0, externalParamList)) { + throw misMatchedTypes("loop initializer", initType, methodType(returnType, externalParamList)); } } - Class iterableType = outerList.isEmpty() ? null : outerList.get(0); - if (iterableType != null && !Iterable.class.isAssignableFrom(iterableType) && !iterableType.isArray()) { - throw newIllegalArgumentException( - "inferred first loop argument must be an array or inherit from Iterable: " + iterableType); - } return iterableType; // help the caller a bit } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java Fri Nov 11 16:44:36 2016 +0100 @@ -31,6 +31,7 @@ import java.io.UncheckedIOException; import java.net.URI; import java.nio.ByteBuffer; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -1997,6 +1998,13 @@ public Optional hashes(ModuleDescriptor descriptor) { return descriptor.hashes(); } + + @Override + public ModuleFinder newModulePath(Runtime.Version version, + boolean isLinkPhase, + Path... entries) { + return new ModulePath(version, isLinkPhase, entries); + } }); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java Fri Nov 11 16:44:36 2016 +0100 @@ -228,7 +228,7 @@ * *

  1. If the name matches the regular expression {@code * "-(\\d+(\\.|$))"} then the module name will be derived from the - * subsequence proceeding the hyphen of the first occurrence. The + * subsequence preceding the hyphen of the first occurrence. The * subsequence after the hyphen is parsed as a {@link * ModuleDescriptor.Version} and ignored if it cannot be parsed as * a {@code Version}.

  2. @@ -248,18 +248,23 @@ *
  3. It {@link ModuleDescriptor#requires() requires} {@code * java.base}.

  4. * - *
  5. All entries in the JAR file with names ending with {@code - * .class} are assumed to be class files where the name corresponds - * to the fully qualified name of the class. The packages of all - * classes are {@link ModuleDescriptor#exports() exported}.

  6. + *
  7. The set of packages in the module is derived from the names + * of non-directory entries in the JAR file. A candidate package name + * is derived from an entry using the characters up to, but not + * including, the last forward slash. All remaining forward slashes are + * replaced with dot ({@code "."}). If the resulting string is a valid + * Java identifier then it is assumed to be a package name. For example, + * if the JAR file contains an entry "{@code p/q/Foo.class}" then the + * package name derived is "{@code p.q}". All packages are {@link + * ModuleDescriptor#exports() exported}.

  8. * - *
  9. The contents of all entries starting with {@code + *

  10. The contents of entries starting with {@code * META-INF/services/} are assumed to be service configuration files - * (see {@link java.util.ServiceLoader}). The name of the file - * (that follows {@code META-INF/services/}) is assumed to be the - * fully-qualified binary name of a service type. The entries in the - * file are assumed to be the fully-qualified binary names of - * provider classes.

  11. + * (see {@link java.util.ServiceLoader}). If the name of a file + * (that follows {@code META-INF/services/}) is a legal Java identifier + * then it is assumed to be the fully-qualified binary name of a + * service type. The entries in the file are assumed to be the + * fully-qualified binary names of provider classes.

    * *
  12. If the JAR file has a {@code Main-Class} attribute in its * main manifest then its value is the {@link @@ -271,8 +276,8 @@ * {@link ModuleDescriptor.Builder ModuleDescriptor.Builder} API) for an * automatic module then {@code FindException} is thrown. This can arise, * for example, when a legal Java identifier name cannot be derived from - * the file name of the JAR file or where a package name derived from an - * entry ending with {@code .class} is not a legal Java identifier.

    + * the file name of the JAR file or where the JAR file contains a {@code + * .class} in the top-level directory of the JAR file.

    * *

    In addition to JAR files, an implementation may also support modules * that are packaged in other implementation specific module formats. When @@ -283,8 +288,10 @@ * *

    As with automatic modules, the contents of a packaged or exploded * module may need to be scanned in order to determine the packages - * in the module. If a {@code .class} file that corresponds to a class in an - * unnamed package is encountered then {@code FindException} is thrown.

    + * in the module. If a {@code .class} file (other than {@code + * module-info.class}) is found in the top-level directory then it is + * assumed to be a class in the unnamed package and so {@code FindException} + * is thrown.

    * *

    Finders created by this method are lazy and do not eagerly check * that the given file paths are directories or packaged modules. @@ -341,7 +348,7 @@ * @return A {@code ModuleFinder} that composes a sequence of module finders */ static ModuleFinder compose(ModuleFinder... finders) { - // copy the list, also checking for nulls + // copy the list and check for nulls final List finderList = List.of(finders); return new ModuleFinder() { diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/lang/module/ModulePath.java --- a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java Fri Nov 11 16:44:36 2016 +0100 @@ -33,10 +33,12 @@ import java.io.InputStreamReader; import java.io.UncheckedIOException; import java.lang.module.ModuleDescriptor.Requires; +import java.net.URI; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.util.Collections; import java.util.HashMap; @@ -52,49 +54,53 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import jdk.internal.jmod.JmodFile; import jdk.internal.jmod.JmodFile.Section; -import jdk.internal.module.ConfigurableModuleFinder; +import jdk.internal.module.Checks; import jdk.internal.perf.PerfCounter; +import jdk.internal.util.jar.VersionedStream; /** * A {@code ModuleFinder} that locates modules on the file system by searching * a sequence of directories or packaged modules. * - * The {@code ModuleFinder} can be configured to work in either the run-time + * The {@code ModuleFinder} can be created to work in either the run-time * or link-time phases. In both cases it locates modular JAR and exploded - * modules. When configured for link-time then it additionally locates + * modules. When created for link-time then it additionally locates * modules in JMOD files. */ -class ModulePath implements ConfigurableModuleFinder { +class ModulePath implements ModuleFinder { private static final String MODULE_INFO = "module-info.class"; + // the version to use for multi-release modular JARs + private final Runtime.Version releaseVersion; + + // true for the link phase (supports modules packaged in JMOD format) + private final boolean isLinkPhase; + // the entries on this module path private final Path[] entries; private int next; - // true if in the link phase - private boolean isLinkPhase; - // map of module name to module reference map for modules already located private final Map cachedModules = new HashMap<>(); - ModulePath(Path... entries) { + ModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) { + this.releaseVersion = version; + this.isLinkPhase = isLinkPhase; this.entries = entries.clone(); for (Path entry : this.entries) { Objects.requireNonNull(entry); } } - @Override - public void configurePhase(Phase phase) { - isLinkPhase = (phase == Phase.LINK_TIME); + ModulePath(Path... entries) { + this(JarFile.runtimeVersion(), false, entries); } @Override @@ -239,9 +245,13 @@ if (mref != null) { // can have at most one version of a module in the directory String name = mref.descriptor().name(); - if (nameToReference.put(name, mref) != null) { + ModuleReference previous = nameToReference.put(name, mref); + if (previous != null) { + String fn1 = fileName(mref); + String fn2 = fileName(previous); throw new FindException("Two versions of module " - + name + " found in " + dir); + + name + " found in " + dir + + " (" + fn1 + " and " + fn2 + ")"); } } } @@ -294,6 +304,25 @@ } + /** + * Returns a string with the file name of the module if possible. + * If the module location is not a file URI then return the URI + * as a string. + */ + private String fileName(ModuleReference mref) { + URI uri = mref.location().orElse(null); + if (uri != null) { + if (uri.getScheme().equalsIgnoreCase("file")) { + Path file = Paths.get(uri); + return file.getFileName().toString(); + } else { + return uri.toString(); + } + } else { + return ""; + } + } + // -- jmod files -- private Set jmodPackages(JmodFile jf) { @@ -301,7 +330,7 @@ .filter(e -> e.section() == Section.CLASSES) .map(JmodFile.Entry::name) .map(this::toPackageName) - .filter(pkg -> pkg.length() > 0) // module-info + .flatMap(Optional::stream) .collect(Collectors.toSet()); } @@ -328,8 +357,8 @@ private static final String SERVICES_PREFIX = "META-INF/services/"; /** - * Returns a container with the service type corresponding to the name of - * a services configuration file. + * Returns the service type corresponding to the name of a services + * configuration file if it is a valid Java identifier. * * For example, if called with "META-INF/services/p.S" then this method * returns a container with the value "p.S". @@ -341,7 +370,8 @@ String prefix = cf.substring(0, index); if (prefix.equals(SERVICES_PREFIX)) { String sn = cf.substring(index); - return Optional.of(sn); + if (Checks.isJavaIdentifier(sn)) + return Optional.of(sn); } } return Optional.empty(); @@ -416,28 +446,28 @@ if (vs != null) builder.version(vs); - // scan the entries in the JAR file to locate the .class and service - // configuration file - Map> map = - versionedStream(jf) - .map(JarEntry::getName) - .filter(s -> (s.endsWith(".class") ^ s.startsWith(SERVICES_PREFIX))) - .collect(Collectors.partitioningBy(s -> s.endsWith(".class"), - Collectors.toSet())); - Set classFiles = map.get(Boolean.TRUE); - Set configFiles = map.get(Boolean.FALSE); + // scan the names of the entries in the JAR file + Map> map = VersionedStream.stream(jf) + .filter(e -> !e.isDirectory()) + .map(JarEntry::getName) + .collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX), + Collectors.toSet())); + + Set resources = map.get(Boolean.FALSE); + Set configFiles = map.get(Boolean.TRUE); // all packages are exported - classFiles.stream() - .map(c -> toPackageName(c)) - .distinct() - .forEach(builder::exports); + resources.stream() + .map(this::toPackageName) + .flatMap(Optional::stream) + .distinct() + .forEach(builder::exports); // map names of service configuration files to service names Set serviceNames = configFiles.stream() - .map(this::toServiceName) - .flatMap(Optional::stream) - .collect(Collectors.toSet()); + .map(this::toServiceName) + .flatMap(Optional::stream) + .collect(Collectors.toSet()); // parse each service configuration file for (String sn : serviceNames) { @@ -502,25 +532,13 @@ return mn; } - private Stream versionedStream(JarFile jf) { - if (jf.isMultiRelease()) { - // a stream of JarEntries whose names are base names and whose - // contents are from the corresponding versioned entries in - // a multi-release jar file - return jf.stream().map(JarEntry::getName) - .filter(name -> !name.startsWith("META-INF/versions/")) - .map(jf::getJarEntry); - } else { - return jf.stream(); - } - } - private Set jarPackages(JarFile jf) { - return versionedStream(jf) - .filter(e -> e.getName().endsWith(".class")) - .map(e -> toPackageName(e.getName())) - .filter(pkg -> pkg.length() > 0) // module-info - .collect(Collectors.toSet()); + return VersionedStream.stream(jf) + .filter(e -> !e.isDirectory()) + .map(JarEntry::getName) + .map(this::toPackageName) + .flatMap(Optional::stream) + .collect(Collectors.toSet()); } /** @@ -535,7 +553,7 @@ try (JarFile jf = new JarFile(file.toFile(), true, // verify ZipFile.OPEN_READ, - JarFile.runtimeVersion())) + releaseVersion)) { ModuleDescriptor md; JarEntry entry = jf.getJarEntry(MODULE_INFO); @@ -565,11 +583,11 @@ private Set explodedPackages(Path dir) { try { return Files.find(dir, Integer.MAX_VALUE, - ((path, attrs) -> attrs.isRegularFile() && - path.toString().endsWith(".class"))) - .map(path -> toPackageName(dir.relativize(path))) - .filter(pkg -> pkg.length() > 0) // module-info - .collect(Collectors.toSet()); + ((path, attrs) -> attrs.isRegularFile())) + .map(path -> dir.relativize(path)) + .map(this::toPackageName) + .flatMap(Optional::stream) + .collect(Collectors.toSet()); } catch (IOException x) { throw new UncheckedIOException(x); } @@ -595,29 +613,62 @@ return ModuleReferences.newExplodedModule(md, dir); } - - // + /** + * Maps the name of an entry in a JAR or ZIP file to a package name. + * + * @throws IllegalArgumentException if the name is a class file in + * the top-level directory of the JAR/ZIP file (and it's + * not module-info.class) + */ + private Optional toPackageName(String name) { + assert !name.endsWith("/"); - // p/q/T.class => p.q - private String toPackageName(String cn) { - assert cn.endsWith(".class"); - int start = 0; - int index = cn.lastIndexOf("/"); - if (index > start) { - return cn.substring(start, index).replace('/', '.'); + int index = name.lastIndexOf("/"); + if (index == -1) { + if (name.endsWith(".class") && !name.equals(MODULE_INFO)) { + throw new IllegalArgumentException(name + + " found in top-level directory:" + + " (unnamed package not allowed in module)"); + } + return Optional.empty(); + } + + String pn = name.substring(0, index).replace('/', '.'); + if (Checks.isJavaIdentifier(pn)) { + return Optional.of(pn); } else { - return ""; + // not a valid package name + return Optional.empty(); } } - private String toPackageName(Path path) { - String name = path.toString(); - assert name.endsWith(".class"); - int index = name.lastIndexOf(File.separatorChar); - if (index != -1) { - return name.substring(0, index).replace(File.separatorChar, '.'); + /** + * Maps the relative path of an entry in an exploded module to a package + * name. + * + * @throws IllegalArgumentException if the name is a class file in + * the top-level directory (and it's not module-info.class) + */ + private Optional toPackageName(Path file) { + assert file.getRoot() == null; + + Path parent = file.getParent(); + if (parent == null) { + String name = file.toString(); + if (name.endsWith(".class") && !name.equals(MODULE_INFO)) { + throw new IllegalArgumentException(name + + " found in in top-level directory" + + " (unnamed package not allowed in module)"); + } + return Optional.empty(); + } + + String pn = parent.toString().replace(File.separatorChar, '.'); + if (Checks.isJavaIdentifier(pn)) { + return Optional.of(pn); } else { - return ""; + // not a valid package name + return Optional.empty(); } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java Fri Nov 11 16:44:36 2016 +0100 @@ -32,6 +32,7 @@ import java.nio.ByteBuffer; import java.util.Objects; import java.util.Optional; +import java.util.stream.Stream; /** @@ -44,6 +45,11 @@ * module. A module reader is also intended to be used by {@code ClassLoader} * implementations that load classes and resources from modules.

    * + *

    A resource in a module is identified by a name that is a + * '{@code /}'-separated path string. For example, module {@code java.base} may + * have a resource "{@code java/lang/Object.class}" that, by convention, is the + * class file for {@code java.lang.Object}.

    + * *

    A {@code ModuleReader} is {@linkplain ModuleReference#open open} upon * creation and is closed by invoking the {@link #close close} method. Failure * to close a module reader may result in a resource leak. The {@code @@ -52,8 +58,8 @@ * *

    A {@code ModuleReader} implementation may require permissions to access * resources in the module. Consequently the {@link #find find}, {@link #open - * open} and {@link #read read} methods may throw {@code SecurityException} if - * access is denied by the security manager.

    + * open}, {@link #read read}, and {@link #list list} methods may throw {@code + * SecurityException} if access is denied by the security manager.

    * * @see ModuleReference * @since 9 @@ -84,6 +90,9 @@ * Opens a resource, returning an input stream to read the resource in * the module. * + *

    The behavior of the input stream when used after the module reader + * is closed is implementation specific and therefore not specified.

    + * * @implSpec The default implementation invokes the {@link #find(String) * find} method to get a URI to the resource. If found, then it attempts * to construct a {@link java.net.URL URL} and open a connection to the @@ -172,17 +181,37 @@ } /** + * Lists the contents of the module, returning a stream of elements that + * are the names of all resources in the module. + * + *

    In lazy implementations then an {@code IOException} may be thrown + * when using the stream to list the module contents. If this occurs then + * the {@code IOException} will be wrapped in an {@link + * java.io.UncheckedIOException} and thrown from the method that caused the + * access to be attempted. {@code SecurityException} may also be thrown + * when using the stream to list the module contents and access is denied + * by the security manager.

    + * + *

    The behavior of the stream when used after the module reader is + * closed is implementation specific and therefore not specified.

    + * + * @return A stream of elements that are the names of all resources + * in the module + * + * @throws IOException + * If an I/O error occurs or the module reader is closed + * @throws SecurityException + * If denied by the security manager + */ + Stream list() throws IOException; + + /** * Closes the module reader. Once closed then subsequent calls to locate or - * read a resource will fail by returning {@code Optional.empty()} or - * throwing {@code IOException}. + * read a resource will fail by throwing {@code IOException}. * *

    A module reader is not required to be asynchronously closeable. If a * thread is reading a resource and another thread invokes the close method, - * then the second thread may block until the read operation is complete. - * - *

    The behavior of {@code InputStream}s obtained using the {@link - * #open(String) open} method and used after the module reader is closed - * is implementation specific and therefore not specified. + * then the second thread may block until the read operation is complete.

    */ @Override void close() throws IOException; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java Fri Nov 11 16:44:36 2016 +0100 @@ -35,6 +35,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.concurrent.locks.Lock; @@ -43,14 +44,17 @@ import java.util.function.Supplier; import java.util.jar.JarEntry; import java.util.jar.JarFile; -import java.util.zip.ZipEntry; +import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.zip.ZipFile; +import jdk.internal.jmod.JmodFile; import jdk.internal.misc.JavaLangAccess; import jdk.internal.misc.SharedSecrets; import jdk.internal.module.ModuleHashes; import jdk.internal.module.ModuleHashes.HashSupplier; import jdk.internal.module.ModulePatcher; +import jdk.internal.util.jar.VersionedStream; import sun.net.www.ParseUtil; @@ -140,6 +144,13 @@ abstract Optional implOpen(String name) throws IOException; /** + * Returns a stream of the names of resources in the module. This + * method is invoked by the list method to do the actual work of + * creating the stream. + */ + abstract Stream implList() throws IOException; + + /** * Closes the module reader. This method is invoked by close to do the * actual work of closing the module reader. */ @@ -175,7 +186,21 @@ } @Override - public void close() throws IOException { + public final Stream list() throws IOException { + readLock.lock(); + try { + if (!closed) { + return implList(); + } else { + throw new IOException("ModuleReader is closed"); + } + } finally { + readLock.unlock(); + } + } + + @Override + public final void close() throws IOException { writeLock.lock(); try { if (!closed) { @@ -241,6 +266,16 @@ } @Override + Stream implList() throws IOException { + // take snapshot to avoid async close + List names = VersionedStream.stream(jf) + .filter(e -> !e.isDirectory()) + .map(JarEntry::getName) + .collect(Collectors.toList()); + return names.stream(); + } + + @Override void implClose() throws IOException { jf.close(); } @@ -251,30 +286,31 @@ * A ModuleReader for a JMOD file. */ static class JModModuleReader extends SafeCloseModuleReader { - private final ZipFile zf; + private final JmodFile jf; private final URI uri; - static ZipFile newZipFile(Path path) { + static JmodFile newJmodFile(Path path) { try { - return new ZipFile(path.toFile()); + return new JmodFile(path); } catch (IOException ioe) { throw new UncheckedIOException(ioe); } } JModModuleReader(Path path, URI uri) { - this.zf = newZipFile(path); + this.jf = newJmodFile(path); this.uri = uri; } - private ZipEntry getEntry(String name) { - return zf.getEntry("classes/" + Objects.requireNonNull(name)); + private JmodFile.Entry getEntry(String name) { + Objects.requireNonNull(name); + return jf.getEntry(JmodFile.Section.CLASSES, name); } @Override Optional implFind(String name) { - ZipEntry ze = getEntry(name); - if (ze != null) { + JmodFile.Entry je = getEntry(name); + if (je != null) { String encodedPath = ParseUtil.encodePath(name, false); String uris = "jmod:" + uri + "!/" + encodedPath; return Optional.of(URI.create(uris)); @@ -285,17 +321,27 @@ @Override Optional implOpen(String name) throws IOException { - ZipEntry ze = getEntry(name); - if (ze != null) { - return Optional.of(zf.getInputStream(ze)); + JmodFile.Entry je = getEntry(name); + if (je != null) { + return Optional.of(jf.getInputStream(je)); } else { return Optional.empty(); } } @Override + Stream implList() throws IOException { + // take snapshot to avoid async close + List names = jf.stream() + .filter(e -> e.section() == JmodFile.Section.CLASSES) + .map(JmodFile.Entry::name) + .collect(Collectors.toList()); + return names.stream(); + } + + @Override void implClose() throws IOException { - zf.close(); + jf.close(); } } @@ -378,6 +424,17 @@ } @Override + public Stream list() throws IOException { + ensureOpen(); + // sym links not followed + return Files.find(dir, Integer.MAX_VALUE, + (path, attrs) -> attrs.isRegularFile()) + .map(f -> dir.relativize(f) + .toString() + .replace(File.separatorChar, '/')); + } + + @Override public void close() { closed = true; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java --- a/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java Fri Nov 11 16:44:36 2016 +0100 @@ -32,14 +32,21 @@ import java.net.URI; import java.net.URLConnection; import java.nio.ByteBuffer; +import java.util.ArrayDeque; import java.util.Collections; +import java.util.Deque; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.Spliterator; +import java.util.function.Consumer; import java.util.function.Supplier; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import jdk.internal.jimage.ImageLocation; import jdk.internal.jimage.ImageReader; @@ -62,6 +69,8 @@ class SystemModuleFinder implements ModuleFinder { + private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess(); + private static final PerfCounter initTime = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime"); private static final PerfCounter moduleCount @@ -73,8 +82,6 @@ // ImageReader used to access all modules in the image private static final ImageReader imageReader; - private static final JavaNetUriAccess jnua = SharedSecrets.getJavaNetUriAccess(); - // the set of modules in the run-time image private static final Set modules; @@ -170,8 +177,7 @@ HashSupplier hash) { String mn = md.name(); - - URI uri = jnua.create("jrt", "/".concat(mn)); + URI uri = JNUA.create("jrt", "/".concat(mn)); Supplier readerSupplier = new Supplier<>() { @Override @@ -332,10 +338,101 @@ } @Override + public Stream list() throws IOException { + if (closed) + throw new IOException("ModuleReader is closed"); + + Spliterator s = new ModuleContentSpliterator(module); + return StreamSupport.stream(s, false); + } + + @Override public void close() { // nothing else to do closed = true; } } + /** + * A Spliterator for traversing the resources of a module linked into the + * run-time image. + */ + static class ModuleContentSpliterator implements Spliterator { + final String moduleRoot; + final Deque stack; + Iterator iterator; + + ModuleContentSpliterator(String module) throws IOException { + moduleRoot = "/modules/" + module; + stack = new ArrayDeque<>(); + + // push the root node to the stack to get started + ImageReader.Node dir = imageReader.findNode(moduleRoot); + if (dir == null || !dir.isDirectory()) + throw new IOException(moduleRoot + " not a directory"); + stack.push(dir); + iterator = Collections.emptyIterator(); + } + + /** + * Returns the name of the next non-directory node or {@code null} if + * there are no remaining nodes to visit. + */ + private String next() throws IOException { + for (;;) { + while (iterator.hasNext()) { + ImageReader.Node node = iterator.next(); + String name = node.getName(); + if (node.isDirectory()) { + // build node + ImageReader.Node dir = imageReader.findNode(name); + assert dir.isDirectory(); + stack.push(dir); + } else { + // strip /modules/$MODULE/ prefix + return name.substring(moduleRoot.length() + 1); + } + } + + if (stack.isEmpty()) { + return null; + } else { + ImageReader.Node dir = stack.poll(); + assert dir.isDirectory(); + iterator = dir.getChildren().iterator(); + } + } + } + + @Override + public boolean tryAdvance(Consumer action) { + String next; + try { + next = next(); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + if (next != null) { + action.accept(next); + return true; + } else { + return false; + } + } + + @Override + public Spliterator trySplit() { + return null; + } + + @Override + public int characteristics() { + return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE; + } + + @Override + public long estimateSize() { + return Long.MAX_VALUE; + } + } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/net/InetAddress.java --- a/jdk/src/java.base/share/classes/java/net/InetAddress.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/net/InetAddress.java Fri Nov 11 16:44:36 2016 +0100 @@ -201,13 +201,13 @@ * Specify the address family: Internet Protocol, Version 4 * @since 1.4 */ - static final int IPv4 = 1; + @Native static final int IPv4 = 1; /** * Specify the address family: Internet Protocol, Version 6 * @since 1.4 */ - static final int IPv6 = 2; + @Native static final int IPv6 = 2; /* Specify address family preference */ static transient final int preferIPv6Address; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/net/URLClassLoader.java --- a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java Fri Nov 11 16:44:36 2016 +0100 @@ -110,19 +110,19 @@ if (security != null) { security.checkCreateClassLoader(); } - ucp = new URLClassPath(urls); + this.ucp = new URLClassPath(urls); this.acc = AccessController.getContext(); } - URLClassLoader(URL[] urls, ClassLoader parent, + URLClassLoader(String name, URL[] urls, ClassLoader parent, AccessControlContext acc) { - super(parent); + super(name, parent); // this is to make the stack depth consistent with 1.1 SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkCreateClassLoader(); } - ucp = new URLClassPath(urls); + this.ucp = new URLClassPath(urls); this.acc = acc; } @@ -154,7 +154,7 @@ if (security != null) { security.checkCreateClassLoader(); } - ucp = new URLClassPath(urls); + this.ucp = new URLClassPath(urls); this.acc = AccessController.getContext(); } @@ -165,7 +165,7 @@ if (security != null) { security.checkCreateClassLoader(); } - ucp = new URLClassPath(urls); + this.ucp = new URLClassPath(urls); this.acc = acc; } @@ -198,8 +198,76 @@ if (security != null) { security.checkCreateClassLoader(); } - ucp = new URLClassPath(urls, factory); - acc = AccessController.getContext(); + this.ucp = new URLClassPath(urls, factory); + this.acc = AccessController.getContext(); + } + + + /** + * Constructs a new named {@code URLClassLoader} for the specified URLs. + * The URLs will be searched in the order specified for classes + * and resources after first searching in the specified parent class loader. + * Any URL that ends with a '/' is assumed to refer to a directory. + * Otherwise, the URL is assumed to refer to a JAR file which will be + * downloaded and opened as needed. + * + * @param name class loader name; or {@code null} if not named + * @param urls the URLs from which to load classes and resources + * @param parent the parent class loader for delegation + * + * @throws IllegalArgumentException if the given name is empty. + * @throws NullPointerException if {@code urls} is {@code null}. + * + * @throws SecurityException if a security manager exists and its + * {@link SecurityManager#checkCreateClassLoader()} method doesn't + * allow creation of a class loader. + * + * @since 9 + */ + public URLClassLoader(String name, + URL[] urls, + ClassLoader parent) { + super(name, parent); + // this is to make the stack depth consistent with 1.1 + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkCreateClassLoader(); + } + this.ucp = new URLClassPath(urls); + this.acc = AccessController.getContext(); + } + + /** + * Constructs a new named {@code URLClassLoader} for the specified URLs, + * parent class loader, and URLStreamHandlerFactory. + * The parent argument will be used as the parent class loader for delegation. + * The factory argument will be used as the stream handler factory to + * obtain protocol handlers when creating new jar URLs. + * + * @param name class loader name; or {@code null} if not named + * @param urls the URLs from which to load classes and resources + * @param parent the parent class loader for delegation + * @param factory the URLStreamHandlerFactory to use when creating URLs + * + * @throws IllegalArgumentException if the given name is empty. + * @throws NullPointerException if {@code urls} is {@code null}. + * + * @throws SecurityException if a security manager exists and its + * {@code checkCreateClassLoader} method doesn't allow + * creation of a class loader. + * + * @since 9 + */ + public URLClassLoader(String name, URL[] urls, ClassLoader parent, + URLStreamHandlerFactory factory) { + super(name, parent); + // this is to make the stack depth consistent with 1.1 + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkCreateClassLoader(); + } + this.ucp = new URLClassPath(urls, factory); + this.acc = AccessController.getContext(); } /* A map (used as a set) to keep track of closeable local resources @@ -735,7 +803,7 @@ URLClassLoader ucl = AccessController.doPrivileged( new PrivilegedAction<>() { public URLClassLoader run() { - return new FactoryURLClassLoader(urls, parent, acc); + return new FactoryURLClassLoader(null, urls, parent, acc); } }); return ucl; @@ -785,9 +853,9 @@ ClassLoader.registerAsParallelCapable(); } - FactoryURLClassLoader(URL[] urls, ClassLoader parent, + FactoryURLClassLoader(String name, URL[] urls, ClassLoader parent, AccessControlContext acc) { - super(urls, parent, acc); + super(name, urls, parent, acc); } FactoryURLClassLoader(URL[] urls, AccessControlContext acc) { diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java --- a/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2016, Oracle and/or its affiliates. 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,8 +55,8 @@ private static final SecureRandom random = new SecureRandom(); private static Path generatePath(String prefix, String suffix, Path dir) { long n = random.nextLong(); - n = (n == Long.MIN_VALUE) ? 0 : Math.abs(n); - Path name = dir.getFileSystem().getPath(prefix + Long.toString(n) + suffix); + String s = prefix + Long.toUnsignedString(n) + suffix; + Path name = dir.getFileSystem().getPath(s); // the generated name should be a simple file name if (name.getParent() != null) throw new IllegalArgumentException("Invalid prefix or suffix"); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java --- a/jdk/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java Fri Nov 11 16:44:36 2016 +0100 @@ -26,6 +26,7 @@ package java.security; import java.security.spec.AlgorithmParameterSpec; +import java.util.Objects; /** * The {@code AlgorithmParameterGenerator} class is used to generate a @@ -153,16 +154,19 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard algorithm names. * - * @return the new AlgorithmParameterGenerator object. + * @return the new {@code AlgorithmParameterGenerator} object * - * @exception NoSuchAlgorithmException if no Provider supports an - * AlgorithmParameterGeneratorSpi implementation for the - * specified algorithm. + * @throws NoSuchAlgorithmException if no {@code Provider} supports an + * {@code AlgorithmParameterGeneratorSpi} implementation for the + * specified algorithm + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider */ public static AlgorithmParameterGenerator getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); try { Object[] objs = Security.getImpl(algorithm, "AlgorithmParameterGenerator", @@ -197,17 +201,20 @@ * * @param provider the string name of the Provider. * - * @return the new AlgorithmParameterGenerator object. + * @return the new {@code AlgorithmParameterGenerator} object * - * @exception NoSuchAlgorithmException if an AlgorithmParameterGeneratorSpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws IllegalArgumentException if the provider name is {@code null} + * or empty * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws NoSuchAlgorithmException if an + * {@code AlgorithmParameterGeneratorSpi} + * implementation for the specified algorithm is not + * available from the specified provider * - * @exception IllegalArgumentException if the provider name is null - * or empty. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider */ @@ -215,6 +222,7 @@ String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); if (provider == null || provider.length() == 0) throw new IllegalArgumentException("missing provider"); Object[] objs = Security.getImpl(algorithm, @@ -241,15 +249,19 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard algorithm names. * - * @param provider the Provider object. + * @param provider the {@code Provider} object. * - * @return the new AlgorithmParameterGenerator object. + * @return the new {@code AlgorithmParameterGenerator} object + * + * @throws IllegalArgumentException if the specified provider is + * {@code null} * - * @exception NoSuchAlgorithmException if an AlgorithmParameterGeneratorSpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if an + * {@code AlgorithmParameterGeneratorSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object * - * @exception IllegalArgumentException if the specified provider is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -259,6 +271,7 @@ Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); if (provider == null) throw new IllegalArgumentException("missing provider"); Object[] objs = Security.getImpl(algorithm, diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/security/AlgorithmParameters.java --- a/jdk/src/java.base/share/classes/java/security/AlgorithmParameters.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/security/AlgorithmParameters.java Fri Nov 11 16:44:36 2016 +0100 @@ -28,6 +28,7 @@ import java.io.*; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; +import java.util.Objects; /** * This class is used as an opaque representation of cryptographic parameters. @@ -140,16 +141,19 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard algorithm names. * - * @return the new parameter object. + * @return the new parameter object * - * @exception NoSuchAlgorithmException if no Provider supports an - * AlgorithmParametersSpi implementation for the - * specified algorithm. + * @throws NoSuchAlgorithmException if no {@code Provider} supports an + * {@code AlgorithmParametersSpi} implementation for the + * specified algorithm + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider */ public static AlgorithmParameters getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); try { Object[] objs = Security.getImpl(algorithm, "AlgorithmParameters", (String)null); @@ -184,17 +188,19 @@ * * @param provider the name of the provider. * - * @return the new parameter object. + * @return the new parameter object * - * @exception NoSuchAlgorithmException if an AlgorithmParametersSpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws IllegalArgumentException if the provider name is {@code null} + * or empty * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws NoSuchAlgorithmException if an {@code AlgorithmParametersSpi} + * implementation for the specified algorithm is not + * available from the specified provider * - * @exception IllegalArgumentException if the provider name is null - * or empty. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider */ @@ -202,6 +208,7 @@ String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); if (provider == null || provider.length() == 0) throw new IllegalArgumentException("missing provider"); Object[] objs = Security.getImpl(algorithm, "AlgorithmParameters", @@ -231,13 +238,16 @@ * * @param provider the name of the provider. * - * @return the new parameter object. + * @return the new parameter object + * + * @throws IllegalArgumentException if the provider is {@code null} * - * @exception NoSuchAlgorithmException if an AlgorithmParameterGeneratorSpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if an + * {@code AlgorithmParameterGeneratorSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object * - * @exception IllegalArgumentException if the provider is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -247,6 +257,7 @@ Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); if (provider == null) throw new IllegalArgumentException("missing provider"); Object[] objs = Security.getImpl(algorithm, "AlgorithmParameters", diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/security/KeyFactory.java --- a/jdk/src/java.base/share/classes/java/security/KeyFactory.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/security/KeyFactory.java Fri Nov 11 16:44:36 2016 +0100 @@ -167,16 +167,19 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard algorithm names. * - * @return the new KeyFactory object. + * @return the new {@code KeyFactory} object * - * @exception NoSuchAlgorithmException if no Provider supports a - * KeyFactorySpi implementation for the - * specified algorithm. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code KeyFactorySpi} implementation for the + * specified algorithm + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider */ public static KeyFactory getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); return new KeyFactory(algorithm); } @@ -200,22 +203,25 @@ * * @param provider the name of the provider. * - * @return the new KeyFactory object. + * @return the new {@code KeyFactory} object * - * @exception NoSuchAlgorithmException if a KeyFactorySpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws IllegalArgumentException if the provider name is {@code null} + * or empty * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws NoSuchAlgorithmException if a {@code KeyFactorySpi} + * implementation for the specified algorithm is not + * available from the specified provider * - * @exception IllegalArgumentException if the provider name is null - * or empty. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider */ public static KeyFactory getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = GetInstance.getInstance("KeyFactory", KeyFactorySpi.class, algorithm, provider); return new KeyFactory((KeyFactorySpi)instance.impl, @@ -239,13 +245,16 @@ * * @param provider the provider. * - * @return the new KeyFactory object. + * @return the new {@code KeyFactory} object + * + * @throws IllegalArgumentException if the specified provider is + * {@code null} * - * @exception NoSuchAlgorithmException if a KeyFactorySpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if a {@code KeyFactorySpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object * - * @exception IllegalArgumentException if the specified provider is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -253,6 +262,7 @@ */ public static KeyFactory getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = GetInstance.getInstance("KeyFactory", KeyFactorySpi.class, algorithm, provider); return new KeyFactory((KeyFactorySpi)instance.impl, diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/security/KeyPairGenerator.java --- a/jdk/src/java.base/share/classes/java/security/KeyPairGenerator.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/security/KeyPairGenerator.java Fri Nov 11 16:44:36 2016 +0100 @@ -209,16 +209,19 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard algorithm names. * - * @return the new KeyPairGenerator object. + * @return the new {@code KeyPairGenerator} object * - * @exception NoSuchAlgorithmException if no Provider supports a - * KeyPairGeneratorSpi implementation for the - * specified algorithm. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code KeyPairGeneratorSpi} implementation for the + * specified algorithm + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider */ public static KeyPairGenerator getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); List list = GetInstance.getServices("KeyPairGenerator", algorithm); Iterator t = list.iterator(); @@ -267,23 +270,26 @@ * * @param provider the string name of the provider. * - * @return the new KeyPairGenerator object. + * @return the new {@code KeyPairGenerator} object * - * @exception NoSuchAlgorithmException if a KeyPairGeneratorSpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws IllegalArgumentException if the provider name is {@code null} + * or empty * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws NoSuchAlgorithmException if a {@code KeyPairGeneratorSpi} + * implementation for the specified algorithm is not + * available from the specified provider * - * @exception IllegalArgumentException if the provider name is null - * or empty. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider */ public static KeyPairGenerator getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = GetInstance.getInstance("KeyPairGenerator", KeyPairGeneratorSpi.class, algorithm, provider); return getInstance(instance, algorithm); @@ -306,13 +312,16 @@ * * @param provider the provider. * - * @return the new KeyPairGenerator object. + * @return the new {@code KeyPairGenerator} object + * + * @throws IllegalArgumentException if the specified provider is + * {@code null} * - * @exception NoSuchAlgorithmException if a KeyPairGeneratorSpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if a {@code KeyPairGeneratorSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object * - * @exception IllegalArgumentException if the specified provider is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -320,6 +329,7 @@ */ public static KeyPairGenerator getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = GetInstance.getInstance("KeyPairGenerator", KeyPairGeneratorSpi.class, algorithm, provider); return getInstance(instance, algorithm); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/security/KeyStore.java --- a/jdk/src/java.base/share/classes/java/security/KeyStore.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/security/KeyStore.java Fri Nov 11 16:44:36 2016 +0100 @@ -26,7 +26,6 @@ package java.security; import java.io.*; -import java.net.URI; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; @@ -855,17 +854,20 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard keystore types. * - * @return a keystore object of the specified type. + * @return a keystore object of the specified type * - * @exception KeyStoreException if no Provider supports a - * KeyStoreSpi implementation for the - * specified type. + * @throws KeyStoreException if no {@code Provider} supports a + * {@code KeyStoreSpi} implementation for the + * specified type + * + * @throws NullPointerException if {@code type} is {@code null} * * @see Provider */ public static KeyStore getInstance(String type) throws KeyStoreException { + Objects.requireNonNull(type, "null type name"); try { Object[] objs = Security.getImpl(type, "KeyStore", (String)null); return new KeyStore((KeyStoreSpi)objs[0], (Provider)objs[1], type); @@ -895,23 +897,26 @@ * * @param provider the name of the provider. * - * @return a keystore object of the specified type. + * @return a keystore object of the specified type * - * @exception KeyStoreException if a KeyStoreSpi - * implementation for the specified type is not - * available from the specified provider. + * @throws IllegalArgumentException if the provider name is {@code null} + * or empty * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws KeyStoreException if a {@code KeyStoreSpi} + * implementation for the specified type is not + * available from the specified provider * - * @exception IllegalArgumentException if the provider name is null - * or empty. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list + * + * @throws NullPointerException if {@code type} is {@code null} * * @see Provider */ public static KeyStore getInstance(String type, String provider) throws KeyStoreException, NoSuchProviderException { + Objects.requireNonNull(type, "null type name"); if (provider == null || provider.length() == 0) throw new IllegalArgumentException("missing provider"); try { @@ -938,13 +943,16 @@ * * @param provider the provider. * - * @return a keystore object of the specified type. + * @return a keystore object of the specified type + * + * @throws IllegalArgumentException if the specified provider is + * {@code null} * - * @exception KeyStoreException if KeyStoreSpi - * implementation for the specified type is not available - * from the specified Provider object. + * @throws KeyStoreException if {@code KeyStoreSpi} + * implementation for the specified type is not available + * from the specified {@code Provider} object * - * @exception IllegalArgumentException if the specified provider is null. + * @throws NullPointerException if {@code type} is {@code null} * * @see Provider * @@ -953,6 +961,7 @@ public static KeyStore getInstance(String type, Provider provider) throws KeyStoreException { + Objects.requireNonNull(type, "null type name"); if (provider == null) throw new IllegalArgumentException("missing provider"); try { diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/security/MessageDigest.java --- a/jdk/src/java.base/share/classes/java/security/MessageDigest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/security/MessageDigest.java Fri Nov 11 16:44:36 2016 +0100 @@ -26,13 +26,8 @@ package java.security; import java.util.*; -import java.lang.*; -import java.io.IOException; import java.io.ByteArrayOutputStream; import java.io.PrintStream; -import java.io.InputStream; -import java.io.ByteArrayInputStream; -import java.security.InvalidKeyException; import java.nio.ByteBuffer; import sun.security.util.Debug; @@ -163,16 +158,20 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard algorithm names. * - * @return a Message Digest object that implements the specified algorithm. + * @return a {@code MessageDigest} object that implements the + * specified algorithm * - * @exception NoSuchAlgorithmException if no Provider supports a - * MessageDigestSpi implementation for the - * specified algorithm. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code MessageDigestSpi} implementation for the + * specified algorithm + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider */ public static MessageDigest getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); try { MessageDigest md; Object[] objs = Security.getImpl(algorithm, "MessageDigest", @@ -216,23 +215,27 @@ * * @param provider the name of the provider. * - * @return a MessageDigest object that implements the specified algorithm. + * @return a {@code MessageDigest} object that implements the + * specified algorithm * - * @exception NoSuchAlgorithmException if a MessageDigestSpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws IllegalArgumentException if the provider name is {@code null} + * or empty * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws NoSuchAlgorithmException if a {@code MessageDigestSpi} + * implementation for the specified algorithm is not + * available from the specified provider * - * @exception IllegalArgumentException if the provider name is null - * or empty. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider */ public static MessageDigest getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); if (provider == null || provider.length() == 0) throw new IllegalArgumentException("missing provider"); Object[] objs = Security.getImpl(algorithm, "MessageDigest", provider); @@ -265,13 +268,17 @@ * * @param provider the provider. * - * @return a MessageDigest object that implements the specified algorithm. + * @return a {@code MessageDigest} object that implements the + * specified algorithm + * + * @throws IllegalArgumentException if the specified provider is + * {@code null} * - * @exception NoSuchAlgorithmException if a MessageDigestSpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if a {@code MessageDigestSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object * - * @exception IllegalArgumentException if the specified provider is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -281,6 +288,7 @@ Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); if (provider == null) throw new IllegalArgumentException("missing provider"); Object[] objs = Security.getImpl(algorithm, "MessageDigest", provider); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/security/Policy.java --- a/jdk/src/java.base/share/classes/java/security/Policy.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/security/Policy.java Fri Nov 11 16:44:36 2016 +0100 @@ -29,6 +29,7 @@ import java.util.Enumeration; import java.util.WeakHashMap; import java.util.concurrent.atomic.AtomicReference; +import java.util.Objects; import sun.security.jca.GetInstance; import sun.security.util.Debug; import sun.security.util.SecurityConstants; @@ -372,26 +373,26 @@ * * @param params parameters for the Policy, which may be null. * - * @return the new Policy object. + * @return the new {@code Policy} object * - * @exception SecurityException if the caller does not have permission - * to get a Policy instance for the specified type. - * - * @exception NullPointerException if the specified type is null. + * @throws IllegalArgumentException if the specified parameters + * are not understood by the {@code PolicySpi} implementation + * from the selected {@code Provider} * - * @exception IllegalArgumentException if the specified parameters - * are not understood by the PolicySpi implementation - * from the selected Provider. + * @throws NoSuchAlgorithmException if no {@code Provider} supports + * a {@code PolicySpi} implementation for the specified type * - * @exception NoSuchAlgorithmException if no Provider supports a PolicySpi - * implementation for the specified type. + * @throws NullPointerException if {@code type} is {@code null} + * + * @throws SecurityException if the caller does not have permission + * to get a {@code Policy} instance for the specified type. * * @see Provider * @since 1.6 */ public static Policy getInstance(String type, Policy.Parameters params) throws NoSuchAlgorithmException { - + Objects.requireNonNull(type, "null type name"); checkPermission(type); try { GetInstance.Instance instance = GetInstance.getInstance("Policy", @@ -428,23 +429,24 @@ * * @param provider the provider. * - * @return the new Policy object. + * @return the new {@code Policy} object * - * @exception SecurityException if the caller does not have permission - * to get a Policy instance for the specified type. - * - * @exception NullPointerException if the specified type is null. + * @throws IllegalArgumentException if the specified provider + * is {@code null} or empty, or if the specified parameters are + * not understood by the {@code PolicySpi} implementation from + * the specified provider * - * @exception IllegalArgumentException if the specified provider - * is null or empty, - * or if the specified parameters are not understood by - * the PolicySpi implementation from the specified provider. + * @throws NoSuchAlgorithmException if the specified provider does not + * support a {@code PolicySpi} implementation for the specified + * type * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list * - * @exception NoSuchAlgorithmException if the specified provider does not - * support a PolicySpi implementation for the specified type. + * @throws NullPointerException if {@code type} is {@code null} + * + * @throws SecurityException if the caller does not have permission + * to get a {@code Policy} instance for the specified type * * @see Provider * @since 1.6 @@ -454,6 +456,7 @@ String provider) throws NoSuchProviderException, NoSuchAlgorithmException { + Objects.requireNonNull(type, "null type name"); if (provider == null || provider.length() == 0) { throw new IllegalArgumentException("missing provider"); } @@ -492,19 +495,21 @@ * * @param provider the Provider. * - * @return the new Policy object. + * @return the new {@code Policy} object * - * @exception SecurityException if the caller does not have permission - * to get a Policy instance for the specified type. - * - * @exception NullPointerException if the specified type is null. + * @throws IllegalArgumentException if the specified {@code Provider} + * is {@code null}, or if the specified parameters are not + * understood by the {@code PolicySpi} implementation from the + * specified {@code Provider} * - * @exception IllegalArgumentException if the specified Provider is null, - * or if the specified parameters are not understood by - * the PolicySpi implementation from the specified Provider. + * @throws NoSuchAlgorithmException if the specified {@code Provider} + * does not support a {@code PolicySpi} implementation for + * the specified type * - * @exception NoSuchAlgorithmException if the specified Provider does not - * support a PolicySpi implementation for the specified type. + * @throws NullPointerException if {@code type} is {@code null} + * + * @throws SecurityException if the caller does not have permission + * to get a {@code Policy} instance for the specified type * * @see Provider * @since 1.6 @@ -514,6 +519,7 @@ Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(type, "null type name"); if (provider == null) { throw new IllegalArgumentException("missing provider"); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/security/SecureClassLoader.java --- a/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java Fri Nov 11 16:44:36 2016 +0100 @@ -25,8 +25,6 @@ package java.security; -import java.net.URL; -import java.util.ArrayList; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; @@ -114,6 +112,30 @@ } /** + * Creates a new {@code SecureClassLoader} of the specified name and + * using the specified parent class loader for delegation. + * + * @param name class loader name; or {@code null} if not named + * @param parent the parent class loader + * + * @throws IllegalArgumentException if the given name is empty. + * + * @throws SecurityException if a security manager exists and its + * {@link SecurityManager#checkCreateClassLoader()} method + * doesn't allow creation of a class loader. + * + * @since 9 + */ + protected SecureClassLoader(String name, ClassLoader parent) { + super(name, parent); + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkCreateClassLoader(); + } + initialized = true; + } + + /** * Converts an array of bytes into an instance of class Class, * with an optional CodeSource. Before the * class can be used it must be resolved. diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/security/SecureRandom.java --- a/jdk/src/java.base/share/classes/java/security/SecureRandom.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/security/SecureRandom.java Fri Nov 11 16:44:36 2016 +0100 @@ -303,11 +303,13 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard RNG algorithm names. * - * @return the new {@code SecureRandom} object. + * @return the new {@code SecureRandom} object * - * @exception NoSuchAlgorithmException if no Provider supports a - * {@code SecureRandomSpi} implementation for the - * specified algorithm. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code SecureRandomSpi} implementation for the + * specified algorithm + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -315,6 +317,7 @@ */ public static SecureRandom getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = GetInstance.getInstance("SecureRandom", SecureRandomSpi.class, algorithm); return new SecureRandom((SecureRandomSpi)instance.impl, @@ -341,17 +344,19 @@ * * @param provider the name of the provider. * - * @return the new {@code SecureRandom} object. + * @return the new {@code SecureRandom} object + * + * @throws IllegalArgumentException if the provider name is {@code null} + * or empty * * @throws NoSuchAlgorithmException if a {@code SecureRandomSpi} * implementation for the specified algorithm is not - * available from the specified provider. + * available from the specified provider * * @throws NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * registered in the security provider list * - * @throws IllegalArgumentException if the provider name is null - * or empty. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -359,6 +364,7 @@ */ public static SecureRandom getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = GetInstance.getInstance("SecureRandom", SecureRandomSpi.class, algorithm, provider); return new SecureRandom((SecureRandomSpi)instance.impl, @@ -382,13 +388,16 @@ * * @param provider the provider. * - * @return the new {@code SecureRandom} object. + * @return the new {@code SecureRandom} object + * + * @throws IllegalArgumentException if the specified provider is + * {@code null} * * @throws NoSuchAlgorithmException if a {@code SecureRandomSpi} * implementation for the specified algorithm is not available - * from the specified {@code Provider} object. + * from the specified {@code Provider} object * - * @throws IllegalArgumentException if the specified provider is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -396,6 +405,7 @@ */ public static SecureRandom getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = GetInstance.getInstance("SecureRandom", SecureRandomSpi.class, algorithm, provider); return new SecureRandom((SecureRandomSpi)instance.impl, @@ -433,13 +443,16 @@ * @param params the {@code SecureRandomParameters} * the newly created {@code SecureRandom} object must support. * - * @return the new {@code SecureRandom} object. + * @return the new {@code SecureRandom} object + * + * @throws IllegalArgumentException if the specified params is + * {@code null} * * @throws NoSuchAlgorithmException if no Provider supports a * {@code SecureRandomSpi} implementation for the specified - * algorithm and parameters. + * algorithm and parameters * - * @throws IllegalArgumentException if the specified params is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -448,6 +461,7 @@ public static SecureRandom getInstance( String algorithm, SecureRandomParameters params) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); if (params == null) { throw new IllegalArgumentException("params cannot be null"); } @@ -481,17 +495,19 @@ * * @param provider the name of the provider. * - * @return the new {@code SecureRandom} object. + * @return the new {@code SecureRandom} object + * + * @throws IllegalArgumentException if the provider name is {@code null} + * or empty, or params is {@code null} * * @throws NoSuchAlgorithmException if the specified provider does not * support a {@code SecureRandomSpi} implementation for the - * specified algorithm and parameters. + * specified algorithm and parameters * * @throws NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * registered in the security provider list * - * @throws IllegalArgumentException if the provider name is null - * or empty, or params is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -500,6 +516,7 @@ public static SecureRandom getInstance(String algorithm, SecureRandomParameters params, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); if (params == null) { throw new IllegalArgumentException("params cannot be null"); } @@ -531,14 +548,16 @@ * * @param provider the provider. * - * @return the new {@code SecureRandom} object. + * @return the new {@code SecureRandom} object + * + * @throws IllegalArgumentException if the specified provider or params + * is {@code null} * * @throws NoSuchAlgorithmException if the specified provider does not * support a {@code SecureRandomSpi} implementation for the - * specified algorithm and parameters. + * specified algorithm and parameters * - * @throws IllegalArgumentException if the specified provider or params - * is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -547,6 +566,7 @@ public static SecureRandom getInstance(String algorithm, SecureRandomParameters params, Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); if (params == null) { throw new IllegalArgumentException("params cannot be null"); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/security/Signature.java --- a/jdk/src/java.base/share/classes/java/security/Signature.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/security/Signature.java Fri Nov 11 16:44:36 2016 +0100 @@ -213,16 +213,19 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard algorithm names. * - * @return the new Signature object. + * @return the new {@code Signature} object * - * @exception NoSuchAlgorithmException if no Provider supports a - * Signature implementation for the - * specified algorithm. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code Signature} implementation for the + * specified algorithm + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider */ public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); List list; if (algorithm.equalsIgnoreCase(RSA_SIGNATURE)) { list = GetInstance.getServices(rsaIds); @@ -335,22 +338,25 @@ * * @param provider the name of the provider. * - * @return the new Signature object. + * @return the new {@code Signature} object * - * @exception NoSuchAlgorithmException if a SignatureSpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws IllegalArgumentException if the provider name is {@code null} + * or empty * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws NoSuchAlgorithmException if a {@code SignatureSpi} + * implementation for the specified algorithm is not + * available from the specified provider * - * @exception IllegalArgumentException if the provider name is null - * or empty. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider */ public static Signature getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); if (algorithm.equalsIgnoreCase(RSA_SIGNATURE)) { // exception compatibility with existing code if ((provider == null) || (provider.length() == 0)) { @@ -385,13 +391,15 @@ * * @param provider the provider. * - * @return the new Signature object. + * @return the new {@code Signature} object + * + * @throws IllegalArgumentException if the provider is {@code null} * - * @exception NoSuchAlgorithmException if a SignatureSpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if a {@code SignatureSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object * - * @exception IllegalArgumentException if the provider is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -399,6 +407,7 @@ */ public static Signature getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); if (algorithm.equalsIgnoreCase(RSA_SIGNATURE)) { // exception compatibility with existing code if (provider == null) { diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/security/cert/CertPathBuilder.java --- a/jdk/src/java.base/share/classes/java/security/cert/CertPathBuilder.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/security/cert/CertPathBuilder.java Fri Nov 11 16:44:36 2016 +0100 @@ -32,7 +32,7 @@ import java.security.PrivilegedAction; import java.security.Provider; import java.security.Security; -import sun.security.util.Debug; +import java.util.Objects; import sun.security.jca.*; import sun.security.jca.GetInstance.Instance; @@ -157,16 +157,19 @@ * for information about standard algorithm names. * * @return a {@code CertPathBuilder} object that implements the - * specified algorithm. + * specified algorithm * - * @throws NoSuchAlgorithmException if no Provider supports a - * CertPathBuilderSpi implementation for the - * specified algorithm. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code CertPathBuilderSpi} implementation for the + * specified algorithm + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static CertPathBuilder getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = GetInstance.getInstance("CertPathBuilder", CertPathBuilderSpi.class, algorithm); return new CertPathBuilder((CertPathBuilderSpi)instance.impl, @@ -194,22 +197,25 @@ * @param provider the name of the provider. * * @return a {@code CertPathBuilder} object that implements the - * specified algorithm. + * specified algorithm * - * @throws NoSuchAlgorithmException if a CertPathBuilderSpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws IllegalArgumentException if the {@code provider} is + * {@code null} or empty + * + * @throws NoSuchAlgorithmException if a {@code CertPathBuilderSpi} + * implementation for the specified algorithm is not + * available from the specified provider * * @throws NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * registered in the security provider list * - * @exception IllegalArgumentException if the {@code provider} is - * null or empty. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static CertPathBuilder getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = GetInstance.getInstance("CertPathBuilder", CertPathBuilderSpi.class, algorithm, provider); return new CertPathBuilder((CertPathBuilderSpi)instance.impl, @@ -234,19 +240,22 @@ * @param provider the provider. * * @return a {@code CertPathBuilder} object that implements the - * specified algorithm. + * specified algorithm + * + * @throws IllegalArgumentException if the {@code provider} is + * {@code null} * - * @exception NoSuchAlgorithmException if a CertPathBuilderSpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if a {@code CertPathBuilderSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object * - * @exception IllegalArgumentException if the {@code provider} is - * null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static CertPathBuilder getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = GetInstance.getInstance("CertPathBuilder", CertPathBuilderSpi.class, algorithm, provider); return new CertPathBuilder((CertPathBuilderSpi)instance.impl, diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/security/cert/CertPathValidator.java --- a/jdk/src/java.base/share/classes/java/security/cert/CertPathValidator.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/security/cert/CertPathValidator.java Fri Nov 11 16:44:36 2016 +0100 @@ -32,7 +32,7 @@ import java.security.PrivilegedAction; import java.security.Provider; import java.security.Security; -import sun.security.util.Debug; +import java.util.Objects; import sun.security.jca.*; import sun.security.jca.GetInstance.Instance; @@ -158,16 +158,19 @@ * for information about standard algorithm names. * * @return a {@code CertPathValidator} object that implements the - * specified algorithm. + * specified algorithm * - * @exception NoSuchAlgorithmException if no Provider supports a - * CertPathValidatorSpi implementation for the - * specified algorithm. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code CertPathValidatorSpi} implementation for the + * specified algorithm + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static CertPathValidator getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = GetInstance.getInstance("CertPathValidator", CertPathValidatorSpi.class, algorithm); return new CertPathValidator((CertPathValidatorSpi)instance.impl, @@ -195,23 +198,26 @@ * @param provider the name of the provider. * * @return a {@code CertPathValidator} object that implements the - * specified algorithm. + * specified algorithm * - * @exception NoSuchAlgorithmException if a CertPathValidatorSpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws IllegalArgumentException if the {@code provider} is + * {@code null} or empty * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws NoSuchAlgorithmException if a {@code CertPathValidatorSpi} + * implementation for the specified algorithm is not + * available from the specified provider * - * @exception IllegalArgumentException if the {@code provider} is - * null or empty. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static CertPathValidator getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = GetInstance.getInstance("CertPathValidator", CertPathValidatorSpi.class, algorithm, provider); return new CertPathValidator((CertPathValidatorSpi)instance.impl, @@ -236,19 +242,22 @@ * @param provider the provider. * * @return a {@code CertPathValidator} object that implements the - * specified algorithm. + * specified algorithm + * + * @throws IllegalArgumentException if the {@code provider} is + * {@code null} * - * @exception NoSuchAlgorithmException if a CertPathValidatorSpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if a {@code CertPathValidatorSpi} + * implementation for the specified algorithm is not available + * from the specified Provider object * - * @exception IllegalArgumentException if the {@code provider} is - * null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static CertPathValidator getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = GetInstance.getInstance("CertPathValidator", CertPathValidatorSpi.class, algorithm, provider); return new CertPathValidator((CertPathValidatorSpi)instance.impl, diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/security/cert/CertStore.java --- a/jdk/src/java.base/share/classes/java/security/cert/CertStore.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/security/cert/CertStore.java Fri Nov 11 16:44:36 2016 +0100 @@ -33,6 +33,7 @@ import java.security.Provider; import java.security.Security; import java.util.Collection; +import java.util.Objects; import sun.security.jca.*; import sun.security.jca.GetInstance.Instance; @@ -218,20 +219,23 @@ * @param params the initialization parameters (may be {@code null}). * * @return a {@code CertStore} object that implements the specified - * {@code CertStore} type. - * - * @throws NoSuchAlgorithmException if no Provider supports a - * CertStoreSpi implementation for the specified type. + * {@code CertStore} type * * @throws InvalidAlgorithmParameterException if the specified - * initialization parameters are inappropriate for this - * {@code CertStore}. + * initialization parameters are inappropriate for this + * {@code CertStore} + * + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code CertStoreSpi} implementation for the specified type + * + * @throws NullPointerException if {@code type} is {@code null} * * @see java.security.Provider */ public static CertStore getInstance(String type, CertStoreParameters params) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { + Objects.requireNonNull(type, "null type name"); try { Instance instance = GetInstance.getInstance("CertStore", CertStoreSpi.class, type, params); @@ -243,7 +247,8 @@ } private static CertStore handleException(NoSuchAlgorithmException e) - throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { + throws NoSuchAlgorithmException, + InvalidAlgorithmParameterException { Throwable cause = e.getCause(); if (cause instanceof InvalidAlgorithmParameterException) { throw (InvalidAlgorithmParameterException)cause; @@ -280,21 +285,23 @@ * @param provider the name of the provider. * * @return a {@code CertStore} object that implements the - * specified type. + * specified type * - * @throws NoSuchAlgorithmException if a CertStoreSpi - * implementation for the specified type is not - * available from the specified provider. + * @throws IllegalArgumentException if the {@code provider} is + * {@code null} or empty * * @throws InvalidAlgorithmParameterException if the specified - * initialization parameters are inappropriate for this - * {@code CertStore}. + * initialization parameters are inappropriate for this + * {@code CertStore} + * + * @throws NoSuchAlgorithmException if a {@code CertStoreSpi} + * implementation for the specified type is not + * available from the specified provider * * @throws NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * registered in the security provider list * - * @exception IllegalArgumentException if the {@code provider} is - * null or empty. + * @throws NullPointerException if {@code type} is {@code null} * * @see java.security.Provider */ @@ -302,6 +309,7 @@ CertStoreParameters params, String provider) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(type, "null type name"); try { Instance instance = GetInstance.getInstance("CertStore", CertStoreSpi.class, type, params, provider); @@ -338,24 +346,27 @@ * @param provider the provider. * * @return a {@code CertStore} object that implements the - * specified type. + * specified type * - * @exception NoSuchAlgorithmException if a CertStoreSpi - * implementation for the specified type is not available - * from the specified Provider object. + * @throws IllegalArgumentException if the {@code provider} is + * null * * @throws InvalidAlgorithmParameterException if the specified - * initialization parameters are inappropriate for this - * {@code CertStore} + * initialization parameters are inappropriate for this + * {@code CertStore} * - * @exception IllegalArgumentException if the {@code provider} is - * null. + * @throws NoSuchAlgorithmException if a {@code CertStoreSpi} + * implementation for the specified type is not available + * from the specified Provider object + * + * @throws NullPointerException if {@code type} is {@code null} * * @see java.security.Provider */ public static CertStore getInstance(String type, CertStoreParameters params, Provider provider) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { + Objects.requireNonNull(type, "null type name"); try { Instance instance = GetInstance.getInstance("CertStore", CertStoreSpi.class, type, params, provider); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/security/cert/CertificateFactory.java --- a/jdk/src/java.base/share/classes/java/security/cert/CertificateFactory.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/security/cert/CertificateFactory.java Fri Nov 11 16:44:36 2016 +0100 @@ -29,10 +29,9 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.security.Provider; import java.security.Security; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; @@ -177,16 +176,19 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard certificate types. * - * @return a certificate factory object for the specified type. + * @return a certificate factory object for the specified type * - * @exception CertificateException if no Provider supports a - * CertificateFactorySpi implementation for the - * specified type. + * @throws CertificateException if no {@code Provider} supports a + * {@code CertificateFactorySpi} implementation for the + * specified type + * + * @throws NullPointerException if {@code type} is {@code null} * * @see java.security.Provider */ public static final CertificateFactory getInstance(String type) throws CertificateException { + Objects.requireNonNull(type, "null type name"); try { Instance instance = GetInstance.getInstance("CertificateFactory", CertificateFactorySpi.class, type); @@ -217,23 +219,26 @@ * * @param provider the name of the provider. * - * @return a certificate factory object for the specified type. + * @return a certificate factory object for the specified type * - * @exception CertificateException if a CertificateFactorySpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws CertificateException if a {@code CertificateFactorySpi} + * implementation for the specified algorithm is not + * available from the specified provider * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws IllegalArgumentException if the provider name is {@code null} + * or empty * - * @exception IllegalArgumentException if the provider name is null - * or empty. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list + * + * @throws NullPointerException if {@code type} is {@code null} * * @see java.security.Provider */ public static final CertificateFactory getInstance(String type, String provider) throws CertificateException, NoSuchProviderException { + Objects.requireNonNull(type, "null type name"); try { Instance instance = GetInstance.getInstance("CertificateFactory", CertificateFactorySpi.class, type, provider); @@ -260,14 +265,16 @@ * for information about standard certificate types. * @param provider the provider. * - * @return a certificate factory object for the specified type. + * @return a certificate factory object for the specified type * - * @exception CertificateException if a CertificateFactorySpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws CertificateException if a {@code CertificateFactorySpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object * - * @exception IllegalArgumentException if the {@code provider} is - * null. + * @throws IllegalArgumentException if the {@code provider} is + * {@code null} + * + * @throws NullPointerException if {@code type} is {@code null} * * @see java.security.Provider * @@ -275,6 +282,7 @@ */ public static final CertificateFactory getInstance(String type, Provider provider) throws CertificateException { + Objects.requireNonNull(type, "null type name"); try { Instance instance = GetInstance.getInstance("CertificateFactory", CertificateFactorySpi.class, type, provider); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/util/ImmutableCollections.java --- a/jdk/src/java.base/share/classes/java/util/ImmutableCollections.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/util/ImmutableCollections.java Fri Nov 11 16:44:36 2016 +0100 @@ -53,7 +53,8 @@ */ static final int SALT; static { - SALT = new Random().nextInt(); + long nt = System.nanoTime(); + SALT = (int)((nt >>> 32) ^ nt); } /** No instances. */ @@ -63,7 +64,7 @@ * The reciprocal of load factor. Given a number of elements * to store, multiply by this factor to get the table size. */ - static final double EXPAND_FACTOR = 2.0; + static final int EXPAND_FACTOR = 2; static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); } @@ -84,7 +85,14 @@ } static final class List0 extends AbstractImmutableList { - List0() { } + private static final List0 INSTANCE = new List0<>(); + + @SuppressWarnings("unchecked") + static List0 instance() { + return (List0) INSTANCE; + } + + private List0() { } @Override public int size() { @@ -214,7 +222,14 @@ } static final class Set0 extends AbstractImmutableSet { - Set0() { } + private static final Set0 INSTANCE = new Set0<>(); + + @SuppressWarnings("unchecked") + static Set0 instance() { + return (Set0) INSTANCE; + } + + private Set0() { } @Override public int size() { @@ -351,7 +366,7 @@ SetN(E... input) { size = input.length; // implicit nullcheck of input - elements = (E[])new Object[(int)Math.ceil(EXPAND_FACTOR * input.length)]; + elements = (E[])new Object[EXPAND_FACTOR * input.length]; for (int i = 0; i < input.length; i++) { E e = Objects.requireNonNull(input[i]); int idx = probe(e); @@ -450,7 +465,14 @@ } static final class Map0 extends AbstractImmutableMap { - Map0() { } + private static final Map0 INSTANCE = new Map0<>(); + + @SuppressWarnings("unchecked") + static Map0 instance() { + return (Map0) INSTANCE; + } + + private Map0() { } @Override public Set> entrySet() { @@ -529,7 +551,7 @@ } size = input.length >> 1; - int len = (int)Math.ceil(EXPAND_FACTOR * input.length); + int len = EXPAND_FACTOR * input.length; len = (len + 1) & ~1; // ensure table is even length table = new Object[len]; @@ -789,7 +811,7 @@ return Set.of(array); case IMM_MAP: if (array.length == 0) { - return new ImmutableCollections.Map0<>(); + return ImmutableCollections.Map0.instance(); } else if (array.length == 2) { return new ImmutableCollections.Map1<>(array[0], array[1]); } else { diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/util/List.java --- a/jdk/src/java.base/share/classes/java/util/List.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/util/List.java Fri Nov 11 16:44:36 2016 +0100 @@ -786,7 +786,7 @@ * @since 9 */ static List of() { - return new ImmutableCollections.List0<>(); + return ImmutableCollections.List0.instance(); } /** @@ -1030,7 +1030,7 @@ Objects.requireNonNull(elements); switch (elements.length) { case 0: - return new ImmutableCollections.List0<>(); + return ImmutableCollections.List0.instance(); case 1: return new ImmutableCollections.List1<>(elements[0]); case 2: diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/util/Map.java --- a/jdk/src/java.base/share/classes/java/util/Map.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/util/Map.java Fri Nov 11 16:44:36 2016 +0100 @@ -1286,7 +1286,7 @@ * @since 9 */ static Map of() { - return new ImmutableCollections.Map0<>(); + return ImmutableCollections.Map0.instance(); } /** @@ -1604,7 +1604,7 @@ static Map ofEntries(Entry... entries) { Objects.requireNonNull(entries); if (entries.length == 0) { - return new ImmutableCollections.Map0<>(); + return ImmutableCollections.Map0.instance(); } else if (entries.length == 1) { return new ImmutableCollections.Map1<>(entries[0].getKey(), entries[0].getValue()); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/util/Scanner.java --- a/jdk/src/java.base/share/classes/java/util/Scanner.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/util/Scanner.java Fri Nov 11 16:44:36 2016 +0100 @@ -1267,6 +1267,9 @@ // The next operation should occur in the specified radix but // the default is left untouched. private void setRadix(int radix) { + if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX)) + throw new IllegalArgumentException("radix:"+radix); + if (this.radix != radix) { // Force rebuilding and recompilation of radix dependent patterns integerPattern = null; @@ -1811,10 +1814,15 @@ * interpreted as a byte value in the specified radix using the * {@link #nextByte} method. The scanner does not advance past any input. * + *

    If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as a byte value * @return true if and only if this scanner's next token is a valid * byte value * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public boolean hasNextByte(int radix) { setRadix(radix); @@ -1869,6 +1877,10 @@ * {@link Byte#parseByte(String, int) Byte.parseByte} with the * specified radix. * + *

    If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as a byte value * @return the {@code byte} scanned from the input * @throws InputMismatchException @@ -1876,6 +1888,7 @@ * regular expression, or is out of range * @throws NoSuchElementException if input is exhausted * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public byte nextByte(int radix) { // Check cached result @@ -1917,10 +1930,15 @@ * interpreted as a short value in the specified radix using the * {@link #nextShort} method. The scanner does not advance past any input. * + *

    If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as a short value * @return true if and only if this scanner's next token is a valid * short value in the specified radix * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public boolean hasNextShort(int radix) { setRadix(radix); @@ -1975,6 +1993,10 @@ * {@link Short#parseShort(String, int) Short.parseShort} with the * specified radix. * + *

    If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as a short value * @return the {@code short} scanned from the input * @throws InputMismatchException @@ -1982,6 +2004,7 @@ * regular expression, or is out of range * @throws NoSuchElementException if input is exhausted * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public short nextShort(int radix) { // Check cached result @@ -2023,10 +2046,15 @@ * interpreted as an int value in the specified radix using the * {@link #nextInt} method. The scanner does not advance past any input. * + *

    If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as an int value * @return true if and only if this scanner's next token is a valid * int value * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public boolean hasNextInt(int radix) { setRadix(radix); @@ -2105,6 +2133,10 @@ * {@link Integer#parseInt(String, int) Integer.parseInt} with the * specified radix. * + *

    If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as an int value * @return the {@code int} scanned from the input * @throws InputMismatchException @@ -2112,6 +2144,7 @@ * regular expression, or is out of range * @throws NoSuchElementException if input is exhausted * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public int nextInt(int radix) { // Check cached result @@ -2153,10 +2186,15 @@ * interpreted as a long value in the specified radix using the * {@link #nextLong} method. The scanner does not advance past any input. * + *

    If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as a long value * @return true if and only if this scanner's next token is a valid * long value * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public boolean hasNextLong(int radix) { setRadix(radix); @@ -2211,6 +2249,10 @@ * {@link Long#parseLong(String, int) Long.parseLong} with the * specified radix. * + *

    If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as an int value * @return the {@code long} scanned from the input * @throws InputMismatchException @@ -2218,6 +2260,7 @@ * regular expression, or is out of range * @throws NoSuchElementException if input is exhausted * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public long nextLong(int radix) { // Check cached result @@ -2450,10 +2493,15 @@ * the {@link #nextBigInteger} method. The scanner does not advance past * any input. * + *

    If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token as an integer * @return true if and only if this scanner's next token is a valid * {@code BigInteger} * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public boolean hasNextBigInteger(int radix) { setRadix(radix); @@ -2504,6 +2552,10 @@ * java.math.BigInteger#BigInteger(java.lang.String) * BigInteger(String, int)} constructor with the specified radix. * + *

    If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX} + * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an + * {@code IllegalArgumentException} is thrown. + * * @param radix the radix used to interpret the token * @return the {@code BigInteger} scanned from the input * @throws InputMismatchException @@ -2511,6 +2563,7 @@ * regular expression, or is out of range * @throws NoSuchElementException if the input is exhausted * @throws IllegalStateException if this scanner is closed + * @throws IllegalArgumentException if the radix is out of range */ public BigInteger nextBigInteger(int radix) { // Check cached result diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/util/Set.java --- a/jdk/src/java.base/share/classes/java/util/Set.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/util/Set.java Fri Nov 11 16:44:36 2016 +0100 @@ -448,7 +448,7 @@ * @since 9 */ static Set of() { - return new ImmutableCollections.Set0<>(); + return ImmutableCollections.Set0.instance(); } /** @@ -692,7 +692,7 @@ Objects.requireNonNull(elements); switch (elements.length) { case 0: - return new ImmutableCollections.Set0<>(); + return ImmutableCollections.Set0.instance(); case 1: return new ImmutableCollections.Set1<>(elements[0]); case 2: diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/java/util/stream/Collectors.java --- a/jdk/src/java.base/share/classes/java/util/stream/Collectors.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/java/util/stream/Collectors.java Fri Nov 11 16:44:36 2016 +0100 @@ -508,7 +508,7 @@ * transformation. For example, one could adapt the {@link #toList()} * collector to always produce an immutable list with: *

    {@code
    -     *     List people
    +     *     List list
          *         = people.stream().collect(collectingAndThen(toList(), Collections::unmodifiableList));
          * }
    * diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/javax/crypto/Cipher.java --- a/jdk/src/java.base/share/classes/javax/crypto/Cipher.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/javax/crypto/Cipher.java Fri Nov 11 16:44:36 2016 +0100 @@ -493,21 +493,24 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard transformation names. * - * @return a cipher that implements the requested transformation. + * @return a cipher that implements the requested transformation * - * @exception NoSuchAlgorithmException if {@code transformation} - * is null, empty, in an invalid format, - * or if no Provider supports a CipherSpi implementation for the - * specified algorithm. + * @throws NoSuchAlgorithmException if {@code transformation} + * is {@code null}, empty, in an invalid format, + * or if no {@code Provider} supports a {@code CipherSpi} + * implementation for the specified algorithm * - * @exception NoSuchPaddingException if {@code transformation} - * contains a padding scheme that is not available. + * @throws NoSuchPaddingException if {@code transformation} + * contains a padding scheme that is not available * * @see java.security.Provider */ public static final Cipher getInstance(String transformation) throws NoSuchAlgorithmException, NoSuchPaddingException { + if ((transformation == null) || transformation.equals("")) { + throw new NoSuchAlgorithmException("Null or empty transformation"); + } List transforms = getTransforms(transformation); List cipherServices = new ArrayList<>(transforms.size()); for (Transform transform : transforms) { @@ -570,21 +573,22 @@ * * @param provider the name of the provider. * - * @return a cipher that implements the requested transformation. + * @return a cipher that implements the requested transformation * - * @exception NoSuchAlgorithmException if {@code transformation} - * is null, empty, in an invalid format, - * or if a CipherSpi implementation for the specified algorithm - * is not available from the specified provider. + * @throws IllegalArgumentException if the {@code provider} + * is {@code null} or empty * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws NoSuchAlgorithmException if {@code transformation} + * is {@code null}, empty, in an invalid format, + * or if a {@code CipherSpi} implementation for the + * specified algorithm is not available from the specified + * provider * - * @exception NoSuchPaddingException if {@code transformation} - * contains a padding scheme that is not available. + * @throws NoSuchPaddingException if {@code transformation} + * contains a padding scheme that is not available * - * @exception IllegalArgumentException if the {@code provider} - * is null or empty. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list * * @see java.security.Provider */ @@ -593,6 +597,9 @@ throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException { + if ((transformation == null) || transformation.equals("")) { + throw new NoSuchAlgorithmException("Null or empty transformation"); + } if ((provider == null) || (provider.length() == 0)) { throw new IllegalArgumentException("Missing provider"); } @@ -622,18 +629,19 @@ * * @param provider the provider. * - * @return a cipher that implements the requested transformation. + * @return a cipher that implements the requested transformation + * + * @throws IllegalArgumentException if the {@code provider} + * is {@code null} * - * @exception NoSuchAlgorithmException if {@code transformation} - * is null, empty, in an invalid format, - * or if a CipherSpi implementation for the specified algorithm - * is not available from the specified Provider object. + * @throws NoSuchAlgorithmException if {@code transformation} + * is {@code null}, empty, in an invalid format, + * or if a {@code CipherSpi} implementation for the + * specified algorithm is not available from the specified + * {@code Provider} object * - * @exception NoSuchPaddingException if {@code transformation} - * contains a padding scheme that is not available. - * - * @exception IllegalArgumentException if the {@code provider} - * is null. + * @throws NoSuchPaddingException if {@code transformation} + * contains a padding scheme that is not available * * @see java.security.Provider */ @@ -641,6 +649,9 @@ Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException { + if ((transformation == null) || transformation.equals("")) { + throw new NoSuchAlgorithmException("Null or empty transformation"); + } if (provider == null) { throw new IllegalArgumentException("Missing provider"); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java --- a/jdk/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java Fri Nov 11 16:44:36 2016 +0100 @@ -34,6 +34,7 @@ import java.security.InvalidKeyException; import java.security.InvalidAlgorithmParameterException; import java.security.spec.AlgorithmParameterSpec; +import java.util.Objects; import sun.security.jca.GetInstance.Instance; @@ -128,19 +129,19 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard exemption mechanism names. * - * @return the new ExemptionMechanism object. + * @return the new {@code ExemptionMechanism} object * - * @exception NullPointerException if algorithm - * is null. + * @throws NoSuchAlgorithmException if no {@code Provider} supports an + * {@code ExemptionMechanismSpi} implementation for the + * specified algorithm * - * @exception NoSuchAlgorithmException if no Provider supports an - * ExemptionMechanismSpi implementation for the - * specified algorithm. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final ExemptionMechanism getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = JceSecurity.getInstance("ExemptionMechanism", ExemptionMechanismSpi.class, algorithm); return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl, @@ -169,26 +170,26 @@ * * @param provider the name of the provider. * - * @return the new ExemptionMechanism object. + * @return the new {@code ExemptionMechanism} object * - * @exception NullPointerException if algorithm - * is null. + * @throws IllegalArgumentException if the {@code provider} + * is {@code null} or empty * - * @exception NoSuchAlgorithmException if an ExemptionMechanismSpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws NoSuchAlgorithmException if an {@code ExemptionMechanismSpi} + * implementation for the specified algorithm is not + * available from the specified provider * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list * - * @exception IllegalArgumentException if the provider - * is null or empty. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final ExemptionMechanism getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = JceSecurity.getInstance("ExemptionMechanism", ExemptionMechanismSpi.class, algorithm, provider); return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl, @@ -213,22 +214,22 @@ * * @param provider the provider. * - * @return the new ExemptionMechanism object. + * @return the new {@code ExemptionMechanism} object * - * @exception NullPointerException if algorithm - * is null. + * @throws IllegalArgumentException if the {@code provider} + * is null * - * @exception NoSuchAlgorithmException if an ExemptionMechanismSpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if an {@code ExemptionMechanismSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider object} * - * @exception IllegalArgumentException if the provider - * is null. + * @exception NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final ExemptionMechanism getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = JceSecurity.getInstance("ExemptionMechanism", ExemptionMechanismSpi.class, algorithm, provider); return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl, diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/javax/crypto/KeyAgreement.java --- a/jdk/src/java.base/share/classes/javax/crypto/KeyAgreement.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/javax/crypto/KeyAgreement.java Fri Nov 11 16:44:36 2016 +0100 @@ -165,19 +165,19 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard algorithm names. * - * @return the new {@code KeyAgreement} object. + * @return the new {@code KeyAgreement} object * - * @exception NullPointerException if the specified algorithm - * is null. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code KeyAgreementSpi} implementation for the + * specified algorithm * - * @exception NoSuchAlgorithmException if no Provider supports a - * KeyAgreementSpi implementation for the - * specified algorithm. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final KeyAgreement getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); List services = GetInstance.getServices("KeyAgreement", algorithm); // make sure there is at least one service from a signed provider @@ -214,26 +214,26 @@ * * @param provider the name of the provider. * - * @return the new {@code KeyAgreement} object. + * @return the new {@code KeyAgreement} object * - * @exception NullPointerException if the specified algorithm - * is null. + * @throws IllegalArgumentException if the {@code provider} + * is {@code null} or empty * - * @exception NoSuchAlgorithmException if a KeyAgreementSpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws NoSuchAlgorithmException if a {@code KeyAgreementSpi} + * implementation for the specified algorithm is not + * available from the specified provider * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list * - * @exception IllegalArgumentException if the {@code provider} - * is null or empty. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final KeyAgreement getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = JceSecurity.getInstance ("KeyAgreement", KeyAgreementSpi.class, algorithm, provider); return new KeyAgreement((KeyAgreementSpi)instance.impl, @@ -258,22 +258,22 @@ * * @param provider the provider. * - * @return the new {@code KeyAgreement} object. + * @return the new {@code KeyAgreement} object * - * @exception NullPointerException if the specified algorithm - * is null. + * @throws IllegalArgumentException if the {@code provider} + * is {@code null} * - * @exception NoSuchAlgorithmException if a KeyAgreementSpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if a {@code KeyAgreementSpi} + * implementation for the specified algorithm is not available + * from the specified Provider object * - * @exception IllegalArgumentException if the {@code provider} - * is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final KeyAgreement getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = JceSecurity.getInstance ("KeyAgreement", KeyAgreementSpi.class, algorithm, provider); return new KeyAgreement((KeyAgreementSpi)instance.impl, diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/javax/crypto/KeyGenerator.java --- a/jdk/src/java.base/share/classes/javax/crypto/KeyGenerator.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/javax/crypto/KeyGenerator.java Fri Nov 11 16:44:36 2016 +0100 @@ -216,18 +216,19 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard algorithm names. * - * @return the new {@code KeyGenerator} object. - * - * @exception NullPointerException if the specified algorithm is null. + * @return the new {@code KeyGenerator} object * - * @exception NoSuchAlgorithmException if no Provider supports a - * KeyGeneratorSpi implementation for the - * specified algorithm. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code KeyGeneratorSpi} implementation for the + * specified algorithm + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final KeyGenerator getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); return new KeyGenerator(algorithm); } @@ -251,25 +252,26 @@ * * @param provider the name of the provider. * - * @return the new {@code KeyGenerator} object. + * @return the new {@code KeyGenerator} object * - * @exception NullPointerException if the specified algorithm is null. + * @throws IllegalArgumentException if the {@code provider} + * is {@code null} or empty * - * @exception NoSuchAlgorithmException if a KeyGeneratorSpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws NoSuchAlgorithmException if a {@code KeyGeneratorSpi} + * implementation for the specified algorithm is not + * available from the specified provider * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list * - * @exception IllegalArgumentException if the {@code provider} - * is null or empty. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final KeyGenerator getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = JceSecurity.getInstance("KeyGenerator", KeyGeneratorSpi.class, algorithm, provider); return new KeyGenerator((KeyGeneratorSpi)instance.impl, @@ -293,21 +295,22 @@ * * @param provider the provider. * - * @return the new {@code KeyGenerator} object. + * @return the new {@code KeyGenerator} object * - * @exception NullPointerException if the specified algorithm is null. + * @throws IllegalArgumentException if the {@code provider} + * is {@code null} * - * @exception NoSuchAlgorithmException if a KeyGeneratorSpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if a {@code KeyGeneratorSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object * - * @exception IllegalArgumentException if the {@code provider} - * is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final KeyGenerator getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = JceSecurity.getInstance("KeyGenerator", KeyGeneratorSpi.class, algorithm, provider); return new KeyGenerator((KeyGeneratorSpi)instance.impl, diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/javax/crypto/Mac.java --- a/jdk/src/java.base/share/classes/javax/crypto/Mac.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/javax/crypto/Mac.java Fri Nov 11 16:44:36 2016 +0100 @@ -166,16 +166,18 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard algorithm names. * - * @return the new {@code Mac} object. + * @return the new {@code Mac} object * - * @exception NoSuchAlgorithmException if no Provider supports a - * MacSpi implementation for the - * specified algorithm. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code MacSpi} implementation for the specified algorithm + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final Mac getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); List services = GetInstance.getServices("Mac", algorithm); // make sure there is at least one service from a signed provider Iterator t = services.iterator(); @@ -210,22 +212,25 @@ * * @param provider the name of the provider. * - * @return the new {@code Mac} object. + * @return the new {@code Mac} object * - * @exception NoSuchAlgorithmException if a MacSpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws IllegalArgumentException if the {@code provider} + * is {@code null} or empty * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws NoSuchAlgorithmException if a {@code MacSpi} + * implementation for the specified algorithm is not + * available from the specified provider * - * @exception IllegalArgumentException if the {@code provider} - * is null or empty. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final Mac getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = JceSecurity.getInstance ("Mac", MacSpi.class, algorithm, provider); return new Mac((MacSpi)instance.impl, instance.provider, algorithm); @@ -248,19 +253,22 @@ * * @param provider the provider. * - * @return the new {@code Mac} object. + * @return the new {@code Mac} object + * + * @throws IllegalArgumentException if the {@code provider} is + * {@code null} * - * @exception NoSuchAlgorithmException if a MacSpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if a {@code MacSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object * - * @exception IllegalArgumentException if the {@code provider} - * is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final Mac getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = JceSecurity.getInstance ("Mac", MacSpi.class, algorithm, provider); return new Mac((MacSpi)instance.impl, instance.provider, algorithm); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/javax/crypto/SecretKeyFactory.java --- a/jdk/src/java.base/share/classes/javax/crypto/SecretKeyFactory.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/javax/crypto/SecretKeyFactory.java Fri Nov 11 16:44:36 2016 +0100 @@ -152,19 +152,19 @@ * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard algorithm names. * - * @return the new {@code SecretKeyFactory} object. + * @return the new {@code SecretKeyFactory} object * - * @exception NullPointerException if the specified algorithm - * is null. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code SecretKeyFactorySpi} implementation for the + * specified algorithm * - * @exception NoSuchAlgorithmException if no Provider supports a - * SecretKeyFactorySpi implementation for the - * specified algorithm. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final SecretKeyFactory getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); return new SecretKeyFactory(algorithm); } @@ -189,26 +189,26 @@ * * @param provider the name of the provider. * - * @return the new {@code SecretKeyFactory} object. + * @return the new {@code SecretKeyFactory} object * - * @exception NoSuchAlgorithmException if a SecretKeyFactorySpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws IllegalArgumentException if the {@code provider} + * is {@code null} or empty * - * @exception NullPointerException if the specified algorithm - * is null. + * @throws NoSuchAlgorithmException if a {@code SecretKeyFactorySpi} + * implementation for the specified algorithm is not + * available from the specified provider * * @throws NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * registered in the security provider list * - * @exception IllegalArgumentException if the {@code provider} - * is null or empty. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final SecretKeyFactory getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = JceSecurity.getInstance("SecretKeyFactory", SecretKeyFactorySpi.class, algorithm, provider); return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl, @@ -233,22 +233,22 @@ * * @param provider the provider. * - * @return the new {@code SecretKeyFactory} object. + * @return the new {@code SecretKeyFactory} object * - * @exception NullPointerException if the specified algorithm - * is null. + * @throws IllegalArgumentException if the {@code provider} + * is {@code null} * - * @exception NoSuchAlgorithmException if a SecretKeyFactorySpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if a {@code SecretKeyFactorySpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object * - * @exception IllegalArgumentException if the {@code provider} - * is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final SecretKeyFactory getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); Instance instance = JceSecurity.getInstance("SecretKeyFactory", SecretKeyFactorySpi.class, algorithm, provider); return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl, diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/javax/net/ssl/KeyManagerFactory.java --- a/jdk/src/java.base/share/classes/javax/net/ssl/KeyManagerFactory.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/javax/net/ssl/KeyManagerFactory.java Fri Nov 11 16:44:36 2016 +0100 @@ -27,6 +27,7 @@ import java.security.Security; import java.security.*; +import java.util.Objects; import sun.security.jca.GetInstance; @@ -130,17 +131,19 @@ * Java Secure Socket Extension Reference Guide * for information about standard algorithm names. * - * @return the new KeyManagerFactory object. + * @return the new {@code KeyManagerFactory} object * - * @exception NoSuchAlgorithmException if no Provider supports a - * KeyManagerFactorySpi implementation for the - * specified algorithm. - * @exception NullPointerException if algorithm is null. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code KeyManagerFactorySpi} implementation for the + * specified algorithm + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final KeyManagerFactory getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); GetInstance.Instance instance = GetInstance.getInstance ("KeyManagerFactory", KeyManagerFactorySpi.class, algorithm); @@ -168,23 +171,26 @@ * * @param provider the name of the provider. * - * @return the new KeyManagerFactory object. + * @return the new {@code KeyManagerFactory} object * - * @throws NoSuchAlgorithmException if a KeyManagerFactorySpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws IllegalArgumentException if the provider name is {@code null} + * or empty + * + * @throws NoSuchAlgorithmException if a {@code KeyManagerFactorySpi} + * implementation for the specified algorithm is not + * available from the specified provider * * @throws NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * registered in the security provider list * - * @throws IllegalArgumentException if the provider name is null or empty. - * @throws NullPointerException if algorithm is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final KeyManagerFactory getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); GetInstance.Instance instance = GetInstance.getInstance ("KeyManagerFactory", KeyManagerFactorySpi.class, algorithm, provider); @@ -209,19 +215,21 @@ * * @param provider an instance of the provider. * - * @return the new KeyManagerFactory object. + * @return the new {@code KeyManagerFactory} object + * + * @throws IllegalArgumentException if provider is {@code null} * - * @throws NoSuchAlgorithmException if a KeyManagerFactorySpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if a {@code @KeyManagerFactorySpi} + * implementation for the specified algorithm is not available + * from the specified Provider object * - * @throws IllegalArgumentException if provider is null. - * @throws NullPointerException if algorithm is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final KeyManagerFactory getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); GetInstance.Instance instance = GetInstance.getInstance ("KeyManagerFactory", KeyManagerFactorySpi.class, algorithm, provider); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/javax/net/ssl/SSLContext.java --- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLContext.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLContext.java Fri Nov 11 16:44:36 2016 +0100 @@ -26,6 +26,7 @@ package javax.net.ssl; import java.security.*; +import java.util.Objects; import sun.security.jca.GetInstance; @@ -151,17 +152,19 @@ * Documentation * for information about standard protocol names. * - * @return the new {@code SSLContext} object. + * @return the new {@code SSLContext} object * - * @exception NoSuchAlgorithmException if no Provider supports a - * SSLContextSpi implementation for the - * specified protocol. - * @exception NullPointerException if protocol is null. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code SSLContextSpi} implementation for the + * specified protocol + * + * @throws NullPointerException if {@code protocol} is {@code null} * * @see java.security.Provider */ public static SSLContext getInstance(String protocol) throws NoSuchAlgorithmException { + Objects.requireNonNull(protocol, "null protocol name"); GetInstance.Instance instance = GetInstance.getInstance ("SSLContext", SSLContextSpi.class, protocol); return new SSLContext((SSLContextSpi)instance.impl, instance.provider, @@ -189,22 +192,25 @@ * * @param provider the name of the provider. * - * @return the new {@code SSLContext} object. + * @return the new {@code SSLContext} object * - * @throws NoSuchAlgorithmException if a SSLContextSpi - * implementation for the specified protocol is not - * available from the specified provider. + * @throws IllegalArgumentException if the provider name is + * {@code null} or empty + * + * @throws NoSuchAlgorithmException if a {@code SSLContextSpi} + * implementation for the specified protocol is not + * available from the specified provider * * @throws NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * registered in the security provider list * - * @throws IllegalArgumentException if the provider name is null or empty. - * @throws NullPointerException if protocol is null. + * @throws NullPointerException if {@code protocol} is {@code null} * * @see java.security.Provider */ public static SSLContext getInstance(String protocol, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(protocol, "null protocol name"); GetInstance.Instance instance = GetInstance.getInstance ("SSLContext", SSLContextSpi.class, protocol, provider); return new SSLContext((SSLContextSpi)instance.impl, instance.provider, @@ -229,19 +235,21 @@ * * @param provider an instance of the provider. * - * @return the new {@code SSLContext} object. + * @return the new {@code SSLContext} object + * + * @throws IllegalArgumentException if the provider is {@code null} * - * @throws NoSuchAlgorithmException if a SSLContextSpi - * implementation for the specified protocol is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if a {@code SSLContextSpi} + * implementation for the specified protocol is not available + * from the specified {@code Provider} object * - * @throws IllegalArgumentException if the provider is null. - * @throws NullPointerException if protocol is null. + * @throws NullPointerException if {@code protocol} is {@code null} * * @see java.security.Provider */ public static SSLContext getInstance(String protocol, Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(protocol, "null protocol name"); GetInstance.Instance instance = GetInstance.getInstance ("SSLContext", SSLContextSpi.class, protocol, provider); return new SSLContext((SSLContextSpi)instance.impl, instance.provider, diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/javax/net/ssl/TrustManagerFactory.java --- a/jdk/src/java.base/share/classes/javax/net/ssl/TrustManagerFactory.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/javax/net/ssl/TrustManagerFactory.java Fri Nov 11 16:44:36 2016 +0100 @@ -27,6 +27,7 @@ import java.security.Security; import java.security.*; +import java.util.Objects; import sun.security.jca.GetInstance; @@ -144,17 +145,19 @@ * Java Secure Socket Extension Reference Guide * for information about standard algorithm names. * - * @return the new TrustManagerFactory object. + * @return the new {@code TrustManagerFactory} object * - * @exception NoSuchAlgorithmException if no Provider supports a - * TrustManagerFactorySpi implementation for the - * specified algorithm. - * @exception NullPointerException if algorithm is null. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code TrustManagerFactorySpi} implementation for the + * specified algorithm + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final TrustManagerFactory getInstance(String algorithm) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); GetInstance.Instance instance = GetInstance.getInstance ("TrustManagerFactory", TrustManagerFactorySpi.class, algorithm); @@ -182,23 +185,26 @@ * * @param provider the name of the provider. * - * @return the new TrustManagerFactory object + * @return the new {@code TrustManagerFactory} object * - * @throws NoSuchAlgorithmException if a TrustManagerFactorySpi - * implementation for the specified algorithm is not - * available from the specified provider. + * @throws IllegalArgumentException if the provider name is + * {@code null} or empty + * + * @throws NoSuchAlgorithmException if a {@code TrustManagerFactorySpi} + * implementation for the specified algorithm is not + * available from the specified provider * * @throws NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * registered in the security provider list * - * @throws IllegalArgumentException if the provider name is null or empty. - * @throws NullPointerException if algorithm is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final TrustManagerFactory getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { + Objects.requireNonNull(algorithm, "null algorithm name"); GetInstance.Instance instance = GetInstance.getInstance ("TrustManagerFactory", TrustManagerFactorySpi.class, algorithm, provider); @@ -223,19 +229,21 @@ * * @param provider an instance of the provider. * - * @return the new TrustManagerFactory object. + * @return the new {@code TrustManagerFactory} object + * + * @throws IllegalArgumentException if the provider is {@code null} * - * @throws NoSuchAlgorithmException if a TrustManagerFactorySpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws NoSuchAlgorithmException if a {@code TrustManagerFactorySpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object * - * @throws IllegalArgumentException if the provider is null. - * @throws NullPointerException if algorithm is null. + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see java.security.Provider */ public static final TrustManagerFactory getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); GetInstance.Instance instance = GetInstance.getInstance ("TrustManagerFactory", TrustManagerFactorySpi.class, algorithm, provider); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/javax/security/auth/login/Configuration.java --- a/jdk/src/java.base/share/classes/javax/security/auth/login/Configuration.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/javax/security/auth/login/Configuration.java Fri Nov 11 16:44:36 2016 +0100 @@ -329,27 +329,29 @@ * * @param params parameters for the Configuration, which may be null. * - * @return the new Configuration object. + * @return the new {@code Configuration} object * - * @exception SecurityException if the caller does not have permission - * to get a Configuration instance for the specified type. - * - * @exception NullPointerException if the specified type is null. + * @throws IllegalArgumentException if the specified parameters + * are not understood by the {@code ConfigurationSpi} + * implementation from the selected {@code Provider} * - * @exception IllegalArgumentException if the specified parameters - * are not understood by the ConfigurationSpi implementation - * from the selected Provider. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code ConfigurationSpi} implementation for the specified type * - * @exception NoSuchAlgorithmException if no Provider supports a - * ConfigurationSpi implementation for the specified type. + * @throws NullPointerException if {@code type} is {@code null} + * + * @throws SecurityException if the caller does not have permission + * to get a {@code Configuration} instance for the specified type * * @see Provider + * * @since 1.6 */ public static Configuration getInstance(String type, Configuration.Parameters params) throws NoSuchAlgorithmException { + Objects.requireNonNull(type, "null type name"); checkPermission(type); try { GetInstance.Instance instance = GetInstance.getInstance @@ -387,24 +389,24 @@ * * @param provider the provider. * - * @return the new Configuration object. + * @return the new {@code Configuration} object * - * @exception SecurityException if the caller does not have permission - * to get a Configuration instance for the specified type. - * - * @exception NullPointerException if the specified type is null. + * @throws IllegalArgumentException if the specified provider + * is {@code null} or empty, or if the specified parameters + * are not understood by the {@code ConfigurationSpi} + * implementation from the specified provider * - * @exception IllegalArgumentException if the specified provider - * is null or empty, - * or if the specified parameters are not understood by - * the ConfigurationSpi implementation from the specified provider. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws NoSuchAlgorithmException if the specified provider does not + * support a {@code ConfigurationSpi} implementation for the + * specified type * - * @exception NoSuchAlgorithmException if the specified provider does not - * support a ConfigurationSpi implementation for the specified - * type. + * @throws NullPointerException if {@code type} is {@code null} + * + * @throws SecurityException if the caller does not have permission + * to get a {@code Configuration} instance for the specified type * * @see Provider * @since 1.6 @@ -414,6 +416,7 @@ String provider) throws NoSuchProviderException, NoSuchAlgorithmException { + Objects.requireNonNull(type, "null type name"); if (provider == null || provider.length() == 0) { throw new IllegalArgumentException("missing provider"); } @@ -453,20 +456,21 @@ * * @param provider the Provider. * - * @return the new Configuration object. + * @return the new {@code Configuration} object * - * @exception SecurityException if the caller does not have permission - * to get a Configuration instance for the specified type. - * - * @exception NullPointerException if the specified type is null. + * @throws IllegalArgumentException if the specified {@code Provider} + * is {@code null}, or if the specified parameters are not + * understood by the {@code ConfigurationSpi} implementation + * from the specified Provider * - * @exception IllegalArgumentException if the specified Provider is null, - * or if the specified parameters are not understood by - * the ConfigurationSpi implementation from the specified Provider. + * @throws NoSuchAlgorithmException if the specified {@code Provider} + * does not support a {@code ConfigurationSpi} implementation + * for the specified type * - * @exception NoSuchAlgorithmException if the specified Provider does not - * support a ConfigurationSpi implementation for the specified - * type. + * @throws NullPointerException if {@code type} is {@code null} + * + * @throws SecurityException if the caller does not have permission + * to get a {@code Configuration} instance for the specified type * * @see Provider * @since 1.6 @@ -476,6 +480,7 @@ Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(type, "null type name"); if (provider == null) { throw new IllegalArgumentException("missing provider"); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java --- a/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java Fri Nov 11 16:44:36 2016 +0100 @@ -176,6 +176,16 @@ } /** + * Returns the {@code Entry} for a resource in a JMOD file section + * or {@code null} if not found. + */ + public Entry getEntry(Section section, String name) { + String entry = section.jmodDir() + "/" + name; + ZipEntry ze = zipfile.getEntry(entry); + return (ze != null) ? new Entry(ze) : null; + } + + /** * Opens an {@code InputStream} for reading the named entry of the given * section in this jmod file. * @@ -185,7 +195,6 @@ public InputStream getInputStream(Section section, String name) throws IOException { - String entry = section.jmodDir() + "/" + name; ZipEntry e = zipfile.getEntry(entry); if (e == null) { @@ -195,6 +204,15 @@ } /** + * Opens an {@code InputStream} for reading an entry in the JMOD file. + * + * @throws IOException if an I/O error occurs + */ + public InputStream getInputStream(Entry entry) throws IOException { + return zipfile.getInputStream(entry.zipEntry()); + } + + /** * Returns a stream of non-directory entries in this jmod file. */ public Stream stream() { diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java --- a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java Fri Nov 11 16:44:36 2016 +0100 @@ -53,6 +53,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.jar.Attributes; import java.util.jar.Manifest; +import java.util.stream.Stream; import jdk.internal.module.ModulePatcher.PatchedModuleReader; import jdk.internal.misc.VM; @@ -144,9 +145,9 @@ /** * Create a new instance. */ - BuiltinClassLoader(BuiltinClassLoader parent, URLClassPath ucp) { + BuiltinClassLoader(String name, BuiltinClassLoader parent, URLClassPath ucp) { // ensure getParent() returns null when the parent is the boot loader - super(parent == null || parent == ClassLoaders.bootLoader() ? null : parent); + super(name, parent == null || parent == ClassLoaders.bootLoader() ? null : parent); this.parent = parent; this.ucp = ucp; @@ -749,6 +750,10 @@ return Optional.empty(); } @Override + public Stream list() { + return Stream.empty(); + } + @Override public void close() { throw new InternalError("Should not get here"); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java --- a/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java Fri Nov 11 16:44:36 2016 +0100 @@ -69,16 +69,17 @@ bcp = toURLClassPath(s); // we have a class path if -cp is specified or -m is not specified. - // If neither is specified then default to -cp . + // If neither is specified then default to -cp + // If -cp is not specified and -m is specified, the value of + // java.class.path is an empty string, then no class path. URLClassPath ucp = null; String mainMid = System.getProperty("jdk.module.main"); String cp = System.getProperty("java.class.path"); - if (mainMid == null && cp == null) + if (cp == null) cp = ""; - if (cp != null) + if (mainMid == null || cp.length() > 0) ucp = toURLClassPath(cp); - // create the class loaders BOOT_LOADER = new BootClassLoader(bcp); PLATFORM_LOADER = new PlatformClassLoader(BOOT_LOADER); @@ -117,7 +118,7 @@ */ private static class BootClassLoader extends BuiltinClassLoader { BootClassLoader(URLClassPath bcp) { - super(null, bcp); + super(null, null, bcp); } @Override @@ -137,7 +138,7 @@ } PlatformClassLoader(BootClassLoader parent) { - super(parent, null); + super("platform", parent, null); } /** @@ -164,7 +165,7 @@ final URLClassPath ucp; AppClassLoader(PlatformClassLoader parent, URLClassPath ucp) { - super(parent, ucp); + super("app", parent, ucp); this.ucp = ucp; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java --- a/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java Fri Nov 11 16:44:36 2016 +0100 @@ -53,6 +53,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; /** @@ -534,6 +535,10 @@ return Optional.empty(); } @Override + public Stream list() { + return Stream.empty(); + } + @Override public void close() { throw new InternalError("Should not get here"); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java --- a/jdk/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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 @@ -137,13 +137,20 @@ } public static boolean isSystem(Module m) { - ClassLoader cl = AccessController.doPrivileged(new PrivilegedAction<>() { + return AccessController.doPrivileged(new PrivilegedAction<>() { @Override - public ClassLoader run() { - return m.getClassLoader(); + public Boolean run() { + final ClassLoader moduleCL = m.getClassLoader(); + if (moduleCL == null) return true; + ClassLoader cl = ClassLoader.getPlatformClassLoader(); + while (cl != null && moduleCL != cl) { + cl = cl.getParent(); + } + // returns true if moduleCL is the platform class loader + // or one of its ancestors. + return moduleCL == cl; } }); - return cl == null; } @Override diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java Fri Nov 11 16:44:36 2016 +0100 @@ -39,6 +39,7 @@ import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; import java.net.URI; +import java.nio.file.Path; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -103,6 +104,11 @@ ModuleHashes hashes); /** + * Returns the object with the hashes of other modules + */ + Optional hashes(ModuleDescriptor descriptor); + + /** * Resolves a collection of root modules, with service binding * and the empty configuration as the parent. The post resolution * checks are optionally run. @@ -120,8 +126,10 @@ Supplier readerSupplier); /** - * Returns the object with the hashes of other modules + * Creates a ModuleFinder for a module path. */ - Optional hashes(ModuleDescriptor descriptor); + ModuleFinder newModulePath(Runtime.Version version, + boolean isLinkPhase, + Path... entries); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/jdk/internal/module/ConfigurableModuleFinder.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/ConfigurableModuleFinder.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.internal.module; - -import java.lang.module.ModuleFinder; - -/** - * A ModuleFinder that may be configured to work at either run-time - * or link-time. - */ - -public interface ConfigurableModuleFinder extends ModuleFinder { - - public static enum Phase { - RUN_TIME, - LINK_TIME - } - - /** - * Configures this finder to work in the given phase. - */ - void configurePhase(Phase phase); - -} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java Fri Nov 11 16:44:36 2016 +0100 @@ -57,7 +57,15 @@ cw.visit(Opcodes.V1_9, ACC_MODULE, name, null, null, null); cw.visitAttribute(new ModuleAttribute(md)); - cw.visitAttribute(new ConcealedPackagesAttribute(md.conceals())); + + // for tests: write the ConcealedPackages attribute when there are non-exported packages + long nExportedPackages = md.exports().stream() + .map(ModuleDescriptor.Exports::source) + .distinct() + .count(); + if (md.packages().size() > nExportedPackages) + cw.visitAttribute(new ConcealedPackagesAttribute(md.packages())); + md.version().ifPresent(v -> cw.visitAttribute(new VersionAttribute(v))); md.mainClass().ifPresent(mc -> cw.visitAttribute(new MainClassAttribute(mc))); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java Fri Nov 11 16:44:36 2016 +0100 @@ -50,6 +50,7 @@ import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.stream.Stream; import jdk.internal.loader.Resource; import jdk.internal.misc.JavaLangModuleAccess; @@ -159,21 +160,19 @@ // is not supported by the boot class loader try (JarFile jf = new JarFile(file.toFile())) { jf.stream() - .filter(e -> e.getName().endsWith(".class")) .map(e -> toPackageName(file, e)) - .filter(pn -> pn.length() > 0) + .filter(Checks::isJavaIdentifier) .forEach(packages::add); } } else if (Files.isDirectory(file)) { - // exploded directory + // exploded directory without following sym links Path top = file; Files.find(top, Integer.MAX_VALUE, - ((path, attrs) -> attrs.isRegularFile() && - path.toString().endsWith(".class"))) + ((path, attrs) -> attrs.isRegularFile())) .map(path -> toPackageName(top, path)) - .filter(pn -> pn.length() > 0) + .filter(Checks::isJavaIdentifier) .forEach(packages::add); } @@ -381,6 +380,15 @@ } @Override + public Stream list() throws IOException { + Stream s = delegate().list(); + for (ResourceFinder finder : finders) { + s = Stream.concat(s, finder.list()); + } + return s.distinct(); + } + + @Override public void close() throws IOException { closeAll(finders); delegate().close(); @@ -393,6 +401,7 @@ */ private static interface ResourceFinder extends Closeable { Resource find(String name) throws IOException; + Stream list() throws IOException; } @@ -453,6 +462,13 @@ } }; } + + @Override + public Stream list() throws IOException { + return jf.stream() + .filter(e -> !e.isDirectory()) + .map(JarEntry::getName); + } } @@ -527,6 +543,15 @@ } }; } + + @Override + public Stream list() throws IOException { + return Files.find(dir, Integer.MAX_VALUE, + (path, attrs) -> attrs.isRegularFile()) + .map(f -> dir.relativize(f) + .toString() + .replace(File.separatorChar, '/')); + } } @@ -537,7 +562,7 @@ Path entry = top.relativize(file); Path parent = entry.getParent(); if (parent == null) { - return warnUnnamedPackage(top, entry.toString()); + return warnIfModuleInfo(top, entry.toString()); } else { return parent.toString().replace(File.separatorChar, '.'); } @@ -557,14 +582,15 @@ String name = entry.getName(); int index = name.lastIndexOf("/"); if (index == -1) { - return warnUnnamedPackage(file, name); + return warnIfModuleInfo(file, name); } else { return name.substring(0, index).replace('/', '.'); } } - private static String warnUnnamedPackage(Path file, String e) { - System.err.println("WARNING: " + e + " not allowed in patch: " + file); + private static String warnIfModuleInfo(Path file, String e) { + if (e.equals("module-info.class")) + System.err.println("WARNING: " + e + " ignored in patch: " + file); return ""; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java --- a/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java Fri Nov 11 16:44:36 2016 +0100 @@ -364,6 +364,16 @@ } } + public final Constructor newConstructorForSerialization(Class cl, + Constructor constructorToCall) + { + if (constructorToCall.getDeclaringClass() == cl) { + constructorToCall.setAccessible(true); + return constructorToCall; + } + return generateConstructor(cl, constructorToCall); + } + public final Constructor newConstructorForSerialization(Class cl) { Class initCl = cl; while (Serializable.class.isAssignableFrom(initCl)) { @@ -383,6 +393,12 @@ } catch (NoSuchMethodException ex) { return null; } + return generateConstructor(cl, constructorToCall); + } + + private final Constructor generateConstructor(Class cl, + Constructor constructorToCall) { + ConstructorAccessor acc = new MethodAccessorGenerator(). generateSerializationConstructor(cl, diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/module-info.java --- a/jdk/src/java.base/share/classes/module-info.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -196,7 +196,8 @@ jdk.vm.ci; exports jdk.internal.util.jar to jdk.jartool, - jdk.jdeps; + jdk.jdeps, + jdk.jlink; exports jdk.internal.vm to java.management, jdk.jvmstat; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties --- a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 2016, Oracle and/or its affiliates. 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,7 +31,7 @@ \ (to execute the main class in a module)\n\ where options include:\n -java.launcher.opt.datamodel =\ -d{0}\t use a {0}-bit data model if available\n +java.launcher.opt.datamodel =\ -d{0}\t Deprecated, will be removed in a future release\n java.launcher.opt.vmselect =\ {0}\t to select the "{1}" VM\n java.launcher.opt.hotspot =\ {0}\t is a synonym for the "{1}" VM [deprecated]\n @@ -95,6 +95,12 @@ \ load Java programming language agent, see java.lang.instrument\n\ \ -splash:\n\ \ show splash screen with specified image\n\ +\ HiDPI scaled images are automatically supported and used\n\ +\ if available. The unscaled image filename, e.g. image.ext,\n\ +\ should always be passed as the argument to the -splash option.\n\ +\ The most appropriate scaled image provided will be picked up\n\ +\ automatically.\n\ +\ See the SplashScreen API documentation for more information.\n\ \ @ read options from the specified file\n\ \To specify an argument for a long option, you can use --= or\n\ \-- .\n\ diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java --- a/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java Fri Nov 11 16:44:36 2016 +0100 @@ -253,20 +253,20 @@ } private static String toSourceString(char c) { - StringBuilder sb = new StringBuilder(); - sb.append("'"); + StringBuilder sb = new StringBuilder(4); + sb.append('\''); if (c == '\'') sb.append("\\'"); else sb.append(c); - sb.append("'"); - return sb.toString(); + return sb.append('\'') + .toString(); } private static String toSourceString(long ell) { - return (Math.abs(ell) <= Integer.MAX_VALUE) ? - String.valueOf(ell) : - (String.valueOf(ell) + "L"); + String str = String.valueOf(ell); + return (ell < Integer.MIN_VALUE || ell > Integer.MAX_VALUE) + ? (str + 'L') : str; } /** @@ -278,10 +278,7 @@ sb.append('"'); // Escape embedded quote characters, if present, but don't do // anything more heroic. - if (s.indexOf('"') != -1) { - s = s.replace("\"", "\\\""); - } - sb.append(s); + sb.append(s.replace("\"", "\\\"")); sb.append('"'); return sb.toString(); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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 @@ -42,10 +42,6 @@ private DTLSReassembler reassembler = null; - // Cache the session identifier for the detection of session-resuming - // handshake. - byte[] prevSessionID = new byte[0]; - int readEpoch; int prevReadEpoch; @@ -114,13 +110,7 @@ @Override Plaintext acquirePlaintext() { if (reassembler != null) { - Plaintext plaintext = reassembler.acquirePlaintext(); - if (reassembler.finished()) { - // discard all buffered unused message. - reassembler = null; - } - - return plaintext; + return reassembler.acquirePlaintext(); } return null; @@ -149,40 +139,54 @@ packet.get(recordEnS); int recordEpoch = ((recordEnS[0] & 0xFF) << 8) | (recordEnS[1] & 0xFF); // pos: 3, 4 - long recordSeq = Authenticator.toLong(recordEnS); + long recordSeq = ((recordEnS[2] & 0xFFL) << 40) | + ((recordEnS[3] & 0xFFL) << 32) | + ((recordEnS[4] & 0xFFL) << 24) | + ((recordEnS[5] & 0xFFL) << 16) | + ((recordEnS[6] & 0xFFL) << 8) | + (recordEnS[7] & 0xFFL); // pos: 5-10 + int contentLen = ((packet.get() & 0xFF) << 8) | - (packet.get() & 0xFF); // pos: 11, 12 + (packet.get() & 0xFF); // pos: 11, 12 if (debug != null && Debug.isOn("record")) { - System.out.println(Thread.currentThread().getName() + - ", READ: " + + Debug.log("READ: " + ProtocolVersion.valueOf(majorVersion, minorVersion) + " " + Record.contentName(contentType) + ", length = " + contentLen); } int recLim = srcPos + DTLSRecord.headerSize + contentLen; - if (this.readEpoch > recordEpoch) { - // Discard old records delivered before this epoch. + if (this.prevReadEpoch > recordEpoch) { // Reset the position of the packet buffer. packet.position(recLim); + if (debug != null && Debug.isOn("record")) { + Debug.printHex("READ: discard this old record", recordEnS); + } return null; } + // Buffer next epoch message if necessary. if (this.readEpoch < recordEpoch) { - if (contentType != Record.ct_handshake) { - // just discard it if not a handshake message + // Discard the record younger than the current epcoh if: + // 1. it is not a handshake message, or + // 2. it is not of next epoch. + if (((contentType != Record.ct_handshake) && + (contentType != Record.ct_change_cipher_spec)) || + (this.readEpoch < (recordEpoch - 1))) { + packet.position(recLim); + + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Premature record (epoch), discard it."); + } + return null; } - // Not ready to decrypt this record, may be encrypted Finished + // Not ready to decrypt this record, may be an encrypted Finished // message, need to buffer it. - if (reassembler == null) { - reassembler = new DTLSReassembler(); - } - byte[] fragment = new byte[contentLen]; packet.get(fragment); // copy the fragment RecordFragment buffered = new RecordFragment(fragment, contentType, @@ -194,94 +198,130 @@ // consume the full record in the packet buffer. packet.position(recLim); - Plaintext plaintext = reassembler.acquirePlaintext(); - if (reassembler.finished()) { - // discard all buffered unused message. + return reassembler.acquirePlaintext(); + } + + // + // Now, the message is of this epoch or the previous epoch. + // + Authenticator decodeAuthenticator; + CipherBox decodeCipher; + if (this.readEpoch == recordEpoch) { + decodeAuthenticator = readAuthenticator; + decodeCipher = readCipher; + } else { // prevReadEpoch == recordEpoch + decodeAuthenticator = prevReadAuthenticator; + decodeCipher = prevReadCipher; + } + + // decrypt the fragment + packet.limit(recLim); + packet.position(srcPos + DTLSRecord.headerSize); + + ByteBuffer plaintextFragment; + try { + plaintextFragment = decrypt(decodeAuthenticator, + decodeCipher, contentType, packet, recordEnS); + } catch (BadPaddingException bpe) { + if (debug != null && Debug.isOn("ssl")) { + Debug.log("Discard invalid record: " + bpe); + } + + // invalid, discard this record [section 4.1.2.7, RFC 6347] + return null; + } finally { + // comsume a complete record + packet.limit(srcLim); + packet.position(recLim); + } + + if (contentType != Record.ct_change_cipher_spec && + contentType != Record.ct_handshake) { // app data or alert + // no retransmission + // Cleanup the handshake reassembler if necessary. + if ((reassembler != null) && + (reassembler.handshakeEpoch < recordEpoch)) { + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Cleanup the handshake reassembler"); + } + reassembler = null; } - return plaintext; + return new Plaintext(contentType, majorVersion, minorVersion, + recordEpoch, Authenticator.toLong(recordEnS), + plaintextFragment); } - if (this.readEpoch == recordEpoch) { - // decrypt the fragment - packet.limit(recLim); - packet.position(srcPos + DTLSRecord.headerSize); - - ByteBuffer plaintextFragment; - try { - plaintextFragment = decrypt(readAuthenticator, - readCipher, contentType, packet, recordEnS); - } catch (BadPaddingException bpe) { - if (debug != null && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - " discard invalid record: " + bpe); - } - - // invalid, discard this record [section 4.1.2.7, RFC 6347] - return null; - } finally { - // comsume a complete record - packet.limit(srcLim); - packet.position(recLim); - } - - if (contentType != Record.ct_change_cipher_spec && - contentType != Record.ct_handshake) { // app data or alert - // no retransmission - return new Plaintext(contentType, majorVersion, minorVersion, - recordEpoch, recordSeq, plaintextFragment); - } - - if (contentType == Record.ct_change_cipher_spec) { - if (reassembler == null) { + if (contentType == Record.ct_change_cipher_spec) { + if (reassembler == null) { + if (this.readEpoch != recordEpoch) { // handshake has not started, should be an // old handshake message, discard it. + + if (debug != null && Debug.isOn("verbose")) { + Debug.log( + "Lagging behind ChangeCipherSpec, discard it."); + } + return null; } - reassembler.queueUpFragment( - new RecordFragment(plaintextFragment, contentType, - majorVersion, minorVersion, - recordEnS, recordEpoch, recordSeq, false)); - } else { // handshake record - // One record may contain 1+ more handshake messages. - while (plaintextFragment.remaining() > 0) { + reassembler = new DTLSReassembler(recordEpoch); + } + + reassembler.queueUpChangeCipherSpec( + new RecordFragment(plaintextFragment, contentType, + majorVersion, minorVersion, + recordEnS, recordEpoch, recordSeq, false)); + } else { // handshake record + // One record may contain 1+ more handshake messages. + while (plaintextFragment.remaining() > 0) { + + HandshakeFragment hsFrag = parseHandshakeMessage( + contentType, majorVersion, minorVersion, + recordEnS, recordEpoch, recordSeq, plaintextFragment); - HandshakeFragment hsFrag = parseHandshakeMessage( - contentType, majorVersion, minorVersion, - recordEnS, recordEpoch, recordSeq, plaintextFragment); + if (hsFrag == null) { + // invalid, discard this record + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Invalid handshake message, discard it."); + } + + return null; + } - if (hsFrag == null) { - // invalid, discard this record + if (reassembler == null) { + if (this.readEpoch != recordEpoch) { + // handshake has not started, should be an + // old handshake message, discard it. + + if (debug != null && Debug.isOn("verbose")) { + Debug.log( + "Lagging behind handshake record, discard it."); + } + return null; } - if ((reassembler == null) && - isKickstart(hsFrag.handshakeType)) { - reassembler = new DTLSReassembler(); - } - - if (reassembler != null) { - reassembler.queueUpHandshake(hsFrag); - } // else, just ignore the message. - } - } - - // Completed the read of the full record. Acquire the reassembled - // messages. - if (reassembler != null) { - Plaintext plaintext = reassembler.acquirePlaintext(); - if (reassembler.finished()) { - // discard all buffered unused message. - reassembler = null; + reassembler = new DTLSReassembler(recordEpoch); } - return plaintext; + reassembler.queueUpHandshake(hsFrag); } } - return null; // make the complier happy + // Completed the read of the full record. Acquire the reassembled + // messages. + if (reassembler != null) { + return reassembler.acquirePlaintext(); + } + + if (debug != null && Debug.isOn("verbose")) { + Debug.log("The reassembler is not initialized yet."); + } + + return null; } @Override @@ -330,12 +370,6 @@ } } - private static boolean isKickstart(byte handshakeType) { - return (handshakeType == HandshakeMessage.ht_client_hello) || - (handshakeType == HandshakeMessage.ht_hello_request) || - (handshakeType == HandshakeMessage.ht_hello_verify_request); - } - private static HandshakeFragment parseHandshakeMessage( byte contentType, byte majorVersion, byte minorVersion, byte[] recordEnS, int recordEpoch, long recordSeq, @@ -344,9 +378,7 @@ int remaining = plaintextFragment.remaining(); if (remaining < handshakeHeaderSize) { if (debug != null && Debug.isOn("ssl")) { - System.out.println( - Thread.currentThread().getName() + - " discard invalid record: " + + Debug.log("Discard invalid record: " + "too small record to hold a handshake fragment"); } @@ -372,9 +404,7 @@ (plaintextFragment.get() & 0xFF); // pos: 9-11 if ((remaining - handshakeHeaderSize) < fragmentLength) { if (debug != null && Debug.isOn("ssl")) { - System.out.println( - Thread.currentThread().getName() + - " discard invalid record: " + + Debug.log("Discard invalid record: " + "not a complete handshake fragment in the record"); } @@ -431,7 +461,39 @@ @Override public int compareTo(RecordFragment o) { - return Long.compareUnsigned(this.recordSeq, o.recordSeq); + if (this.contentType == Record.ct_change_cipher_spec) { + if (o.contentType == Record.ct_change_cipher_spec) { + // Only one incoming ChangeCipherSpec message for an epoch. + // + // Ignore duplicated ChangeCipherSpec messages. + return Integer.compare(this.recordEpoch, o.recordEpoch); + } else if ((this.recordEpoch == o.recordEpoch) && + (o.contentType == Record.ct_handshake)) { + // ChangeCipherSpec is the latest message of an epoch. + return 1; + } + } else if (o.contentType == Record.ct_change_cipher_spec) { + if ((this.recordEpoch == o.recordEpoch) && + (this.contentType == Record.ct_handshake)) { + // ChangeCipherSpec is the latest message of an epoch. + return -1; + } else { + // different epoch or this is not a handshake message + return compareToSequence(o.recordEpoch, o.recordSeq); + } + } + + return compareToSequence(o.recordEpoch, o.recordSeq); + } + + int compareToSequence(int epoch, long seq) { + if (this.recordEpoch > epoch) { + return 1; + } else if (this.recordEpoch == epoch) { + return Long.compare(this.recordSeq, seq); + } else { + return -1; + } } } @@ -465,12 +527,24 @@ if (o instanceof HandshakeFragment) { HandshakeFragment other = (HandshakeFragment)o; if (this.messageSeq != other.messageSeq) { - // keep the insertion order for the same message + // keep the insertion order of handshake messages return this.messageSeq - other.messageSeq; + } else if (this.fragmentOffset != other.fragmentOffset) { + // small fragment offset was transmitted first + return this.fragmentOffset - other.fragmentOffset; + } else if (this.fragmentLength == other.fragmentLength) { + // retransmissions, ignore duplicated messages. + return 0; } + + // Should be repacked for suitable fragment length. + // + // Note that the acquiring processes will reassemble the + // the fragments later. + return compareToSequence(o.recordEpoch, o.recordSeq); } - return Long.compareUnsigned(this.recordSeq, o.recordSeq); + return super.compareTo(o); } } @@ -484,24 +558,72 @@ } } + private static final class HandshakeFlight implements Cloneable { + static final byte HF_UNKNOWN = HandshakeMessage.ht_not_applicable; + + byte handshakeType; // handshake type + int flightEpoch; // the epoch of the first message + int minMessageSeq; // minimal message sequence + + int maxMessageSeq; // maximum message sequence + int maxRecordEpoch; // maximum record sequence number + long maxRecordSeq; // maximum record sequence number + + HashMap> holesMap; + + HandshakeFlight() { + this.handshakeType = HF_UNKNOWN; + this.flightEpoch = 0; + this.minMessageSeq = 0; + + this.maxMessageSeq = 0; + this.maxRecordEpoch = 0; + this.maxRecordSeq = -1; + + this.holesMap = new HashMap<>(5); + } + + boolean isRetransmitOf(HandshakeFlight hs) { + return (hs != null) && + (this.handshakeType == hs.handshakeType) && + (this.minMessageSeq == hs.minMessageSeq); + } + + @Override + public Object clone() { + HandshakeFlight hf = new HandshakeFlight(); + + hf.handshakeType = this.handshakeType; + hf.flightEpoch = this.flightEpoch; + hf.minMessageSeq = this.minMessageSeq; + + hf.maxMessageSeq = this.maxMessageSeq; + hf.maxRecordEpoch = this.maxRecordEpoch; + hf.maxRecordSeq = this.maxRecordSeq; + + hf.holesMap = new HashMap<>(this.holesMap); + + return hf; + } + } + final class DTLSReassembler { + // The handshake epoch. + final int handshakeEpoch; + + // The buffered fragments. TreeSet bufferedFragments = new TreeSet<>(); - HashMap> holesMap = new HashMap<>(5); + // The handshake flight in progress. + HandshakeFlight handshakeFlight = new HandshakeFlight(); - // Epoch, sequence number and handshake message sequence of the - // beginning message of a flight. - byte flightType = (byte)0xFF; - - int flightTopEpoch = 0; - long flightTopRecordSeq = -1; - int flightTopMessageSeq = 0; + // The preceding handshake flight. + HandshakeFlight precedingFlight = null; // Epoch, sequence number and handshake message sequence of the // next message acquisition of a flight. - int nextRecordEpoch = 0; // next record epoch + int nextRecordEpoch; // next record epoch long nextRecordSeq = 0; // next record sequence number - int nextMessageSeq = 0; // next handshake message number // Expect ChangeCipherSpec and Finished messages for the final flight. boolean expectCCSFlight = false; @@ -510,65 +632,66 @@ boolean flightIsReady = false; boolean needToCheckFlight = false; - // Is it a session-resuming abbreviated handshake.? - boolean isAbbreviatedHandshake = false; - - // The handshke fragment with the biggest record sequence number - // in a flight, not counting the Finished message. - HandshakeFragment lastHandshakeFragment = null; + DTLSReassembler(int handshakeEpoch) { + this.handshakeEpoch = handshakeEpoch; + this.nextRecordEpoch = handshakeEpoch; - // Is handshake (intput) finished? - boolean handshakeFinished = false; - - DTLSReassembler() { - // blank - } - - boolean finished() { - return handshakeFinished; + this.handshakeFlight.flightEpoch = handshakeEpoch; } void expectingFinishFlight() { expectCCSFlight = true; } + // Queue up a handshake message. void queueUpHandshake(HandshakeFragment hsf) { - - if ((nextRecordEpoch > hsf.recordEpoch) || - (nextRecordSeq > hsf.recordSeq) || - (nextMessageSeq > hsf.messageSeq)) { - // too old, discard this record + if (!isDesirable(hsf)) { + // Not a dedired record, discard it. return; } - // Is it the first message of next flight? - if ((flightTopMessageSeq == hsf.messageSeq) && - (hsf.fragmentOffset == 0) && (flightTopRecordSeq == -1)) { + // Clean up the retransmission messages if necessary. + cleanUpRetransmit(hsf); - flightType = hsf.handshakeType; - flightTopEpoch = hsf.recordEpoch; - flightTopRecordSeq = hsf.recordSeq; + // Is it the first message of next flight? + // + // Note: the Finished message is handled in the final CCS flight. + boolean isMinimalFlightMessage = false; + if (handshakeFlight.minMessageSeq == hsf.messageSeq) { + isMinimalFlightMessage = true; + } else if ((precedingFlight != null) && + (precedingFlight.minMessageSeq == hsf.messageSeq)) { + isMinimalFlightMessage = true; + } + + if (isMinimalFlightMessage && (hsf.fragmentOffset == 0) && + (hsf.handshakeType != HandshakeMessage.ht_finished)) { - if (hsf.handshakeType == HandshakeMessage.ht_server_hello) { - // Is it a session-resuming handshake? - try { - isAbbreviatedHandshake = - isSessionResuming(hsf.fragment, prevSessionID); - } catch (SSLException ssle) { - if (debug != null && Debug.isOn("ssl")) { - System.out.println( - Thread.currentThread().getName() + - " discard invalid record: " + ssle); - } + // reset the handshake flight + handshakeFlight.handshakeType = hsf.handshakeType; + handshakeFlight.flightEpoch = hsf.recordEpoch; + handshakeFlight.minMessageSeq = hsf.messageSeq; + } - // invalid, discard it [section 4.1.2.7, RFC 6347] - return; - } + if (hsf.handshakeType == HandshakeMessage.ht_finished) { + handshakeFlight.maxMessageSeq = hsf.messageSeq; + handshakeFlight.maxRecordEpoch = hsf.recordEpoch; + handshakeFlight.maxRecordSeq = hsf.recordSeq; + } else { + if (handshakeFlight.maxMessageSeq < hsf.messageSeq) { + handshakeFlight.maxMessageSeq = hsf.messageSeq; + } - if (!isAbbreviatedHandshake) { - prevSessionID = getSessionID(hsf.fragment); + int n = (hsf.recordEpoch - handshakeFlight.maxRecordEpoch); + if (n > 0) { + handshakeFlight.maxRecordEpoch = hsf.recordEpoch; + handshakeFlight.maxRecordSeq = hsf.recordSeq; + } else if (n == 0) { + // the same epoch + if (handshakeFlight.maxRecordSeq < hsf.recordSeq) { + handshakeFlight.maxRecordSeq = hsf.recordSeq; } - } + } // Otherwise, it is unlikely to happen. } boolean fragmented = false; @@ -578,7 +701,8 @@ fragmented = true; } - List holes = holesMap.get(hsf.handshakeType); + List holes = + handshakeFlight.holesMap.get(hsf.handshakeType); if (holes == null) { if (!fragmented) { holes = Collections.emptyList(); @@ -586,7 +710,7 @@ holes = new LinkedList(); holes.add(new HoleDescriptor(0, hsf.messageLength)); } - holesMap.put(hsf.handshakeType, holes); + handshakeFlight.holesMap.put(hsf.handshakeType, holes); } else if (holes.isEmpty()) { // Have got the full handshake message. This record may be // a handshake message retransmission. Discard this record. @@ -594,20 +718,11 @@ // It's OK to discard retransmission as the handshake hash // is computed as if each handshake message had been sent // as a single fragment. - // - // Note that ClientHello messages are delivered twice in - // DTLS handshaking. - if ((hsf.handshakeType != HandshakeMessage.ht_client_hello && - hsf.handshakeType != ht_hello_verify_request) || - (nextMessageSeq != hsf.messageSeq)) { - return; + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Have got the full message, discard it."); } - if (fragmented) { - holes = new LinkedList(); - holes.add(new HoleDescriptor(0, hsf.messageLength)); - } - holesMap.put(hsf.handshakeType, holes); + return; } if (fragmented) { @@ -628,9 +743,7 @@ (hole.limit < fragmentLimit))) { if (debug != null && Debug.isOn("ssl")) { - System.out.println( - Thread.currentThread().getName() + - " discard invalid record: " + + Debug.log("Discard invalid record: " + "handshake fragment ranges are overlapping"); } @@ -659,48 +772,205 @@ } } - // append this fragment - bufferedFragments.add(hsf); - - if ((lastHandshakeFragment == null) || - (lastHandshakeFragment.compareTo(hsf) < 0)) { - - lastHandshakeFragment = hsf; + // buffer this fragment + if (hsf.handshakeType == HandshakeMessage.ht_finished) { + // Need no status update. + bufferedFragments.add(hsf); + } else { + bufferFragment(hsf); } - - if (flightIsReady) { - flightIsReady = false; - } - needToCheckFlight = true; } - // queue up change_cipher_spec or encrypted message - void queueUpFragment(RecordFragment rf) { - if ((nextRecordEpoch > rf.recordEpoch) || - (nextRecordSeq > rf.recordSeq)) { - // too old, discard this record + // Queue up a ChangeCipherSpec message + void queueUpChangeCipherSpec(RecordFragment rf) { + if (!isDesirable(rf)) { + // Not a dedired record, discard it. return; } - // Is it the first message of next flight? - if (expectCCSFlight && - (rf.contentType == Record.ct_change_cipher_spec)) { + // Clean up the retransmission messages if necessary. + cleanUpRetransmit(rf); - flightType = (byte)0xFE; - flightTopEpoch = rf.recordEpoch; - flightTopRecordSeq = rf.recordSeq; + // Is it the first message of this flight? + // + // Note: the first message of the final flight is ChangeCipherSpec. + if (expectCCSFlight) { + handshakeFlight.handshakeType = HandshakeFlight.HF_UNKNOWN; + handshakeFlight.flightEpoch = rf.recordEpoch; + } + + // The epoch should be the same as the first message of the flight. + if (handshakeFlight.maxRecordSeq < rf.recordSeq) { + handshakeFlight.maxRecordSeq = rf.recordSeq; } + // buffer this fragment + bufferFragment(rf); + } + + // Queue up a ciphertext message. + // + // Note: not yet be able to decrypt the message. + void queueUpFragment(RecordFragment rf) { + if (!isDesirable(rf)) { + // Not a dedired record, discard it. + return; + } + + // Clean up the retransmission messages if necessary. + cleanUpRetransmit(rf); + + // buffer this fragment + bufferFragment(rf); + } + + private void bufferFragment(RecordFragment rf) { // append this fragment bufferedFragments.add(rf); if (flightIsReady) { flightIsReady = false; } - needToCheckFlight = true; + + if (!needToCheckFlight) { + needToCheckFlight = true; + } + } + + private void cleanUpRetransmit(RecordFragment rf) { + // Does the next flight start? + boolean isNewFlight = false; + if (precedingFlight != null) { + if (precedingFlight.flightEpoch < rf.recordEpoch) { + isNewFlight = true; + } else { + if (rf instanceof HandshakeFragment) { + HandshakeFragment hsf = (HandshakeFragment)rf; + if (precedingFlight.maxMessageSeq < hsf.messageSeq) { + isNewFlight = true; + } + } else if (rf.contentType != Record.ct_change_cipher_spec) { + // ciphertext + if (precedingFlight.maxRecordEpoch < rf.recordEpoch) { + isNewFlight = true; + } + } + } + } + + if (!isNewFlight) { + // Need no cleanup. + return; + } + + // clean up the buffer + for (Iterator it = bufferedFragments.iterator(); + it.hasNext();) { + + RecordFragment frag = it.next(); + boolean isOld = false; + if (frag.recordEpoch < precedingFlight.maxRecordEpoch) { + isOld = true; + } else if (frag.recordEpoch == precedingFlight.maxRecordEpoch) { + if (frag.recordSeq <= precedingFlight.maxRecordSeq) { + isOld = true; + } + } + + if (!isOld && (frag instanceof HandshakeFragment)) { + HandshakeFragment hsf = (HandshakeFragment)frag; + isOld = (hsf.messageSeq <= precedingFlight.maxMessageSeq); + } + + if (isOld) { + it.remove(); + } else { + // Safe to break as items in the buffer are ordered. + break; + } + } + + // discard retransmissions of the previous flight if any. + precedingFlight = null; } - boolean isEmpty() { + // Is a desired record? + // + // Check for retransmission and lost records. + private boolean isDesirable(RecordFragment rf) { + // + // Discard records old than the previous epoch. + // + int previousEpoch = nextRecordEpoch - 1; + if (rf.recordEpoch < previousEpoch) { + // Too old to use, discard this record. + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Too old epoch to use this record, discard it."); + } + + return false; + } + + // + // Allow retransmission of last flight of the previous epoch + // + // For example, the last server delivered flight for session + // resuming abbreviated handshaking consist three messages: + // ServerHello + // [ChangeCipherSpec] + // Finished + // + // The epoch number is incremented and the sequence number is reset + // if the ChangeCipherSpec is sent. + if (rf.recordEpoch == previousEpoch) { + boolean isDesired = true; + if (precedingFlight == null) { + isDesired = false; + } else { + if (rf instanceof HandshakeFragment) { + HandshakeFragment hsf = (HandshakeFragment)rf; + if (precedingFlight.minMessageSeq > hsf.messageSeq) { + isDesired = false; + } + } else if (rf.contentType == Record.ct_change_cipher_spec) { + // ChangeCipherSpec + if (precedingFlight.flightEpoch != rf.recordEpoch) { + isDesired = false; + } + } else { // ciphertext + if ((rf.recordEpoch < precedingFlight.maxRecordEpoch) || + (rf.recordEpoch == precedingFlight.maxRecordEpoch && + rf.recordSeq <= precedingFlight.maxRecordSeq)) { + isDesired = false; + } + } + } + + if (!isDesired) { + // Too old to use, discard this retransmitted record + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Too old retransmission to use, discard it."); + } + + return false; + } + } else if ((rf.recordEpoch == nextRecordEpoch) && + (nextRecordSeq > rf.recordSeq)) { + + // Previously disordered record for the current epoch. + // + // Should has been retransmitted. Discard this record. + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Lagging behind record (sequence), discard it."); + } + + return false; + } + + return true; + } + + private boolean isEmpty() { return (bufferedFragments.isEmpty() || (!flightIsReady && !needToCheckFlight) || (needToCheckFlight && !flightIsReady())); @@ -708,12 +978,9 @@ Plaintext acquirePlaintext() { if (bufferedFragments.isEmpty()) { - // reset the flight - if (flightIsReady) { - flightIsReady = false; - needToCheckFlight = false; + if (debug != null && Debug.isOn("verbose")) { + Debug.log("No received handshake messages"); } - return null; } @@ -721,27 +988,103 @@ // check the fligth status flightIsReady = flightIsReady(); - // set for next flight + // Reset if this flight is ready. if (flightIsReady) { - flightTopMessageSeq = lastHandshakeFragment.messageSeq + 1; - flightTopRecordSeq = -1; + // Retransmitted handshake messages are not needed for + // further handshaking processing. + if (handshakeFlight.isRetransmitOf(precedingFlight)) { + // cleanup + bufferedFragments.clear(); + + // Reset the next handshake flight. + resetHandshakeFlight(precedingFlight); + + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Received a retransmission flight."); + } + + return Plaintext.PLAINTEXT_NULL; + } } needToCheckFlight = false; } if (!flightIsReady) { + if (debug != null && Debug.isOn("verbose")) { + Debug.log("The handshake flight is not ready to use: " + + handshakeFlight.handshakeType); + } return null; } RecordFragment rFrag = bufferedFragments.first(); + Plaintext plaintext; if (!rFrag.isCiphertext) { // handshake message, or ChangeCipherSpec message - return acquireHandshakeMessage(); + plaintext = acquireHandshakeMessage(); + + // Reset the handshake flight. + if (bufferedFragments.isEmpty()) { + // Need not to backup the holes map. Clear up it at first. + handshakeFlight.holesMap.clear(); // cleanup holes map + + // Update the preceding flight. + precedingFlight = (HandshakeFlight)handshakeFlight.clone(); + + // Reset the next handshake flight. + resetHandshakeFlight(precedingFlight); + + if (expectCCSFlight && + (precedingFlight.flightEpoch == + HandshakeFlight.HF_UNKNOWN)) { + expectCCSFlight = false; + } + } } else { // a Finished message or other ciphertexts - return acquireCachedMessage(); + plaintext = acquireCachedMessage(); } + + return plaintext; + } + + // + // Reset the handshake flight from a previous one. + // + private void resetHandshakeFlight(HandshakeFlight prev) { + // Reset the next handshake flight. + handshakeFlight.handshakeType = HandshakeFlight.HF_UNKNOWN; + handshakeFlight.flightEpoch = prev.maxRecordEpoch; + if (prev.flightEpoch != prev.maxRecordEpoch) { + // a new epoch starts + handshakeFlight.minMessageSeq = 0; + } else { + // stay at the same epoch + // + // The minimal message sequence number will get updated if + // a flight retransmission happens. + handshakeFlight.minMessageSeq = prev.maxMessageSeq + 1; + } + + // cleanup the maximum sequence number and epoch number. + // + // Note: actually, we need to do nothing because the reassembler + // of handshake messages will reset them properly even for + // retransmissions. + // + handshakeFlight.maxMessageSeq = 0; + handshakeFlight.maxRecordEpoch = handshakeFlight.flightEpoch; + + // Record sequence number cannot wrap even for retransmissions. + handshakeFlight.maxRecordSeq = prev.maxRecordSeq + 1; + + // cleanup holes map + handshakeFlight.holesMap.clear(); + + // Ready to accept new input record. + flightIsReady = false; + needToCheckFlight = false; } private Plaintext acquireCachedMessage() { @@ -750,6 +1093,9 @@ if (readEpoch != rFrag.recordEpoch) { if (readEpoch > rFrag.recordEpoch) { // discard old records + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Discard old buffered ciphertext fragments."); + } bufferedFragments.remove(rFrag); // popup the fragment } @@ -757,6 +1103,10 @@ if (flightIsReady) { flightIsReady = false; } + + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Not yet ready to decrypt the cached fragments."); + } return null; } @@ -768,9 +1118,8 @@ plaintextFragment = decrypt(readAuthenticator, readCipher, rFrag.contentType, fragment, rFrag.recordEnS); } catch (BadPaddingException bpe) { - if (debug != null && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - " discard invalid record: " + bpe); + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Discard invalid record: " + bpe); } // invalid, discard this record [section 4.1.2.7, RFC 6347] @@ -782,7 +1131,6 @@ // beginning of the next flight) message. Need not to check // any ChangeCipherSpec message. if (rFrag.contentType == Record.ct_handshake) { - HandshakeFragment finFrag = null; while (plaintextFragment.remaining() > 0) { HandshakeFragment hsFrag = parseHandshakeMessage( rFrag.contentType, @@ -792,66 +1140,31 @@ if (hsFrag == null) { // invalid, discard this record + if (debug != null && Debug.isOn("verbose")) { + Debug.printHex( + "Invalid handshake fragment, discard it", + plaintextFragment); + } return null; } - if (hsFrag.handshakeType == HandshakeMessage.ht_finished) { - finFrag = hsFrag; - - // reset for the next flight - this.flightType = (byte)0xFF; - this.flightTopEpoch = rFrag.recordEpoch; - this.flightTopMessageSeq = hsFrag.messageSeq + 1; - this.flightTopRecordSeq = -1; - } else { - // reset the flight - if (flightIsReady) { - flightIsReady = false; - } - queueUpHandshake(hsFrag); + queueUpHandshake(hsFrag); + // The flight ready status (flightIsReady) should have + // been checked and updated for the Finished handshake + // message before the decryption. Please don't update + // flightIsReady for Finished messages. + if (hsFrag.handshakeType != HandshakeMessage.ht_finished) { + flightIsReady = false; + needToCheckFlight = true; } } - this.nextRecordSeq = rFrag.recordSeq + 1; - this.nextMessageSeq = 0; - - if (finFrag != null) { - this.nextRecordEpoch = finFrag.recordEpoch; - this.nextRecordSeq = finFrag.recordSeq + 1; - this.nextMessageSeq = finFrag.messageSeq + 1; - - // Finished message does not fragment. - byte[] recordFrag = new byte[finFrag.messageLength + 4]; - Plaintext plaintext = new Plaintext(finFrag.contentType, - finFrag.majorVersion, finFrag.minorVersion, - finFrag.recordEpoch, finFrag.recordSeq, - ByteBuffer.wrap(recordFrag)); - - // fill the handshake fragment of the record - recordFrag[0] = finFrag.handshakeType; - recordFrag[1] = - (byte)((finFrag.messageLength >>> 16) & 0xFF); - recordFrag[2] = - (byte)((finFrag.messageLength >>> 8) & 0xFF); - recordFrag[3] = (byte)(finFrag.messageLength & 0xFF); - - System.arraycopy(finFrag.fragment, 0, - recordFrag, 4, finFrag.fragmentLength); - - // handshake hashing - handshakeHashing(finFrag, plaintext); - - // input handshake finished - handshakeFinished = true; - - return plaintext; - } else { - return acquirePlaintext(); - } + return acquirePlaintext(); } else { return new Plaintext(rFrag.contentType, rFrag.majorVersion, rFrag.minorVersion, - rFrag.recordEpoch, rFrag.recordSeq, + rFrag.recordEpoch, + Authenticator.toLong(rFrag.recordEnS), plaintextFragment); } } @@ -861,17 +1174,23 @@ RecordFragment rFrag = bufferedFragments.first(); if (rFrag.contentType == Record.ct_change_cipher_spec) { this.nextRecordEpoch = rFrag.recordEpoch + 1; + + // For retransmissions, the next record sequence number is a + // positive value. Don't worry about it as the acquiring of + // the immediately followed Finished handshake message will + // reset the next record sequence number correctly. this.nextRecordSeq = 0; - // no change on next handshake message sequence number - bufferedFragments.remove(rFrag); // popup the fragment + // Popup the fragment. + bufferedFragments.remove(rFrag); // Reload if this message has been reserved for handshake hash. handshakeHash.reload(); return new Plaintext(rFrag.contentType, rFrag.majorVersion, rFrag.minorVersion, - rFrag.recordEpoch, rFrag.recordSeq, + rFrag.recordEpoch, + Authenticator.toLong(rFrag.recordEnS), ByteBuffer.wrap(rFrag.fragment)); } else { // rFrag.contentType == Record.ct_handshake HandshakeFragment hsFrag = (HandshakeFragment)rFrag; @@ -882,13 +1201,13 @@ // this.nextRecordEpoch = hsFrag.recordEpoch; this.nextRecordSeq = hsFrag.recordSeq + 1; - this.nextMessageSeq = hsFrag.messageSeq + 1; // Note: may try to avoid byte array copy in the future. byte[] recordFrag = new byte[hsFrag.messageLength + 4]; Plaintext plaintext = new Plaintext(hsFrag.contentType, hsFrag.majorVersion, hsFrag.minorVersion, - hsFrag.recordEpoch, hsFrag.recordSeq, + hsFrag.recordEpoch, + Authenticator.toLong(hsFrag.recordEnS), ByteBuffer.wrap(recordFrag)); // fill the handshake fragment of the record @@ -913,7 +1232,8 @@ byte[] recordFrag = new byte[hsFrag.messageLength + 4]; Plaintext plaintext = new Plaintext(hsFrag.contentType, hsFrag.majorVersion, hsFrag.minorVersion, - hsFrag.recordEpoch, hsFrag.recordSeq, + hsFrag.recordEpoch, + Authenticator.toLong(hsFrag.recordEnS), ByteBuffer.wrap(recordFrag)); // fill the handshake fragment of the record @@ -957,7 +1277,6 @@ handshakeHashing(hsFrag, plaintext); this.nextRecordSeq = maxRecodeSN + 1; - this.nextMessageSeq = msgSeq + 1; return plaintext; } @@ -966,15 +1285,26 @@ boolean flightIsReady() { - // - // the ChangeCipherSpec/Finished flight - // - if (expectCCSFlight) { - // Have the ChangeCipherSpec/Finished messages been received? - return hasFinisedMessage(bufferedFragments); - } + byte flightType = handshakeFlight.handshakeType; + if (flightType == HandshakeFlight.HF_UNKNOWN) { + // + // the ChangeCipherSpec/Finished flight + // + if (expectCCSFlight) { + // Have the ChangeCipherSpec/Finished flight been received? + boolean isReady = hasFinishedMessage(bufferedFragments); + if (debug != null && Debug.isOn("verbose")) { + Debug.log( + "Has the final flight been received? " + isReady); + } - if (flightType == (byte)0xFF) { + return isReady; + } + + if (debug != null && Debug.isOn("verbose")) { + Debug.log("No flight is received yet."); + } + return false; } @@ -983,7 +1313,12 @@ (flightType == HandshakeMessage.ht_hello_verify_request)) { // single handshake message flight - return hasCompleted(holesMap.get(flightType)); + boolean isReady = hasCompleted(flightType); + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Is the handshake message completed? " + isReady); + } + + return isReady; } // @@ -991,31 +1326,52 @@ // if (flightType == HandshakeMessage.ht_server_hello) { // Firstly, check the first flight handshake message. - if (!hasCompleted(holesMap.get(flightType))) { + if (!hasCompleted(flightType)) { + if (debug != null && Debug.isOn("verbose")) { + Debug.log( + "The ServerHello message is not completed yet."); + } + return false; } // // an abbreviated handshake // - if (isAbbreviatedHandshake) { - // Ready to use the flight if received the - // ChangeCipherSpec and Finished messages. - return hasFinisedMessage(bufferedFragments); + if (hasFinishedMessage(bufferedFragments)) { + if (debug != null && Debug.isOn("verbose")) { + Debug.log("It's an abbreviated handshake."); + } + + return true; } // // a full handshake // - if (lastHandshakeFragment.handshakeType != - HandshakeMessage.ht_server_hello_done) { + List holes = handshakeFlight.holesMap.get( + HandshakeMessage.ht_server_hello_done); + if ((holes == null) || !holes.isEmpty()) { // Not yet got the final message of the flight. + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Not yet got the ServerHelloDone message"); + } + return false; } // Have all handshake message been received? - return hasCompleted(bufferedFragments, - flightTopMessageSeq, lastHandshakeFragment.messageSeq); + boolean isReady = hasCompleted(bufferedFragments, + handshakeFlight.minMessageSeq, + handshakeFlight.maxMessageSeq); + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Is the ServerHello flight (message " + + handshakeFlight.minMessageSeq + "-" + + handshakeFlight.maxMessageSeq + + ") completed? " + isReady); + } + + return isReady; } // @@ -1029,92 +1385,65 @@ (flightType == HandshakeMessage.ht_client_key_exchange)) { // Firstly, check the first flight handshake message. - if (!hasCompleted(holesMap.get(flightType))) { - return false; - } + if (!hasCompleted(flightType)) { + if (debug != null && Debug.isOn("verbose")) { + Debug.log( + "The ClientKeyExchange or client Certificate " + + "message is not completed yet."); + } - if (!hasFinisedMessage(bufferedFragments)) { - // not yet got the ChangeCipherSpec/Finished messages return false; } - if (flightType == HandshakeMessage.ht_client_key_exchange) { - // single handshake message flight - return true; + // Is client CertificateVerify a mandatory message? + if (flightType == HandshakeMessage.ht_certificate) { + if (needClientVerify(bufferedFragments) && + !hasCompleted(ht_certificate_verify)) { + + if (debug != null && Debug.isOn("verbose")) { + Debug.log( + "Not yet have the CertificateVerify message"); + } + + return false; + } } - // - // flightType == HandshakeMessage.ht_certificate - // - // We don't support certificates containing fixed - // Diffie-Hellman parameters. Therefore, CertificateVerify - // message is required if client Certificate message presents. - // - if (lastHandshakeFragment.handshakeType != - HandshakeMessage.ht_certificate_verify) { - // Not yet got the final message of the flight. + if (!hasFinishedMessage(bufferedFragments)) { + // not yet have the ChangeCipherSpec/Finished messages + if (debug != null && Debug.isOn("verbose")) { + Debug.log( + "Not yet have the ChangeCipherSpec and " + + "Finished messages"); + } + return false; } // Have all handshake message been received? - return hasCompleted(bufferedFragments, - flightTopMessageSeq, lastHandshakeFragment.messageSeq); + boolean isReady = hasCompleted(bufferedFragments, + handshakeFlight.minMessageSeq, + handshakeFlight.maxMessageSeq); + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Is the ClientKeyExchange flight (message " + + handshakeFlight.minMessageSeq + "-" + + handshakeFlight.maxMessageSeq + + ") completed? " + isReady); + } + + return isReady; } // // Otherwise, need to receive more handshake messages. // - return false; - } - - private boolean isSessionResuming( - byte[] fragment, byte[] prevSid) throws SSLException { - - // As the first fragment of ServerHello should be big enough - // to hold the session_id field, need not to worry about the - // fragmentation here. - if ((fragment == null) || (fragment.length < 38)) { - // 38: the minimal ServerHello body length - throw new SSLException( - "Invalid ServerHello message: no sufficient data"); - } - - int sidLen = fragment[34]; // 34: the length field - if (sidLen > 32) { // opaque SessionID<0..32> - throw new SSLException( - "Invalid ServerHello message: invalid session id"); - } - - if (fragment.length < 38 + sidLen) { - throw new SSLException( - "Invalid ServerHello message: no sufficient data"); - } - - if (sidLen != 0 && (prevSid.length == sidLen)) { - // may be a session-resuming handshake - for (int i = 0; i < sidLen; i++) { - if (prevSid[i] != fragment[35 + i]) { - // 35: the session identifier - return false; - } - } - - return true; + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Need to receive more handshake messages"); } return false; } - private byte[] getSessionID(byte[] fragment) { - // The validity has been checked in the call to isSessionResuming(). - int sidLen = fragment[34]; // 34: the sessionID length field - - byte[] temporary = new byte[sidLen]; - System.arraycopy(fragment, 35, temporary, 0, sidLen); - - return temporary; - } - // Looking for the ChangeCipherSpec and Finished messages. // // As the cached Finished message should be a ciphertext, we don't @@ -1122,8 +1451,7 @@ // to the spec of TLS/DTLS handshaking, a Finished message is always // sent immediately after a ChangeCipherSpec message. The first // ciphertext handshake message should be the expected Finished message. - private boolean hasFinisedMessage( - Set fragments) { + private boolean hasFinishedMessage(Set fragments) { boolean hasCCS = false; boolean hasFin = false; @@ -1147,7 +1475,35 @@ return hasFin && hasCCS; } - private boolean hasCompleted(List holes) { + // Is client CertificateVerify a mandatory message? + // + // In the current implementation, client CertificateVerify is a + // mandatory message if the client Certificate is not empty. + private boolean needClientVerify(Set fragments) { + + // The caller should have checked the completion of the first + // present handshake message. Need not to check it again. + for (RecordFragment rFrag : fragments) { + if ((rFrag.contentType != Record.ct_handshake) || + rFrag.isCiphertext) { + break; + } + + HandshakeFragment hsFrag = (HandshakeFragment)rFrag; + if (hsFrag.handshakeType != HandshakeMessage.ht_certificate) { + continue; + } + + return (rFrag.fragment != null) && + (rFrag.fragment.length > DTLSRecord.minCertPlaintextSize); + } + + return false; + } + + private boolean hasCompleted(byte handshakeType) { + List holes = + handshakeFlight.holesMap.get(handshakeType); if (holes == null) { // not yet received this kind of handshake message return false; @@ -1173,7 +1529,7 @@ continue; } else if (hsFrag.messageSeq == (presentMsgSeq + 1)) { // check the completion of the handshake message - if (!hasCompleted(holesMap.get(hsFrag.handshakeType))) { + if (!hasCompleted(hsFrag.handshakeType)) { return false; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. 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 @@ -279,6 +279,16 @@ fragmenter = null; } + @Override + void launchRetransmission() { + // Note: Please don't retransmit if there are handshake messages + // or alerts waiting in the queue. + if (((alertMemos == null) || alertMemos.isEmpty()) && + (fragmenter != null) && fragmenter.isRetransmittable()) { + fragmenter.setRetransmission(); + } + } + // buffered record fragment private static class RecordMemo { byte contentType; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/security/ssl/DTLSRecord.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/DTLSRecord.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSRecord.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. 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 @@ -84,4 +84,18 @@ + maxPadding // padding + maxMacSize; // MAC + /* + * Minimum record size of Certificate handshake message. + * Client sends a certificate message containing no certificates if no + * suitable certificate is available. That is, the certificate_list + * structure has a length of zero. + * + * struct { + * ASN.1Cert certificate_list<0..2^24-1>; + * } Certificate; + */ + static final int minCertPlaintextSize = + headerSize // record header + + handshakeHeaderSize // handshake header + + 3; // cert list length } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/security/ssl/Debug.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. 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 @@ -145,6 +145,13 @@ } /** + * Print a message to stdout. + */ + static void log(String message) { + System.out.println(Thread.currentThread().getName() + ": " + message); + } + + /** * print a blank line to stderr that is prefixed with the prefix. */ @@ -156,7 +163,6 @@ /** * print a message to stderr that is prefixed with the prefix. */ - public static void println(String prefix, String message) { System.err.println(prefix + ": "+message); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/security/ssl/OutputRecord.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/OutputRecord.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/OutputRecord.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. 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 @@ -194,6 +194,11 @@ // blank } + // apply to DTLS SSLEngine + void launchRetransmission() { + // blank + } + @Override public synchronized void close() throws IOException { if (!isClosed) { @@ -224,6 +229,9 @@ sequenceNumber = authenticator.sequenceNumber(); } + // The sequence number may be shared for different purpose. + boolean sharedSequenceNumber = false; + // "flip" but skip over header again, add MAC & encrypt if (authenticator instanceof MAC) { MAC signer = (MAC)authenticator; @@ -243,6 +251,11 @@ // reset the position and limit destination.limit(destination.position()); destination.position(dstContent); + + // The signer has used and increased the sequence number. + if (isDTLS) { + sharedSequenceNumber = true; + } } } @@ -261,6 +274,11 @@ // Encrypt may pad, so again the limit may be changed. encCipher.encrypt(destination, dstLim); + + // The cipher has used and increased the sequence number. + if (isDTLS && encCipher.isAEADMode()) { + sharedSequenceNumber = true; + } } else { destination.position(destination.limit()); } @@ -290,8 +308,10 @@ destination.put(headerOffset + 11, (byte)(fragLen >> 8)); destination.put(headerOffset + 12, (byte)fragLen); - // Increase the sequence number for next use. - authenticator.increaseSequenceNumber(); + // Increase the sequence number for next use if it is not shared. + if (!sharedSequenceNumber) { + authenticator.increaseSequenceNumber(); + } } // Update destination position to reflect the amount of data produced. diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/security/ssl/Plaintext.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/Plaintext.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/Plaintext.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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 @@ -38,7 +38,7 @@ byte majorVersion; byte minorVersion; int recordEpoch; // incremented on every cipher state change - long recordSN; + long recordSN; // contains epcoh number (epoch | sequence) ByteBuffer fragment; // null if need to be reassembled HandshakeStatus handshakeStatus; // null if not used or not handshaking diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 @@ -994,7 +994,22 @@ // plainText should never be null for TLS protocols HandshakeStatus hsStatus = null; - if (!isDTLS || plainText != null) { + if (plainText == Plaintext.PLAINTEXT_NULL) { + // Only happens for DTLS protocols. + // + // Received a retransmitted flight, and need to retransmit the + // previous delivered handshake flight messages. + if (enableRetransmissions) { + if (debug != null && Debug.isOn("verbose")) { + Debug.log( + "Retransmit the previous handshake flight messages."); + } + + synchronized (this) { + outputRecord.launchRetransmission(); + } + } // Otherwise, discard the retransmitted flight. + } else if (!isDTLS || plainText != null) { hsStatus = processInputRecord(plainText, appData, offset, length); } @@ -1003,7 +1018,7 @@ } if (plainText == null) { - plainText = new Plaintext(); + plainText = Plaintext.PLAINTEXT_NULL; } plainText.handshakeStatus = hsStatus; @@ -1378,7 +1393,8 @@ // Acquire the buffered to-be-delivered records or retransmissions. // // May have buffered records, or need retransmission if handshaking. - if (!outputRecord.isEmpty() || (handshaker != null)) { + if (!outputRecord.isEmpty() || + (enableRetransmissions && handshaker != null)) { ciphertext = outputRecord.acquireCiphertext(netData); } @@ -1403,13 +1419,36 @@ HandshakeStatus hsStatus = null; Ciphertext.RecordType recordType = ciphertext.recordType; - if ((handshaker != null) && - (recordType.contentType == Record.ct_handshake) && - (recordType.handshakeType == HandshakeMessage.ht_finished) && - handshaker.isDone() && outputRecord.isEmpty()) { + if ((recordType.contentType == Record.ct_handshake) && + (recordType.handshakeType == HandshakeMessage.ht_finished) && + outputRecord.isEmpty()) { + + if (handshaker == null) { + hsStatus = HandshakeStatus.FINISHED; + } else if (handshaker.isDone()) { + hsStatus = finishHandshake(); + connectionState = cs_DATA; - hsStatus = finishHandshake(); - connectionState = cs_DATA; + // Retransmit the last flight twice. + // + // The application data transactions may begin immediately + // after the last flight. If the last flight get lost, the + // application data may be discarded accordingly. As could + // be an issue for some applications. This impact can be + // mitigated by sending the last fligth twice. + if (isDTLS && enableRetransmissions) { + if (debug != null && Debug.isOn("verbose")) { + Debug.log( + "Retransmit the last flight messages."); + } + + synchronized (this) { + outputRecord.launchRetransmission(); + } + + hsStatus = HandshakeStatus.NEED_WRAP; + } + } } // Otherwise, the followed call to getHSStatus() will help. /* @@ -1676,12 +1715,17 @@ synchronized void fatal(byte description, String diagnostic) throws SSLException { - fatal(description, diagnostic, null); + fatal(description, diagnostic, null, false); } synchronized void fatal(byte description, Throwable cause) throws SSLException { - fatal(description, null, cause); + fatal(description, null, cause, false); + } + + synchronized void fatal(byte description, String diagnostic, + Throwable cause) throws SSLException { + fatal(description, diagnostic, cause, false); } /* @@ -1693,12 +1737,12 @@ * levels which then call here. This code needs to determine * if one of the lower levels has already started the process. * - * We won't worry about Error's, if we have one of those, + * We won't worry about Errors, if we have one of those, * we're in worse trouble. Note: the networking code doesn't * deal with Errors either. */ synchronized void fatal(byte description, String diagnostic, - Throwable cause) throws SSLException { + Throwable cause, boolean recvFatalAlert) throws SSLException { /* * If we have no further information, make a general-purpose @@ -1759,10 +1803,11 @@ } /* - * If we haven't even started handshaking yet, no need - * to generate the fatal close alert. + * If we haven't even started handshaking yet, or we are the + * recipient of a fatal alert, no need to generate a fatal close + * alert. */ - if (oldState != cs_START) { + if (oldState != cs_START && !recvFatalAlert) { sendAlert(Alerts.alert_fatal, description); } @@ -1802,10 +1847,6 @@ byte level = fragment.get(); byte description = fragment.get(); - if (description == -1) { // check for short message - fatal(Alerts.alert_illegal_parameter, "Short alert message"); - } - if (debug != null && (Debug.isOn("record") || Debug.isOn("handshake"))) { synchronized (System.out) { @@ -1823,7 +1864,9 @@ } if (level == Alerts.alert_warning) { - if (description == Alerts.alert_close_notify) { + if (description == -1) { // check for short message + fatal(Alerts.alert_illegal_parameter, "Short alert message"); + } else if (description == Alerts.alert_close_notify) { if (connectionState == cs_HANDSHAKE) { fatal(Alerts.alert_unexpected_message, "Received close_notify during handshake"); @@ -1846,10 +1889,14 @@ } else { // fatal or unknown level String reason = "Received fatal alert: " + Alerts.alertDescription(description); - if (closeReason == null) { - closeReason = Alerts.getSSLException(description, reason); - } - fatal(Alerts.alert_unexpected_message, reason); + + // The inbound and outbound queues will be closed as part of + // the call to fatal. The handhaker to needs to be set to null + // so subsequent calls to getHandshakeStatus will return + // NOT_HANDSHAKING. + handshaker = null; + Throwable cause = Alerts.getSSLException(description, reason); + fatal(description, null, cause, true); } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java Fri Nov 11 16:44:36 2016 +0100 @@ -558,73 +558,6 @@ applicationProtocol = ""; } - // cookie exchange - if (isDTLS) { - HelloCookieManager hcMgr = sslContext.getHelloCookieManager(); - if ((mesg.cookie == null) || (mesg.cookie.length == 0) || - (!hcMgr.isValid(mesg))) { - - // - // Perform cookie exchange for DTLS handshaking if no cookie - // or the cookie is invalid in the ClientHello message. - // - HelloVerifyRequest m0 = new HelloVerifyRequest(hcMgr, mesg); - - if (debug != null && Debug.isOn("handshake")) { - m0.print(System.out); - } - - m0.write(output); - handshakeState.update(m0, resumingSession); - output.flush(); - - return; - } - } - - /* - * FIRST, construct the ServerHello using the options and priorities - * from the ClientHello. Update the (pending) cipher spec as we do - * so, and save the client's version to protect against rollback - * attacks. - * - * There are a bunch of minor tasks here, and one major one: deciding - * if the short or the full handshake sequence will be used. - */ - ServerHello m1 = new ServerHello(); - - clientRequestedVersion = mesg.protocolVersion; - - // select a proper protocol version. - ProtocolVersion selectedVersion = - selectProtocolVersion(clientRequestedVersion); - if (selectedVersion == null || - selectedVersion.v == ProtocolVersion.SSL20Hello.v) { - fatalSE(Alerts.alert_handshake_failure, - "Client requested protocol " + clientRequestedVersion + - " not enabled or not supported"); - } - - handshakeHash.protocolDetermined(selectedVersion); - setVersion(selectedVersion); - - m1.protocolVersion = protocolVersion; - - // - // random ... save client and server values for later use - // in computing the master secret (from pre-master secret) - // and thence the other crypto keys. - // - // NOTE: this use of three inputs to generating _each_ set - // of ciphers slows things down, but it does increase the - // security since each connection in the session can hold - // its own authenticated (and strong) keys. One could make - // creation of a session a rare thing... - // - clnt_random = mesg.clnt_random; - svr_random = new RandomCookie(sslContext.getSecureRandom()); - m1.svr_random = svr_random; - session = null; // forget about the current session // // Here we go down either of two paths: (a) the fast one, where @@ -732,6 +665,73 @@ } } // else client did not try to resume + // cookie exchange + if (isDTLS && !resumingSession) { + HelloCookieManager hcMgr = sslContext.getHelloCookieManager(); + if ((mesg.cookie == null) || (mesg.cookie.length == 0) || + (!hcMgr.isValid(mesg))) { + + // + // Perform cookie exchange for DTLS handshaking if no cookie + // or the cookie is invalid in the ClientHello message. + // + HelloVerifyRequest m0 = new HelloVerifyRequest(hcMgr, mesg); + + if (debug != null && Debug.isOn("handshake")) { + m0.print(System.out); + } + + m0.write(output); + handshakeState.update(m0, resumingSession); + output.flush(); + + return; + } + } + + /* + * FIRST, construct the ServerHello using the options and priorities + * from the ClientHello. Update the (pending) cipher spec as we do + * so, and save the client's version to protect against rollback + * attacks. + * + * There are a bunch of minor tasks here, and one major one: deciding + * if the short or the full handshake sequence will be used. + */ + ServerHello m1 = new ServerHello(); + + clientRequestedVersion = mesg.protocolVersion; + + // select a proper protocol version. + ProtocolVersion selectedVersion = + selectProtocolVersion(clientRequestedVersion); + if (selectedVersion == null || + selectedVersion.v == ProtocolVersion.SSL20Hello.v) { + fatalSE(Alerts.alert_handshake_failure, + "Client requested protocol " + clientRequestedVersion + + " not enabled or not supported"); + } + + handshakeHash.protocolDetermined(selectedVersion); + setVersion(selectedVersion); + + m1.protocolVersion = protocolVersion; + + // + // random ... save client and server values for later use + // in computing the master secret (from pre-master secret) + // and thence the other crypto keys. + // + // NOTE: this use of three inputs to generating _each_ set + // of ciphers slows things down, but it does increase the + // security since each connection in the session can hold + // its own authenticated (and strong) keys. One could make + // creation of a session a rare thing... + // + clnt_random = mesg.clnt_random; + svr_random = new RandomCookie(sslContext.getSecureRandom()); + m1.svr_random = svr_random; + // // If client hasn't specified a session we can resume, start a // new one and choose its cipher suite and compression options. diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/text/BreakDictionary.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/sun/text/BreakDictionary.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,306 @@ +/* + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved + * (C) Copyright IBM Corp. 1996 - 2002 - All Rights Reserved + * + * The original version of this source code and documentation + * is copyrighted and owned by Taligent, Inc., a wholly-owned + * subsidiary of IBM. These materials are provided under terms + * of a License Agreement between Taligent and Sun. This technology + * is protected by multiple US and International patents. + * + * This notice and attribution to Taligent may not be removed. + * Taligent is a registered trademark of Taligent, Inc. + */ +package sun.text; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.util.MissingResourceException; +import sun.text.CompactByteArray; +import sun.text.SupplementaryCharacterData; + +/** + * This is the class that represents the list of known words used by + * DictionaryBasedBreakIterator. The conceptual data structure used + * here is a trie: there is a node hanging off the root node for every + * letter that can start a word. Each of these nodes has a node hanging + * off of it for every letter that can be the second letter of a word + * if this node is the first letter, and so on. The trie is represented + * as a two-dimensional array that can be treated as a table of state + * transitions. Indexes are used to compress this array, taking + * advantage of the fact that this array will always be very sparse. + */ +class BreakDictionary { + + //========================================================================= + // data members + //========================================================================= + + /** + * The version of the dictionary that was read in. + */ + private static int supportedVersion = 1; + + /** + * Maps from characters to column numbers. The main use of this is to + * avoid making room in the array for empty columns. + */ + private CompactByteArray columnMap = null; + private SupplementaryCharacterData supplementaryCharColumnMap = null; + + /** + * The number of actual columns in the table + */ + private int numCols; + + /** + * Columns are organized into groups of 32. This says how many + * column groups. (We could calculate this, but we store the + * value to avoid having to repeatedly calculate it.) + */ + private int numColGroups; + + /** + * The actual compressed state table. Each conceptual row represents + * a state, and the cells in it contain the row numbers of the states + * to transition to for each possible letter. 0 is used to indicate + * an illegal combination of letters (i.e., the error state). The + * table is compressed by eliminating all the unpopulated (i.e., zero) + * cells. Multiple conceptual rows can then be doubled up in a single + * physical row by sliding them up and possibly shifting them to one + * side or the other so the populated cells don't collide. Indexes + * are used to identify unpopulated cells and to locate populated cells. + */ + private short[] table = null; + + /** + * This index maps logical row numbers to physical row numbers + */ + private short[] rowIndex = null; + + /** + * A bitmap is used to tell which cells in the comceptual table are + * populated. This array contains all the unique bit combinations + * in that bitmap. If the table is more than 32 columns wide, + * successive entries in this array are used for a single row. + */ + private int[] rowIndexFlags = null; + + /** + * This index maps from a logical row number into the bitmap table above. + * (This keeps us from storing duplicate bitmap combinations.) Since there + * are a lot of rows with only one populated cell, instead of wasting space + * in the bitmap table, we just store a negative number in this index for + * rows with one populated cell. The absolute value of that number is + * the column number of the populated cell. + */ + private short[] rowIndexFlagsIndex = null; + + /** + * For each logical row, this index contains a constant that is added to + * the logical column number to get the physical column number + */ + private byte[] rowIndexShifts = null; + + //========================================================================= + // deserialization + //========================================================================= + + BreakDictionary(String dictionaryName, byte[] dictionaryData) { + try { + setupDictionary(dictionaryName, dictionaryData); + } catch (BufferUnderflowException bue) { + MissingResourceException e; + e = new MissingResourceException("Corrupted dictionary data", + dictionaryName, ""); + e.initCause(bue); + throw e; + } + } + + private void setupDictionary(String dictionaryName, byte[] dictionaryData) { + ByteBuffer bb = ByteBuffer.wrap(dictionaryData); + + // check version + int version = bb.getInt(); + if (version != supportedVersion) { + throw new MissingResourceException("Dictionary version(" + version + ") is unsupported", + dictionaryName, ""); + } + + // Check data size + int len = bb.getInt(); + if (bb.position() + len != bb.limit()) { + throw new MissingResourceException("Dictionary size is wrong: " + bb.limit(), + dictionaryName, ""); + } + + // read in the column map for BMP characteres (this is serialized in + // its internal form: an index array followed by a data array) + len = bb.getInt(); + short[] temp = new short[len]; + for (int i = 0; i < len; i++) { + temp[i] = bb.getShort(); + } + len = bb.getInt(); + byte[] temp2 = new byte[len]; + bb.get(temp2); + columnMap = new CompactByteArray(temp, temp2); + + // read in numCols and numColGroups + numCols = bb.getInt(); + numColGroups = bb.getInt(); + + // read in the row-number index + len = bb.getInt(); + rowIndex = new short[len]; + for (int i = 0; i < len; i++) { + rowIndex[i] = bb.getShort(); + } + + // load in the populated-cells bitmap: index first, then bitmap list + len = bb.getInt(); + rowIndexFlagsIndex = new short[len]; + for (int i = 0; i < len; i++) { + rowIndexFlagsIndex[i] = bb.getShort(); + } + len = bb.getInt(); + rowIndexFlags = new int[len]; + for (int i = 0; i < len; i++) { + rowIndexFlags[i] = bb.getInt(); + } + + // load in the row-shift index + len = bb.getInt(); + rowIndexShifts = new byte[len]; + bb.get(rowIndexShifts); + + // load in the actual state table + len = bb.getInt(); + table = new short[len]; + for (int i = 0; i < len; i++) { + table[i] = bb.getShort(); + } + + // finally, prepare the column map for supplementary characters + len = bb.getInt(); + int[] temp3 = new int[len]; + for (int i = 0; i < len; i++) { + temp3[i] = bb.getInt(); + } + assert bb.position() == bb.limit(); + + supplementaryCharColumnMap = new SupplementaryCharacterData(temp3); + } + + //========================================================================= + // access to the words + //========================================================================= + + /** + * Uses the column map to map the character to a column number, then + * passes the row and column number to getNextState() + * @param row The current state + * @param ch The character whose column we're interested in + * @return The new state to transition to + */ + public final short getNextStateFromCharacter(int row, int ch) { + int col; + if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + col = columnMap.elementAt((char)ch); + } else { + col = supplementaryCharColumnMap.getValue(ch); + } + return getNextState(row, col); + } + + /** + * Returns the value in the cell with the specified (logical) row and + * column numbers. In DictionaryBasedBreakIterator, the row number is + * a state number, the column number is an input, and the return value + * is the row number of the new state to transition to. (0 is the + * "error" state, and -1 is the "end of word" state in a dictionary) + * @param row The row number of the current state + * @param col The column number of the input character (0 means "not a + * dictionary character") + * @return The row number of the new state to transition to + */ + public final short getNextState(int row, int col) { + if (cellIsPopulated(row, col)) { + // we map from logical to physical row number by looking up the + // mapping in rowIndex; we map from logical column number to + // physical column number by looking up a shift value for this + // logical row and offsetting the logical column number by + // the shift amount. Then we can use internalAt() to actually + // get the value out of the table. + return internalAt(rowIndex[row], col + rowIndexShifts[row]); + } + else { + return 0; + } + } + + /** + * Given (logical) row and column numbers, returns true if the + * cell in that position is populated + */ + private boolean cellIsPopulated(int row, int col) { + // look up the entry in the bitmap index for the specified row. + // If it's a negative number, it's the column number of the only + // populated cell in the row + if (rowIndexFlagsIndex[row] < 0) { + return col == -rowIndexFlagsIndex[row]; + } + + // if it's a positive number, it's the offset of an entry in the bitmap + // list. If the table is more than 32 columns wide, the bitmap is stored + // successive entries in the bitmap list, so we have to divide the column + // number by 32 and offset the number we got out of the index by the result. + // Once we have the appropriate piece of the bitmap, test the appropriate + // bit and return the result. + else { + int flags = rowIndexFlags[rowIndexFlagsIndex[row] + (col >> 5)]; + return (flags & (1 << (col & 0x1f))) != 0; + } + } + + /** + * Implementation of getNextState() when we know the specified cell is + * populated. + * @param row The PHYSICAL row number of the cell + * @param col The PHYSICAL column number of the cell + * @return The value stored in the cell + */ + private short internalAt(int row, int col) { + // the table is a one-dimensional array, so this just does the math necessary + // to treat it as a two-dimensional array (we don't just use a two-dimensional + // array because two-dimensional arrays are inefficient in Java) + return table[row * numCols + col]; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/text/DictionaryBasedBreakIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/sun/text/DictionaryBasedBreakIterator.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,526 @@ +/* + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved + * (C) Copyright IBM Corp. 1996 - 2002 - All Rights Reserved + * + * The original version of this source code and documentation + * is copyrighted and owned by Taligent, Inc., a wholly-owned + * subsidiary of IBM. These materials are provided under terms + * of a License Agreement between Taligent and Sun. This technology + * is protected by multiple US and International patents. + * + * This notice and attribution to Taligent may not be removed. + * Taligent is a registered trademark of Taligent, Inc. + */ + +package sun.text; + +import java.text.CharacterIterator; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * A subclass of RuleBasedBreakIterator that adds the ability to use a dictionary + * to further subdivide ranges of text beyond what is possible using just the + * state-table-based algorithm. This is necessary, for example, to handle + * word and line breaking in Thai, which doesn't use spaces between words. The + * state-table-based algorithm used by RuleBasedBreakIterator is used to divide + * up text as far as possible, and then contiguous ranges of letters are + * repeatedly compared against a list of known words (i.e., the dictionary) + * to divide them up into words. + * + * DictionaryBasedBreakIterator uses the same rule language as RuleBasedBreakIterator, + * but adds one more special substitution name: <dictionary>. This substitution + * name is used to identify characters in words in the dictionary. The idea is that + * if the iterator passes over a chunk of text that includes two or more characters + * in a row that are included in <dictionary>, it goes back through that range and + * derives additional break positions (if possible) using the dictionary. + * + * DictionaryBasedBreakIterator is also constructed with the filename of a dictionary + * file. It follows a prescribed search path to locate the dictionary (right now, + * it looks for it in /com/ibm/text/resources in each directory in the classpath, + * and won't find it in JAR files, but this location is likely to change). The + * dictionary file is in a serialized binary format. We have a very primitive (and + * slow) BuildDictionaryFile utility for creating dictionary files, but aren't + * currently making it public. Contact us for help. + */ +public class DictionaryBasedBreakIterator extends RuleBasedBreakIterator { + + /** + * a list of known words that is used to divide up contiguous ranges of letters, + * stored in a compressed, indexed, format that offers fast access + */ + private BreakDictionary dictionary; + + /** + * a list of flags indicating which character categories are contained in + * the dictionary file (this is used to determine which ranges of characters + * to apply the dictionary to) + */ + private boolean[] categoryFlags; + + /** + * a temporary hiding place for the number of dictionary characters in the + * last range passed over by next() + */ + private int dictionaryCharCount; + + /** + * when a range of characters is divided up using the dictionary, the break + * positions that are discovered are stored here, preventing us from having + * to use either the dictionary or the state table again until the iterator + * leaves this range of text + */ + private int[] cachedBreakPositions; + + /** + * if cachedBreakPositions is not null, this indicates which item in the + * cache the current iteration position refers to + */ + private int positionInCache; + + /** + * Constructs a DictionaryBasedBreakIterator. + * + * @param ruleFile the name of the rule data file + * @param ruleData the rule data loaded from the rule data file + * @param dictionaryFile the name of the dictionary file + * @param dictionartData the dictionary data loaded from the dictionary file + * @throws MissingResourceException if rule data or dictionary initialization failed + */ + public DictionaryBasedBreakIterator(String ruleFile, byte[] ruleData, + String dictionaryFile, byte[] dictionaryData) { + super(ruleFile, ruleData); + byte[] tmp = super.getAdditionalData(); + if (tmp != null) { + prepareCategoryFlags(tmp); + super.setAdditionalData(null); + } + dictionary = new BreakDictionary(dictionaryFile, dictionaryData); + } + + private void prepareCategoryFlags(byte[] data) { + categoryFlags = new boolean[data.length]; + for (int i = 0; i < data.length; i++) { + categoryFlags[i] = (data[i] == (byte)1) ? true : false; + } + } + + @Override + public void setText(CharacterIterator newText) { + super.setText(newText); + cachedBreakPositions = null; + dictionaryCharCount = 0; + positionInCache = 0; + } + + /** + * Sets the current iteration position to the beginning of the text. + * (i.e., the CharacterIterator's starting offset). + * @return The offset of the beginning of the text. + */ + @Override + public int first() { + cachedBreakPositions = null; + dictionaryCharCount = 0; + positionInCache = 0; + return super.first(); + } + + /** + * Sets the current iteration position to the end of the text. + * (i.e., the CharacterIterator's ending offset). + * @return The text's past-the-end offset. + */ + @Override + public int last() { + cachedBreakPositions = null; + dictionaryCharCount = 0; + positionInCache = 0; + return super.last(); + } + + /** + * Advances the iterator one step backwards. + * @return The position of the last boundary position before the + * current iteration position + */ + @Override + public int previous() { + CharacterIterator text = getText(); + + // if we have cached break positions and we're still in the range + // covered by them, just move one step backward in the cache + if (cachedBreakPositions != null && positionInCache > 0) { + --positionInCache; + text.setIndex(cachedBreakPositions[positionInCache]); + return cachedBreakPositions[positionInCache]; + } + + // otherwise, dump the cache and use the inherited previous() method to move + // backward. This may fill up the cache with new break positions, in which + // case we have to mark our position in the cache + else { + cachedBreakPositions = null; + int result = super.previous(); + if (cachedBreakPositions != null) { + positionInCache = cachedBreakPositions.length - 2; + } + return result; + } + } + + /** + * Sets the current iteration position to the last boundary position + * before the specified position. + * @param offset The position to begin searching from + * @return The position of the last boundary before "offset" + */ + @Override + public int preceding(int offset) { + CharacterIterator text = getText(); + checkOffset(offset, text); + + // if we have no cached break positions, or "offset" is outside the + // range covered by the cache, we can just call the inherited routine + // (which will eventually call other routines in this class that may + // refresh the cache) + if (cachedBreakPositions == null || offset <= cachedBreakPositions[0] || + offset > cachedBreakPositions[cachedBreakPositions.length - 1]) { + cachedBreakPositions = null; + return super.preceding(offset); + } + + // on the other hand, if "offset" is within the range covered by the cache, + // then all we have to do is search the cache for the last break position + // before "offset" + else { + positionInCache = 0; + while (positionInCache < cachedBreakPositions.length + && offset > cachedBreakPositions[positionInCache]) { + ++positionInCache; + } + --positionInCache; + text.setIndex(cachedBreakPositions[positionInCache]); + return text.getIndex(); + } + } + + /** + * Sets the current iteration position to the first boundary position after + * the specified position. + * @param offset The position to begin searching forward from + * @return The position of the first boundary after "offset" + */ + @Override + public int following(int offset) { + CharacterIterator text = getText(); + checkOffset(offset, text); + + // if we have no cached break positions, or if "offset" is outside the + // range covered by the cache, then dump the cache and call our + // inherited following() method. This will call other methods in this + // class that may refresh the cache. + if (cachedBreakPositions == null || offset < cachedBreakPositions[0] || + offset >= cachedBreakPositions[cachedBreakPositions.length - 1]) { + cachedBreakPositions = null; + return super.following(offset); + } + + // on the other hand, if "offset" is within the range covered by the + // cache, then just search the cache for the first break position + // after "offset" + else { + positionInCache = 0; + while (positionInCache < cachedBreakPositions.length + && offset >= cachedBreakPositions[positionInCache]) { + ++positionInCache; + } + text.setIndex(cachedBreakPositions[positionInCache]); + return text.getIndex(); + } + } + + /** + * This is the implementation function for next(). + */ + @Override + protected int handleNext() { + CharacterIterator text = getText(); + + // if there are no cached break positions, or if we've just moved + // off the end of the range covered by the cache, we have to dump + // and possibly regenerate the cache + if (cachedBreakPositions == null || + positionInCache == cachedBreakPositions.length - 1) { + + // start by using the inherited handleNext() to find a tentative return + // value. dictionaryCharCount tells us how many dictionary characters + // we passed over on our way to the tentative return value + int startPos = text.getIndex(); + dictionaryCharCount = 0; + int result = super.handleNext(); + + // if we passed over more than one dictionary character, then we use + // divideUpDictionaryRange() to regenerate the cached break positions + // for the new range + if (dictionaryCharCount > 1 && result - startPos > 1) { + divideUpDictionaryRange(startPos, result); + } + + // otherwise, the value we got back from the inherited fuction + // is our return value, and we can dump the cache + else { + cachedBreakPositions = null; + return result; + } + } + + // if the cache of break positions has been regenerated (or existed all + // along), then just advance to the next break position in the cache + // and return it + if (cachedBreakPositions != null) { + ++positionInCache; + text.setIndex(cachedBreakPositions[positionInCache]); + return cachedBreakPositions[positionInCache]; + } + return -9999; // SHOULD NEVER GET HERE! + } + + /** + * Looks up a character category for a character. + */ + @Override + protected int lookupCategory(int c) { + // this override of lookupCategory() exists only to keep track of whether we've + // passed over any dictionary characters. It calls the inherited lookupCategory() + // to do the real work, and then checks whether its return value is one of the + // categories represented in the dictionary. If it is, bump the dictionary- + // character count. + int result = super.lookupCategory(c); + if (result != RuleBasedBreakIterator.IGNORE && categoryFlags[result]) { + ++dictionaryCharCount; + } + return result; + } + + /** + * This is the function that actually implements the dictionary-based + * algorithm. Given the endpoints of a range of text, it uses the + * dictionary to determine the positions of any boundaries in this + * range. It stores all the boundary positions it discovers in + * cachedBreakPositions so that we only have to do this work once + * for each time we enter the range. + */ + @SuppressWarnings("unchecked") + private void divideUpDictionaryRange(int startPos, int endPos) { + CharacterIterator text = getText(); + + // the range we're dividing may begin or end with non-dictionary characters + // (i.e., for line breaking, we may have leading or trailing punctuation + // that needs to be kept with the word). Seek from the beginning of the + // range to the first dictionary character + text.setIndex(startPos); + int c = getCurrent(); + int category = lookupCategory(c); + while (category == IGNORE || !categoryFlags[category]) { + c = getNext(); + category = lookupCategory(c); + } + + // initialize. We maintain two stacks: currentBreakPositions contains + // the list of break positions that will be returned if we successfully + // finish traversing the whole range now. possibleBreakPositions lists + // all other possible word ends we've passed along the way. (Whenever + // we reach an error [a sequence of characters that can't begin any word + // in the dictionary], we back up, possibly delete some breaks from + // currentBreakPositions, move a break from possibleBreakPositions + // to currentBreakPositions, and start over from there. This process + // continues in this way until we either successfully make it all the way + // across the range, or exhaust all of our combinations of break + // positions.) + Stack currentBreakPositions = new Stack<>(); + Stack possibleBreakPositions = new Stack<>(); + List wrongBreakPositions = new ArrayList<>(); + + // the dictionary is implemented as a trie, which is treated as a state + // machine. -1 represents the end of a legal word. Every word in the + // dictionary is represented by a path from the root node to -1. A path + // that ends in state 0 is an illegal combination of characters. + int state = 0; + + // these two variables are used for error handling. We keep track of the + // farthest we've gotten through the range being divided, and the combination + // of breaks that got us that far. If we use up all possible break + // combinations, the text contains an error or a word that's not in the + // dictionary. In this case, we "bless" the break positions that got us the + // farthest as real break positions, and then start over from scratch with + // the character where the error occurred. + int farthestEndPoint = text.getIndex(); + Stack bestBreakPositions = null; + + // initialize (we always exit the loop with a break statement) + c = getCurrent(); + while (true) { + + // if we can transition to state "-1" from our current state, we're + // on the last character of a legal word. Push that position onto + // the possible-break-positions stack + if (dictionary.getNextState(state, 0) == -1) { + possibleBreakPositions.push(text.getIndex()); + } + + // look up the new state to transition to in the dictionary + state = dictionary.getNextStateFromCharacter(state, c); + + // if the character we're sitting on causes us to transition to + // the "end of word" state, then it was a non-dictionary character + // and we've successfully traversed the whole range. Drop out + // of the loop. + if (state == -1) { + currentBreakPositions.push(text.getIndex()); + break; + } + + // if the character we're sitting on causes us to transition to + // the error state, or if we've gone off the end of the range + // without transitioning to the "end of word" state, we've hit + // an error... + else if (state == 0 || text.getIndex() >= endPos) { + + // if this is the farthest we've gotten, take note of it in + // case there's an error in the text + if (text.getIndex() > farthestEndPoint) { + farthestEndPoint = text.getIndex(); + + @SuppressWarnings("unchecked") + Stack currentBreakPositionsCopy = (Stack) currentBreakPositions.clone(); + + bestBreakPositions = currentBreakPositionsCopy; + } + + // wrongBreakPositions is a list of all break positions + // we've tried starting that didn't allow us to traverse + // all the way through the text. Every time we pop a + // break position off of currentBreakPositions, we put it + // into wrongBreakPositions to avoid trying it again later. + // If we make it to this spot, we're either going to back + // up to a break in possibleBreakPositions and try starting + // over from there, or we've exhausted all possible break + // positions and are going to do the fallback procedure. + // This loop prevents us from messing with anything in + // possibleBreakPositions that didn't work as a starting + // point the last time we tried it (this is to prevent a bunch of + // repetitive checks from slowing down some extreme cases) + while (!possibleBreakPositions.isEmpty() + && wrongBreakPositions.contains(possibleBreakPositions.peek())) { + possibleBreakPositions.pop(); + } + + // if we've used up all possible break-position combinations, there's + // an error or an unknown word in the text. In this case, we start + // over, treating the farthest character we've reached as the beginning + // of the range, and "blessing" the break positions that got us that + // far as real break positions + if (possibleBreakPositions.isEmpty()) { + if (bestBreakPositions != null) { + currentBreakPositions = bestBreakPositions; + if (farthestEndPoint < endPos) { + text.setIndex(farthestEndPoint + 1); + } + else { + break; + } + } + else { + if ((currentBreakPositions.size() == 0 || + currentBreakPositions.peek().intValue() != text.getIndex()) + && text.getIndex() != startPos) { + currentBreakPositions.push(text.getIndex()); + } + getNext(); + currentBreakPositions.push(text.getIndex()); + } + } + + // if we still have more break positions we can try, then promote the + // last break in possibleBreakPositions into currentBreakPositions, + // and get rid of all entries in currentBreakPositions that come after + // it. Then back up to that position and start over from there (i.e., + // treat that position as the beginning of a new word) + else { + Integer temp = possibleBreakPositions.pop(); + Integer temp2 = null; + while (!currentBreakPositions.isEmpty() && temp.intValue() < + currentBreakPositions.peek().intValue()) { + temp2 = currentBreakPositions.pop(); + wrongBreakPositions.add(temp2); + } + currentBreakPositions.push(temp); + text.setIndex(currentBreakPositions.peek().intValue()); + } + + // re-sync "c" for the next go-round, and drop out of the loop if + // we've made it off the end of the range + c = getCurrent(); + if (text.getIndex() >= endPos) { + break; + } + } + + // if we didn't hit any exceptional conditions on this last iteration, + // just advance to the next character and loop + else { + c = getNext(); + } + } + + // dump the last break position in the list, and replace it with the actual + // end of the range (which may be the same character, or may be further on + // because the range actually ended with non-dictionary characters we want to + // keep with the word) + if (!currentBreakPositions.isEmpty()) { + currentBreakPositions.pop(); + } + currentBreakPositions.push(endPos); + + // create a regular array to hold the break positions and copy + // the break positions from the stack to the array (in addition, + // our starting position goes into this array as a break position). + // This array becomes the cache of break positions used by next() + // and previous(), so this is where we actually refresh the cache. + cachedBreakPositions = new int[currentBreakPositions.size() + 1]; + cachedBreakPositions[0] = startPos; + + for (int i = 0; i < currentBreakPositions.size(); i++) { + cachedBreakPositions[i + 1] = currentBreakPositions.elementAt(i).intValue(); + } + positionInCache = 0; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,1144 @@ +/* + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved + * (C) Copyright IBM Corp. 1996 - 2002 - All Rights Reserved + * + * The original version of this source code and documentation + * is copyrighted and owned by Taligent, Inc., a wholly-owned + * subsidiary of IBM. These materials are provided under terms + * of a License Agreement between Taligent and Sun. This technology + * is protected by multiple US and International patents. + * + * This notice and attribution to Taligent may not be removed. + * Taligent is a registered trademark of Taligent, Inc. + */ + +package sun.text; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.text.BreakIterator; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.MissingResourceException; +import sun.text.CompactByteArray; +import sun.text.SupplementaryCharacterData; + +/** + *

    A subclass of BreakIterator whose behavior is specified using a list of rules.

    + * + *

    There are two kinds of rules, which are separated by semicolons: substitutions + * and regular expressions.

    + * + *

    A substitution rule defines a name that can be used in place of an expression. It + * consists of a name, which is a string of characters contained in angle brackets, an equals + * sign, and an expression. (There can be no whitespace on either side of the equals sign.) + * To keep its syntactic meaning intact, the expression must be enclosed in parentheses or + * square brackets. A substitution is visible after its definition, and is filled in using + * simple textual substitution. Substitution definitions can contain other substitutions, as + * long as those substitutions have been defined first. Substitutions are generally used to + * make the regular expressions (which can get quite complex) shorted and easier to read. + * They typically define either character categories or commonly-used subexpressions.

    + * + *

    There is one special substitution.  If the description defines a substitution + * called "<ignore>", the expression must be a [] expression, and the + * expression defines a set of characters (the "ignore characters") that + * will be transparent to the BreakIterator.  A sequence of characters will break the + * same way it would if any ignore characters it contains are taken out.  Break + * positions never occur befoer ignore characters.

    + * + *

    A regular expression uses a subset of the normal Unix regular-expression syntax, and + * defines a sequence of characters to be kept together. With one significant exception, the + * iterator uses a longest-possible-match algorithm when matching text to regular + * expressions. The iterator also treats descriptions containing multiple regular expressions + * as if they were ORed together (i.e., as if they were separated by |).

    + * + *

    The special characters recognized by the regular-expression parser are as follows:

    + * + *
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    *Specifies that the expression preceding the asterisk may occur any number + * of times (including not at all).
    {}Encloses a sequence of characters that is optional.
    ()Encloses a sequence of characters.  If followed by *, the sequence + * repeats.  Otherwise, the parentheses are just a grouping device and a way to delimit + * the ends of expressions containing |.
    |Separates two alternative sequences of characters.  Either one + * sequence or the other, but not both, matches this expression.  The | character can + * only occur inside ().
    .Matches any character.
    *?Specifies a non-greedy asterisk.  *? works the same way as *, except + * when there is overlap between the last group of characters in the expression preceding the + * * and the first group of characters following the *.  When there is this kind of + * overlap, * will match the longest sequence of characters that match the expression before + * the *, and *? will match the shortest sequence of characters matching the expression + * before the *?.  For example, if you have "xxyxyyyxyxyxxyxyxyy" in the text, + * "x[xy]*x" will match through to the last x (i.e., "xxyxyyyxyxyxxyxyxyy", + * but "x[xy]*?x" will only match the first two xes ("xxyxyyyxyxyxxyxyxyy").
    []Specifies a group of alternative characters.  A [] expression will + * match any single character that is specified in the [] expression.  For more on the + * syntax of [] expressions, see below.
    /Specifies where the break position should go if text matches this + * expression.  (e.g., "[a-z]*/[:Zs:]*[1-0]" will match if the iterator sees a run + * of letters, followed by a run of whitespace, followed by a digit, but the break position + * will actually go before the whitespace).  Expressions that don't contain / put the + * break position at the end of the matching text.
    \Escape character.  The \ itself is ignored, but causes the next + * character to be treated as literal character.  This has no effect for many + * characters, but for the characters listed above, this deprives them of their special + * meaning.  (There are no special escape sequences for Unicode characters, or tabs and + * newlines; these are all handled by a higher-level protocol.  In a Java string, + * "\n" will be converted to a literal newline character by the time the + * regular-expression parser sees it.  Of course, this means that \ sequences that are + * visible to the regexp parser must be written as \\ when inside a Java string.)  All + * characters in the ASCII range except for letters, digits, and control characters are + * reserved characters to the parser and must be preceded by \ even if they currently don't + * mean anything.
    !If ! appears at the beginning of a regular expression, it tells the regexp + * parser that this expression specifies the backwards-iteration behavior of the iterator, + * and not its normal iteration behavior.  This is generally only used in situations + * where the automatically-generated backwards-iteration brhavior doesn't produce + * satisfactory results and must be supplemented with extra client-specified rules.
    (all others)All other characters are treated as literal characters, which must match + * the corresponding character(s) in the text exactly.
    + *
    + * + *

    Within a [] expression, a number of other special characters can be used to specify + * groups of characters:

    + * + *
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    -Specifies a range of matching characters.  For example + * "[a-p]" matches all lowercase Latin letters from a to p (inclusive).  The - + * sign specifies ranges of continuous Unicode numeric values, not ranges of characters in a + * language's alphabetical order: "[a-z]" doesn't include capital letters, nor does + * it include accented letters such as a-umlaut.
    ::A pair of colons containing a one- or two-letter code matches all + * characters in the corresponding Unicode category.  The two-letter codes are the same + * as the two-letter codes in the Unicode database (for example, "[:Sc::Sm:]" + * matches all currency symbols and all math symbols).  Specifying a one-letter code is + * the same as specifying all two-letter codes that begin with that letter (for example, + * "[:L:]" matches all letters, and is equivalent to + * "[:Lu::Ll::Lo::Lm::Lt:]").  Anything other than a valid two-letter Unicode + * category code or a single letter that begins a Unicode category code is illegal within + * colons.
    [][] expressions can nest.  This has no effect, except when used in + * conjunction with the ^ token.
    ^Excludes the character (or the characters in the [] expression) following + * it from the group of characters.  For example, "[a-z^p]" matches all Latin + * lowercase letters except p.  "[:L:^[\u4e00-\u9fff]]" matches all letters + * except the Han ideographs.
    (all others)All other characters are treated as literal characters.  (For + * example, "[aeiou]" specifies just the letters a, e, i, o, and u.)
    + *
    + * + *

    For a more complete explanation, see http://www.ibm.com/java/education/boundaries/boundaries.html. + *   For examples, see the resource data (which is annotated).

    + * + * @author Richard Gillam + */ +public class RuleBasedBreakIterator extends BreakIterator { + + /** + * A token used as a character-category value to identify ignore characters + */ + protected static final byte IGNORE = -1; + + /** + * The state number of the starting state + */ + private static final short START_STATE = 1; + + /** + * The state-transition value indicating "stop" + */ + private static final short STOP_STATE = 0; + + /** + * Magic number for the BreakIterator data file format. + */ + static final byte[] LABEL = { + (byte)'B', (byte)'I', (byte)'d', (byte)'a', (byte)'t', (byte)'a', + (byte)'\0' + }; + static final int LABEL_LENGTH = LABEL.length; + + /** + * Version number of the dictionary that was read in. + */ + static final byte supportedVersion = 1; + + /** + * An array length of indices for BMP characters + */ + private static final int BMP_INDICES_LENGTH = 512; + + /** + * Tables that indexes from character values to character category numbers + */ + private CompactByteArray charCategoryTable = null; + private SupplementaryCharacterData supplementaryCharCategoryTable = null; + + /** + * The table of state transitions used for forward iteration + */ + private short[] stateTable = null; + + /** + * The table of state transitions used to sync up the iterator with the + * text in backwards and random-access iteration + */ + private short[] backwardsStateTable = null; + + /** + * A list of flags indicating which states in the state table are accepting + * ("end") states + */ + private boolean[] endStates = null; + + /** + * A list of flags indicating which states in the state table are + * lookahead states (states which turn lookahead on and off) + */ + private boolean[] lookaheadStates = null; + + /** + * A table for additional data. May be used by a subclass of + * RuleBasedBreakIterator. + */ + private byte[] additionalData = null; + + /** + * The number of character categories (and, thus, the number of columns in + * the state tables) + */ + private int numCategories; + + /** + * The character iterator through which this BreakIterator accesses the text + */ + private CharacterIterator text = null; + + /** + * A CRC32 value of all data in datafile + */ + private long checksum; + + //======================================================================= + // constructors + //======================================================================= + + /** + * Constructs a RuleBasedBreakIterator using the given rule data. + * + * @throws MissingResourceException if the rule data is invalid or corrupted + */ + public RuleBasedBreakIterator(String ruleFile, byte[] ruleData) { + ByteBuffer bb = ByteBuffer.wrap(ruleData); + try { + validateRuleData(ruleFile, bb); + setupTables(ruleFile, bb); + } catch (BufferUnderflowException bue) { + MissingResourceException e; + e = new MissingResourceException("Corrupted rule data file", ruleFile, ""); + e.initCause(bue); + throw e; + } + } + + /** + * Initializes the fields with the given rule data. + * The data format is as follows: + *
    +     *   BreakIteratorData {
    +     *       u1           magic[7];
    +     *       u1           version;
    +     *       u4           totalDataSize;
    +     *       header_info  header;
    +     *       body         value;
    +     *   }
    +     * 
    + * totalDataSize is the summation of the size of + * header_info and body in byte count. + *

    + * In header, each field except for checksum implies the + * length of each field. Since BMPdataLength is a fixed-length + * data(512 entries), its length isn't included in header. + * checksum is a CRC32 value of all in body. + *

    +     *   header_info {
    +     *       u4           stateTableLength;
    +     *       u4           backwardsStateTableLength;
    +     *       u4           endStatesLength;
    +     *       u4           lookaheadStatesLength;
    +     *       u4           BMPdataLength;
    +     *       u4           nonBMPdataLength;
    +     *       u4           additionalDataLength;
    +     *       u8           checksum;
    +     *   }
    +     * 
    + *

    + * + * Finally, BMPindices and BMPdata are set to + * charCategoryTable. nonBMPdata is set to + * supplementaryCharCategoryTable. + *

    +     *   body {
    +     *       u2           stateTable[stateTableLength];
    +     *       u2           backwardsStateTable[backwardsStateTableLength];
    +     *       u1           endStates[endStatesLength];
    +     *       u1           lookaheadStates[lookaheadStatesLength];
    +     *       u2           BMPindices[512];
    +     *       u1           BMPdata[BMPdataLength];
    +     *       u4           nonBMPdata[numNonBMPdataLength];
    +     *       u1           additionalData[additionalDataLength];
    +     *   }
    +     * 
    + * + * @throws BufferUnderflowException if the end-of-data is reached before + * setting up all the tables + */ + private void setupTables(String ruleFile, ByteBuffer bb) { + /* Read header_info. */ + int stateTableLength = bb.getInt(); + int backwardsStateTableLength = bb.getInt(); + int endStatesLength = bb.getInt(); + int lookaheadStatesLength = bb.getInt(); + int BMPdataLength = bb.getInt(); + int nonBMPdataLength = bb.getInt(); + int additionalDataLength = bb.getInt(); + checksum = bb.getLong(); + + /* Read stateTable[numCategories * numRows] */ + stateTable = new short[stateTableLength]; + for (int i = 0; i < stateTableLength; i++) { + stateTable[i] = bb.getShort(); + } + + /* Read backwardsStateTable[numCategories * numRows] */ + backwardsStateTable = new short[backwardsStateTableLength]; + for (int i = 0; i < backwardsStateTableLength; i++) { + backwardsStateTable[i] = bb.getShort(); + } + + /* Read endStates[numRows] */ + endStates = new boolean[endStatesLength]; + for (int i = 0; i < endStatesLength; i++) { + endStates[i] = bb.get() == 1; + } + + /* Read lookaheadStates[numRows] */ + lookaheadStates = new boolean[lookaheadStatesLength]; + for (int i = 0; i < lookaheadStatesLength; i++) { + lookaheadStates[i] = bb.get() == 1; + } + + /* Read a category table and indices for BMP characters. */ + short[] temp1 = new short[BMP_INDICES_LENGTH]; // BMPindices + for (int i = 0; i < BMP_INDICES_LENGTH; i++) { + temp1[i] = bb.getShort(); + } + byte[] temp2 = new byte[BMPdataLength]; // BMPdata + bb.get(temp2); + charCategoryTable = new CompactByteArray(temp1, temp2); + + /* Read a category table for non-BMP characters. */ + int[] temp3 = new int[nonBMPdataLength]; + for (int i = 0; i < nonBMPdataLength; i++) { + temp3[i] = bb.getInt(); + } + supplementaryCharCategoryTable = new SupplementaryCharacterData(temp3); + + /* Read additional data */ + if (additionalDataLength > 0) { + additionalData = new byte[additionalDataLength]; + bb.get(additionalData); + } + assert bb.position() == bb.limit(); + + /* Set numCategories */ + numCategories = stateTable.length / endStates.length; + } + + /** + * Validates the magic number, version, and the length of the given data. + * + * @throws BufferUnderflowException if the end-of-data is reached while + * validating data + * @throws MissingResourceException if valification failed + */ + void validateRuleData(String ruleFile, ByteBuffer bb) { + /* Verify the magic number. */ + for (int i = 0; i < LABEL_LENGTH; i++) { + if (bb.get() != LABEL[i]) { + throw new MissingResourceException("Wrong magic number", + ruleFile, ""); + } + } + + /* Verify the version number. */ + byte version = bb.get(); + if (version != supportedVersion) { + throw new MissingResourceException("Unsupported version(" + version + ")", + ruleFile, ""); + } + + // Check the length of the rest of data + int len = bb.getInt(); + if (bb.position() + len != bb.limit()) { + throw new MissingResourceException("Wrong data length", + ruleFile, ""); + } + } + + byte[] getAdditionalData() { + return additionalData; + } + + void setAdditionalData(byte[] b) { + additionalData = b; + } + + //======================================================================= + // boilerplate + //======================================================================= + /** + * Clones this iterator. + * @return A newly-constructed RuleBasedBreakIterator with the same + * behavior as this one. + */ + @Override + public Object clone() { + RuleBasedBreakIterator result = (RuleBasedBreakIterator) super.clone(); + if (text != null) { + result.text = (CharacterIterator) text.clone(); + } + return result; + } + + /** + * Returns true if both BreakIterators are of the same class, have the same + * rules, and iterate over the same text. + */ + @Override + public boolean equals(Object that) { + try { + if (that == null) { + return false; + } + + RuleBasedBreakIterator other = (RuleBasedBreakIterator) that; + if (checksum != other.checksum) { + return false; + } + if (text == null) { + return other.text == null; + } else { + return text.equals(other.text); + } + } + catch(ClassCastException e) { + return false; + } + } + + /** + * Returns text + */ + @Override + public String toString() { + return "[checksum=0x" + Long.toHexString(checksum) + ']'; + } + + /** + * Compute a hashcode for this BreakIterator + * @return A hash code + */ + @Override + public int hashCode() { + return (int)checksum; + } + + //======================================================================= + // BreakIterator overrides + //======================================================================= + + /** + * Sets the current iteration position to the beginning of the text. + * (i.e., the CharacterIterator's starting offset). + * @return The offset of the beginning of the text. + */ + @Override + public int first() { + CharacterIterator t = getText(); + + t.first(); + return t.getIndex(); + } + + /** + * Sets the current iteration position to the end of the text. + * (i.e., the CharacterIterator's ending offset). + * @return The text's past-the-end offset. + */ + @Override + public int last() { + CharacterIterator t = getText(); + + // I'm not sure why, but t.last() returns the offset of the last character, + // rather than the past-the-end offset + t.setIndex(t.getEndIndex()); + return t.getIndex(); + } + + /** + * Advances the iterator either forward or backward the specified number of steps. + * Negative values move backward, and positive values move forward. This is + * equivalent to repeatedly calling next() or previous(). + * @param n The number of steps to move. The sign indicates the direction + * (negative is backwards, and positive is forwards). + * @return The character offset of the boundary position n boundaries away from + * the current one. + */ + @Override + public int next(int n) { + int result = current(); + while (n > 0) { + result = handleNext(); + --n; + } + while (n < 0) { + result = previous(); + ++n; + } + return result; + } + + /** + * Advances the iterator to the next boundary position. + * @return The position of the first boundary after this one. + */ + @Override + public int next() { + return handleNext(); + } + + private int cachedLastKnownBreak = BreakIterator.DONE; + + /** + * Advances the iterator backwards, to the last boundary preceding this one. + * @return The position of the last boundary position preceding this one. + */ + @Override + public int previous() { + // if we're already sitting at the beginning of the text, return DONE + CharacterIterator text = getText(); + if (current() == text.getBeginIndex()) { + return BreakIterator.DONE; + } + + // set things up. handlePrevious() will back us up to some valid + // break position before the current position (we back our internal + // iterator up one step to prevent handlePrevious() from returning + // the current position), but not necessarily the last one before + // where we started + int start = current(); + int lastResult = cachedLastKnownBreak; + if (lastResult >= start || lastResult <= BreakIterator.DONE) { + getPrevious(); + lastResult = handlePrevious(); + } else { + //it might be better to check if handlePrevious() give us closer + //safe value but handlePrevious() is slow too + //So, this has to be done carefully + text.setIndex(lastResult); + } + int result = lastResult; + + // iterate forward from the known break position until we pass our + // starting point. The last break position before the starting + // point is our return value + while (result != BreakIterator.DONE && result < start) { + lastResult = result; + result = handleNext(); + } + + // set the current iteration position to be the last break position + // before where we started, and then return that value + text.setIndex(lastResult); + cachedLastKnownBreak = lastResult; + return lastResult; + } + + /** + * Returns previous character + */ + private int getPrevious() { + char c2 = text.previous(); + if (Character.isLowSurrogate(c2) && + text.getIndex() > text.getBeginIndex()) { + char c1 = text.previous(); + if (Character.isHighSurrogate(c1)) { + return Character.toCodePoint(c1, c2); + } else { + text.next(); + } + } + return (int)c2; + } + + /** + * Returns current character + */ + int getCurrent() { + char c1 = text.current(); + if (Character.isHighSurrogate(c1) && + text.getIndex() < text.getEndIndex()) { + char c2 = text.next(); + text.previous(); + if (Character.isLowSurrogate(c2)) { + return Character.toCodePoint(c1, c2); + } + } + return (int)c1; + } + + /** + * Returns the count of next character. + */ + private int getCurrentCodePointCount() { + char c1 = text.current(); + if (Character.isHighSurrogate(c1) && + text.getIndex() < text.getEndIndex()) { + char c2 = text.next(); + text.previous(); + if (Character.isLowSurrogate(c2)) { + return 2; + } + } + return 1; + } + + /** + * Returns next character + */ + int getNext() { + int index = text.getIndex(); + int endIndex = text.getEndIndex(); + if (index == endIndex || + (index += getCurrentCodePointCount()) >= endIndex) { + return CharacterIterator.DONE; + } + text.setIndex(index); + return getCurrent(); + } + + /** + * Returns the position of next character. + */ + private int getNextIndex() { + int index = text.getIndex() + getCurrentCodePointCount(); + int endIndex = text.getEndIndex(); + if (index > endIndex) { + return endIndex; + } else { + return index; + } + } + + /** + * Throw IllegalArgumentException unless begin <= offset < end. + */ + protected static final void checkOffset(int offset, CharacterIterator text) { + if (offset < text.getBeginIndex() || offset > text.getEndIndex()) { + throw new IllegalArgumentException("offset out of bounds"); + } + } + + /** + * Sets the iterator to refer to the first boundary position following + * the specified position. + * @offset The position from which to begin searching for a break position. + * @return The position of the first break after the current position. + */ + @Override + public int following(int offset) { + + CharacterIterator text = getText(); + checkOffset(offset, text); + + // Set our internal iteration position (temporarily) + // to the position passed in. If this is the _beginning_ position, + // then we can just use next() to get our return value + text.setIndex(offset); + if (offset == text.getBeginIndex()) { + cachedLastKnownBreak = handleNext(); + return cachedLastKnownBreak; + } + + // otherwise, we have to sync up first. Use handlePrevious() to back + // us up to a known break position before the specified position (if + // we can determine that the specified position is a break position, + // we don't back up at all). This may or may not be the last break + // position at or before our starting position. Advance forward + // from here until we've passed the starting position. The position + // we stop on will be the first break position after the specified one. + int result = cachedLastKnownBreak; + if (result >= offset || result <= BreakIterator.DONE) { + result = handlePrevious(); + } else { + //it might be better to check if handlePrevious() give us closer + //safe value but handlePrevious() is slow too + //So, this has to be done carefully + text.setIndex(result); + } + while (result != BreakIterator.DONE && result <= offset) { + result = handleNext(); + } + cachedLastKnownBreak = result; + return result; + } + + /** + * Sets the iterator to refer to the last boundary position before the + * specified position. + * @offset The position to begin searching for a break from. + * @return The position of the last boundary before the starting position. + */ + @Override + public int preceding(int offset) { + // if we start by updating the current iteration position to the + // position specified by the caller, we can just use previous() + // to carry out this operation + CharacterIterator text = getText(); + checkOffset(offset, text); + text.setIndex(offset); + return previous(); + } + + /** + * Returns true if the specified position is a boundary position. As a side + * effect, leaves the iterator pointing to the first boundary position at + * or after "offset". + * @param offset the offset to check. + * @return True if "offset" is a boundary position. + */ + @Override + public boolean isBoundary(int offset) { + CharacterIterator text = getText(); + checkOffset(offset, text); + if (offset == text.getBeginIndex()) { + return true; + } + + // to check whether this is a boundary, we can use following() on the + // position before the specified one and return true if the position we + // get back is the one the user specified + else { + return following(offset - 1) == offset; + } + } + + /** + * Returns the current iteration position. + * @return The current iteration position. + */ + @Override + public int current() { + return getText().getIndex(); + } + + /** + * Return a CharacterIterator over the text being analyzed. This version + * of this method returns the actual CharacterIterator we're using internally. + * Changing the state of this iterator can have undefined consequences. If + * you need to change it, clone it first. + * @return An iterator over the text being analyzed. + */ + @Override + public CharacterIterator getText() { + // The iterator is initialized pointing to no text at all, so if this + // function is called while we're in that state, we have to fudge an + // iterator to return. + if (text == null) { + text = new StringCharacterIterator(""); + } + return text; + } + + /** + * Set the iterator to analyze a new piece of text. This function resets + * the current iteration position to the beginning of the text. + * @param newText An iterator over the text to analyze. + */ + @Override + public void setText(CharacterIterator newText) { + // Test iterator to see if we need to wrap it in a SafeCharIterator. + // The correct behavior for CharacterIterators is to allow the + // position to be set to the endpoint of the iterator. Many + // CharacterIterators do not uphold this, so this is a workaround + // to permit them to use this class. + int end = newText.getEndIndex(); + boolean goodIterator; + try { + newText.setIndex(end); // some buggy iterators throw an exception here + goodIterator = newText.getIndex() == end; + } + catch(IllegalArgumentException e) { + goodIterator = false; + } + + if (goodIterator) { + text = newText; + } + else { + text = new SafeCharIterator(newText); + } + text.first(); + + cachedLastKnownBreak = BreakIterator.DONE; + } + + + //======================================================================= + // implementation + //======================================================================= + + /** + * This method is the actual implementation of the next() method. All iteration + * vectors through here. This method initializes the state machine to state 1 + * and advances through the text character by character until we reach the end + * of the text or the state machine transitions to state 0. We update our return + * value every time the state machine passes through a possible end state. + */ + protected int handleNext() { + // if we're already at the end of the text, return DONE. + CharacterIterator text = getText(); + if (text.getIndex() == text.getEndIndex()) { + return BreakIterator.DONE; + } + + // no matter what, we always advance at least one character forward + int result = getNextIndex(); + int lookaheadResult = 0; + + // begin in state 1 + int state = START_STATE; + int category; + int c = getCurrent(); + + // loop until we reach the end of the text or transition to state 0 + while (c != CharacterIterator.DONE && state != STOP_STATE) { + + // look up the current character's character category (which tells us + // which column in the state table to look at) + category = lookupCategory(c); + + // if the character isn't an ignore character, look up a state + // transition in the state table + if (category != IGNORE) { + state = lookupState(state, category); + } + + // if the state we've just transitioned to is a lookahead state, + // (but not also an end state), save its position. If it's + // both a lookahead state and an end state, update the break position + // to the last saved lookup-state position + if (lookaheadStates[state]) { + if (endStates[state]) { + result = lookaheadResult; + } + else { + lookaheadResult = getNextIndex(); + } + } + + // otherwise, if the state we've just transitioned to is an accepting + // state, update the break position to be the current iteration position + else { + if (endStates[state]) { + result = getNextIndex(); + } + } + + c = getNext(); + } + + // if we've run off the end of the text, and the very last character took us into + // a lookahead state, advance the break position to the lookahead position + // (the theory here is that if there are no characters at all after the lookahead + // position, that always matches the lookahead criteria) + if (c == CharacterIterator.DONE && lookaheadResult == text.getEndIndex()) { + result = lookaheadResult; + } + + text.setIndex(result); + return result; + } + + /** + * This method backs the iterator back up to a "safe position" in the text. + * This is a position that we know, without any context, must be a break position. + * The various calling methods then iterate forward from this safe position to + * the appropriate position to return. (For more information, see the description + * of buildBackwardsStateTable() in RuleBasedBreakIterator.Builder.) + */ + protected int handlePrevious() { + CharacterIterator text = getText(); + int state = START_STATE; + int category = 0; + int lastCategory = 0; + int c = getCurrent(); + + // loop until we reach the beginning of the text or transition to state 0 + while (c != CharacterIterator.DONE && state != STOP_STATE) { + + // save the last character's category and look up the current + // character's category + lastCategory = category; + category = lookupCategory(c); + + // if the current character isn't an ignore character, look up a + // state transition in the backwards state table + if (category != IGNORE) { + state = lookupBackwardState(state, category); + } + + // then advance one character backwards + c = getPrevious(); + } + + // if we didn't march off the beginning of the text, we're either one or two + // positions away from the real break position. (One because of the call to + // previous() at the end of the loop above, and another because the character + // that takes us into the stop state will always be the character BEFORE + // the break position.) + if (c != CharacterIterator.DONE) { + if (lastCategory != IGNORE) { + getNext(); + getNext(); + } + else { + getNext(); + } + } + return text.getIndex(); + } + + /** + * Looks up a character's category (i.e., its category for breaking purposes, + * not its Unicode category) + */ + protected int lookupCategory(int c) { + if (c < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + return charCategoryTable.elementAt((char)c); + } else { + return supplementaryCharCategoryTable.getValue(c); + } + } + + /** + * Given a current state and a character category, looks up the + * next state to transition to in the state table. + */ + protected int lookupState(int state, int category) { + return stateTable[state * numCategories + category]; + } + + /** + * Given a current state and a character category, looks up the + * next state to transition to in the backwards state table. + */ + protected int lookupBackwardState(int state, int category) { + return backwardsStateTable[state * numCategories + category]; + } + + /* + * This class exists to work around a bug in incorrect implementations + * of CharacterIterator, which incorrectly handle setIndex(endIndex). + * This iterator relies only on base.setIndex(n) where n is less than + * endIndex. + * + * One caveat: if the base iterator's begin and end indices change + * the change will not be reflected by this wrapper. Does that matter? + */ + // TODO: Review this class to see if it's still required. + private static final class SafeCharIterator implements CharacterIterator, + Cloneable { + + private CharacterIterator base; + private int rangeStart; + private int rangeLimit; + private int currentIndex; + + SafeCharIterator(CharacterIterator base) { + this.base = base; + this.rangeStart = base.getBeginIndex(); + this.rangeLimit = base.getEndIndex(); + this.currentIndex = base.getIndex(); + } + + @Override + public char first() { + return setIndex(rangeStart); + } + + @Override + public char last() { + return setIndex(rangeLimit - 1); + } + + @Override + public char current() { + if (currentIndex < rangeStart || currentIndex >= rangeLimit) { + return DONE; + } + else { + return base.setIndex(currentIndex); + } + } + + @Override + public char next() { + + currentIndex++; + if (currentIndex >= rangeLimit) { + currentIndex = rangeLimit; + return DONE; + } + else { + return base.setIndex(currentIndex); + } + } + + @Override + public char previous() { + + currentIndex--; + if (currentIndex < rangeStart) { + currentIndex = rangeStart; + return DONE; + } + else { + return base.setIndex(currentIndex); + } + } + + @Override + public char setIndex(int i) { + + if (i < rangeStart || i > rangeLimit) { + throw new IllegalArgumentException("Invalid position"); + } + currentIndex = i; + return current(); + } + + @Override + public int getBeginIndex() { + return rangeStart; + } + + @Override + public int getEndIndex() { + return rangeLimit; + } + + @Override + public int getIndex() { + return currentIndex; + } + + @Override + public Object clone() { + + SafeCharIterator copy = null; + try { + copy = (SafeCharIterator) super.clone(); + } + catch(CloneNotSupportedException e) { + throw new Error("Clone not supported: " + e); + } + + CharacterIterator copyOfBase = (CharacterIterator) base.clone(); + copy.base = copyOfBase; + return copy; + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/text/resources/BreakIteratorResources.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/sun/text/resources/BreakIteratorResources.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.text.resources; + +import java.util.ResourceBundle; +import sun.util.resources.BreakIteratorResourceBundle; + +public class BreakIteratorResources extends BreakIteratorResourceBundle { + @Override + protected ResourceBundle getBreakIteratorInfo() { + return new BreakIteratorInfo(); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/util/locale/provider/BreakDictionary.java --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakDictionary.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,352 +0,0 @@ -/* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * - * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved - * (C) Copyright IBM Corp. 1996 - 2002 - All Rights Reserved - * - * The original version of this source code and documentation - * is copyrighted and owned by Taligent, Inc., a wholly-owned - * subsidiary of IBM. These materials are provided under terms - * of a License Agreement between Taligent and Sun. This technology - * is protected by multiple US and International patents. - * - * This notice and attribution to Taligent may not be removed. - * Taligent is a registered trademark of Taligent, Inc. - */ -package sun.util.locale.provider; - -import java.io.BufferedInputStream; -import java.io.InputStream; -import java.io.IOException; -import java.lang.reflect.Module; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.MissingResourceException; -import sun.text.CompactByteArray; -import sun.text.SupplementaryCharacterData; - -/** - * This is the class that represents the list of known words used by - * DictionaryBasedBreakIterator. The conceptual data structure used - * here is a trie: there is a node hanging off the root node for every - * letter that can start a word. Each of these nodes has a node hanging - * off of it for every letter that can be the second letter of a word - * if this node is the first letter, and so on. The trie is represented - * as a two-dimensional array that can be treated as a table of state - * transitions. Indexes are used to compress this array, taking - * advantage of the fact that this array will always be very sparse. - */ -class BreakDictionary { - - //========================================================================= - // data members - //========================================================================= - - /** - * The version of the dictionary that was read in. - */ - private static int supportedVersion = 1; - - /** - * Maps from characters to column numbers. The main use of this is to - * avoid making room in the array for empty columns. - */ - private CompactByteArray columnMap = null; - private SupplementaryCharacterData supplementaryCharColumnMap = null; - - /** - * The number of actual columns in the table - */ - private int numCols; - - /** - * Columns are organized into groups of 32. This says how many - * column groups. (We could calculate this, but we store the - * value to avoid having to repeatedly calculate it.) - */ - private int numColGroups; - - /** - * The actual compressed state table. Each conceptual row represents - * a state, and the cells in it contain the row numbers of the states - * to transition to for each possible letter. 0 is used to indicate - * an illegal combination of letters (i.e., the error state). The - * table is compressed by eliminating all the unpopulated (i.e., zero) - * cells. Multiple conceptual rows can then be doubled up in a single - * physical row by sliding them up and possibly shifting them to one - * side or the other so the populated cells don't collide. Indexes - * are used to identify unpopulated cells and to locate populated cells. - */ - private short[] table = null; - - /** - * This index maps logical row numbers to physical row numbers - */ - private short[] rowIndex = null; - - /** - * A bitmap is used to tell which cells in the comceptual table are - * populated. This array contains all the unique bit combinations - * in that bitmap. If the table is more than 32 columns wide, - * successive entries in this array are used for a single row. - */ - private int[] rowIndexFlags = null; - - /** - * This index maps from a logical row number into the bitmap table above. - * (This keeps us from storing duplicate bitmap combinations.) Since there - * are a lot of rows with only one populated cell, instead of wasting space - * in the bitmap table, we just store a negative number in this index for - * rows with one populated cell. The absolute value of that number is - * the column number of the populated cell. - */ - private short[] rowIndexFlagsIndex = null; - - /** - * For each logical row, this index contains a constant that is added to - * the logical column number to get the physical column number - */ - private byte[] rowIndexShifts = null; - - //========================================================================= - // deserialization - //========================================================================= - - BreakDictionary(Module module, String dictionaryName) - throws IOException, MissingResourceException { - - readDictionaryFile(module, dictionaryName); - } - - private void readDictionaryFile(final Module module, final String dictionaryName) - throws IOException, MissingResourceException { - - BufferedInputStream in; - try { - PrivilegedExceptionAction pa = () -> { - String pathName = "jdk.localedata".equals(module.getName()) ? - "sun/text/resources/ext/" : - "sun/text/resources/"; - InputStream is = module.getResourceAsStream(pathName + dictionaryName); - if (is == null) { - // Try to load the file with "java.base" module instance. Assumption - // here is that the fall back data files to be read should reside in - // java.base. - is = BreakDictionary.class.getModule().getResourceAsStream("sun/text/resources/" + dictionaryName); - } - - return new BufferedInputStream(is); - }; - in = AccessController.doPrivileged(pa); - } - catch (PrivilegedActionException e) { - throw new InternalError(e.toString(), e); - } - - byte[] buf = new byte[8]; - if (in.read(buf) != 8) { - throw new MissingResourceException("Wrong data length", - dictionaryName, ""); - } - - // check version - int version = RuleBasedBreakIterator.getInt(buf, 0); - if (version != supportedVersion) { - throw new MissingResourceException("Dictionary version(" + version + ") is unsupported", - dictionaryName, ""); - } - - // get data size - int len = RuleBasedBreakIterator.getInt(buf, 4); - buf = new byte[len]; - if (in.read(buf) != len) { - throw new MissingResourceException("Wrong data length", - dictionaryName, ""); - } - - // close the stream - in.close(); - - int l; - int offset = 0; - - // read in the column map for BMP characteres (this is serialized in - // its internal form: an index array followed by a data array) - l = RuleBasedBreakIterator.getInt(buf, offset); - offset += 4; - short[] temp = new short[l]; - for (int i = 0; i < l; i++, offset+=2) { - temp[i] = RuleBasedBreakIterator.getShort(buf, offset); - } - l = RuleBasedBreakIterator.getInt(buf, offset); - offset += 4; - byte[] temp2 = new byte[l]; - for (int i = 0; i < l; i++, offset++) { - temp2[i] = buf[offset]; - } - columnMap = new CompactByteArray(temp, temp2); - - // read in numCols and numColGroups - numCols = RuleBasedBreakIterator.getInt(buf, offset); - offset += 4; - numColGroups = RuleBasedBreakIterator.getInt(buf, offset); - offset += 4; - - // read in the row-number index - l = RuleBasedBreakIterator.getInt(buf, offset); - offset += 4; - rowIndex = new short[l]; - for (int i = 0; i < l; i++, offset+=2) { - rowIndex[i] = RuleBasedBreakIterator.getShort(buf, offset); - } - - // load in the populated-cells bitmap: index first, then bitmap list - l = RuleBasedBreakIterator.getInt(buf, offset); - offset += 4; - rowIndexFlagsIndex = new short[l]; - for (int i = 0; i < l; i++, offset+=2) { - rowIndexFlagsIndex[i] = RuleBasedBreakIterator.getShort(buf, offset); - } - l = RuleBasedBreakIterator.getInt(buf, offset); - offset += 4; - rowIndexFlags = new int[l]; - for (int i = 0; i < l; i++, offset+=4) { - rowIndexFlags[i] = RuleBasedBreakIterator.getInt(buf, offset); - } - - // load in the row-shift index - l = RuleBasedBreakIterator.getInt(buf, offset); - offset += 4; - rowIndexShifts = new byte[l]; - for (int i = 0; i < l; i++, offset++) { - rowIndexShifts[i] = buf[offset]; - } - - // load in the actual state table - l = RuleBasedBreakIterator.getInt(buf, offset); - offset += 4; - table = new short[l]; - for (int i = 0; i < l; i++, offset+=2) { - table[i] = RuleBasedBreakIterator.getShort(buf, offset); - } - - // finally, prepare the column map for supplementary characters - l = RuleBasedBreakIterator.getInt(buf, offset); - offset += 4; - int[] temp3 = new int[l]; - for (int i = 0; i < l; i++, offset+=4) { - temp3[i] = RuleBasedBreakIterator.getInt(buf, offset); - } - supplementaryCharColumnMap = new SupplementaryCharacterData(temp3); - } - - //========================================================================= - // access to the words - //========================================================================= - - /** - * Uses the column map to map the character to a column number, then - * passes the row and column number to getNextState() - * @param row The current state - * @param ch The character whose column we're interested in - * @return The new state to transition to - */ - public final short getNextStateFromCharacter(int row, int ch) { - int col; - if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { - col = columnMap.elementAt((char)ch); - } else { - col = supplementaryCharColumnMap.getValue(ch); - } - return getNextState(row, col); - } - - /** - * Returns the value in the cell with the specified (logical) row and - * column numbers. In DictionaryBasedBreakIterator, the row number is - * a state number, the column number is an input, and the return value - * is the row number of the new state to transition to. (0 is the - * "error" state, and -1 is the "end of word" state in a dictionary) - * @param row The row number of the current state - * @param col The column number of the input character (0 means "not a - * dictionary character") - * @return The row number of the new state to transition to - */ - public final short getNextState(int row, int col) { - if (cellIsPopulated(row, col)) { - // we map from logical to physical row number by looking up the - // mapping in rowIndex; we map from logical column number to - // physical column number by looking up a shift value for this - // logical row and offsetting the logical column number by - // the shift amount. Then we can use internalAt() to actually - // get the value out of the table. - return internalAt(rowIndex[row], col + rowIndexShifts[row]); - } - else { - return 0; - } - } - - /** - * Given (logical) row and column numbers, returns true if the - * cell in that position is populated - */ - private boolean cellIsPopulated(int row, int col) { - // look up the entry in the bitmap index for the specified row. - // If it's a negative number, it's the column number of the only - // populated cell in the row - if (rowIndexFlagsIndex[row] < 0) { - return col == -rowIndexFlagsIndex[row]; - } - - // if it's a positive number, it's the offset of an entry in the bitmap - // list. If the table is more than 32 columns wide, the bitmap is stored - // successive entries in the bitmap list, so we have to divide the column - // number by 32 and offset the number we got out of the index by the result. - // Once we have the appropriate piece of the bitmap, test the appropriate - // bit and return the result. - else { - int flags = rowIndexFlags[rowIndexFlagsIndex[row] + (col >> 5)]; - return (flags & (1 << (col & 0x1f))) != 0; - } - } - - /** - * Implementation of getNextState() when we know the specified cell is - * populated. - * @param row The PHYSICAL row number of the cell - * @param col The PHYSICAL column number of the cell - * @return The value stored in the cell - */ - private short internalAt(int row, int col) { - // the table is a one-dimensional array, so this just does the math necessary - // to treat it as a two-dimensional array (we don't just use a two-dimensional - // array because two-dimensional arrays are inefficient in Java) - return table[row * numCols + col]; - } -} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. 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,6 +32,8 @@ import java.util.MissingResourceException; import java.util.Objects; import java.util.Set; +import sun.text.DictionaryBasedBreakIterator; +import sun.text.RuleBasedBreakIterator; /** * Concrete implementation of the {@link java.text.spi.BreakIteratorProvider @@ -153,29 +155,31 @@ } private BreakIterator getBreakInstance(Locale locale, - int type, - String dataName, - String dictionaryName) { + int type, + String ruleName, + String dictionaryName) { Objects.requireNonNull(locale); LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(locale); String[] classNames = (String[]) lr.getBreakIteratorInfo("BreakIteratorClasses"); - String dataFile = (String) lr.getBreakIteratorInfo(dataName); + String ruleFile = (String) lr.getBreakIteratorInfo(ruleName); + byte[] ruleData = lr.getBreakIteratorResources(ruleName); try { switch (classNames[type]) { case "RuleBasedBreakIterator": - return new RuleBasedBreakIterator( - lr.getBreakIteratorDataModule(), dataFile); + return new RuleBasedBreakIterator(ruleFile, ruleData); + case "DictionaryBasedBreakIterator": String dictionaryFile = (String) lr.getBreakIteratorInfo(dictionaryName); - return new DictionaryBasedBreakIterator( - lr.getBreakIteratorDataModule(), dataFile, dictionaryFile); + byte[] dictionaryData = lr.getBreakIteratorResources(dictionaryName); + return new DictionaryBasedBreakIterator(ruleFile, ruleData, + dictionaryFile, dictionaryData); default: throw new IllegalArgumentException("Invalid break iterator class \"" + classNames[type] + "\""); } - } catch (IOException | MissingResourceException | IllegalArgumentException e) { + } catch (MissingResourceException | IllegalArgumentException e) { throw new InternalError(e.toString(), e); } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/util/locale/provider/DictionaryBasedBreakIterator.java --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/DictionaryBasedBreakIterator.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,524 +0,0 @@ -/* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * - * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved - * (C) Copyright IBM Corp. 1996 - 2002 - All Rights Reserved - * - * The original version of this source code and documentation - * is copyrighted and owned by Taligent, Inc., a wholly-owned - * subsidiary of IBM. These materials are provided under terms - * of a License Agreement between Taligent and Sun. This technology - * is protected by multiple US and International patents. - * - * This notice and attribution to Taligent may not be removed. - * Taligent is a registered trademark of Taligent, Inc. - */ - -package sun.util.locale.provider; - -import java.io.IOException; -import java.lang.reflect.Module; -import java.text.CharacterIterator; -import java.util.ArrayList; -import java.util.List; -import java.util.Stack; - -/** - * A subclass of RuleBasedBreakIterator that adds the ability to use a dictionary - * to further subdivide ranges of text beyond what is possible using just the - * state-table-based algorithm. This is necessary, for example, to handle - * word and line breaking in Thai, which doesn't use spaces between words. The - * state-table-based algorithm used by RuleBasedBreakIterator is used to divide - * up text as far as possible, and then contiguous ranges of letters are - * repeatedly compared against a list of known words (i.e., the dictionary) - * to divide them up into words. - * - * DictionaryBasedBreakIterator uses the same rule language as RuleBasedBreakIterator, - * but adds one more special substitution name: <dictionary>. This substitution - * name is used to identify characters in words in the dictionary. The idea is that - * if the iterator passes over a chunk of text that includes two or more characters - * in a row that are included in <dictionary>, it goes back through that range and - * derives additional break positions (if possible) using the dictionary. - * - * DictionaryBasedBreakIterator is also constructed with the filename of a dictionary - * file. It follows a prescribed search path to locate the dictionary (right now, - * it looks for it in /com/ibm/text/resources in each directory in the classpath, - * and won't find it in JAR files, but this location is likely to change). The - * dictionary file is in a serialized binary format. We have a very primitive (and - * slow) BuildDictionaryFile utility for creating dictionary files, but aren't - * currently making it public. Contact us for help. - */ -class DictionaryBasedBreakIterator extends RuleBasedBreakIterator { - - /** - * a list of known words that is used to divide up contiguous ranges of letters, - * stored in a compressed, indexed, format that offers fast access - */ - private BreakDictionary dictionary; - - /** - * a list of flags indicating which character categories are contained in - * the dictionary file (this is used to determine which ranges of characters - * to apply the dictionary to) - */ - private boolean[] categoryFlags; - - /** - * a temporary hiding place for the number of dictionary characters in the - * last range passed over by next() - */ - private int dictionaryCharCount; - - /** - * when a range of characters is divided up using the dictionary, the break - * positions that are discovered are stored here, preventing us from having - * to use either the dictionary or the state table again until the iterator - * leaves this range of text - */ - private int[] cachedBreakPositions; - - /** - * if cachedBreakPositions is not null, this indicates which item in the - * cache the current iteration position refers to - */ - private int positionInCache; - - /** - * Constructs a DictionaryBasedBreakIterator. - * @param module The module where the dictionary file resides - * @param dictionaryFilename The filename of the dictionary file to use - */ - DictionaryBasedBreakIterator(Module module, String dataFile, String dictionaryFile) - throws IOException { - super(module, dataFile); - byte[] tmp = super.getAdditionalData(); - if (tmp != null) { - prepareCategoryFlags(tmp); - super.setAdditionalData(null); - } - dictionary = new BreakDictionary(module, dictionaryFile); - } - - private void prepareCategoryFlags(byte[] data) { - categoryFlags = new boolean[data.length]; - for (int i = 0; i < data.length; i++) { - categoryFlags[i] = (data[i] == (byte)1) ? true : false; - } - } - - @Override - public void setText(CharacterIterator newText) { - super.setText(newText); - cachedBreakPositions = null; - dictionaryCharCount = 0; - positionInCache = 0; - } - - /** - * Sets the current iteration position to the beginning of the text. - * (i.e., the CharacterIterator's starting offset). - * @return The offset of the beginning of the text. - */ - @Override - public int first() { - cachedBreakPositions = null; - dictionaryCharCount = 0; - positionInCache = 0; - return super.first(); - } - - /** - * Sets the current iteration position to the end of the text. - * (i.e., the CharacterIterator's ending offset). - * @return The text's past-the-end offset. - */ - @Override - public int last() { - cachedBreakPositions = null; - dictionaryCharCount = 0; - positionInCache = 0; - return super.last(); - } - - /** - * Advances the iterator one step backwards. - * @return The position of the last boundary position before the - * current iteration position - */ - @Override - public int previous() { - CharacterIterator text = getText(); - - // if we have cached break positions and we're still in the range - // covered by them, just move one step backward in the cache - if (cachedBreakPositions != null && positionInCache > 0) { - --positionInCache; - text.setIndex(cachedBreakPositions[positionInCache]); - return cachedBreakPositions[positionInCache]; - } - - // otherwise, dump the cache and use the inherited previous() method to move - // backward. This may fill up the cache with new break positions, in which - // case we have to mark our position in the cache - else { - cachedBreakPositions = null; - int result = super.previous(); - if (cachedBreakPositions != null) { - positionInCache = cachedBreakPositions.length - 2; - } - return result; - } - } - - /** - * Sets the current iteration position to the last boundary position - * before the specified position. - * @param offset The position to begin searching from - * @return The position of the last boundary before "offset" - */ - @Override - public int preceding(int offset) { - CharacterIterator text = getText(); - checkOffset(offset, text); - - // if we have no cached break positions, or "offset" is outside the - // range covered by the cache, we can just call the inherited routine - // (which will eventually call other routines in this class that may - // refresh the cache) - if (cachedBreakPositions == null || offset <= cachedBreakPositions[0] || - offset > cachedBreakPositions[cachedBreakPositions.length - 1]) { - cachedBreakPositions = null; - return super.preceding(offset); - } - - // on the other hand, if "offset" is within the range covered by the cache, - // then all we have to do is search the cache for the last break position - // before "offset" - else { - positionInCache = 0; - while (positionInCache < cachedBreakPositions.length - && offset > cachedBreakPositions[positionInCache]) { - ++positionInCache; - } - --positionInCache; - text.setIndex(cachedBreakPositions[positionInCache]); - return text.getIndex(); - } - } - - /** - * Sets the current iteration position to the first boundary position after - * the specified position. - * @param offset The position to begin searching forward from - * @return The position of the first boundary after "offset" - */ - @Override - public int following(int offset) { - CharacterIterator text = getText(); - checkOffset(offset, text); - - // if we have no cached break positions, or if "offset" is outside the - // range covered by the cache, then dump the cache and call our - // inherited following() method. This will call other methods in this - // class that may refresh the cache. - if (cachedBreakPositions == null || offset < cachedBreakPositions[0] || - offset >= cachedBreakPositions[cachedBreakPositions.length - 1]) { - cachedBreakPositions = null; - return super.following(offset); - } - - // on the other hand, if "offset" is within the range covered by the - // cache, then just search the cache for the first break position - // after "offset" - else { - positionInCache = 0; - while (positionInCache < cachedBreakPositions.length - && offset >= cachedBreakPositions[positionInCache]) { - ++positionInCache; - } - text.setIndex(cachedBreakPositions[positionInCache]); - return text.getIndex(); - } - } - - /** - * This is the implementation function for next(). - */ - @Override - protected int handleNext() { - CharacterIterator text = getText(); - - // if there are no cached break positions, or if we've just moved - // off the end of the range covered by the cache, we have to dump - // and possibly regenerate the cache - if (cachedBreakPositions == null || - positionInCache == cachedBreakPositions.length - 1) { - - // start by using the inherited handleNext() to find a tentative return - // value. dictionaryCharCount tells us how many dictionary characters - // we passed over on our way to the tentative return value - int startPos = text.getIndex(); - dictionaryCharCount = 0; - int result = super.handleNext(); - - // if we passed over more than one dictionary character, then we use - // divideUpDictionaryRange() to regenerate the cached break positions - // for the new range - if (dictionaryCharCount > 1 && result - startPos > 1) { - divideUpDictionaryRange(startPos, result); - } - - // otherwise, the value we got back from the inherited fuction - // is our return value, and we can dump the cache - else { - cachedBreakPositions = null; - return result; - } - } - - // if the cache of break positions has been regenerated (or existed all - // along), then just advance to the next break position in the cache - // and return it - if (cachedBreakPositions != null) { - ++positionInCache; - text.setIndex(cachedBreakPositions[positionInCache]); - return cachedBreakPositions[positionInCache]; - } - return -9999; // SHOULD NEVER GET HERE! - } - - /** - * Looks up a character category for a character. - */ - @Override - protected int lookupCategory(int c) { - // this override of lookupCategory() exists only to keep track of whether we've - // passed over any dictionary characters. It calls the inherited lookupCategory() - // to do the real work, and then checks whether its return value is one of the - // categories represented in the dictionary. If it is, bump the dictionary- - // character count. - int result = super.lookupCategory(c); - if (result != RuleBasedBreakIterator.IGNORE && categoryFlags[result]) { - ++dictionaryCharCount; - } - return result; - } - - /** - * This is the function that actually implements the dictionary-based - * algorithm. Given the endpoints of a range of text, it uses the - * dictionary to determine the positions of any boundaries in this - * range. It stores all the boundary positions it discovers in - * cachedBreakPositions so that we only have to do this work once - * for each time we enter the range. - */ - @SuppressWarnings("unchecked") - private void divideUpDictionaryRange(int startPos, int endPos) { - CharacterIterator text = getText(); - - // the range we're dividing may begin or end with non-dictionary characters - // (i.e., for line breaking, we may have leading or trailing punctuation - // that needs to be kept with the word). Seek from the beginning of the - // range to the first dictionary character - text.setIndex(startPos); - int c = getCurrent(); - int category = lookupCategory(c); - while (category == IGNORE || !categoryFlags[category]) { - c = getNext(); - category = lookupCategory(c); - } - - // initialize. We maintain two stacks: currentBreakPositions contains - // the list of break positions that will be returned if we successfully - // finish traversing the whole range now. possibleBreakPositions lists - // all other possible word ends we've passed along the way. (Whenever - // we reach an error [a sequence of characters that can't begin any word - // in the dictionary], we back up, possibly delete some breaks from - // currentBreakPositions, move a break from possibleBreakPositions - // to currentBreakPositions, and start over from there. This process - // continues in this way until we either successfully make it all the way - // across the range, or exhaust all of our combinations of break - // positions.) - Stack currentBreakPositions = new Stack<>(); - Stack possibleBreakPositions = new Stack<>(); - List wrongBreakPositions = new ArrayList<>(); - - // the dictionary is implemented as a trie, which is treated as a state - // machine. -1 represents the end of a legal word. Every word in the - // dictionary is represented by a path from the root node to -1. A path - // that ends in state 0 is an illegal combination of characters. - int state = 0; - - // these two variables are used for error handling. We keep track of the - // farthest we've gotten through the range being divided, and the combination - // of breaks that got us that far. If we use up all possible break - // combinations, the text contains an error or a word that's not in the - // dictionary. In this case, we "bless" the break positions that got us the - // farthest as real break positions, and then start over from scratch with - // the character where the error occurred. - int farthestEndPoint = text.getIndex(); - Stack bestBreakPositions = null; - - // initialize (we always exit the loop with a break statement) - c = getCurrent(); - while (true) { - - // if we can transition to state "-1" from our current state, we're - // on the last character of a legal word. Push that position onto - // the possible-break-positions stack - if (dictionary.getNextState(state, 0) == -1) { - possibleBreakPositions.push(text.getIndex()); - } - - // look up the new state to transition to in the dictionary - state = dictionary.getNextStateFromCharacter(state, c); - - // if the character we're sitting on causes us to transition to - // the "end of word" state, then it was a non-dictionary character - // and we've successfully traversed the whole range. Drop out - // of the loop. - if (state == -1) { - currentBreakPositions.push(text.getIndex()); - break; - } - - // if the character we're sitting on causes us to transition to - // the error state, or if we've gone off the end of the range - // without transitioning to the "end of word" state, we've hit - // an error... - else if (state == 0 || text.getIndex() >= endPos) { - - // if this is the farthest we've gotten, take note of it in - // case there's an error in the text - if (text.getIndex() > farthestEndPoint) { - farthestEndPoint = text.getIndex(); - - @SuppressWarnings("unchecked") - Stack currentBreakPositionsCopy = (Stack) currentBreakPositions.clone(); - - bestBreakPositions = currentBreakPositionsCopy; - } - - // wrongBreakPositions is a list of all break positions - // we've tried starting that didn't allow us to traverse - // all the way through the text. Every time we pop a - // break position off of currentBreakPositions, we put it - // into wrongBreakPositions to avoid trying it again later. - // If we make it to this spot, we're either going to back - // up to a break in possibleBreakPositions and try starting - // over from there, or we've exhausted all possible break - // positions and are going to do the fallback procedure. - // This loop prevents us from messing with anything in - // possibleBreakPositions that didn't work as a starting - // point the last time we tried it (this is to prevent a bunch of - // repetitive checks from slowing down some extreme cases) - while (!possibleBreakPositions.isEmpty() - && wrongBreakPositions.contains(possibleBreakPositions.peek())) { - possibleBreakPositions.pop(); - } - - // if we've used up all possible break-position combinations, there's - // an error or an unknown word in the text. In this case, we start - // over, treating the farthest character we've reached as the beginning - // of the range, and "blessing" the break positions that got us that - // far as real break positions - if (possibleBreakPositions.isEmpty()) { - if (bestBreakPositions != null) { - currentBreakPositions = bestBreakPositions; - if (farthestEndPoint < endPos) { - text.setIndex(farthestEndPoint + 1); - } - else { - break; - } - } - else { - if ((currentBreakPositions.size() == 0 || - currentBreakPositions.peek().intValue() != text.getIndex()) - && text.getIndex() != startPos) { - currentBreakPositions.push(text.getIndex()); - } - getNext(); - currentBreakPositions.push(text.getIndex()); - } - } - - // if we still have more break positions we can try, then promote the - // last break in possibleBreakPositions into currentBreakPositions, - // and get rid of all entries in currentBreakPositions that come after - // it. Then back up to that position and start over from there (i.e., - // treat that position as the beginning of a new word) - else { - Integer temp = possibleBreakPositions.pop(); - Integer temp2 = null; - while (!currentBreakPositions.isEmpty() && temp.intValue() < - currentBreakPositions.peek().intValue()) { - temp2 = currentBreakPositions.pop(); - wrongBreakPositions.add(temp2); - } - currentBreakPositions.push(temp); - text.setIndex(currentBreakPositions.peek().intValue()); - } - - // re-sync "c" for the next go-round, and drop out of the loop if - // we've made it off the end of the range - c = getCurrent(); - if (text.getIndex() >= endPos) { - break; - } - } - - // if we didn't hit any exceptional conditions on this last iteration, - // just advance to the next character and loop - else { - c = getNext(); - } - } - - // dump the last break position in the list, and replace it with the actual - // end of the range (which may be the same character, or may be further on - // because the range actually ended with non-dictionary characters we want to - // keep with the word) - if (!currentBreakPositions.isEmpty()) { - currentBreakPositions.pop(); - } - currentBreakPositions.push(endPos); - - // create a regular array to hold the break positions and copy - // the break positions from the stack to the array (in addition, - // our starting position goes into this array as a break position). - // This array becomes the cache of break positions used by next() - // and previous(), so this is where we actually refresh the cache. - cachedBreakPositions = new int[currentBreakPositions.size() + 1]; - cachedBreakPositions[0] = startPos; - - for (int i = 0; i < currentBreakPositions.size(); i++) { - cachedBreakPositions[i + 1] = currentBreakPositions.elementAt(i).intValue(); - } - positionInCache = 0; - } -} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. 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 @@ -42,7 +42,6 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; -import java.lang.reflect.Module; import java.text.MessageFormat; import java.util.Calendar; import java.util.LinkedHashSet; @@ -113,13 +112,14 @@ if (data == null || ((biInfo = data.get()) == null)) { biInfo = localeData.getBreakIteratorInfo(locale).getObject(key); cache.put(cacheKey, new ResourceReference(cacheKey, biInfo, referenceQueue)); - } + } return biInfo; } - Module getBreakIteratorDataModule() { - return localeData.getBreakIteratorInfo(locale).getClass().getModule(); + @SuppressWarnings("unchecked") + byte[] getBreakIteratorResources(String key) { + return (byte[]) localeData.getBreakIteratorResources(locale).getObject(key); } int getCalendarData(String key) { diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1198 +0,0 @@ -/* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * - * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved - * (C) Copyright IBM Corp. 1996 - 2002 - All Rights Reserved - * - * The original version of this source code and documentation - * is copyrighted and owned by Taligent, Inc., a wholly-owned - * subsidiary of IBM. These materials are provided under terms - * of a License Agreement between Taligent and Sun. This technology - * is protected by multiple US and International patents. - * - * This notice and attribution to Taligent may not be removed. - * Taligent is a registered trademark of Taligent, Inc. - */ - -package sun.util.locale.provider; - -import java.io.BufferedInputStream; -import java.io.InputStream; -import java.io.IOException; -import java.lang.reflect.Module; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.text.BreakIterator; -import java.text.CharacterIterator; -import java.text.StringCharacterIterator; -import java.util.MissingResourceException; -import sun.text.CompactByteArray; -import sun.text.SupplementaryCharacterData; - -/** - *

    A subclass of BreakIterator whose behavior is specified using a list of rules.

    - * - *

    There are two kinds of rules, which are separated by semicolons: substitutions - * and regular expressions.

    - * - *

    A substitution rule defines a name that can be used in place of an expression. It - * consists of a name, which is a string of characters contained in angle brackets, an equals - * sign, and an expression. (There can be no whitespace on either side of the equals sign.) - * To keep its syntactic meaning intact, the expression must be enclosed in parentheses or - * square brackets. A substitution is visible after its definition, and is filled in using - * simple textual substitution. Substitution definitions can contain other substitutions, as - * long as those substitutions have been defined first. Substitutions are generally used to - * make the regular expressions (which can get quite complex) shorted and easier to read. - * They typically define either character categories or commonly-used subexpressions.

    - * - *

    There is one special substitution.  If the description defines a substitution - * called "<ignore>", the expression must be a [] expression, and the - * expression defines a set of characters (the "ignore characters") that - * will be transparent to the BreakIterator.  A sequence of characters will break the - * same way it would if any ignore characters it contains are taken out.  Break - * positions never occur befoer ignore characters.

    - * - *

    A regular expression uses a subset of the normal Unix regular-expression syntax, and - * defines a sequence of characters to be kept together. With one significant exception, the - * iterator uses a longest-possible-match algorithm when matching text to regular - * expressions. The iterator also treats descriptions containing multiple regular expressions - * as if they were ORed together (i.e., as if they were separated by |).

    - * - *

    The special characters recognized by the regular-expression parser are as follows:

    - * - *
    - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
    *Specifies that the expression preceding the asterisk may occur any number - * of times (including not at all).
    {}Encloses a sequence of characters that is optional.
    ()Encloses a sequence of characters.  If followed by *, the sequence - * repeats.  Otherwise, the parentheses are just a grouping device and a way to delimit - * the ends of expressions containing |.
    |Separates two alternative sequences of characters.  Either one - * sequence or the other, but not both, matches this expression.  The | character can - * only occur inside ().
    .Matches any character.
    *?Specifies a non-greedy asterisk.  *? works the same way as *, except - * when there is overlap between the last group of characters in the expression preceding the - * * and the first group of characters following the *.  When there is this kind of - * overlap, * will match the longest sequence of characters that match the expression before - * the *, and *? will match the shortest sequence of characters matching the expression - * before the *?.  For example, if you have "xxyxyyyxyxyxxyxyxyy" in the text, - * "x[xy]*x" will match through to the last x (i.e., "xxyxyyyxyxyxxyxyxyy", - * but "x[xy]*?x" will only match the first two xes ("xxyxyyyxyxyxxyxyxyy").
    []Specifies a group of alternative characters.  A [] expression will - * match any single character that is specified in the [] expression.  For more on the - * syntax of [] expressions, see below.
    /Specifies where the break position should go if text matches this - * expression.  (e.g., "[a-z]*/[:Zs:]*[1-0]" will match if the iterator sees a run - * of letters, followed by a run of whitespace, followed by a digit, but the break position - * will actually go before the whitespace).  Expressions that don't contain / put the - * break position at the end of the matching text.
    \Escape character.  The \ itself is ignored, but causes the next - * character to be treated as literal character.  This has no effect for many - * characters, but for the characters listed above, this deprives them of their special - * meaning.  (There are no special escape sequences for Unicode characters, or tabs and - * newlines; these are all handled by a higher-level protocol.  In a Java string, - * "\n" will be converted to a literal newline character by the time the - * regular-expression parser sees it.  Of course, this means that \ sequences that are - * visible to the regexp parser must be written as \\ when inside a Java string.)  All - * characters in the ASCII range except for letters, digits, and control characters are - * reserved characters to the parser and must be preceded by \ even if they currently don't - * mean anything.
    !If ! appears at the beginning of a regular expression, it tells the regexp - * parser that this expression specifies the backwards-iteration behavior of the iterator, - * and not its normal iteration behavior.  This is generally only used in situations - * where the automatically-generated backwards-iteration brhavior doesn't produce - * satisfactory results and must be supplemented with extra client-specified rules.
    (all others)All other characters are treated as literal characters, which must match - * the corresponding character(s) in the text exactly.
    - *
    - * - *

    Within a [] expression, a number of other special characters can be used to specify - * groups of characters:

    - * - *
    - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
    -Specifies a range of matching characters.  For example - * "[a-p]" matches all lowercase Latin letters from a to p (inclusive).  The - - * sign specifies ranges of continuous Unicode numeric values, not ranges of characters in a - * language's alphabetical order: "[a-z]" doesn't include capital letters, nor does - * it include accented letters such as a-umlaut.
    ::A pair of colons containing a one- or two-letter code matches all - * characters in the corresponding Unicode category.  The two-letter codes are the same - * as the two-letter codes in the Unicode database (for example, "[:Sc::Sm:]" - * matches all currency symbols and all math symbols).  Specifying a one-letter code is - * the same as specifying all two-letter codes that begin with that letter (for example, - * "[:L:]" matches all letters, and is equivalent to - * "[:Lu::Ll::Lo::Lm::Lt:]").  Anything other than a valid two-letter Unicode - * category code or a single letter that begins a Unicode category code is illegal within - * colons.
    [][] expressions can nest.  This has no effect, except when used in - * conjunction with the ^ token.
    ^Excludes the character (or the characters in the [] expression) following - * it from the group of characters.  For example, "[a-z^p]" matches all Latin - * lowercase letters except p.  "[:L:^[\u4e00-\u9fff]]" matches all letters - * except the Han ideographs.
    (all others)All other characters are treated as literal characters.  (For - * example, "[aeiou]" specifies just the letters a, e, i, o, and u.)
    - *
    - * - *

    For a more complete explanation, see http://www.ibm.com/java/education/boundaries/boundaries.html. - *   For examples, see the resource data (which is annotated).

    - * - * @author Richard Gillam - */ -class RuleBasedBreakIterator extends BreakIterator { - - /** - * A token used as a character-category value to identify ignore characters - */ - protected static final byte IGNORE = -1; - - /** - * The state number of the starting state - */ - private static final short START_STATE = 1; - - /** - * The state-transition value indicating "stop" - */ - private static final short STOP_STATE = 0; - - /** - * Magic number for the BreakIterator data file format. - */ - static final byte[] LABEL = { - (byte)'B', (byte)'I', (byte)'d', (byte)'a', (byte)'t', (byte)'a', - (byte)'\0' - }; - static final int LABEL_LENGTH = LABEL.length; - - /** - * Version number of the dictionary that was read in. - */ - static final byte supportedVersion = 1; - - /** - * Header size in byte count - */ - private static final int HEADER_LENGTH = 36; - - /** - * An array length of indices for BMP characters - */ - private static final int BMP_INDICES_LENGTH = 512; - - /** - * Tables that indexes from character values to character category numbers - */ - private CompactByteArray charCategoryTable = null; - private SupplementaryCharacterData supplementaryCharCategoryTable = null; - - /** - * The table of state transitions used for forward iteration - */ - private short[] stateTable = null; - - /** - * The table of state transitions used to sync up the iterator with the - * text in backwards and random-access iteration - */ - private short[] backwardsStateTable = null; - - /** - * A list of flags indicating which states in the state table are accepting - * ("end") states - */ - private boolean[] endStates = null; - - /** - * A list of flags indicating which states in the state table are - * lookahead states (states which turn lookahead on and off) - */ - private boolean[] lookaheadStates = null; - - /** - * A table for additional data. May be used by a subclass of - * RuleBasedBreakIterator. - */ - private byte[] additionalData = null; - - /** - * The number of character categories (and, thus, the number of columns in - * the state tables) - */ - private int numCategories; - - /** - * The character iterator through which this BreakIterator accesses the text - */ - private CharacterIterator text = null; - - /** - * A CRC32 value of all data in datafile - */ - private long checksum; - - //======================================================================= - // constructors - //======================================================================= - - /** - * Constructs a RuleBasedBreakIterator according to the module and the datafile - * provided. - */ - RuleBasedBreakIterator(Module module, String datafile) - throws IOException, MissingResourceException { - readTables(module, datafile); - } - - /** - * Read datafile. The datafile's format is as follows: - *
    -     *   BreakIteratorData {
    -     *       u1           magic[7];
    -     *       u1           version;
    -     *       u4           totalDataSize;
    -     *       header_info  header;
    -     *       body         value;
    -     *   }
    -     * 
    - * totalDataSize is the summation of the size of - * header_info and body in byte count. - *

    - * In header, each field except for checksum implies the - * length of each field. Since BMPdataLength is a fixed-length - * data(512 entries), its length isn't included in header. - * checksum is a CRC32 value of all in body. - *

    -     *   header_info {
    -     *       u4           stateTableLength;
    -     *       u4           backwardsStateTableLength;
    -     *       u4           endStatesLength;
    -     *       u4           lookaheadStatesLength;
    -     *       u4           BMPdataLength;
    -     *       u4           nonBMPdataLength;
    -     *       u4           additionalDataLength;
    -     *       u8           checksum;
    -     *   }
    -     * 
    - *

    - * - * Finally, BMPindices and BMPdata are set to - * charCategoryTable. nonBMPdata is set to - * supplementaryCharCategoryTable. - *

    -     *   body {
    -     *       u2           stateTable[stateTableLength];
    -     *       u2           backwardsStateTable[backwardsStateTableLength];
    -     *       u1           endStates[endStatesLength];
    -     *       u1           lookaheadStates[lookaheadStatesLength];
    -     *       u2           BMPindices[512];
    -     *       u1           BMPdata[BMPdataLength];
    -     *       u4           nonBMPdata[numNonBMPdataLength];
    -     *       u1           additionalData[additionalDataLength];
    -     *   }
    -     * 
    - */ - protected final void readTables(Module module, String datafile) - throws IOException, MissingResourceException { - - byte[] buffer = readFile(module, datafile); - - /* Read header_info. */ - int stateTableLength = getInt(buffer, 0); - int backwardsStateTableLength = getInt(buffer, 4); - int endStatesLength = getInt(buffer, 8); - int lookaheadStatesLength = getInt(buffer, 12); - int BMPdataLength = getInt(buffer, 16); - int nonBMPdataLength = getInt(buffer, 20); - int additionalDataLength = getInt(buffer, 24); - checksum = getLong(buffer, 28); - - /* Read stateTable[numCategories * numRows] */ - stateTable = new short[stateTableLength]; - int offset = HEADER_LENGTH; - for (int i = 0; i < stateTableLength; i++, offset+=2) { - stateTable[i] = getShort(buffer, offset); - } - - /* Read backwardsStateTable[numCategories * numRows] */ - backwardsStateTable = new short[backwardsStateTableLength]; - for (int i = 0; i < backwardsStateTableLength; i++, offset+=2) { - backwardsStateTable[i] = getShort(buffer, offset); - } - - /* Read endStates[numRows] */ - endStates = new boolean[endStatesLength]; - for (int i = 0; i < endStatesLength; i++, offset++) { - endStates[i] = buffer[offset] == 1; - } - - /* Read lookaheadStates[numRows] */ - lookaheadStates = new boolean[lookaheadStatesLength]; - for (int i = 0; i < lookaheadStatesLength; i++, offset++) { - lookaheadStates[i] = buffer[offset] == 1; - } - - /* Read a category table and indices for BMP characters. */ - short[] temp1 = new short[BMP_INDICES_LENGTH]; // BMPindices - for (int i = 0; i < BMP_INDICES_LENGTH; i++, offset+=2) { - temp1[i] = getShort(buffer, offset); - } - byte[] temp2 = new byte[BMPdataLength]; // BMPdata - System.arraycopy(buffer, offset, temp2, 0, BMPdataLength); - offset += BMPdataLength; - charCategoryTable = new CompactByteArray(temp1, temp2); - - /* Read a category table for non-BMP characters. */ - int[] temp3 = new int[nonBMPdataLength]; - for (int i = 0; i < nonBMPdataLength; i++, offset+=4) { - temp3[i] = getInt(buffer, offset); - } - supplementaryCharCategoryTable = new SupplementaryCharacterData(temp3); - - /* Read additional data */ - if (additionalDataLength > 0) { - additionalData = new byte[additionalDataLength]; - System.arraycopy(buffer, offset, additionalData, 0, additionalDataLength); - } - - /* Set numCategories */ - numCategories = stateTable.length / endStates.length; - } - - protected byte[] readFile(final Module module, final String datafile) - throws IOException, MissingResourceException { - - BufferedInputStream is; - try { - PrivilegedExceptionAction pa = () -> { - String pathName = "jdk.localedata".equals(module.getName()) ? - "sun/text/resources/ext/" : - "sun/text/resources/"; - InputStream in = module.getResourceAsStream(pathName + datafile); - if (in == null) { - // Try to load the file with "java.base" module instance. Assumption - // here is that the fall back data files to be read should reside in - // java.base. - in = RuleBasedBreakIterator.class.getModule().getResourceAsStream("sun/text/resources/" + datafile); - } - - return new BufferedInputStream(in); - }; - is = AccessController.doPrivileged(pa); - } catch (PrivilegedActionException e) { - throw new InternalError(e.toString(), e); - } - - int offset = 0; - - /* First, read magic, version, and header_info. */ - int len = LABEL_LENGTH + 5; - byte[] buf = new byte[len]; - if (is.read(buf) != len) { - throw new MissingResourceException("Wrong header length", - datafile, ""); - } - - /* Validate the magic number. */ - for (int i = 0; i < LABEL_LENGTH; i++, offset++) { - if (buf[offset] != LABEL[offset]) { - throw new MissingResourceException("Wrong magic number", - datafile, ""); - } - } - - /* Validate the version number. */ - if (buf[offset] != supportedVersion) { - throw new MissingResourceException("Unsupported version(" + buf[offset] + ")", - datafile, ""); - } - - /* Read data: totalDataSize + 8(for checksum) */ - len = getInt(buf, ++offset); - buf = new byte[len]; - if (is.read(buf) != len) { - throw new MissingResourceException("Wrong data length", - datafile, ""); - } - - is.close(); - - return buf; - } - - byte[] getAdditionalData() { - return additionalData; - } - - void setAdditionalData(byte[] b) { - additionalData = b; - } - - //======================================================================= - // boilerplate - //======================================================================= - /** - * Clones this iterator. - * @return A newly-constructed RuleBasedBreakIterator with the same - * behavior as this one. - */ - @Override - public Object clone() { - RuleBasedBreakIterator result = (RuleBasedBreakIterator) super.clone(); - if (text != null) { - result.text = (CharacterIterator) text.clone(); - } - return result; - } - - /** - * Returns true if both BreakIterators are of the same class, have the same - * rules, and iterate over the same text. - */ - @Override - public boolean equals(Object that) { - try { - if (that == null) { - return false; - } - - RuleBasedBreakIterator other = (RuleBasedBreakIterator) that; - if (checksum != other.checksum) { - return false; - } - if (text == null) { - return other.text == null; - } else { - return text.equals(other.text); - } - } - catch(ClassCastException e) { - return false; - } - } - - /** - * Returns text - */ - @Override - public String toString() { - return "[checksum=0x" + Long.toHexString(checksum) + ']'; - } - - /** - * Compute a hashcode for this BreakIterator - * @return A hash code - */ - @Override - public int hashCode() { - return (int)checksum; - } - - //======================================================================= - // BreakIterator overrides - //======================================================================= - - /** - * Sets the current iteration position to the beginning of the text. - * (i.e., the CharacterIterator's starting offset). - * @return The offset of the beginning of the text. - */ - @Override - public int first() { - CharacterIterator t = getText(); - - t.first(); - return t.getIndex(); - } - - /** - * Sets the current iteration position to the end of the text. - * (i.e., the CharacterIterator's ending offset). - * @return The text's past-the-end offset. - */ - @Override - public int last() { - CharacterIterator t = getText(); - - // I'm not sure why, but t.last() returns the offset of the last character, - // rather than the past-the-end offset - t.setIndex(t.getEndIndex()); - return t.getIndex(); - } - - /** - * Advances the iterator either forward or backward the specified number of steps. - * Negative values move backward, and positive values move forward. This is - * equivalent to repeatedly calling next() or previous(). - * @param n The number of steps to move. The sign indicates the direction - * (negative is backwards, and positive is forwards). - * @return The character offset of the boundary position n boundaries away from - * the current one. - */ - @Override - public int next(int n) { - int result = current(); - while (n > 0) { - result = handleNext(); - --n; - } - while (n < 0) { - result = previous(); - ++n; - } - return result; - } - - /** - * Advances the iterator to the next boundary position. - * @return The position of the first boundary after this one. - */ - @Override - public int next() { - return handleNext(); - } - - private int cachedLastKnownBreak = BreakIterator.DONE; - - /** - * Advances the iterator backwards, to the last boundary preceding this one. - * @return The position of the last boundary position preceding this one. - */ - @Override - public int previous() { - // if we're already sitting at the beginning of the text, return DONE - CharacterIterator text = getText(); - if (current() == text.getBeginIndex()) { - return BreakIterator.DONE; - } - - // set things up. handlePrevious() will back us up to some valid - // break position before the current position (we back our internal - // iterator up one step to prevent handlePrevious() from returning - // the current position), but not necessarily the last one before - // where we started - int start = current(); - int lastResult = cachedLastKnownBreak; - if (lastResult >= start || lastResult <= BreakIterator.DONE) { - getPrevious(); - lastResult = handlePrevious(); - } else { - //it might be better to check if handlePrevious() give us closer - //safe value but handlePrevious() is slow too - //So, this has to be done carefully - text.setIndex(lastResult); - } - int result = lastResult; - - // iterate forward from the known break position until we pass our - // starting point. The last break position before the starting - // point is our return value - while (result != BreakIterator.DONE && result < start) { - lastResult = result; - result = handleNext(); - } - - // set the current iteration position to be the last break position - // before where we started, and then return that value - text.setIndex(lastResult); - cachedLastKnownBreak = lastResult; - return lastResult; - } - - /** - * Returns previous character - */ - private int getPrevious() { - char c2 = text.previous(); - if (Character.isLowSurrogate(c2) && - text.getIndex() > text.getBeginIndex()) { - char c1 = text.previous(); - if (Character.isHighSurrogate(c1)) { - return Character.toCodePoint(c1, c2); - } else { - text.next(); - } - } - return (int)c2; - } - - /** - * Returns current character - */ - int getCurrent() { - char c1 = text.current(); - if (Character.isHighSurrogate(c1) && - text.getIndex() < text.getEndIndex()) { - char c2 = text.next(); - text.previous(); - if (Character.isLowSurrogate(c2)) { - return Character.toCodePoint(c1, c2); - } - } - return (int)c1; - } - - /** - * Returns the count of next character. - */ - private int getCurrentCodePointCount() { - char c1 = text.current(); - if (Character.isHighSurrogate(c1) && - text.getIndex() < text.getEndIndex()) { - char c2 = text.next(); - text.previous(); - if (Character.isLowSurrogate(c2)) { - return 2; - } - } - return 1; - } - - /** - * Returns next character - */ - int getNext() { - int index = text.getIndex(); - int endIndex = text.getEndIndex(); - if (index == endIndex || - (index += getCurrentCodePointCount()) >= endIndex) { - return CharacterIterator.DONE; - } - text.setIndex(index); - return getCurrent(); - } - - /** - * Returns the position of next character. - */ - private int getNextIndex() { - int index = text.getIndex() + getCurrentCodePointCount(); - int endIndex = text.getEndIndex(); - if (index > endIndex) { - return endIndex; - } else { - return index; - } - } - - /** - * Throw IllegalArgumentException unless begin <= offset < end. - */ - protected static final void checkOffset(int offset, CharacterIterator text) { - if (offset < text.getBeginIndex() || offset > text.getEndIndex()) { - throw new IllegalArgumentException("offset out of bounds"); - } - } - - /** - * Sets the iterator to refer to the first boundary position following - * the specified position. - * @offset The position from which to begin searching for a break position. - * @return The position of the first break after the current position. - */ - @Override - public int following(int offset) { - - CharacterIterator text = getText(); - checkOffset(offset, text); - - // Set our internal iteration position (temporarily) - // to the position passed in. If this is the _beginning_ position, - // then we can just use next() to get our return value - text.setIndex(offset); - if (offset == text.getBeginIndex()) { - cachedLastKnownBreak = handleNext(); - return cachedLastKnownBreak; - } - - // otherwise, we have to sync up first. Use handlePrevious() to back - // us up to a known break position before the specified position (if - // we can determine that the specified position is a break position, - // we don't back up at all). This may or may not be the last break - // position at or before our starting position. Advance forward - // from here until we've passed the starting position. The position - // we stop on will be the first break position after the specified one. - int result = cachedLastKnownBreak; - if (result >= offset || result <= BreakIterator.DONE) { - result = handlePrevious(); - } else { - //it might be better to check if handlePrevious() give us closer - //safe value but handlePrevious() is slow too - //So, this has to be done carefully - text.setIndex(result); - } - while (result != BreakIterator.DONE && result <= offset) { - result = handleNext(); - } - cachedLastKnownBreak = result; - return result; - } - - /** - * Sets the iterator to refer to the last boundary position before the - * specified position. - * @offset The position to begin searching for a break from. - * @return The position of the last boundary before the starting position. - */ - @Override - public int preceding(int offset) { - // if we start by updating the current iteration position to the - // position specified by the caller, we can just use previous() - // to carry out this operation - CharacterIterator text = getText(); - checkOffset(offset, text); - text.setIndex(offset); - return previous(); - } - - /** - * Returns true if the specified position is a boundary position. As a side - * effect, leaves the iterator pointing to the first boundary position at - * or after "offset". - * @param offset the offset to check. - * @return True if "offset" is a boundary position. - */ - @Override - public boolean isBoundary(int offset) { - CharacterIterator text = getText(); - checkOffset(offset, text); - if (offset == text.getBeginIndex()) { - return true; - } - - // to check whether this is a boundary, we can use following() on the - // position before the specified one and return true if the position we - // get back is the one the user specified - else { - return following(offset - 1) == offset; - } - } - - /** - * Returns the current iteration position. - * @return The current iteration position. - */ - @Override - public int current() { - return getText().getIndex(); - } - - /** - * Return a CharacterIterator over the text being analyzed. This version - * of this method returns the actual CharacterIterator we're using internally. - * Changing the state of this iterator can have undefined consequences. If - * you need to change it, clone it first. - * @return An iterator over the text being analyzed. - */ - @Override - public CharacterIterator getText() { - // The iterator is initialized pointing to no text at all, so if this - // function is called while we're in that state, we have to fudge an - // iterator to return. - if (text == null) { - text = new StringCharacterIterator(""); - } - return text; - } - - /** - * Set the iterator to analyze a new piece of text. This function resets - * the current iteration position to the beginning of the text. - * @param newText An iterator over the text to analyze. - */ - @Override - public void setText(CharacterIterator newText) { - // Test iterator to see if we need to wrap it in a SafeCharIterator. - // The correct behavior for CharacterIterators is to allow the - // position to be set to the endpoint of the iterator. Many - // CharacterIterators do not uphold this, so this is a workaround - // to permit them to use this class. - int end = newText.getEndIndex(); - boolean goodIterator; - try { - newText.setIndex(end); // some buggy iterators throw an exception here - goodIterator = newText.getIndex() == end; - } - catch(IllegalArgumentException e) { - goodIterator = false; - } - - if (goodIterator) { - text = newText; - } - else { - text = new SafeCharIterator(newText); - } - text.first(); - - cachedLastKnownBreak = BreakIterator.DONE; - } - - - //======================================================================= - // implementation - //======================================================================= - - /** - * This method is the actual implementation of the next() method. All iteration - * vectors through here. This method initializes the state machine to state 1 - * and advances through the text character by character until we reach the end - * of the text or the state machine transitions to state 0. We update our return - * value every time the state machine passes through a possible end state. - */ - protected int handleNext() { - // if we're already at the end of the text, return DONE. - CharacterIterator text = getText(); - if (text.getIndex() == text.getEndIndex()) { - return BreakIterator.DONE; - } - - // no matter what, we always advance at least one character forward - int result = getNextIndex(); - int lookaheadResult = 0; - - // begin in state 1 - int state = START_STATE; - int category; - int c = getCurrent(); - - // loop until we reach the end of the text or transition to state 0 - while (c != CharacterIterator.DONE && state != STOP_STATE) { - - // look up the current character's character category (which tells us - // which column in the state table to look at) - category = lookupCategory(c); - - // if the character isn't an ignore character, look up a state - // transition in the state table - if (category != IGNORE) { - state = lookupState(state, category); - } - - // if the state we've just transitioned to is a lookahead state, - // (but not also an end state), save its position. If it's - // both a lookahead state and an end state, update the break position - // to the last saved lookup-state position - if (lookaheadStates[state]) { - if (endStates[state]) { - result = lookaheadResult; - } - else { - lookaheadResult = getNextIndex(); - } - } - - // otherwise, if the state we've just transitioned to is an accepting - // state, update the break position to be the current iteration position - else { - if (endStates[state]) { - result = getNextIndex(); - } - } - - c = getNext(); - } - - // if we've run off the end of the text, and the very last character took us into - // a lookahead state, advance the break position to the lookahead position - // (the theory here is that if there are no characters at all after the lookahead - // position, that always matches the lookahead criteria) - if (c == CharacterIterator.DONE && lookaheadResult == text.getEndIndex()) { - result = lookaheadResult; - } - - text.setIndex(result); - return result; - } - - /** - * This method backs the iterator back up to a "safe position" in the text. - * This is a position that we know, without any context, must be a break position. - * The various calling methods then iterate forward from this safe position to - * the appropriate position to return. (For more information, see the description - * of buildBackwardsStateTable() in RuleBasedBreakIterator.Builder.) - */ - protected int handlePrevious() { - CharacterIterator text = getText(); - int state = START_STATE; - int category = 0; - int lastCategory = 0; - int c = getCurrent(); - - // loop until we reach the beginning of the text or transition to state 0 - while (c != CharacterIterator.DONE && state != STOP_STATE) { - - // save the last character's category and look up the current - // character's category - lastCategory = category; - category = lookupCategory(c); - - // if the current character isn't an ignore character, look up a - // state transition in the backwards state table - if (category != IGNORE) { - state = lookupBackwardState(state, category); - } - - // then advance one character backwards - c = getPrevious(); - } - - // if we didn't march off the beginning of the text, we're either one or two - // positions away from the real break position. (One because of the call to - // previous() at the end of the loop above, and another because the character - // that takes us into the stop state will always be the character BEFORE - // the break position.) - if (c != CharacterIterator.DONE) { - if (lastCategory != IGNORE) { - getNext(); - getNext(); - } - else { - getNext(); - } - } - return text.getIndex(); - } - - /** - * Looks up a character's category (i.e., its category for breaking purposes, - * not its Unicode category) - */ - protected int lookupCategory(int c) { - if (c < Character.MIN_SUPPLEMENTARY_CODE_POINT) { - return charCategoryTable.elementAt((char)c); - } else { - return supplementaryCharCategoryTable.getValue(c); - } - } - - /** - * Given a current state and a character category, looks up the - * next state to transition to in the state table. - */ - protected int lookupState(int state, int category) { - return stateTable[state * numCategories + category]; - } - - /** - * Given a current state and a character category, looks up the - * next state to transition to in the backwards state table. - */ - protected int lookupBackwardState(int state, int category) { - return backwardsStateTable[state * numCategories + category]; - } - - static long getLong(byte[] buf, int offset) { - long num = buf[offset]&0xFF; - for (int i = 1; i < 8; i++) { - num = num<<8 | (buf[offset+i]&0xFF); - } - return num; - } - - static int getInt(byte[] buf, int offset) { - int num = buf[offset]&0xFF; - for (int i = 1; i < 4; i++) { - num = num<<8 | (buf[offset+i]&0xFF); - } - return num; - } - - static short getShort(byte[] buf, int offset) { - short num = (short)(buf[offset]&0xFF); - num = (short)(num<<8 | (buf[offset+1]&0xFF)); - return num; - } - - /* - * This class exists to work around a bug in incorrect implementations - * of CharacterIterator, which incorrectly handle setIndex(endIndex). - * This iterator relies only on base.setIndex(n) where n is less than - * endIndex. - * - * One caveat: if the base iterator's begin and end indices change - * the change will not be reflected by this wrapper. Does that matter? - */ - // TODO: Review this class to see if it's still required. - private static final class SafeCharIterator implements CharacterIterator, - Cloneable { - - private CharacterIterator base; - private int rangeStart; - private int rangeLimit; - private int currentIndex; - - SafeCharIterator(CharacterIterator base) { - this.base = base; - this.rangeStart = base.getBeginIndex(); - this.rangeLimit = base.getEndIndex(); - this.currentIndex = base.getIndex(); - } - - @Override - public char first() { - return setIndex(rangeStart); - } - - @Override - public char last() { - return setIndex(rangeLimit - 1); - } - - @Override - public char current() { - if (currentIndex < rangeStart || currentIndex >= rangeLimit) { - return DONE; - } - else { - return base.setIndex(currentIndex); - } - } - - @Override - public char next() { - - currentIndex++; - if (currentIndex >= rangeLimit) { - currentIndex = rangeLimit; - return DONE; - } - else { - return base.setIndex(currentIndex); - } - } - - @Override - public char previous() { - - currentIndex--; - if (currentIndex < rangeStart) { - currentIndex = rangeStart; - return DONE; - } - else { - return base.setIndex(currentIndex); - } - } - - @Override - public char setIndex(int i) { - - if (i < rangeStart || i > rangeLimit) { - throw new IllegalArgumentException("Invalid position"); - } - currentIndex = i; - return current(); - } - - @Override - public int getBeginIndex() { - return rangeStart; - } - - @Override - public int getEndIndex() { - return rangeLimit; - } - - @Override - public int getIndex() { - return currentIndex; - } - - @Override - public Object clone() { - - SafeCharIterator copy = null; - try { - copy = (SafeCharIterator) super.clone(); - } - catch(CloneNotSupportedException e) { - throw new Error("Clone not supported: " + e); - } - - CharacterIterator copyOfBase = (CharacterIterator) base.clone(); - copy.base = copyOfBase; - return copy; - } - } -} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/util/resources/BreakIteratorResourceBundle.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/sun/util/resources/BreakIteratorResourceBundle.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.util.resources; + +import java.io.InputStream; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Collections; +import java.util.Enumeration; +import java.util.ResourceBundle; +import java.util.Set; + +/** + * BreakIteratorResourceBundle is an abstract class for loading BreakIterator + * data (rules or dictionary) from each module. An implementation class must + * implement getBreakIteratorInfo() that returns an instance of the + * corresponding BreakIteratorInfo (basename). The data name is taken from the + * BreakIteratorInfo instance. + * + *

    For example, if the given key is "WordDictionary" and Locale is "th", the + * data name is taken from a BreakIteratorInfo_th and the key's value is + * "thai_dict". Its data thai_dict is loaded from the Module of the + * implementation class of this class. + */ + +public abstract class BreakIteratorResourceBundle extends ResourceBundle { + // If any keys that are not for data names are added to BreakIteratorInfo*, + // those keys must be added to NON_DATA_KEYS. + private static final Set NON_DATA_KEYS = Set.of("BreakIteratorClasses"); + + private volatile Set keys; + + /** + * Returns an instance of the corresponding {@code BreakIteratorInfo} (basename). + * The instance shouldn't have its parent. + */ + protected abstract ResourceBundle getBreakIteratorInfo(); + + @Override + protected Object handleGetObject(String key) { + if (NON_DATA_KEYS.contains(key)) { + return null; + } + ResourceBundle info = getBreakIteratorInfo(); + if (!info.containsKey(key)) { + return null; + } + String path = getClass().getPackage().getName().replace('.', '/') + + '/' + info.getString(key); + byte[] data; + try (InputStream is = getResourceAsStream(path)) { + data = is.readAllBytes(); + } catch (Exception e) { + throw new InternalError("Can't load " + path, e); + } + return data; + } + + private InputStream getResourceAsStream(String path) throws Exception { + PrivilegedExceptionAction pa; + pa = () -> getClass().getModule().getResourceAsStream(path); + InputStream is; + try { + is = AccessController.doPrivileged(pa); + } catch (PrivilegedActionException e) { + throw e.getException(); + } + return is; + } + + @Override + public Enumeration getKeys() { + return Collections.enumeration(keySet()); + } + + @Override + protected Set handleKeySet() { + if (keys == null) { + ResourceBundle info = getBreakIteratorInfo(); + Set k = info.keySet(); + k.removeAll(NON_DATA_KEYS); + synchronized (this) { + if (keys == null) { + keys = k; + } + } + } + return keys; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java --- a/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java Fri Nov 11 16:44:36 2016 +0100 @@ -123,6 +123,14 @@ } /** + * Gets a break iterator resources resource bundle, using + * privileges to allow accessing a sun.* package. + */ + public ResourceBundle getBreakIteratorResources(Locale locale) { + return getBundle(type.getTextResourcesPackage() + ".BreakIteratorResources", locale); + } + + /** * Gets a collation data resource bundle, using privileges * to allow accessing a sun.* package. */ diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/conf/security/java.security --- a/jdk/src/java.base/share/conf/security/java.security Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/conf/security/java.security Fri Nov 11 16:44:36 2016 +0100 @@ -645,6 +645,9 @@ # before larger keysize constraints of the same algorithm. For example: # "RSA keySize < 1024 & jdkCA, RSA keySize < 2048". # +# Note: The algorithm restrictions do not apply to trust anchors or +# self-signed certificates. +# # Note: This property is currently used by Oracle's PKIX implementation. It # is not guaranteed to be examined and used by other implementations. # @@ -714,6 +717,9 @@ # See the specification of "jdk.certpath.disabledAlgorithms" for the # syntax of the disabled algorithm string. # +# Note: The algorithm restrictions do not apply to trust anchors or +# self-signed certificates. +# # Note: This property is currently used by Oracle's JSSE implementation. # It is not guaranteed to be examined and used by other implementations. # diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/lib/security/default.policy --- a/jdk/src/java.base/share/lib/security/default.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/lib/security/default.policy Fri Nov 11 16:44:36 2016 +0100 @@ -32,8 +32,22 @@ permission javax.smartcardio.CardPermission "*", "*"; permission java.lang.RuntimePermission "loadLibrary.j2pcsc"; permission java.lang.RuntimePermission - "accessClassInPackage.sun.security.*"; - permission java.util.PropertyPermission "*", "read"; + "accessClassInPackage.sun.security.jca"; + permission java.lang.RuntimePermission + "accessClassInPackage.sun.security.util"; + permission java.util.PropertyPermission + "javax.smartcardio.TerminalFactory.DefaultType", "read"; + permission java.util.PropertyPermission "os.name", "read"; + permission java.util.PropertyPermission "os.arch", "read"; + permission java.util.PropertyPermission "sun.arch.data.model", "read"; + permission java.util.PropertyPermission + "sun.security.smartcardio.library", "read"; + permission java.util.PropertyPermission + "sun.security.smartcardio.t0GetResponse", "read"; + permission java.util.PropertyPermission + "sun.security.smartcardio.t1GetResponse", "read"; + permission java.util.PropertyPermission + "sun.security.smartcardio.t1StripLe", "read"; // needed for looking up native PC/SC library permission java.io.FilePermission "<>","read"; permission java.security.SecurityPermission "putProviderProperty.SunPCSC"; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/native/include/jvm.h --- a/jdk/src/java.base/share/native/include/jvm.h Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/native/include/jvm.h Fri Nov 11 16:44:36 2016 +0100 @@ -165,14 +165,24 @@ JNIEXPORT jboolean JNICALL JVM_IsSupportedJNIVersion(jint version); +JNIEXPORT jobjectArray JNICALL +JVM_GetVmArguments(JNIEnv *env); + + /* * java.lang.Throwable */ JNIEXPORT void JNICALL JVM_FillInStackTrace(JNIEnv *env, jobject throwable); +/* + * java.lang.StackTraceElement + */ JNIEXPORT void JNICALL -JVM_GetStackTraceElements(JNIEnv *env, jobject throwable, jobjectArray elements); +JVM_InitStackTraceElementArray(JNIEnv *env, jobjectArray elements, jobject throwable); + +JNIEXPORT void JNICALL +JVM_InitStackTraceElement(JNIEnv* env, jobject element, jobject stackFrameInfo); /* * java.lang.StackWalker @@ -194,12 +204,6 @@ jint frame_count, jint start_index, jobjectArray frames); -JNIEXPORT void JNICALL -JVM_ToStackTraceElement(JNIEnv* env, jobject frame, jobject stackElement); - -JNIEXPORT jobjectArray JNICALL -JVM_GetVmArguments(JNIEnv *env); - /* * java.lang.Thread */ diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/native/include/jvmti.h --- a/jdk/src/java.base/share/native/include/jvmti.h Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2551 +0,0 @@ -/* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - /* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */ - - /* Include file for the Java(tm) Virtual Machine Tool Interface */ - -#ifndef _JAVA_JVMTI_H_ -#define _JAVA_JVMTI_H_ - -#include "jni.h" - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - JVMTI_VERSION_1 = 0x30010000, - JVMTI_VERSION_1_0 = 0x30010000, - JVMTI_VERSION_1_1 = 0x30010100, - JVMTI_VERSION_1_2 = 0x30010200, - JVMTI_VERSION_9 = 0x30090000, - - JVMTI_VERSION = 0x30000000 + (9 * 0x10000) + (0 * 0x100) + 0 /* version: 9.0.0 */ -}; - -JNIEXPORT jint JNICALL -Agent_OnLoad(JavaVM *vm, char *options, void *reserved); - -JNIEXPORT jint JNICALL -Agent_OnAttach(JavaVM* vm, char* options, void* reserved); - -JNIEXPORT void JNICALL -Agent_OnUnload(JavaVM *vm); - - /* Forward declaration of the environment */ - -struct _jvmtiEnv; - -struct jvmtiInterface_1_; - -#ifdef __cplusplus -typedef _jvmtiEnv jvmtiEnv; -#else -typedef const struct jvmtiInterface_1_ *jvmtiEnv; -#endif /* __cplusplus */ - -/* Derived Base Types */ - -typedef jobject jthread; -typedef jobject jthreadGroup; -typedef jlong jlocation; -struct _jrawMonitorID; -typedef struct _jrawMonitorID *jrawMonitorID; -typedef struct JNINativeInterface_ jniNativeInterface; - - /* Constants */ - - - /* Thread State Flags */ - -enum { - JVMTI_THREAD_STATE_ALIVE = 0x0001, - JVMTI_THREAD_STATE_TERMINATED = 0x0002, - JVMTI_THREAD_STATE_RUNNABLE = 0x0004, - JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER = 0x0400, - JVMTI_THREAD_STATE_WAITING = 0x0080, - JVMTI_THREAD_STATE_WAITING_INDEFINITELY = 0x0010, - JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT = 0x0020, - JVMTI_THREAD_STATE_SLEEPING = 0x0040, - JVMTI_THREAD_STATE_IN_OBJECT_WAIT = 0x0100, - JVMTI_THREAD_STATE_PARKED = 0x0200, - JVMTI_THREAD_STATE_SUSPENDED = 0x100000, - JVMTI_THREAD_STATE_INTERRUPTED = 0x200000, - JVMTI_THREAD_STATE_IN_NATIVE = 0x400000, - JVMTI_THREAD_STATE_VENDOR_1 = 0x10000000, - JVMTI_THREAD_STATE_VENDOR_2 = 0x20000000, - JVMTI_THREAD_STATE_VENDOR_3 = 0x40000000 -}; - - /* java.lang.Thread.State Conversion Masks */ - -enum { - JVMTI_JAVA_LANG_THREAD_STATE_MASK = JVMTI_THREAD_STATE_TERMINATED | JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_RUNNABLE | JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER | JVMTI_THREAD_STATE_WAITING | JVMTI_THREAD_STATE_WAITING_INDEFINITELY | JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT, - JVMTI_JAVA_LANG_THREAD_STATE_NEW = 0, - JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED = JVMTI_THREAD_STATE_TERMINATED, - JVMTI_JAVA_LANG_THREAD_STATE_RUNNABLE = JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_RUNNABLE, - JVMTI_JAVA_LANG_THREAD_STATE_BLOCKED = JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER, - JVMTI_JAVA_LANG_THREAD_STATE_WAITING = JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_WAITING | JVMTI_THREAD_STATE_WAITING_INDEFINITELY, - JVMTI_JAVA_LANG_THREAD_STATE_TIMED_WAITING = JVMTI_THREAD_STATE_ALIVE | JVMTI_THREAD_STATE_WAITING | JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT -}; - - /* Thread Priority Constants */ - -enum { - JVMTI_THREAD_MIN_PRIORITY = 1, - JVMTI_THREAD_NORM_PRIORITY = 5, - JVMTI_THREAD_MAX_PRIORITY = 10 -}; - - /* Heap Filter Flags */ - -enum { - JVMTI_HEAP_FILTER_TAGGED = 0x4, - JVMTI_HEAP_FILTER_UNTAGGED = 0x8, - JVMTI_HEAP_FILTER_CLASS_TAGGED = 0x10, - JVMTI_HEAP_FILTER_CLASS_UNTAGGED = 0x20 -}; - - /* Heap Visit Control Flags */ - -enum { - JVMTI_VISIT_OBJECTS = 0x100, - JVMTI_VISIT_ABORT = 0x8000 -}; - - /* Heap Reference Enumeration */ - -typedef enum { - JVMTI_HEAP_REFERENCE_CLASS = 1, - JVMTI_HEAP_REFERENCE_FIELD = 2, - JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT = 3, - JVMTI_HEAP_REFERENCE_CLASS_LOADER = 4, - JVMTI_HEAP_REFERENCE_SIGNERS = 5, - JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN = 6, - JVMTI_HEAP_REFERENCE_INTERFACE = 7, - JVMTI_HEAP_REFERENCE_STATIC_FIELD = 8, - JVMTI_HEAP_REFERENCE_CONSTANT_POOL = 9, - JVMTI_HEAP_REFERENCE_SUPERCLASS = 10, - JVMTI_HEAP_REFERENCE_JNI_GLOBAL = 21, - JVMTI_HEAP_REFERENCE_SYSTEM_CLASS = 22, - JVMTI_HEAP_REFERENCE_MONITOR = 23, - JVMTI_HEAP_REFERENCE_STACK_LOCAL = 24, - JVMTI_HEAP_REFERENCE_JNI_LOCAL = 25, - JVMTI_HEAP_REFERENCE_THREAD = 26, - JVMTI_HEAP_REFERENCE_OTHER = 27 -} jvmtiHeapReferenceKind; - - /* Primitive Type Enumeration */ - -typedef enum { - JVMTI_PRIMITIVE_TYPE_BOOLEAN = 90, - JVMTI_PRIMITIVE_TYPE_BYTE = 66, - JVMTI_PRIMITIVE_TYPE_CHAR = 67, - JVMTI_PRIMITIVE_TYPE_SHORT = 83, - JVMTI_PRIMITIVE_TYPE_INT = 73, - JVMTI_PRIMITIVE_TYPE_LONG = 74, - JVMTI_PRIMITIVE_TYPE_FLOAT = 70, - JVMTI_PRIMITIVE_TYPE_DOUBLE = 68 -} jvmtiPrimitiveType; - - /* Heap Object Filter Enumeration */ - -typedef enum { - JVMTI_HEAP_OBJECT_TAGGED = 1, - JVMTI_HEAP_OBJECT_UNTAGGED = 2, - JVMTI_HEAP_OBJECT_EITHER = 3 -} jvmtiHeapObjectFilter; - - /* Heap Root Kind Enumeration */ - -typedef enum { - JVMTI_HEAP_ROOT_JNI_GLOBAL = 1, - JVMTI_HEAP_ROOT_SYSTEM_CLASS = 2, - JVMTI_HEAP_ROOT_MONITOR = 3, - JVMTI_HEAP_ROOT_STACK_LOCAL = 4, - JVMTI_HEAP_ROOT_JNI_LOCAL = 5, - JVMTI_HEAP_ROOT_THREAD = 6, - JVMTI_HEAP_ROOT_OTHER = 7 -} jvmtiHeapRootKind; - - /* Object Reference Enumeration */ - -typedef enum { - JVMTI_REFERENCE_CLASS = 1, - JVMTI_REFERENCE_FIELD = 2, - JVMTI_REFERENCE_ARRAY_ELEMENT = 3, - JVMTI_REFERENCE_CLASS_LOADER = 4, - JVMTI_REFERENCE_SIGNERS = 5, - JVMTI_REFERENCE_PROTECTION_DOMAIN = 6, - JVMTI_REFERENCE_INTERFACE = 7, - JVMTI_REFERENCE_STATIC_FIELD = 8, - JVMTI_REFERENCE_CONSTANT_POOL = 9 -} jvmtiObjectReferenceKind; - - /* Iteration Control Enumeration */ - -typedef enum { - JVMTI_ITERATION_CONTINUE = 1, - JVMTI_ITERATION_IGNORE = 2, - JVMTI_ITERATION_ABORT = 0 -} jvmtiIterationControl; - - /* Class Status Flags */ - -enum { - JVMTI_CLASS_STATUS_VERIFIED = 1, - JVMTI_CLASS_STATUS_PREPARED = 2, - JVMTI_CLASS_STATUS_INITIALIZED = 4, - JVMTI_CLASS_STATUS_ERROR = 8, - JVMTI_CLASS_STATUS_ARRAY = 16, - JVMTI_CLASS_STATUS_PRIMITIVE = 32 -}; - - /* Event Enable/Disable */ - -typedef enum { - JVMTI_ENABLE = 1, - JVMTI_DISABLE = 0 -} jvmtiEventMode; - - /* Extension Function/Event Parameter Types */ - -typedef enum { - JVMTI_TYPE_JBYTE = 101, - JVMTI_TYPE_JCHAR = 102, - JVMTI_TYPE_JSHORT = 103, - JVMTI_TYPE_JINT = 104, - JVMTI_TYPE_JLONG = 105, - JVMTI_TYPE_JFLOAT = 106, - JVMTI_TYPE_JDOUBLE = 107, - JVMTI_TYPE_JBOOLEAN = 108, - JVMTI_TYPE_JOBJECT = 109, - JVMTI_TYPE_JTHREAD = 110, - JVMTI_TYPE_JCLASS = 111, - JVMTI_TYPE_JVALUE = 112, - JVMTI_TYPE_JFIELDID = 113, - JVMTI_TYPE_JMETHODID = 114, - JVMTI_TYPE_CCHAR = 115, - JVMTI_TYPE_CVOID = 116, - JVMTI_TYPE_JNIENV = 117 -} jvmtiParamTypes; - - /* Extension Function/Event Parameter Kinds */ - -typedef enum { - JVMTI_KIND_IN = 91, - JVMTI_KIND_IN_PTR = 92, - JVMTI_KIND_IN_BUF = 93, - JVMTI_KIND_ALLOC_BUF = 94, - JVMTI_KIND_ALLOC_ALLOC_BUF = 95, - JVMTI_KIND_OUT = 96, - JVMTI_KIND_OUT_BUF = 97 -} jvmtiParamKind; - - /* Timer Kinds */ - -typedef enum { - JVMTI_TIMER_USER_CPU = 30, - JVMTI_TIMER_TOTAL_CPU = 31, - JVMTI_TIMER_ELAPSED = 32 -} jvmtiTimerKind; - - /* Phases of execution */ - -typedef enum { - JVMTI_PHASE_ONLOAD = 1, - JVMTI_PHASE_PRIMORDIAL = 2, - JVMTI_PHASE_START = 6, - JVMTI_PHASE_LIVE = 4, - JVMTI_PHASE_DEAD = 8 -} jvmtiPhase; - - /* Version Interface Types */ - -enum { - JVMTI_VERSION_INTERFACE_JNI = 0x00000000, - JVMTI_VERSION_INTERFACE_JVMTI = 0x30000000 -}; - - /* Version Masks */ - -enum { - JVMTI_VERSION_MASK_INTERFACE_TYPE = 0x70000000, - JVMTI_VERSION_MASK_MAJOR = 0x0FFF0000, - JVMTI_VERSION_MASK_MINOR = 0x0000FF00, - JVMTI_VERSION_MASK_MICRO = 0x000000FF -}; - - /* Version Shifts */ - -enum { - JVMTI_VERSION_SHIFT_MAJOR = 16, - JVMTI_VERSION_SHIFT_MINOR = 8, - JVMTI_VERSION_SHIFT_MICRO = 0 -}; - - /* Verbose Flag Enumeration */ - -typedef enum { - JVMTI_VERBOSE_OTHER = 0, - JVMTI_VERBOSE_GC = 1, - JVMTI_VERBOSE_CLASS = 2, - JVMTI_VERBOSE_JNI = 4 -} jvmtiVerboseFlag; - - /* JLocation Format Enumeration */ - -typedef enum { - JVMTI_JLOCATION_JVMBCI = 1, - JVMTI_JLOCATION_MACHINEPC = 2, - JVMTI_JLOCATION_OTHER = 0 -} jvmtiJlocationFormat; - - /* Resource Exhaustion Flags */ - -enum { - JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR = 0x0001, - JVMTI_RESOURCE_EXHAUSTED_JAVA_HEAP = 0x0002, - JVMTI_RESOURCE_EXHAUSTED_THREADS = 0x0004 -}; - - /* Errors */ - -typedef enum { - JVMTI_ERROR_NONE = 0, - JVMTI_ERROR_INVALID_THREAD = 10, - JVMTI_ERROR_INVALID_THREAD_GROUP = 11, - JVMTI_ERROR_INVALID_PRIORITY = 12, - JVMTI_ERROR_THREAD_NOT_SUSPENDED = 13, - JVMTI_ERROR_THREAD_SUSPENDED = 14, - JVMTI_ERROR_THREAD_NOT_ALIVE = 15, - JVMTI_ERROR_INVALID_OBJECT = 20, - JVMTI_ERROR_INVALID_CLASS = 21, - JVMTI_ERROR_CLASS_NOT_PREPARED = 22, - JVMTI_ERROR_INVALID_METHODID = 23, - JVMTI_ERROR_INVALID_LOCATION = 24, - JVMTI_ERROR_INVALID_FIELDID = 25, - JVMTI_ERROR_NO_MORE_FRAMES = 31, - JVMTI_ERROR_OPAQUE_FRAME = 32, - JVMTI_ERROR_TYPE_MISMATCH = 34, - JVMTI_ERROR_INVALID_SLOT = 35, - JVMTI_ERROR_DUPLICATE = 40, - JVMTI_ERROR_NOT_FOUND = 41, - JVMTI_ERROR_INVALID_MONITOR = 50, - JVMTI_ERROR_NOT_MONITOR_OWNER = 51, - JVMTI_ERROR_INTERRUPT = 52, - JVMTI_ERROR_INVALID_CLASS_FORMAT = 60, - JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION = 61, - JVMTI_ERROR_FAILS_VERIFICATION = 62, - JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED = 63, - JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED = 64, - JVMTI_ERROR_INVALID_TYPESTATE = 65, - JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED = 66, - JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED = 67, - JVMTI_ERROR_UNSUPPORTED_VERSION = 68, - JVMTI_ERROR_NAMES_DONT_MATCH = 69, - JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED = 70, - JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED = 71, - JVMTI_ERROR_UNMODIFIABLE_CLASS = 79, - JVMTI_ERROR_NOT_AVAILABLE = 98, - JVMTI_ERROR_MUST_POSSESS_CAPABILITY = 99, - JVMTI_ERROR_NULL_POINTER = 100, - JVMTI_ERROR_ABSENT_INFORMATION = 101, - JVMTI_ERROR_INVALID_EVENT_TYPE = 102, - JVMTI_ERROR_ILLEGAL_ARGUMENT = 103, - JVMTI_ERROR_NATIVE_METHOD = 104, - JVMTI_ERROR_CLASS_LOADER_UNSUPPORTED = 106, - JVMTI_ERROR_OUT_OF_MEMORY = 110, - JVMTI_ERROR_ACCESS_DENIED = 111, - JVMTI_ERROR_WRONG_PHASE = 112, - JVMTI_ERROR_INTERNAL = 113, - JVMTI_ERROR_UNATTACHED_THREAD = 115, - JVMTI_ERROR_INVALID_ENVIRONMENT = 116, - JVMTI_ERROR_MAX = 116 -} jvmtiError; - - /* Event IDs */ - -typedef enum { - JVMTI_MIN_EVENT_TYPE_VAL = 50, - JVMTI_EVENT_VM_INIT = 50, - JVMTI_EVENT_VM_DEATH = 51, - JVMTI_EVENT_THREAD_START = 52, - JVMTI_EVENT_THREAD_END = 53, - JVMTI_EVENT_CLASS_FILE_LOAD_HOOK = 54, - JVMTI_EVENT_CLASS_LOAD = 55, - JVMTI_EVENT_CLASS_PREPARE = 56, - JVMTI_EVENT_VM_START = 57, - JVMTI_EVENT_EXCEPTION = 58, - JVMTI_EVENT_EXCEPTION_CATCH = 59, - JVMTI_EVENT_SINGLE_STEP = 60, - JVMTI_EVENT_FRAME_POP = 61, - JVMTI_EVENT_BREAKPOINT = 62, - JVMTI_EVENT_FIELD_ACCESS = 63, - JVMTI_EVENT_FIELD_MODIFICATION = 64, - JVMTI_EVENT_METHOD_ENTRY = 65, - JVMTI_EVENT_METHOD_EXIT = 66, - JVMTI_EVENT_NATIVE_METHOD_BIND = 67, - JVMTI_EVENT_COMPILED_METHOD_LOAD = 68, - JVMTI_EVENT_COMPILED_METHOD_UNLOAD = 69, - JVMTI_EVENT_DYNAMIC_CODE_GENERATED = 70, - JVMTI_EVENT_DATA_DUMP_REQUEST = 71, - JVMTI_EVENT_MONITOR_WAIT = 73, - JVMTI_EVENT_MONITOR_WAITED = 74, - JVMTI_EVENT_MONITOR_CONTENDED_ENTER = 75, - JVMTI_EVENT_MONITOR_CONTENDED_ENTERED = 76, - JVMTI_EVENT_RESOURCE_EXHAUSTED = 80, - JVMTI_EVENT_GARBAGE_COLLECTION_START = 81, - JVMTI_EVENT_GARBAGE_COLLECTION_FINISH = 82, - JVMTI_EVENT_OBJECT_FREE = 83, - JVMTI_EVENT_VM_OBJECT_ALLOC = 84, - JVMTI_MAX_EVENT_TYPE_VAL = 84 -} jvmtiEvent; - - - /* Pre-Declarations */ -struct _jvmtiThreadInfo; -typedef struct _jvmtiThreadInfo jvmtiThreadInfo; -struct _jvmtiMonitorStackDepthInfo; -typedef struct _jvmtiMonitorStackDepthInfo jvmtiMonitorStackDepthInfo; -struct _jvmtiThreadGroupInfo; -typedef struct _jvmtiThreadGroupInfo jvmtiThreadGroupInfo; -struct _jvmtiFrameInfo; -typedef struct _jvmtiFrameInfo jvmtiFrameInfo; -struct _jvmtiStackInfo; -typedef struct _jvmtiStackInfo jvmtiStackInfo; -struct _jvmtiHeapReferenceInfoField; -typedef struct _jvmtiHeapReferenceInfoField jvmtiHeapReferenceInfoField; -struct _jvmtiHeapReferenceInfoArray; -typedef struct _jvmtiHeapReferenceInfoArray jvmtiHeapReferenceInfoArray; -struct _jvmtiHeapReferenceInfoConstantPool; -typedef struct _jvmtiHeapReferenceInfoConstantPool jvmtiHeapReferenceInfoConstantPool; -struct _jvmtiHeapReferenceInfoStackLocal; -typedef struct _jvmtiHeapReferenceInfoStackLocal jvmtiHeapReferenceInfoStackLocal; -struct _jvmtiHeapReferenceInfoJniLocal; -typedef struct _jvmtiHeapReferenceInfoJniLocal jvmtiHeapReferenceInfoJniLocal; -struct _jvmtiHeapReferenceInfoReserved; -typedef struct _jvmtiHeapReferenceInfoReserved jvmtiHeapReferenceInfoReserved; -union _jvmtiHeapReferenceInfo; -typedef union _jvmtiHeapReferenceInfo jvmtiHeapReferenceInfo; -struct _jvmtiHeapCallbacks; -typedef struct _jvmtiHeapCallbacks jvmtiHeapCallbacks; -struct _jvmtiClassDefinition; -typedef struct _jvmtiClassDefinition jvmtiClassDefinition; -struct _jvmtiMonitorUsage; -typedef struct _jvmtiMonitorUsage jvmtiMonitorUsage; -struct _jvmtiLineNumberEntry; -typedef struct _jvmtiLineNumberEntry jvmtiLineNumberEntry; -struct _jvmtiLocalVariableEntry; -typedef struct _jvmtiLocalVariableEntry jvmtiLocalVariableEntry; -struct _jvmtiParamInfo; -typedef struct _jvmtiParamInfo jvmtiParamInfo; -struct _jvmtiExtensionFunctionInfo; -typedef struct _jvmtiExtensionFunctionInfo jvmtiExtensionFunctionInfo; -struct _jvmtiExtensionEventInfo; -typedef struct _jvmtiExtensionEventInfo jvmtiExtensionEventInfo; -struct _jvmtiTimerInfo; -typedef struct _jvmtiTimerInfo jvmtiTimerInfo; -struct _jvmtiAddrLocationMap; -typedef struct _jvmtiAddrLocationMap jvmtiAddrLocationMap; - - /* Function Types */ - -typedef void (JNICALL *jvmtiStartFunction) - (jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg); - -typedef jint (JNICALL *jvmtiHeapIterationCallback) - (jlong class_tag, jlong size, jlong* tag_ptr, jint length, void* user_data); - -typedef jint (JNICALL *jvmtiHeapReferenceCallback) - (jvmtiHeapReferenceKind reference_kind, const jvmtiHeapReferenceInfo* reference_info, jlong class_tag, jlong referrer_class_tag, jlong size, jlong* tag_ptr, jlong* referrer_tag_ptr, jint length, void* user_data); - -typedef jint (JNICALL *jvmtiPrimitiveFieldCallback) - (jvmtiHeapReferenceKind kind, const jvmtiHeapReferenceInfo* info, jlong object_class_tag, jlong* object_tag_ptr, jvalue value, jvmtiPrimitiveType value_type, void* user_data); - -typedef jint (JNICALL *jvmtiArrayPrimitiveValueCallback) - (jlong class_tag, jlong size, jlong* tag_ptr, jint element_count, jvmtiPrimitiveType element_type, const void* elements, void* user_data); - -typedef jint (JNICALL *jvmtiStringPrimitiveValueCallback) - (jlong class_tag, jlong size, jlong* tag_ptr, const jchar* value, jint value_length, void* user_data); - -typedef jint (JNICALL *jvmtiReservedCallback) - (); - -typedef jvmtiIterationControl (JNICALL *jvmtiHeapObjectCallback) - (jlong class_tag, jlong size, jlong* tag_ptr, void* user_data); - -typedef jvmtiIterationControl (JNICALL *jvmtiHeapRootCallback) - (jvmtiHeapRootKind root_kind, jlong class_tag, jlong size, jlong* tag_ptr, void* user_data); - -typedef jvmtiIterationControl (JNICALL *jvmtiStackReferenceCallback) - (jvmtiHeapRootKind root_kind, jlong class_tag, jlong size, jlong* tag_ptr, jlong thread_tag, jint depth, jmethodID method, jint slot, void* user_data); - -typedef jvmtiIterationControl (JNICALL *jvmtiObjectReferenceCallback) - (jvmtiObjectReferenceKind reference_kind, jlong class_tag, jlong size, jlong* tag_ptr, jlong referrer_tag, jint referrer_index, void* user_data); - -typedef jvmtiError (JNICALL *jvmtiExtensionFunction) - (jvmtiEnv* jvmti_env, ...); - -typedef void (JNICALL *jvmtiExtensionEvent) - (jvmtiEnv* jvmti_env, ...); - - - /* Structure Types */ -struct _jvmtiThreadInfo { - char* name; - jint priority; - jboolean is_daemon; - jthreadGroup thread_group; - jobject context_class_loader; -}; -struct _jvmtiMonitorStackDepthInfo { - jobject monitor; - jint stack_depth; -}; -struct _jvmtiThreadGroupInfo { - jthreadGroup parent; - char* name; - jint max_priority; - jboolean is_daemon; -}; -struct _jvmtiFrameInfo { - jmethodID method; - jlocation location; -}; -struct _jvmtiStackInfo { - jthread thread; - jint state; - jvmtiFrameInfo* frame_buffer; - jint frame_count; -}; -struct _jvmtiHeapReferenceInfoField { - jint index; -}; -struct _jvmtiHeapReferenceInfoArray { - jint index; -}; -struct _jvmtiHeapReferenceInfoConstantPool { - jint index; -}; -struct _jvmtiHeapReferenceInfoStackLocal { - jlong thread_tag; - jlong thread_id; - jint depth; - jmethodID method; - jlocation location; - jint slot; -}; -struct _jvmtiHeapReferenceInfoJniLocal { - jlong thread_tag; - jlong thread_id; - jint depth; - jmethodID method; -}; -struct _jvmtiHeapReferenceInfoReserved { - jlong reserved1; - jlong reserved2; - jlong reserved3; - jlong reserved4; - jlong reserved5; - jlong reserved6; - jlong reserved7; - jlong reserved8; -}; -union _jvmtiHeapReferenceInfo { - jvmtiHeapReferenceInfoField field; - jvmtiHeapReferenceInfoArray array; - jvmtiHeapReferenceInfoConstantPool constant_pool; - jvmtiHeapReferenceInfoStackLocal stack_local; - jvmtiHeapReferenceInfoJniLocal jni_local; - jvmtiHeapReferenceInfoReserved other; -}; -struct _jvmtiHeapCallbacks { - jvmtiHeapIterationCallback heap_iteration_callback; - jvmtiHeapReferenceCallback heap_reference_callback; - jvmtiPrimitiveFieldCallback primitive_field_callback; - jvmtiArrayPrimitiveValueCallback array_primitive_value_callback; - jvmtiStringPrimitiveValueCallback string_primitive_value_callback; - jvmtiReservedCallback reserved5; - jvmtiReservedCallback reserved6; - jvmtiReservedCallback reserved7; - jvmtiReservedCallback reserved8; - jvmtiReservedCallback reserved9; - jvmtiReservedCallback reserved10; - jvmtiReservedCallback reserved11; - jvmtiReservedCallback reserved12; - jvmtiReservedCallback reserved13; - jvmtiReservedCallback reserved14; - jvmtiReservedCallback reserved15; -}; -struct _jvmtiClassDefinition { - jclass klass; - jint class_byte_count; - const unsigned char* class_bytes; -}; -struct _jvmtiMonitorUsage { - jthread owner; - jint entry_count; - jint waiter_count; - jthread* waiters; - jint notify_waiter_count; - jthread* notify_waiters; -}; -struct _jvmtiLineNumberEntry { - jlocation start_location; - jint line_number; -}; -struct _jvmtiLocalVariableEntry { - jlocation start_location; - jint length; - char* name; - char* signature; - char* generic_signature; - jint slot; -}; -struct _jvmtiParamInfo { - char* name; - jvmtiParamKind kind; - jvmtiParamTypes base_type; - jboolean null_ok; -}; -struct _jvmtiExtensionFunctionInfo { - jvmtiExtensionFunction func; - char* id; - char* short_description; - jint param_count; - jvmtiParamInfo* params; - jint error_count; - jvmtiError* errors; -}; -struct _jvmtiExtensionEventInfo { - jint extension_event_index; - char* id; - char* short_description; - jint param_count; - jvmtiParamInfo* params; -}; -struct _jvmtiTimerInfo { - jlong max_value; - jboolean may_skip_forward; - jboolean may_skip_backward; - jvmtiTimerKind kind; - jlong reserved1; - jlong reserved2; -}; -struct _jvmtiAddrLocationMap { - const void* start_address; - jlocation location; -}; - -typedef struct { - unsigned int can_tag_objects : 1; - unsigned int can_generate_field_modification_events : 1; - unsigned int can_generate_field_access_events : 1; - unsigned int can_get_bytecodes : 1; - unsigned int can_get_synthetic_attribute : 1; - unsigned int can_get_owned_monitor_info : 1; - unsigned int can_get_current_contended_monitor : 1; - unsigned int can_get_monitor_info : 1; - unsigned int can_pop_frame : 1; - unsigned int can_redefine_classes : 1; - unsigned int can_signal_thread : 1; - unsigned int can_get_source_file_name : 1; - unsigned int can_get_line_numbers : 1; - unsigned int can_get_source_debug_extension : 1; - unsigned int can_access_local_variables : 1; - unsigned int can_maintain_original_method_order : 1; - unsigned int can_generate_single_step_events : 1; - unsigned int can_generate_exception_events : 1; - unsigned int can_generate_frame_pop_events : 1; - unsigned int can_generate_breakpoint_events : 1; - unsigned int can_suspend : 1; - unsigned int can_redefine_any_class : 1; - unsigned int can_get_current_thread_cpu_time : 1; - unsigned int can_get_thread_cpu_time : 1; - unsigned int can_generate_method_entry_events : 1; - unsigned int can_generate_method_exit_events : 1; - unsigned int can_generate_all_class_hook_events : 1; - unsigned int can_generate_compiled_method_load_events : 1; - unsigned int can_generate_monitor_events : 1; - unsigned int can_generate_vm_object_alloc_events : 1; - unsigned int can_generate_native_method_bind_events : 1; - unsigned int can_generate_garbage_collection_events : 1; - unsigned int can_generate_object_free_events : 1; - unsigned int can_force_early_return : 1; - unsigned int can_get_owned_monitor_stack_depth_info : 1; - unsigned int can_get_constant_pool : 1; - unsigned int can_set_native_method_prefix : 1; - unsigned int can_retransform_classes : 1; - unsigned int can_retransform_any_class : 1; - unsigned int can_generate_resource_exhaustion_heap_events : 1; - unsigned int can_generate_resource_exhaustion_threads_events : 1; - unsigned int can_generate_early_vmstart : 1; - unsigned int can_generate_early_class_hook_events : 1; - unsigned int : 5; - unsigned int : 16; - unsigned int : 16; - unsigned int : 16; - unsigned int : 16; - unsigned int : 16; -} jvmtiCapabilities; - - - /* Event Definitions */ - -typedef void (JNICALL *jvmtiEventReserved)(void); - - -typedef void (JNICALL *jvmtiEventBreakpoint) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jmethodID method, - jlocation location); - -typedef void (JNICALL *jvmtiEventClassFileLoadHook) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jclass class_being_redefined, - jobject loader, - const char* name, - jobject protection_domain, - jint class_data_len, - const unsigned char* class_data, - jint* new_class_data_len, - unsigned char** new_class_data); - -typedef void (JNICALL *jvmtiEventClassLoad) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jclass klass); - -typedef void (JNICALL *jvmtiEventClassPrepare) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jclass klass); - -typedef void (JNICALL *jvmtiEventCompiledMethodLoad) - (jvmtiEnv *jvmti_env, - jmethodID method, - jint code_size, - const void* code_addr, - jint map_length, - const jvmtiAddrLocationMap* map, - const void* compile_info); - -typedef void (JNICALL *jvmtiEventCompiledMethodUnload) - (jvmtiEnv *jvmti_env, - jmethodID method, - const void* code_addr); - -typedef void (JNICALL *jvmtiEventDataDumpRequest) - (jvmtiEnv *jvmti_env); - -typedef void (JNICALL *jvmtiEventDynamicCodeGenerated) - (jvmtiEnv *jvmti_env, - const char* name, - const void* address, - jint length); - -typedef void (JNICALL *jvmtiEventException) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jmethodID method, - jlocation location, - jobject exception, - jmethodID catch_method, - jlocation catch_location); - -typedef void (JNICALL *jvmtiEventExceptionCatch) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jmethodID method, - jlocation location, - jobject exception); - -typedef void (JNICALL *jvmtiEventFieldAccess) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jmethodID method, - jlocation location, - jclass field_klass, - jobject object, - jfieldID field); - -typedef void (JNICALL *jvmtiEventFieldModification) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jmethodID method, - jlocation location, - jclass field_klass, - jobject object, - jfieldID field, - char signature_type, - jvalue new_value); - -typedef void (JNICALL *jvmtiEventFramePop) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jmethodID method, - jboolean was_popped_by_exception); - -typedef void (JNICALL *jvmtiEventGarbageCollectionFinish) - (jvmtiEnv *jvmti_env); - -typedef void (JNICALL *jvmtiEventGarbageCollectionStart) - (jvmtiEnv *jvmti_env); - -typedef void (JNICALL *jvmtiEventMethodEntry) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jmethodID method); - -typedef void (JNICALL *jvmtiEventMethodExit) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jmethodID method, - jboolean was_popped_by_exception, - jvalue return_value); - -typedef void (JNICALL *jvmtiEventMonitorContendedEnter) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jobject object); - -typedef void (JNICALL *jvmtiEventMonitorContendedEntered) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jobject object); - -typedef void (JNICALL *jvmtiEventMonitorWait) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jobject object, - jlong timeout); - -typedef void (JNICALL *jvmtiEventMonitorWaited) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jobject object, - jboolean timed_out); - -typedef void (JNICALL *jvmtiEventNativeMethodBind) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jmethodID method, - void* address, - void** new_address_ptr); - -typedef void (JNICALL *jvmtiEventObjectFree) - (jvmtiEnv *jvmti_env, - jlong tag); - -typedef void (JNICALL *jvmtiEventResourceExhausted) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jint flags, - const void* reserved, - const char* description); - -typedef void (JNICALL *jvmtiEventSingleStep) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jmethodID method, - jlocation location); - -typedef void (JNICALL *jvmtiEventThreadEnd) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread); - -typedef void (JNICALL *jvmtiEventThreadStart) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread); - -typedef void (JNICALL *jvmtiEventVMDeath) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env); - -typedef void (JNICALL *jvmtiEventVMInit) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread); - -typedef void (JNICALL *jvmtiEventVMObjectAlloc) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env, - jthread thread, - jobject object, - jclass object_klass, - jlong size); - -typedef void (JNICALL *jvmtiEventVMStart) - (jvmtiEnv *jvmti_env, - JNIEnv* jni_env); - - /* Event Callback Structure */ - -typedef struct { - /* 50 : VM Initialization Event */ - jvmtiEventVMInit VMInit; - /* 51 : VM Death Event */ - jvmtiEventVMDeath VMDeath; - /* 52 : Thread Start */ - jvmtiEventThreadStart ThreadStart; - /* 53 : Thread End */ - jvmtiEventThreadEnd ThreadEnd; - /* 54 : Class File Load Hook */ - jvmtiEventClassFileLoadHook ClassFileLoadHook; - /* 55 : Class Load */ - jvmtiEventClassLoad ClassLoad; - /* 56 : Class Prepare */ - jvmtiEventClassPrepare ClassPrepare; - /* 57 : VM Start Event */ - jvmtiEventVMStart VMStart; - /* 58 : Exception */ - jvmtiEventException Exception; - /* 59 : Exception Catch */ - jvmtiEventExceptionCatch ExceptionCatch; - /* 60 : Single Step */ - jvmtiEventSingleStep SingleStep; - /* 61 : Frame Pop */ - jvmtiEventFramePop FramePop; - /* 62 : Breakpoint */ - jvmtiEventBreakpoint Breakpoint; - /* 63 : Field Access */ - jvmtiEventFieldAccess FieldAccess; - /* 64 : Field Modification */ - jvmtiEventFieldModification FieldModification; - /* 65 : Method Entry */ - jvmtiEventMethodEntry MethodEntry; - /* 66 : Method Exit */ - jvmtiEventMethodExit MethodExit; - /* 67 : Native Method Bind */ - jvmtiEventNativeMethodBind NativeMethodBind; - /* 68 : Compiled Method Load */ - jvmtiEventCompiledMethodLoad CompiledMethodLoad; - /* 69 : Compiled Method Unload */ - jvmtiEventCompiledMethodUnload CompiledMethodUnload; - /* 70 : Dynamic Code Generated */ - jvmtiEventDynamicCodeGenerated DynamicCodeGenerated; - /* 71 : Data Dump Request */ - jvmtiEventDataDumpRequest DataDumpRequest; - /* 72 */ - jvmtiEventReserved reserved72; - /* 73 : Monitor Wait */ - jvmtiEventMonitorWait MonitorWait; - /* 74 : Monitor Waited */ - jvmtiEventMonitorWaited MonitorWaited; - /* 75 : Monitor Contended Enter */ - jvmtiEventMonitorContendedEnter MonitorContendedEnter; - /* 76 : Monitor Contended Entered */ - jvmtiEventMonitorContendedEntered MonitorContendedEntered; - /* 77 */ - jvmtiEventReserved reserved77; - /* 78 */ - jvmtiEventReserved reserved78; - /* 79 */ - jvmtiEventReserved reserved79; - /* 80 : Resource Exhausted */ - jvmtiEventResourceExhausted ResourceExhausted; - /* 81 : Garbage Collection Start */ - jvmtiEventGarbageCollectionStart GarbageCollectionStart; - /* 82 : Garbage Collection Finish */ - jvmtiEventGarbageCollectionFinish GarbageCollectionFinish; - /* 83 : Object Free */ - jvmtiEventObjectFree ObjectFree; - /* 84 : VM Object Allocation */ - jvmtiEventVMObjectAlloc VMObjectAlloc; -} jvmtiEventCallbacks; - - - /* Function Interface */ - -typedef struct jvmtiInterface_1_ { - - /* 1 : RESERVED */ - void *reserved1; - - /* 2 : Set Event Notification Mode */ - jvmtiError (JNICALL *SetEventNotificationMode) (jvmtiEnv* env, - jvmtiEventMode mode, - jvmtiEvent event_type, - jthread event_thread, - ...); - - /* 3 : Get All Modules */ - jvmtiError (JNICALL *GetAllModules) (jvmtiEnv* env, - jint* module_count_ptr, - jobject** modules_ptr); - - /* 4 : Get All Threads */ - jvmtiError (JNICALL *GetAllThreads) (jvmtiEnv* env, - jint* threads_count_ptr, - jthread** threads_ptr); - - /* 5 : Suspend Thread */ - jvmtiError (JNICALL *SuspendThread) (jvmtiEnv* env, - jthread thread); - - /* 6 : Resume Thread */ - jvmtiError (JNICALL *ResumeThread) (jvmtiEnv* env, - jthread thread); - - /* 7 : Stop Thread */ - jvmtiError (JNICALL *StopThread) (jvmtiEnv* env, - jthread thread, - jobject exception); - - /* 8 : Interrupt Thread */ - jvmtiError (JNICALL *InterruptThread) (jvmtiEnv* env, - jthread thread); - - /* 9 : Get Thread Info */ - jvmtiError (JNICALL *GetThreadInfo) (jvmtiEnv* env, - jthread thread, - jvmtiThreadInfo* info_ptr); - - /* 10 : Get Owned Monitor Info */ - jvmtiError (JNICALL *GetOwnedMonitorInfo) (jvmtiEnv* env, - jthread thread, - jint* owned_monitor_count_ptr, - jobject** owned_monitors_ptr); - - /* 11 : Get Current Contended Monitor */ - jvmtiError (JNICALL *GetCurrentContendedMonitor) (jvmtiEnv* env, - jthread thread, - jobject* monitor_ptr); - - /* 12 : Run Agent Thread */ - jvmtiError (JNICALL *RunAgentThread) (jvmtiEnv* env, - jthread thread, - jvmtiStartFunction proc, - const void* arg, - jint priority); - - /* 13 : Get Top Thread Groups */ - jvmtiError (JNICALL *GetTopThreadGroups) (jvmtiEnv* env, - jint* group_count_ptr, - jthreadGroup** groups_ptr); - - /* 14 : Get Thread Group Info */ - jvmtiError (JNICALL *GetThreadGroupInfo) (jvmtiEnv* env, - jthreadGroup group, - jvmtiThreadGroupInfo* info_ptr); - - /* 15 : Get Thread Group Children */ - jvmtiError (JNICALL *GetThreadGroupChildren) (jvmtiEnv* env, - jthreadGroup group, - jint* thread_count_ptr, - jthread** threads_ptr, - jint* group_count_ptr, - jthreadGroup** groups_ptr); - - /* 16 : Get Frame Count */ - jvmtiError (JNICALL *GetFrameCount) (jvmtiEnv* env, - jthread thread, - jint* count_ptr); - - /* 17 : Get Thread State */ - jvmtiError (JNICALL *GetThreadState) (jvmtiEnv* env, - jthread thread, - jint* thread_state_ptr); - - /* 18 : Get Current Thread */ - jvmtiError (JNICALL *GetCurrentThread) (jvmtiEnv* env, - jthread* thread_ptr); - - /* 19 : Get Frame Location */ - jvmtiError (JNICALL *GetFrameLocation) (jvmtiEnv* env, - jthread thread, - jint depth, - jmethodID* method_ptr, - jlocation* location_ptr); - - /* 20 : Notify Frame Pop */ - jvmtiError (JNICALL *NotifyFramePop) (jvmtiEnv* env, - jthread thread, - jint depth); - - /* 21 : Get Local Variable - Object */ - jvmtiError (JNICALL *GetLocalObject) (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, - jobject* value_ptr); - - /* 22 : Get Local Variable - Int */ - jvmtiError (JNICALL *GetLocalInt) (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, - jint* value_ptr); - - /* 23 : Get Local Variable - Long */ - jvmtiError (JNICALL *GetLocalLong) (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, - jlong* value_ptr); - - /* 24 : Get Local Variable - Float */ - jvmtiError (JNICALL *GetLocalFloat) (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, - jfloat* value_ptr); - - /* 25 : Get Local Variable - Double */ - jvmtiError (JNICALL *GetLocalDouble) (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, - jdouble* value_ptr); - - /* 26 : Set Local Variable - Object */ - jvmtiError (JNICALL *SetLocalObject) (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, - jobject value); - - /* 27 : Set Local Variable - Int */ - jvmtiError (JNICALL *SetLocalInt) (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, - jint value); - - /* 28 : Set Local Variable - Long */ - jvmtiError (JNICALL *SetLocalLong) (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, - jlong value); - - /* 29 : Set Local Variable - Float */ - jvmtiError (JNICALL *SetLocalFloat) (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, - jfloat value); - - /* 30 : Set Local Variable - Double */ - jvmtiError (JNICALL *SetLocalDouble) (jvmtiEnv* env, - jthread thread, - jint depth, - jint slot, - jdouble value); - - /* 31 : Create Raw Monitor */ - jvmtiError (JNICALL *CreateRawMonitor) (jvmtiEnv* env, - const char* name, - jrawMonitorID* monitor_ptr); - - /* 32 : Destroy Raw Monitor */ - jvmtiError (JNICALL *DestroyRawMonitor) (jvmtiEnv* env, - jrawMonitorID monitor); - - /* 33 : Raw Monitor Enter */ - jvmtiError (JNICALL *RawMonitorEnter) (jvmtiEnv* env, - jrawMonitorID monitor); - - /* 34 : Raw Monitor Exit */ - jvmtiError (JNICALL *RawMonitorExit) (jvmtiEnv* env, - jrawMonitorID monitor); - - /* 35 : Raw Monitor Wait */ - jvmtiError (JNICALL *RawMonitorWait) (jvmtiEnv* env, - jrawMonitorID monitor, - jlong millis); - - /* 36 : Raw Monitor Notify */ - jvmtiError (JNICALL *RawMonitorNotify) (jvmtiEnv* env, - jrawMonitorID monitor); - - /* 37 : Raw Monitor Notify All */ - jvmtiError (JNICALL *RawMonitorNotifyAll) (jvmtiEnv* env, - jrawMonitorID monitor); - - /* 38 : Set Breakpoint */ - jvmtiError (JNICALL *SetBreakpoint) (jvmtiEnv* env, - jmethodID method, - jlocation location); - - /* 39 : Clear Breakpoint */ - jvmtiError (JNICALL *ClearBreakpoint) (jvmtiEnv* env, - jmethodID method, - jlocation location); - - /* 40 : Get Named Module */ - jvmtiError (JNICALL *GetNamedModule) (jvmtiEnv* env, - jobject class_loader, - const char* package_name, - jobject* module_ptr); - - /* 41 : Set Field Access Watch */ - jvmtiError (JNICALL *SetFieldAccessWatch) (jvmtiEnv* env, - jclass klass, - jfieldID field); - - /* 42 : Clear Field Access Watch */ - jvmtiError (JNICALL *ClearFieldAccessWatch) (jvmtiEnv* env, - jclass klass, - jfieldID field); - - /* 43 : Set Field Modification Watch */ - jvmtiError (JNICALL *SetFieldModificationWatch) (jvmtiEnv* env, - jclass klass, - jfieldID field); - - /* 44 : Clear Field Modification Watch */ - jvmtiError (JNICALL *ClearFieldModificationWatch) (jvmtiEnv* env, - jclass klass, - jfieldID field); - - /* 45 : Is Modifiable Class */ - jvmtiError (JNICALL *IsModifiableClass) (jvmtiEnv* env, - jclass klass, - jboolean* is_modifiable_class_ptr); - - /* 46 : Allocate */ - jvmtiError (JNICALL *Allocate) (jvmtiEnv* env, - jlong size, - unsigned char** mem_ptr); - - /* 47 : Deallocate */ - jvmtiError (JNICALL *Deallocate) (jvmtiEnv* env, - unsigned char* mem); - - /* 48 : Get Class Signature */ - jvmtiError (JNICALL *GetClassSignature) (jvmtiEnv* env, - jclass klass, - char** signature_ptr, - char** generic_ptr); - - /* 49 : Get Class Status */ - jvmtiError (JNICALL *GetClassStatus) (jvmtiEnv* env, - jclass klass, - jint* status_ptr); - - /* 50 : Get Source File Name */ - jvmtiError (JNICALL *GetSourceFileName) (jvmtiEnv* env, - jclass klass, - char** source_name_ptr); - - /* 51 : Get Class Modifiers */ - jvmtiError (JNICALL *GetClassModifiers) (jvmtiEnv* env, - jclass klass, - jint* modifiers_ptr); - - /* 52 : Get Class Methods */ - jvmtiError (JNICALL *GetClassMethods) (jvmtiEnv* env, - jclass klass, - jint* method_count_ptr, - jmethodID** methods_ptr); - - /* 53 : Get Class Fields */ - jvmtiError (JNICALL *GetClassFields) (jvmtiEnv* env, - jclass klass, - jint* field_count_ptr, - jfieldID** fields_ptr); - - /* 54 : Get Implemented Interfaces */ - jvmtiError (JNICALL *GetImplementedInterfaces) (jvmtiEnv* env, - jclass klass, - jint* interface_count_ptr, - jclass** interfaces_ptr); - - /* 55 : Is Interface */ - jvmtiError (JNICALL *IsInterface) (jvmtiEnv* env, - jclass klass, - jboolean* is_interface_ptr); - - /* 56 : Is Array Class */ - jvmtiError (JNICALL *IsArrayClass) (jvmtiEnv* env, - jclass klass, - jboolean* is_array_class_ptr); - - /* 57 : Get Class Loader */ - jvmtiError (JNICALL *GetClassLoader) (jvmtiEnv* env, - jclass klass, - jobject* classloader_ptr); - - /* 58 : Get Object Hash Code */ - jvmtiError (JNICALL *GetObjectHashCode) (jvmtiEnv* env, - jobject object, - jint* hash_code_ptr); - - /* 59 : Get Object Monitor Usage */ - jvmtiError (JNICALL *GetObjectMonitorUsage) (jvmtiEnv* env, - jobject object, - jvmtiMonitorUsage* info_ptr); - - /* 60 : Get Field Name (and Signature) */ - jvmtiError (JNICALL *GetFieldName) (jvmtiEnv* env, - jclass klass, - jfieldID field, - char** name_ptr, - char** signature_ptr, - char** generic_ptr); - - /* 61 : Get Field Declaring Class */ - jvmtiError (JNICALL *GetFieldDeclaringClass) (jvmtiEnv* env, - jclass klass, - jfieldID field, - jclass* declaring_class_ptr); - - /* 62 : Get Field Modifiers */ - jvmtiError (JNICALL *GetFieldModifiers) (jvmtiEnv* env, - jclass klass, - jfieldID field, - jint* modifiers_ptr); - - /* 63 : Is Field Synthetic */ - jvmtiError (JNICALL *IsFieldSynthetic) (jvmtiEnv* env, - jclass klass, - jfieldID field, - jboolean* is_synthetic_ptr); - - /* 64 : Get Method Name (and Signature) */ - jvmtiError (JNICALL *GetMethodName) (jvmtiEnv* env, - jmethodID method, - char** name_ptr, - char** signature_ptr, - char** generic_ptr); - - /* 65 : Get Method Declaring Class */ - jvmtiError (JNICALL *GetMethodDeclaringClass) (jvmtiEnv* env, - jmethodID method, - jclass* declaring_class_ptr); - - /* 66 : Get Method Modifiers */ - jvmtiError (JNICALL *GetMethodModifiers) (jvmtiEnv* env, - jmethodID method, - jint* modifiers_ptr); - - /* 67 : RESERVED */ - void *reserved67; - - /* 68 : Get Max Locals */ - jvmtiError (JNICALL *GetMaxLocals) (jvmtiEnv* env, - jmethodID method, - jint* max_ptr); - - /* 69 : Get Arguments Size */ - jvmtiError (JNICALL *GetArgumentsSize) (jvmtiEnv* env, - jmethodID method, - jint* size_ptr); - - /* 70 : Get Line Number Table */ - jvmtiError (JNICALL *GetLineNumberTable) (jvmtiEnv* env, - jmethodID method, - jint* entry_count_ptr, - jvmtiLineNumberEntry** table_ptr); - - /* 71 : Get Method Location */ - jvmtiError (JNICALL *GetMethodLocation) (jvmtiEnv* env, - jmethodID method, - jlocation* start_location_ptr, - jlocation* end_location_ptr); - - /* 72 : Get Local Variable Table */ - jvmtiError (JNICALL *GetLocalVariableTable) (jvmtiEnv* env, - jmethodID method, - jint* entry_count_ptr, - jvmtiLocalVariableEntry** table_ptr); - - /* 73 : Set Native Method Prefix */ - jvmtiError (JNICALL *SetNativeMethodPrefix) (jvmtiEnv* env, - const char* prefix); - - /* 74 : Set Native Method Prefixes */ - jvmtiError (JNICALL *SetNativeMethodPrefixes) (jvmtiEnv* env, - jint prefix_count, - char** prefixes); - - /* 75 : Get Bytecodes */ - jvmtiError (JNICALL *GetBytecodes) (jvmtiEnv* env, - jmethodID method, - jint* bytecode_count_ptr, - unsigned char** bytecodes_ptr); - - /* 76 : Is Method Native */ - jvmtiError (JNICALL *IsMethodNative) (jvmtiEnv* env, - jmethodID method, - jboolean* is_native_ptr); - - /* 77 : Is Method Synthetic */ - jvmtiError (JNICALL *IsMethodSynthetic) (jvmtiEnv* env, - jmethodID method, - jboolean* is_synthetic_ptr); - - /* 78 : Get Loaded Classes */ - jvmtiError (JNICALL *GetLoadedClasses) (jvmtiEnv* env, - jint* class_count_ptr, - jclass** classes_ptr); - - /* 79 : Get Classloader Classes */ - jvmtiError (JNICALL *GetClassLoaderClasses) (jvmtiEnv* env, - jobject initiating_loader, - jint* class_count_ptr, - jclass** classes_ptr); - - /* 80 : Pop Frame */ - jvmtiError (JNICALL *PopFrame) (jvmtiEnv* env, - jthread thread); - - /* 81 : Force Early Return - Object */ - jvmtiError (JNICALL *ForceEarlyReturnObject) (jvmtiEnv* env, - jthread thread, - jobject value); - - /* 82 : Force Early Return - Int */ - jvmtiError (JNICALL *ForceEarlyReturnInt) (jvmtiEnv* env, - jthread thread, - jint value); - - /* 83 : Force Early Return - Long */ - jvmtiError (JNICALL *ForceEarlyReturnLong) (jvmtiEnv* env, - jthread thread, - jlong value); - - /* 84 : Force Early Return - Float */ - jvmtiError (JNICALL *ForceEarlyReturnFloat) (jvmtiEnv* env, - jthread thread, - jfloat value); - - /* 85 : Force Early Return - Double */ - jvmtiError (JNICALL *ForceEarlyReturnDouble) (jvmtiEnv* env, - jthread thread, - jdouble value); - - /* 86 : Force Early Return - Void */ - jvmtiError (JNICALL *ForceEarlyReturnVoid) (jvmtiEnv* env, - jthread thread); - - /* 87 : Redefine Classes */ - jvmtiError (JNICALL *RedefineClasses) (jvmtiEnv* env, - jint class_count, - const jvmtiClassDefinition* class_definitions); - - /* 88 : Get Version Number */ - jvmtiError (JNICALL *GetVersionNumber) (jvmtiEnv* env, - jint* version_ptr); - - /* 89 : Get Capabilities */ - jvmtiError (JNICALL *GetCapabilities) (jvmtiEnv* env, - jvmtiCapabilities* capabilities_ptr); - - /* 90 : Get Source Debug Extension */ - jvmtiError (JNICALL *GetSourceDebugExtension) (jvmtiEnv* env, - jclass klass, - char** source_debug_extension_ptr); - - /* 91 : Is Method Obsolete */ - jvmtiError (JNICALL *IsMethodObsolete) (jvmtiEnv* env, - jmethodID method, - jboolean* is_obsolete_ptr); - - /* 92 : Suspend Thread List */ - jvmtiError (JNICALL *SuspendThreadList) (jvmtiEnv* env, - jint request_count, - const jthread* request_list, - jvmtiError* results); - - /* 93 : Resume Thread List */ - jvmtiError (JNICALL *ResumeThreadList) (jvmtiEnv* env, - jint request_count, - const jthread* request_list, - jvmtiError* results); - - /* 94 : RESERVED */ - void *reserved94; - - /* 95 : RESERVED */ - void *reserved95; - - /* 96 : RESERVED */ - void *reserved96; - - /* 97 : RESERVED */ - void *reserved97; - - /* 98 : RESERVED */ - void *reserved98; - - /* 99 : RESERVED */ - void *reserved99; - - /* 100 : Get All Stack Traces */ - jvmtiError (JNICALL *GetAllStackTraces) (jvmtiEnv* env, - jint max_frame_count, - jvmtiStackInfo** stack_info_ptr, - jint* thread_count_ptr); - - /* 101 : Get Thread List Stack Traces */ - jvmtiError (JNICALL *GetThreadListStackTraces) (jvmtiEnv* env, - jint thread_count, - const jthread* thread_list, - jint max_frame_count, - jvmtiStackInfo** stack_info_ptr); - - /* 102 : Get Thread Local Storage */ - jvmtiError (JNICALL *GetThreadLocalStorage) (jvmtiEnv* env, - jthread thread, - void** data_ptr); - - /* 103 : Set Thread Local Storage */ - jvmtiError (JNICALL *SetThreadLocalStorage) (jvmtiEnv* env, - jthread thread, - const void* data); - - /* 104 : Get Stack Trace */ - jvmtiError (JNICALL *GetStackTrace) (jvmtiEnv* env, - jthread thread, - jint start_depth, - jint max_frame_count, - jvmtiFrameInfo* frame_buffer, - jint* count_ptr); - - /* 105 : RESERVED */ - void *reserved105; - - /* 106 : Get Tag */ - jvmtiError (JNICALL *GetTag) (jvmtiEnv* env, - jobject object, - jlong* tag_ptr); - - /* 107 : Set Tag */ - jvmtiError (JNICALL *SetTag) (jvmtiEnv* env, - jobject object, - jlong tag); - - /* 108 : Force Garbage Collection */ - jvmtiError (JNICALL *ForceGarbageCollection) (jvmtiEnv* env); - - /* 109 : Iterate Over Objects Reachable From Object */ - jvmtiError (JNICALL *IterateOverObjectsReachableFromObject) (jvmtiEnv* env, - jobject object, - jvmtiObjectReferenceCallback object_reference_callback, - const void* user_data); - - /* 110 : Iterate Over Reachable Objects */ - jvmtiError (JNICALL *IterateOverReachableObjects) (jvmtiEnv* env, - jvmtiHeapRootCallback heap_root_callback, - jvmtiStackReferenceCallback stack_ref_callback, - jvmtiObjectReferenceCallback object_ref_callback, - const void* user_data); - - /* 111 : Iterate Over Heap */ - jvmtiError (JNICALL *IterateOverHeap) (jvmtiEnv* env, - jvmtiHeapObjectFilter object_filter, - jvmtiHeapObjectCallback heap_object_callback, - const void* user_data); - - /* 112 : Iterate Over Instances Of Class */ - jvmtiError (JNICALL *IterateOverInstancesOfClass) (jvmtiEnv* env, - jclass klass, - jvmtiHeapObjectFilter object_filter, - jvmtiHeapObjectCallback heap_object_callback, - const void* user_data); - - /* 113 : RESERVED */ - void *reserved113; - - /* 114 : Get Objects With Tags */ - jvmtiError (JNICALL *GetObjectsWithTags) (jvmtiEnv* env, - jint tag_count, - const jlong* tags, - jint* count_ptr, - jobject** object_result_ptr, - jlong** tag_result_ptr); - - /* 115 : Follow References */ - jvmtiError (JNICALL *FollowReferences) (jvmtiEnv* env, - jint heap_filter, - jclass klass, - jobject initial_object, - const jvmtiHeapCallbacks* callbacks, - const void* user_data); - - /* 116 : Iterate Through Heap */ - jvmtiError (JNICALL *IterateThroughHeap) (jvmtiEnv* env, - jint heap_filter, - jclass klass, - const jvmtiHeapCallbacks* callbacks, - const void* user_data); - - /* 117 : RESERVED */ - void *reserved117; - - /* 118 : RESERVED */ - void *reserved118; - - /* 119 : RESERVED */ - void *reserved119; - - /* 120 : Set JNI Function Table */ - jvmtiError (JNICALL *SetJNIFunctionTable) (jvmtiEnv* env, - const jniNativeInterface* function_table); - - /* 121 : Get JNI Function Table */ - jvmtiError (JNICALL *GetJNIFunctionTable) (jvmtiEnv* env, - jniNativeInterface** function_table); - - /* 122 : Set Event Callbacks */ - jvmtiError (JNICALL *SetEventCallbacks) (jvmtiEnv* env, - const jvmtiEventCallbacks* callbacks, - jint size_of_callbacks); - - /* 123 : Generate Events */ - jvmtiError (JNICALL *GenerateEvents) (jvmtiEnv* env, - jvmtiEvent event_type); - - /* 124 : Get Extension Functions */ - jvmtiError (JNICALL *GetExtensionFunctions) (jvmtiEnv* env, - jint* extension_count_ptr, - jvmtiExtensionFunctionInfo** extensions); - - /* 125 : Get Extension Events */ - jvmtiError (JNICALL *GetExtensionEvents) (jvmtiEnv* env, - jint* extension_count_ptr, - jvmtiExtensionEventInfo** extensions); - - /* 126 : Set Extension Event Callback */ - jvmtiError (JNICALL *SetExtensionEventCallback) (jvmtiEnv* env, - jint extension_event_index, - jvmtiExtensionEvent callback); - - /* 127 : Dispose Environment */ - jvmtiError (JNICALL *DisposeEnvironment) (jvmtiEnv* env); - - /* 128 : Get Error Name */ - jvmtiError (JNICALL *GetErrorName) (jvmtiEnv* env, - jvmtiError error, - char** name_ptr); - - /* 129 : Get JLocation Format */ - jvmtiError (JNICALL *GetJLocationFormat) (jvmtiEnv* env, - jvmtiJlocationFormat* format_ptr); - - /* 130 : Get System Properties */ - jvmtiError (JNICALL *GetSystemProperties) (jvmtiEnv* env, - jint* count_ptr, - char*** property_ptr); - - /* 131 : Get System Property */ - jvmtiError (JNICALL *GetSystemProperty) (jvmtiEnv* env, - const char* property, - char** value_ptr); - - /* 132 : Set System Property */ - jvmtiError (JNICALL *SetSystemProperty) (jvmtiEnv* env, - const char* property, - const char* value_ptr); - - /* 133 : Get Phase */ - jvmtiError (JNICALL *GetPhase) (jvmtiEnv* env, - jvmtiPhase* phase_ptr); - - /* 134 : Get Current Thread CPU Timer Information */ - jvmtiError (JNICALL *GetCurrentThreadCpuTimerInfo) (jvmtiEnv* env, - jvmtiTimerInfo* info_ptr); - - /* 135 : Get Current Thread CPU Time */ - jvmtiError (JNICALL *GetCurrentThreadCpuTime) (jvmtiEnv* env, - jlong* nanos_ptr); - - /* 136 : Get Thread CPU Timer Information */ - jvmtiError (JNICALL *GetThreadCpuTimerInfo) (jvmtiEnv* env, - jvmtiTimerInfo* info_ptr); - - /* 137 : Get Thread CPU Time */ - jvmtiError (JNICALL *GetThreadCpuTime) (jvmtiEnv* env, - jthread thread, - jlong* nanos_ptr); - - /* 138 : Get Timer Information */ - jvmtiError (JNICALL *GetTimerInfo) (jvmtiEnv* env, - jvmtiTimerInfo* info_ptr); - - /* 139 : Get Time */ - jvmtiError (JNICALL *GetTime) (jvmtiEnv* env, - jlong* nanos_ptr); - - /* 140 : Get Potential Capabilities */ - jvmtiError (JNICALL *GetPotentialCapabilities) (jvmtiEnv* env, - jvmtiCapabilities* capabilities_ptr); - - /* 141 : RESERVED */ - void *reserved141; - - /* 142 : Add Capabilities */ - jvmtiError (JNICALL *AddCapabilities) (jvmtiEnv* env, - const jvmtiCapabilities* capabilities_ptr); - - /* 143 : Relinquish Capabilities */ - jvmtiError (JNICALL *RelinquishCapabilities) (jvmtiEnv* env, - const jvmtiCapabilities* capabilities_ptr); - - /* 144 : Get Available Processors */ - jvmtiError (JNICALL *GetAvailableProcessors) (jvmtiEnv* env, - jint* processor_count_ptr); - - /* 145 : Get Class Version Numbers */ - jvmtiError (JNICALL *GetClassVersionNumbers) (jvmtiEnv* env, - jclass klass, - jint* minor_version_ptr, - jint* major_version_ptr); - - /* 146 : Get Constant Pool */ - jvmtiError (JNICALL *GetConstantPool) (jvmtiEnv* env, - jclass klass, - jint* constant_pool_count_ptr, - jint* constant_pool_byte_count_ptr, - unsigned char** constant_pool_bytes_ptr); - - /* 147 : Get Environment Local Storage */ - jvmtiError (JNICALL *GetEnvironmentLocalStorage) (jvmtiEnv* env, - void** data_ptr); - - /* 148 : Set Environment Local Storage */ - jvmtiError (JNICALL *SetEnvironmentLocalStorage) (jvmtiEnv* env, - const void* data); - - /* 149 : Add To Bootstrap Class Loader Search */ - jvmtiError (JNICALL *AddToBootstrapClassLoaderSearch) (jvmtiEnv* env, - const char* segment); - - /* 150 : Set Verbose Flag */ - jvmtiError (JNICALL *SetVerboseFlag) (jvmtiEnv* env, - jvmtiVerboseFlag flag, - jboolean value); - - /* 151 : Add To System Class Loader Search */ - jvmtiError (JNICALL *AddToSystemClassLoaderSearch) (jvmtiEnv* env, - const char* segment); - - /* 152 : Retransform Classes */ - jvmtiError (JNICALL *RetransformClasses) (jvmtiEnv* env, - jint class_count, - const jclass* classes); - - /* 153 : Get Owned Monitor Stack Depth Info */ - jvmtiError (JNICALL *GetOwnedMonitorStackDepthInfo) (jvmtiEnv* env, - jthread thread, - jint* monitor_info_count_ptr, - jvmtiMonitorStackDepthInfo** monitor_info_ptr); - - /* 154 : Get Object Size */ - jvmtiError (JNICALL *GetObjectSize) (jvmtiEnv* env, - jobject object, - jlong* size_ptr); - - /* 155 : Get Local Instance */ - jvmtiError (JNICALL *GetLocalInstance) (jvmtiEnv* env, - jthread thread, - jint depth, - jobject* value_ptr); - -} jvmtiInterface_1; - -struct _jvmtiEnv { - const struct jvmtiInterface_1_ *functions; -#ifdef __cplusplus - - - jvmtiError Allocate(jlong size, - unsigned char** mem_ptr) { - return functions->Allocate(this, size, mem_ptr); - } - - jvmtiError Deallocate(unsigned char* mem) { - return functions->Deallocate(this, mem); - } - - jvmtiError GetThreadState(jthread thread, - jint* thread_state_ptr) { - return functions->GetThreadState(this, thread, thread_state_ptr); - } - - jvmtiError GetCurrentThread(jthread* thread_ptr) { - return functions->GetCurrentThread(this, thread_ptr); - } - - jvmtiError GetAllThreads(jint* threads_count_ptr, - jthread** threads_ptr) { - return functions->GetAllThreads(this, threads_count_ptr, threads_ptr); - } - - jvmtiError SuspendThread(jthread thread) { - return functions->SuspendThread(this, thread); - } - - jvmtiError SuspendThreadList(jint request_count, - const jthread* request_list, - jvmtiError* results) { - return functions->SuspendThreadList(this, request_count, request_list, results); - } - - jvmtiError ResumeThread(jthread thread) { - return functions->ResumeThread(this, thread); - } - - jvmtiError ResumeThreadList(jint request_count, - const jthread* request_list, - jvmtiError* results) { - return functions->ResumeThreadList(this, request_count, request_list, results); - } - - jvmtiError StopThread(jthread thread, - jobject exception) { - return functions->StopThread(this, thread, exception); - } - - jvmtiError InterruptThread(jthread thread) { - return functions->InterruptThread(this, thread); - } - - jvmtiError GetThreadInfo(jthread thread, - jvmtiThreadInfo* info_ptr) { - return functions->GetThreadInfo(this, thread, info_ptr); - } - - jvmtiError GetOwnedMonitorInfo(jthread thread, - jint* owned_monitor_count_ptr, - jobject** owned_monitors_ptr) { - return functions->GetOwnedMonitorInfo(this, thread, owned_monitor_count_ptr, owned_monitors_ptr); - } - - jvmtiError GetOwnedMonitorStackDepthInfo(jthread thread, - jint* monitor_info_count_ptr, - jvmtiMonitorStackDepthInfo** monitor_info_ptr) { - return functions->GetOwnedMonitorStackDepthInfo(this, thread, monitor_info_count_ptr, monitor_info_ptr); - } - - jvmtiError GetCurrentContendedMonitor(jthread thread, - jobject* monitor_ptr) { - return functions->GetCurrentContendedMonitor(this, thread, monitor_ptr); - } - - jvmtiError RunAgentThread(jthread thread, - jvmtiStartFunction proc, - const void* arg, - jint priority) { - return functions->RunAgentThread(this, thread, proc, arg, priority); - } - - jvmtiError SetThreadLocalStorage(jthread thread, - const void* data) { - return functions->SetThreadLocalStorage(this, thread, data); - } - - jvmtiError GetThreadLocalStorage(jthread thread, - void** data_ptr) { - return functions->GetThreadLocalStorage(this, thread, data_ptr); - } - - jvmtiError GetTopThreadGroups(jint* group_count_ptr, - jthreadGroup** groups_ptr) { - return functions->GetTopThreadGroups(this, group_count_ptr, groups_ptr); - } - - jvmtiError GetThreadGroupInfo(jthreadGroup group, - jvmtiThreadGroupInfo* info_ptr) { - return functions->GetThreadGroupInfo(this, group, info_ptr); - } - - jvmtiError GetThreadGroupChildren(jthreadGroup group, - jint* thread_count_ptr, - jthread** threads_ptr, - jint* group_count_ptr, - jthreadGroup** groups_ptr) { - return functions->GetThreadGroupChildren(this, group, thread_count_ptr, threads_ptr, group_count_ptr, groups_ptr); - } - - jvmtiError GetStackTrace(jthread thread, - jint start_depth, - jint max_frame_count, - jvmtiFrameInfo* frame_buffer, - jint* count_ptr) { - return functions->GetStackTrace(this, thread, start_depth, max_frame_count, frame_buffer, count_ptr); - } - - jvmtiError GetAllStackTraces(jint max_frame_count, - jvmtiStackInfo** stack_info_ptr, - jint* thread_count_ptr) { - return functions->GetAllStackTraces(this, max_frame_count, stack_info_ptr, thread_count_ptr); - } - - jvmtiError GetThreadListStackTraces(jint thread_count, - const jthread* thread_list, - jint max_frame_count, - jvmtiStackInfo** stack_info_ptr) { - return functions->GetThreadListStackTraces(this, thread_count, thread_list, max_frame_count, stack_info_ptr); - } - - jvmtiError GetFrameCount(jthread thread, - jint* count_ptr) { - return functions->GetFrameCount(this, thread, count_ptr); - } - - jvmtiError PopFrame(jthread thread) { - return functions->PopFrame(this, thread); - } - - jvmtiError GetFrameLocation(jthread thread, - jint depth, - jmethodID* method_ptr, - jlocation* location_ptr) { - return functions->GetFrameLocation(this, thread, depth, method_ptr, location_ptr); - } - - jvmtiError NotifyFramePop(jthread thread, - jint depth) { - return functions->NotifyFramePop(this, thread, depth); - } - - jvmtiError ForceEarlyReturnObject(jthread thread, - jobject value) { - return functions->ForceEarlyReturnObject(this, thread, value); - } - - jvmtiError ForceEarlyReturnInt(jthread thread, - jint value) { - return functions->ForceEarlyReturnInt(this, thread, value); - } - - jvmtiError ForceEarlyReturnLong(jthread thread, - jlong value) { - return functions->ForceEarlyReturnLong(this, thread, value); - } - - jvmtiError ForceEarlyReturnFloat(jthread thread, - jfloat value) { - return functions->ForceEarlyReturnFloat(this, thread, value); - } - - jvmtiError ForceEarlyReturnDouble(jthread thread, - jdouble value) { - return functions->ForceEarlyReturnDouble(this, thread, value); - } - - jvmtiError ForceEarlyReturnVoid(jthread thread) { - return functions->ForceEarlyReturnVoid(this, thread); - } - - jvmtiError FollowReferences(jint heap_filter, - jclass klass, - jobject initial_object, - const jvmtiHeapCallbacks* callbacks, - const void* user_data) { - return functions->FollowReferences(this, heap_filter, klass, initial_object, callbacks, user_data); - } - - jvmtiError IterateThroughHeap(jint heap_filter, - jclass klass, - const jvmtiHeapCallbacks* callbacks, - const void* user_data) { - return functions->IterateThroughHeap(this, heap_filter, klass, callbacks, user_data); - } - - jvmtiError GetTag(jobject object, - jlong* tag_ptr) { - return functions->GetTag(this, object, tag_ptr); - } - - jvmtiError SetTag(jobject object, - jlong tag) { - return functions->SetTag(this, object, tag); - } - - jvmtiError GetObjectsWithTags(jint tag_count, - const jlong* tags, - jint* count_ptr, - jobject** object_result_ptr, - jlong** tag_result_ptr) { - return functions->GetObjectsWithTags(this, tag_count, tags, count_ptr, object_result_ptr, tag_result_ptr); - } - - jvmtiError ForceGarbageCollection() { - return functions->ForceGarbageCollection(this); - } - - jvmtiError IterateOverObjectsReachableFromObject(jobject object, - jvmtiObjectReferenceCallback object_reference_callback, - const void* user_data) { - return functions->IterateOverObjectsReachableFromObject(this, object, object_reference_callback, user_data); - } - - jvmtiError IterateOverReachableObjects(jvmtiHeapRootCallback heap_root_callback, - jvmtiStackReferenceCallback stack_ref_callback, - jvmtiObjectReferenceCallback object_ref_callback, - const void* user_data) { - return functions->IterateOverReachableObjects(this, heap_root_callback, stack_ref_callback, object_ref_callback, user_data); - } - - jvmtiError IterateOverHeap(jvmtiHeapObjectFilter object_filter, - jvmtiHeapObjectCallback heap_object_callback, - const void* user_data) { - return functions->IterateOverHeap(this, object_filter, heap_object_callback, user_data); - } - - jvmtiError IterateOverInstancesOfClass(jclass klass, - jvmtiHeapObjectFilter object_filter, - jvmtiHeapObjectCallback heap_object_callback, - const void* user_data) { - return functions->IterateOverInstancesOfClass(this, klass, object_filter, heap_object_callback, user_data); - } - - jvmtiError GetLocalObject(jthread thread, - jint depth, - jint slot, - jobject* value_ptr) { - return functions->GetLocalObject(this, thread, depth, slot, value_ptr); - } - - jvmtiError GetLocalInstance(jthread thread, - jint depth, - jobject* value_ptr) { - return functions->GetLocalInstance(this, thread, depth, value_ptr); - } - - jvmtiError GetLocalInt(jthread thread, - jint depth, - jint slot, - jint* value_ptr) { - return functions->GetLocalInt(this, thread, depth, slot, value_ptr); - } - - jvmtiError GetLocalLong(jthread thread, - jint depth, - jint slot, - jlong* value_ptr) { - return functions->GetLocalLong(this, thread, depth, slot, value_ptr); - } - - jvmtiError GetLocalFloat(jthread thread, - jint depth, - jint slot, - jfloat* value_ptr) { - return functions->GetLocalFloat(this, thread, depth, slot, value_ptr); - } - - jvmtiError GetLocalDouble(jthread thread, - jint depth, - jint slot, - jdouble* value_ptr) { - return functions->GetLocalDouble(this, thread, depth, slot, value_ptr); - } - - jvmtiError SetLocalObject(jthread thread, - jint depth, - jint slot, - jobject value) { - return functions->SetLocalObject(this, thread, depth, slot, value); - } - - jvmtiError SetLocalInt(jthread thread, - jint depth, - jint slot, - jint value) { - return functions->SetLocalInt(this, thread, depth, slot, value); - } - - jvmtiError SetLocalLong(jthread thread, - jint depth, - jint slot, - jlong value) { - return functions->SetLocalLong(this, thread, depth, slot, value); - } - - jvmtiError SetLocalFloat(jthread thread, - jint depth, - jint slot, - jfloat value) { - return functions->SetLocalFloat(this, thread, depth, slot, value); - } - - jvmtiError SetLocalDouble(jthread thread, - jint depth, - jint slot, - jdouble value) { - return functions->SetLocalDouble(this, thread, depth, slot, value); - } - - jvmtiError SetBreakpoint(jmethodID method, - jlocation location) { - return functions->SetBreakpoint(this, method, location); - } - - jvmtiError ClearBreakpoint(jmethodID method, - jlocation location) { - return functions->ClearBreakpoint(this, method, location); - } - - jvmtiError SetFieldAccessWatch(jclass klass, - jfieldID field) { - return functions->SetFieldAccessWatch(this, klass, field); - } - - jvmtiError ClearFieldAccessWatch(jclass klass, - jfieldID field) { - return functions->ClearFieldAccessWatch(this, klass, field); - } - - jvmtiError SetFieldModificationWatch(jclass klass, - jfieldID field) { - return functions->SetFieldModificationWatch(this, klass, field); - } - - jvmtiError ClearFieldModificationWatch(jclass klass, - jfieldID field) { - return functions->ClearFieldModificationWatch(this, klass, field); - } - - jvmtiError GetAllModules(jint* module_count_ptr, - jobject** modules_ptr) { - return functions->GetAllModules(this, module_count_ptr, modules_ptr); - } - - jvmtiError GetNamedModule(jobject class_loader, - const char* package_name, - jobject* module_ptr) { - return functions->GetNamedModule(this, class_loader, package_name, module_ptr); - } - - jvmtiError GetLoadedClasses(jint* class_count_ptr, - jclass** classes_ptr) { - return functions->GetLoadedClasses(this, class_count_ptr, classes_ptr); - } - - jvmtiError GetClassLoaderClasses(jobject initiating_loader, - jint* class_count_ptr, - jclass** classes_ptr) { - return functions->GetClassLoaderClasses(this, initiating_loader, class_count_ptr, classes_ptr); - } - - jvmtiError GetClassSignature(jclass klass, - char** signature_ptr, - char** generic_ptr) { - return functions->GetClassSignature(this, klass, signature_ptr, generic_ptr); - } - - jvmtiError GetClassStatus(jclass klass, - jint* status_ptr) { - return functions->GetClassStatus(this, klass, status_ptr); - } - - jvmtiError GetSourceFileName(jclass klass, - char** source_name_ptr) { - return functions->GetSourceFileName(this, klass, source_name_ptr); - } - - jvmtiError GetClassModifiers(jclass klass, - jint* modifiers_ptr) { - return functions->GetClassModifiers(this, klass, modifiers_ptr); - } - - jvmtiError GetClassMethods(jclass klass, - jint* method_count_ptr, - jmethodID** methods_ptr) { - return functions->GetClassMethods(this, klass, method_count_ptr, methods_ptr); - } - - jvmtiError GetClassFields(jclass klass, - jint* field_count_ptr, - jfieldID** fields_ptr) { - return functions->GetClassFields(this, klass, field_count_ptr, fields_ptr); - } - - jvmtiError GetImplementedInterfaces(jclass klass, - jint* interface_count_ptr, - jclass** interfaces_ptr) { - return functions->GetImplementedInterfaces(this, klass, interface_count_ptr, interfaces_ptr); - } - - jvmtiError GetClassVersionNumbers(jclass klass, - jint* minor_version_ptr, - jint* major_version_ptr) { - return functions->GetClassVersionNumbers(this, klass, minor_version_ptr, major_version_ptr); - } - - jvmtiError GetConstantPool(jclass klass, - jint* constant_pool_count_ptr, - jint* constant_pool_byte_count_ptr, - unsigned char** constant_pool_bytes_ptr) { - return functions->GetConstantPool(this, klass, constant_pool_count_ptr, constant_pool_byte_count_ptr, constant_pool_bytes_ptr); - } - - jvmtiError IsInterface(jclass klass, - jboolean* is_interface_ptr) { - return functions->IsInterface(this, klass, is_interface_ptr); - } - - jvmtiError IsArrayClass(jclass klass, - jboolean* is_array_class_ptr) { - return functions->IsArrayClass(this, klass, is_array_class_ptr); - } - - jvmtiError IsModifiableClass(jclass klass, - jboolean* is_modifiable_class_ptr) { - return functions->IsModifiableClass(this, klass, is_modifiable_class_ptr); - } - - jvmtiError GetClassLoader(jclass klass, - jobject* classloader_ptr) { - return functions->GetClassLoader(this, klass, classloader_ptr); - } - - jvmtiError GetSourceDebugExtension(jclass klass, - char** source_debug_extension_ptr) { - return functions->GetSourceDebugExtension(this, klass, source_debug_extension_ptr); - } - - jvmtiError RetransformClasses(jint class_count, - const jclass* classes) { - return functions->RetransformClasses(this, class_count, classes); - } - - jvmtiError RedefineClasses(jint class_count, - const jvmtiClassDefinition* class_definitions) { - return functions->RedefineClasses(this, class_count, class_definitions); - } - - jvmtiError GetObjectSize(jobject object, - jlong* size_ptr) { - return functions->GetObjectSize(this, object, size_ptr); - } - - jvmtiError GetObjectHashCode(jobject object, - jint* hash_code_ptr) { - return functions->GetObjectHashCode(this, object, hash_code_ptr); - } - - jvmtiError GetObjectMonitorUsage(jobject object, - jvmtiMonitorUsage* info_ptr) { - return functions->GetObjectMonitorUsage(this, object, info_ptr); - } - - jvmtiError GetFieldName(jclass klass, - jfieldID field, - char** name_ptr, - char** signature_ptr, - char** generic_ptr) { - return functions->GetFieldName(this, klass, field, name_ptr, signature_ptr, generic_ptr); - } - - jvmtiError GetFieldDeclaringClass(jclass klass, - jfieldID field, - jclass* declaring_class_ptr) { - return functions->GetFieldDeclaringClass(this, klass, field, declaring_class_ptr); - } - - jvmtiError GetFieldModifiers(jclass klass, - jfieldID field, - jint* modifiers_ptr) { - return functions->GetFieldModifiers(this, klass, field, modifiers_ptr); - } - - jvmtiError IsFieldSynthetic(jclass klass, - jfieldID field, - jboolean* is_synthetic_ptr) { - return functions->IsFieldSynthetic(this, klass, field, is_synthetic_ptr); - } - - jvmtiError GetMethodName(jmethodID method, - char** name_ptr, - char** signature_ptr, - char** generic_ptr) { - return functions->GetMethodName(this, method, name_ptr, signature_ptr, generic_ptr); - } - - jvmtiError GetMethodDeclaringClass(jmethodID method, - jclass* declaring_class_ptr) { - return functions->GetMethodDeclaringClass(this, method, declaring_class_ptr); - } - - jvmtiError GetMethodModifiers(jmethodID method, - jint* modifiers_ptr) { - return functions->GetMethodModifiers(this, method, modifiers_ptr); - } - - jvmtiError GetMaxLocals(jmethodID method, - jint* max_ptr) { - return functions->GetMaxLocals(this, method, max_ptr); - } - - jvmtiError GetArgumentsSize(jmethodID method, - jint* size_ptr) { - return functions->GetArgumentsSize(this, method, size_ptr); - } - - jvmtiError GetLineNumberTable(jmethodID method, - jint* entry_count_ptr, - jvmtiLineNumberEntry** table_ptr) { - return functions->GetLineNumberTable(this, method, entry_count_ptr, table_ptr); - } - - jvmtiError GetMethodLocation(jmethodID method, - jlocation* start_location_ptr, - jlocation* end_location_ptr) { - return functions->GetMethodLocation(this, method, start_location_ptr, end_location_ptr); - } - - jvmtiError GetLocalVariableTable(jmethodID method, - jint* entry_count_ptr, - jvmtiLocalVariableEntry** table_ptr) { - return functions->GetLocalVariableTable(this, method, entry_count_ptr, table_ptr); - } - - jvmtiError GetBytecodes(jmethodID method, - jint* bytecode_count_ptr, - unsigned char** bytecodes_ptr) { - return functions->GetBytecodes(this, method, bytecode_count_ptr, bytecodes_ptr); - } - - jvmtiError IsMethodNative(jmethodID method, - jboolean* is_native_ptr) { - return functions->IsMethodNative(this, method, is_native_ptr); - } - - jvmtiError IsMethodSynthetic(jmethodID method, - jboolean* is_synthetic_ptr) { - return functions->IsMethodSynthetic(this, method, is_synthetic_ptr); - } - - jvmtiError IsMethodObsolete(jmethodID method, - jboolean* is_obsolete_ptr) { - return functions->IsMethodObsolete(this, method, is_obsolete_ptr); - } - - jvmtiError SetNativeMethodPrefix(const char* prefix) { - return functions->SetNativeMethodPrefix(this, prefix); - } - - jvmtiError SetNativeMethodPrefixes(jint prefix_count, - char** prefixes) { - return functions->SetNativeMethodPrefixes(this, prefix_count, prefixes); - } - - jvmtiError CreateRawMonitor(const char* name, - jrawMonitorID* monitor_ptr) { - return functions->CreateRawMonitor(this, name, monitor_ptr); - } - - jvmtiError DestroyRawMonitor(jrawMonitorID monitor) { - return functions->DestroyRawMonitor(this, monitor); - } - - jvmtiError RawMonitorEnter(jrawMonitorID monitor) { - return functions->RawMonitorEnter(this, monitor); - } - - jvmtiError RawMonitorExit(jrawMonitorID monitor) { - return functions->RawMonitorExit(this, monitor); - } - - jvmtiError RawMonitorWait(jrawMonitorID monitor, - jlong millis) { - return functions->RawMonitorWait(this, monitor, millis); - } - - jvmtiError RawMonitorNotify(jrawMonitorID monitor) { - return functions->RawMonitorNotify(this, monitor); - } - - jvmtiError RawMonitorNotifyAll(jrawMonitorID monitor) { - return functions->RawMonitorNotifyAll(this, monitor); - } - - jvmtiError SetJNIFunctionTable(const jniNativeInterface* function_table) { - return functions->SetJNIFunctionTable(this, function_table); - } - - jvmtiError GetJNIFunctionTable(jniNativeInterface** function_table) { - return functions->GetJNIFunctionTable(this, function_table); - } - - jvmtiError SetEventCallbacks(const jvmtiEventCallbacks* callbacks, - jint size_of_callbacks) { - return functions->SetEventCallbacks(this, callbacks, size_of_callbacks); - } - - jvmtiError SetEventNotificationMode(jvmtiEventMode mode, - jvmtiEvent event_type, - jthread event_thread, - ...) { - return functions->SetEventNotificationMode(this, mode, event_type, event_thread); - } - - jvmtiError GenerateEvents(jvmtiEvent event_type) { - return functions->GenerateEvents(this, event_type); - } - - jvmtiError GetExtensionFunctions(jint* extension_count_ptr, - jvmtiExtensionFunctionInfo** extensions) { - return functions->GetExtensionFunctions(this, extension_count_ptr, extensions); - } - - jvmtiError GetExtensionEvents(jint* extension_count_ptr, - jvmtiExtensionEventInfo** extensions) { - return functions->GetExtensionEvents(this, extension_count_ptr, extensions); - } - - jvmtiError SetExtensionEventCallback(jint extension_event_index, - jvmtiExtensionEvent callback) { - return functions->SetExtensionEventCallback(this, extension_event_index, callback); - } - - jvmtiError GetPotentialCapabilities(jvmtiCapabilities* capabilities_ptr) { - return functions->GetPotentialCapabilities(this, capabilities_ptr); - } - - jvmtiError AddCapabilities(const jvmtiCapabilities* capabilities_ptr) { - return functions->AddCapabilities(this, capabilities_ptr); - } - - jvmtiError RelinquishCapabilities(const jvmtiCapabilities* capabilities_ptr) { - return functions->RelinquishCapabilities(this, capabilities_ptr); - } - - jvmtiError GetCapabilities(jvmtiCapabilities* capabilities_ptr) { - return functions->GetCapabilities(this, capabilities_ptr); - } - - jvmtiError GetCurrentThreadCpuTimerInfo(jvmtiTimerInfo* info_ptr) { - return functions->GetCurrentThreadCpuTimerInfo(this, info_ptr); - } - - jvmtiError GetCurrentThreadCpuTime(jlong* nanos_ptr) { - return functions->GetCurrentThreadCpuTime(this, nanos_ptr); - } - - jvmtiError GetThreadCpuTimerInfo(jvmtiTimerInfo* info_ptr) { - return functions->GetThreadCpuTimerInfo(this, info_ptr); - } - - jvmtiError GetThreadCpuTime(jthread thread, - jlong* nanos_ptr) { - return functions->GetThreadCpuTime(this, thread, nanos_ptr); - } - - jvmtiError GetTimerInfo(jvmtiTimerInfo* info_ptr) { - return functions->GetTimerInfo(this, info_ptr); - } - - jvmtiError GetTime(jlong* nanos_ptr) { - return functions->GetTime(this, nanos_ptr); - } - - jvmtiError GetAvailableProcessors(jint* processor_count_ptr) { - return functions->GetAvailableProcessors(this, processor_count_ptr); - } - - jvmtiError AddToBootstrapClassLoaderSearch(const char* segment) { - return functions->AddToBootstrapClassLoaderSearch(this, segment); - } - - jvmtiError AddToSystemClassLoaderSearch(const char* segment) { - return functions->AddToSystemClassLoaderSearch(this, segment); - } - - jvmtiError GetSystemProperties(jint* count_ptr, - char*** property_ptr) { - return functions->GetSystemProperties(this, count_ptr, property_ptr); - } - - jvmtiError GetSystemProperty(const char* property, - char** value_ptr) { - return functions->GetSystemProperty(this, property, value_ptr); - } - - jvmtiError SetSystemProperty(const char* property, - const char* value_ptr) { - return functions->SetSystemProperty(this, property, value_ptr); - } - - jvmtiError GetPhase(jvmtiPhase* phase_ptr) { - return functions->GetPhase(this, phase_ptr); - } - - jvmtiError DisposeEnvironment() { - return functions->DisposeEnvironment(this); - } - - jvmtiError SetEnvironmentLocalStorage(const void* data) { - return functions->SetEnvironmentLocalStorage(this, data); - } - - jvmtiError GetEnvironmentLocalStorage(void** data_ptr) { - return functions->GetEnvironmentLocalStorage(this, data_ptr); - } - - jvmtiError GetVersionNumber(jint* version_ptr) { - return functions->GetVersionNumber(this, version_ptr); - } - - jvmtiError GetErrorName(jvmtiError error, - char** name_ptr) { - return functions->GetErrorName(this, error, name_ptr); - } - - jvmtiError SetVerboseFlag(jvmtiVerboseFlag flag, - jboolean value) { - return functions->SetVerboseFlag(this, flag, value); - } - - jvmtiError GetJLocationFormat(jvmtiJlocationFormat* format_ptr) { - return functions->GetJLocationFormat(this, format_ptr); - } - -#endif /* __cplusplus */ -}; - - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ - -#endif /* !_JAVA_JVMTI_H_ */ diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/native/launcher/defines.h --- a/jdk/src/java.base/share/native/launcher/defines.h Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/native/launcher/defines.h Fri Nov 11 16:44:36 2016 +0100 @@ -51,16 +51,6 @@ static char* const_progname = NULL; #endif static const char* const_jargs[] = JAVA_ARGS; -/* - * ApplicationHome is prepended to each of these entries; the resulting - * strings are concatenated (separated by PATH_SEPARATOR) and used as the - * value of -cp option to the launcher. - */ -#ifndef APP_CLASSPATH -static const char* const_appclasspath[] = { NULL }; -#else -static const char* const_appclasspath[] = APP_CLASSPATH; -#endif /* APP_CLASSPATH */ #else /* !JAVA_ARGS */ #define HAS_JAVA_ARGS JNI_FALSE static const char* const_progname = "java"; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/native/launcher/main.c --- a/jdk/src/java.base/share/native/launcher/main.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/native/launcher/main.c Fri Nov 11 16:44:36 2016 +0100 @@ -83,7 +83,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow) { - int margc, appclassc; + int margc; char** margv; const jboolean const_javaw = JNI_TRUE; @@ -93,7 +93,7 @@ int main(int argc, char **argv) { - int margc, appclassc; + int margc; char** margv; const jboolean const_javaw = JNI_FALSE; #endif /* JAVAW */ @@ -148,14 +148,9 @@ margv = args->elements; } #endif /* WIN32 */ - if (const_appclasspath[0] == NULL) { - appclassc = 0; - } else { - appclassc = sizeof(const_appclasspath) / sizeof(char *); - } return JLI_Launch(margc, margv, sizeof(const_jargs) / sizeof(char *), const_jargs, - appclassc, const_appclasspath, + 0, NULL, VERSION_STRING, DOT_VERSION, (const_progname != NULL) ? const_progname : *margv, diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/native/libjava/StackFrameInfo.c --- a/jdk/src/java.base/share/native/libjava/StackFrameInfo.c Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * Implementation of class StackFrameInfo - */ - -#include -#include - -#include "jni.h" -#include "jvm.h" - -#include "java_lang_StackFrameInfo.h" - - -/* - * Class: java_lang_StackFrameInfo - * Method: toStackTraceElement0 - * Signature: (Ljava/lang/StackTraceElement;)V - */ -JNIEXPORT void JNICALL Java_java_lang_StackFrameInfo_toStackTraceElement0 - (JNIEnv *env, jobject stackframeinfo, jobject stacktraceinfo) { - JVM_ToStackTraceElement(env, stackframeinfo, stacktraceinfo); -} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/native/libjava/StackTraceElement.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/native/libjava/StackTraceElement.c Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include + +#include "jni.h" +#include "jvm.h" + +#include "java_lang_StackTraceElement.h" + +JNIEXPORT void JNICALL Java_java_lang_StackTraceElement_initStackTraceElement + (JNIEnv *env, jobject dummy, jobject element, jobject stackframeinfo) { + JVM_InitStackTraceElement(env, element, stackframeinfo); +} + +JNIEXPORT void JNICALL Java_java_lang_StackTraceElement_initStackTraceElements + (JNIEnv *env, jobject dummy, jobjectArray elements, jobject throwable) +{ + JVM_InitStackTraceElementArray(env, elements, throwable); +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/native/libjava/Throwable.c --- a/jdk/src/java.base/share/native/libjava/Throwable.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/native/libjava/Throwable.c Fri Nov 11 16:44:36 2016 +0100 @@ -49,10 +49,3 @@ JVM_FillInStackTrace(env, throwable); return throwable; } - -JNIEXPORT void JNICALL -Java_java_lang_Throwable_getStackTraceElements(JNIEnv *env, - jobject throwable, jobjectArray elements) -{ - JVM_GetStackTraceElements(env, throwable, elements); -} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/native/libjli/java.c --- a/jdk/src/java.base/share/native/libjli/java.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/native/libjli/java.c Fri Nov 11 16:44:36 2016 +0100 @@ -1664,19 +1664,21 @@ AddOption(apphome, NULL); /* How big is the application's classpath? */ - size = 40; /* 40: "-Djava.class.path=" */ - for (i = 0; i < cpathc; i++) { - size += (int)JLI_StrLen(home) + (int)JLI_StrLen(cpathv[i]) + 1; /* 1: separator */ + if (cpathc > 0) { + size = 40; /* 40: "-Djava.class.path=" */ + for (i = 0; i < cpathc; i++) { + size += (int)JLI_StrLen(home) + (int)JLI_StrLen(cpathv[i]) + 1; /* 1: separator */ + } + appcp = (char *)JLI_MemAlloc(size + 1); + JLI_StrCpy(appcp, "-Djava.class.path="); + for (i = 0; i < cpathc; i++) { + JLI_StrCat(appcp, home); /* c:\program files\myapp */ + JLI_StrCat(appcp, cpathv[i]); /* \lib\myapp.jar */ + JLI_StrCat(appcp, separator); /* ; */ + } + appcp[JLI_StrLen(appcp)-1] = '\0'; /* remove trailing path separator */ + AddOption(appcp, NULL); } - appcp = (char *)JLI_MemAlloc(size + 1); - JLI_StrCpy(appcp, "-Djava.class.path="); - for (i = 0; i < cpathc; i++) { - JLI_StrCat(appcp, home); /* c:\program files\myapp */ - JLI_StrCat(appcp, cpathv[i]); /* \lib\myapp.jar */ - JLI_StrCat(appcp, separator); /* ; */ - } - appcp[JLI_StrLen(appcp)-1] = '\0'; /* remove trailing path separator */ - AddOption(appcp, NULL); return JNI_TRUE; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/native/libnet/net_util.c --- a/jdk/src/java.base/share/native/libnet/net_util.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/native/libnet/net_util.c Fri Nov 11 16:44:36 2016 +0100 @@ -23,20 +23,19 @@ * questions. */ -#include "jni.h" -#include "jvm.h" -#include "jni_util.h" #include "net_util.h" -int IPv6_supported() ; -int reuseport_supported() ; +#include "java_net_InetAddress.h" + +int IPv6_supported(); +int reuseport_supported(); static int IPv6_available; static int REUSEPORT_available; JNIEXPORT jint JNICALL ipv6_available() { - return IPv6_available ; + return IPv6_available; } JNIEXPORT jint JNICALL reuseport_available() @@ -204,13 +203,8 @@ JNIEXPORT jobject JNICALL NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { jobject iaObj; -#ifdef AF_INET6 if (him->sa_family == AF_INET6) { -#ifdef WIN32 - struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; -#else struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; -#endif jbyte *caddr = (jbyte *)&(him6->sin6_addr); if (NET_IsIPv4Mapped(caddr)) { int address; @@ -218,7 +212,7 @@ CHECK_NULL_RETURN(iaObj, NULL); address = NET_IPv4MappedToIPv4(caddr); setInetAddress_addr(env, iaObj, address); - setInetAddress_family(env, iaObj, IPv4); + setInetAddress_family(env, iaObj, java_net_InetAddress_IPv4); } else { jint scope; jboolean ret; @@ -227,21 +221,19 @@ ret = setInet6Address_ipaddress(env, iaObj, (char *)&(him6->sin6_addr)); if (ret == JNI_FALSE) return NULL; - setInetAddress_family(env, iaObj, IPv6); + setInetAddress_family(env, iaObj, java_net_InetAddress_IPv6); scope = getScopeID(him); setInet6Address_scopeid(env, iaObj, scope); } *port = ntohs(him6->sin6_port); - } else -#endif /* AF_INET6 */ - { - struct sockaddr_in *him4 = (struct sockaddr_in *)him; - iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); - CHECK_NULL_RETURN(iaObj, NULL); - setInetAddress_family(env, iaObj, IPv4); - setInetAddress_addr(env, iaObj, ntohl(him4->sin_addr.s_addr)); - *port = ntohs(him4->sin_port); - } + } else { + struct sockaddr_in *him4 = (struct sockaddr_in *)him; + iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); + CHECK_NULL_RETURN(iaObj, NULL); + setInetAddress_family(env, iaObj, java_net_InetAddress_IPv4); + setInetAddress_addr(env, iaObj, ntohl(him4->sin_addr.s_addr)); + *port = ntohs(him4->sin_port); + } return iaObj; } @@ -250,14 +242,10 @@ { jint family = AF_INET; -#ifdef AF_INET6 - family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6; + family = getInetAddress_family(env, iaObj) == java_net_InetAddress_IPv4 ? + AF_INET : AF_INET6; if (him->sa_family == AF_INET6) { -#ifdef WIN32 - struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; -#else struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; -#endif jbyte *caddrNew = (jbyte *)&(him6->sin6_addr); if (NET_IsIPv4Mapped(caddrNew)) { int addrNew; @@ -287,22 +275,20 @@ return JNI_FALSE; } } - } else -#endif /* AF_INET6 */ - { - struct sockaddr_in *him4 = (struct sockaddr_in *)him; - int addrNew, addrCur; - if (family != AF_INET) { - return JNI_FALSE; - } - addrNew = ntohl(him4->sin_addr.s_addr); - addrCur = getInetAddress_addr(env, iaObj); - if (addrNew == addrCur) { - return JNI_TRUE; - } else { - return JNI_FALSE; - } + } else { + struct sockaddr_in *him4 = (struct sockaddr_in *)him; + int addrNew, addrCur; + if (family != AF_INET) { + return JNI_FALSE; } + addrNew = ntohl(him4->sin_addr.s_addr); + addrCur = getInetAddress_addr(env, iaObj); + if (addrNew == addrCur) { + return JNI_TRUE; + } else { + return JNI_FALSE; + } + } } unsigned short diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/share/native/libnet/net_util.h --- a/jdk/src/java.base/share/native/libnet/net_util.h Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/share/native/libnet/net_util.h Fri Nov 11 16:44:36 2016 +0100 @@ -36,12 +36,6 @@ #define MAX_PACKET_LEN 65536 -#define IPv4 1 -#define IPv6 2 - -#define NET_ERROR(env, ex, msg) \ -{ if (!(*env)->ExceptionOccurred(env)) JNU_ThrowByName(env, ex, msg); } - #define NET_WAIT_READ 0x01 #define NET_WAIT_WRITE 0x02 #define NET_WAIT_CONNECT 0x04 @@ -127,45 +121,43 @@ JNIEXPORT void JNICALL Java_java_net_NetworkInterface_init(JNIEnv *env, jclass cls); JNIEXPORT void JNICALL NET_ThrowNew(JNIEnv *env, int errorNum, char *msg); + int NET_GetError(); void NET_ThrowCurrent(JNIEnv *env, char *msg); jfieldID NET_GetFileDescriptorID(JNIEnv *env); -JNIEXPORT jint JNICALL ipv6_available() ; +JNIEXPORT jint JNICALL ipv6_available(); -JNIEXPORT jint JNICALL reuseport_available() ; +JNIEXPORT jint JNICALL reuseport_available(); JNIEXPORT int JNICALL -NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him, int *len, jboolean v4MappedAddress); +NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, + struct sockaddr *him, int *len, + jboolean v4MappedAddress); JNIEXPORT jobject JNICALL NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port); void platformInit(); + void parseExclusiveBindProperty(JNIEnv *env); -void -NET_SetTrafficClass(struct sockaddr *him, int trafficClass); +void NET_SetTrafficClass(struct sockaddr *him, int trafficClass); -JNIEXPORT jint JNICALL -NET_GetPortFromSockaddr(struct sockaddr *him); +JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(struct sockaddr *him); JNIEXPORT jint JNICALL NET_SockaddrEqualsInetAddress(JNIEnv *env,struct sockaddr *him, jobject iaObj); -int -NET_IsIPv4Mapped(jbyte* caddr); +int NET_IsIPv4Mapped(jbyte* caddr); -int -NET_IPv4MappedToIPv4(jbyte* caddr); +int NET_IPv4MappedToIPv4(jbyte* caddr); -int -NET_IsEqual(jbyte* caddr1, jbyte* caddr2); +int NET_IsEqual(jbyte* caddr1, jbyte* caddr2); -int -NET_IsZeroAddr(jbyte* caddr); +int NET_IsZeroAddr(jbyte* caddr); /* Socket operations * @@ -191,9 +183,9 @@ JNIEXPORT jint JNICALL NET_EnableFastTcpLoopback(int fd); -int getScopeID (struct sockaddr *); +int getScopeID(struct sockaddr *); -int cmpScopeID (unsigned int, struct sockaddr *); +int cmpScopeID(unsigned int, struct sockaddr *); unsigned short in_cksum(unsigned short *addr, int len); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/unix/conf/s390x/jvm.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/unix/conf/s390x/jvm.cfg Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,34 @@ +# Copyright (c) 2011, 2016, Oracle and/or its affiliates. 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.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=" option, but that too is unsupported +# and may not be available in a future release. +# +-server KNOWN +-client IGNORE diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/unix/native/libnet/Inet4AddressImpl.c --- a/jdk/src/java.base/unix/native/libnet/Inet4AddressImpl.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/unix/native/libnet/Inet4AddressImpl.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,27 +22,17 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - +#include #include -#include #include -#include +#include #include -#include #include #include -#include +#include #include -#include -#include +#include -#ifdef _ALLBSD_SOURCE -#include -#include -#endif - -#include "jvm.h" -#include "jni_util.h" #include "net_util.h" #include "java_net_Inet4AddressImpl.h" @@ -293,13 +283,12 @@ addr |= ((caddr[2] <<8) & 0xff00); addr |= (caddr[3] & 0xff); memset((char *) &him4, 0, sizeof(him4)); - him4.sin_addr.s_addr = (uint32_t) htonl(addr); + him4.sin_addr.s_addr = htonl(addr); him4.sin_family = AF_INET; sa = (struct sockaddr *) &him4; len = sizeof(him4); - error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0, - NI_NAMEREQD); + error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0, NI_NAMEREQD); if (!error) { ret = (*env)->NewStringUTF(env, host); @@ -443,7 +432,7 @@ if (!skip) { struct addrinfo *next - = (struct addrinfo*) malloc(sizeof(struct addrinfo)); + = (struct addrinfo *)malloc(sizeof(struct addrinfo)); if (!next) { JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); ret = NULL; @@ -528,13 +517,12 @@ addr |= ((caddr[2] <<8) & 0xff00); addr |= (caddr[3] & 0xff); memset((void *) &him4, 0, sizeof(him4)); - him4.sin_addr.s_addr = (uint32_t) htonl(addr); + him4.sin_addr.s_addr = htonl(addr); him4.sin_family = AF_INET; sa = (struct sockaddr *) &him4; len = sizeof(him4); - error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0, - NI_NAMEREQD); + error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0, NI_NAMEREQD); if (!error) { ret = (*env)->NewStringUTF(env, host); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/unix/native/libnet/Inet6AddressImpl.c --- a/jdk/src/java.base/unix/native/libnet/Inet6AddressImpl.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/unix/native/libnet/Inet6AddressImpl.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,29 +22,21 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - +#include #include +#include +#include #include #include -#include #include -#include -#include -#include -#include -#include -#ifdef MACOSX +#include + +#if defined(_ALLBSD_SOURCE) #include #include -#include /* gethostname */ #endif -#include "jvm.h" -#include "jni_util.h" #include "net_util.h" -#ifndef IPV6_DEFS_H -#include -#endif #include "java_net_Inet4AddressImpl.h" #include "java_net_Inet6AddressImpl.h" @@ -80,7 +72,7 @@ hostname[NI_MAXHOST] = '\0'; } -#if defined(__solaris__) && defined(AF_INET6) +#if defined(__solaris__) if (ret == 0) { /* Solaris doesn't want to give us a fully qualified domain name. * We do a reverse lookup to try and get one. This works @@ -259,9 +251,7 @@ int retLen = 0; int getaddrinfo_error=0; -#ifdef AF_INET6 struct addrinfo hints, *res, *resNew = NULL; -#endif /* AF_INET6 */ initInetAddressIDs(env); JNU_CHECK_EXCEPTION_RETURN(env, NULL); @@ -273,7 +263,6 @@ hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE); CHECK_NULL_RETURN(hostname, NULL); -#ifdef AF_INET6 /* Try once, with our static buffer. */ memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; @@ -467,7 +456,6 @@ } freeaddrinfo(res); -#endif /* AF_INET6 */ return ret; } @@ -483,7 +471,6 @@ jstring ret = NULL; -#ifdef AF_INET6 char host[NI_MAXHOST+1]; int error = 0; int len = 0; @@ -504,30 +491,28 @@ addr |= ((caddr[2] <<8) & 0xff00); addr |= (caddr[3] & 0xff); memset((void *) &him4, 0, sizeof(him4)); - him4.sin_addr.s_addr = (uint32_t) htonl(addr); + him4.sin_addr.s_addr = htonl(addr); him4.sin_family = AF_INET; - sa = (struct sockaddr *) &him4; + sa = (struct sockaddr *)&him4; len = sizeof(him4); } else { /* * For IPv6 address construct a sockaddr_in6 structure. */ (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr); - memset((void *) &him6, 0, sizeof(him6)); - memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) ); + memset((void *)&him6, 0, sizeof(him6)); + memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr)); him6.sin6_family = AF_INET6; - sa = (struct sockaddr *) &him6 ; - len = sizeof(him6) ; + sa = (struct sockaddr *)&him6; + len = sizeof(him6); } - error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0, - NI_NAMEREQD); + error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0, NI_NAMEREQD); if (!error) { ret = (*env)->NewStringUTF(env, host); CHECK_NULL_RETURN(ret, NULL); } -#endif /* AF_INET6 */ if (ret == NULL) { JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL); @@ -542,7 +527,6 @@ fcntl(fd, F_SETFL, flags); \ } -#ifdef AF_INET6 static jboolean ping6(JNIEnv *env, jint fd, struct sockaddr_in6* him, jint timeout, struct sockaddr_in6* netif, jint ttl) { @@ -649,7 +633,6 @@ close(fd); return JNI_FALSE; } -#endif /* AF_INET6 */ /* * Class: java_net_Inet6AddressImpl @@ -663,7 +646,6 @@ jint timeout, jbyteArray ifArray, jint ttl, jint if_scope) { -#ifdef AF_INET6 jbyte caddr[16]; jint fd, sz; struct sockaddr_in6 him6; @@ -812,7 +794,4 @@ close(fd); return JNI_FALSE; } -#else /* AF_INET6 */ - return JNI_FALSE; -#endif /* AF_INET6 */ } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/unix/native/libnet/InetAddressImplFactory.c --- a/jdk/src/java.base/unix/native/libnet/InetAddressImplFactory.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/unix/native/libnet/InetAddressImplFactory.c Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -37,14 +37,10 @@ * Signature: ()I */ JNIEXPORT jboolean JNICALL -Java_java_net_InetAddressImplFactory_isIPv6Supported(JNIEnv *env, jclass cls) -{ -#ifdef AF_INET6 +Java_java_net_InetAddressImplFactory_isIPv6Supported(JNIEnv *env, jclass cls) { if (ipv6_available()) { return JNI_TRUE; - } else -#endif /* AF_INET6 */ - { - return JNI_FALSE; - } + } else { + return JNI_FALSE; + } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/unix/native/libnet/NetworkInterface.c --- a/jdk/src/java.base/unix/native/libnet/NetworkInterface.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/unix/native/libnet/NetworkInterface.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,55 +22,36 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - +#include #include -#include -#include -#include -#include -#include -#include -#include #include #include - -#if defined(__solaris__) -#include -#include -#include -#include -#endif - -#if defined(__linux__) +#include +#include #include -#include -#include -#endif #if defined(_AIX) -#include #include #include #include #endif -#if defined(_ALLBSD_SOURCE) -#include -#include +#if defined(__solaris__) +#include +#include #include -#if defined(__APPLE__) +#endif + +#if defined(_ALLBSD_SOURCE) #include -#include #include -#include #include #endif -#endif -#include "jvm.h" -#include "jni_util.h" #include "net_util.h" +#include "java_net_InetAddress.h" + #if defined(__linux__) #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6" #elif defined(__solaris__) @@ -145,10 +126,7 @@ static netif *enumInterfaces(JNIEnv *env); static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs); - -#if defined(AF_INET6) static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs); -#endif static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs, struct sockaddr *ifr_addrP, @@ -331,11 +309,8 @@ (JNIEnv *env, jclass cls, jobject iaObj) { netif *ifs, *curr; -#if defined(AF_INET6) - int family = (getInetAddress_family(env, iaObj) == IPv4) ? AF_INET : AF_INET6; -#else - int family = AF_INET; -#endif + int family = (getInetAddress_family(env, iaObj) == java_net_InetAddress_IPv4) ? + AF_INET : AF_INET6; jobject obj = NULL; jboolean match = JNI_FALSE; @@ -361,9 +336,7 @@ match = JNI_TRUE; break; } - } -#if defined(AF_INET6) - if (family == AF_INET6) { + } else if (family == AF_INET6) { jbyte *bytes = (jbyte *)&( ((struct sockaddr_in6*)addrP->addr)->sin6_addr); jbyte caddr[16]; @@ -381,7 +354,6 @@ break; } } -#endif } if (match) { @@ -725,7 +697,6 @@ return NULL; } } -#if defined(AF_INET6) if (addrP->family == AF_INET6) { int scope=0; iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID); @@ -754,7 +725,6 @@ return NULL; } } -#endif (*env)->SetObjectArrayElement(env, addrArr, addr_index++, iaObj); addrP = addrP->next; @@ -815,25 +785,23 @@ } // If IPv6 is available then enumerate IPv6 addresses. -#if defined(AF_INET6) - // User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true, - // so we have to call ipv6_available() - if (ipv6_available()) { - sock = openSocket(env, AF_INET6); - if (sock < 0 && (*env)->ExceptionOccurred(env)) { - freeif(ifs); - return NULL; - } + // User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true, + // so we have to call ipv6_available() + if (ipv6_available()) { + sock = openSocket(env, AF_INET6); + if (sock < 0 && (*env)->ExceptionOccurred(env)) { + freeif(ifs); + return NULL; + } - ifs = enumIPv6Interfaces(env, sock, ifs); - close(sock); + ifs = enumIPv6Interfaces(env, sock, ifs); + close(sock); - if ((*env)->ExceptionOccurred(env)) { - freeif(ifs); - return NULL; - } + if ((*env)->ExceptionOccurred(env)) { + freeif(ifs); + return NULL; } -#endif + } return ifs; } @@ -889,12 +857,8 @@ // Allocate for addr and brdcast at once -#if defined(AF_INET6) addr_size = (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); -#else - addr_size = sizeof(struct sockaddr_in); -#endif CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr) + 2 * addr_size); addrP->addr = (struct sockaddr *)((char *)addrP + sizeof(netaddr)); @@ -1083,7 +1047,6 @@ /** Linux **/ #if defined(__linux__) -#if defined(AF_INET6) /* * Opens a socket for further ioctl calls. Tries AF_INET socket first and * if it fails return AF_INET6 socket. @@ -1109,11 +1072,6 @@ // IPv6 socket regardless of type of address of an interface. return sock; } -#else -static int openSocketWithFallback(JNIEnv *env, const char *ifname) { - return openSocket(env, AF_INET); -} -#endif /* * Enumerates and returns all IPv4 interfaces on Linux. @@ -1197,8 +1155,6 @@ return ifs; } -#if defined(AF_INET6) - /* * Enumerates and returns all IPv6 interfaces on Linux. */ @@ -1240,8 +1196,6 @@ return ifs; } -#endif /* AF_INET6 */ - /* * Try to get the interface index. */ @@ -1330,7 +1284,6 @@ /** AIX **/ #if defined(_AIX) -#if defined(AF_INET6) /* * Opens a socket for further ioctl calls. Tries AF_INET socket first and * if it fails return AF_INET6 socket. @@ -1354,11 +1307,6 @@ return sock; } -#else -static int openSocketWithFallback(JNIEnv *env, const char *ifname) { - return openSocket(env, AF_INET); -} -#endif /* * Enumerates and returns all IPv4 interfaces on AIX. @@ -1442,8 +1390,6 @@ return ifs; } -#if defined(AF_INET6) - /* * Enumerates and returns all IPv6 interfaces on AIX. */ @@ -1518,8 +1464,6 @@ return ifs; } -#endif /* AF_INET6 */ - /* * Try to get the interface index. */ @@ -1614,7 +1558,6 @@ /** Solaris **/ #if defined(__solaris__) -#if defined(AF_INET6) /* * Opens a socket for further ioctl calls. Tries AF_INET socket first and * if it fails return AF_INET6 socket. @@ -1659,11 +1602,6 @@ return sock; } -#else -static int openSocketWithFallback(JNIEnv *env, const char *ifname) { - return openSocket(env, AF_INET); -} -#endif /* * Enumerates and returns all IPv4 interfaces on Solaris. @@ -1739,8 +1677,6 @@ return ifs; } -#if defined(AF_INET6) - /* * Enumerates and returns all IPv6 interfaces on Solaris. */ @@ -1803,8 +1739,6 @@ return ifs; } -#endif /* AF_INET6 */ - /* * Try to get the interface index. * (Not supported on Solaris 2.6 or 7) @@ -1976,7 +1910,6 @@ /** BSD **/ #if defined(_ALLBSD_SOURCE) -#if defined(AF_INET6) /* * Opens a socket for further ioctl calls. Tries AF_INET socket first and * if it fails return AF_INET6 socket. @@ -2000,11 +1933,6 @@ return sock; } -#else -static int openSocketWithFallback(JNIEnv *env, const char *ifname) { - return openSocket(env, AF_INET); -} -#endif /* * Enumerates and returns all IPv4 interfaces on BSD. @@ -2050,8 +1978,6 @@ return ifs; } -#if defined(AF_INET6) - /* * Enumerates and returns all IPv6 interfaces on BSD. */ @@ -2092,8 +2018,6 @@ return ifs; } -#endif /* AF_INET6 */ - /* * Try to get the interface index. */ diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c --- a/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,29 +22,23 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - #include -#include #include #include -#include -#include +#include -#ifdef __solaris__ -#include -#include -#include +#if defined(__solaris__) +#include +#endif -#ifndef BSD_COMP -#define BSD_COMP -#endif -#endif +#include "net_util.h" + +#include "java_net_PlainDatagramSocketImpl.h" +#include "java_net_InetAddress.h" +#include "java_net_NetworkInterface.h" +#include "java_net_SocketOptions.h" + #ifdef __linux__ -#include -#include -#include -#include - #define IPV6_MULTICAST_IF 17 #ifndef SO_BSDCOMPAT #define SO_BSDCOMPAT 14 @@ -58,7 +52,11 @@ #endif #endif // __linux__ -#include +#ifdef __solaris__ +#ifndef BSD_COMP +#define BSD_COMP +#endif +#endif #ifndef IPTOS_TOS_MASK #define IPTOS_TOS_MASK 0x1e @@ -67,12 +65,6 @@ #define IPTOS_PREC_MASK 0xe0 #endif -#include "jvm.h" -#include "jni_util.h" -#include "net_util.h" -#include "java_net_SocketOptions.h" -#include "java_net_PlainDatagramSocketImpl.h" -#include "java_net_NetworkInterface.h" /************************************************************************ * PlainDatagramSocketImpl */ @@ -151,9 +143,6 @@ JNIEXPORT void JNICALL Java_java_net_PlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) { -#ifdef __linux__ - struct utsname sysinfo; -#endif pdsi_fdID = (*env)->GetFieldID(env, cls, "fd", "Ljava/io/FileDescriptor;"); CHECK_NULL(pdsi_fdID); @@ -310,13 +299,10 @@ #if defined(__linux__) || defined(_ALLBSD_SOURCE) memset(&addr, 0, sizeof(addr)); -#ifdef AF_INET6 if (ipv6_available()) { addr.sa6.sin6_family = AF_UNSPEC; len = sizeof(struct sockaddr_in6); - } else -#endif - { + } else { addr.sa4.sin_family = AF_UNSPEC; len = sizeof(struct sockaddr_in); } @@ -330,12 +316,9 @@ localPort = NET_GetPortFromSockaddr(&addr.sa); if (localPort == 0) { localPort = (*env)->GetIntField(env, this, pdsi_localPortID); -#ifdef AF_INET6 if (addr.sa.sa_family == AF_INET6) { addr.sa6.sin6_port = htons(localPort); - } else -#endif /* AF_INET6 */ - { + } else { addr.sa4.sin_port = htons(localPort); } @@ -443,12 +426,9 @@ (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen, (jbyte *)fullPacket); -#ifdef AF_INET6 if (trafficClass != 0 && ipv6_available()) { NET_SetTrafficClass(&rmtaddr.sa, trafficClass); } -#endif /* AF_INET6 */ - /* * Send the datagram. @@ -549,11 +529,8 @@ } iaObj = NET_SockaddrToInetAddress(env, &rmtaddr.sa, &port); -#ifdef AF_INET6 - family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6; -#else - family = AF_INET; -#endif + family = getInetAddress_family(env, iaObj) == java_net_InetAddress_IPv4 ? + AF_INET : AF_INET6; if (family == AF_INET) { /* this API can't handle IPV6 addresses */ int address = getInetAddress_addr(env, iaObj); setInetAddress_addr(env, addressObj, address); @@ -918,11 +895,7 @@ jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); int arg, fd, t = 1; char tmpbuf[1024]; -#ifdef AF_INET6 int domain = ipv6_available() ? AF_INET6 : AF_INET; -#else - int domain = AF_INET; -#endif if (IS_NULL(fdObj)) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", @@ -936,7 +909,6 @@ return; } -#ifdef AF_INET6 /* Disable IPV6_V6ONLY to ensure dual-socket support */ if (domain == AF_INET6) { arg = 0; @@ -947,7 +919,6 @@ return; } } -#endif /* AF_INET6 */ #ifdef __APPLE__ arg = 65507; @@ -987,7 +958,7 @@ } #endif -#if defined (__linux__) && defined (AF_INET6) +#if defined (__linux__) /* * On Linux for IPv6 sockets we must set the hop limit * to 1 to be compatible with default TTL of 1 for IPv4 sockets. @@ -1071,7 +1042,7 @@ */ for (i = 0; i < len; i++) { addr = (*env)->GetObjectArrayElement(env, addrArray, i); - if (getInetAddress_family(env, addr) == IPv4) { + if (getInetAddress_family(env, addr) == java_net_InetAddress_IPv4) { in.s_addr = htonl(getInetAddress_addr(env, addr)); break; } @@ -1088,7 +1059,6 @@ * Set outgoing multicast interface designated by a NetworkInterface. * Throw exception if failed. */ -#ifdef AF_INET6 static void mcast_set_if_by_if_v6(JNIEnv *env, jobject this, int fd, jobject value) { static jfieldID ni_indexID; int index; @@ -1113,9 +1083,7 @@ } return; } - } -#endif /* AF_INET6 */ /* * Set outgoing multicast interface designated by an InetAddress. @@ -1137,7 +1105,6 @@ * Set outgoing multicast interface designated by an InetAddress. * Throw exception if failed. */ -#ifdef AF_INET6 static void mcast_set_if_by_addr_v6(JNIEnv *env, jobject this, int fd, jobject value) { static jclass ni_class; if (ni_class == NULL) { @@ -1159,7 +1126,6 @@ mcast_set_if_by_if_v6(env, this, fd, value); } -#endif /* * Sets the multicast interface. @@ -1191,7 +1157,6 @@ /* * value is an InetAddress. */ -#ifdef AF_INET6 #ifdef __linux__ mcast_set_if_by_addr_v4(env, this, fd, value); if (ipv6_available()) { @@ -1207,16 +1172,12 @@ mcast_set_if_by_addr_v4(env, this, fd, value); } #endif /* __linux__ */ -#else - mcast_set_if_by_addr_v4(env, this, fd, value); -#endif /* AF_INET6 */ } if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) { /* * value is a NetworkInterface. */ -#ifdef AF_INET6 #ifdef __linux__ mcast_set_if_by_if_v4(env, this, fd, value); if (ipv6_available()) { @@ -1232,9 +1193,6 @@ mcast_set_if_by_if_v4(env, this, fd, value); } #endif /* __linux__ */ -#else - mcast_set_if_by_if_v4(env, this, fd, value); -#endif /* AF_INET6 */ } } @@ -1266,7 +1224,6 @@ /* * Enable/disable local loopback of multicast datagrams. */ -#ifdef AF_INET6 static void mcast_set_loop_v6(JNIEnv *env, jobject this, int fd, jobject value) { jclass cls; jfieldID fid; @@ -1289,14 +1246,12 @@ } } -#endif /* AF_INET6 */ /* * Sets the multicast loopback mode. */ static void setMulticastLoopbackMode(JNIEnv *env, jobject this, int fd, jint opt, jobject value) { -#ifdef AF_INET6 #ifdef __linux__ mcast_set_loop_v4(env, this, fd, value); if (ipv6_available()) { @@ -1312,9 +1267,6 @@ mcast_set_loop_v4(env, this, fd, value); } #endif /* __linux__ */ -#else - mcast_set_loop_v4(env, this, fd, value); -#endif /* AF_INET6 */ } /* @@ -1456,11 +1408,9 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, jint opt) { jboolean isIPV4 = JNI_TRUE; -#ifdef AF_INET6 if (ipv6_available()) { isIPV4 = JNI_FALSE; } -#endif /* * IPv4 implementation @@ -1559,7 +1509,6 @@ } -#ifdef AF_INET6 /* * IPv6 implementation */ @@ -1677,7 +1626,6 @@ } return ni; } -#endif return NULL; } @@ -1815,7 +1763,6 @@ /* * Set hops limit for a socket. Throw exception if failed. */ -#ifdef AF_INET6 static void setHopLimit(JNIEnv *env, int fd, jint ttl) { int ittl = (int)ttl; if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, @@ -1824,7 +1771,6 @@ (env, JNU_JAVANETPKG "SocketException", "Error setting socket option"); } } -#endif /* * Class: java_net_PlainDatagramSocketImpl @@ -1847,7 +1793,6 @@ fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); } /* setsockopt to be correct TTL */ -#ifdef AF_INET6 #ifdef __linux__ setTTL(env, fd, ttl); JNU_CHECK_EXCEPTION(env); @@ -1861,9 +1806,6 @@ setTTL(env, fd, ttl); } #endif /* __linux__ */ -#else - setTTL(env, fd, ttl); -#endif /* AF_INET6 */ } /* @@ -1896,7 +1838,6 @@ fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID); } /* getsockopt of TTL */ -#ifdef AF_INET6 if (ipv6_available()) { int ttl = 0; socklen_t len = sizeof(ttl); @@ -1908,19 +1849,17 @@ return -1; } return (jint)ttl; - } else -#endif /* AF_INET6 */ - { - u_char ttl = 0; - socklen_t len = sizeof(ttl); - if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, - (char*)&ttl, &len) < 0) { - JNU_ThrowByNameWithMessageAndLastError - (env, JNU_JAVANETPKG "SocketException", "Error getting socket option"); - return -1; - } - return (jint)ttl; + } else { + u_char ttl = 0; + socklen_t len = sizeof(ttl); + if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, + (char*)&ttl, &len) < 0) { + JNU_ThrowByNameWithMessageAndLastError + (env, JNU_JAVANETPKG "SocketException", "Error getting socket option"); + return -1; } + return (jint)ttl; + } } @@ -1966,22 +1905,14 @@ /* * Determine if this is an IPv4 or IPv6 join/leave. */ -#ifdef AF_INET6 ipv6_join_leave = ipv6_available(); #ifdef __linux__ - if (getInetAddress_family(env, iaObj) == IPv4) { + if (getInetAddress_family(env, iaObj) == java_net_InetAddress_IPv4) { ipv6_join_leave = JNI_FALSE; } #endif -#else - /* - * IPv6 not compiled in - */ - ipv6_join_leave = JNI_FALSE; -#endif - /* * For IPv4 join use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option * @@ -2006,7 +1937,7 @@ * NetworkInterface */ if (niObj != NULL) { -#if defined(__linux__) && defined(AF_INET6) +#if defined(__linux__) if (ipv6_available()) { static jfieldID ni_indexID; @@ -2062,7 +1993,7 @@ if (niObj == NULL) { -#if defined(__linux__) && defined(AF_INET6) +#if defined(__linux__) if (ipv6_available()) { int index; @@ -2118,7 +2049,7 @@ * should return ENOPROTOOPT. We assume this will be fixed in Linux * at some stage. */ -#if defined(__linux__) && defined(AF_INET6) +#if defined(__linux__) if (errno == ENOPROTOOPT) { if (ipv6_available()) { ipv6_join_leave = JNI_TRUE; @@ -2155,14 +2086,14 @@ * IPv6 join. If it's an IPv4 multicast group then we use an IPv4-mapped * address. */ -#ifdef AF_INET6 { struct ipv6_mreq mname6; jbyteArray ipaddress; jbyte caddr[16]; jint family; jint address; - family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6; + family = getInetAddress_family(env, iaObj) == java_net_InetAddress_IPv4 ? + AF_INET : AF_INET6; if (family == AF_INET) { /* will convert to IPv4-mapped address */ memset((char *) caddr, 0, 16); address = getInetAddress_addr(env, iaObj); @@ -2242,7 +2173,6 @@ } } } -#endif } /* diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c --- a/jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,32 +22,8 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +#include -#include -#include -#include -#include -#if defined(__linux__) -#include -#endif -#include /* Defines TCP_NODELAY, needed for 2.6 */ -#include -#ifdef __linux__ -#include -#endif -#include -#include - -#ifdef __solaris__ -#include -#endif -#ifdef __linux__ -#include -#include -#endif - -#include "jvm.h" -#include "jni_util.h" #include "net_util.h" #include "java_net_SocketOptions.h" @@ -186,11 +162,7 @@ jobject fdObj, ssObj; int fd; int type = (stream ? SOCK_STREAM : SOCK_DGRAM); -#ifdef AF_INET6 int domain = ipv6_available() ? AF_INET6 : AF_INET; -#else - int domain = AF_INET; -#endif if (socketExceptionCls == NULL) { jclass c = (*env)->FindClass(env, "java/net/SocketException"); @@ -214,7 +186,6 @@ return; } -#ifdef AF_INET6 /* Disable IPV6_V6ONLY to ensure dual-socket support */ if (domain == AF_INET6) { int arg = 0; @@ -225,7 +196,6 @@ return; } } -#endif /* AF_INET6 */ /* * If this is a server socket then enable SO_REUSEADDR @@ -295,11 +265,10 @@ } setDefaultScopeID(env, &him.sa); -#ifdef AF_INET6 if (trafficClass != 0 && ipv6_available()) { NET_SetTrafficClass(&him.sa, trafficClass); } -#endif /* AF_INET6 */ + if (timeout <= 0) { connect_rv = NET_Connect(fd, &him.sa, len); #ifdef __solaris__ diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/unix/native/libnet/SdpSupport.c --- a/jdk/src/java.base/unix/native/libnet/SdpSupport.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/unix/native/libnet/SdpSupport.c Fri Nov 11 16:44:36 2016 +0100 @@ -56,11 +56,7 @@ int s; #if defined(__solaris__) - #ifdef AF_INET6 int domain = ipv6_available() ? AF_INET6 : AF_INET; - #else - int domain = AF_INET; - #endif s = socket(domain, SOCK_STREAM, PROTO_SDP); #elif defined(__linux__) /** diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/unix/native/libnet/SocketInputStream.c --- a/jdk/src/java.base/unix/native/libnet/SocketInputStream.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/unix/native/libnet/SocketInputStream.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,20 +22,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - +#include #include -#include #include -#include -#include -#include "jvm.h" -#include "jni_util.h" #include "net_util.h" #include "java_net_SocketInputStream.h" -/************************************************************************ +/* * SocketInputStream */ diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/unix/native/libnet/SocketOutputStream.c --- a/jdk/src/java.base/unix/native/libnet/SocketOutputStream.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/unix/native/libnet/SocketOutputStream.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,15 +22,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - +#include #include -#include #include -#include -#include -#include "jni_util.h" -#include "jvm.h" #include "net_util.h" #include "java_net_SocketOutputStream.h" diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/unix/native/libnet/net_util_md.c --- a/jdk/src/java.base/unix/native/libnet/net_util_md.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/unix/native/libnet/net_util_md.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,60 +22,42 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - +#include #include +#include +#include // defines TCP_NODELAY +#include #include -#include -#include -#include /* Defines TCP_NODELAY, needed for 2.6 */ -#include -#include -#include -#include -#include +#include #include -#ifndef _ALLBSD_SOURCE -#include -#else -#include -#include -#include -#include -#ifndef MAXINT -#define MAXINT INT_MAX -#endif -#endif - -#ifdef __solaris__ -#include -#include -#include -#include -#endif - -#ifdef __linux__ -#include +#if defined(__linux__) #include #include #include +#endif -#ifndef IPV6_FLOWINFO_SEND +#if defined(__solaris__) +#include +#include +#include +#include +#include +#endif + +#include "net_util.h" + +#include "java_net_SocketOptions.h" +#include "java_net_InetAddress.h" + +#if defined(__linux__) && !defined(IPV6_FLOWINFO_SEND) #define IPV6_FLOWINFO_SEND 33 #endif -#endif - -#ifdef _AIX -#include +#if defined(__solaris__) && !defined(MAXINT) +#define MAXINT INT_MAX #endif -#include "jni_util.h" -#include "jvm.h" -#include "net_util.h" - -#include "java_net_SocketOptions.h" - /* * EXCLBIND socket options only on Solaris */ @@ -324,11 +306,6 @@ jint IPv6_supported() { -#ifndef AF_INET6 - return JNI_FALSE; -#endif - -#ifdef AF_INET6 int fd; void *ipv6_fn; SOCKETADDRESS sa; @@ -433,7 +410,6 @@ } else { return JNI_TRUE; } -#endif /* AF_INET6 */ } #endif /* DONT_ENABLE_IPV6 */ @@ -484,7 +460,7 @@ } } -#if defined(__linux__) && defined(AF_INET6) +#if defined(__linux__) /* following code creates a list of addresses from the kernel * routing table that are routed via the loopback address. @@ -804,15 +780,15 @@ int *len, jboolean v4MappedAddress) { jint family; family = getInetAddress_family(env, iaObj); -#ifdef AF_INET6 /* needs work. 1. family 2. clean up him6 etc deallocate memory */ - if (ipv6_available() && !(family == IPv4 && v4MappedAddress == JNI_FALSE)) { + if (ipv6_available() && !(family == java_net_InetAddress_IPv4 && + v4MappedAddress == JNI_FALSE)) { struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; jbyte caddr[16]; jint address; - - if (family == IPv4) { /* will convert to IPv4-mapped address */ + if (family == java_net_InetAddress_IPv4) { + // convert to IPv4-mapped address memset((char *) caddr, 0, 16); address = getInetAddress_addr(env, iaObj); if (address == INADDR_ANY) { @@ -834,9 +810,9 @@ him6->sin6_port = htons(port); memcpy((void *)&(him6->sin6_addr), caddr, sizeof(struct in6_addr) ); him6->sin6_family = AF_INET6; - *len = sizeof(struct sockaddr_in6) ; + *len = sizeof(struct sockaddr_in6); -#if defined(_ALLBSD_SOURCE) && defined(_AF_INET6) +#if defined(_ALLBSD_SOURCE) // XXXBSD: should we do something with scope id here ? see below linux comment /* MMM: Come back to this! */ #endif @@ -880,11 +856,11 @@ * try determine the appropriate interface. */ if (kernelIsV24()) { - cached_scope_id = getDefaultIPv6Interface( &(him6->sin6_addr) ); + cached_scope_id = getDefaultIPv6Interface(&(him6->sin6_addr)); } else { - cached_scope_id = getLocalScopeID( (char *)&(him6->sin6_addr) ); + cached_scope_id = getLocalScopeID((char *)&(him6->sin6_addr)); if (cached_scope_id == 0) { - cached_scope_id = getDefaultIPv6Interface( &(him6->sin6_addr) ); + cached_scope_id = getDefaultIPv6Interface(&(him6->sin6_addr)); } } (*env)->SetIntField(env, iaObj, ia6_cachedscopeidID, cached_scope_id); @@ -906,52 +882,44 @@ #else /* handle scope_id for solaris */ - if (family != IPv4) { + if (family != java_net_InetAddress_IPv4) { if (ia6_scopeidID) { him6->sin6_scope_id = getInet6Address_scopeid(env, iaObj); } } #endif - } else -#endif /* AF_INET6 */ - { - struct sockaddr_in *him4 = (struct sockaddr_in*)him; - jint address; - if (family == IPv6) { - JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family unavailable"); - return -1; - } - memset((char *) him4, 0, sizeof(struct sockaddr_in)); - address = getInetAddress_addr(env, iaObj); - him4->sin_port = htons((short) port); - him4->sin_addr.s_addr = (uint32_t) htonl(address); - him4->sin_family = AF_INET; - *len = sizeof(struct sockaddr_in); + } else { + struct sockaddr_in *him4 = (struct sockaddr_in *)him; + jint address; + if (family == java_net_InetAddress_IPv6) { + JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family unavailable"); + return -1; } + memset((char *)him4, 0, sizeof(struct sockaddr_in)); + address = getInetAddress_addr(env, iaObj); + him4->sin_port = htons((short) port); + him4->sin_addr.s_addr = htonl(address); + him4->sin_family = AF_INET; + *len = sizeof(struct sockaddr_in); + } return 0; } void NET_SetTrafficClass(struct sockaddr *him, int trafficClass) { -#ifdef AF_INET6 if (him->sa_family == AF_INET6) { struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; him6->sin6_flowinfo = htonl((trafficClass & 0xff) << 20); } -#endif /* AF_INET6 */ } JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(struct sockaddr *him) { -#ifdef AF_INET6 if (him->sa_family == AF_INET6) { return ntohs(((struct sockaddr_in6*)him)->sin6_port); - - } else -#endif /* AF_INET6 */ - { - return ntohs(((struct sockaddr_in*)him)->sin_port); - } + } else { + return ntohs(((struct sockaddr_in*)him)->sin_port); + } } int @@ -1024,7 +992,6 @@ int i; -#ifdef AF_INET6 if (ipv6_available()) { switch (cmd) { // Different multicast options if IPv6 is enabled @@ -1047,7 +1014,6 @@ #endif } } -#endif /* * Map the Java level option to the native level @@ -1079,7 +1045,7 @@ * 0 if no matching interface * >1 interface index to use for the link-local address. */ -#if defined(__linux__) && defined(AF_INET6) +#if defined(__linux__) int getDefaultIPv6Interface(struct in6_addr *target_addr) { FILE *f; char srcp[8][5]; @@ -1316,7 +1282,7 @@ if (level == IPPROTO_IP && opt == IP_TOS) { int *iptos; -#if defined(AF_INET6) && defined(__linux__) +#if defined(__linux__) if (ipv6_available()) { int optval = 1; if (setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, @@ -1520,7 +1486,7 @@ int NET_Bind(int fd, struct sockaddr *him, int len) { -#if defined(__solaris__) && defined(AF_INET6) +#if defined(__solaris__) int level = -1; int exclbind = -1; #endif @@ -1584,7 +1550,7 @@ rv = bind(fd, him, len); -#if defined(__solaris__) && defined(AF_INET6) +#if defined(__solaris__) if (rv < 0) { int en = errno; /* Restore *_EXCLBIND if the bind fails */ diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/unix/native/libnet/net_util_md.h --- a/jdk/src/java.base/unix/native/libnet/net_util_md.h Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/unix/native/libnet/net_util_md.h Fri Nov 11 16:44:36 2016 +0100 @@ -26,13 +26,9 @@ #ifndef NET_UTILS_MD_H #define NET_UTILS_MD_H +#include +#include #include -#include -#include -#include -#include - -#include int NET_Timeout(int s, long timeout); int NET_Timeout0(int s, long timeout, long currentTime); @@ -88,18 +84,11 @@ #define MAX_HEAP_BUFFER_LEN 65536 #endif -#ifdef AF_INET6 typedef union { struct sockaddr sa; struct sockaddr_in sa4; struct sockaddr_in6 sa6; } SOCKETADDRESS; -#else -typedef union { - struct sockaddr sa; - struct sockaddr_in sa4; -} SOCKETADDRESS; -#endif /************************************************************************ * Utilities @@ -107,10 +96,8 @@ #ifdef __linux__ int kernelIsV24(); -#ifdef AF_INET6 int getDefaultIPv6Interface(struct in6_addr *target_addr); #endif -#endif #ifdef __solaris__ int net_getParam(char *driver, char *param); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c --- a/jdk/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,10 +22,8 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -#include -#include -#include "jni.h" #include "net_util.h" + #include "java_net_DualStackPlainDatagramSocketImpl.h" /* diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c --- a/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,11 +22,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -#include -#include -#include "jni.h" #include "net_util.h" + #include "java_net_DualStackPlainSocketImpl.h" +#include "java_net_SocketOptions.h" #define SET_BLOCKING 0 #define SET_NONBLOCKING 1 diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c --- a/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. 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 @@ -22,24 +22,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "net_util.h" #include "java_net_InetAddress.h" #include "java_net_Inet4AddressImpl.h" -#include "net_util.h" -#include "icmp.h" - /* * Returns true if hostname is in dotted IP address format. Note that this diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/windows/native/libnet/Inet6AddressImpl.c --- a/jdk/src/java.base/windows/native/libnet/Inet6AddressImpl.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/windows/native/libnet/Inet6AddressImpl.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,38 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "net_util.h" #include "java_net_InetAddress.h" #include "java_net_Inet4AddressImpl.h" #include "java_net_Inet6AddressImpl.h" -#include "net_util.h" -#include "icmp.h" - -#ifdef WIN32 -#ifndef _WIN64 - -/* Retain this code a little longer to support building in - * old environments. _MSC_VER is defined as: - * 1200 for MSVC++ 6.0 - * 1310 for Vc7 - */ -#if defined(_MSC_VER) && _MSC_VER < 1310 -#define sockaddr_in6 SOCKADDR_IN6 -#endif -#endif -#define uint32_t UINT32 -#endif /* * Inet6AddressImpl @@ -300,7 +275,7 @@ addr |= ((caddr[2] <<8) & 0xff00); addr |= (caddr[3] & 0xff); memset((char *) &him4, 0, sizeof(him4)); - him4.sin_addr.s_addr = (uint32_t) htonl(addr); + him4.sin_addr.s_addr = htonl(addr); him4.sin_family = AF_INET; sa = (struct sockaddr *) &him4; len = sizeof(him4); @@ -330,8 +305,6 @@ return ret; } -#ifdef AF_INET6 - /** * ping implementation using tcp port 7 (echo) */ @@ -493,7 +466,6 @@ return JNI_FALSE; } } -#endif /* AF_INET6 */ /* * Class: java_net_Inet6AddressImpl @@ -507,7 +479,6 @@ jint timeout, jbyteArray ifArray, jint ttl, jint if_scope) { -#ifdef AF_INET6 jbyte caddr[16]; jint sz; struct sockaddr_in6 him6; @@ -573,6 +544,5 @@ return ping6(env, netif, &him6, timeout, hIcmpFile); } -#endif /* AF_INET6 */ return JNI_FALSE; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/windows/native/libnet/NetworkInterface.c --- a/jdk/src/java.base/windows/native/libnet/NetworkInterface.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/windows/native/libnet/NetworkInterface.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,17 +22,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - -#include -#include -#include /* needed for htonl */ -#include -#include +#include "net_util.h" +#include "NetworkInterface.h" #include "java_net_NetworkInterface.h" -#include "jni_util.h" - -#include "NetworkInterface.h" /* * Windows implementation of the java.net.NetworkInterface native methods. diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/windows/native/libnet/NetworkInterface.h --- a/jdk/src/java.base/windows/native/libnet/NetworkInterface.h Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/windows/native/libnet/NetworkInterface.h Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 @@ -26,7 +26,6 @@ #ifndef NETWORK_INTERFACE_H #define NETWORK_INTERFACE_H -#include #include "net_util.h" /* diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/windows/native/libnet/NetworkInterface_winXP.c --- a/jdk/src/java.base/windows/native/libnet/NetworkInterface_winXP.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/windows/native/libnet/NetworkInterface_winXP.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,19 +22,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - -#include -#include -#include /* needed for htonl */ -#include -#include -#include +#include "net_util.h" +#include "NetworkInterface.h" #include "java_net_NetworkInterface.h" -#include "jni_util.h" - -#include "NetworkInterface.h" -#include "net_util.h" /* * Windows implementation of the java.net.NetworkInterface native methods. diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/windows/native/libnet/SocketInputStream.c --- a/jdk/src/java.base/windows/native/libnet/SocketInputStream.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/windows/native/libnet/SocketInputStream.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,24 +22,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +#include -#include -#include -#include -#include -#include -#include -#include +#include "net_util.h" #include "java_net_SocketInputStream.h" -#include "net_util.h" -#include "jni_util.h" - /************************************************************************* * SocketInputStream */ - static jfieldID IO_fd_fdID; /* diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/windows/native/libnet/SocketOutputStream.c --- a/jdk/src/java.base/windows/native/libnet/SocketOutputStream.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/windows/native/libnet/SocketOutputStream.c Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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 @@ -22,20 +22,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +#include -#include -#include -#include -#include -#include -#include -#include +#include "net_util.h" #include "java_net_SocketOutputStream.h" -#include "net_util.h" -#include "jni_util.h" - /************************************************************************ * SocketOutputStream */ diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c --- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,15 +22,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "net_util.h" +#include "NetworkInterface.h" + +#include "java_net_TwoStacksPlainDatagramSocketImpl.h" +#include "java_net_SocketOptions.h" +#include "java_net_NetworkInterface.h" +#include "java_net_InetAddress.h" #ifndef IPTOS_TOS_MASK #define IPTOS_TOS_MASK 0x1e @@ -39,14 +39,6 @@ #define IPTOS_PREC_MASK 0xe0 #endif -#include "java_net_TwoStacksPlainDatagramSocketImpl.h" -#include "java_net_SocketOptions.h" -#include "java_net_NetworkInterface.h" - -#include "NetworkInterface.h" -#include "jvm.h" -#include "jni_util.h" -#include "net_util.h" #define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000) #define IN_MULTICAST(i) IN_CLASSD(i) @@ -439,7 +431,7 @@ memset((char *)&lcladdr, 0, sizeof(lcladdr)); family = getInetAddress_family(env, addressObj); - if (family == IPv6 && !ipv6_supported) { + if (family == java_net_InetAddress_IPv6 && !ipv6_supported) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family not supported"); return; @@ -561,13 +553,13 @@ addr = getInetAddress_addr(env, address); family = getInetAddress_family(env, address); - if (family == IPv6 && !ipv6_supported) { + if (family == java_net_InetAddress_IPv6 && !ipv6_supported) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family not supported"); return; } - fdc = family == IPv4? fd: fd1; + fdc = family == java_net_InetAddress_IPv4 ? fd : fd1; if (xp_or_later) { /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which @@ -605,12 +597,12 @@ jint fd, len; SOCKETADDRESS addr; - if (family == IPv4) { + if (family == java_net_InetAddress_IPv4) { fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); - len = sizeof (struct sockaddr_in); + len = sizeof(struct sockaddr_in); } else { fdObj = (*env)->GetObjectField(env, this, pdsi_fd1ID); - len = sizeof (struct SOCKADDR_IN6); + len = sizeof(struct sockaddr_in6); } if (IS_NULL(fdObj)) { @@ -678,7 +670,7 @@ } family = getInetAddress_family(env, iaObj); - if (family == IPv4) { + if (family == java_net_InetAddress_IPv4) { fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); } else { if (!ipv6_available()) { @@ -906,7 +898,7 @@ return 0; } setInetAddress_addr(env, addressObj, ntohl(remote_addr.sa4.sin_addr.s_addr)); - setInetAddress_family(env, addressObj, IPv4); + setInetAddress_family(env, addressObj, java_net_InetAddress_IPv4); /* return port */ return ntohs(remote_addr.sa4.sin_port); @@ -1610,7 +1602,7 @@ { jobject addr; - int ret = getInetAddrFromIf (env, IPv4, nif, &addr); + int ret = getInetAddrFromIf(env, java_net_InetAddress_IPv4, nif, &addr); if (ret == -1) { return -1; } @@ -2285,9 +2277,9 @@ len = sizeof(struct sockaddr_in); /* family==-1 when socket is not connected */ - if ((family == IPv6) || (family == -1 && fd == -1)) { + if ((family == java_net_InetAddress_IPv6) || (family == -1 && fd == -1)) { fd = fd1; /* must be IPv6 only */ - len = sizeof (struct SOCKADDR_IN6); + len = sizeof(struct sockaddr_in6); } if (fd == -1) { diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c --- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,23 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - -#include -#include -#include -#include -#include #include -#include - -#include "java_net_SocketOptions.h" -#include "java_net_TwoStacksPlainSocketImpl.h" -#include "java_net_InetAddress.h" -#include "java_io_FileDescriptor.h" -#include "java_lang_Integer.h" #include "net_util.h" -#include "jni_util.h" + +#include "java_net_TwoStacksPlainSocketImpl.h" +#include "java_net_SocketOptions.h" +#include "java_net_InetAddress.h" /************************************************************************ * TwoStacksPlainSocketImpl @@ -413,7 +403,7 @@ family = getInetAddress_family(env, iaObj); - if (family == IPv6 && !ipv6_supported) { + if (family == java_net_InetAddress_IPv6 && !ipv6_supported) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family not supported"); return; @@ -655,18 +645,18 @@ return; } if (fd2 == fd) { /* v4 */ - len = sizeof (struct sockaddr_in); + len = sizeof(struct sockaddr_in); } else { - len = sizeof (struct SOCKADDR_IN6); + len = sizeof(struct sockaddr_in6); } fd = fd2; } else { int ret; if (fd1 != -1) { fd = fd1; - len = sizeof (struct SOCKADDR_IN6); + len = sizeof(struct sockaddr_in6); } else { - len = sizeof (struct sockaddr_in); + len = sizeof(struct sockaddr_in); } if (timeout) { ret = NET_Timeout(fd, timeout); @@ -728,7 +718,7 @@ } setInetAddress_addr(env, socketAddressObj, ntohl(him.sa4.sin_addr.s_addr)); - setInetAddress_family(env, socketAddressObj, IPv4); + setInetAddress_family(env, socketAddressObj, java_net_InetAddress_IPv4); (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj); } else { /* AF_INET6 -> Inet6Address */ @@ -754,7 +744,7 @@ return; } setInet6Address_ipaddress(env, socketAddressObj, (char *)&him.sa6.sin6_addr); - setInetAddress_family(env, socketAddressObj, IPv6); + setInetAddress_family(env, socketAddressObj, java_net_InetAddress_IPv6); setInet6Address_scopeid(env, socketAddressObj, him.sa6.sin6_scope_id); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/windows/native/libnet/icmp.h --- a/jdk/src/java.base/windows/native/libnet/icmp.h Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef ICMP_H -#define ICMP_H - -/* - * Structure of an internet header, naked of options. - * - * We declare ip_len and ip_off to be short, rather than ushort_t - * pragmatically since otherwise unsigned comparisons can result - * against negative integers quite easily, and fail in subtle ways. - */ -struct ip { - unsigned char ip_hl:4, /* header length */ - ip_v:4; /* version */ - unsigned char ip_tos; /* type of service */ - short ip_len; /* total length */ - unsigned short ip_id; /* identification */ - short ip_off; /* fragment offset field */ -#define IP_DF 0x4000 /* don't fragment flag */ -#define IP_MF 0x2000 /* more fragments flag */ - unsigned char ip_ttl; /* time to live */ - unsigned char ip_p; /* protocol */ - unsigned short ip_sum; /* checksum */ - struct in_addr ip_src, ip_dst; /* source and dest address */ -}; - -/* - * Structure of an icmp header. - */ -struct icmp { - unsigned char icmp_type; /* type of message, see below */ - unsigned char icmp_code; /* type sub code */ - unsigned short icmp_cksum; /* ones complement cksum of struct */ - union { - unsigned char ih_pptr; /* ICMP_PARAMPROB */ - struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ - struct ih_idseq { - unsigned short icd_id; - unsigned short icd_seq; - } ih_idseq; - int ih_void; - - /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ - struct ih_pmtu { - unsigned short ipm_void; - unsigned short ipm_nextmtu; - } ih_pmtu; - - struct ih_rtradv { - unsigned char irt_num_addrs; - unsigned char irt_wpa; - unsigned short irt_lifetime; - } ih_rtradv; - } icmp_hun; -#define icmp_pptr icmp_hun.ih_pptr -#define icmp_gwaddr icmp_hun.ih_gwaddr -#define icmp_id icmp_hun.ih_idseq.icd_id -#define icmp_seq icmp_hun.ih_idseq.icd_seq -#define icmp_void icmp_hun.ih_void -#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void -#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu - union { - struct id_ts { - unsigned int its_otime; - unsigned int its_rtime; - unsigned int its_ttime; - } id_ts; - struct id_ip { - struct ip idi_ip; - /* options and then 64 bits of data */ - } id_ip; - unsigned int id_mask; - char id_data[1]; - } icmp_dun; -#define icmp_otime icmp_dun.id_ts.its_otime -#define icmp_rtime icmp_dun.id_ts.its_rtime -#define icmp_ttime icmp_dun.id_ts.its_ttime -#define icmp_ip icmp_dun.id_ip.idi_ip -#define icmp_mask icmp_dun.id_mask -#define icmp_data icmp_dun.id_data -}; - -#define ICMP_ECHOREPLY 0 /* echo reply */ -#define ICMP_ECHO 8 /* echo service */ - -/* - * ICMPv6 structures & constants - */ - -typedef struct icmp6_hdr { - u_char icmp6_type; /* type field */ - u_char icmp6_code; /* code field */ - u_short icmp6_cksum; /* checksum field */ - union { - u_int icmp6_un_data32[1]; /* type-specific field */ - u_short icmp6_un_data16[2]; /* type-specific field */ - u_char icmp6_un_data8[4]; /* type-specific field */ - } icmp6_dataun; -} icmp6_t; - -#define icmp6_data32 icmp6_dataun.icmp6_un_data32 -#define icmp6_data16 icmp6_dataun.icmp6_un_data16 -#define icmp6_data8 icmp6_dataun.icmp6_un_data8 -#define icmp6_pptr icmp6_data32[0] /* parameter prob */ -#define icmp6_mtu icmp6_data32[0] /* packet too big */ -#define icmp6_id icmp6_data16[0] /* echo request/reply */ -#define icmp6_seq icmp6_data16[1] /* echo request/reply */ -#define icmp6_maxdelay icmp6_data16[0] /* mcast group membership */ - -struct ip6_pseudo_hdr /* for calculate the ICMPv6 checksum */ -{ - struct in6_addr ip6_src; - struct in6_addr ip6_dst; - u_int ip6_plen; - u_int ip6_nxt; -}; - -#define ICMP6_ECHO_REQUEST 128 -#define ICMP6_ECHO_REPLY 129 -#define IPPROTO_ICMPV6 58 -#define IPV6_UNICAST_HOPS 4 /* Set/get IP unicast hop limit */ - - -#endif diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/windows/native/libnet/net_util_md.c --- a/jdk/src/java.base/windows/native/libnet/net_util_md.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/windows/native/libnet/net_util_md.c Fri Nov 11 16:44:36 2016 +0100 @@ -22,12 +22,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +#include "net_util.h" -#include -#include - -#include "net_util.h" -#include "jni.h" +#include "java_net_InetAddress.h" +#include "java_net_SocketOptions.h" // Taken from mstcpip.h in Windows SDK 8.0 or newer. #define SIO_LOOPBACK_FAST_PATH _WSAIOW(IOC_VENDOR,16) @@ -593,7 +591,7 @@ void dumpAddr (char *str, void *addr) { - struct SOCKADDR_IN6 *a = (struct SOCKADDR_IN6 *)addr; + struct sockaddr_in6 *a = (struct sockaddr_in6 *)addr; int family = a->sin6_family; printf ("%s\n", str); if (family == AF_INET) { @@ -812,7 +810,7 @@ * 0 if error * > 0 interface index to use */ -jint getDefaultIPv6Interface(JNIEnv *env, struct SOCKADDR_IN6 *target_addr) +jint getDefaultIPv6Interface(JNIEnv *env, struct sockaddr_in6 *target_addr) { int ret; DWORD b; @@ -866,9 +864,9 @@ int *len, jboolean v4MappedAddress) { jint family, iafam; iafam = getInetAddress_family(env, iaObj); - family = (iafam == IPv4)? AF_INET : AF_INET6; + family = (iafam == java_net_InetAddress_IPv4)? AF_INET : AF_INET6; if (ipv6_available() && !(family == AF_INET && v4MappedAddress == JNI_FALSE)) { - struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; + struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; jbyte caddr[16]; jint address, scopeid = 0; jint cached_scope_id = 0; @@ -894,7 +892,7 @@ cached_scope_id = (jint)(*env)->GetIntField(env, iaObj, ia6_cachedscopeidID); } - memset((char *)him6, 0, sizeof(struct SOCKADDR_IN6)); + memset((char *)him6, 0, sizeof(struct sockaddr_in6)); him6->sin6_port = (u_short) htons((u_short)port); memcpy((void *)&(him6->sin6_addr), caddr, sizeof(struct in6_addr) ); him6->sin6_family = AF_INET6; @@ -904,7 +902,7 @@ (*env)->SetIntField(env, iaObj, ia6_cachedscopeidID, cached_scope_id); } him6->sin6_scope_id = scopeid != 0 ? scopeid : cached_scope_id; - *len = sizeof(struct SOCKADDR_IN6) ; + *len = sizeof(struct sockaddr_in6) ; } else { struct sockaddr_in *him4 = (struct sockaddr_in *)him; jint address; @@ -964,12 +962,12 @@ } int getScopeID(struct sockaddr *him) { - struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; + struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; return him6->sin6_scope_id; } int cmpScopeID(unsigned int scope, struct sockaddr *him) { - struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him; + struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him; return him6->sin6_scope_id == scope; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.base/windows/native/libnet/net_util_md.h --- a/jdk/src/java.base/windows/native/libnet/net_util_md.h Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.base/windows/native/libnet/net_util_md.h Fri Nov 11 16:44:36 2016 +0100 @@ -22,195 +22,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - #include #include - -/* typedefs that were defined correctly for the first time - * in Nov. 2001 SDK, which we need to include here. - * Specifically, in6_addr and sockaddr_in6 (which is defined but - * not correctly). When moving to a later SDK remove following - * code between START and END - */ - -/* --- START --- */ - -/* WIN64 already uses newer SDK */ -#ifdef _WIN64 - -#define SOCKADDR_IN6 sockaddr_in6 - -#else - -#ifdef _MSC_VER -#define WS2TCPIP_INLINE __inline -#else -#define WS2TCPIP_INLINE extern inline /* GNU style */ -#endif - -#if defined(_MSC_VER) && _MSC_VER >= 1310 - -#define SOCKADDR_IN6 sockaddr_in6 - -#else - -/*SO_REUSEPORT is not supported on Windows, define it to 0*/ -#define SO_REUSEPORT 0 - -/* Retain this code a little longer to support building in - * old environments. _MSC_VER is defined as: - * 1200 for MSVC++ 6.0 - * 1310 for Vc7 - */ - -#define IPPROTO_IPV6 41 -#define IPV6_MULTICAST_IF 9 - -struct in6_addr { - union { - u_char Byte[16]; - u_short Word[8]; - } u; -}; - -/* -** Defines to match RFC 2553. -*/ -#define _S6_un u -#define _S6_u8 Byte -#define s6_addr _S6_un._S6_u8 - -/* -** Defines for our implementation. -*/ -#define s6_bytes u.Byte -#define s6_words u.Word - -/* IPv6 socket address structure, RFC 2553 */ - -struct SOCKADDR_IN6 { - short sin6_family; /* AF_INET6 */ - u_short sin6_port; /* Transport level port number */ - u_long sin6_flowinfo; /* IPv6 flow information */ - struct in6_addr sin6_addr; /* IPv6 address */ - u_long sin6_scope_id; /* set of interfaces for a scope */ -}; - - -/* Error codes from getaddrinfo() */ - -#define EAI_AGAIN WSATRY_AGAIN -#define EAI_BADFLAGS WSAEINVAL -#define EAI_FAIL WSANO_RECOVERY -#define EAI_FAMILY WSAEAFNOSUPPORT -#define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY -//#define EAI_NODATA WSANO_DATA -#define EAI_NONAME WSAHOST_NOT_FOUND -#define EAI_SERVICE WSATYPE_NOT_FOUND -#define EAI_SOCKTYPE WSAESOCKTNOSUPPORT - -#define EAI_NODATA EAI_NONAME - -/* Structure used in getaddrinfo() call */ - -typedef struct addrinfo { - int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ - int ai_family; /* PF_xxx */ - int ai_socktype; /* SOCK_xxx */ - int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ - size_t ai_addrlen; /* Length of ai_addr */ - char *ai_canonname; /* Canonical name for nodename */ - struct sockaddr *ai_addr; /* Binary address */ - struct addrinfo *ai_next; /* Next structure in linked list */ -} ADDRINFO, FAR * LPADDRINFO; - -/* Flags used in "hints" argument to getaddrinfo() */ - -#define AI_PASSIVE 0x1 /* Socket address will be used in bind() call */ -#define AI_CANONNAME 0x2 /* Return canonical name in first ai_canonname */ -#define AI_NUMERICHOST 0x4 /* Nodename must be a numeric address string */ - -/* IPv6 Multicasting definitions */ - -/* Argument structure for IPV6_JOIN_GROUP and IPV6_LEAVE_GROUP */ - -typedef struct ipv6_mreq { - struct in6_addr ipv6mr_multiaddr; /* IPv6 multicast address */ - unsigned int ipv6mr_interface; /* Interface index */ -} IPV6_MREQ; - -#define IPV6_ADD_MEMBERSHIP 12 /* Add an IP group membership */ -#define IPV6_DROP_MEMBERSHIP 13 /* Drop an IP group membership */ -#define IPV6_MULTICAST_LOOP 11 /* Set/get IP multicast loopback */ - -WS2TCPIP_INLINE int -IN6_IS_ADDR_MULTICAST(const struct in6_addr *a) -{ - return (a->s6_bytes[0] == 0xff); -} - -WS2TCPIP_INLINE int -IN6_IS_ADDR_LINKLOCAL(const struct in6_addr *a) -{ - return (a->s6_bytes[0] == 0xfe - && a->s6_bytes[1] == 0x80); -} - -#define NI_MAXHOST 1025 /* Max size of a fully-qualified domain name */ -#define NI_MAXSERV 32 /* Max size of a service name */ - -#define INET_ADDRSTRLEN 16 /* Max size of numeric form of IPv4 address */ -#define INET6_ADDRSTRLEN 46 /* Max size of numeric form of IPv6 address */ - -/* Flags for getnameinfo() */ - -#define NI_NOFQDN 0x01 /* Only return nodename portion for local hosts */ -#define NI_NUMERICHOST 0x02 /* Return numeric form of the host's address */ -#define NI_NAMEREQD 0x04 /* Error if the host's name not in DNS */ -#define NI_NUMERICSERV 0x08 /* Return numeric form of the service (port #) */ -#define NI_DGRAM 0x10 /* Service is a datagram service */ - - -#define IN6_IS_ADDR_V4MAPPED(a) \ - (((a)->s6_words[0] == 0) && ((a)->s6_words[1] == 0) && \ - ((a)->s6_words[2] == 0) && ((a)->s6_words[3] == 0) && \ - ((a)->s6_words[4] == 0) && ((a)->s6_words[5] == 0xffff)) - - -/* --- END --- */ -#endif /* end 'else older build environment' */ - -#endif - -#if !INCL_WINSOCK_API_TYPEDEFS - -typedef -int -(WSAAPI * LPFN_GETADDRINFO)( - IN const char FAR * nodename, - IN const char FAR * servname, - IN const struct addrinfo FAR * hints, - OUT struct addrinfo FAR * FAR * res - ); - -typedef -void -(WSAAPI * LPFN_FREEADDRINFO)( - IN struct addrinfo FAR * ai - ); - -typedef -int -(WSAAPI * LPFN_GETNAMEINFO)( - IN const struct sockaddr FAR * sa, - IN int salen, - OUT char FAR * host, - IN DWORD hostlen, - OUT char FAR * serv, - IN DWORD servlen, - IN int flags - ); -#endif +#include +#include /* used to disable connection reset messages on Windows XP */ #ifndef SIO_UDP_CONNRESET @@ -229,13 +44,9 @@ #define IPV6_V6ONLY 27 /* Treat wildcard bind as AF_INET6-only. */ #endif -#include "java_io_FileDescriptor.h" -#include "java_net_SocketOptions.h" - #define MAX_BUFFER_LEN 2048 #define MAX_HEAP_BUFFER_LEN 65536 - /* true if SO_RCVTIMEO is supported by underlying provider */ extern jboolean isRcvTimeoutSupported; @@ -249,7 +60,7 @@ typedef union { struct sockaddr sa; struct sockaddr_in sa4; - struct SOCKADDR_IN6 sa6; + struct sockaddr_in6 sa6; } SOCKETADDRESS; /* @@ -264,7 +75,7 @@ #define SOCKETADDRESS_COPY(DST,SRC) { \ if ((SRC)->sa_family == AF_INET6) { \ - memcpy ((DST), (SRC), sizeof (struct SOCKADDR_IN6)); \ + memcpy ((DST), (SRC), sizeof (struct sockaddr_in6)); \ } else { \ memcpy ((DST), (SRC), sizeof (struct sockaddr_in)); \ } \ diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/classes/sun/java2d/OSXSurfaceData.java --- a/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXSurfaceData.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXSurfaceData.java Fri Nov 11 16:44:36 2016 +0100 @@ -74,8 +74,13 @@ this.fGraphicsStatesInt = this.fGraphicsStates.asIntBuffer(); this.fGraphicsStatesFloat = this.fGraphicsStates.asFloatBuffer(); this.fGraphicsStatesLong = this.fGraphicsStates.asLongBuffer(); - this.fGraphicsStatesObject = new Object[6]; // clip coordinates + clip types + texture paint image + stroke dash - // array + font + font paint + this.fGraphicsStatesObject = new Object[8]; // clip coordinates + + // clip types + + // texture paint image + + // stroke dash array + + // font + font paint + + // linear/radial gradient color + + // linear/radial gradient fractions // NOTE: All access to the DrawingQueue comes through this OSXSurfaceData instance. Therefore // every instance method of OSXSurfaceData that accesses the fDrawingQueue is synchronized. @@ -292,10 +297,10 @@ @Native static final int kHintsFractionalMetricsIndex = 46; @Native static final int kHintsRenderingIndex = 47; @Native static final int kHintsInterpolationIndex = 48; - // live resizing info - @Native static final int kCanDrawDuringLiveResizeIndex = 49; + //gradient info + @Native static final int kRadiusIndex = 49; - @Native static final int kSizeOfParameters = kCanDrawDuringLiveResizeIndex + 1; + @Native static final int kSizeOfParameters = kRadiusIndex + 1; // for objectParameters @Native static final int kClipCoordinatesIndex = 0; @@ -304,6 +309,8 @@ @Native static final int kStrokeDashArrayIndex = 3; @Native static final int kFontIndex = 4; @Native static final int kFontPaintIndex = 5; + @Native static final int kColorArrayIndex = 6; + @Native static final int kFractionsArrayIndex = 7; // possible state changes @Native static final int kBoundsChangedBit = 1 << 0; @@ -329,6 +336,8 @@ @Native static final int kColorSystem = 1; @Native static final int kColorGradient = 2; @Native static final int kColorTexture = 3; + @Native static final int kColorLinearGradient = 4; + @Native static final int kColorRadialGradient = 5; // possible gradient color states @Native static final int kColorNonCyclic = 0; @@ -522,6 +531,28 @@ int lastPaintIndex = 0; BufferedImage texturePaintImage = null; + void setGradientViaRasterPath(SunGraphics2D sg2d) { + if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorTexture) || (lastPaint != sg2d.paint) || ((this.fChangeFlag & kBoundsChangedBit) != 0)) { + PaintContext context = sg2d.paint.createContext(sg2d.getDeviceColorModel(), userBounds, userBounds, sIdentityMatrix, sg2d.getRenderingHints()); + WritableRaster raster = (WritableRaster) (context.getRaster(userBounds.x, userBounds.y, userBounds.width, userBounds.height)); + ColorModel cm = context.getColorModel(); + texturePaintImage = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null); + + this.fGraphicsStatesInt.put(kColorStateIndex, kColorTexture); + this.fGraphicsStatesInt.put(kColorWidthIndex, texturePaintImage.getWidth()); + this.fGraphicsStatesInt.put(kColorHeightIndex, texturePaintImage.getHeight()); + this.fGraphicsStatesFloat.put(kColortxIndex, (float) userBounds.getX()); + this.fGraphicsStatesFloat.put(kColortyIndex, (float) userBounds.getY()); + this.fGraphicsStatesFloat.put(kColorsxIndex, 1.0f); + this.fGraphicsStatesFloat.put(kColorsyIndex, 1.0f); + this.fGraphicsStatesObject[kTextureImageIndex] = OSXOffScreenSurfaceData.createNewSurface(texturePaintImage); + + this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); + } else { + this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); + } + } + void setupPaint(SunGraphics2D sg2d, int x, int y, int w, int h) { if (sg2d.paint instanceof SystemColor) { SystemColor color = (SystemColor) sg2d.paint; @@ -567,6 +598,75 @@ } else { this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); } + } else if (sg2d.paint instanceof LinearGradientPaint) { + LinearGradientPaint color = (LinearGradientPaint) sg2d.paint; + if (color.getCycleMethod() == LinearGradientPaint.CycleMethod.NO_CYCLE) { + if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorLinearGradient) || (lastPaint != sg2d.paint)) { + + this.fGraphicsStatesInt.put(kColorStateIndex, kColorLinearGradient); + int numColor = color.getColors().length; + int colorArray[] = new int[numColor]; + for (int i = 0; i < numColor; i++) { + colorArray[i] = color.getColors()[i].getRGB(); + } + this.fGraphicsStatesObject[kColorArrayIndex] = colorArray; + + int numFractions = color.getFractions().length; + float fractionArray[] = new float[numFractions]; + for (int i = 0; i < numFractions; i++) { + fractionArray[i] = color.getFractions()[i]; + } + this.fGraphicsStatesObject[kFractionsArrayIndex] = color.getFractions(); + + Point2D p = color.getStartPoint(); + this.fGraphicsStatesFloat.put(kColorx1Index, (float) p.getX()); + this.fGraphicsStatesFloat.put(kColory1Index, (float) p.getY()); + p = color.getEndPoint(); + this.fGraphicsStatesFloat.put(kColorx2Index, (float) p.getX()); + this.fGraphicsStatesFloat.put(kColory2Index, (float) p.getY()); + + this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); + } else { + this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); + } + } else { + setGradientViaRasterPath(sg2d); + } + } else if (sg2d.paint instanceof RadialGradientPaint) { + RadialGradientPaint color = (RadialGradientPaint) sg2d.paint; + if (color.getCycleMethod() == RadialGradientPaint.CycleMethod.NO_CYCLE) { + if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorRadialGradient) || (lastPaint != sg2d.paint)) { + + this.fGraphicsStatesInt.put(kColorStateIndex, kColorRadialGradient); + int numColor = color.getColors().length; + int colorArray[] = new int[numColor]; + for (int i = 0; i < numColor; i++) { + colorArray[i] = color.getColors()[i].getRGB(); + } + this.fGraphicsStatesObject[kColorArrayIndex] = colorArray; + + int numStops = color.getFractions().length; + float stopsArray[] = new float[numStops]; + for (int i = 0; i < numStops; i++) { + stopsArray[i] = color.getFractions()[i]; + } + this.fGraphicsStatesObject[kFractionsArrayIndex] = color.getFractions(); + + Point2D p = color.getFocusPoint(); + this.fGraphicsStatesFloat.put(kColorx1Index, (float) p.getX()); + this.fGraphicsStatesFloat.put(kColory1Index, (float) p.getY()); + p = color.getCenterPoint(); + this.fGraphicsStatesFloat.put(kColorx2Index, (float) p.getX()); + this.fGraphicsStatesFloat.put(kColory2Index, (float) p.getY()); + this.fGraphicsStatesFloat.put(kRadiusIndex, color.getRadius()); + + this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); + } else { + this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); + } + } else { + setGradientViaRasterPath(sg2d); + } } else if (sg2d.paint instanceof TexturePaint) { if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorTexture) || (lastPaint != sg2d.paint)) { TexturePaint color = (TexturePaint) sg2d.paint; @@ -587,27 +687,7 @@ this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); } } else { - if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorTexture) || (lastPaint != sg2d.paint) || ((this.fChangeFlag & kBoundsChangedBit) != 0)) { - PaintContext context = sg2d.paint.createContext(sg2d.getDeviceColorModel(), userBounds, userBounds, sIdentityMatrix, sg2d.getRenderingHints()); - WritableRaster raster = (WritableRaster) (context.getRaster(userBounds.x, userBounds.y, userBounds.width, userBounds.height)); - ColorModel cm = context.getColorModel(); - texturePaintImage = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null); - - this.fGraphicsStatesInt.put(kColorStateIndex, kColorTexture); - this.fGraphicsStatesInt.put(kColorWidthIndex, texturePaintImage.getWidth()); - this.fGraphicsStatesInt.put(kColorHeightIndex, texturePaintImage.getHeight()); - this.fGraphicsStatesFloat.put(kColortxIndex, (float) userBounds.getX()); - this.fGraphicsStatesFloat.put(kColortyIndex, (float) userBounds.getY()); - this.fGraphicsStatesFloat.put(kColorsxIndex, 1.0f); - this.fGraphicsStatesFloat.put(kColorsyIndex, 1.0f); - this.fGraphicsStatesObject[kTextureImageIndex] = sun.awt.image.BufImgSurfaceData.createData(texturePaintImage); - - context.dispose(); - - this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); - } else { - this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); - } + setGradientViaRasterPath(sg2d); } lastPaint = sg2d.paint; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java Fri Nov 11 16:44:36 2016 +0100 @@ -29,11 +29,9 @@ import java.awt.*; import java.beans.*; -import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.*; import java.util.concurrent.Callable; -import sun.awt.AWTAccessor; import javax.accessibility.*; import javax.swing.*; @@ -73,8 +71,20 @@ } public void propertyChange(final PropertyChangeEvent evt) { - if (evt.getNewValue() == null) return; - focusChanged(); + Object newValue = evt.getNewValue(); + if (newValue == null) return; + // Don't post focus on things that don't matter, i.e. alert, colorchooser, + // desktoppane, dialog, directorypane, filechooser, filler, fontchoose, + // frame, glasspane, layeredpane, optionpane, panel, rootpane, separator, + // tooltip, viewport, window. + // List taken from initializeRoles() in JavaComponentUtilities.m. + if (newValue instanceof Accessible) { + AccessibleContext nvAC = ((Accessible) newValue).getAccessibleContext(); + AccessibleRole nvRole = nvAC.getAccessibleRole(); + if (!ignoredRoles.contains(roleKey(nvRole))) { + focusChanged(); + } + } } private native void focusChanged(); @@ -683,9 +693,15 @@ if (context == null) continue; if (whichChildren == JAVA_AX_VISIBLE_CHILDREN) { - if (!context.getAccessibleComponent().isVisible()) continue; + AccessibleComponent acomp = context.getAccessibleComponent(); + if (acomp == null || !acomp.isVisible()) { + continue; + } } else if (whichChildren == JAVA_AX_SELECTED_CHILDREN) { - if (!ac.getAccessibleSelection().isAccessibleChildSelected(i)) continue; + AccessibleSelection sel = ac.getAccessibleSelection(); + if (sel == null || !sel.isAccessibleChildSelected(i)) { + continue; + } } if (!allowIgnored) { diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java Fri Nov 11 16:44:36 2016 +0100 @@ -39,7 +39,10 @@ import static javax.accessibility.AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY; import static javax.accessibility.AccessibleContext.ACCESSIBLE_CARET_PROPERTY; import static javax.accessibility.AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY; +import static javax.accessibility.AccessibleContext.ACCESSIBLE_STATE_PROPERTY; import static javax.accessibility.AccessibleContext.ACCESSIBLE_TEXT_PROPERTY; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; import sun.awt.AWTAccessor; @@ -63,6 +66,9 @@ private static native void valueChanged(long ptr); private static native void selectedTextChanged(long ptr); private static native void selectionChanged(long ptr); + private static native void menuOpened(long ptr); + private static native void menuClosed(long ptr); + private static native void menuItemSelected(long ptr); private Accessible accessible; @@ -111,16 +117,45 @@ public void propertyChange(PropertyChangeEvent e) { String name = e.getPropertyName(); if ( ptr != 0 ) { + Object newValue = e.getNewValue(); + Object oldValue = e.getOldValue(); if (name.compareTo(ACCESSIBLE_CARET_PROPERTY) == 0) { selectedTextChanged(ptr); } else if (name.compareTo(ACCESSIBLE_TEXT_PROPERTY) == 0 ) { valueChanged(ptr); } else if (name.compareTo(ACCESSIBLE_SELECTION_PROPERTY) == 0 ) { selectionChanged(ptr); - } else if (name.compareTo(ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0 ) { - Object nv = e.getNewValue(); - if (nv instanceof AccessibleContext) { - activeDescendant = (AccessibleContext)nv; + } else if (name.compareTo(ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0 ) { + if (newValue instanceof AccessibleContext) { + activeDescendant = (AccessibleContext)newValue; + } + } else if (name.compareTo(ACCESSIBLE_STATE_PROPERTY) == 0) { + AccessibleContext thisAC = accessible.getAccessibleContext(); + AccessibleRole thisRole = thisAC.getAccessibleRole(); + Accessible parentAccessible = thisAC.getAccessibleParent(); + AccessibleRole parentRole = null; + if (parentAccessible != null) { + parentRole = parentAccessible.getAccessibleContext().getAccessibleRole(); + } + // At least for now don't handle combo box menu state changes. + // This may change when later fixing issues which currently + // exist for combo boxes, but for now the following is only + // for JPopupMenus, not for combobox menus. + if (parentRole != AccessibleRole.COMBO_BOX) { + if (thisRole == AccessibleRole.POPUP_MENU) { + if ( newValue != null && + ((AccessibleState)newValue) == AccessibleState.VISIBLE ) { + menuOpened(ptr); + } else if ( oldValue != null && + ((AccessibleState)oldValue) == AccessibleState.VISIBLE ) { + menuClosed(ptr); + } + } else if (thisRole == AccessibleRole.MENU_ITEM) { + if ( newValue != null && + ((AccessibleState)newValue) == AccessibleState.FOCUSED ) { + menuItemSelected(ptr); + } + } } } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java Fri Nov 11 16:44:36 2016 +0100 @@ -97,7 +97,7 @@ int absY = locationOnScreen.y + y; responder.handleScrollEvent(x, y, absX, absY, modifierFlags, deltaX, - deltaY); + deltaY, NSEvent.SCROLL_PHASE_UNSUPPORTED); } public void handleKeyEvent(int eventType, int modifierFlags, String characters, diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java Fri Nov 11 16:44:36 2016 +0100 @@ -44,6 +44,8 @@ private final PlatformEventNotifier eventNotifier; private final boolean isNpapiCallback; private int lastKeyPressCode = KeyEvent.VK_UNDEFINED; + private final DeltaAccumulator deltaAccumulatorX = new DeltaAccumulator(); + private final DeltaAccumulator deltaAccumulatorY = new DeltaAccumulator(); CPlatformResponder(final PlatformEventNotifier eventNotifier, final boolean isNpapiCallback) { @@ -89,37 +91,37 @@ */ void handleScrollEvent(final int x, final int y, final int absX, final int absY, final int modifierFlags, - final double deltaX, final double deltaY) { + final double deltaX, final double deltaY, + final int scrollPhase) { int jmodifiers = NSEvent.nsToJavaModifiers(modifierFlags); final boolean isShift = (jmodifiers & InputEvent.SHIFT_DOWN_MASK) != 0; + int roundDeltaX = deltaAccumulatorX.getRoundedDelta(deltaX, scrollPhase); + int roundDeltaY = deltaAccumulatorY.getRoundedDelta(deltaY, scrollPhase); + // Vertical scroll. - if (!isShift && deltaY != 0.0) { - dispatchScrollEvent(x, y, absX, absY, jmodifiers, deltaY); + if (!isShift && (deltaY != 0.0 || roundDeltaY != 0)) { + dispatchScrollEvent(x, y, absX, absY, jmodifiers, roundDeltaY, deltaY); } // Horizontal scroll or shirt+vertical scroll. final double delta = isShift && deltaY != 0.0 ? deltaY : deltaX; - if (delta != 0.0) { + final int roundDelta = isShift && roundDeltaY != 0 ? roundDeltaY : roundDeltaX; + if (delta != 0.0 || roundDelta != 0) { jmodifiers |= InputEvent.SHIFT_DOWN_MASK; - dispatchScrollEvent(x, y, absX, absY, jmodifiers, delta); + dispatchScrollEvent(x, y, absX, absY, jmodifiers, roundDelta, delta); } } private void dispatchScrollEvent(final int x, final int y, final int absX, final int absY, final int modifiers, - final double delta) { + final int roundDelta, final double delta) { final long when = System.currentTimeMillis(); final int scrollType = MouseWheelEvent.WHEEL_UNIT_SCROLL; final int scrollAmount = 1; - int wheelRotation = (int) delta; - int signum = (int) Math.signum(delta); - if (signum * delta < 1) { - wheelRotation = signum; - } // invert the wheelRotation for the peer eventNotifier.notifyMouseWheelEvent(when, x, y, absX, absY, modifiers, scrollType, scrollAmount, - -wheelRotation, -delta, null); + -roundDelta, -delta, null); } /** @@ -260,4 +262,46 @@ void handleWindowFocusEvent(boolean gained, LWWindowPeer opposite) { eventNotifier.notifyActivation(gained, opposite); } + + static class DeltaAccumulator { + + static final double MIN_THRESHOLD = 0.1; + static final double MAX_THRESHOLD = 0.5; + double accumulatedDelta; + + int getRoundedDelta(double delta, int scrollPhase) { + + int roundDelta = (int) Math.round(delta); + + if (scrollPhase == NSEvent.SCROLL_PHASE_UNSUPPORTED) { // mouse wheel + if (roundDelta == 0 && delta != 0) { + roundDelta = delta > 0 ? 1 : -1; + } + } else { // trackpad + boolean begin = scrollPhase == NSEvent.SCROLL_PHASE_BEGAN; + boolean end = scrollPhase == NSEvent.SCROLL_MASK_PHASE_ENDED + || scrollPhase == NSEvent.SCROLL_MASK_PHASE_CANCELLED; + + if (begin) { + accumulatedDelta = 0; + } + + accumulatedDelta += delta; + + double absAccumulatedDelta = Math.abs(accumulatedDelta); + if (absAccumulatedDelta > MAX_THRESHOLD) { + roundDelta = (int) Math.round(accumulatedDelta); + accumulatedDelta -= roundDelta; + } + + if (end) { + if (roundDelta == 0 && absAccumulatedDelta > MIN_THRESHOLD) { + roundDelta = accumulatedDelta > 0 ? 1 : -1; + } + } + } + + return roundDelta; + } + } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformView.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformView.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformView.java Fri Nov 11 16:44:36 2016 +0100 @@ -194,7 +194,8 @@ if (event.getType() == CocoaConstants.NSScrollWheel) { responder.handleScrollEvent(x, y, absX, absY, event.getModifierFlags(), - event.getScrollDeltaX(), event.getScrollDeltaY()); + event.getScrollDeltaX(), event.getScrollDeltaY(), + event.getScrollPhase()); } else { responder.handleMouseEvent(event.getType(), event.getModifierFlags(), event.getButtonNumber(), event.getClickCount(), x, y, diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java Fri Nov 11 16:44:36 2016 +0100 @@ -178,12 +178,6 @@ return; } - // See if this has an NSPrintInfo in it. - NSPrintInfo nsPrintInfo = (NSPrintInfo)attributes.get(NSPrintInfo.class); - if (nsPrintInfo != null) { - fNSPrintInfo = nsPrintInfo.getValue(); - } - PageRanges pageRangesAttr = (PageRanges)attributes.get(PageRanges.class); if (isSupportedValue(pageRangesAttr, attributes)) { SunPageSelection rangeSelect = (SunPageSelection)attributes.get(SunPageSelection.class); @@ -563,8 +557,11 @@ @Override protected void finalize() { - if (fNSPrintInfo != -1) { - dispose(fNSPrintInfo); + synchronized (fNSPrintInfoLock) { + if (fNSPrintInfo != -1) { + dispose(fNSPrintInfo); + } + fNSPrintInfo = -1; } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSEvent.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSEvent.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSEvent.java Fri Nov 11 16:44:36 2016 +0100 @@ -32,6 +32,13 @@ * JDK functionality. */ final class NSEvent { + + static final int SCROLL_PHASE_UNSUPPORTED = 1; + static final int SCROLL_PHASE_BEGAN = 2; + static final int SCROLL_PHASE_CONTINUED = 3; + static final int SCROLL_MASK_PHASE_CANCELLED = 4; + static final int SCROLL_MASK_PHASE_ENDED = 5; + private int type; private int modifierFlags; @@ -42,6 +49,7 @@ private int y; private double scrollDeltaY; private double scrollDeltaX; + private int scrollPhase; private int absX; private int absY; @@ -62,7 +70,7 @@ // Called from native NSEvent(int type, int modifierFlags, int clickCount, int buttonNumber, int x, int y, int absX, int absY, - double scrollDeltaY, double scrollDeltaX) { + double scrollDeltaY, double scrollDeltaX, int scrollPhase) { this.type = type; this.modifierFlags = modifierFlags; this.clickCount = clickCount; @@ -73,6 +81,7 @@ this.absY = absY; this.scrollDeltaY = scrollDeltaY; this.scrollDeltaX = scrollDeltaX; + this.scrollPhase = scrollPhase; } int getType() { @@ -107,6 +116,10 @@ return scrollDeltaX; } + int getScrollPhase() { + return scrollPhase; + } + int getAbsX() { return absX; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSPrintInfo.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSPrintInfo.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.lwawt.macosx; - - -import java.io.*; -import javax.print.attribute.*; - -@SuppressWarnings("serial") // JDK implementation class -public final class NSPrintInfo implements PrintJobAttribute, PrintRequestAttribute, Serializable, Cloneable { - - private long fNSPrintInfo; - - public NSPrintInfo(long nsPrintInfo) { - fNSPrintInfo = nsPrintInfo; - } - - public long getValue() { - return fNSPrintInfo; - } - - public boolean equals(Object object) { - return (object != null && object instanceof NSPrintInfo && fNSPrintInfo == ((NSPrintInfo)object).fNSPrintInfo); - } - - public int hashCode() { - return (int)fNSPrintInfo; - } - - public String toString() { - return "" + fNSPrintInfo; - } - - public Class getCategory() { - return NSPrintInfo.class; - } - - public String getName() { - return "nsPrintInfo"; - } -} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m Fri Nov 11 16:44:36 2016 +0100 @@ -383,7 +383,7 @@ } static JNF_CLASS_CACHE(jc_NSEvent, "sun/lwawt/macosx/NSEvent"); - static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IIIIIIIIDD)V"); + static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IIIIIIIIDDI)V"); jobject jEvent = JNFNewObject(env, jctor_NSEvent, [event type], [event modifierFlags], @@ -392,7 +392,8 @@ (jint)localPoint.x, (jint)localPoint.y, (jint)absP.x, (jint)absP.y, [event deltaY], - [event deltaX]); + [event deltaX], + [AWTToolkit scrollStateWithEvent: event]); CHECK_NULL(jEvent); static JNF_CLASS_CACHE(jc_PlatformView, "sun/lwawt/macosx/CPlatformView"); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m Fri Nov 11 16:44:36 2016 +0100 @@ -317,7 +317,7 @@ [self setPropertiesForStyleBits:styleBits mask:MASK(_METHOD_PROP_BITMASK)]; if (IS(self.styleBits, IS_POPUP)) { - [self.nsWindow setCollectionBehavior:(1 << 8) /*NSWindowCollectionBehaviorFullScreenAuxiliary*/]; + [self.nsWindow setCollectionBehavior:(1 << 8) /*NSWindowCollectionBehaviorFullScreenAuxiliary*/]; } return self; @@ -330,7 +330,7 @@ // returns id for the topmost window under mouse + (NSInteger) getTopmostWindowUnderMouseID { NSInteger result = -1; - + NSRect screenRect = [[NSScreen mainScreen] frame]; NSPoint nsMouseLocation = [NSEvent mouseLocation]; CGPoint cgMouseLocation = CGPointMake(nsMouseLocation.x, screenRect.size.height - nsMouseLocation.y); @@ -433,18 +433,18 @@ // Tests wheather the corresponding Java paltform window is visible or not + (BOOL) isJavaPlatformWindowVisible:(NSWindow *)window { BOOL isVisible = NO; - + if ([AWTWindow isAWTWindow:window] && [window delegate] != nil) { AWTWindow *awtWindow = (AWTWindow *)[window delegate]; [AWTToolkit eventCountPlusPlus]; - + JNIEnv *env = [ThreadUtilities getJNIEnv]; jobject platformWindow = [awtWindow.javaPlatformWindow jObjectWithEnv:env]; if (platformWindow != NULL) { static JNF_MEMBER_CACHE(jm_isVisible, jc_CPlatformWindow, "isVisible", "()Z"); isVisible = JNFCallBooleanMethod(env, platformWindow, jm_isVisible) == JNI_TRUE ? YES : NO; (*env)->DeleteLocalRef(env, platformWindow); - + } } return isVisible; @@ -577,7 +577,9 @@ - (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)newFrame { - return [self standardFrame]; + return NSEqualSizes(NSZeroSize, [self standardFrame].size) + ? newFrame + : [self standardFrame]; } // Hides/shows window's childs during iconify/de-iconify operation @@ -1085,17 +1087,17 @@ jdouble width, jdouble height) { JNF_COCOA_ENTER(env); - + NSRect jrect = NSMakeRect(originX, originY, width, height); - + NSWindow *nsWindow = OBJC(windowPtr); [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ - + NSRect rect = ConvertNSScreenRect(NULL, jrect); AWTWindow *window = (AWTWindow*)[nsWindow delegate]; window.standardFrame = rect; }]; - + JNF_COCOA_EXIT(env); } @@ -1366,7 +1368,7 @@ } else { [JNFException raise:env as:kIllegalArgumentException reason:"unknown event type"]; } - + JNF_COCOA_EXIT(env); } @@ -1476,7 +1478,7 @@ if (CGDisplayRelease(aID) == kCGErrorSuccess) { NSUInteger styleMask = [AWTWindow styleMaskForStyleBits:window.styleBits]; - [nsWindow setStyleMask:styleMask]; + [nsWindow setStyleMask:styleMask]; [nsWindow setLevel: window.preFullScreenLevel]; // GraphicsDevice takes care of restoring pre full screen bounds diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobotKeyCode.m --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobotKeyCode.m Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobotKeyCode.m Fri Nov 11 16:44:36 2016 +0100 @@ -45,7 +45,7 @@ self = [super init]; if (nil != self) { - javaToMacKeyMap = [NSDictionary dictionaryWithObjectsAndKeys : + self.javaToMacKeyMap = [NSDictionary dictionaryWithObjectsAndKeys : [NSNumber numberWithInt : OSX_Delete], [NSNumber numberWithInt : java_awt_event_KeyEvent_VK_BACK_SPACE], [NSNumber numberWithInt : OSX_kVK_Tab], [NSNumber numberWithInt : java_awt_event_KeyEvent_VK_TAB], [NSNumber numberWithInt : OSX_kVK_Return], [NSNumber numberWithInt : java_awt_event_KeyEvent_VK_ENTER], diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m Fri Nov 11 16:44:36 2016 +0100 @@ -139,9 +139,9 @@ jint clickCount; clickCount = [event clickCount]; - + static JNF_CLASS_CACHE(jc_NSEvent, "sun/lwawt/macosx/NSEvent"); - static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IIIIIIIIDD)V"); + static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IIIIIIIIDDI)V"); jobject jEvent = JNFNewObject(env, jctor_NSEvent, [event type], [event modifierFlags], @@ -150,7 +150,8 @@ (jint)localPoint.x, (jint)localPoint.y, (jint)absP.x, (jint)absP.y, [event deltaY], - [event deltaX]); + [event deltaX], + [AWTToolkit scrollStateWithEvent: event]); CHECK_NULL(jEvent); static JNF_CLASS_CACHE(jc_TrayIcon, "sun/lwawt/macosx/CTrayIcon"); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m Fri Nov 11 16:44:36 2016 +0100 @@ -66,7 +66,6 @@ static JNF_MEMBER_CACHE(jf_ptr, sjc_CAccessible, "ptr", "J"); static JNF_STATIC_MEMBER_CACHE(sjm_getCAccessible, sjc_CAccessible, "getCAccessible", "(Ljavax/accessibility/Accessible;)Lsun/lwawt/macosx/CAccessible;"); - static jobject sAccessibilityClass = NULL; // sAttributeNamesForRoleCache holds the names of the attributes to which each java @@ -213,6 +212,24 @@ NSAccessibilityPostNotification(self, NSAccessibilitySelectedChildrenChangedNotification); } +- (void)postMenuOpened +{ + AWT_ASSERT_APPKIT_THREAD; + NSAccessibilityPostNotification(self, (NSString *)kAXMenuOpenedNotification); +} + +- (void)postMenuClosed +{ + AWT_ASSERT_APPKIT_THREAD; + NSAccessibilityPostNotification(self, (NSString *)kAXMenuClosedNotification); +} + +- (void)postMenuItemSelected +{ + AWT_ASSERT_APPKIT_THREAD; + NSAccessibilityPostNotification(self, (NSString *)kAXMenuItemSelectedNotification); +} + - (BOOL)isEqual:(id)anObject { if (![anObject isKindOfClass:[self class]]) return NO; @@ -278,8 +295,7 @@ + (jobject) getCAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env { if (JNFIsInstanceOf(env, jaccessible, &sjc_CAccessible)) { return jaccessible; - } - else if (JNFIsInstanceOf(env, jaccessible, &sjc_Accessible)) { + } else if (JNFIsInstanceOf(env, jaccessible, &sjc_Accessible)) { return JNFCallStaticObjectMethod(env, sjm_getCAccessible, jaccessible); } return NULL; @@ -368,6 +384,14 @@ // must init freshly -alloc'd object [newChild initWithParent:parent withEnv:env withAccessible:jCAX withIndex:index withView:view withJavaRole:javaRole]; // must init new instance + // If creating a JPopupMenu (not a combobox popup list) need to fire menuOpened. + // This is the only way to know if the menu is opening; visible state change + // can't be caught because the listeners are not set up in time. + if ( [javaRole isEqualToString:@"popupmenu"] && + ![[parent javaRole] isEqualToString:@"combobox"] ) { + [newChild postMenuOpened]; + } + // must hard retain pointer poked into Java object [newChild retain]; JNFSetLongField(env, jCAX, jf_ptr, ptr_to_jlong(newChild)); @@ -634,6 +658,15 @@ return moreNames; } } + // popupmenu's return values not selected children + if ( [javaRole isEqualToString:@"popupmenu"] && + ![[[self parent] javaRole] isEqualToString:@"combobox"] ) { + NSMutableArray *moreNames = + [[NSMutableArray alloc] initWithCapacity: [names count] + 1]; + [moreNames addObjectsFromArray: names]; + [moreNames addObject:NSAccessibilityValueAttribute]; + return moreNames; + } return names; } // end @synchronized @@ -707,6 +740,7 @@ return value; } + - (BOOL)accessibilityIsChildrenAttributeSettable { return NO; @@ -939,6 +973,13 @@ if (fNSRole == nil) { NSString *javaRole = [self javaRole]; fNSRole = [sRoles objectForKey:javaRole]; + // The sRoles NSMutableDictionary maps popupmenu to Mac's popup button. + // JComboBox behavior currently relies on this. However this is not the + // proper mapping for a JPopupMenu so fix that. + if ( [javaRole isEqualToString:@"popupmenu"] && + ![[[self parent] javaRole] isEqualToString:@"combobox"] ) { + fNSRole = NSAccessibilityMenuRole; + } if (fNSRole == nil) { // this component has assigned itself a custom AccessibleRole not in the sRoles array fNSRole = javaRole; @@ -947,6 +988,7 @@ } return fNSRole; } + - (BOOL)accessibilityIsRoleAttributeSettable { return NO; @@ -1046,8 +1088,7 @@ - (NSString *)accessibilitySubroleAttribute { NSString *value = nil; - if ([[self javaRole] isEqualToString:@"passwordtext"]) - { + if ([[self javaRole] isEqualToString:@"passwordtext"]) { value = NSAccessibilitySecureTextFieldSubrole; } /* @@ -1123,6 +1164,45 @@ JNIEnv* env = [ThreadUtilities getJNIEnv]; + // Need to handle popupmenus differently. + // + // At least for now don't handle combo box menus. + // This may change when later fixing issues which currently + // exist for combo boxes, but for now the following is only + // for JPopupMenus, not for combobox menus. + id parent = [self parent]; + if ( [[self javaRole] isEqualToString:@"popupmenu"] && + ![[parent javaRole] isEqualToString:@"combobox"] ) { + NSArray *children = + [JavaComponentAccessibility childrenOfParent:self + withEnv:env + withChildrenCode:JAVA_AX_ALL_CHILDREN + allowIgnored:YES]; + if ([children count] > 0) { + // handle case of AXMenuItem + // need to ask menu what is selected + NSArray *selectedChildrenOfMenu = + [self accessibilitySelectedChildrenAttribute]; + JavaComponentAccessibility *selectedMenuItem = + [selectedChildrenOfMenu objectAtIndex:0]; + if (selectedMenuItem != nil) { + jobject itemValue = + JNFCallStaticObjectMethod( env, + sjm_getAccessibleName, + selectedMenuItem->fAccessible, + selectedMenuItem->fComponent ); // AWT_THREADING Safe (AWTRunLoop) + if (itemValue == NULL) { + return nil; + } + NSString* itemString = JNFJavaToNSString(env, itemValue); + (*env)->DeleteLocalRef(env, itemValue); + return itemString; + } else { + return nil; + } + } + } + // ask Java for the component's accessibleValue. In java, the "accessibleValue" just means a numerical value // a text value is taken care of in JavaTextAccessibility @@ -1345,6 +1425,54 @@ /* * Class: sun_lwawt_macosx_CAccessible + * Method: menuOpened + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuOpened +(JNIEnv *env, jclass jklass, jlong element) +{ +JNF_COCOA_ENTER(env); + [ThreadUtilities performOnMainThread:@selector(postMenuOpened) + on:(JavaComponentAccessibility *)jlong_to_ptr(element) + withObject:nil + waitUntilDone:NO]; +JNF_COCOA_EXIT(env); +} + +/* + * Class: sun_lwawt_macosx_CAccessible + * Method: menuClosed + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuClosed +(JNIEnv *env, jclass jklass, jlong element) +{ +JNF_COCOA_ENTER(env); + [ThreadUtilities performOnMainThread:@selector(postMenuClosed) + on:(JavaComponentAccessibility *)jlong_to_ptr(element) + withObject:nil + waitUntilDone:NO]; +JNF_COCOA_EXIT(env); +} + +/* + * Class: sun_lwawt_macosx_CAccessible + * Method: menuItemSelected + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuItemSelected +(JNIEnv *env, jclass jklass, jlong element) +{ +JNF_COCOA_ENTER(env); + [ThreadUtilities performOnMainThread:@selector(postMenuItemSelected) + on:(JavaComponentAccessibility *)jlong_to_ptr(element) + withObject:nil + waitUntilDone:NO]; +JNF_COCOA_EXIT(env); +} + +/* + * Class: sun_lwawt_macosx_CAccessible * Method: unregisterFromCocoaAXSystem * Signature: (I)V */ diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.h --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.h Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.h Fri Nov 11 16:44:36 2016 +0100 @@ -41,6 +41,7 @@ @interface AWTToolkit : NSObject { } + (long) getEventCount; + (void) eventCountPlusPlus; ++ (jint) scrollStateWithEvent: (NSEvent*) event; @end /* diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m Fri Nov 11 16:44:36 2016 +0100 @@ -43,6 +43,13 @@ #import +// SCROLL PHASE STATE +#define SCROLL_PHASE_UNSUPPORTED 1 +#define SCROLL_PHASE_BEGAN 2 +#define SCROLL_PHASE_CONTINUED 3 +#define SCROLL_PHASE_CANCELLED 4 +#define SCROLL_PHASE_ENDED 5 + int gNumberOfButtons; jint* gButtonDownMasks; @@ -72,6 +79,23 @@ eventCount++; } ++ (jint) scrollStateWithEvent: (NSEvent*) event { + + if ([event type] != NSScrollWheel) { + return 0; + } + + NSEventPhase phase = [event phase]; + NSEventPhase momentumPhase = [event momentumPhase]; + + if (!phase && !momentumPhase) return SCROLL_PHASE_UNSUPPORTED; + switch (phase) { + case NSEventPhaseBegan: return SCROLL_PHASE_BEGAN; + case NSEventPhaseCancelled: return SCROLL_PHASE_CANCELLED; + case NSEventPhaseEnded: return SCROLL_PHASE_ENDED; + default: return SCROLL_PHASE_CONTINUED; + } +} @end diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h Fri Nov 11 16:44:36 2016 +0100 @@ -44,6 +44,8 @@ SD_Fill, SD_EOFill, SD_Shade, + SD_LinearGradient, + SD_RadialGradient, SD_Pattern, SD_Image, SD_Text, @@ -65,6 +67,17 @@ }; typedef struct _stateShadingInfo StateShadingInfo; +struct _stateGradientInfo +{ + CGPoint start; + CGPoint end; + CGFloat radius; + CGFloat* colordata; + CGFloat* fractionsdata; + jint fractionsLength; +}; +typedef struct _stateGradientInfo StateGradientInfo; + struct _statePatternInfo { CGFloat tx; @@ -122,6 +135,7 @@ // its callees. StateShadingInfo* shadingInfo; // tracks shading and its parameters + StateGradientInfo* gradientInfo; // tracks gradient and its parameters StatePatternInfo* patternInfo; // tracks pattern and its parameters StateGraphicsInfo graphicsStateInfo; // tracks other graphics state diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.m --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.m Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.m Fri Nov 11 16:44:36 2016 +0100 @@ -268,9 +268,105 @@ free(info); } +static inline void contextQuartzLinearGradientPath(QuartzSDOps* qsdo) +{ + +PRINT(" contextQuartzLinearGradientPath"); + + CGContextRef cgRef = qsdo->cgRef; + StateGradientInfo *gradientInfo = qsdo->gradientInfo; + + CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + size_t num_locations = gradientInfo->fractionsLength; + CGFloat *locations = (CGFloat *) malloc(sizeof(CGFloat) * num_locations); + int i = 0; + size_t component_size = num_locations * 4; + CGFloat components[component_size]; + CGGradientRef gradient = NULL; + + for (int i = 0; i < num_locations; i++) { + locations[i] = gradientInfo->fractionsdata[i]; +//fprintf(stderr, "locations[%d] %f\n", i, locations[i]); + } + for (i = 0; i < component_size; i++) { + components[i] = gradientInfo->colordata[i]; +//fprintf(stderr, "components[%d] %f, gradientInfo->colordata[%d] %f\n", +// i, components[i], i, gradientInfo->colordata[i]); + } + CGContextSaveGState(cgRef); + gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, num_locations); +//fprintf(stderr, "gradientInfo->start.x %f, gradientInfo->start.y %f\n", +// gradientInfo->start.x, gradientInfo->start.y); +//fprintf(stderr, "gradientInfo->end.x %f, gradientInfo->end.y %f\n", +// gradientInfo->end.x, gradientInfo->end.y); + if (qsdo->isEvenOddFill) { + CGContextEOClip(cgRef); + } else { + CGContextClip(cgRef); + } + CGContextDrawLinearGradient(cgRef, gradient, gradientInfo->start, gradientInfo->end, kCGGradientDrawsAfterEndLocation); + + CGContextRestoreGState(cgRef); + CGColorSpaceRelease(colorspace); + CGGradientRelease(gradient); + free(locations); + free(gradientInfo->colordata); + free(gradientInfo->fractionsdata); +} + +static inline void contextQuartzRadialGradientPath(QuartzSDOps* qsdo) +{ + +PRINT(" contextQuartzRadialGradientPath"); + + CGContextRef cgRef = qsdo->cgRef; + StateGradientInfo *gradientInfo = qsdo->gradientInfo; + + CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + size_t num_locations = gradientInfo->fractionsLength; + CGFloat *locations = (CGFloat *) malloc(sizeof(CGFloat) * num_locations); + int i = 0; + size_t component_size = num_locations * 4; + CGFloat components[component_size]; + CGGradientRef gradient = NULL; + CGFloat startRadius = gradientInfo->radius; + CGFloat endRadius = gradientInfo->radius; + + for (int i = 0; i < num_locations; i++) { + locations[i] = gradientInfo->fractionsdata[i]; +//fprintf(stderr, "locations[%d] %f\n", i, locations[i]); + } + for (i = 0; i < component_size; i++) { + components[i] = gradientInfo->colordata[i]; +//fprintf(stderr, "components[%d] %f, gradientInfo->colordata[%d] %f\n", +// i, components[i], i, gradientInfo->colordata[i]); + } + CGContextSaveGState(cgRef); + gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, num_locations); +//fprintf(stderr, "gradientInfo->start.x %f, gradientInfo->start.y %f\n", +// gradientInfo->start.x, gradientInfo->start.y); +//fprintf(stderr, "gradientInfo->end.x %f, gradientInfo->end.y %f\n", +// gradientInfo->end.x, gradientInfo->end.y); + if (qsdo->isEvenOddFill) { + CGContextEOClip(cgRef); + } else { + CGContextClip(cgRef); + } +//fprintf(stderr, "gradientInfo->startRadius %f, gradientInfo->endRadius %f\n",startRadius,endRadius); + CGContextDrawRadialGradient(cgRef, gradient, gradientInfo->start, 0, gradientInfo->end, endRadius, kCGGradientDrawsAfterEndLocation); + + CGContextRestoreGState(cgRef); + CGColorSpaceRelease(colorspace); + CGGradientRelease(gradient); + free(locations); + free(gradientInfo->colordata); + free(gradientInfo->fractionsdata); +} + static inline void contextGradientPath(QuartzSDOps* qsdo) { PRINT(" ContextGradientPath") + CGContextRef cgRef = qsdo->cgRef; StateShadingInfo* shadingInfo = qsdo->shadingInfo; @@ -827,6 +923,81 @@ qsdo->renderType = renderType; } +void setupGradient(JNIEnv *env, QuartzSDOps* qsdo, jfloat* javaFloatGraphicsStates) +{ + static const CGFloat kColorConversionMultiplier = 1.0f/255.0f; + qsdo->gradientInfo = (StateGradientInfo*)malloc(sizeof(StateGradientInfo)); + if (qsdo->gradientInfo == NULL) + { + [JNFException raise:env as:kOutOfMemoryError reason:"Failed to malloc memory for gradient paint"]; + } + + qsdo->graphicsStateInfo.simpleStroke = NO; + qsdo->graphicsStateInfo.simpleColor = NO; + + qsdo->gradientInfo->start.x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorx1Index]; + qsdo->gradientInfo->start.y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColory1Index]; + qsdo->gradientInfo->end.x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorx2Index]; + qsdo->gradientInfo->end.y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColory2Index]; + + jobject colorArray = ((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kColorArrayIndex)); + if (colorArray != NULL) + { + jint length = (*env)->GetArrayLength(env, colorArray); +//fprintf(stderr, "length %d\n", length); + + jint* jcolorData = (jint*)(*env)->GetPrimitiveArrayCritical(env, colorArray, NULL); + CGFloat* colors= (CGFloat*)calloc(0, sizeof(CGFloat)*length); + if (jcolorData != NULL) + { + jint i; + for (i=0; iReleasePrimitiveArrayCritical(env, colorArray, jcolorData, 0); + qsdo->gradientInfo->colordata = (CGFloat*)calloc(0, sizeof(CGFloat)*4*length); + for (int i = 0; i < length; i++) + { + jint c1 = colors[i]; +//fprintf(stderr, "c1 %x\n", c1); + qsdo->gradientInfo->colordata[i*4] = ((c1>>16)&0xff)*kColorConversionMultiplier; +//fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4, qsdo->gradientInfo->colordata[i*4]); + + qsdo->gradientInfo->colordata[i*4+1] = ((c1>>8)&0xff)*kColorConversionMultiplier; +//fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4+1, qsdo->gradientInfo->colordata[i*4+1]); + + qsdo->gradientInfo->colordata[i*4+2] = ((c1>>0)&0xff)*kColorConversionMultiplier; +//fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4+2, qsdo->gradientInfo->colordata[i*4+2]); + + qsdo->gradientInfo->colordata[i*4+3] = ((c1>>24)&0xff)*kColorConversionMultiplier; +//fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4+3, qsdo->gradientInfo->colordata[i*4+3]); + } + free(colors); + } + jobject fractionsArray = ((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kFractionsArrayIndex)); + if (fractionsArray != NULL) + { + jint length = (*env)->GetArrayLength(env, fractionsArray); +//fprintf(stderr, "fractions length %d\n", length); + qsdo->gradientInfo->fractionsLength = length; + + jfloat* jfractionsData = (jfloat*)(*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL); + if (jfractionsData != NULL) + { + qsdo->gradientInfo->fractionsdata = (CGFloat *)malloc(sizeof(CGFloat) *length); + jint i; + for (i=0; igradientInfo->fractionsdata[i] = jfractionsData[i]; +//fprintf(stderr, "jfrationsData[%d] %f, qsdo->gradientInfo->fractionsdata[%d] = %f\n", i, jfractionsData[i], i, qsdo->gradientInfo->fractionsdata[i]); + } + (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, jfractionsData, 0); + } + } +} + SDRenderType SetUpPaint(JNIEnv *env, QuartzSDOps *qsdo, SDRenderType renderType) { CGContextRef cgRef = qsdo->cgRef; @@ -898,6 +1069,21 @@ break; } + case sun_java2d_OSXSurfaceData_kColorLinearGradient: + { + renderType = SD_LinearGradient; + setupGradient(env, qsdo, javaFloatGraphicsStates); + break; + } + + case sun_java2d_OSXSurfaceData_kColorRadialGradient: + { + renderType = SD_RadialGradient; + setupGradient(env, qsdo, javaFloatGraphicsStates); + qsdo->gradientInfo->radius = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kRadiusIndex]; + break; + } + case sun_java2d_OSXSurfaceData_kColorTexture: { qsdo->patternInfo = (StatePatternInfo*)malloc(sizeof(StatePatternInfo)); @@ -1076,11 +1262,24 @@ } break; + case SD_LinearGradient: + if (CGContextIsPathEmpty(qsdo->cgRef) == 0) + { + contextQuartzLinearGradientPath(qsdo); + } + break; + + case SD_RadialGradient: + if (CGContextIsPathEmpty(qsdo->cgRef) == 0) + { + contextQuartzRadialGradientPath(qsdo); + } + break; + case SD_Pattern: if (CGContextIsPathEmpty(qsdo->cgRef) == 0) { - //TODO:BG - //contextTexturePath(env, qsdo); + contextTexturePath(env, qsdo); } break; @@ -1111,4 +1310,8 @@ gradientPaintReleaseFunction(qsdo->shadingInfo); qsdo->shadingInfo = NULL; } + if (qsdo->gradientInfo != NULL) { + gradientPaintReleaseFunction(qsdo->gradientInfo); + qsdo->gradientInfo = NULL; + } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m Fri Nov 11 16:44:36 2016 +0100 @@ -193,6 +193,44 @@ return [sFontFamilyTable objectForKey:fontname]; } +static void addFont(CTFontUIFontType uiType, + NSMutableArray *allFonts, + NSMutableDictionary* fontFamilyTable) { + + CTFontRef font = CTFontCreateUIFontForLanguage(uiType, 0.0, NULL); + if (font == NULL) { + return; + } + CTFontDescriptorRef desc = CTFontCopyFontDescriptor(font); + if (desc == NULL) { + CFRelease(font); + return; + } + CFStringRef family = CTFontDescriptorCopyAttribute(desc, kCTFontFamilyNameAttribute); + if (family == NULL) { + CFRelease(desc); + CFRelease(font); + return; + } + CFStringRef name = CTFontDescriptorCopyAttribute(desc, kCTFontNameAttribute); + if (name == NULL) { + CFRelease(family); + CFRelease(desc); + CFRelease(font); + return; + } + [allFonts addObject:name]; + [fontFamilyTable setObject:family forKey:name]; +#ifdef DEBUG + NSLog(@"name is : %@", (NSString*)name); + NSLog(@"family is : %@", (NSString*)family); +#endif + CFRelease(family); + CFRelease(name); + CFRelease(desc); + CFRelease(font); +} + static NSArray* GetFilteredFonts() { @@ -227,6 +265,16 @@ } } + /* + * JavaFX registers these fonts and so JDK needs to do so as well. + * If this isn't done we will have mis-matched rendering, since + * although these may include fonts that are enumerated normally + * they also demonstrably includes fonts that are not. + */ + addFont(kCTFontUIFontSystem, allFonts, fontFamilyTable); + addFont(kCTFontUIFontEmphasizedSystem, allFonts, fontFamilyTable); + addFont(kCTFontUIFontUserFixedPitch, allFonts, fontFamilyTable); + sFilteredFonts = allFonts; sFontFamilyTable = fontFamilyTable; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m --- a/jdk/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. 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 @@ -47,6 +47,10 @@ #include #import "ThreadUtilities.h" +NSString* findScaledImageName(NSString *fileName, + NSUInteger dotIndex, + NSString *strToAppend); + static NSScreen* SplashNSScreen() { return [[NSScreen screens] objectAtIndex: 0]; @@ -134,8 +138,8 @@ } jboolean SplashGetScaledImageName(const char* jar, const char* file, - float *scaleFactor, char *scaledFile, - const size_t scaledImageLength) { + float *scaleFactor, char *scaledFile, + const size_t scaledImageLength) { *scaleFactor = 1; if(isSWTRunning()){ @@ -158,18 +162,14 @@ options:NSBackwardsSearch]; NSUInteger dotIndex = range.location; NSString *fileName2x = nil; - - if (dotIndex == NSNotFound) { - fileName2x = [fileName stringByAppendingString: @"@2x"]; - } else { - fileName2x = [fileName substringToIndex: dotIndex]; - fileName2x = [fileName2x stringByAppendingString: @"@2x"]; - fileName2x = [fileName2x stringByAppendingString: - [fileName substringFromIndex: dotIndex]]; + + fileName2x = findScaledImageName(fileName, dotIndex, @"@2x"); + if(![[NSFileManager defaultManager] + fileExistsAtPath: fileName2x]) { + fileName2x = findScaledImageName(fileName, dotIndex, @"@200pct"); } - - if ((fileName2x != nil) && (jar || [[NSFileManager defaultManager] - fileExistsAtPath: fileName2x])){ + if (jar || [[NSFileManager defaultManager] + fileExistsAtPath: fileName2x]){ if (strlen([fileName2x UTF8String]) > scaledImageLength) { [pool drain]; return JNI_FALSE; @@ -458,3 +458,16 @@ sendctl(splash, SPLASHCTL_RECONFIGURE); } +NSString* findScaledImageName(NSString *fileName, NSUInteger dotIndex, NSString *strToAppend) { + NSString *fileName2x = nil; + if (dotIndex == NSNotFound) { + fileName2x = [fileName stringByAppendingString: strToAppend]; + } else { + fileName2x = [fileName substringToIndex: dotIndex]; + fileName2x = [fileName2x stringByAppendingString: strToAppend]; + fileName2x = [fileName2x stringByAppendingString: + [fileName substringFromIndex: dotIndex]]; + } + return fileName2x; +} + diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java Fri Nov 11 16:44:36 2016 +0100 @@ -1314,7 +1314,7 @@ super(locale); this.canWriteCompressed = true; this.canWriteProgressive = true; - this.compressionTypes = new String[] {"LZW", "lzw"}; + this.compressionTypes = new String[] {"LZW"}; this.compressionType = compressionTypes[0]; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java Fri Nov 11 16:44:36 2016 +0100 @@ -298,31 +298,24 @@ public void paintIcon(Component c, Graphics g, int xo, int yo) { int w = getIconWidth(); int h = getIconHeight(); - - g.setColor(lightShadow); - g.drawLine(xo, yo, xo+w-1, yo); - g.drawLine(xo, yo+1, xo+w-3, yo+1); - g.setColor(darkShadow); - g.drawLine(xo+w-2, yo+1, xo+w-1, yo+1); + int x1 = xo + w - 1; + int y1 = yo; + int x2 = xo + w / 2; + int y2 = yo + h - 1; - for ( int x = xo+1, y = yo+2, dx = w-6; y+1 < yo+h; y += 2 ) { - g.setColor(lightShadow); - g.drawLine(x, y, x+1, y); - g.drawLine(x, y+1, x+1, y+1); - if ( dx > 0 ) { - g.setColor(fill); - g.drawLine(x+2, y, x+1+dx, y); - g.drawLine(x+2, y+1, x+1+dx, y+1); - } - g.setColor(darkShadow); - g.drawLine(x+dx+2, y, x+dx+3, y); - g.drawLine(x+dx+2, y+1, x+dx+3, y+1); - x += 1; - dx -= 2; - } + g.setColor(fill); + g.fillPolygon(new int[]{xo, x1, x2}, new int[]{yo, y1, y2}, 3); + g.setColor(lightShadow); + g.drawLine(xo, yo, x1, y1); + g.drawLine(xo, yo + 1, x2, y2); + g.drawLine(xo, yo + 1, x1, y1 + 1); + g.drawLine(xo + 1, yo + 1, x2, y2 - 1); g.setColor(darkShadow); - g.drawLine(xo+(w/2), yo+h-1, xo+(w/2), yo+h-1); + g.drawLine(x1, y1 + 1, x2, y2); + g.drawLine(x1 - 1, y1 + 1, x2, y2 - 1); + g.drawLine(x1 - 1, y1 + 1, x1, y1 + 1); // corner + g.drawLine(x2, y2, x2, y2); // corner } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java Fri Nov 11 16:44:36 2016 +0100 @@ -249,17 +249,11 @@ if (check) { // draw check g.setColor(foreground); - g.drawLine(csize-2,1,csize-2,2); - g.drawLine(csize-3,2,csize-3,3); - g.drawLine(csize-4,3,csize-4,4); - g.drawLine(csize-5,4,csize-5,6); - g.drawLine(csize-6,5,csize-6,8); - g.drawLine(csize-7,6,csize-7,10); - g.drawLine(csize-8,7,csize-8,10); - g.drawLine(csize-9,6,csize-9,9); - g.drawLine(csize-10,5,csize-10,8); - g.drawLine(csize-11,5,csize-11,7); - g.drawLine(csize-12,6,csize-12,6); + int[] xa = {csize - 12, csize - 8, csize - 7, csize - 4, + csize - 2, csize - 2, csize - 8, csize - 10, + csize - 11}; + int[] ya = new int[]{6, 10, 10, 4, 2, 1, 7, 5, 5}; + g.fillPolygon(xa, ya, 9); } g.translate(-x, -y); g.setColor(oldColor); @@ -301,50 +295,18 @@ if (checkIn){ g.setColor(shadow); - g.drawLine(x+5,y+0,x+8,y+0); - g.drawLine(x+3,y+1,x+4,y+1); - g.drawLine(x+9,y+1,x+9,y+1); - g.drawLine(x+2,y+2,x+2,y+2); - g.drawLine(x+1,y+3,x+1,y+3); - g.drawLine(x,y+4,x,y+9); - g.drawLine(x+1,y+10,x+1,y+10); - g.drawLine(x+2,y+11,x+2,y+11); + g.drawArc(x, y, w - 1, h - 1, 45, 180); g.setColor(highlight); - g.drawLine(x+3,y+12,x+4,y+12); - g.drawLine(x+5,y+13,x+8,y+13); - g.drawLine(x+9,y+12,x+10,y+12); - g.drawLine(x+11,y+11,x+11,y+11); - g.drawLine(x+12,y+10,x+12,y+10); - g.drawLine(x+13,y+9,x+13,y+4); - g.drawLine(x+12,y+3,x+12,y+3); - g.drawLine(x+11,y+2,x+11,y+2); - g.drawLine(x+10,y+1,x+10,y+1); + g.drawArc(x, y, w - 1, h - 1, 45, -180); g.setColor(dot); - g.fillRect(x+4,y+5,6,4); - g.drawLine(x+5,y+4,x+8,y+4); - g.drawLine(x+5,y+9,x+8,y+9); + g.fillOval(x + 3, y + 3, 7, 7); } else { g.setColor(highlight); - g.drawLine(x+5,y+0,x+8,y+0); - g.drawLine(x+3,y+1,x+4,y+1); - g.drawLine(x+9,y+1,x+9,y+1); - g.drawLine(x+2,y+2,x+2,y+2); - g.drawLine(x+1,y+3,x+1,y+3); - g.drawLine(x,y+4,x,y+9); - g.drawLine(x+1,y+10,x+1,y+10); - g.drawLine(x+2,y+11,x+2,y+11); + g.drawArc(x, y, w - 1, h - 1, 45, 180); g.setColor(shadow); - g.drawLine(x+3,y+12,x+4,y+12); - g.drawLine(x+5,y+13,x+8,y+13); - g.drawLine(x+9,y+12,x+10,y+12); - g.drawLine(x+11,y+11,x+11,y+11); - g.drawLine(x+12,y+10,x+12,y+10); - g.drawLine(x+13,y+9,x+13,y+4); - g.drawLine(x+12,y+3,x+12,y+3); - g.drawLine(x+11,y+2,x+11,y+2); - g.drawLine(x+10,y+1,x+10,y+1); + g.drawArc(x, y, w - 1, h - 1, 45, -180); } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java Fri Nov 11 16:44:36 2016 +0100 @@ -117,95 +117,57 @@ switch (direction) { case NORTH: + g.setColor(fill); + g.fillPolygon(new int[]{cx, 0, s - 1}, new int[]{0, s - 1, s - 1}, 3); + g.setColor(trail); + g.drawLine(cx, 0, s - 1, s - 2); + g.drawLine(0, s - 1, s - 1, s - 1); + g.drawLine(s - 1, s - 2, s - 1, s - 1); // corner g.setColor(lead); - g.drawLine(cx, 0, cx, 0); - for (int x = cx - 1, y = 1, dx = 1; y <= s - 2; y += 2) { - g.setColor(lead); - g.drawLine(x, y, x, y); - if (y >= (s - 2)) { - g.drawLine(x, y + 1, x, y + 1); - } - g.setColor(fill); - g.drawLine(x + 1, y, x + dx, y); - if (y < (s - 2)) { - g.drawLine(x, y + 1, x + dx + 1, y + 1); - } - g.setColor(trail); - g.drawLine(x + dx + 1, y, x + dx + 1, y); - if (y >= (s - 2)) { - g.drawLine(x + 1, y + 1, x + dx + 1, y + 1); - } - dx += 2; - x -= 1; - } + g.drawLine(cx, 0, 0, s - 2); + g.drawLine(cx, 0, cx, 0); // corner + g.drawLine(0, s - 1, 0, s - 1); // corner break; case SOUTH: + g.setColor(fill); + g.fillPolygon(new int[]{0, s - 1, cx}, new int[]{1, 1, s}, 3); g.setColor(trail); - g.drawLine(cx, s, cx, s); - for (int x = cx - 1, y = s - 1, dx = 1; y >= 1; y -= 2) { - g.setColor(lead); - g.drawLine(x, y, x, y); - if (y <= 2) { - g.drawLine(x, y - 1, x + dx + 1, y - 1); - } - g.setColor(fill); - g.drawLine(x + 1, y, x + dx, y); - if (y > 2) { - g.drawLine(x, y - 1, x + dx + 1, y - 1); - } - g.setColor(trail); - g.drawLine(x + dx + 1, y, x + dx + 1, y); - - dx += 2; - x -= 1; - } + g.drawLine(s - 1, 2, cx, s); + g.drawLine(s - 1, 2, s - 1, 2); // corner + g.setColor(lead); + g.drawLine(0, 2, cx, s); + g.drawLine(0, 1, s - 1, 1); + g.drawLine(0, 1, 0, 2); + g.setColor(trail); + g.drawLine(cx, s, cx, s); // corner break; case EAST: + g.setColor(fill); + g.fillPolygon(new int[]{1, s, 1}, new int[]{0, cy, s}, 3); + g.setColor(trail); + g.drawLine(1, s, s, cy); + g.drawLine(2, s, 2, s); // corner g.setColor(lead); + g.drawLine(1, 0, 1, s); + g.drawLine(2, 0, s, cy); + g.drawLine(2, 0, 2, 0); // corner g.drawLine(s, cy, s, cy); - for (int y = cy - 1, x = s - 1, dy = 1; x >= 1; x -= 2) { - g.setColor(lead); - g.drawLine(x, y, x, y); - if (x <= 2) { - g.drawLine(x - 1, y, x - 1, y + dy + 1); - } - g.setColor(fill); - g.drawLine(x, y + 1, x, y + dy); - if (x > 2) { - g.drawLine(x - 1, y, x - 1, y + dy + 1); - } - g.setColor(trail); - g.drawLine(x, y + dy + 1, x, y + dy + 1); - - dy += 2; - y -= 1; - } break; case WEST: + g.setColor(fill); + g.fillPolygon(new int[]{0, s - 1, s - 1}, new int[]{cy, 0, s}, 3); + g.drawLine(s - 1, 0, s - 1, s); g.setColor(trail); - g.drawLine(0, cy, 0, cy); - for (int y = cy - 1, x = 1, dy = 1; x <= s - 2; x += 2) { - g.setColor(lead); - g.drawLine(x, y, x, y); - if (x >= (s - 2)) { - g.drawLine(x + 1, y, x + 1, y); - } - g.setColor(fill); - g.drawLine(x, y + 1, x, y + dy); - if (x < (s - 2)) { - g.drawLine(x + 1, y, x + 1, y + dy + 1); - } - g.setColor(trail); - g.drawLine(x, y + dy + 1, x, y + dy + 1); - if (x >= (s - 2)) { - g.drawLine(x + 1, y + 1, x + 1, y + dy + 1); - } - dy += 2; - y -= 1; - } + g.drawLine(0, cy, s - 1, s); + g.drawLine(s - 1, 0, s - 1, s); + g.setColor(lead); + g.drawLine(0, cy, s - 2, 0); + g.drawLine(s - 2, 0, s - 1, 0); // corner + g.setColor(trail); + g.drawLine(0, cy, 0, cy); // corner break; } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/com/sun/media/sound/AlawCodec.java --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AlawCodec.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AlawCodec.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. 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 @@ -30,25 +30,26 @@ import java.util.Vector; import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.spi.FormatConversionProvider; /** * A-law encodes linear data, and decodes a-law data to linear data. * * @author Kara Kytle */ -public final class AlawCodec extends SunCodec { +public final class AlawCodec extends FormatConversionProvider { /* Tables used for A-law decoding */ private static final byte[] ALAW_TABH = new byte[256]; private static final byte[] ALAW_TABL = new byte[256]; - private static final AudioFormat.Encoding[] alawEncodings = { AudioFormat.Encoding.ALAW, AudioFormat.Encoding.PCM_SIGNED }; - - private static final short seg_end [] = {0xFF, 0x1FF, 0x3FF, - 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF}; + private static final short seg_end[] = { + 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF + }; /** * Initializes the decode tables. @@ -73,13 +74,14 @@ } } + @Override + public AudioFormat.Encoding[] getSourceEncodings() { + return new Encoding[]{Encoding.ALAW, Encoding.PCM_SIGNED}; + } - /** - * Constructs a new ALAW codec object. - */ - public AlawCodec() { - - super(alawEncodings, alawEncodings); + @Override + public AudioFormat.Encoding[] getTargetEncodings() { + return getSourceEncodings(); } @Override diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. 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 @@ -562,8 +562,7 @@ @Override public Encoding[] getTargetEncodings() { - return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED, - Encoding.PCM_FLOAT }; + return getSourceEncodings(); } @Override diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 @@ -1034,6 +1034,7 @@ // $$fb part of fix for 4679187: Clip.open() throws unexpected Exceptions Toolkit.isFullySpecifiedAudioFormat(format); + Toolkit.validateBuffer(format.getFrameSize(), bufferSize); byte[] newData = new byte[bufferSize]; System.arraycopy(data, offset, newData, 0, bufferSize); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/com/sun/media/sound/PCMtoPCMCodec.java --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/PCMtoPCMCodec.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/PCMtoPCMCodec.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. 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 @@ -30,32 +30,26 @@ import java.util.Vector; import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.spi.FormatConversionProvider; /** * Converts among signed/unsigned and little/big endianness of sampled. * * @author Jan Borgersen */ -public final class PCMtoPCMCodec extends SunCodec { - - private static final AudioFormat.Encoding[] inputEncodings = { - AudioFormat.Encoding.PCM_SIGNED, - AudioFormat.Encoding.PCM_UNSIGNED, - }; +public final class PCMtoPCMCodec extends FormatConversionProvider { - private static final AudioFormat.Encoding[] outputEncodings = { - AudioFormat.Encoding.PCM_SIGNED, - AudioFormat.Encoding.PCM_UNSIGNED, - }; + @Override + public AudioFormat.Encoding[] getSourceEncodings() { + return new Encoding[]{Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED}; + } - /** - * Constructs a new PCMtoPCM codec object. - */ - public PCMtoPCMCodec() { - - super( inputEncodings, outputEncodings); + @Override + public AudioFormat.Encoding[] getTargetEncodings() { + return getSourceEncodings(); } @Override diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftMixingClip.java --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftMixingClip.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftMixingClip.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. 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 @@ -363,9 +363,7 @@ if (AudioFloatConverter.getConverter(format) == null) throw new IllegalArgumentException("Invalid format : " + format.toString()); - if (bufferSize % format.getFrameSize() != 0) - throw new IllegalArgumentException( - "Buffer size does not represent an integral number of sample frames!"); + Toolkit.validateBuffer(format.getFrameSize(), bufferSize); if (data != null) { this.data = Arrays.copyOf(data, data.length); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/com/sun/media/sound/SunCodec.java --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SunCodec.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.media.sound; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.spi.FormatConversionProvider; - -/** - * A codec can encode and/or decode audio data. It provides an - * AudioInputStream from which processed data may be read. - *

    - * Its input format represents the format of the incoming - * audio data, or the format of the data in the underlying stream. - *

    - * Its output format represents the format of the processed, outgoing - * audio data. This is the format of the data which may be read from - * the filtered stream. - * - * @author Kara Kytle - */ -abstract class SunCodec extends FormatConversionProvider { - - private final AudioFormat.Encoding[] inputEncodings; - private final AudioFormat.Encoding[] outputEncodings; - - /** - * Constructs a new codec object. - */ - SunCodec(final AudioFormat.Encoding[] inputEncodings, - final AudioFormat.Encoding[] outputEncodings) { - this.inputEncodings = inputEncodings; - this.outputEncodings = outputEncodings; - } - - @Override - public final AudioFormat.Encoding[] getSourceEncodings() { - AudioFormat.Encoding[] encodings = new AudioFormat.Encoding[inputEncodings.length]; - System.arraycopy(inputEncodings, 0, encodings, 0, inputEncodings.length); - return encodings; - } - - @Override - public final AudioFormat.Encoding[] getTargetEncodings() { - AudioFormat.Encoding[] encodings = new AudioFormat.Encoding[outputEncodings.length]; - System.arraycopy(outputEncodings, 0, encodings, 0, outputEncodings.length); - return encodings; - } -} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/com/sun/media/sound/Toolkit.java --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/Toolkit.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/Toolkit.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. 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 @@ -149,6 +149,20 @@ return (long) (((double) frames) / format.getFrameRate() * 1000000.0d); } + /** + * Throws an exception if the buffer size does not represent an integral + * number of sample frames. + */ + static void validateBuffer(final int frameSize, final int bufferSize) { + if (bufferSize % frameSize == 0) { + return; + } + throw new IllegalArgumentException(String.format( + "Buffer size (%d) does not represent an integral number of " + + "sample frames (%d)", bufferSize, frameSize)); + } + + static void isFullySpecifiedAudioFormat(AudioFormat format) { if (!format.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED) && !format.getEncoding().equals(AudioFormat.Encoding.PCM_UNSIGNED) diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/com/sun/media/sound/UlawCodec.java --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/UlawCodec.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/UlawCodec.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. 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 @@ -30,26 +30,26 @@ import java.util.Vector; import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.spi.FormatConversionProvider; /** * U-law encodes linear data, and decodes u-law data to linear data. * * @author Kara Kytle */ -public final class UlawCodec extends SunCodec { +public final class UlawCodec extends FormatConversionProvider { /* Tables used for U-law decoding */ private static final byte[] ULAW_TABH = new byte[256]; private static final byte[] ULAW_TABL = new byte[256]; - private static final AudioFormat.Encoding[] ulawEncodings = {AudioFormat.Encoding.ULAW, - AudioFormat.Encoding.PCM_SIGNED}; - - private static final short seg_end [] = {0xFF, 0x1FF, 0x3FF, - 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF}; + private static final short seg_end[] = { + 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF + }; /** * Initializes the decode tables. @@ -69,11 +69,14 @@ } } - /** - * Constructs a new ULAW codec object. - */ - public UlawCodec() { - super(ulawEncodings, ulawEncodings); + @Override + public AudioFormat.Encoding[] getSourceEncodings() { + return new Encoding[]{Encoding.ULAW, Encoding.PCM_SIGNED}; + } + + @Override + public AudioFormat.Encoding[] getTargetEncodings() { + return getSourceEncodings(); } @Override diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/java/awt/Component.java --- a/jdk/src/java.desktop/share/classes/java/awt/Component.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/java/awt/Component.java Fri Nov 11 16:44:36 2016 +0100 @@ -851,8 +851,8 @@ { comp.setGraphicsConfiguration(gc); } - public boolean requestFocus(Component comp, FocusEvent.Cause cause) { - return comp.requestFocus(cause); + public void requestFocus(Component comp, FocusEvent.Cause cause) { + comp.requestFocus(cause); } public boolean canBeFocusOwner(Component comp) { return comp.canBeFocusOwner(); @@ -7511,8 +7511,51 @@ requestFocusHelper(false, true); } - boolean requestFocus(FocusEvent.Cause cause) { - return requestFocusHelper(false, true, cause); + + /** + * Requests by the reason of {@code cause} that this Component get the input + * focus, and that this Component's top-level ancestor become the + * focused Window. This component must be displayable, focusable, visible + * and all of its ancestors (with the exception of the top-level Window) + * must be visible for the request to be granted. Every effort will be + * made to honor the request; however, in some cases it may be + * impossible to do so. Developers must never assume that this + * Component is the focus owner until this Component receives a + * FOCUS_GAINED event. + *

    + * The focus request effect may also depend on the provided + * cause value. If this request is succeed the {@code FocusEvent} + * generated in the result will receive the cause value specified as the + * argument of method. If this request is denied because this Component's + * top-level Window cannot become the focused Window, the request will be + * remembered and will be granted when the Window is later focused by the + * user. + *

    + * This method cannot be used to set the focus owner to no Component at + * all. Use {@code KeyboardFocusManager.clearGlobalFocusOwner()} + * instead. + *

    + * Because the focus behavior of this method is platform-dependent, + * developers are strongly encouraged to use + * {@code requestFocusInWindow(FocusEvent.Cause)} when possible. + * + *

    Note: Not all focus transfers result from invoking this method. As + * such, a component may receive focus without this or any of the other + * {@code requestFocus} methods of {@code Component} being invoked. + * + * @param cause the cause why the focus is requested + * @see FocusEvent + * @see FocusEvent.Cause + * @see #requestFocusInWindow(FocusEvent.Cause) + * @see java.awt.event.FocusEvent + * @see #addFocusListener + * @see #isFocusable + * @see #isDisplayable + * @see KeyboardFocusManager#clearGlobalFocusOwner + * @since 9 + */ + public void requestFocus(FocusEvent.Cause cause) { + requestFocusHelper(false, true, cause); } /** @@ -7578,9 +7621,77 @@ return requestFocusHelper(temporary, true); } - boolean requestFocus(boolean temporary, FocusEvent.Cause cause) { + /** + * Requests by the reason of {@code cause} that this {@code Component} get + * the input focus, and that this {@code Component}'s top-level ancestor + * become the focused {@code Window}. This component must be + * displayable, focusable, visible and all of its ancestors (with + * the exception of the top-level Window) must be visible for the + * request to be granted. Every effort will be made to honor the + * request; however, in some cases it may be impossible to do + * so. Developers must never assume that this component is the + * focus owner until this component receives a FOCUS_GAINED + * event. If this request is denied because this component's + * top-level window cannot become the focused window, the request + * will be remembered and will be granted when the window is later + * focused by the user. + *

    + * This method returns a boolean value. If {@code false} is returned, + * the request is guaranteed to fail. If {@code true} is + * returned, the request will succeed unless it is vetoed, or an + * extraordinary event, such as disposal of the component's peer, occurs + * before the request can be granted by the native windowing system. Again, + * while a return value of {@code true} indicates that the request is + * likely to succeed, developers must never assume that this component is + * the focus owner until this component receives a FOCUS_GAINED event. + *

    + * The focus request effect may also depend on the provided + * cause value. If this request is succeed the {FocusEvent} + * generated in the result will receive the cause value specified as the + * argument of the method. + *

    + * This method cannot be used to set the focus owner to no component at + * all. Use {@code KeyboardFocusManager.clearGlobalFocusOwner} + * instead. + *

    + * Because the focus behavior of this method is platform-dependent, + * developers are strongly encouraged to use + * {@code requestFocusInWindow} when possible. + *

    + * Every effort will be made to ensure that {@code FocusEvent}s + * generated as a + * result of this request will have the specified temporary value. However, + * because specifying an arbitrary temporary state may not be implementable + * on all native windowing systems, correct behavior for this method can be + * guaranteed only for lightweight {@code Component}s. + * This method is not intended + * for general use, but exists instead as a hook for lightweight component + * libraries, such as Swing. + *

    + * Note: Not all focus transfers result from invoking this method. As + * such, a component may receive focus without this or any of the other + * {@code requestFocus} methods of {@code Component} being invoked. + * + * @param temporary true if the focus change is temporary, + * such as when the window loses the focus; for + * more information on temporary focus changes see the + *Focus Specification + * + * @param cause the cause why the focus is requested + * @return {@code false} if the focus change request is guaranteed to + * fail; {@code true} if it is likely to succeed + * @see FocusEvent + * @see FocusEvent.Cause + * @see #addFocusListener + * @see #isFocusable + * @see #isDisplayable + * @see KeyboardFocusManager#clearGlobalFocusOwner + * @since 9 + */ + protected boolean requestFocus(boolean temporary, FocusEvent.Cause cause) { return requestFocusHelper(temporary, true, cause); } + /** * Requests that this Component get the input focus, if this * Component's top-level ancestor is already the focused @@ -7629,7 +7740,59 @@ return requestFocusHelper(false, false); } - boolean requestFocusInWindow(FocusEvent.Cause cause) { + /** + * Requests by the reason of {@code cause} that this Component get the input + * focus, if this Component's top-level ancestor is already the focused + * Window. This component must be displayable, focusable, visible + * and all of its ancestors (with the exception of the top-level + * Window) must be visible for the request to be granted. Every + * effort will be made to honor the request; however, in some + * cases it may be impossible to do so. Developers must never + * assume that this Component is the focus owner until this + * Component receives a FOCUS_GAINED event. + *

    + * This method returns a boolean value. If {@code false} is returned, + * the request is guaranteed to fail. If {@code true} is + * returned, the request will succeed unless it is vetoed, or an + * extraordinary event, such as disposal of the Component's peer, occurs + * before the request can be granted by the native windowing system. Again, + * while a return value of {@code true} indicates that the request is + * likely to succeed, developers must never assume that this Component is + * the focus owner until this Component receives a FOCUS_GAINED event. + *

    + * The focus request effect may also depend on the provided + * cause value. If this request is succeed the {@code FocusEvent} + * generated in the result will receive the cause value specified as the + * argument of the method. + *

    + * This method cannot be used to set the focus owner to no Component at + * all. Use {@code KeyboardFocusManager.clearGlobalFocusOwner()} + * instead. + *

    + * The focus behavior of this method can be implemented uniformly across + * platforms, and thus developers are strongly encouraged to use this + * method over {@code requestFocus(FocusEvent.Cause)} when possible. + * Code which relies on {@code requestFocus(FocusEvent.Cause)} may exhibit + * different focus behavior on different platforms. + * + *

    Note: Not all focus transfers result from invoking this method. As + * such, a component may receive focus without this or any of the other + * {@code requestFocus} methods of {@code Component} being invoked. + * + * @param cause the cause why the focus is requested + * @return {@code false} if the focus change request is guaranteed to + * fail; {@code true} if it is likely to succeed + * @see #requestFocus(FocusEvent.Cause) + * @see FocusEvent + * @see FocusEvent.Cause + * @see java.awt.event.FocusEvent + * @see #addFocusListener + * @see #isFocusable + * @see #isDisplayable + * @see KeyboardFocusManager#clearGlobalFocusOwner + * @since 9 + */ + public boolean requestFocusInWindow(FocusEvent.Cause cause) { return requestFocusHelper(false, false, cause); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/java/awt/DisplayMode.java --- a/jdk/src/java.desktop/share/classes/java/awt/DisplayMode.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/java/awt/DisplayMode.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. 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 @@ -142,6 +142,7 @@ /** * {@inheritDoc} */ + @Override public boolean equals(Object dm) { if (dm instanceof DisplayMode) { return equals((DisplayMode)dm); @@ -153,9 +154,20 @@ /** * {@inheritDoc} */ + @Override public int hashCode() { return getWidth() + getHeight() + getBitDepth() * 7 + getRefreshRate() * 13; } + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return getWidth() + "x" + getHeight() + "x" + + (getBitDepth() > 0 ? getBitDepth() + "bpp": "[Multi depth]") + + "@" + (getRefreshRate() > 0 ? getRefreshRate() + "Hz" : + "[Unknown refresh rate]"); + } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/java/awt/Font.java --- a/jdk/src/java.desktop/share/classes/java/awt/Font.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/java/awt/Font.java Fri Nov 11 16:44:36 2016 +0100 @@ -154,6 +154,10 @@ * associated with a font face, each differing in size, style, transform * and font features. *

    + * Glyphs may not always be rendered with the requested properties (e.g, font + * and style) due to platform limitations such as the absence of suitable + * platform fonts to implement a logical font. + *

    * The {@link GraphicsEnvironment#getAllFonts() getAllFonts} method * of the {@code GraphicsEnvironment} class returns an * array of all font faces available in the system. These font faces are diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/java/awt/SplashScreen.java --- a/jdk/src/java.desktop/share/classes/java/awt/SplashScreen.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/java/awt/SplashScreen.java Fri Nov 11 16:44:36 2016 +0100 @@ -65,6 +65,16 @@ *

      * java -splash:filename.gif Test
      * 
    + * HiDPI scaled image is also supported. + * Unscaled image name i.e. filename.gif should be passed in + * {@code manifest.mf}/{@code -splash:} option for all image types irrespective of + * HiDPI and Non-HiDPI. + * Following is the naming convention for scaled images. + * Screen scale 1.25: filename@125pct.gif + * Screen scale 1.50: filename@150pct.gif + * Screen scale 2: filename@200pct.gif and filename@2x.gif both are supported + * Screen scale 2.50: filename@250pct.gif + * Screen scale 3: filename@300pct.gif and filename@3x.gif both are supported * The command line interface has higher precedence over the manifest * setting. *

    diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataNode.java --- a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataNode.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataNode.java Fri Nov 11 16:44:36 2016 +0100 @@ -122,7 +122,7 @@ } public Node item(int index) { - if (index < 0 || index > nodes.size()) { + if (index < 0 || index >= nodes.size()) { return null; } return nodes.get(index); @@ -882,7 +882,7 @@ } private void getElementsByTagName(String name, List l) { - if (nodeName.equals(name)) { + if (nodeName.equals(name) || "*".equals(name)) { l.add(this); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/imageio/package.html --- a/jdk/src/java.desktop/share/classes/javax/imageio/package.html Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/imageio/package.html Fri Nov 11 16:44:36 2016 +0100 @@ -2,7 +2,7 @@ + + BMP + yes + yes + none + + BMP metadata format + + + + GIF + yes + yes + + GIF plug-in notes + + GIF metadata format + JPEG @@ -76,14 +95,15 @@ PNG metadata format - + - BMP + TIFF yes yes - none - - BMP metadata format + + TIFF plug-in notes + + TIFF metadata format @@ -94,16 +114,6 @@ WBMP metadata format - - - GIF - yes - yes - - GIF plug-in notes - - GIF metadata format -
    diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifGPSTagSet.java --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifGPSTagSet.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifGPSTagSet.java Fri Nov 11 16:44:36 2016 +0100 @@ -55,9 +55,7 @@ * * @see #TAG_GPS_VERSION_ID */ - public static final String GPS_VERSION_2_2 = - new String(new byte[] { '2', '2', '0', '0' }, - StandardCharsets.US_ASCII); + public static final String GPS_VERSION_2_2 = "2200"; /** * A tag indicating the North or South latitude (type ASCII, count = 2). diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java Fri Nov 11 16:44:36 2016 +0100 @@ -71,9 +71,7 @@ * * @see #TAG_EXIF_VERSION */ - public static final String EXIF_VERSION_2_1 = - new String(new byte[] { '0', '2', '1', '0' }, - StandardCharsets.US_ASCII); + public static final String EXIF_VERSION_2_1 = "0210"; /** * A value to be used with the "ExifVersion" tag to indicate Exif version @@ -82,9 +80,7 @@ * * @see #TAG_EXIF_VERSION */ - public static final String EXIF_VERSION_2_2 = - new String(new byte[] { '0', '2', '2', '0' }, - StandardCharsets.US_ASCII); + public static final String EXIF_VERSION_2_2 = "0220"; /** * A tag indicating the FlashPix version number (type UNDEFINED, diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java Fri Nov 11 16:44:36 2016 +0100 @@ -261,7 +261,7 @@ * @see TIFFDirectory * @see TIFFTag */ -public class TIFFField implements Cloneable { +public final class TIFFField implements Cloneable { private static final String[] typeNames = { null, diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java Fri Nov 11 16:44:36 2016 +0100 @@ -48,7 +48,7 @@ * * @since 9 */ -public class TIFFImageReadParam extends ImageReadParam { +public final class TIFFImageReadParam extends ImageReadParam { private List allowedTagSets = new ArrayList(4); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/FormatConversionProvider.java --- a/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/FormatConversionProvider.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/FormatConversionProvider.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ package javax.sound.sampled.spi; -import java.util.Objects; +import java.util.stream.Stream; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; @@ -81,16 +81,8 @@ * {@code false} * @throws NullPointerException if {@code sourceEncoding} is {@code null} */ - public boolean isSourceEncodingSupported(Encoding sourceEncoding) { - Objects.requireNonNull(sourceEncoding); - Encoding sourceEncodings[] = getSourceEncodings(); - - for(int i=0; iEnter key occurs. */ protected JButton defaultButton; - /** - * As of Java 2 platform v1.3 this unusable field is no longer used. - * To override the default button you should replace the Action - * in the JRootPane's ActionMap. Please refer to - * the key bindings specification for further details. - * - * @deprecated As of Java 2 platform v1.3. - * @see #defaultButton - */ - @Deprecated - protected DefaultAction defaultPressAction; - /** - * As of Java 2 platform v1.3 this unusable field is no longer used. - * To override the default button you should replace the Action - * in the JRootPane's ActionMap. Please refer to - * the key bindings specification for further details. - * - * @deprecated As of Java 2 platform v1.3. - * @see #defaultButton - */ - @Deprecated - protected DefaultAction defaultReleaseAction; /** * Whether or not true double buffering should be used. This is typically @@ -829,35 +807,6 @@ } } - @SuppressWarnings("serial") - static class DefaultAction extends AbstractAction { - JButton owner; - JRootPane root; - boolean press; - DefaultAction(JRootPane root, boolean press) { - this.root = root; - this.press = press; - } - public void setOwner(JButton owner) { - this.owner = owner; - } - public void actionPerformed(ActionEvent e) { - if (owner != null && SwingUtilities.getRootPane(owner) == root) { - ButtonModel model = owner.getModel(); - if (press) { - model.setArmed(true); - model.setPressed(true); - } else { - model.setPressed(false); - } - } - } - public boolean isEnabled() { - return owner.getModel().isEnabled(); - } - } - - /** * Overridden to enforce the position of the glass component as * the zero child. diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java Fri Nov 11 16:44:36 2016 +0100 @@ -46,7 +46,11 @@ * @return the coordinates as a {@code Rectangle} * @exception BadLocationException if the given position does not * represent a valid location in the associated document + * + * @deprecated replaced by + * {@link #modelToView2D(JTextComponent, int, Position.Bias)} */ + @Deprecated(since = "9") public abstract Rectangle modelToView(JTextComponent t, int pos) throws BadLocationException; /** @@ -59,7 +63,11 @@ * @return the coordinates as a {@code Rectangle} * @exception BadLocationException if the given position does not * represent a valid location in the associated document + * + * @deprecated replaced by + * {@link #modelToView2D(JTextComponent, int, Position.Bias)} */ + @Deprecated(since = "9") public abstract Rectangle modelToView(JTextComponent t, int pos, Position.Bias bias) throws BadLocationException; /** @@ -92,7 +100,11 @@ * should be in the same coordinate system as the mouse * events. * @return the offset from the start of the document >= 0 + * + * @deprecated replaced by + * {@link #viewToModel2D(JTextComponent, Point2D, Position.Bias[])} */ + @Deprecated(since = "9") public abstract int viewToModel(JTextComponent t, Point pt); /** @@ -110,7 +122,11 @@ * * @return the location within the model that best represents the * given point in the view >= 0 + * + * @deprecated replaced by + * {@link #viewToModel2D(JTextComponent, Point2D, Position.Bias[])} */ + @Deprecated(since = "9") public abstract int viewToModel(JTextComponent t, Point pt, Position.Bias[] biasReturn); @@ -222,7 +238,11 @@ * @return a {@code String} containing the tooltip * @see javax.swing.text.JTextComponent#getToolTipText * @since 1.4 + * + * @deprecated replaced by + * {@link #getToolTipText2D(JTextComponent, Point2D)} */ + @Deprecated(since = "9") public String getToolTipText(JTextComponent t, Point pt) { return null; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java Fri Nov 11 16:44:36 2016 +0100 @@ -28,6 +28,8 @@ import java.awt.*; import java.awt.event.*; import java.awt.datatransfer.*; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; import java.awt.im.InputContext; import java.beans.*; import java.io.*; @@ -1047,7 +1049,12 @@ * @exception BadLocationException if the given position does not * represent a valid location in the associated document * @see TextUI#modelToView + * + * @deprecated replaced by + * {@link #modelToView2D(JTextComponent, int, Position.Bias)} */ + @Deprecated(since = "9") + @Override public Rectangle modelToView(JTextComponent tc, int pos) throws BadLocationException { return modelToView(tc, pos, Position.Bias.Forward); } @@ -1064,8 +1071,30 @@ * @exception BadLocationException if the given position does not * represent a valid location in the associated document * @see TextUI#modelToView + * + * @deprecated replaced by + * {@link #modelToView2D(JTextComponent, int, Position.Bias)} */ - public Rectangle modelToView(JTextComponent tc, int pos, Position.Bias bias) throws BadLocationException { + @Deprecated(since = "9") + @Override + public Rectangle modelToView(JTextComponent tc, int pos, Position.Bias bias) + throws BadLocationException + { + return (Rectangle) modelToView(tc, pos, bias, false); + } + + @Override + public Rectangle2D modelToView2D(JTextComponent tc, int pos, + Position.Bias bias) + throws BadLocationException + { + return modelToView(tc, pos, bias, true); + } + + private Rectangle2D modelToView(JTextComponent tc, int pos, + Position.Bias bias, boolean useFPAPI) + throws BadLocationException + { Document doc = editor.getDocument(); if (doc instanceof AbstractDocument) { ((AbstractDocument)doc).readLock(); @@ -1076,7 +1105,7 @@ rootView.setSize(alloc.width, alloc.height); Shape s = rootView.modelToView(pos, alloc, bias); if (s != null) { - return s.getBounds(); + return useFPAPI ? s.getBounds2D() : s.getBounds(); } } } finally { @@ -1099,7 +1128,12 @@ * @return the offset from the start of the document >= 0, * -1 if not painted * @see TextUI#viewToModel + * + * @deprecated replaced by + * {@link #viewToModel2D(JTextComponent, Point2D, Position.Bias[])} */ + @Deprecated(since = "9") + @Override public int viewToModel(JTextComponent tc, Point pt) { return viewToModel(tc, pt, discardBias); } @@ -1116,9 +1150,25 @@ * @return the offset from the start of the document >= 0, * -1 if the component doesn't yet have a positive size. * @see TextUI#viewToModel + * + * @deprecated replaced by + * {@link #viewToModel2D(JTextComponent, Point2D, Position.Bias[])} */ + @Deprecated(since = "9") + @Override public int viewToModel(JTextComponent tc, Point pt, Position.Bias[] biasReturn) { + return viewToModel(tc, pt.x, pt.y, biasReturn); + } + + @Override + public int viewToModel2D(JTextComponent tc, Point2D pt, + Position.Bias[] biasReturn) { + return viewToModel(tc, (float) pt.getX(), (float) pt.getY(), biasReturn); + } + + private int viewToModel(JTextComponent tc, float x, float y, + Position.Bias[] biasReturn) { int offs = -1; Document doc = editor.getDocument(); if (doc instanceof AbstractDocument) { @@ -1128,7 +1178,7 @@ Rectangle alloc = getVisibleEditorRect(); if (alloc != null) { rootView.setSize(alloc.width, alloc.height); - offs = rootView.viewToModel(pt.x, pt.y, alloc, biasReturn); + offs = rootView.viewToModel(x, y, alloc, biasReturn); } } finally { if (doc instanceof AbstractDocument) { diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalBorders.java --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalBorders.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalBorders.java Fri Nov 11 16:44:36 2016 +0100 @@ -739,7 +739,7 @@ /** * The instance of {@code MetalBumps}. */ - protected MetalBumps bumps = new MetalBumps( 10, 10, + private MetalBumps bumps = new MetalBumps( 10, 10, MetalLookAndFeel.getControlHighlight(), MetalLookAndFeel.getControlDarkShadow(), UIManager.getColor("ToolBar.background")); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java Fri Nov 11 16:44:36 2016 +0100 @@ -923,7 +923,7 @@ * @param fc a {@code JFileChooser} * @return a new instance of {@code DirectoryComboBoxRenderer} */ - protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer(JFileChooser fc) { + private DefaultListCellRenderer createDirectoryComboBoxRenderer(JFileChooser fc) { return new DirectoryComboBoxRenderer(); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalScrollBarUI.java --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalScrollBarUI.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalScrollBarUI.java Fri Nov 11 16:44:36 2016 +0100 @@ -62,7 +62,7 @@ /** * The metal bumps. */ - protected MetalBumps bumps; + private MetalBumps bumps; /** * The increase button. diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/swing/plaf/multi/MultiTextUI.java --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/multi/MultiTextUI.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/multi/MultiTextUI.java Fri Nov 11 16:44:36 2016 +0100 @@ -38,6 +38,8 @@ import javax.swing.JComponent; import java.awt.Graphics; import java.awt.Dimension; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; import javax.accessibility.Accessible; /** @@ -97,7 +99,11 @@ * * @return the value obtained from the first UI, which is * the UI obtained from the default LookAndFeel + * + * @deprecated replaced by + * {@link #modelToView2D(JTextComponent, int, Position.Bias)} */ + @Deprecated(since = "9") public Rectangle modelToView(JTextComponent a, int b) throws BadLocationException { Rectangle returnValue = @@ -113,7 +119,12 @@ * * @return the value obtained from the first UI, which is * the UI obtained from the default LookAndFeel + * + * @deprecated replaced by + * {@link #modelToView2D(JTextComponent, int, Position.Bias)} */ + @Deprecated(since = "9") + @Override public Rectangle modelToView(JTextComponent a, int b, Position.Bias c) throws BadLocationException { Rectangle returnValue = @@ -124,12 +135,24 @@ return returnValue; } + @Override + public Rectangle2D modelToView2D(JTextComponent a, int b, Position.Bias c) throws BadLocationException { + Rectangle2D returnValue = + ((TextUI) (uis.elementAt(0))).modelToView2D(a,b,c); + for (int i = 1; i < uis.size(); i++) { + ((TextUI) (uis.elementAt(i))).modelToView2D(a,b,c); + } + return returnValue; + } + /** * Invokes the viewToModel method on each UI handled by this object. * * @return the value obtained from the first UI, which is * the UI obtained from the default LookAndFeel */ + @Deprecated(since = "9") + @Override public int viewToModel(JTextComponent a, Point b) { int returnValue = ((TextUI) (uis.elementAt(0))).viewToModel(a,b); @@ -145,6 +168,8 @@ * @return the value obtained from the first UI, which is * the UI obtained from the default LookAndFeel */ + @Deprecated(since = "9") + @Override public int viewToModel(JTextComponent a, Point b, Position.Bias[] c) { int returnValue = ((TextUI) (uis.elementAt(0))).viewToModel(a,b,c); @@ -154,6 +179,16 @@ return returnValue; } + @Override + public int viewToModel2D(JTextComponent a, Point2D b, Position.Bias[] c) { + int returnValue = + ((TextUI) (uis.elementAt(0))).viewToModel2D(a,b,c); + for (int i = 1; i < uis.size(); i++) { + ((TextUI) (uis.elementAt(i))).viewToModel2D(a,b,c); + } + return returnValue; + } + /** * Invokes the getNextVisualPositionFrom method on each UI handled by this object. * diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter1.java --- a/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter1.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter1.java Fri Nov 11 16:44:36 2016 +0100 @@ -98,26 +98,27 @@ Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : a.getBounds(); // determine the x coordinate to render the glyphs - int x = alloc.x; + float x = alloc.x; int p = v.getStartOffset(); int[] justificationData = getJustificationData(v); if (p != p0) { text = v.getText(p, p0); - int width = Utilities.getTabbedTextWidth(v, text, metrics, x, expander, p, - justificationData); + float width = Utilities.getTabbedTextWidth(v, text, metrics, x, + expander, p, + justificationData); x += width; SegmentCache.releaseSharedSegment(text); } // determine the y coordinate to render the glyphs - int y = alloc.y + metrics.getHeight() - metrics.getDescent(); + float y = alloc.y + metrics.getHeight() - metrics.getDescent(); // render the glyphs text = v.getText(p0, p1); g.setFont(metrics.getFont()); Utilities.drawTabbedText(v, text, x, y, g, expander,p0, - justificationData); + justificationData, true); SegmentCache.releaseSharedSegment(text); } @@ -210,9 +211,9 @@ TabExpander expander = v.getTabExpander(); Segment s = v.getText(p0, v.getEndOffset()); int[] justificationData = getJustificationData(v); - int index = Utilities.getTabbedTextOffset(v, s, metrics, (int)x, (int)(x+len), + int index = Utilities.getTabbedTextOffset(v, s, metrics, x, (x+len), expander, p0, false, - justificationData); + justificationData, true); SegmentCache.releaseSharedSegment(s); int p1 = p0 + index; return p1; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter2.java --- a/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter2.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter2.java Fri Nov 11 16:44:36 2016 +0100 @@ -145,8 +145,9 @@ // vertical at the baseline, should use slope and check if glyphs // are being rendered vertically. - alloc.setRect(alloc.getX() + locs[0], alloc.getY(), 1, alloc.getHeight()); - return alloc; + Rectangle2D rect = new Rectangle2D.Float(); + rect.setRect(alloc.getX() + locs[0], alloc.getY(), 1, alloc.getHeight()); + return rect; } /** diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java --- a/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java Fri Nov 11 16:44:36 2016 +0100 @@ -49,6 +49,8 @@ import java.awt.im.InputMethodRequests; import java.awt.font.TextHitInfo; import java.awt.font.TextAttribute; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; import java.awt.print.Printable; import java.awt.print.PrinterException; @@ -1370,12 +1372,38 @@ * @exception BadLocationException if the given position does not * represent a valid location in the associated document * @see TextUI#modelToView + * + * @deprecated replaced by + * {@link #modelToView2D(int)} */ + @Deprecated(since = "9") public Rectangle modelToView(int pos) throws BadLocationException { return getUI().modelToView(this, pos); } /** + * Converts the given location in the model to a place in + * the view coordinate system. + * The component must have a positive size for + * this translation to be computed (i.e. layout cannot + * be computed until the component has been sized). The + * component does not have to be visible or painted. + * + * @param pos the position {@code >= 0} + * @return the coordinates as a rectangle, with (r.x, r.y) as the location + * in the coordinate system, or null if the component does + * not yet have a positive size. + * @exception BadLocationException if the given position does not + * represent a valid location in the associated document + * @see TextUI#modelToView2D + * + * @since 9 + */ + public Rectangle2D modelToView2D(int pos) throws BadLocationException { + return getUI().modelToView2D(this, pos, Position.Bias.Forward); + } + + /** * Converts the given place in the view coordinate system * to the nearest representative location in the model. * The component must have a positive size for @@ -1388,12 +1416,36 @@ * or -1 if the component does not yet have a positive * size. * @see TextUI#viewToModel + * + * @deprecated replaced by + * {@link #viewToModel2D(Point2D)} */ + @Deprecated(since = "9") public int viewToModel(Point pt) { return getUI().viewToModel(this, pt); } /** + * Converts the given place in the view coordinate system + * to the nearest representative location in the model. + * The component must have a positive size for + * this translation to be computed (i.e. layout cannot + * be computed until the component has been sized). The + * component does not have to be visible or painted. + * + * @param pt the location in the view to translate + * @return the offset {@code >= 0} from the start of the document, + * or {@code -1} if the component does not yet have a positive + * size. + * @see TextUI#viewToModel2D + * + * @since 9 + */ + public int viewToModel2D(Point2D pt) { + return getUI().viewToModel2D(this, pt, new Position.Bias[1]); + } + + /** * Transfers the currently selected range in the associated * text model to the system clipboard, removing the contents * from the model. The current selection is reset. Does nothing diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/swing/text/ParagraphView.java --- a/jdk/src/java.desktop/share/classes/javax/swing/text/ParagraphView.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/ParagraphView.java Fri Nov 11 16:44:36 2016 +0100 @@ -27,6 +27,7 @@ import java.util.Arrays; import java.awt.*; import java.awt.font.TextAttribute; +import java.awt.geom.Rectangle2D; import javax.swing.event.*; import javax.swing.SizeRequirements; @@ -888,10 +889,9 @@ int height = r.height; int y = r.y; Shape loc = super.modelToView(pos, a, b); - r = loc.getBounds(); - r.height = height; - r.y = y; - return r; + Rectangle2D bounds = loc.getBounds2D(); + bounds.setRect(bounds.getX(), y, bounds.getWidth(), height); + return bounds; } /** diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java --- a/jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java Fri Nov 11 16:44:36 2016 +0100 @@ -26,7 +26,11 @@ import sun.swing.SwingUtilities2; import java.awt.*; +import java.awt.font.FontRenderContext; +import java.security.AccessController; +import java.security.PrivilegedAction; import javax.swing.JPasswordField; +import static javax.swing.text.PlainView.isFPMethodOverriden; /** * Implements a View suitable for use in JPasswordField @@ -61,15 +65,40 @@ * @param p1 the ending offset in the model >= p0 * @return the X location of the end of the range >= 0 * @exception BadLocationException if p0 or p1 are out of range + * + * @deprecated replaced by + * {@link #drawUnselectedText(Graphics2D, float, float, int, int)} */ + @Deprecated(since = "9") + @Override protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1) throws BadLocationException { + return (int) drawUnselectedTextImpl(g, x, y, p0, p1, false); + } + @Override + protected float drawUnselectedText(Graphics2D g, float x, float y, + int p0, int p1) + throws BadLocationException + { + return drawUnselectedTextImpl(g, x, y, p0, p1, true); + } + + private float drawUnselectedTextImpl(Graphics g, float x, float y, + int p0, int p1, + boolean useFPAPI) + throws BadLocationException + { Container c = getContainer(); if (c instanceof JPasswordField) { JPasswordField f = (JPasswordField) c; - if (! f.echoCharIsSet()) { - return super.drawUnselectedText(g, x, y, p0, p1); + if (!f.echoCharIsSet()) { + boolean useDrawUnselectedFPAPI = useFPAPI + && drawUnselectedTextOverridden + && g instanceof Graphics2D; + return (useDrawUnselectedFPAPI ) + ? super.drawUnselectedText((Graphics2D) g, x, y, p0, p1) + : super.drawUnselectedText(g, (int) x, (int) y, p0, p1); } if (f.isEnabled()) { g.setColor(f.getForeground()); @@ -79,8 +108,13 @@ } char echoChar = f.getEchoChar(); int n = p1 - p0; + boolean useEchoCharFPAPI = useFPAPI + && drawEchoCharacterOverridden + && g instanceof Graphics2D; for (int i = 0; i < n; i++) { - x = drawEchoCharacter(g, x, y, echoChar); + x = (useEchoCharFPAPI) + ? drawEchoCharacter((Graphics2D) g, x, y, echoChar) + : drawEchoCharacter(g, (int) x, (int) y, echoChar); } } return x; @@ -100,20 +134,50 @@ * @param p1 the ending offset in the model >= p0 * @return the X location of the end of the range >= 0 * @exception BadLocationException if p0 or p1 are out of range + * + * @deprecated replaced by + * {@link #drawSelectedText(Graphics2D, float, float, int, int)} */ + @Deprecated(since = "9") + @Override protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1) throws BadLocationException { + return (int) drawSelectedTextImpl(g, x, y, p0, p1, false); + } + + @Override + protected float drawSelectedText(Graphics2D g, float x, float y, + int p0, int p1) throws BadLocationException + { + return drawSelectedTextImpl(g, x, y, p0, p1, true); + } + + private float drawSelectedTextImpl(Graphics g, float x, float y, + int p0, int p1, + boolean useFPAPI) + throws BadLocationException { g.setColor(selected); Container c = getContainer(); if (c instanceof JPasswordField) { JPasswordField f = (JPasswordField) c; - if (! f.echoCharIsSet()) { - return super.drawSelectedText(g, x, y, p0, p1); + if (!f.echoCharIsSet()) { + boolean useDrawUnselectedFPAPI = useFPAPI + && drawSelectedTextOverridden + && g instanceof Graphics2D; + return (useFPAPI) + ? super.drawSelectedText((Graphics2D) g, x, y, p0, p1) + : super.drawSelectedText(g, (int) x, (int) y, p0, p1); } char echoChar = f.getEchoChar(); int n = p1 - p0; + boolean useEchoCharFPAPI = useFPAPI + && drawEchoCharacterOverridden + && g instanceof Graphics2D; for (int i = 0; i < n; i++) { - x = drawEchoCharacter(g, x, y, echoChar); + x = (useEchoCharFPAPI) + ? drawEchoCharacter((Graphics2D) g, x, y, echoChar) + : drawEchoCharacter(g, (int) x, (int) y, echoChar); + } } return x; @@ -130,12 +194,13 @@ * @param y the starting Y coordinate >= 0 * @param c the echo character * @return the updated X position >= 0 + * + * @deprecated replaced by + * {@link #drawEchoCharacter(Graphics2D, float, float, char)} */ + @Deprecated(since = "9") protected int drawEchoCharacter(Graphics g, int x, int y, char c) { - ONE[0] = c; - SwingUtilities2.drawChars(Utilities.getJComponent(this), - g, ONE, 0, 1, x, y); - return x + g.getFontMetrics().charWidth(c); + return (int) drawEchoCharacterImpl(g, x, y, c, false); } /** @@ -144,18 +209,29 @@ * object is set to the appropriate foreground color for selected * or unselected text. * - * @implSpec This implementation calls - * {@link #drawEchoCharacter(Graphics, int, int, char) - * drawEchoCharacter((Graphics) g, (int) x, (int) y, c)}. - * * @param g the graphics context * @param x the starting X coordinate {@code >= 0} * @param y the starting Y coordinate {@code >= 0} * @param c the echo character * @return the updated X position {@code >= 0} + * + * @since 9 */ protected float drawEchoCharacter(Graphics2D g, float x, float y, char c) { - return drawEchoCharacter((Graphics) g, (int) x, (int) y, c); + return drawEchoCharacterImpl(g, x, y, c, true); + } + + private float drawEchoCharacterImpl(Graphics g, float x, float y, + char c, boolean useFPAPI) { + ONE[0] = c; + SwingUtilities2.drawChars(Utilities.getJComponent(this), + g, ONE, 0, 1, x, y); + if (useFPAPI) { + return x + g.getFontMetrics().charWidth(c); + } else { + FontRenderContext frc = g.getFontMetrics().getFontRenderContext(); + return x + (float) g.getFont().getStringBounds(ONE, 0, 1, frc).getWidth(); + } } /** @@ -253,4 +329,23 @@ } static char[] ONE = new char[1]; + + private final boolean drawEchoCharacterOverridden; + + { + final Class CLS = getClass(); + final Class INT = Integer.TYPE; + final Class FP = Float.TYPE; + final Class CHAR = Character.TYPE; + + drawEchoCharacterOverridden = AccessController + .doPrivileged(new PrivilegedAction() { + @Override + public Boolean run() { + Class[] intTypes = {Graphics.class, INT, INT, CHAR}; + Class[] fpTypes = {Graphics2D.class, FP, FP, CHAR}; + return isFPMethodOverriden("drawEchoCharacter", CLS, intTypes, fpTypes); + } + }); + } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java --- a/jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java Fri Nov 11 16:44:36 2016 +0100 @@ -24,11 +24,14 @@ */ package javax.swing.text; -import java.util.Vector; -import java.util.Properties; import java.awt.*; +import java.awt.font.FontRenderContext; +import java.awt.geom.Rectangle2D; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Objects; import javax.swing.event.*; +import java.lang.reflect.Module; /** * Implements View interface for a simple multi-line text view @@ -61,17 +64,6 @@ } /** - * Returns the tab size set for the document, defaulting to 8. - * - * @implSpec This implementation calls {@link #getTabSize() getTabSize()}. - * - * @return the tab size - */ - protected float getFractionalTabSize() { - return getTabSize(); - } - - /** * Renders a line of text, suppressing whitespace at the end * and expanding any tabs. This is implemented to make calls * to the methods drawUnselectedText and @@ -84,8 +76,16 @@ * @param y the starting Y position >= 0 * @see #drawUnselectedText * @see #drawSelectedText + * + * @deprecated replaced by + * {@link #drawLine(int, Graphics2D, float, float)} */ + @Deprecated(since = "9") protected void drawLine(int lineIndex, Graphics g, int x, int y) { + drawLineImpl(lineIndex, g, x, y); + } + + private void drawLineImpl(int lineIndex, Graphics g, float x, float y) { Element line = getElement().getElement(lineIndex); Element elem; @@ -112,22 +112,23 @@ * {@code drawSelectedText} so that the way selected and * unselected text are rendered can be customized. * - * @implSpec This implementation calls - * {@link #drawLine(int, Graphics, int, int) - * drawLine(lineIndex, (Graphics)g, (int) x, (int) y)}. - * * @param lineIndex the line to draw {@code >= 0} * @param g the {@code Graphics} context * @param x the starting X position {@code >= 0} * @param y the starting Y position {@code >= 0} * @see #drawUnselectedText * @see #drawSelectedText + * + * @since 9 */ protected void drawLine(int lineIndex, Graphics2D g, float x, float y) { - drawLine(lineIndex, (Graphics)g, (int) x, (int) y); + drawLineImpl(lineIndex, g, x, y); } - private int drawElement(int lineIndex, Element elem, Graphics g, int x, int y) throws BadLocationException { + private float drawElement(int lineIndex, Element elem, Graphics g, + float x, float y) + throws BadLocationException + { int p0 = elem.getStartOffset(); int p1 = elem.getEndOffset(); p1 = Math.min(getDocument().getLength(), p1); @@ -144,23 +145,23 @@ } else { if (sel0 == sel1 || selected == unselected) { // no selection, or it is invisible - x = drawUnselectedText(g, x, y, p0, p1); + x = callDrawUnselectedText(g, x, y, p0, p1); } else if ((p0 >= sel0 && p0 <= sel1) && (p1 >= sel0 && p1 <= sel1)) { - x = drawSelectedText(g, x, y, p0, p1); + x = callDrawSelectedText(g, x, y, p0, p1); } else if (sel0 >= p0 && sel0 <= p1) { if (sel1 >= p0 && sel1 <= p1) { - x = drawUnselectedText(g, x, y, p0, sel0); - x = drawSelectedText(g, x, y, sel0, sel1); - x = drawUnselectedText(g, x, y, sel1, p1); + x = callDrawUnselectedText(g, x, y, p0, sel0); + x = callDrawSelectedText(g, x, y, sel0, sel1); + x = callDrawUnselectedText(g, x, y, sel1, p1); } else { - x = drawUnselectedText(g, x, y, p0, sel0); - x = drawSelectedText(g, x, y, sel0, p1); + x = callDrawUnselectedText(g, x, y, p0, sel0); + x = callDrawSelectedText(g, x, y, sel0, p1); } } else if (sel1 >= p0 && sel1 <= p1) { - x = drawSelectedText(g, x, y, p0, sel1); - x = drawUnselectedText(g, x, y, sel1, p1); + x = callDrawSelectedText(g, x, y, p0, sel1); + x = callDrawUnselectedText(g, x, y, sel1, p1); } else { - x = drawUnselectedText(g, x, y, p0, p1); + x = callDrawUnselectedText(g, x, y, p0, p1); } } @@ -178,14 +179,36 @@ * @param p1 the ending position in the model >= 0 * @return the X location of the end of the range >= 0 * @exception BadLocationException if the range is invalid + * + * @deprecated replaced by + * {@link #drawUnselectedText(Graphics2D, float, float, int, int)} */ + @Deprecated(since = "9") protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1) throws BadLocationException { + return (int) drawUnselectedTextImpl(g, x, y, p0, p1, false); + } + + private float callDrawUnselectedText(Graphics g, float x, float y, + int p0, int p1) + throws BadLocationException + { + return drawUnselectedTextOverridden && (g instanceof Graphics2D) + ? drawUnselectedText((Graphics2D) g, x, y, p0, p1) + : drawUnselectedText(g, (int) x, (int) y, p0, p1); + } + + private float drawUnselectedTextImpl(Graphics g, float x, float y, + int p0, int p1, + boolean useFPAPI) + throws BadLocationException + { g.setColor(unselected); Document doc = getDocument(); Segment s = SegmentCache.getSharedSegment(); doc.getText(p0, p1 - p0, s); - int ret = Utilities.drawTabbedText(this, s, x, y, g, this, p0); + float ret = Utilities.drawTabbedText(this, s, x, y, g, this, p0, null, + useFPAPI); SegmentCache.releaseSharedSegment(s); return ret; } @@ -194,10 +217,6 @@ * Renders the given range in the model as normal unselected * text. Uses the foreground or disabled color to render the text. * - * @implSpec This implementation calls - * {@link #drawUnselectedText(Graphics, int, int, int, int) - * drawUnselectedText((Graphics)g, (int) x, (int) y, p0, p1)}. - * * @param g the graphics context * @param x the starting X coordinate {@code >= 0} * @param y the starting Y coordinate {@code >= 0} @@ -205,10 +224,12 @@ * @param p1 the ending position in the model {@code >= 0} * @return the X location of the end of the range {@code >= 0} * @exception BadLocationException if the range is invalid + * + * @since 9 */ protected float drawUnselectedText(Graphics2D g, float x, float y, int p0, int p1) throws BadLocationException { - return drawUnselectedText((Graphics)g, (int) x, (int) y, p0, p1); + return drawUnselectedTextImpl(g, x, y, p0, p1, true); } /** @@ -224,14 +245,38 @@ * @param p1 the ending position in the model >= 0 * @return the location of the end of the range * @exception BadLocationException if the range is invalid + * + * @deprecated replaced by + * {@link #drawSelectedText(Graphics2D, float, float, int, int)} */ + @Deprecated(since = "9") protected int drawSelectedText(Graphics g, int x, - int y, int p0, int p1) throws BadLocationException { + int y, int p0, int p1) + throws BadLocationException + { + return (int) drawSelectedTextImpl(g, x, y, p0, p1, false); + } + + float callDrawSelectedText(Graphics g, float x, float y, + int p0, int p1) + throws BadLocationException + { + return drawSelectedTextOverridden && g instanceof Graphics2D + ? drawSelectedText((Graphics2D) g, x, y, p0, p1) + : drawSelectedText(g, (int) x, (int) y, p0, p1); + } + + private float drawSelectedTextImpl(Graphics g, float x, float y, + int p0, int p1, + boolean useFPAPI) + throws BadLocationException + { g.setColor(selected); Document doc = getDocument(); Segment s = SegmentCache.getSharedSegment(); doc.getText(p0, p1 - p0, s); - int ret = Utilities.drawTabbedText(this, s, x, y, g, this, p0); + float ret = Utilities.drawTabbedText(this, s, x, y, g, this, p0, null, + useFPAPI); SegmentCache.releaseSharedSegment(s); return ret; } @@ -242,10 +287,6 @@ * the hosting component. It assumes the highlighter will render * the selected background. * - * @implSpec This implementation calls - * {@link #drawSelectedText(Graphics, int, int, int, int) - * drawSelectedText((Graphics)g, (int) x, (int) y, p0, p1)}. - * * @param g the graphics context * @param x the starting X coordinate {@code >= 0} * @param y the starting Y coordinate {@code >= 0} @@ -253,11 +294,12 @@ * @param p1 the ending position in the model {@code >= 0} * @return the location of the end of the range * @exception BadLocationException if the range is invalid + * + * @since 9 */ - protected float drawSelectedText(Graphics2D g, float x, float y, int p0, int p1) throws BadLocationException { - return drawSelectedText((Graphics)g, (int) x, (int) y, p0, p1); + return drawSelectedTextImpl(g, x, y, p0, p1, true); } /** @@ -287,7 +329,13 @@ // The font changed, we need to recalculate the // longest line. calculateLongestLine(); - tabSize = getTabSize() * metrics.charWidth('m'); + if (useFloatingPointAPI) { + FontRenderContext frc = metrics.getFontRenderContext(); + float tabWidth = (float) font.getStringBounds("m", frc).getWidth(); + tabSize = getTabSize() * tabWidth; + } else { + tabSize = getTabSize() * metrics.charWidth('m'); + } } } @@ -388,7 +436,11 @@ originalA, host, this); } } - drawLine(line, g, x, y); + if (drawLineOverridden && (g instanceof Graphics2D)) { + drawLine(line, (Graphics2D) g, (float) x, (float) y); + } else { + drawLine(line, g, x, y); + } y += fontHeight; if (line == 0) { // This should never really happen, in so far as if @@ -435,6 +487,13 @@ int p0 = line.getStartOffset(); Segment s = SegmentCache.getSharedSegment(); doc.getText(p0, pos - p0, s); + + if (useFloatingPointAPI) { + float xOffs = Utilities.getTabbedTextWidth(s, metrics, (float) tabBase, this, p0); + SegmentCache.releaseSharedSegment(s); + return new Rectangle2D.Float(lineArea.x + xOffs, lineArea.y, 1, metrics.getHeight()); + } + int xOffs = Utilities.getTabbedTextWidth(s, metrics, tabBase, this,p0); SegmentCache.releaseSharedSegment(s); @@ -456,14 +515,13 @@ * given point in the view >= 0 * @see View#viewToModel */ - public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) { + public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) { // PENDING(prinz) properly calculate bias bias[0] = Position.Bias.Forward; Rectangle alloc = a.getBounds(); Document doc = getDocument(); - int x = (int) fx; - int y = (int) fy; + if (y < alloc.y) { // above the area covered by this icon, so the position // is assumed to be the start of the coverage for this view. @@ -481,7 +539,7 @@ Element map = doc.getDefaultRootElement(); int fontHeight = metrics.getHeight(); int lineIndex = (fontHeight > 0 ? - Math.abs((y - alloc.y) / fontHeight) : + (int)Math.abs((y - alloc.y) / fontHeight) : map.getElementCount() - 1); if (lineIndex >= map.getElementCount()) { return getEndOffset() - 1; @@ -507,7 +565,7 @@ doc.getText(p0, p1 - p0, s); tabBase = alloc.x; int offs = p0 + Utilities.getTabbedTextOffset(s, metrics, - tabBase, x, this, p0); + tabBase, x, this, p0, true); SegmentCache.releaseSharedSegment(s); return offs; } catch (BadLocationException e) { @@ -586,7 +644,7 @@ if (tabSize == 0) { return x; } - int ntabs = (((int) x) - tabBase) / tabSize; + float ntabs = (x - tabBase) / tabSize; return tabBase + ((ntabs + 1) * tabSize); } @@ -758,6 +816,28 @@ return w; } + static boolean isFPMethodOverriden(String method, + Class cls, + Class[] intTypes, + Class[] fpTypes) + { + Module thisModule = PlainView.class.getModule(); + while (!thisModule.equals(cls.getModule())) { + try { + cls.getDeclaredMethod(method, fpTypes); + return true; + } catch (Exception e1) { + try { + cls.getDeclaredMethod(method, intTypes); + return false; + } catch (Exception e2) { + cls = cls.getSuperclass(); + } + } + } + return true; + } + // --- member variables ----------------------------------------------- /** @@ -780,7 +860,7 @@ Font font; Segment lineBuffer; - int tabSize; + float tabSize; int tabBase; int sel0; @@ -796,4 +876,46 @@ */ int firstLineOffset; + final boolean drawLineOverridden; + final boolean drawSelectedTextOverridden; + final boolean drawUnselectedTextOverridden; + final boolean useFloatingPointAPI; + + { + final Class CLS = getClass(); + final Class INT = Integer.TYPE; + final Class FP = Float.TYPE; + + drawLineOverridden = AccessController + .doPrivileged(new PrivilegedAction() { + @Override + public Boolean run() { + Class[] intTypes = {INT, Graphics.class, INT, INT}; + Class[] fpTypes = {INT, Graphics2D.class, FP, FP}; + return isFPMethodOverriden("drawLine", CLS, intTypes, fpTypes); + } + }); + + drawUnselectedTextOverridden = AccessController + .doPrivileged(new PrivilegedAction() { + @Override + public Boolean run() { + Class[] intTypes = {Graphics.class, INT, INT, INT, INT}; + Class[] fpTypes = {Graphics2D.class, FP, FP, INT, INT}; + return isFPMethodOverriden("drawUnselectedText", CLS, intTypes, fpTypes); + } + }); + + drawSelectedTextOverridden = AccessController + .doPrivileged(new PrivilegedAction() { + @Override + public Boolean run() { + Class[] intTypes = {Graphics.class, INT, INT, INT, INT}; + Class[] fpTypes = {Graphics2D.class, FP, FP, INT, INT}; + return isFPMethodOverriden("drawSelectedText", CLS, intTypes, fpTypes); + } + }); + + useFloatingPointAPI = drawUnselectedTextOverridden || drawSelectedTextOverridden; + } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/swing/text/Utilities.java --- a/jdk/src/java.desktop/share/classes/javax/swing/text/Utilities.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/Utilities.java Fri Nov 11 16:44:36 2016 +0100 @@ -24,24 +24,23 @@ */ package javax.swing.text; -import java.lang.reflect.Method; - import java.awt.Component; import java.awt.Rectangle; import java.awt.Graphics; import java.awt.FontMetrics; import java.awt.Shape; -import java.awt.Toolkit; import java.awt.Graphics2D; -import java.awt.font.FontRenderContext; -import java.awt.font.TextLayout; import java.awt.font.TextAttribute; +import java.awt.geom.Rectangle2D; import java.text.*; import javax.swing.JComponent; import javax.swing.SwingConstants; import javax.swing.text.ParagraphView.Row; import sun.swing.SwingUtilities2; +import static sun.swing.SwingUtilities2.drawChars; +import static sun.swing.SwingUtilities2.getFontCharWidth; +import static sun.swing.SwingUtilities2.getFontCharsWidth; /** * A collection of methods to deal with various text @@ -78,7 +77,11 @@ * tabs will be expanded as a space character. * @param startOffset starting offset of the text in the document >= 0 * @return the X location at the end of the rendered text + * + * @deprecated replaced by + * {@link #drawTabbedText(Segment, float, float, Graphics2D, TabExpander, int)} */ + @Deprecated(since = "9") public static final int drawTabbedText(Segment s, int x, int y, Graphics g, TabExpander e, int startOffset) { return drawTabbedText(null, s, x, y, g, e, startOffset); @@ -96,6 +99,8 @@ * tabs will be expanded as a space character. * @param startOffset starting offset of the text in the document {@code >= 0} * @return the X location at the end of the rendered text + * + * @since 9 */ public static final float drawTabbedText(Segment s, float x, float y, Graphics2D g, @@ -138,9 +143,19 @@ Segment s, int x, int y, Graphics g, TabExpander e, int startOffset, int [] justificationData) { + return (int) drawTabbedText(view, s, x, y, g, e, startOffset, + justificationData, false); + } + + static final float drawTabbedText(View view, + Segment s, float x, float y, Graphics g, + TabExpander e, int startOffset, + int [] justificationData, + boolean useFPAPI) + { JComponent component = getJComponent(view); FontMetrics metrics = SwingUtilities2.getFontMetrics(component, g); - int nextX = x; + float nextX = x; char[] txt = s.array; int txtOffset = s.offset; int flushLen = 0; @@ -174,19 +189,19 @@ && i <= endJustifiableContent )) { if (flushLen > 0) { - nextX = SwingUtilities2.drawChars(component, g, txt, - flushIndex, flushLen, x, y); + nextX = drawChars(component, g, txt, flushIndex, flushLen, x, y); flushLen = 0; } flushIndex = i + 1; if (txt[i] == '\t') { if (e != null) { - nextX = (int) e.nextTabStop((float) nextX, startOffset + i - txtOffset); + nextX = e.nextTabStop(nextX, startOffset + i - txtOffset); } else { - nextX += metrics.charWidth(' '); + nextX += getFontCharWidth(' ', metrics, useFPAPI); } } else if (txt[i] == ' ') { - nextX += metrics.charWidth(' ') + spaceAddon; + float spaceWidth = getFontCharWidth(' ', metrics, useFPAPI); + nextX += spaceWidth + spaceAddon; if (i <= spaceAddonLeftoverEnd) { nextX++; } @@ -194,8 +209,8 @@ x = nextX; } else if ((txt[i] == '\n') || (txt[i] == '\r')) { if (flushLen > 0) { - nextX = SwingUtilities2.drawChars(component, g, txt, - flushIndex, flushLen, x, y); + nextX = drawChars(component, g, txt, flushIndex, flushLen, + x, y, useFPAPI); flushLen = 0; } flushIndex = i + 1; @@ -205,8 +220,7 @@ } } if (flushLen > 0) { - nextX = SwingUtilities2.drawChars(component, g,txt, flushIndex, - flushLen, x, y); + nextX = drawChars(component, g,txt, flushIndex, flushLen, x, y, useFPAPI); } return nextX; } @@ -223,7 +237,11 @@ * tabs will be expanded as a space character. * @param startOffset starting offset of the text in the document >= 0 * @return the width of the text + * + * @deprecated replaced by + * {@link #getTabbedTextWidth(Segment, FontMetrics, float, TabExpander, int)} */ + @Deprecated(since = "9") public static final int getTabbedTextWidth(Segment s, FontMetrics metrics, int x, TabExpander e, int startOffset) { return getTabbedTextWidth(null, s, metrics, x, e, startOffset, null); @@ -240,11 +258,13 @@ * tabs will be expanded as a space character. * @param startOffset starting offset of the text in the document {@code >= 0} * @return the width of the text + * + * @since 9 */ public static final float getTabbedTextWidth(Segment s, FontMetrics metrics, float x, TabExpander e, int startOffset) { - return getTabbedTextWidth(s, metrics, (int) x, e, startOffset); + return getTabbedTextWidth(null, s, metrics, x, e, startOffset, null); } // In addition to the previous method it can extend spaces for @@ -254,10 +274,32 @@ // one: // @param justificationData justificationData for the row. // if null not justification is needed - static final int getTabbedTextWidth(View view, Segment s, FontMetrics metrics, int x, + static final int getTabbedTextWidth(View view, Segment s, + FontMetrics metrics, int x, + TabExpander e, int startOffset, + int[] justificationData) + { + return (int) getTabbedTextWidth(view, s, metrics, x, e, startOffset, + justificationData, false); + + } + + static final float getTabbedTextWidth(View view, Segment s, + FontMetrics metrics, float x, TabExpander e, int startOffset, - int[] justificationData) { - int nextX = x; + int[] justificationData) + { + return getTabbedTextWidth(view, s, metrics, x, e, startOffset, + justificationData, true); + + } + + static final float getTabbedTextWidth(View view, Segment s, + FontMetrics metrics, float x, + TabExpander e, int startOffset, + int[] justificationData, + boolean useFPAPI) { + float nextX = x; char[] txt = s.array; int txtOffset = s.offset; int n = s.offset + s.count; @@ -294,13 +336,13 @@ charCount = 0; if (txt[i] == '\t') { if (e != null) { - nextX = (int) e.nextTabStop((float) nextX, - startOffset + i - txtOffset); + nextX = e.nextTabStop(nextX, startOffset + i - txtOffset); } else { - nextX += metrics.charWidth(' '); + nextX += getFontCharWidth(' ', metrics, useFPAPI); } } else if (txt[i] == ' ') { - nextX += metrics.charWidth(' ') + spaceAddon; + float spaceWidth = getFontCharWidth(' ', metrics, useFPAPI); + nextX += spaceWidth + spaceAddon; if (i <= spaceAddonLeftoverEnd) { nextX++; } @@ -308,13 +350,15 @@ } else if(txt[i] == '\n') { // Ignore newlines, they take up space and we shouldn't be // counting them. - nextX += metrics.charsWidth(txt, i - charCount, charCount); + nextX += getFontCharsWidth(txt, i - charCount, charCount, + metrics, useFPAPI); charCount = 0; } else { charCount++; } } - nextX += metrics.charsWidth(txt, n - charCount, charCount); + nextX += getFontCharsWidth(txt, n - charCount, charCount, + metrics, useFPAPI); return nextX - x; } @@ -334,7 +378,12 @@ * tabs will be expanded as a space character. * @param startOffset starting offset of the text in the document >= 0 * @return the offset into the text >= 0 + * + * @deprecated replaced by + * {@link #getTabbedTextOffset(Segment, FontMetrics, float, float, + * TabExpander, int, boolean)} */ + @Deprecated(since = "9") public static final int getTabbedTextOffset(Segment s, FontMetrics metrics, int x0, int x, TabExpander e, int startOffset) { @@ -346,7 +395,7 @@ int startOffset, int[] justificationData) { return getTabbedTextOffset(view, s, metrics, x0, x, e, startOffset, true, - justificationData); + justificationData, false); } /** @@ -365,13 +414,19 @@ * @param startOffset starting offset of the text in the document >= 0 * @param round whether or not to round * @return the offset into the text >= 0 + * + * @deprecated replaced by + * {@link #getTabbedTextOffset(Segment, FontMetrics, float, float, + * TabExpander, int, boolean)} */ + @Deprecated(since = "9") public static final int getTabbedTextOffset(Segment s, FontMetrics metrics, int x0, int x, TabExpander e, int startOffset, boolean round) { - return getTabbedTextOffset(null, s, metrics, x0, x, e, startOffset, round, null); + return getTabbedTextOffset(null, s, metrics, x0, x, e, startOffset, + round, null, false); } /** @@ -390,6 +445,8 @@ * @param startOffset starting offset of the text in the document {@code >= 0} * @param round whether or not to round * @return the offset into the text {@code >= 0} + * + * @since 9 */ public static final int getTabbedTextOffset(Segment s, FontMetrics metrics, @@ -398,8 +455,8 @@ int startOffset, boolean round) { - return getTabbedTextOffset(null, s, metrics, (int) x0, (int) x, e, - startOffset, round, null); + return getTabbedTextOffset(null, s, metrics, x0, x, e, + startOffset, round, null, true); } // In addition to the previous method it can extend spaces for @@ -412,15 +469,16 @@ static final int getTabbedTextOffset(View view, Segment s, FontMetrics metrics, - int x0, int x, TabExpander e, + float x0, float x, TabExpander e, int startOffset, boolean round, - int[] justificationData) { + int[] justificationData, + boolean useFPAPI) { if (x0 >= x) { // x before x0, return. return 0; } - int nextX = x0; + float nextX = x0; // s may be a shared segment, so it is copied prior to calling // the tab expander char[] txt = s.array; @@ -456,19 +514,19 @@ )){ if (txt[i] == '\t') { if (e != null) { - nextX = (int) e.nextTabStop((float) nextX, - startOffset + i - txtOffset); + nextX = e.nextTabStop(nextX, startOffset + i - txtOffset); } else { - nextX += metrics.charWidth(' '); + nextX += getFontCharWidth(' ', metrics, useFPAPI); } } else if (txt[i] == ' ') { - nextX += metrics.charWidth(' ') + spaceAddon; + nextX += getFontCharWidth(' ', metrics, useFPAPI); + nextX += spaceAddon; if (i <= spaceAddonLeftoverEnd) { nextX++; } } } else { - nextX += metrics.charWidth(txt[i]); + nextX += getFontCharWidth(txt[i], metrics, useFPAPI); } if (x < nextX) { // found the hit position... return the appropriate side @@ -480,12 +538,15 @@ if (round) { offset = i + 1 - txtOffset; - int width = metrics.charsWidth(txt, txtOffset, offset); - int span = x - x0; + float width = getFontCharsWidth(txt, txtOffset, offset, + metrics, useFPAPI); + float span = x - x0; if (span < width) { while (offset > 0) { - int nextWidth = offset > 1 ? metrics.charsWidth(txt, txtOffset, offset - 1) : 0; + float charsWidth = getFontCharsWidth(txt, txtOffset, + offset - 1, metrics, useFPAPI); + float nextWidth = offset > 1 ? charsWidth : 0; if (span >= nextWidth) { if (span - nextWidth < width - span) { @@ -502,7 +563,9 @@ } else { offset = i - txtOffset; - while (offset > 0 && metrics.charsWidth(txt, txtOffset, offset) > (x - x0)) { + while (offset > 0 && getFontCharsWidth(txt, txtOffset, offset, + metrics, useFPAPI) + > (x - x0)) { offset--; } } @@ -528,15 +591,26 @@ * tabs will be expanded as a space character. * @param startOffset starting offset in the document of the text * @return the offset into the given text + * + * @deprecated replaced by + * {@link #getBreakLocation(Segment, FontMetrics, float, float, + * TabExpander, int)} */ + @Deprecated(since = "9") public static final int getBreakLocation(Segment s, FontMetrics metrics, int x0, int x, TabExpander e, int startOffset) { + return getBreakLocation(s, metrics, x0, x, e, startOffset, false); + } + + static final int getBreakLocation(Segment s, FontMetrics metrics, + float x0, float x, TabExpander e, + int startOffset, boolean useFPIAPI) { char[] txt = s.array; int txtOffset = s.offset; int txtCount = s.count; - int index = Utilities.getTabbedTextOffset(s, metrics, x0, x, - e, startOffset, false); + int index = getTabbedTextOffset(null, s, metrics, x0, x, e, startOffset, + false, null, useFPIAPI); if (index >= txtCount - 1) { return txtCount; @@ -577,11 +651,13 @@ * tabs will be expanded as a space character. * @param startOffset starting offset in the document of the text * @return the offset into the given text + * + * @since 9 */ public static final int getBreakLocation(Segment s, FontMetrics metrics, float x0, float x, TabExpander e, int startOffset) { - return getBreakLocation(s, metrics, (int) x0, (int) x, e, startOffset); + return getBreakLocation(s, metrics, x0, x, e, startOffset, false); } /** @@ -627,16 +703,16 @@ * @exception BadLocationException if the offset is out of range */ public static final int getRowEnd(JTextComponent c, int offs) throws BadLocationException { - Rectangle r = c.modelToView(offs); + Rectangle2D r = c.modelToView2D(offs); if (r == null) { return -1; } int n = c.getDocument().getLength(); int lastOffs = offs; - int y = r.y; - while ((r != null) && (y == r.y)) { + double y = r.getY(); + while ((r != null) && (y == r.getY())) { // Skip invisible elements - if (r.height !=0) { + if (r.getHeight() !=0) { offs = lastOffs; } lastOffs += 1; @@ -657,27 +733,44 @@ * @return the position >= 0 if the request can be computed, otherwise * a value of -1 will be returned. * @exception BadLocationException if the offset is out of range + * + * @deprecated replaced by + * {@link #getPositionAbove(JTextComponent, int, float)} */ - public static final int getPositionAbove(JTextComponent c, int offs, int x) throws BadLocationException { + @Deprecated(since = "9") + public static final int getPositionAbove(JTextComponent c, int offs, int x) + throws BadLocationException + { + return getPositionAbove(c, offs, x, false); + } + + static final int getPositionAbove(JTextComponent c, int offs, float x, + boolean useFPAPI) throws BadLocationException + { int lastOffs = getRowStart(c, offs) - 1; if (lastOffs < 0) { return -1; } - int bestSpan = Integer.MAX_VALUE; - int y = 0; - Rectangle r = null; + double bestSpan = Integer.MAX_VALUE; + double y = 0; + Rectangle2D r = null; if (lastOffs >= 0) { - r = c.modelToView(lastOffs); - y = r.y; + r = useFPAPI ? c.modelToView2D(lastOffs) : c.modelToView(lastOffs); + y = r.getY(); } - while ((r != null) && (y == r.y)) { - int span = Math.abs(r.x - x); + while ((r != null) && (y == r.getY())) { + double span = Math.abs(r.getX() - x); if (span < bestSpan) { offs = lastOffs; bestSpan = span; } lastOffs -= 1; - r = (lastOffs >= 0) ? c.modelToView(lastOffs) : null; + + if ((lastOffs >= 0)) { + r = useFPAPI ? c.modelToView2D(lastOffs) : c.modelToView(lastOffs); + } else { + r = null; + } } return offs; } @@ -694,10 +787,12 @@ * @return the position {@code >= 0} if the request can be computed, otherwise * a value of -1 will be returned. * @exception BadLocationException if the offset is out of range + * + * @since 9 */ public static final int getPositionAbove(JTextComponent c, int offs, float x) throws BadLocationException { - return getPositionAbove(c, offs, (int) x); + return getPositionAbove(c, offs, x, true); } /** @@ -712,28 +807,45 @@ * @return the position >= 0 if the request can be computed, otherwise * a value of -1 will be returned. * @exception BadLocationException if the offset is out of range + * + * @deprecated replaced by + * {@link #getPositionBelow(JTextComponent, int, float)} */ - public static final int getPositionBelow(JTextComponent c, int offs, int x) throws BadLocationException { + @Deprecated(since = "9") + public static final int getPositionBelow(JTextComponent c, int offs, int x) + throws BadLocationException + { + return getPositionBelow(c, offs, x, false); + } + + static final int getPositionBelow(JTextComponent c, int offs, float x, + boolean useFPAPI) throws BadLocationException + { int lastOffs = getRowEnd(c, offs) + 1; if (lastOffs <= 0) { return -1; } - int bestSpan = Integer.MAX_VALUE; + double bestSpan = Integer.MAX_VALUE; int n = c.getDocument().getLength(); - int y = 0; - Rectangle r = null; + double y = 0; + Rectangle2D r = null; if (lastOffs <= n) { - r = c.modelToView(lastOffs); - y = r.y; + r = useFPAPI ? c.modelToView2D(lastOffs) : c.modelToView(lastOffs); + y = r.getY(); } - while ((r != null) && (y == r.y)) { - int span = Math.abs(x - r.x); + while ((r != null) && (y == r.getY())) { + double span = Math.abs(x - r.getX()); if (span < bestSpan) { offs = lastOffs; bestSpan = span; } lastOffs += 1; - r = (lastOffs <= n) ? c.modelToView(lastOffs) : null; + + if (lastOffs <= n) { + r = useFPAPI ? c.modelToView2D(lastOffs) : c.modelToView(lastOffs); + } else { + r = null; + } } return offs; } @@ -750,10 +862,12 @@ * @return the position {@code >= 0} if the request can be computed, otherwise * a value of -1 will be returned. * @exception BadLocationException if the offset is out of range + * + * @since 9 */ public static final int getPositionBelow(JTextComponent c, int offs, float x) throws BadLocationException { - return getPositionBelow(c, offs, (int) x); + return getPositionBelow(c, offs, x, true); } /** @@ -1029,7 +1143,23 @@ */ static int drawComposedText(View view, AttributeSet attr, Graphics g, int x, int y, int p0, int p1) - throws BadLocationException { + throws BadLocationException + { + return (int) drawComposedText(view, attr, g, x, y, p0, p1, false); + } + + static float drawComposedText(View view, AttributeSet attr, Graphics g, + float x, float y, int p0, int p1) + throws BadLocationException + { + return drawComposedText(view, attr, g, x, y, p0, p1, true); + } + + static float drawComposedText(View view, AttributeSet attr, Graphics g, + float x, float y, int p0, int p1, + boolean useFPAPI) + throws BadLocationException + { Graphics2D g2d = (Graphics2D)g; AttributedString as = (AttributedString)attr.getAttribute( StyleConstants.ComposedTextAttribute); @@ -1039,8 +1169,7 @@ return x; AttributedCharacterIterator aci = as.getIterator(null, p0, p1); - return x + (int)SwingUtilities2.drawString( - getJComponent(view), g2d,aci,x,y); + return x + SwingUtilities2.drawString(getJComponent(view), g2d, aci, x, y); } /** diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java --- a/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java Fri Nov 11 16:44:36 2016 +0100 @@ -25,8 +25,12 @@ package javax.swing.text; import java.awt.*; +import java.awt.font.FontRenderContext; import java.lang.ref.SoftReference; +import java.security.AccessController; +import java.security.PrivilegedAction; import javax.swing.event.*; +import static javax.swing.text.PlainView.isFPMethodOverriden; /** * View of plain text (text with only one font and color) @@ -87,17 +91,6 @@ } /** - * Returns the tab size set for the document, defaulting to 8. - * - * @implSpec This implementation calls {@link #getTabSize() getTabSize()}. - * - * @return the tab size - */ - protected float getFractionalTabSize() { - return getTabSize(); - } - - /** * Renders a line of text, suppressing whitespace at the end * and expanding any tabs. This is implemented to make calls * to the methods drawUnselectedText and @@ -111,8 +104,17 @@ * @param y the starting Y position >= 0 * @see #drawUnselectedText * @see #drawSelectedText + * + * @deprecated replaced by + * {@link #drawLine(int, int, Graphics2D, float, float)} */ + @Deprecated(since = "9") protected void drawLine(int p0, int p1, Graphics g, int x, int y) { + drawLineImpl(p0, p1, g, x, y, false); + } + + private void drawLineImpl(int p0, int p1, Graphics g, float x, float y, + boolean useFPAPI) { Element lineMap = getElement(); Element line = lineMap.getElement(lineMap.getElementIndex(p0)); Element elem; @@ -143,10 +145,6 @@ * drawSelectedText so that the way selected and * unselected text are rendered can be customized. * - * @implSpec This implementation calls - * {@link #drawLine(int, int, Graphics, int, int) - * drawLine(p0, p1, (Graphics) g, (int) x, (int) y)}. - * * @param p0 the starting document location to use >= 0 * @param p1 the ending document location to use >= p1 * @param g the graphics context @@ -154,12 +152,17 @@ * @param y the starting Y position >= 0 * @see #drawUnselectedText * @see #drawSelectedText + * + * @since 9 */ protected void drawLine(int p0, int p1, Graphics2D g, float x, float y) { - drawLine(p0, p1, (Graphics) g, (int) x, (int) y); + drawLineImpl(p0, p1, g, x, y, true); } - private int drawText(Element elem, int p0, int p1, Graphics g, int x, int y) throws BadLocationException { + private float drawText(Element elem, int p0, int p1, Graphics g, + float x, float y) + throws BadLocationException + { p1 = Math.min(getDocument().getLength(), p1); AttributeSet attr = elem.getAttributes(); @@ -171,23 +174,23 @@ } else { if (sel0 == sel1 || selected == unselected) { // no selection, or it is invisible - x = drawUnselectedText(g, x, y, p0, p1); + x = callDrawUnselectedText(g, x, y, p0, p1); } else if ((p0 >= sel0 && p0 <= sel1) && (p1 >= sel0 && p1 <= sel1)) { - x = drawSelectedText(g, x, y, p0, p1); + x = callDrawSelectedText(g, x, y, p0, p1); } else if (sel0 >= p0 && sel0 <= p1) { if (sel1 >= p0 && sel1 <= p1) { - x = drawUnselectedText(g, x, y, p0, sel0); - x = drawSelectedText(g, x, y, sel0, sel1); - x = drawUnselectedText(g, x, y, sel1, p1); + x = callDrawUnselectedText(g, x, y, p0, sel0); + x = callDrawSelectedText(g, x, y, sel0, sel1); + x = callDrawUnselectedText(g, x, y, sel1, p1); } else { - x = drawUnselectedText(g, x, y, p0, sel0); - x = drawSelectedText(g, x, y, sel0, p1); + x = callDrawUnselectedText(g, x, y, p0, sel0); + x = callDrawSelectedText(g, x, y, sel0, p1); } } else if (sel1 >= p0 && sel1 <= p1) { - x = drawSelectedText(g, x, y, p0, sel1); - x = drawUnselectedText(g, x, y, sel1, p1); + x = callDrawSelectedText(g, x, y, p0, sel1); + x = callDrawUnselectedText(g, x, y, sel1, p1); } else { - x = drawUnselectedText(g, x, y, p0, p1); + x = callDrawUnselectedText(g, x, y, p0, p1); } } @@ -205,14 +208,36 @@ * @param p1 the ending position in the model >= p0 * @return the X location of the end of the range >= 0 * @exception BadLocationException if the range is invalid + * + * @deprecated replaced by + * {@link #drawUnselectedText(Graphics2D, float, float, int, int)} */ + @Deprecated(since = "9") protected int drawUnselectedText(Graphics g, int x, int y, - int p0, int p1) throws BadLocationException { + int p0, int p1) throws BadLocationException + { + return (int) drawUnselectedTextImpl(g, x, y, p0, p1, false); + } + + private float callDrawUnselectedText(Graphics g, float x, float y, + int p0, int p1) + throws BadLocationException + { + return drawUnselectedTextOverridden && g instanceof Graphics2D + ? drawUnselectedText((Graphics2D) g, x, y, p0, p1) + : drawUnselectedText(g, (int) x, (int) y, p0, p1); + } + + private float drawUnselectedTextImpl(Graphics g, float x, float y, + int p0, int p1, boolean useFPAPI) + throws BadLocationException + { g.setColor(unselected); Document doc = getDocument(); Segment segment = SegmentCache.getSharedSegment(); doc.getText(p0, p1 - p0, segment); - int ret = Utilities.drawTabbedText(this, segment, x, y, g, this, p0); + float ret = Utilities.drawTabbedText(this, segment, x, y, g, this, p0, + null, useFPAPI); SegmentCache.releaseSharedSegment(segment); return ret; } @@ -221,10 +246,6 @@ * Renders the given range in the model as normal unselected * text. * - * @implSpec This implementation calls - * {@link #drawUnselectedText(Graphics, int, int, int, int) - * drawUnselectedText((Graphics)g, (int) x, (int) y, p0, p1)}. - * * @param g the graphics context * @param x the starting X coordinate >= 0 * @param y the starting Y coordinate >= 0 @@ -232,10 +253,12 @@ * @param p1 the ending position in the model >= p0 * @return the X location of the end of the range >= 0 * @exception BadLocationException if the range is invalid + * + * @since 9 */ protected float drawUnselectedText(Graphics2D g, float x, float y, int p0, int p1) throws BadLocationException { - return drawUnselectedText((Graphics) g, (int) x, (int) y, p0, p1); + return drawUnselectedTextImpl(g, x, y, p0, p1, true); } /** * Renders the given range in the model as selected text. This @@ -250,14 +273,37 @@ * @param p1 the ending position in the model >= p0 * @return the location of the end of the range. * @exception BadLocationException if the range is invalid + * + * @deprecated replaced by + * {@link #drawSelectedText(Graphics2D, float, float, int, int)} */ - protected int drawSelectedText(Graphics g, int x, - int y, int p0, int p1) throws BadLocationException { + @Deprecated(since = "9") + protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1) + throws BadLocationException + { + return (int) drawSelectedTextImpl(g, x, y, p0, p1, false); + } + + private float callDrawSelectedText(Graphics g, float x, float y, + int p0, int p1) + throws BadLocationException + { + return drawSelectedTextOverridden && g instanceof Graphics2D + ? drawSelectedText((Graphics2D) g, x, y, p0, p1) + : drawSelectedText(g, (int) x, (int) y, p0, p1); + } + + private float drawSelectedTextImpl(Graphics g, float x, float y, + int p0, int p1, + boolean useFPAPI) + throws BadLocationException + { g.setColor(selected); Document doc = getDocument(); Segment segment = SegmentCache.getSharedSegment(); doc.getText(p0, p1 - p0, segment); - int ret = Utilities.drawTabbedText(this, segment, x, y, g, this, p0); + float ret = Utilities.drawTabbedText(this, segment, x, y, g, this, p0, + null, useFPAPI); SegmentCache.releaseSharedSegment(segment); return ret; } @@ -268,10 +314,6 @@ * the hosting component. It assumes the highlighter will render * the selected background. * - * @implSpec This implementation calls - * {@link #drawSelectedText(Graphics, int, int, int, int) - * drawSelectedText((Graphics)g, (int) x, (int) y, p0, p1)}. - * * @param g the graphics context * @param x the starting X coordinate >= 0 * @param y the starting Y coordinate >= 0 @@ -279,10 +321,12 @@ * @param p1 the ending position in the model >= p0 * @return the location of the end of the range. * @exception BadLocationException if the range is invalid + * + * @since 9 */ protected float drawSelectedText(Graphics2D g, float x, float y, int p0, int p1) throws BadLocationException { - return drawSelectedText((Graphics) g, (int) x, (int) y, p0, p1); + return drawSelectedTextImpl(g, x, y, p0, p1, true); } /** * Gives access to a buffer that can be used to fetch @@ -395,7 +439,13 @@ Component host = getContainer(); Font f = host.getFont(); metrics = host.getFontMetrics(f); - tabSize = getTabSize() * metrics.charWidth('m'); + if (useFloatingPointAPI) { + FontRenderContext frc = metrics.getFontRenderContext(); + float tabWidth = (float) f.getStringBounds("m", frc).getWidth(); + tabSize = getTabSize() * tabWidth; + } else { + tabSize = getTabSize() * metrics.charWidth('m'); + } } // --- TabExpander methods ------------------------------------------ @@ -413,7 +463,7 @@ public float nextTabStop(float x, int tabOffset) { if (tabSize == 0) return x; - int ntabs = ((int) x - tabBase) / tabSize; + float ntabs = (x - tabBase) / tabSize; return tabBase + ((ntabs + 1) * tabSize); } @@ -591,7 +641,7 @@ Segment lineBuffer; boolean widthChanging; int tabBase; - int tabSize; + float tabSize; boolean wordWrap; int sel0; @@ -668,6 +718,7 @@ int end = getEndOffset(); int p0 = start; int[] lineEnds = getLineEnds(); + boolean useDrawLineFP = drawLineOverridden && g instanceof Graphics2D; for (int i = 0; i < lineCount; i++) { int p1 = (lineEnds == null) ? end : start + lineEnds[i]; @@ -677,8 +728,11 @@ : p1; dh.paintLayeredHighlights(g, p0, hOffset, a, host, this); } - drawLine(p0, p1, g, x, y); - + if (useDrawLineFP) { + drawLine(p0, p1, (Graphics2D) g, (float) x, (float) y); + } else { + drawLine(p0, p1, g, x, y); + } p0 = p1; y += metrics.getHeight(); } @@ -929,4 +983,47 @@ int lineCount; SoftReference lineCache = null; } + + private final boolean drawLineOverridden; + private final boolean drawSelectedTextOverridden; + private final boolean drawUnselectedTextOverridden; + private final boolean useFloatingPointAPI; + + { + final Class CLS = getClass(); + final Class INT = Integer.TYPE; + final Class FP = Float.TYPE; + + drawLineOverridden = AccessController + .doPrivileged(new PrivilegedAction() { + @Override + public Boolean run() { + Class[] intTypes = {INT, INT, Graphics.class, INT, INT}; + Class[] fpTypes = {INT, INT, Graphics2D.class, FP, FP}; + return isFPMethodOverriden("drawLine", CLS, intTypes, fpTypes); + } + }); + + drawUnselectedTextOverridden = AccessController + .doPrivileged(new PrivilegedAction() { + @Override + public Boolean run() { + Class[] intTypes = {Graphics.class, INT, INT, INT, INT}; + Class[] fpTypes = {Graphics2D.class, FP, FP, INT, INT}; + return isFPMethodOverriden("drawUnselectedText", CLS, intTypes, fpTypes); + } + }); + + drawSelectedTextOverridden = AccessController + .doPrivileged(new PrivilegedAction() { + @Override + public Boolean run() { + Class[] intTypes = {Graphics.class, INT, INT, INT, INT}; + Class[] fpTypes = {Graphics2D.class, FP, FP, INT, INT}; + return isFPMethodOverriden("drawSelectedText", CLS, intTypes, fpTypes); + } + }); + + useFloatingPointAPI = drawUnselectedTextOverridden || drawSelectedTextOverridden; + } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/module-info.java --- a/jdk/src/java.desktop/share/classes/module-info.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -88,6 +88,9 @@ exports sun.awt to jdk.accessibility; + exports com.sun.awt to + jdk.desktop; + uses java.awt.im.spi.InputMethodDescriptor; uses javax.accessibility.AccessibilityProvider; uses javax.imageio.spi.ImageInputStreamSpi; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java --- a/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java Fri Nov 11 16:44:36 2016 +0100 @@ -107,7 +107,7 @@ /* * Requests focus to the component. */ - boolean requestFocus(Component comp, Cause cause); + void requestFocus(Component comp, Cause cause); /* * Determines if the component can gain focus. */ @@ -1392,4 +1392,4 @@ AWTAccessor.dropTargetContextAccessor = accessor; } -} \ No newline at end of file +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/sun/awt/IconInfo.java --- a/jdk/src/java.desktop/share/classes/sun/awt/IconInfo.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/awt/IconInfo.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. 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 @@ -103,7 +103,7 @@ } this.scaledWidth = width; this.scaledHeight = height; - this.rawLength = getScaledRawLength(); + this.rawLength = getScaledRawLength(width, height); } /* @@ -112,14 +112,14 @@ public void setScaledSize(int width, int height) { this.scaledWidth = width; this.scaledHeight = height; - this.rawLength = getScaledRawLength(); + this.rawLength = getScaledRawLength(width, height); } /* * returns scaled raw length. */ - private int getScaledRawLength() { - int scaledWidthAndHeight[] = getScaledWidthAndHeight(width, height); + private int getScaledRawLength(int w, int h) { + int scaledWidthAndHeight[] = getScaledWidthAndHeight(w, h); return scaledWidthAndHeight[0] * scaledWidthAndHeight[1] + 2; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java --- a/jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java Fri Nov 11 16:44:36 2016 +0100 @@ -142,8 +142,8 @@ } // WARNING: Don't call it on the Toolkit thread. - public static boolean requestFocusFor(Component target, FocusEvent.Cause cause) { - return AWTAccessor.getComponentAccessor().requestFocus(target, cause); + public static void requestFocusFor(Component target, FocusEvent.Cause cause) { + AWTAccessor.getComponentAccessor().requestFocus(target, cause); } // WARNING: Don't call it on the Toolkit thread. diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java --- a/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java Fri Nov 11 16:44:36 2016 +0100 @@ -1512,9 +1512,9 @@ */ protected abstract boolean syncNativeQueue(final long timeout); - private boolean eventDispatched = false; - private boolean queueEmpty = false; - private final Object waitLock = "Wait Lock"; + private boolean eventDispatched; + private boolean queueEmpty; + private final Object waitLock = new Object(); private boolean isEQEmpty() { EventQueue queue = getSystemEventQueueImpl(); @@ -1531,10 +1531,11 @@ @SuppressWarnings("serial") protected final boolean waitForIdle(final long timeout) { flushPendingEvents(); - boolean queueWasEmpty = isEQEmpty(); - queueEmpty = false; - eventDispatched = false; - synchronized(waitLock) { + final boolean queueWasEmpty; + synchronized (waitLock) { + queueWasEmpty = isEQEmpty(); + queueEmpty = false; + eventDispatched = false; postEvent(AppContext.getAppContext(), new PeerEvent(getSystemEventQueueImpl(), null, PeerEvent.LOW_PRIORITY_EVENT) { @Override diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java --- a/jdk/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java Fri Nov 11 16:44:36 2016 +0100 @@ -30,6 +30,9 @@ import java.awt.Toolkit; import java.io.*; import java.io.FileNotFoundException; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; import java.util.*; import java.util.concurrent.Callable; @@ -243,7 +246,8 @@ if (file instanceof ShellFolder) { return (ShellFolder)file; } - if (!file.exists()) { + + if (!Files.exists(file.toPath(), LinkOption.NOFOLLOW_LINKS)) { throw new FileNotFoundException(); } return shellFolderManager.createShellFolder(file); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/sun/font/NullFontScaler.java --- a/jdk/src/java.desktop/share/classes/sun/font/NullFontScaler.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/font/NullFontScaler.java Fri Nov 11 16:44:36 2016 +0100 @@ -36,8 +36,8 @@ boolean supportsCJK, int filesize) {} StrikeMetrics getFontMetrics(long pScalerContext) { - return new StrikeMetrics(0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, - 0xf0,0xf0,0xf0,0xf0); + return new StrikeMetrics(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f); } float getGlyphAdvance(long pScalerContext, int glyphCode) { @@ -71,7 +71,7 @@ return getNullScalerContext(); } - void invalidateScalerContext(long ppScalerContext) { + void invalidateScalerContext(long pScalerContext) { //nothing to do } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java --- a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java Fri Nov 11 16:44:36 2016 +0100 @@ -1902,11 +1902,7 @@ clipRegion = devClip; } else if (usrClip instanceof Rectangle2D) { clipState = CLIP_RECTANGULAR; - if (usrClip instanceof Rectangle) { - clipRegion = devClip.getIntersection((Rectangle)usrClip); - } else { - clipRegion = devClip.getIntersection(usrClip.getBounds()); - } + clipRegion = devClip.getIntersection((Rectangle2D) usrClip); } else { PathIterator cpi = usrClip.getPathIterator(null); int box[] = new int[4]; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/sun/java2d/pipe/Region.java --- a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/Region.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/Region.java Fri Nov 11 16:44:36 2016 +0100 @@ -28,10 +28,13 @@ import java.awt.Rectangle; import java.awt.Shape; import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; import java.awt.geom.RectangularShape; import sun.java2d.loops.TransformHelper; +import static java.lang.Double.isNaN; + /** * This class encapsulates a definition of a two dimensional region which * consists of a number of Y ranges each containing multiple X bands. @@ -118,6 +121,34 @@ } /** + * Returns the closest {@code int} to the argument, with ties rounding to + * negative infinity. + *

    + * Special cases: + *

    • If the argument is NaN, the result is 0. + *
    • If the argument is negative infinity or any value less than or + * equal to the value of {@code Integer.MIN_VALUE}, the result is + * equal to the value of {@code Integer.MIN_VALUE}. + *
    • If the argument is positive infinity or any value greater than or + * equal to the value of {@code Integer.MAX_VALUE}, the result is + * equal to the value of {@code Integer.MAX_VALUE}.
    + * + * @param coordinate a floating-point value to be rounded to an integer + * @return the value of the argument rounded to the nearest + * {@code int} value. + */ + public static int clipRound(final double coordinate) { + final double newv = coordinate - 0.5; + if (newv < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } + if (newv > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + return (int) Math.ceil(newv); + } + + /** * Multiply the scale factor {@code sv} and the value {@code v} with * appropriate clipping to the bounds of Integer resolution. If the answer * would be greater than {@code Integer.MAX_VALUE} then {@code @@ -559,6 +590,33 @@ /** * Returns a Region object that represents the intersection of + * this object with the specified Rectangle2D. The return value + * may be this same object if no clipping occurs. + */ + public Region getIntersection(final Rectangle2D r) { + if (r instanceof Rectangle) { + return getIntersection((Rectangle) r); + } + return getIntersectionXYXY(r.getMinX(), r.getMinY(), r.getMaxX(), + r.getMaxY()); + } + + /** + * Returns a Region object that represents the intersection of + * this object with the specified rectangular area. The return + * value may be this same object if no clipping occurs. + */ + public Region getIntersectionXYXY(double lox, double loy, double hix, + double hiy) { + if (isNaN(lox) || isNaN(loy) || isNaN(hix) || isNaN(hiy)) { + return EMPTY_REGION; + } + return getIntersectionXYXY(clipRound(lox), clipRound(loy), + clipRound(hix), clipRound(hiy)); + } + + /** + * Returns a Region object that represents the intersection of * this object with the specified rectangular area. The return * value may be this same object if no clipping occurs. */ diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java --- a/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java Fri Nov 11 16:44:36 2016 +0100 @@ -30,6 +30,7 @@ import static java.awt.RenderingHints.*; import java.awt.event.*; import java.awt.font.*; +import java.awt.geom.Rectangle2D; import java.awt.geom.AffineTransform; import static java.awt.geom.AffineTransform.TYPE_FLIP; import static java.awt.geom.AffineTransform.TYPE_TRANSLATION; @@ -723,10 +724,31 @@ int length, int x, int y) { + return (int) drawChars(c, g, data, offset, length, x, y, false); + } + + public static float drawChars(JComponent c, Graphics g, + char[] data, + int offset, + int length, + float x, + float y) { + return drawChars(c, g, data, offset, length, x, y, true); + } + + public static float drawChars(JComponent c, Graphics g, + char[] data, + int offset, + int length, + float x, + float y, + boolean useFPAPI) { if ( length <= 0 ) { //no need to paint empty strings return x; } - int nextX = x + getFontMetrics(c, g).charsWidth(data, offset, length); + float nextX = x + getFontCharsWidth(data, offset, length, + getFontMetrics(c, g), + useFPAPI); if (isPrinting(g)) { Graphics2D g2d = getGraphics2D(g); if (g2d != null) { @@ -766,8 +788,14 @@ Object aaHint = (c == null) ? null : c.getClientProperty(KEY_TEXT_ANTIALIASING); - if (aaHint != null && (g instanceof Graphics2D)) { - Graphics2D g2 = (Graphics2D)g; + + if (!(g instanceof Graphics2D)) { + g.drawChars(data, offset, length, (int) x, (int) y); + return nextX; + } + + Graphics2D g2 = (Graphics2D) g; + if (aaHint != null) { Object oldContrast = null; Object oldAAValue = g2.getRenderingHint(KEY_TEXT_ANTIALIASING); @@ -788,7 +816,7 @@ } } - g.drawChars(data, offset, length, x, y); + g2.drawString(new String(data, offset, length), x, y); if (oldAAValue != null) { g2.setRenderingHint(KEY_TEXT_ANTIALIASING, oldAAValue); @@ -798,19 +826,59 @@ } } else { - g.drawChars(data, offset, length, x, y); + g2.drawString(new String(data, offset, length), x, y); } return nextX; } + public static float getFontCharWidth(char c, FontMetrics fm, + boolean useFPAPI) + { + return getFontCharsWidth(new char[]{c}, 0, 1, fm, useFPAPI); + } + + public static float getFontCharsWidth(char[] data, int offset, int len, + FontMetrics fm, + boolean useFPAPI) + { + return len == 0 ? 0 : getFontStringWidth(new String(data, offset, len), + fm, useFPAPI); + } + + public static float getFontStringWidth(String data, FontMetrics fm, + boolean useFPAPI) + { + if (useFPAPI) { + Rectangle2D bounds = fm.getFont() + .getStringBounds(data, fm.getFontRenderContext()); + return (float) bounds.getWidth(); + } else { + return fm.stringWidth(data); + } + } + /* * see documentation for drawChars * returns the advance */ public static float drawString(JComponent c, Graphics g, AttributedCharacterIterator iterator, - int x, - int y) { + int x, int y) + { + return drawStringImpl(c, g, iterator, x, y); + } + + public static float drawString(JComponent c, Graphics g, + AttributedCharacterIterator iterator, + float x, float y) + { + return drawStringImpl(c, g, iterator, x, y); + } + + private static float drawStringImpl(JComponent c, Graphics g, + AttributedCharacterIterator iterator, + float x, float y) + { float retVal; boolean isPrinting = isPrinting(g); @@ -825,8 +893,8 @@ Graphics2D g2d = getGraphics2D(g); if (g2d == null) { - g.drawString(iterator,x,y); //for the cases where advance - //matters it should not happen + g.drawString(iterator, (int)x, (int)y); //for the cases where advance + //matters it should not happen retVal = x; } else { diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/classes/sun/swing/plaf/GTKKeybindings.java --- a/jdk/src/java.desktop/share/classes/sun/swing/plaf/GTKKeybindings.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/classes/sun/swing/plaf/GTKKeybindings.java Fri Nov 11 16:44:36 2016 +0100 @@ -219,6 +219,38 @@ "KP_UP", "selectPrevious" }), + "Desktop.ancestorInputMap", + new UIDefaults.LazyInputMap(new Object[] { + "ctrl F5", "restore", + "ctrl F4", "close", + "ctrl F7", "move", + "ctrl F8", "resize", + "RIGHT", "right", + "KP_RIGHT", "right", + "shift RIGHT", "shrinkRight", + "shift KP_RIGHT", "shrinkRight", + "LEFT", "left", + "KP_LEFT", "left", + "shift LEFT", "shrinkLeft", + "shift KP_LEFT", "shrinkLeft", + "UP", "up", + "KP_UP", "up", + "shift UP", "shrinkUp", + "shift KP_UP", "shrinkUp", + "DOWN", "down", + "KP_DOWN", "down", + "shift DOWN", "shrinkDown", + "shift KP_DOWN", "shrinkDown", + "ESCAPE", "escape", + "ctrl F9", "minimize", + "ctrl F10", "maximize", + "ctrl F6", "selectNextFrame", + "ctrl TAB", "selectNextFrame", + "ctrl alt F6", "selectNextFrame", + "shift ctrl alt F6", "selectPreviousFrame", + "ctrl F12", "navigateNext", + "shift ctrl F12", "navigatePrevious" + }), "EditorPane.focusInputMap", multilineInputMap, "FileChooser.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[]{ diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.c --- a/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.c Fri Nov 11 16:44:36 2016 +0100 @@ -25,7 +25,12 @@ #include "splashscreen_impl.h" #include "splashscreen_gfx_impl.h" - +#define BUFF_SIZE 1024 +#ifdef _MSC_VER +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif int splashIsVisible = 0; Splash * @@ -392,5 +397,101 @@ SPLASHEXPORT int SplashGetScaledImgNameMaxPstfixLen(const char *fileName){ - return strlen(fileName) + strlen(".java-scale-200") + 1; + return strlen(fileName) + strlen("@100pct") + 1; } + +jboolean GetScaledImageName(const char *fileName, char *scaleImageName, + float *scaleFactor, const size_t scaledImageLength) { + if (*scaleFactor > 1.0) { + FILE *fp = NULL; + char scaledImgPct[BUFF_SIZE]; + char scaledImgX[BUFF_SIZE]; + char *scaledImageXName = NULL; + char *scaledImagePctName = malloc(scaledImageLength); + char *dupFileName = strdup(fileName); + char *fileExtension = strrchr(dupFileName, '.'); + size_t lengthPct = 0; + size_t lengthX = 0; + int retValPct = 0; + int retValX = 0; + jboolean isPctScaledImage = (*scaleFactor * 100) != ((int) (*scaleFactor)) *100; + snprintf(scaledImgPct, BUFF_SIZE, "%s%d%s", "@", + (int) (*scaleFactor * 100), "pct"); + if (!isPctScaledImage) { + scaledImageXName = malloc(scaledImageLength); + snprintf(scaledImgX, BUFF_SIZE, "%s%d%s", "@", (int) (*scaleFactor), "x"); + } + /*File is missing extension */ + if (fileExtension == NULL) { + lengthPct = strlen(dupFileName) + + strlen(scaledImgPct) + 1; + if (!isPctScaledImage) { + lengthX = strlen(dupFileName) + + strlen(scaledImgX) + 1; + } + if (lengthPct > scaledImageLength || lengthX > scaledImageLength) { + cleanUp(dupFileName, scaledImageXName, scaledImagePctName, scaleFactor); + return JNI_FALSE; + } + retValPct = snprintf(scaledImagePctName, lengthPct, "%s%s", dupFileName, + scaledImgPct); + if (!isPctScaledImage) { + retValX = snprintf(scaledImageXName, lengthX, "%s%s", dupFileName, + scaledImgX); + } + if ((retValPct < 0 || (retValPct > lengthPct - 1)) || + (retValX < 0 || (retValX > lengthX - 1))) { + cleanUp(dupFileName, scaledImageXName, scaledImagePctName, scaleFactor); + return JNI_FALSE; + } + } else { + int length_Without_Ext = fileExtension - dupFileName; + lengthPct = length_Without_Ext + strlen(scaledImgPct) + + strlen(fileExtension) + 1; + if (!isPctScaledImage) { + lengthX = length_Without_Ext + strlen(scaledImgX) + + strlen(fileExtension) + 1; + } + if (lengthPct > scaledImageLength || lengthX > scaledImageLength) { + cleanUp(dupFileName, scaledImageXName, scaledImagePctName, scaleFactor); + return JNI_FALSE; + } + retValPct = snprintf(scaledImagePctName, lengthPct, "%.*s%s%s", + length_Without_Ext, dupFileName, scaledImgPct, fileExtension); + if (!isPctScaledImage) { + retValX = snprintf(scaledImageXName, lengthX, "%.*s%s%s", + length_Without_Ext, dupFileName, scaledImgX, fileExtension); + } + if ((retValPct < 0 || (retValPct > lengthPct - 1)) || + (retValX < 0 || (retValX > lengthX - 1))) { + cleanUp(dupFileName, scaledImageXName, scaledImagePctName, scaleFactor); + return JNI_FALSE; + } + } + free(dupFileName); + if (!(fp = fopen(scaledImagePctName, "r"))) { + if (!isPctScaledImage && (fp = fopen(scaledImageXName, "r"))) { + fclose(fp); + strcpy(scaleImageName, scaledImageXName); + free(scaledImageXName); + free(scaledImagePctName); + return JNI_TRUE; + } + cleanUp(NULL, scaledImageXName, scaledImagePctName, scaleFactor); + return JNI_FALSE; + } + fclose(fp); + strcpy(scaleImageName, scaledImagePctName); + free(scaledImageXName); + free(scaledImagePctName); + return JNI_TRUE; + } + return JNI_FALSE; +} + +void cleanUp(char *fName, char *xName, char *pctName, float *scaleFactor) { + *scaleFactor = 1; + free(fName); + free(xName); + free(pctName); +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.h --- a/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.h Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.h Fri Nov 11 16:44:36 2016 +0100 @@ -150,7 +150,9 @@ void SplashCleanup(Splash * splash); void SplashSetScaleFactor(float scaleFactor); int SplashGetScaledImgNameMaxPstfixLen(const char *fileName); - +void cleanUp(char *fName, char *xName, char *pctName, float *scaleFactor); +jboolean GetScaledImageName(const char *fileName, char *scaledImgName, + float *scaleFactor, const size_t scaledImageLength); typedef struct SplashStream { int (*read)(void* pStream, void* pData, int nBytes); int (*peek)(void* pStream); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java Fri Nov 11 16:44:36 2016 +0100 @@ -301,7 +301,10 @@ } private void resetWMSetInsets() { - wm_set_insets = null; + if (XWM.getWMID() != XWM.UNITY_COMPIZ_WM) { + currentInsets = new Insets(0, 0, 0, 0); + wm_set_insets = null; + } } public void handlePropertyNotify(XEvent xev) { @@ -352,7 +355,7 @@ // and the initially guessed insets were wrong handleCorrectInsets(in); } - } else if (!dimensions.isClientSizeSet()) { + } else if (!insets_corrected || !dimensions.isClientSizeSet()) { insets_corrected = true; // initial insets were guessed correctly. Re-request // frame bounds because they may be changed by WM if the @@ -908,7 +911,6 @@ public void setResizable(boolean resizable) { int fs = winAttr.functions; if (!isResizable() && resizable) { - currentInsets = new Insets(0, 0, 0, 0); resetWMSetInsets(); if (!isEmbedded()) { setReparented(false); @@ -922,7 +924,6 @@ winAttr.functions = fs; XWM.setShellResizable(this); } else if (isResizable() && !resizable) { - currentInsets = new Insets(0, 0, 0, 0); resetWMSetInsets(); if (!isEmbedded()) { setReparented(false); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/unix/native/libawt_xawt/awt/Xrandr.h --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/Xrandr.h Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/Xrandr.h Fri Nov 11 16:44:36 2016 +0100 @@ -118,6 +118,19 @@ RRMode *modes; } XRROutputInfo; +typedef struct { + Time timestamp; + int x, y; + unsigned int width, height; + RRMode mode; + Rotation rotation; + int noutput; + RROutput *outputs; + Rotation rotations; + int npossible; + RROutput *possible; +} XRRCrtcInfo; + XRRScreenResources *XRRGetScreenResources (Display *dpy, Window window); void XRRFreeScreenResources (XRRScreenResources *resources); @@ -126,6 +139,11 @@ RROutput output); void XRRFreeOutputInfo (XRROutputInfo *outputInfo); +XRRCrtcInfo *XRRGetCrtcInfo (Display *dpy, XRRScreenResources *resources, + RRCrtc crtc); +void XRRFreeCrtcInfo (XRRCrtcInfo *crtcInfo); + + /* internal representation is private to the library */ typedef struct _XRRScreenConfiguration XRRScreenConfiguration; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c Fri Nov 11 16:44:36 2016 +0100 @@ -1667,6 +1667,11 @@ typedef void (*XRRFreeOutputInfoType)(XRROutputInfo *outputInfo); +typedef XRRCrtcInfo* (*XRRGetCrtcInfoType)(Display *dpy, + XRRScreenResources *resources, RRCrtc crtc); + +typedef void (*XRRFreeCrtcInfoType)(XRRCrtcInfo *crtcInfo); + static XRRQueryVersionType awt_XRRQueryVersion; static XRRGetScreenInfoType awt_XRRGetScreenInfo; static XRRFreeScreenConfigInfoType awt_XRRFreeScreenConfigInfo; @@ -1680,6 +1685,8 @@ static XRRFreeScreenResourcesType awt_XRRFreeScreenResources; static XRRGetOutputInfoType awt_XRRGetOutputInfo; static XRRFreeOutputInfoType awt_XRRFreeOutputInfo; +static XRRGetCrtcInfoType awt_XRRGetCrtcInfo; +static XRRFreeCrtcInfoType awt_XRRFreeCrtcInfo; #define LOAD_XRANDR_FUNC(f) \ do { \ @@ -1755,6 +1762,8 @@ LOAD_XRANDR_FUNC(XRRFreeScreenResources); LOAD_XRANDR_FUNC(XRRGetOutputInfo); LOAD_XRANDR_FUNC(XRRFreeOutputInfo); + LOAD_XRANDR_FUNC(XRRGetCrtcInfo); + LOAD_XRANDR_FUNC(XRRFreeCrtcInfo); return JNI_TRUE; } @@ -1895,7 +1904,49 @@ AWT_LOCK(); - if (screen < ScreenCount(awt_display)) { + if (usingXinerama && XScreenCount(awt_display) > 0) { + XRRScreenResources *res = awt_XRRGetScreenResources(awt_display, + RootWindow(awt_display, 0)); + if (res) { + if (res->noutput > screen) { + XRROutputInfo *output_info = awt_XRRGetOutputInfo(awt_display, + res, res->outputs[screen]); + if (output_info) { + if (output_info->crtc) { + XRRCrtcInfo *crtc_info = + awt_XRRGetCrtcInfo (awt_display, res, + output_info->crtc); + if (crtc_info) { + if (crtc_info->mode) { + int i; + for (i = 0; i < res->nmode; i++) { + XRRModeInfo *mode = &res->modes[i]; + if (mode->id == crtc_info->mode) { + float rate = 0; + if (mode->hTotal && mode->vTotal) { + rate = ((float)mode->dotClock / + ((float)mode->hTotal * + (float)mode->vTotal)); + } + displayMode = X11GD_CreateDisplayMode( + env, + mode->width, + mode->height, + BIT_DEPTH_MULTI, + (int)(rate +.2)); + break; + } + } + } + awt_XRRFreeCrtcInfo(crtc_info); + } + } + awt_XRRFreeOutputInfo(output_info); + } + } + awt_XRRFreeScreenResources(res); + } + } else { config = awt_XRRGetScreenInfo(awt_display, RootWindow(awt_display, screen)); @@ -1954,7 +2005,7 @@ res, res->outputs[screen]); if (output_info) { int i; - for (i = 0; i < res->nmode; i++) { + for (i = 0; i < output_info->nmode; i++) { RRMode m = output_info->modes[i]; int j; XRRModeInfo *mode; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c Fri Nov 11 16:44:36 2016 +0100 @@ -35,9 +35,6 @@ #include #include "awt.h" -#define GTHREAD_LIB_VERSIONED VERSIONED_JNI_LIB_NAME("gthread-2.0", "0") -#define GTHREAD_LIB JNI_LIB_NAME("gthread-2.0") - #define GTK_TYPE_BORDER ((*fp_gtk_border_get_type)()) #define G_TYPE_FUNDAMENTAL_SHIFT (2) diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h Fri Nov 11 16:44:36 2016 +0100 @@ -351,9 +351,6 @@ guint ellipsize : 3; }; - -typedef struct _GThreadFunctions GThreadFunctions; - /** * Returns : * NULL if the GLib library is compatible with the given version, or a string @@ -449,17 +446,6 @@ static void (*fp_g_list_free) (GList *list); static void (*fp_g_list_free_full) (GList *list, GDestroyNotify free_func); -/** - * This function is available for GLIB > 2.20, so it MUST be - * called within GLIB_CHECK_VERSION(2, 20, 0) check. - */ -static gboolean (*fp_g_thread_get_initialized)(void); - -static void (*fp_g_thread_init)(GThreadFunctions *vtable); -static void (*fp_gdk_threads_init)(void); -static void (*fp_gdk_threads_enter)(void); -static void (*fp_gdk_threads_leave)(void); - static gboolean (*fp_gtk_show_uri)(GdkScreen *screen, const gchar *uri, guint32 timestamp, GError **error); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c Fri Nov 11 16:44:36 2016 +0100 @@ -35,6 +35,7 @@ #include "awt.h" static void *gtk3_libhandle = NULL; +static void *gthread_libhandle = NULL; static jmp_buf j; @@ -87,6 +88,15 @@ return result; } +static void* dl_symbol_gthread(const char* name) +{ + void* result = dlsym(gthread_libhandle, name); + if (!result) + longjmp(j, NO_SYMBOL_EXCEPTION); + + return result; +} + gboolean gtk3_check(const char* lib_name, gboolean load) { if (gtk3_libhandle != NULL) { @@ -261,6 +271,13 @@ return FALSE; } + gthread_libhandle = dlopen(GTHREAD_LIB_VERSIONED, RTLD_LAZY | RTLD_LOCAL); + if (gthread_libhandle == NULL) { + gthread_libhandle = dlopen(GTHREAD_LIB, RTLD_LAZY | RTLD_LOCAL); + if (gthread_libhandle == NULL) + return FALSE; + } + if (setjmp(j) == 0) { fp_gtk_check_version = dl_symbol("gtk_check_version"); @@ -530,8 +547,8 @@ fp_g_path_get_dirname = dl_symbol("g_path_get_dirname"); - fp_gdk_threads_enter = ∅ - fp_gdk_threads_leave = ∅ + fp_gdk_threads_enter = dl_symbol("gdk_threads_enter"); + fp_gdk_threads_leave = dl_symbol("gdk_threads_leave"); /** * Functions for sun_awt_X11_GtkFileDialogPeer.c @@ -556,6 +573,9 @@ dlclose(gtk3_libhandle); gtk3_libhandle = NULL; + dlclose(gthread_libhandle); + gthread_libhandle = NULL; + return NULL; } @@ -651,6 +671,7 @@ dlerror(); dlclose(gtk3_libhandle); + dlclose(gthread_libhandle); if ((gtk3_error = dlerror()) != NULL) { return FALSE; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h Fri Nov 11 16:44:36 2016 +0100 @@ -33,6 +33,9 @@ #define TRUE (!FALSE) #endif +#define GTHREAD_LIB_VERSIONED VERSIONED_JNI_LIB_NAME("gthread-2.0", "0") +#define GTHREAD_LIB JNI_LIB_NAME("gthread-2.0") + #define _G_TYPE_CIC(ip, gt, ct) ((ct*) ip) #define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type) \ (_G_TYPE_CIC ((instance), (g_type), c_type)) @@ -555,6 +558,13 @@ gboolean gtk_load(JNIEnv *env, GtkVersion version, gboolean verbose); gboolean gtk_check_version(GtkVersion version); +typedef struct _GThreadFunctions GThreadFunctions; +static gboolean (*fp_g_thread_get_initialized)(void); +static void (*fp_g_thread_init)(GThreadFunctions *vtable); +static void (*fp_gdk_threads_init)(void); +static void (*fp_gdk_threads_enter)(void); +static void (*fp_gdk_threads_leave)(void); + extern GtkApi* gtk; #endif /* !_GTK_INTERFACE_H */ diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XWindow.c --- a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XWindow.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XWindow.c Fri Nov 11 16:44:36 2016 +0100 @@ -818,6 +818,32 @@ } return awt_UseXKB; } + +/* + * Map a keycode to the corresponding keysym. + * This replaces the deprecated X11 function XKeycodeToKeysym + */ +KeySym +keycodeToKeysym(Display *display, KeyCode keycode, int index) { + static int min_kc = -1; + static int max_kc; + if (min_kc == -1) { + (void) XDisplayKeycodes(display, &min_kc, &max_kc); + } + if (keycode < min_kc || keycode > max_kc || index < 0) { + return NoSymbol; + } + int num_syms; + KeySym *key_syms = XGetKeyboardMapping(display, keycode, 1, &num_syms); + if (index >= num_syms) { + XFree(key_syms); + return NoSymbol; + } + KeySym ks = key_syms[index]; + XFree(key_syms); + return ks; +} + static Boolean isKPevent(XEvent *event) { @@ -833,14 +859,14 @@ */ Boolean bsun = isXsunServer( event ); Boolean bxkb = isXKBenabled( event->xkey.display ); - return IsKeypadKey( XKeycodeToKeysym(event->xkey.display, event->xkey.keycode,(bsun && !bxkb ? 2 : 1) ) ); + return IsKeypadKey( keycodeToKeysym(event->xkey.display, event->xkey.keycode,(bsun && !bxkb ? 2 : 1) ) ); } static void dumpKeysymArray(XEvent *event) { - printf(" 0x%X\n",XKeycodeToKeysym(event->xkey.display, event->xkey.keycode, 0)); - printf(" 0x%X\n",XKeycodeToKeysym(event->xkey.display, event->xkey.keycode, 1)); - printf(" 0x%X\n",XKeycodeToKeysym(event->xkey.display, event->xkey.keycode, 2)); - printf(" 0x%X\n",XKeycodeToKeysym(event->xkey.display, event->xkey.keycode, 3)); + printf(" 0x%X\n",keycodeToKeysym(event->xkey.display, event->xkey.keycode, 0)); + printf(" 0x%X\n",keycodeToKeysym(event->xkey.display, event->xkey.keycode, 1)); + printf(" 0x%X\n",keycodeToKeysym(event->xkey.display, event->xkey.keycode, 2)); + printf(" 0x%X\n",keycodeToKeysym(event->xkey.display, event->xkey.keycode, 3)); } /* * In a next redesign, get rid of this code altogether. @@ -855,20 +881,20 @@ } if( isXsunServer( event ) && !awt_UseXKB) { if( (event->xkey.state & ShiftMask) ) { // shift modifier is on - *keysym = XKeycodeToKeysym(event->xkey.display, + *keysym = keycodeToKeysym(event->xkey.display, event->xkey.keycode, 3); }else { - *keysym = XKeycodeToKeysym(event->xkey.display, + *keysym = keycodeToKeysym(event->xkey.display, event->xkey.keycode, 2); } } else { if( (event->xkey.state & ShiftMask) || // shift modifier is on ((event->xkey.state & LockMask) && // lock modifier is on (awt_ModLockIsShiftLock)) ) { // it is interpreted as ShiftLock - *keysym = XKeycodeToKeysym(event->xkey.display, + *keysym = keycodeToKeysym(event->xkey.display, event->xkey.keycode, 0); }else{ - *keysym = XKeycodeToKeysym(event->xkey.display, + *keysym = keycodeToKeysym(event->xkey.display, event->xkey.keycode, 1); } } @@ -903,7 +929,7 @@ Perhaps using the index (modn in awt_MToolkit.c:setup_modifier_map) would be more correct. */ - *keysym = XKeycodeToKeysym(event->xkey.display, + *keysym = keycodeToKeysym(event->xkey.display, event->xkey.keycode, 2); if (originalKeysym != *keysym) { DTRACE_PRINTLN3("%s originalKeysym=0x%x, keysym=0x%x", @@ -999,7 +1025,6 @@ } } - /* This function is called as the keyChar parameter of a call to * awt_post_java_key_event. It depends on being called after adjustKeySym. * diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XlibWrapper.c --- a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XlibWrapper.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XlibWrapper.c Fri Nov 11 16:44:36 2016 +0100 @@ -49,6 +49,9 @@ #include +// From XWindow.c +extern KeySym keycodeToKeysym(Display *display, KeyCode keycode, int index); + #if defined(DEBUG) static jmethodID lockIsHeldMID = NULL; @@ -1286,7 +1289,7 @@ // report arbitrarily false. return JNI_FALSE; } else { - long ks2 = XKeycodeToKeysym((Display*)jlong_to_ptr(display), kc7, 2); + long ks2 = keycodeToKeysym((Display*)jlong_to_ptr(display), kc7, 2); if( ks2 == XK_KP_7 ) { //XXX If some Xorg server would put XK_KP_7 in keysymarray[2] as well, //XXX for yet unknown to me reason, the sniffer would lie. @@ -1915,12 +1918,13 @@ XQueryKeymap( (Display *) jlong_to_ptr(display), (char *) jlong_to_ptr(vector)); } +// XKeycodeToKeysym is deprecated but for compatibility we keep the API. JNIEXPORT jlong JNICALL Java_sun_awt_X11_XlibWrapper_XKeycodeToKeysym(JNIEnv *env, jclass clazz, jlong display, jint keycode, jint index) { AWT_CHECK_HAVE_LOCK_RETURN(0); - return XKeycodeToKeysym((Display*) jlong_to_ptr(display), (unsigned int)keycode, (int)index); + return keycodeToKeysym((Display*)jlong_to_ptr(display), (unsigned int)keycode, (int)index); } JNIEXPORT jint JNICALL diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Taskbar.c --- a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Taskbar.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Taskbar.c Fri Nov 11 16:44:36 2016 +0100 @@ -97,10 +97,7 @@ void callback(DbusmenuMenuitem* mi, guint ts, jobject data) { JNIEnv* env = (JNIEnv*) JNU_GetEnv(jvm, JNI_VERSION_1_2); - (*env)->CallStaticVoidMethod(env, jTaskbarCls, jTaskbarCallback, data, - fp_dbusmenu_menuitem_property_get_int(mi, "toggle-state") - ? JNI_FALSE - : JNI_TRUE); + (*env)->CallStaticVoidMethod(env, jTaskbarCls, jTaskbarCallback, data); } /* @@ -243,10 +240,9 @@ if (!menu) { menu = fp_dbusmenu_menuitem_new(); + fp_unity_launcher_entry_set_quicklist(entry, menu); } - fp_unity_launcher_entry_set_quicklist(entry, menu); - GList* list = fp_dbusmenu_menuitem_take_children(menu); gtk->g_list_free_full(list, gtk->g_object_unref); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c --- a/jdk/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c Fri Nov 11 16:44:36 2016 +0100 @@ -753,6 +753,9 @@ XMapRaised(splash->display, splash->window); SplashUpdateShape(splash); SplashRedrawWindow(splash); + //map the splash co-ordinates as per system scale + splash->x /= splash->scaleFactor; + splash->y /= splash->scaleFactor; SplashEventLoop(splash); } SplashUnlock(splash); @@ -807,50 +810,6 @@ return JNI_FALSE; #endif *scaleFactor = getNativeScaleFactor(NULL); - if (*scaleFactor == 2.0) { - size_t length = 0; - char *stringToAppend = ".java-scale2x"; - char *dupFileName = strdup(fileName); - char *fileExtension = strrchr(dupFileName, '.'); - if (fileExtension == NULL) { - length = strlen(dupFileName) + strlen(stringToAppend) + 1; - if (length > scaledImageNameLength) { - *scaleFactor = 1; - free(dupFileName); - return JNI_FALSE; - } - int retVal = snprintf(scaledImgName, length, "%s%s", - dupFileName, stringToAppend); - if (retVal < 0 || (retVal != length - 1)) { - free(dupFileName); - *scaleFactor = 1; - return JNI_FALSE; - } - } else { - int length_without_ext = fileExtension - dupFileName; - length = length_without_ext + - strlen(stringToAppend) + strlen(fileExtension) + 1; - if (length > scaledImageNameLength) { - *scaleFactor = 1; - free(dupFileName); - return JNI_FALSE; - } - int retVal = snprintf(scaledImgName, length, "%.*s%s%s", - length_without_ext, dupFileName, stringToAppend, fileExtension); - if (retVal < 0 || retVal != length - 1) { - free(dupFileName); - *scaleFactor = 1; - return JNI_FALSE; - } - } - free(dupFileName); - FILE *fp; - if (!(fp = fopen(scaledImgName, "r"))) { - *scaleFactor = 1; - return JNI_FALSE; - } - fclose(fp); - return JNI_TRUE; - } - return JNI_FALSE; + return GetScaledImageName(fileName, scaledImgName, scaleFactor, scaledImageNameLength); } + diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c --- a/jdk/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c Fri Nov 11 16:44:36 2016 +0100 @@ -535,6 +535,9 @@ splash->hWnd = SplashCreateWindow(splash); if (splash->hWnd) { SplashRedrawWindow(splash); + //map the splash co-ordinates as per system scale + splash->x /= splash->scaleFactor; + splash->y /= splash->scaleFactor; SplashUnlock(splash); SplashMessagePump(); SplashLock(splash); @@ -582,55 +585,7 @@ *scaleFactor = 1.0; GetScreenDpi(getPrimaryMonitor(), &dpiScaleX, &dpiScaleY); *scaleFactor = dpiScaleX > 0 ? dpiScaleX / 96 : *scaleFactor; - if (*scaleFactor > 1.0) { - char strDpi[BUFF_SIZE]; - char *dupFileName = strdup(fileName); - char *fileExtension = strrchr(dupFileName, '.'); - char *nameToAppend = ".scale-"; - size_t length = 0; - int retVal = 0; - _snprintf(strDpi, BUFF_SIZE, "%d", (int)dpiScaleX); - /*File is missing extension */ - if (fileExtension == NULL) { - length = strlen(dupFileName) + strlen(nameToAppend) + - strlen(strDpi) + 1; - if (length > scaledImageLength) { - *scaleFactor = 1; - free(dupFileName); - return JNI_FALSE; - } - retVal = _snprintf(scaleImageName, length, "%s%s%s", dupFileName, - nameToAppend, strDpi); - if (retVal < 0 || (retVal != length - 1)) { - *scaleFactor = 1; - free(dupFileName); - return JNI_FALSE; - } - } - else { - size_t length_Without_Ext = fileExtension - dupFileName; - length = length_Without_Ext + strlen(nameToAppend) + strlen(strDpi) + - strlen(fileExtension) + 1; - if (length > scaledImageLength) { - *scaleFactor = 1; - free(dupFileName); - return JNI_FALSE; - } - retVal = _snprintf(scaleImageName, length, "%.*s%s%s%s", - length_Without_Ext, dupFileName, nameToAppend, strDpi, fileExtension); - if (retVal < 0 || (retVal != length - 1)) { - *scaleFactor = 1; - free(dupFileName); - return JNI_FALSE; - } - } - free(dupFileName); - if (!(fp = fopen(scaleImageName, "r"))) { - *scaleFactor = 1; - return JNI_FALSE; - } - fclose(fp); - return JNI_TRUE; - } - return JNI_FALSE; + return GetScaledImageName(fileName, scaleImageName, + scaleFactor, scaledImageLength); } + diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.logging/share/classes/java/util/logging/LogManager.java --- a/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java Fri Nov 11 16:44:36 2016 +0100 @@ -1449,6 +1449,11 @@ h.close(); } catch (Exception ex) { // Problems closing a handler? Keep going... + } catch (Error e) { + // ignore Errors while shutting down + if (globalHandlersState != STATE_SHUTDOWN) { + throw e; + } } } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java --- a/jdk/src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java Fri Nov 11 16:44:36 2016 +0100 @@ -58,7 +58,8 @@ getString(cd, FILE_NAME), getInt(cd, LINE_NUMBER)); } else { - return new StackTraceElement(getString(cd, MODULE_NAME), + return new StackTraceElement(getString(cd, CLASS_LOADER_NAME), + getString(cd, MODULE_NAME), getString(cd, MODULE_VERSION), getString(cd, CLASS_NAME), getString(cd, METHOD_NAME), @@ -76,13 +77,14 @@ // CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH // stackTraceElementItemNames! final Object[] stackTraceElementItemValues = { + ste.getClassLoaderName(), + ste.getModuleName(), + ste.getModuleVersion(), ste.getClassName(), ste.getMethodName(), ste.getFileName(), ste.getLineNumber(), ste.isNativeMethod(), - ste.getModuleName(), - ste.getModuleVersion(), }; try { return new CompositeDataSupport(stackTraceElementCompositeType, @@ -95,25 +97,29 @@ } // Attribute names - private static final String CLASS_NAME = "className"; - private static final String METHOD_NAME = "methodName"; - private static final String FILE_NAME = "fileName"; - private static final String LINE_NUMBER = "lineNumber"; - private static final String NATIVE_METHOD = "nativeMethod"; - private static final String MODULE_NAME = "moduleName"; - private static final String MODULE_VERSION = "moduleVersion"; + private static final String CLASS_LOADER_NAME = "classLoaderName"; + private static final String MODULE_NAME = "moduleName"; + private static final String MODULE_VERSION = "moduleVersion"; + private static final String CLASS_NAME = "className"; + private static final String METHOD_NAME = "methodName"; + private static final String FILE_NAME = "fileName"; + private static final String LINE_NUMBER = "lineNumber"; + private static final String NATIVE_METHOD = "nativeMethod"; + private static final String[] stackTraceElementItemNames = { + CLASS_LOADER_NAME, + MODULE_NAME, + MODULE_VERSION, CLASS_NAME, METHOD_NAME, FILE_NAME, LINE_NUMBER, NATIVE_METHOD, - MODULE_NAME, - MODULE_VERSION, }; private static final String[] stackTraceElementV9ItemNames = { + CLASS_LOADER_NAME, MODULE_NAME, MODULE_VERSION, }; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.rmi/share/classes/sun/rmi/server/Activation.java --- a/jdk/src/java.rmi/share/classes/sun/rmi/server/Activation.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/Activation.java Fri Nov 11 16:44:36 2016 +0100 @@ -1970,6 +1970,11 @@ AccessController.doPrivileged( new PrivilegedExceptionAction() { public Void run() throws IOException { + boolean disable = Boolean.getBoolean( + "sun.rmi.server.activation.disableErrRedirect"); + if (disable) + return null; + File file = Files.createTempFile("rmid-err", null).toFile(); PrintStream errStream = diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java Fri Nov 11 16:44:36 2016 +0100 @@ -102,6 +102,11 @@ AccessController.doPrivileged((PrivilegedAction) () -> Long.getLong("sun.rmi.transport.tcp.threadKeepAliveTime", 60000)); + /** enable multiplexing protocol */ + private static final boolean enableMultiplexProtocol = // default false + AccessController.doPrivileged((PrivilegedAction) () -> + Boolean.getBoolean("sun.rmi.transport.tcp.enableMultiplexProtocol")); + /** thread pool for connection handlers */ private static final ExecutorService connectionThreadPool = new ThreadPoolExecutor(0, maxConnectionThreads, @@ -796,6 +801,19 @@ break; case TransportConstants.MultiplexProtocol: + + if (!enableMultiplexProtocol) { + if (tcpLog.isLoggable(Log.VERBOSE)) { + tcpLog.log(Log.VERBOSE, "(port " + port + + ") rejecting multiplex protocol"); + } + + // If MultiplexProtocol is disabled, send NACK immediately. + out.writeByte(TransportConstants.ProtocolNack); + out.flush(); + break; + } + if (tcpLog.isLoggable(Log.VERBOSE)) { tcpLog.log(Log.VERBOSE, "(port " + port + ") accepting multiplex protocol"); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java --- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java Fri Nov 11 16:44:36 2016 +0100 @@ -301,12 +301,13 @@ if (!authenticator.ctime.inClockSkew()) throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW); + String alg = AuthTimeWithHash.DEFAULT_HASH_ALG; byte[] hash; try { - hash = MessageDigest.getInstance("MD5") + hash = MessageDigest.getInstance(AuthTimeWithHash.realAlg(alg)) .digest(apReqMessg.authenticator.cipher); } catch (NoSuchAlgorithmException ex) { - throw new AssertionError("Impossible"); + throw new AssertionError("Impossible " + alg); } char[] h = new char[hash.length * 2]; @@ -319,6 +320,7 @@ apReqMessg.ticket.sname.toString(), authenticator.ctime.getSeconds(), authenticator.cusec, + alg, new String(h)); rcache.checkAndStore(KerberosTime.now(), time); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthTime.java --- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthTime.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthTime.java Fri Nov 11 16:44:36 2016 +0100 @@ -116,14 +116,14 @@ if (st.countTokens() != 6) { throw new IOException("Incorrect rcache style"); } - st.nextToken(); + String hashAlg = st.nextToken(); String hash = st.nextToken(); st.nextToken(); client = st.nextToken(); st.nextToken(); server = st.nextToken(); return new AuthTimeWithHash( - client, server, ctime, cusec, hash); + client, server, ctime, cusec, hashAlg, hash); } else { return new AuthTime( client, server, ctime, cusec); diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthTimeWithHash.java --- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthTimeWithHash.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthTimeWithHash.java Fri Nov 11 16:44:36 2016 +0100 @@ -25,6 +25,8 @@ package sun.security.krb5.internal.rcache; +import sun.security.action.GetPropertyAction; + import java.util.Objects; /** @@ -34,14 +36,39 @@ public class AuthTimeWithHash extends AuthTime implements Comparable { + // The hash algorithm can be "HASH" or "SHA256". + public static final String DEFAULT_HASH_ALG; + + static { + if (GetPropertyAction.privilegedGetProperty( + "jdk.krb5.rcache.useMD5", "false").equals("true")) { + DEFAULT_HASH_ALG = "HASH"; + } else { + DEFAULT_HASH_ALG = "SHA256"; + } + } + + public static String realAlg(String alg) { + switch (alg) { + case "HASH": + return "MD5"; + case "SHA256": + return "SHA-256"; + default: + throw new AssertionError(alg + " is not HASH or SHA256"); + } + } + + final String hashAlg; final String hash; /** * Constructs a new AuthTimeWithHash. */ public AuthTimeWithHash(String client, String server, - int ctime, int cusec, String hash) { + int ctime, int cusec, String hashAlg, String hash) { super(client, server, ctime, cusec); + this.hashAlg = hashAlg; this.hash = hash; } @@ -56,6 +83,7 @@ if (!(o instanceof AuthTimeWithHash)) return false; AuthTimeWithHash that = (AuthTimeWithHash)o; return Objects.equals(hash, that.hash) + && Objects.equals(hashAlg, that.hashAlg) && Objects.equals(client, that.client) && Objects.equals(server, that.server) && ctime == that.ctime @@ -91,6 +119,19 @@ /** * Compares with a possibly old style object. Used * in DflCache$Storage#loadAndCheck. + * @return true if all AuthTime fields are the same but different hash + */ + public boolean sameTimeDiffHash(AuthTimeWithHash old) { + if (!this.isSameIgnoresHash(old)) { + return false; + } + return this.hashAlg.equals(old.hashAlg) && + !this.hash.equals(old.hash); + } + + /** + * Compares with a possibly old style object. Used + * in DflCache$Storage#loadAndCheck. * @return true if all AuthTime fields are the same */ public boolean isSameIgnoresHash(AuthTime old) { @@ -112,7 +153,7 @@ String sstring; if (withHash) { cstring = ""; - sstring = String.format("HASH:%s %d:%s %d:%s", hash, + sstring = String.format("%s:%s %d:%s %d:%s", hashAlg, hash, client.length(), client, server.length(), server); } else { diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java --- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java Fri Nov 11 16:44:36 2016 +0100 @@ -96,6 +96,8 @@ * Java also does this way. * * See src/lib/krb5/rcache/rc_io.c and src/lib/krb5/rcache/rc_dfl.c. + * + * Update: New version can use other hash algorithms. */ public class DflCache extends ReplayCache { @@ -300,7 +302,7 @@ if (time.equals(a)) { // Exact match, must be a replay throw new KrbApErrException(Krb5.KRB_AP_ERR_REPEAT); - } else if (time.isSameIgnoresHash(a)) { + } else if (time.sameTimeDiffHash((AuthTimeWithHash)a)) { // Two different authenticators in the same second. // Remember it seeNewButNotSame = true; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.sql/share/classes/java/sql/CallableStatement.java --- a/jdk/src/java.sql/share/classes/java/sql/CallableStatement.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.sql/share/classes/java/sql/CallableStatement.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. 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 @@ -295,7 +295,7 @@ * or getBigDecimal(String parameterName) * @see #setBigDecimal */ - @Deprecated + @Deprecated(since="1.2") BigDecimal getBigDecimal(int parameterIndex, int scale) throws SQLException; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.sql/share/classes/java/sql/Date.java --- a/jdk/src/java.sql/share/classes/java/sql/Date.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.sql/share/classes/java/sql/Date.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. 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 @@ -58,7 +58,7 @@ * @param day 1 to 31 * @deprecated instead use the constructor Date(long date) */ - @Deprecated + @Deprecated(since="1.2") public Date(int year, int month, int day) { super(year, month, day); } @@ -199,7 +199,7 @@ * @exception java.lang.IllegalArgumentException if this method is invoked * @see #setHours */ - @Deprecated + @Deprecated(since="1.2") public int getHours() { throw new java.lang.IllegalArgumentException(); } @@ -212,7 +212,7 @@ * @exception java.lang.IllegalArgumentException if this method is invoked * @see #setMinutes */ - @Deprecated + @Deprecated(since="1.2") public int getMinutes() { throw new java.lang.IllegalArgumentException(); } @@ -225,7 +225,7 @@ * @exception java.lang.IllegalArgumentException if this method is invoked * @see #setSeconds */ - @Deprecated + @Deprecated(since="1.2") public int getSeconds() { throw new java.lang.IllegalArgumentException(); } @@ -238,7 +238,7 @@ * @exception java.lang.IllegalArgumentException if this method is invoked * @see #getHours */ - @Deprecated + @Deprecated(since="1.2") public void setHours(int i) { throw new java.lang.IllegalArgumentException(); } @@ -251,7 +251,7 @@ * @exception java.lang.IllegalArgumentException if this method is invoked * @see #getMinutes */ - @Deprecated + @Deprecated(since="1.2") public void setMinutes(int i) { throw new java.lang.IllegalArgumentException(); } @@ -264,7 +264,7 @@ * @exception java.lang.IllegalArgumentException if this method is invoked * @see #getSeconds */ - @Deprecated + @Deprecated(since="1.2") public void setSeconds(int i) { throw new java.lang.IllegalArgumentException(); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.sql/share/classes/java/sql/DriverManager.java --- a/jdk/src/java.sql/share/classes/java/sql/DriverManager.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.sql/share/classes/java/sql/DriverManager.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. 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 @@ -515,7 +515,7 @@ * @see SecurityManager#checkPermission * @see #getLogStream */ - @Deprecated + @Deprecated(since="1.2") public static void setLogStream(java.io.PrintStream out) { SecurityManager sec = System.getSecurityManager(); @@ -538,7 +538,7 @@ * @deprecated Use {@code getLogWriter} * @see #setLogStream */ - @Deprecated + @Deprecated(since="1.2") public static java.io.PrintStream getLogStream() { return logStream; } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.sql/share/classes/java/sql/PreparedStatement.java --- a/jdk/src/java.sql/share/classes/java/sql/PreparedStatement.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.sql/share/classes/java/sql/PreparedStatement.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. 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 @@ -344,7 +344,7 @@ * this method * @deprecated Use {@code setCharacterStream} */ - @Deprecated + @Deprecated(since="1.2") void setUnicodeStream(int parameterIndex, java.io.InputStream x, int length) throws SQLException; diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.sql/share/classes/java/sql/ResultSet.java --- a/jdk/src/java.sql/share/classes/java/sql/ResultSet.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.sql/share/classes/java/sql/ResultSet.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. 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 @@ -358,7 +358,7 @@ * @deprecated Use {@code getBigDecimal(int columnIndex)} * or {@code getBigDecimal(String columnLabel)} */ - @Deprecated + @Deprecated(since="1.2") BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException; /** @@ -478,7 +478,7 @@ * @deprecated use getCharacterStream in place of * getUnicodeStream */ - @Deprecated + @Deprecated(since="1.2") java.io.InputStream getUnicodeStream(int columnIndex) throws SQLException; /** @@ -646,7 +646,7 @@ * @deprecated Use {@code getBigDecimal(int columnIndex)} * or {@code getBigDecimal(String columnLabel)} */ - @Deprecated + @Deprecated(since="1.2") BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException; /** @@ -764,7 +764,7 @@ * this method * @deprecated use getCharacterStream instead */ - @Deprecated + @Deprecated(since="1.2") java.io.InputStream getUnicodeStream(String columnLabel) throws SQLException; /** diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.sql/share/classes/java/sql/Time.java --- a/jdk/src/java.sql/share/classes/java/sql/Time.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.sql/share/classes/java/sql/Time.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. 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 @@ -60,7 +60,7 @@ * @deprecated Use the constructor that takes a milliseconds value * in place of this constructor */ - @Deprecated + @Deprecated(since="1.2") public Time(int hour, int minute, int second) { super(70, 0, 1, hour, minute, second); } @@ -146,7 +146,7 @@ * method is invoked * @see #setYear */ - @Deprecated + @Deprecated(since="1.2") public int getYear() { throw new java.lang.IllegalArgumentException(); } @@ -160,7 +160,7 @@ * method is invoked * @see #setMonth */ - @Deprecated + @Deprecated(since="1.2") public int getMonth() { throw new java.lang.IllegalArgumentException(); } @@ -173,7 +173,7 @@ * @exception java.lang.IllegalArgumentException if this * method is invoked */ - @Deprecated + @Deprecated(since="1.2") public int getDay() { throw new java.lang.IllegalArgumentException(); } @@ -187,7 +187,7 @@ * method is invoked * @see #setDate */ - @Deprecated + @Deprecated(since="1.2") public int getDate() { throw new java.lang.IllegalArgumentException(); } @@ -201,7 +201,7 @@ * method is invoked * @see #getYear */ - @Deprecated + @Deprecated(since="1.2") public void setYear(int i) { throw new java.lang.IllegalArgumentException(); } @@ -215,7 +215,7 @@ * method is invoked * @see #getMonth */ - @Deprecated + @Deprecated(since="1.2") public void setMonth(int i) { throw new java.lang.IllegalArgumentException(); } @@ -229,7 +229,7 @@ * method is invoked * @see #getDate */ - @Deprecated + @Deprecated(since="1.2") public void setDate(int i) { throw new java.lang.IllegalArgumentException(); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/java.sql/share/classes/java/sql/Timestamp.java --- a/jdk/src/java.sql/share/classes/java/sql/Timestamp.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/java.sql/share/classes/java/sql/Timestamp.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. 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 @@ -88,7 +88,7 @@ * @deprecated instead use the constructor {@code Timestamp(long millis)} * @exception IllegalArgumentException if the nano argument is out of bounds */ - @Deprecated + @Deprecated(since="1.2") public Timestamp(int year, int month, int date, int hour, int minute, int second, int nano) { super(year, month, date, hour, minute, second); diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java --- a/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java Fri Nov 11 16:44:36 2016 +0100 @@ -41,13 +41,13 @@ import javax.accessibility.*; import com.sun.java.accessibility.util.*; +import java.awt.geom.Rectangle2D; import sun.awt.AWTAccessor; import sun.awt.AppContext; import sun.awt.SunToolkit; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; /* * Note: This class has to be public. It's loaded from the VM like this: @@ -1754,7 +1754,7 @@ if (child instanceof JTextComponent) { JTextComponent text = (JTextComponent) child; try { - r = text.modelToView(text.getCaretPosition()); + r = text.modelToView2D(text.getCaretPosition()).getBounds(); if (r != null) { Point p = text.getLocationOnScreen(); r.translate(p.x, p.y); diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.desktop/share/classes/jdk/awt/AWTUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.desktop/share/classes/jdk/awt/AWTUtils.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.awt; + +import java.awt.Component; +import java.awt.Shape; + +import com.sun.awt.AWTUtilities; + +/** + * A class to allow access to JDK-specific utility methods. + * Methods in this class are always deprecated since a caller + * should be aware they may be removed and replaced in the future. + * Access using reflection is highly recommended. + * @since 9 + */ +public final class AWTUtils { + + /** + * No-one should be creating instances of this class. + */ + private AWTUtils() { + } + + /** + * Sets a 'mixing-cutout' shape for the given component. + * + * By default a lightweight component is treated as an opaque rectangle for + * the purposes of the Heavyweight/Lightweight Components Mixing feature. + * This method enables developers to set an arbitrary shape to be cut out + * from heavyweight components positioned underneath the lightweight + * component in the z-order. + *

    + * The {@code shape} argument may have the following values: + *

      + *
    • {@code null} - reverts the default cutout shape (the rectangle equal + * to the component's {@code getBounds()}) + *
    • empty-shape - does not cut out anything from heavyweight + * components. This makes the given lightweight component effectively + * transparent. Note that descendants of the lightweight component still + * affect the shapes of heavyweight components. An example of an + * empty-shape is {@code new Rectangle()}. + *
    • non-empty-shape - the given shape will be cut out from + * heavyweight components. + *
    + *

    + * The most common example when the 'mixing-cutout' shape is needed is a + * glass pane component. The {@link JRootPane#setGlassPane()} method + * automatically sets the empty-shape as the 'mixing-cutout' shape + * for the given glass pane component. If a developer needs some other + * 'mixing-cutout' shape for the glass pane (which is rare), this must be + * changed manually after installing the glass pane to the root pane. + *

    + * Note that the 'mixing-cutout' shape neither affects painting, nor the + * mouse events handling for the given component. It is used exclusively + * for the purposes of the Heavyweight/Lightweight Components Mixing + * feature. + * + * @param component the component that needs non-default + * 'mixing-cutout' shape + * @param shape the new 'mixing-cutout' shape + * @throws NullPointerException if the component argument is {@code null} + * @deprecated This API may be removed or replaced. + */ + @Deprecated + @SuppressWarnings("deprecation") + public static void setComponentMixingCutoutShape(Component component, + Shape shape) { + + AWTUtilities.setComponentMixingCutoutShape(component, shape); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.desktop/share/classes/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.desktop/share/classes/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Provides non-SE desktop APIs. + */ + +module jdk.desktop { + requires public java.desktop; + + exports jdk.awt; +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.editpad/share/classes/jdk/editpad/EditPad.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.editpad/share/classes/jdk/editpad/EditPad.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.editpad; + +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.function.Consumer; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; + +/** + * A minimal Swing editor as a fallback when the user does not specify an + * external editor. + */ +class EditPad implements Runnable { + + private static final String L10N_RB_NAME = "jdk.editpad.resources.l10n"; + private ResourceBundle rb = null; + private final String windowLabel; + private final Consumer errorHandler; + private final String initialText; + private final Runnable closeMark; + private final Consumer saveHandler; + + /** + * Create an Edit Pad minimal editor. + * + * @param windowLabel the label string for the Edit Pad window + * @param errorHandler a handler for unexpected errors + * @param initialText the source to load in the Edit Pad + * @param closeMark a Runnable that is run when Edit Pad closes + * @param saveHandler a handler for changed source (sent the full source) + */ + EditPad(String windowLabel, Consumer errorHandler, String initialText, + Runnable closeMark, Consumer saveHandler) { + this.windowLabel = windowLabel; + this.errorHandler = errorHandler; + this.initialText = initialText; + this.closeMark = closeMark; + this.saveHandler = saveHandler; + } + + @Override + public void run() { + JFrame jframe = new JFrame(windowLabel == null + ? getResourceString("editpad.name") + : windowLabel); + Runnable closer = () -> { + jframe.setVisible(false); + jframe.dispose(); + closeMark.run(); + }; + jframe.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + closer.run(); + } + }); + jframe.setLocationRelativeTo(null); + jframe.setLayout(new BorderLayout()); + JTextArea textArea = new JTextArea(initialText); + textArea.setFont(new Font("monospaced", Font.PLAIN, 13)); + jframe.add(new JScrollPane(textArea), BorderLayout.CENTER); + jframe.add(buttons(closer, textArea), BorderLayout.SOUTH); + + jframe.setSize(800, 600); + jframe.setVisible(true); + } + + private JPanel buttons(Runnable closer, JTextArea textArea) { + FlowLayout flow = new FlowLayout(); + flow.setHgap(35); + JPanel buttons = new JPanel(flow); + addButton(buttons, "editpad.cancel", KeyEvent.VK_C, e -> { + closer.run(); + }); + addButton(buttons, "editpad.accept", KeyEvent.VK_A, e -> { + saveHandler.accept(textArea.getText()); + }); + addButton(buttons, "editpad.exit", KeyEvent.VK_X, e -> { + saveHandler.accept(textArea.getText()); + closer.run(); + }); + return buttons; + } + + private void addButton(JPanel buttons, String rkey, int mnemonic, ActionListener action) { + JButton but = new JButton(getResourceString(rkey)); + but.setMnemonic(mnemonic); + buttons.add(but); + but.addActionListener(action); + } + + private String getResourceString(String key) { + if (rb == null) { + try { + rb = ResourceBundle.getBundle(L10N_RB_NAME); + } catch (MissingResourceException mre) { + error("Cannot find ResourceBundle: %s", L10N_RB_NAME); + return ""; + } + } + String s; + try { + s = rb.getString(key); + } catch (MissingResourceException mre) { + error("Missing resource: %s in %s", key, L10N_RB_NAME); + return ""; + } + return s; + } + + private void error(String fmt, Object... args) { + errorHandler.accept(String.format(fmt, args)); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.editpad/share/classes/jdk/editpad/EditPadProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.editpad/share/classes/jdk/editpad/EditPadProvider.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.editpad; + +import java.util.concurrent.CountDownLatch; +import java.util.function.Consumer; +import javax.swing.SwingUtilities; +import jdk.internal.editor.spi.BuildInEditorProvider; + +/** + * Defines the provider of an Edit Pad implementation. + * + * @author Robert Field + */ +public class EditPadProvider implements BuildInEditorProvider { + + /** + * @return the rank of a provider, greater is better. + */ + @Override + public int rank() { + return 5; + } + + /** + * Create an Edit Pad minimal editor. + * + * @param windowLabel the label string for the Edit Pad window, or null, + * for default window label + * @param initialText the source to load in the Edit Pad + * @param saveHandler a handler for changed source (can be sent the full source) + * @param errorHandler a handler for unexpected errors + */ + @Override + public void edit(String windowLabel, String initialText, + Consumer saveHandler, Consumer errorHandler) { + CountDownLatch closeLock = new CountDownLatch(1); + SwingUtilities.invokeLater( + new EditPad(windowLabel, errorHandler, initialText, closeLock::countDown, saveHandler)); + do { + try { + closeLock.await(); + break; + } catch (InterruptedException ex) { + // ignore and loop + } + } while (true); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.editpad/share/classes/jdk/editpad/resources/l10n.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.editpad/share/classes/jdk/editpad/resources/l10n.properties Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,29 @@ +# +# Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +editpad.name = Edit Pad +editpad.cancel = Cancel +editpad.accept = Accept +editpad.exit = Exit diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.editpad/share/classes/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.editpad/share/classes/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Implementation of the edit pad service. + */ +module jdk.editpad { + requires jdk.internal.ed; + requires java.desktop; + provides jdk.internal.editor.spi.BuildInEditorProvider + with jdk.editpad.EditPadProvider; +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.internal.ed/share/classes/jdk/internal/editor/external/ExternalEditor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.internal.ed/share/classes/jdk/internal/editor/external/ExternalEditor.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.editor.external; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.ClosedWatchServiceException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.util.Arrays; +import java.util.Scanner; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; + +/** + * Wrapper for controlling an external editor. + */ +public class ExternalEditor { + private final Consumer errorHandler; + private final Consumer saveHandler; + private final boolean wait; + + private final Runnable suspendInteractiveInput; + private final Runnable resumeInteractiveInput; + private final Runnable promptForNewLineToEndWait; + + private WatchService watcher; + private Thread watchedThread; + private Path dir; + private Path tmpfile; + + /** + * Launch an external editor. + * + * @param cmd the command to launch (with parameters) + * @param initialText initial text in the editor buffer + * @param errorHandler handler for error messages + * @param saveHandler handler sent the buffer contents on save + * @param suspendInteractiveInput a callback to suspend caller (shell) input + * @param resumeInteractiveInput a callback to resume caller input + * @param wait true, if editor process termination cannot be used to + * determine when done + * @param promptForNewLineToEndWait a callback to prompt for newline if + * wait==true + */ + public static void edit(String[] cmd, String initialText, + Consumer errorHandler, + Consumer saveHandler, + Runnable suspendInteractiveInput, + Runnable resumeInteractiveInput, + boolean wait, + Runnable promptForNewLineToEndWait) { + ExternalEditor ed = new ExternalEditor(errorHandler, saveHandler, suspendInteractiveInput, + resumeInteractiveInput, wait, promptForNewLineToEndWait); + ed.edit(cmd, initialText); + } + + ExternalEditor(Consumer errorHandler, + Consumer saveHandler, + Runnable suspendInteractiveInput, + Runnable resumeInteractiveInput, + boolean wait, + Runnable promptForNewLineToEndWait) { + this.errorHandler = errorHandler; + this.saveHandler = saveHandler; + this.wait = wait; + this.suspendInteractiveInput = suspendInteractiveInput; + this.resumeInteractiveInput = resumeInteractiveInput; + this.promptForNewLineToEndWait = promptForNewLineToEndWait; + } + + private void edit(String[] cmd, String initialText) { + try { + setupWatch(initialText); + launch(cmd); + } catch (IOException ex) { + errorHandler.accept(ex.getMessage()); + } + } + + /** + * Creates a WatchService and registers the given directory + */ + private void setupWatch(String initialText) throws IOException { + this.watcher = FileSystems.getDefault().newWatchService(); + this.dir = Files.createTempDirectory("extedit"); + this.tmpfile = Files.createTempFile(dir, null, ".java"); + Files.write(tmpfile, initialText.getBytes(Charset.forName("UTF-8"))); + dir.register(watcher, + ENTRY_CREATE, + ENTRY_DELETE, + ENTRY_MODIFY); + watchedThread = new Thread(() -> { + for (;;) { + WatchKey key; + try { + key = watcher.take(); + } catch (ClosedWatchServiceException ex) { + // The watch service has been closed, we are done + break; + } catch (InterruptedException ex) { + // tolerate an interrupt + continue; + } + + if (!key.pollEvents().isEmpty()) { + saveFile(); + } + + boolean valid = key.reset(); + if (!valid) { + // The watch service has been closed, we are done + break; + } + } + }); + watchedThread.start(); + } + + private void launch(String[] cmd) throws IOException { + String[] params = Arrays.copyOf(cmd, cmd.length + 1); + params[cmd.length] = tmpfile.toString(); + ProcessBuilder pb = new ProcessBuilder(params); + pb = pb.inheritIO(); + + try { + suspendInteractiveInput.run(); + Process process = pb.start(); + // wait to exit edit mode in one of these ways... + if (wait) { + // -wait option -- ignore process exit, wait for carriage-return + Scanner scanner = new Scanner(System.in); + promptForNewLineToEndWait.run(); + scanner.nextLine(); + } else { + // wait for process to exit + process.waitFor(); + } + } catch (IOException ex) { + errorHandler.accept("process IO failure: " + ex.getMessage()); + } catch (InterruptedException ex) { + errorHandler.accept("process interrupt: " + ex.getMessage()); + } finally { + try { + watcher.close(); + watchedThread.join(); //so that saveFile() is finished. + saveFile(); + } catch (InterruptedException ex) { + errorHandler.accept("process interrupt: " + ex.getMessage()); + } finally { + resumeInteractiveInput.run(); + } + } + } + + private void saveFile() { + try { + saveHandler.accept(Files.lines(tmpfile).collect(Collectors.joining("\n", "", "\n"))); + } catch (IOException ex) { + errorHandler.accept("Failure in read edit file: " + ex.getMessage()); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.internal.ed/share/classes/jdk/internal/editor/spi/BuildInEditorProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.internal.ed/share/classes/jdk/internal/editor/spi/BuildInEditorProvider.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.editor.spi; + +import java.util.function.Consumer; + +/** + * Defines the provider of a built-in editor. + */ +public interface BuildInEditorProvider { + + /** + * @return the rank of a provider, greater is better. + */ + int rank(); + + /** + * Create a simple built-in editor. + * + * @param windowLabel the label string for the Edit Pad window, or null, + * for default window label + * @param initialText the source to load in the Edit Pad + * @param saveHandler a handler for changed source (can be sent the full source) + * @param errorHandler a handler for unexpected errors + */ + void edit(String windowLabel, String initialText, + Consumer saveHandler, Consumer errorHandler); +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.internal.ed/share/classes/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.internal.ed/share/classes/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Internal editor support for JDK tools. Includes the Service Provider + * Interface to built-in editors. + */ +module jdk.internal.ed { + + exports jdk.internal.editor.spi to jdk.editpad, jdk.jshell, jdk.scripting.nashorn.shell; + exports jdk.internal.editor.external to jdk.jshell, jdk.scripting.nashorn.shell; +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java Fri Nov 11 16:44:36 2016 +0100 @@ -80,6 +80,7 @@ String fname, mname, ename; String zname = ""; String rootjar = null; + Set concealedPackages = new HashSet<>(); private static final int BASE_VERSION = 0; @@ -821,22 +822,21 @@ return true; } - private static Set findPackages(ZipFile zf) { - return zf.stream() - .filter(e -> e.getName().endsWith(".class")) - .map(e -> toPackageName(e)) - .filter(pkg -> pkg.length() > 0) - .distinct() - .collect(Collectors.toSet()); - } - private static String toPackageName(ZipEntry entry) { return toPackageName(entry.getName()); } private static String toPackageName(String path) { assert path.endsWith(".class"); - int index = path.lastIndexOf('/'); + int index; + if (path.startsWith(VERSIONS_DIR)) { + index = path.indexOf('/', VERSIONS_DIR.length()); + if (index <= 0) { + return ""; + } + path = path.substring(index + 1); + } + index = path.lastIndexOf('/'); if (index != -1) { return path.substring(0, index).replace('/', '.'); } else { @@ -875,7 +875,7 @@ entryMap.put(entryName, entry); } else if (entries.add(entry)) { jarEntries.add(entryName); - if (entry.basename.endsWith(".class") && !entryName.startsWith(VERSIONS_DIR)) + if (entry.basename.endsWith(".class")) packages.add(toPackageName(entry.basename)); if (isUpdate) entryMap.put(entryName, entry); @@ -1068,7 +1068,7 @@ } jarEntries.add(name); - if (name.endsWith(".class") && !(name.startsWith(VERSIONS_DIR))) + if (name.endsWith(".class")) packages.add(toPackageName(name)); } } @@ -1762,6 +1762,13 @@ } /** + * Print a warning message + */ + void warn(String s) { + err.println(s); + } + + /** * Main routine to start program. */ public static void main(String args[]) { @@ -1975,24 +1982,30 @@ ByteBuffer bb = ByteBuffer.wrap(moduleInfos.get(MODULE_INFO)); ModuleDescriptor rd = ModuleDescriptor.read(bb); - Set exports = rd.exports() - .stream() - .map(Exports::source) - .collect(toSet()); - - Set conceals = packages.stream() - .filter(p -> !exports.contains(p)) - .collect(toSet()); + concealedPackages = findConcealedPackages(rd); for (Map.Entry e: moduleInfos.entrySet()) { ModuleDescriptor vd = ModuleDescriptor.read(ByteBuffer.wrap(e.getValue())); if (!(isValidVersionedDescriptor(vd, rd))) return false; - e.setValue(extendedInfoBytes(rd, vd, e.getValue(), conceals)); + e.setValue(extendedInfoBytes(rd, vd, e.getValue(), concealedPackages)); } return true; } + private Set findConcealedPackages(ModuleDescriptor md){ + Objects.requireNonNull(md); + + Set exports = md.exports() + .stream() + .map(Exports::source) + .collect(toSet()); + + return packages.stream() + .filter(p -> !exports.contains(p)) + .collect(toSet()); + } + private static boolean isPlatformModule(String name) { return name.startsWith("java.") || name.startsWith("jdk."); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java Fri Nov 11 16:44:36 2016 +0100 @@ -152,9 +152,13 @@ return; } if (fp.isPublicClass()) { - main.error(Main.formatMsg("error.validator.new.public.class", entryName)); - isValid = false; - return; + if (!isConcealed(internalName)) { + main.error(Main.formatMsg("error.validator.new.public.class", entryName)); + isValid = false; + return; + } + main.warn(Main.formatMsg("warn.validator.concealed.public.class", entryName)); + debug("%s is a public class entry in a concealed package", entryName); } debug("%s is a non-public class entry", entryName); fps.put(internalName, fp); @@ -169,7 +173,7 @@ // are the two classes/resources identical? if (fp.isIdentical(matchFp)) { - main.error(Main.formatMsg("error.validator.identical.entry", entryName)); + main.warn(Main.formatMsg("warn.validator.identical.entry", entryName)); return; // it's okay, just takes up room } debug("sha1 not equal -- different bytes"); @@ -204,7 +208,7 @@ } debug("%s is a resource", entryName); - main.error(Main.formatMsg("error.validator.resources.with.same.name", entryName)); + main.warn(Main.formatMsg("warn.validator.resources.with.same.name", entryName)); fps.put(internalName, fp); return; } @@ -235,6 +239,15 @@ return entryName.endsWith(".class") ? entryName.substring(0, entryName.length() - 6) : null; } + private boolean isConcealed(String internalName) { + if (main.concealedPackages.isEmpty()) { + return false; + } + int idx = internalName.lastIndexOf('/'); + String pkgName = idx != -1 ? internalName.substring(0, idx).replace('/', '.') : ""; + return main.concealedPackages.contains(pkgName); + } + private void debug(String fmt, Object... args) { if (DEBUG) System.err.format(fmt, args); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties Fri Nov 11 16:44:36 2016 +0100 @@ -99,16 +99,19 @@ entry: {0}, is an isolated nested class error.validator.new.public.class=\ entry: {0}, contains a new public class not found in base entries -error.validator.identical.entry=\ - warning - entry: {0} contains a class that is identical to an entry already in the jar error.validator.incompatible.class.version=\ entry: {0}, has a class version incompatible with an earlier version error.validator.different.api=\ entry: {0}, contains a class with different api from earlier version -error.validator.resources.with.same.name=\ - warning - entry: {0}, multiple resources with same name error.validator.names.mismatch=\ entry: {0}, contains a class with internal name {1}, names do not match +warn.validator.identical.entry=\ + warning - entry: {0} contains a class that is identical to an entry already in the jar +warn.validator.resources.with.same.name=\ + warning - entry: {0}, multiple resources with same name +warn.validator.concealed.public.class=\ + warning - entry {0} is a public class in a concealed package, \n\ + placing this jar on the class path will result in incompatible public interfaces out.added.manifest=\ added manifest out.added.module-info=\ diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java --- a/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. 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 @@ -246,9 +246,9 @@ * @throws java.lang.IllegalArgumentException if the method is not * a member of this object's class, if the size of the argument list * does not match the number of declared arguments for the method, - * if the method is a constructor or static intializer, or + * if the method is a constructor or static initializer, or * if {@link #INVOKE_NONVIRTUAL} is specified and the method is - * either abstract or a non-default interface member. + * abstract. * @throws {@link InvalidTypeException} if any argument in the * argument list is not assignable to the corresponding method argument * type. diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java --- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. 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,10 +347,12 @@ throws InvalidTypeException, InvocationException { /* - * Only default methods allowed for nonvirtual invokes + * For nonvirtual invokes, method must have a body */ - if (isNonVirtual(options) && !method.isDefault()) { - throw new IllegalArgumentException("Not a default method"); + if (isNonVirtual(options)) { + if (method.isAbstract()) { + throw new IllegalArgumentException("Abstract method"); + } } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jdi/share/classes/module-info.java --- a/jdk/src/jdk.jdi/share/classes/module-info.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jdi/share/classes/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. 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,7 +32,6 @@ exports com.sun.jdi.connect.spi; exports com.sun.jdi.event; exports com.sun.jdi.request; - exports com.sun.tools.jdi to jdk.hotspot.agent; uses com.sun.jdi.connect.Connector; uses com.sun.jdi.connect.spi.TransportService; diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java Fri Nov 11 16:44:36 2016 +0100 @@ -359,9 +359,9 @@ if (name.endsWith(".class") && !name.endsWith("module-info.class")) { try { byte[] bytes = reader.getResource(location); - ClassReader cr =new ClassReader(bytes); + ClassReader cr = new ClassReader(bytes); ClassNode cn = new ClassNode(); - cr.accept(cn, ClassReader.EXPAND_FRAMES); + cr.accept(cn, 0); } catch (Exception ex) { log.println("Error(s) in Class: " + name); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java Fri Nov 11 16:44:36 2016 +0100 @@ -30,9 +30,11 @@ import java.io.UncheckedIOException; import java.nio.file.Path; import java.util.Objects; +import java.util.jar.JarFile; import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import jdk.internal.util.jar.VersionedStream; import jdk.tools.jlink.internal.Archive.Entry.EntryType; /** @@ -72,8 +74,8 @@ private final Path file; private final String moduleName; - // currently processed ZipFile - protected ZipFile zipFile; + // currently processed JarFile + private JarFile jarFile; protected JarArchive(String mn, Path file) { Objects.requireNonNull(mn); @@ -95,13 +97,15 @@ @Override public Stream entries() { try { - if (zipFile == null) { + if (jarFile == null) { open(); } } catch (IOException ioe) { throw new UncheckedIOException(ioe); } - return zipFile.stream().map(this::toEntry).filter(n -> n != null); + return VersionedStream.stream(jarFile) + .filter(je -> !je.isDirectory()) + .map(this::toEntry); } abstract EntryType toEntryType(String entryName); @@ -112,16 +116,20 @@ @Override public void close() throws IOException { - if (zipFile != null) { - zipFile.close(); + if (jarFile != null) { + jarFile.close(); } } @Override public void open() throws IOException { - if (zipFile != null) { - zipFile.close(); + if (jarFile != null) { + jarFile.close(); } - zipFile = new ZipFile(file.toFile()); + jarFile = new JarFile(file.toFile(), true, ZipFile.OPEN_READ, JarFile.runtimeVersion()); + } + + protected JarFile getJarFile() { + return jarFile; } } diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java Fri Nov 11 16:44:36 2016 +0100 @@ -33,7 +33,6 @@ import java.lang.module.ModuleReference; import java.lang.module.ResolutionException; import java.lang.module.ResolvedModule; -import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.nio.ByteOrder; import java.nio.file.Files; @@ -41,9 +40,8 @@ import java.nio.file.Paths; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; -import jdk.internal.module.ConfigurableModuleFinder; -import jdk.internal.module.ConfigurableModuleFinder.Phase; import jdk.tools.jlink.internal.TaskHelper.BadArgs; import static jdk.tools.jlink.internal.TaskHelper.JLINK_BUNDLE; import jdk.tools.jlink.internal.Jlink.JlinkConfiguration; @@ -54,6 +52,7 @@ import jdk.tools.jlink.plugin.PluginException; import jdk.tools.jlink.builder.DefaultImageBuilder; import jdk.tools.jlink.plugin.Plugin; +import jdk.internal.misc.SharedSecrets; /** * Implementation for the jlink tool. @@ -63,20 +62,8 @@ public class JlinkTask { static final boolean DEBUG = Boolean.getBoolean("jlink.debug"); - private static void fail(Class type, - String format, - Object... args) throws T { - String msg = new Formatter().format(format, args).toString(); - try { - T t = type.getConstructor(String.class).newInstance(msg); - throw t; - } catch (InstantiationException | - InvocationTargetException | - NoSuchMethodException | - IllegalAccessException e) { - throw new InternalError("Unable to create an instance of " + type, e); - } - } + // jlink API ignores by default. Remove when signing is implemented. + static final boolean IGNORE_SIGNING_DEFAULT = true; private static final TaskHelper taskHelper = new TaskHelper(JLINK_BUNDLE); @@ -144,7 +131,10 @@ }, "--save-opts"), new Option(false, (task, opt, arg) -> { task.options.fullVersion = true; - }, true, "--full-version"),}; + }, true, "--full-version"), + new Option(false, (task, opt, arg) -> { + task.options.ignoreSigning = true; + }, true, "--ignore-signing-information"),}; private static final String PROGNAME = "jlink"; private final OptionsValues options = new OptionsValues(); @@ -161,7 +151,8 @@ /** * Result codes. */ - static final int EXIT_OK = 0, // Completed with no errors. + static final int + EXIT_OK = 0, // Completed with no errors. EXIT_ERROR = 1, // Completed but reported errors. EXIT_CMDERR = 2, // Bad command-line arguments EXIT_SYSERR = 3, // System error or resource exhaustion. @@ -172,12 +163,13 @@ String saveoptsfile; boolean version; boolean fullVersion; - List modulePath = new ArrayList<>(); - Set limitMods = new HashSet<>(); - Set addMods = new HashSet<>(); + final List modulePath = new ArrayList<>(); + final Set limitMods = new HashSet<>(); + final Set addMods = new HashSet<>(); Path output; Path packagedModulesPath; ByteOrder endian = ByteOrder.nativeOrder(); + boolean ignoreSigning = false; } int run(String[] args) { @@ -186,7 +178,7 @@ new PrintWriter(System.err, true)); } try { - optionsHelper.handleOptions(this, args); + optionsHelper.handleOptionsNoUnhandled(this, args); if (options.help) { optionsHelper.showHelp(PROGNAME); return EXIT_OK; @@ -200,7 +192,7 @@ return EXIT_OK; } if (taskHelper.getExistingImage() == null) { - if (options.modulePath == null || options.modulePath.isEmpty()) { + if (options.modulePath.isEmpty()) { throw taskHelper.newBadArgs("err.modulepath.must.be.specified").showUsage(true); } createImage(); @@ -249,19 +241,25 @@ plugins = plugins == null ? new PluginsConfiguration() : plugins; if (config.getModulepaths().isEmpty()) { - throw new Exception("Empty module paths"); + throw new IllegalArgumentException("Empty module paths"); } - ModuleFinder finder - = newModuleFinder(config.getModulepaths(), config.getLimitmods(), config.getModules()); + ModuleFinder finder = newModuleFinder(config.getModulepaths(), + config.getLimitmods(), + config.getModules()); + + if (config.getModules().isEmpty()) { + throw new IllegalArgumentException("No modules to add"); + } // First create the image provider - ImageProvider imageProvider - = createImageProvider(finder, - checkAddMods(config.getModules()), - config.getLimitmods(), - config.getByteOrder(), - null); + ImageProvider imageProvider = + createImageProvider(finder, + config.getModules(), + config.getLimitmods(), + config.getByteOrder(), + null, + IGNORE_SIGNING_DEFAULT); // Then create the Plugin Stack ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(plugins); @@ -299,19 +297,17 @@ } ModuleFinder finder = newModuleFinder(options.modulePath, options.limitMods, options.addMods); - try { - options.addMods = checkAddMods(options.addMods); - } catch (IllegalArgumentException ex) { + if (options.addMods.isEmpty()) { throw taskHelper.newBadArgs("err.mods.must.be.specified", "--add-modules") .showUsage(true); } // First create the image provider - ImageProvider imageProvider - = createImageProvider(finder, + ImageProvider imageProvider = createImageProvider(finder, options.addMods, options.limitMods, options.endian, - options.packagedModulesPath); + options.packagedModulesPath, + options.ignoreSigning); // Then create the Plugin Stack ImagePluginStack stack = ImagePluginConfiguration. @@ -321,31 +317,41 @@ stack.operate(imageProvider); } - private static Set checkAddMods(Set addMods) { - if (addMods.isEmpty()) { - throw new IllegalArgumentException("no modules to add"); - } - return addMods; - } + /** + * Returns a module finder to find the observable modules specified in + * the --module-path and --limit-modules options + */ + private ModuleFinder modulePathFinder() { + Path[] entries = options.modulePath.toArray(new Path[0]); + ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess() + .newModulePath(Runtime.version(), true, entries); - public static ModuleFinder newModuleFinder(List paths, - Set limitMods, - Set addMods) - { - ModuleFinder finder = ModuleFinder.of(paths.toArray(new Path[0])); - - // jmods are located at link-time - if (finder instanceof ConfigurableModuleFinder) { - ((ConfigurableModuleFinder) finder).configurePhase(Phase.LINK_TIME); - } - - // if limitmods is specified then limit the universe - if (!limitMods.isEmpty()) { - finder = limitFinder(finder, limitMods, addMods); + if (!options.limitMods.isEmpty()) { + finder = limitFinder(finder, options.limitMods, Collections.emptySet()); } return finder; } + /* + * Returns a module finder of the given module path that limits + * the observable modules to those in the transitive closure of + * the modules specified in {@code limitMods} plus other modules + * specified in the {@code roots} set. + */ + public static ModuleFinder newModuleFinder(List paths, + Set limitMods, + Set roots) + { + Path[] entries = paths.toArray(new Path[0]); + ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess() + .newModulePath(Runtime.version(), true, entries); + + // if limitmods is specified then limit the universe + if (!limitMods.isEmpty()) { + finder = limitFinder(finder, limitMods, roots); + } + return finder; + } private static Path toPathLocation(ResolvedModule m) { Optional ouri = m.reference().location(); @@ -359,7 +365,8 @@ Set addMods, Set limitMods, ByteOrder order, - Path retainModulesPath) + Path retainModulesPath, + boolean ignoreSigning) throws IOException { if (addMods.isEmpty()) { @@ -373,10 +380,10 @@ Map mods = cf.modules().stream() .collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation)); - return new ImageHelper(cf, mods, order, retainModulesPath); + return new ImageHelper(cf, mods, order, retainModulesPath, ignoreSigning); } - /** + /* * Returns a ModuleFinder that limits observability to the given root * modules, their transitive dependences, plus a set of other modules. */ @@ -460,36 +467,57 @@ } private static class ImageHelper implements ImageProvider { - - final Set archives; final ByteOrder order; final Path packagedModulesPath; + final boolean ignoreSigning; + final Set archives; ImageHelper(Configuration cf, Map modsPaths, ByteOrder order, - Path packagedModulesPath) throws IOException { - archives = modsPaths.entrySet().stream() + Path packagedModulesPath, + boolean ignoreSigning) throws IOException { + this.order = order; + this.packagedModulesPath = packagedModulesPath; + this.ignoreSigning = ignoreSigning; + this.archives = modsPaths.entrySet().stream() .map(e -> newArchive(e.getKey(), e.getValue())) .collect(Collectors.toSet()); - this.order = order; - this.packagedModulesPath = packagedModulesPath; } private Archive newArchive(String module, Path path) { if (path.toString().endsWith(".jmod")) { return new JmodArchive(module, path); } else if (path.toString().endsWith(".jar")) { - return new ModularJarArchive(module, path); + ModularJarArchive modularJarArchive = new ModularJarArchive(module, path); + + Stream signatures = modularJarArchive.entries().filter((entry) -> { + String name = entry.name().toUpperCase(Locale.ENGLISH); + + return name.startsWith("META-INF/") && name.indexOf('/', 9) == -1 && ( + name.endsWith(".SF") || + name.endsWith(".DSA") || + name.endsWith(".RSA") || + name.endsWith(".EC") || + name.startsWith("META-INF/SIG-") + ); + }); + + if (signatures.count() != 0) { + if (ignoreSigning) { + System.err.println(taskHelper.getMessage("warn.signing", path)); + } else { + throw new IllegalArgumentException(taskHelper.getMessage("err.signing", path)); + } + } + + return modularJarArchive; } else if (Files.isDirectory(path)) { return new DirArchive(path); } else { - fail(RuntimeException.class, - "Selected module %s (%s) not in jmod or modular jar format", - module, - path); + throw new IllegalArgumentException( + taskHelper.getMessage("err.not.modular.format", module, path)); } - return null; } @Override @@ -509,30 +537,16 @@ } private static enum Section { - NATIVE_LIBS("native", nativeDir()), - NATIVE_CMDS("bin", "bin"), - CLASSES("classes", "classes"), - CONFIG("conf", "conf"), - UNKNOWN("unknown", "unknown"); - - private static String nativeDir() { - if (System.getProperty("os.name").startsWith("Windows")) { - return "bin"; - } else { - return "lib"; - } - } + NATIVE_LIBS("native"), + NATIVE_CMDS("bin"), + CLASSES("classes"), + CONFIG("conf"), + UNKNOWN("unknown"); private final String jmodDir; - private final String imageDir; - Section(String jmodDir, String imageDir) { + Section(String jmodDir) { this.jmodDir = jmodDir; - this.imageDir = imageDir; - } - - String imageDir() { - return imageDir; } String jmodDir() { diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java Fri Nov 11 16:44:36 2016 +0100 @@ -54,13 +54,9 @@ @Override Entry toEntry(ZipEntry ze) { - if (ze.isDirectory()) { - return null; - } - String name = ze.getName(); EntryType type = toEntryType(name); - return new JarEntry(ze.getName(), getFileName(name), type, zipFile, ze); + return new JarEntry(ze.getName(), getFileName(name), type, getJarFile(), ze); } @Override diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java Fri Nov 11 16:44:36 2016 +0100 @@ -47,8 +47,6 @@ import java.util.ResourceBundle; import java.util.Set; -import jdk.internal.module.ConfigurableModuleFinder; -import jdk.internal.module.ConfigurableModuleFinder.Phase; import jdk.tools.jlink.internal.plugins.ExcludeFilesPlugin; import jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin; import jdk.tools.jlink.plugin.Plugin; @@ -60,6 +58,7 @@ import jdk.tools.jlink.internal.plugins.PluginsResourceBundle; import jdk.tools.jlink.internal.plugins.DefaultCompressPlugin; import jdk.tools.jlink.internal.plugins.StripDebugPlugin; +import jdk.internal.misc.SharedSecrets; /** * @@ -162,6 +161,7 @@ private static final String POST_PROCESS = "--post-process-path"; private Layer pluginsLayer = Layer.boot(); + private final List plugins; private String lastSorter; private boolean listPlugins; private Path existingImage; @@ -185,9 +185,10 @@ pluginsLayer = createPluginsLayer(paths); } + plugins = PluginRepository.getPlugins(pluginsLayer); + Set optionsSeen = new HashSet<>(); - for (Plugin plugin : PluginRepository. - getPlugins(pluginsLayer)) { + for (Plugin plugin : plugins) { if (!Utils.isDisabled(plugin)) { addOrderedPluginOptions(plugin, optionsSeen); } @@ -199,9 +200,19 @@ }, "--plugin-module-path")); mainOptions.add(new PlugOption(true, (task, opt, arg) -> { + for (Plugin plugin : plugins) { + if (plugin.getName().equals(arg)) { + pluginToMaps.remove(plugin); + return; + } + } + throw newBadArgs("err.no.such.plugin", arg); + }, + "--disable-plugin")); + mainOptions.add(new PlugOption(true, (task, opt, arg) -> { Path path = Paths.get(arg); if (!Files.exists(path) || !Files.isDirectory(path)) { - throw newBadArgs("err.existing.image.must.exist"); + throw newBadArgs("err.image.must.exist"); } existingImage = path.toAbsolutePath(); }, true, POST_PROCESS)); @@ -466,7 +477,21 @@ return pp; } + // used by jimage. Return unhandled arguments like "create", "describe". public List handleOptions(T task, String[] args) throws BadArgs { + return handleOptions(task, args, true); + } + + // used by jlink. No unhandled arguments like "create", "describe". + void handleOptionsNoUnhandled(T task, String[] args) throws BadArgs { + handleOptions(task, args, false); + } + + // shared code that handles options for both jlink and jimage. jimage uses arguments like + // "create", "describe" etc. as "task names". Those arguments are unhandled here and returned + // as "unhandled arguments list". jlink does not want such arguments. "collectUnhandled" flag + // tells whether to allow for unhandled arguments or not. + private List handleOptions(T task, String[] args, boolean collectUnhandled) throws BadArgs { // findbugs warning, copy instead of keeping a reference. command = Arrays.copyOf(args, args.length); @@ -499,10 +524,10 @@ String[] arr = new String[filteredArgs.size()]; args = filteredArgs.toArray(arr); - List rest = new ArrayList<>(); + List rest = collectUnhandled? new ArrayList<>() : null; // process options for (int i = 0; i < args.length; i++) { - if (!args[i].isEmpty() && args[i].charAt(0) == '-') { + if (args[i].charAt(0) == '-') { String name = args[i]; PlugOption pluginOption = null; Option option = getOption(name); @@ -539,7 +564,12 @@ i = args.length; } } else { - rest.add(args[i]); + if (collectUnhandled) { + rest.add(args[i]); + } else { + throw new BadArgs("err.orphan.argument", args[i]). + showUsage(true); + } } } return rest; @@ -707,14 +737,10 @@ } static Layer createPluginsLayer(List paths) { - Path[] arr = new Path[paths.size()]; - paths.toArray(arr); - ModuleFinder finder = ModuleFinder.of(arr); - // jmods are located at link-time - if (finder instanceof ConfigurableModuleFinder) { - ((ConfigurableModuleFinder) finder).configurePhase(Phase.LINK_TIME); - } + Path[] dirs = paths.toArray(new Path[0]); + ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess() + .newModulePath(Runtime.version(), true, dirs); Configuration bootConfiguration = Layer.boot().configuration(); try { diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java Fri Nov 11 16:44:36 2016 +0100 @@ -159,13 +159,6 @@ public void configure(Map config) { String mainArgument = config.get(NAME); - if ("none".equals(mainArgument)) { - speciesTypes = Set.of(); - invokerTypes = Set.of(); - dmhMethods = Map.of(); - return; - } - // Start with the default configuration Set defaultBMHSpecies = defaultSpecies(); // Expand BMH species signatures diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties Fri Nov 11 16:44:36 2016 +0100 @@ -62,6 +62,9 @@ main.opt.save-opts=\ \ --save-opts Save jlink options in the given file +main.opt.ignore-signing-information=\ +\ --ignore-signing-information Ignore signing information in modular JARs + main.msg.bug=\ An exception has occurred in jlink. \ Please file a bug at the Java Bug Database (http://bugreport.java.com/bugreport/) \ @@ -88,13 +91,14 @@ err.mods.must.be.specified:no modules specified to {0} err.path.not.found=path not found: {0} err.path.not.valid=invalid path: {0} -err.existing.image.must.exist=existing image doesn't exists or is not a directory +err.image.must.exist=image does not exist or is not a directory err.existing.image.invalid=existing image is not valid err.file.not.found=cannot find file: {0} err.file.error=cannot access file: {0} err.dir.exists={0} already exists err.badpattern=bad pattern {0} err.unknown.option=unknown option: {0} +err.orphan.argument=orphan argument: {0} err.missing.arg=no value given for {0} err.internal.error=internal error: {0} {1} {2} err.invalid.arg.for.option=invalid argument for option: {0} @@ -103,5 +107,9 @@ err.config.defaults=property {0} is missing from configuration err.config.defaults.value=wrong value in defaults property: {0} err.bom.generation=bom file generation failed: {0} -warn.invalid.arg=Invalid classname or pathname not exist: {0} +err.not.modular.format=selected module {0} ({1}) not in jmod or modular JAR format +err.signing=signed modular JAR {0} is currently not supported,\ +\ use --ignore-signing-information to suppress error +warn.signing=signed modular JAR {0} is currently not supported +warn.invalid.arg=invalid classname or pathname not exist: {0} warn.split.package=package {0} defined in {1} {2} diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties Fri Nov 11 16:44:36 2016 +0100 @@ -74,12 +74,11 @@ exclude-jmod-section.description=\ Specify a JMOD section to exclude -generate-jli-classes.argument= +generate-jli-classes.argument=@filename generate-jli-classes.description=\ Takes a file hinting to jlink what java.lang.invoke classes to pre-generate. If\n\ -this flag is not specified a default set of classes will be generated. To \n\ -disable pre-generation specify none as the argument +this flag is not specified a default set of classes will be generated. installed-modules.description=Fast loading of module descriptors (always enabled) @@ -144,6 +143,9 @@ plugin.opt.plugin-module-path=\ \ --plugin-module-path Custom plugin module path +plugin.opt.disable-plugin=\ +\ --disable-plugin Disable the plugin mentioned + plugin.opt.c=\ \ -c, --compress=<0|1|2> Enable compression of resources\ \n More details in --list-plugins option @@ -193,6 +195,8 @@ main.plugin.state=\ Functional state +err.no.such.plugin=No such plugin: {0} + err.provider.not.functional=The provider {0} is not functional. err.plugin.mutiple.options=More than one plugin enabled by {0} option diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Fri Nov 11 16:44:36 2016 +0100 @@ -47,6 +47,7 @@ import java.lang.module.ResolvedModule; import java.net.URI; import java.nio.file.FileSystems; +import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.InvalidPathException; @@ -98,8 +99,6 @@ import jdk.internal.joptsimple.ValueConverter; import jdk.internal.misc.JavaLangModuleAccess; import jdk.internal.misc.SharedSecrets; -import jdk.internal.module.ConfigurableModuleFinder; -import jdk.internal.module.ConfigurableModuleFinder.Phase; import jdk.internal.module.ModuleHashes; import jdk.internal.module.ModuleInfoExtender; import jdk.tools.jlink.internal.Utils; @@ -635,7 +634,8 @@ void processSection(JmodOutputStream out, Section section, Path top) throws IOException { - Files.walkFileTree(top, new SimpleFileVisitor() { + Files.walkFileTree(top, Set.of(FileVisitOption.FOLLOW_LINKS), + Integer.MAX_VALUE, new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException @@ -1298,9 +1298,7 @@ options.manPages = opts.valuesOf(manPages); if (opts.has(modulePath)) { Path[] dirs = opts.valuesOf(modulePath).toArray(new Path[0]); - options.moduleFinder = ModuleFinder.of(dirs); - if (options.moduleFinder instanceof ConfigurableModuleFinder) - ((ConfigurableModuleFinder)options.moduleFinder).configurePhase(Phase.LINK_TIME); + options.moduleFinder = JLMA.newModulePath(Runtime.version(), true, dirs); } if (opts.has(moduleVersion)) options.moduleVersion = opts.valueOf(moduleVersion); diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.jsobject/share/classes/netscape/javascript/JSObject.java --- a/jdk/src/jdk.jsobject/share/classes/netscape/javascript/JSObject.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.jsobject/share/classes/netscape/javascript/JSObject.java Fri Nov 11 16:44:36 2016 +0100 @@ -156,6 +156,7 @@ */ @Deprecated(since = "9") + @SuppressWarnings("exports") public static JSObject getWindow(Applet applet) throws JSException { return ProviderLoader.callGetWindow(applet); } diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/BreakIteratorResources_th.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/BreakIteratorResources_th.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.text.resources.ext; + +import java.util.ResourceBundle; +import sun.util.resources.BreakIteratorResourceBundle; + +public class BreakIteratorResources_th extends BreakIteratorResourceBundle { + @Override + protected ResourceBundle getBreakIteratorInfo() { + return new BreakIteratorInfo_th(); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/src/jdk.unsupported/share/classes/sun/reflect/ReflectionFactory.java --- a/jdk/src/jdk.unsupported/share/classes/sun/reflect/ReflectionFactory.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/src/jdk.unsupported/share/classes/sun/reflect/ReflectionFactory.java Fri Nov 11 16:44:36 2016 +0100 @@ -85,6 +85,21 @@ } /** + * Returns an accessible constructor capable of creating instances + * of the given class, initialized by the given constructor. + * + * @param cl the class to instantiate + * @param constructorToCall the constructor to call + * @return an accessible constructor + */ + public Constructor newConstructorForSerialization(Class cl, + Constructor constructorToCall) + { + return delegate.newConstructorForSerialization(cl, + constructorToCall); + } + + /** * Returns an accessible no-arg constructor for a class. * The no-arg constructor is found searching the class and its supertypes. * diff -r f71b844f33d1 -r 95af45781076 jdk/test/ProblemList.txt --- a/jdk/test/ProblemList.txt Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/ProblemList.txt Fri Nov 11 16:44:36 2016 +0100 @@ -134,8 +134,6 @@ java/lang/instrument/BootClassPath/BootClassPathTest.sh 8072130 macosx-all -java/lang/instrument/DaemonThread/TestDaemonThread.java 8167001 generic-all - java/lang/management/MemoryMXBean/Pending.java 8158837 generic-all java/lang/management/MemoryMXBean/PendingAllGC.sh 8158760 generic-all @@ -186,9 +184,7 @@ java/nio/file/WatchService/MayFlies.java 7158947 solaris-all Solaris 11 java/nio/file/WatchService/LotsOfEvents.java 7158947 solaris-all Solaris 11 -java/nio/charset/coders/BashStreams.java 8149712 generic-all - -java/nio/file/WatchService/DeleteInterference.java 8156511 linux-all +sun/nio/cs/OLD/TestIBMDB.java 8167525 generic-all ############################################################################ @@ -223,6 +219,15 @@ ############################################################################ # jdk_sound +javax/sound/sampled/DirectAudio/bug6372428.java 8055097 generic-all +javax/sound/sampled/Clip/bug5070081.java 8055097 generic-all +javax/sound/sampled/DataLine/LongFramePosition.java 8055097 generic-all + +javax/sound/sampled/Clip/Drain/ClipDrain.java 7062792 generic-all + +javax/sound/sampled/Mixers/DisabledAssertionCrash.java 7067310 generic-all + +javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java 8168881 generic-all ############################################################################ diff -r f71b844f33d1 -r 95af45781076 jdk/test/TEST.groups --- a/jdk/test/TEST.groups Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/TEST.groups Fri Nov 11 16:44:36 2016 +0100 @@ -158,6 +158,7 @@ jdk_net = \ java/net \ + -java/net/httpclient \ com/sun/net/httpserver \ sun/net \ jdk/net diff -r f71b844f33d1 -r 95af45781076 jdk/test/com/sun/corba/serialization/ObjectStreamTest.java --- a/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -42,13 +42,8 @@ import java.util.Objects; import java.util.PropertyPermission; import java.util.Set; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.LongAdder; -import javax.naming.CommunicationException; -import javax.naming.InitialContext; -import javax.naming.Context; -import javax.naming.NamingException; import javax.rmi.CORBA.Util; import javax.rmi.PortableRemoteObject; @@ -56,11 +51,9 @@ import org.omg.CORBA_2_3.portable.OutputStream; import org.omg.CORBA_2_3.portable.InputStream; -import jdk.test.lib.JDKToolFinder; -import jdk.test.lib.JDKToolLauncher; - import org.testng.Assert; -import org.testng.annotations.AfterSuite; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import org.testng.annotations.DataProvider; import org.testng.TestNG; @@ -69,15 +62,13 @@ * @test * @library /test/lib * @build jdk.test.lib.* - * @compile ObjectStreamTest.java ObjectStreamTest$_Echo_Stub.java ObjectStreamTest$_Server_Tie.java - * @modules java.corba/com.sun.corba.se.impl.io java.base/java.io java.corba/com.sun.corba.se.impl.activation + * @compile ObjectStreamTest.java ObjectStreamTest$_Echo_Stub.java + * ObjectStreamTest$_Server_Tie.java + * @modules java.corba/com.sun.corba.se.impl.io java.base/java.io + * java.corba/com.sun.corba.se.impl.activation * @summary Tests of ReflectionFactory use in IIOP Serialization - * @run testng/othervm - * -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory - * -Djava.naming.provider.url=iiop://localhost:1050 ObjectStreamTest - * @run testng/othervm/policy=security.policy - * -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory - * -Djava.naming.provider.url=iiop://localhost:1050 ObjectStreamTest + * @run testng/othervm ObjectStreamTest + * @run testng/othervm/policy=security.policy ObjectStreamTest */ @Test @@ -92,12 +83,6 @@ colorSet.add(Colors.GREEN); } - /** - * The process spawned to run orbd. - */ - static Process orbdProcess; - static Thread orbThread; - @DataProvider(name = "Objects") static Object[][] patterns() { BigInteger bigInteger = new BigInteger("8943892002309239"); @@ -141,7 +126,7 @@ * @param value */ @Test(dataProvider = "Objects") - static void factCheck(Serializable value) { + void factCheck(Serializable value) { Class clazz = value.getClass(); java.io.ObjectStreamClass sOSC = java.io.ObjectStreamClass.lookup(clazz); java.io.ObjectStreamField[] sFields = sOSC.getFields(); @@ -150,25 +135,33 @@ Assert.assertEquals(sFields.length, cFields.length, "Different number of fields"); for (int i = 0; i < sFields.length; i++) { - Assert.assertEquals(sFields[i].getName(), cFields[i].getName(), "different field names " + cFields[i].getName()); - Assert.assertEquals(sFields[i].getType(), cFields[i].getType(), "different field types " + cFields[i].getName()); - Assert.assertEquals(sFields[i].getTypeString(), cFields[i].getTypeString(), "different field typestrings " + cFields[i].getName()); + Assert.assertEquals(sFields[i].getName(), cFields[i].getName(), + "different field names " + cFields[i].getName()); + Assert.assertEquals(sFields[i].getType(), cFields[i].getType(), + "different field types " + cFields[i].getName()); + Assert.assertEquals(sFields[i].getTypeString(), cFields[i].getTypeString(), + "different field typestrings " + cFields[i].getName()); } Assert.assertEquals(baseMethod("hasReadObjectMethod", sOSC, (Class[]) null), - corbaMethod("hasReadObject", cOSC, (Class[]) null), "hasReadObject: " + value.getClass()); + corbaMethod("hasReadObject", cOSC, (Class[]) null), + "hasReadObject: " + value.getClass()); Assert.assertEquals(baseMethod("hasWriteObjectMethod", sOSC, (Class[]) null), - corbaMethod("hasWriteObject", cOSC, (Class[]) null), "hasWriteObject: " + value.getClass()); + corbaMethod("hasWriteObject", cOSC, (Class[]) null), + "hasWriteObject: " + value.getClass()); Assert.assertEquals(baseMethod("hasWriteReplaceMethod", sOSC, (Class[]) null), - corbaMethod("hasWriteReplaceMethod", cOSC, (Class[]) null), "hasWriteReplace: " + value.getClass()); + corbaMethod("hasWriteReplaceMethod", cOSC, (Class[]) null), + "hasWriteReplace: " + value.getClass()); Assert.assertEquals(baseMethod("hasReadResolveMethod", sOSC, (Class[]) null), - corbaMethod("hasReadResolveMethod", cOSC, (Class[]) null), "hasReadResolve: " + value.getClass()); + corbaMethod("hasReadResolveMethod", cOSC, (Class[]) null), + "hasReadResolve: " + value.getClass()); Assert.assertEquals(baseMethod("getSerialVersionUID", sOSC, (Class[]) null), - corbaMethod("getSerialVersionUID", cOSC, (Class[]) null), "getSerialVersionUID: " + value.getClass()); + corbaMethod("getSerialVersionUID", cOSC, (Class[]) null), + "getSerialVersionUID: " + value.getClass()); } @@ -178,7 +171,7 @@ * and deserialized using Util.readAny to equivalent objects. */ @Test(dataProvider = "Objects", enabled = true, dependsOnMethods = {"factCheck"}) - static void WriteValueObjectStreamTest01(Serializable value) throws Exception { + void WriteValueObjectStreamTest01(Serializable value) throws Exception { ORB orb = (ORB) ORB.init(new String[0], null); OutputStream out = (OutputStream) orb.create_output_stream(); @@ -193,15 +186,43 @@ /** * Test that objects can be echoed to a server and come back equivalent. */ - @Test(dataProvider = "Objects", enabled = false, dependsOnMethods = {"factCheck"}) - static void echoObjects(Serializable value) throws Exception { - Context initialNamingContext = Server.init(); - Echo echo = (Echo) PortableRemoteObject.narrow( - initialNamingContext.lookup(Server.serverID), Echo.class); + @Test(dataProvider = "Objects", enabled = true, dependsOnMethods = {"factCheck"}) + void echoObjects(Serializable value) throws Exception { + Echo echo = getEchoStub(); Object actual = echo.echo(value); checkEquals(actual, value); } + + /** + * Initialize the ORB and the singleton Echo server stub. + * @return the stub for the Echo server. + * @throws RemoteException if an error occurs + */ + synchronized Echo getEchoStub() throws RemoteException { + if (echoStub == null) { + ORB orb = (ORB) ORB.init(new String[0], null); + Echo server = new Server(); + echoStub = (javax.rmi.CORBA.Stub) PortableRemoteObject.toStub(server); + echoStub.connect(orb); + } + return (Echo)echoStub; + } + + /** + * The stub for the Echo Server class. Initialized on first use. + */ + private javax.rmi.CORBA.Stub echoStub; + + /** + * After all the tests run shutdown the orb. + */ + @AfterClass + void shutdownOrb() { + ORB orb = (ORB) ORB.init(new String[0], null); + orb.shutdown(true); + } + /** * Check if the value and result are equals, with some tests depending on the type. * @param expected the expected value @@ -209,15 +230,18 @@ */ static void checkEquals(Object actual, Object expected) { Class cl = expected.getClass(); - Assert.assertEquals(actual.getClass(), cl, "type of value not equal to class of result"); + Assert.assertEquals(actual.getClass(), cl, + "type of value not equal to class of result"); try { if (cl.isArray() || !(cl.getDeclaredMethod("equals", cl) == null)) { Assert.assertEquals(actual, expected, "echo'd object not equal"); } else { - Assert.assertEquals(toString(actual), toString(expected), "toString values not equal"); + Assert.assertEquals(toString(actual), toString(expected), + "toString values not equal"); } } catch (NoSuchMethodException ex) { - Assert.assertEquals(toString(actual), toString(expected), "toString values not equal"); + Assert.assertEquals(toString(actual), toString(expected), + "toString values not equal"); } } @@ -301,7 +325,9 @@ * @param argClasses method arguments * @return the value returned from invoking the method */ - static Object corbaMethod(String methodName, com.sun.corba.se.impl.io.ObjectStreamClass osc, Class... argClasses) { + static Object corbaMethod(String methodName, + com.sun.corba.se.impl.io.ObjectStreamClass osc, + Class... argClasses) { Class oscClass = com.sun.corba.se.impl.io.ObjectStreamClass.class; try { @@ -325,7 +351,8 @@ * @param argClasses method arguments * @return the value returned from invoking the method */ - static Object baseMethod(String methodName, java.io.ObjectStreamClass osc, Class... argClasses) { + static Object baseMethod(String methodName, java.io.ObjectStreamClass osc, + Class... argClasses) { Class oscClass = java.io.ObjectStreamClass.class; try { @@ -342,7 +369,7 @@ } /** - * Simple echo interface to check serialization/deserialization. + * Simple echo interface to check IIOP serialization/deserialization. */ interface Echo extends Remote { Object echo(Object obj) throws RemoteException; @@ -350,12 +377,6 @@ static class Server extends PortableRemoteObject implements Echo { - public static final String serverID = "ObjectStreamTestServer"; - - private static Context initialNamingContext; - - private static Server server; - public Server() throws RemoteException { super(); } @@ -363,63 +384,8 @@ public Object echo(Object obj) { return obj; } - - - public static Context init() { - if (initialNamingContext == null) { - try { - startOrbd(); - Thread.sleep(5000L); // Give it 5 seconds - } catch (Exception eex) { - throw new RuntimeException("Orbd", eex); - } - for (int i = 0; i < 1; i++) { - try { - Thread.sleep(1L); - initialNamingContext = new InitialContext(); - server = new Server(); - initialNamingContext.rebind(serverID, server); - } catch (CommunicationException | InterruptedException cex) { - System.out.printf("retry #%d sec: ex: %s%n", i, cex); - } catch (NamingException ex) { - throw new RuntimeException("can't initialize naming context", ex); - } catch (RemoteException rex) { - throw new RuntimeException("can't initialize server", rex); - } - } - } - if (initialNamingContext == null) { - Assert.fail("Can't initialize the Orb, no naming context"); - } - return initialNamingContext; - } } - static void startOrbd() throws Exception { - System.out.println("\nStarting orbd with NS port 1050 "); - JDKToolLauncher orbdLauncher = JDKToolLauncher.create("orbd") - .addToolArg("-ORBInitialHost").addToolArg("localhost") - .addToolArg("-ORBInitialPort").addToolArg("1050"); - - System.out.println("ObjectStreamTest: Executing: " + Arrays.asList(orbdLauncher.getCommand())); - ProcessBuilder pb = new ProcessBuilder(orbdLauncher.getCommand()); - - pb.redirectError(ProcessBuilder.Redirect.INHERIT); - orbdProcess = pb.start(); - } - - @AfterSuite - static void killOrbd() throws Exception { - if (orbdProcess != null) { - orbdProcess.destroyForcibly(); - orbdProcess.waitFor(); - System.out.printf("destroyed orbd, pid: %d, exitValue: %d%n", - orbdProcess.getPid(), orbdProcess.exitValue()); - } - } - - - // Main can be used to run the tests from the command line with only testng.jar. @SuppressWarnings("raw_types") @Test(enabled = false) diff -r f71b844f33d1 -r 95af45781076 jdk/test/com/sun/jdi/InterfaceMethodsTest.java --- a/jdk/test/com/sun/jdi/InterfaceMethodsTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/com/sun/jdi/InterfaceMethodsTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -25,7 +25,8 @@ * @test * @bug 8031195 * @bug 8071657 - * @summary JDI: Add support for static and default methods in interfaces + * @bug 8165827 + * @summary JDI: Add support for static, private and default methods in interfaces * * @modules jdk.jdi * @run build TestScaffold VMConnection TargetListener TargetAdapter @@ -35,11 +36,13 @@ import com.sun.jdi.*; import com.sun.jdi.event.*; import java.util.Collections; +import java.util.Iterator; +import java.util.List; public class InterfaceMethodsTest extends TestScaffold { private static final int RESULT_A = 1; - private static final int RESULT_B = 1; - private static final int RESULT_TARGET = 1; + private static final int RESULT_B = 2; + private static final int RESULT_TARGET = 3; static interface InterfaceA { static int staticMethodA() { @@ -62,7 +65,10 @@ System.out.println("-InterfaceA: default interface method C-"); return RESULT_A; } - + private int privateMethodA() { + System.out.println("-InterfaceA: private interface method A-"); + return RESULT_A; + } int implementedMethod(); } @@ -76,16 +82,18 @@ System.out.println("-InterfaceB: default interface method D-"); return RESULT_B; } - static int staticMethodB() { System.out.println("-InterfaceB: overridden static interface method B-"); return RESULT_B; } - static int staticMethodC() { System.out.println("-InterfaceB: static interface method C-"); return RESULT_B; } + private int privateMethodB() { + System.out.println("-InterfaceB: private interface method B-"); + return RESULT_B; + } } final static class TargetClass implements InterfaceB { @@ -102,7 +110,7 @@ @Override public int defaultMethodB() { - System.out.println("-TargetClass: overridden default interface method D"); + System.out.println("-TargetClass: overridden default interface method B"); return RESULT_TARGET; } @@ -169,9 +177,18 @@ } private void testInterfaceA(ObjectReference ref) { + + ReferenceType ifaceClass = (ReferenceType)vm().classesByName(INTERFACEA_NAME).get(0); + + /* Private method calls */ + + Method m = testLookup(ifaceClass, "privateMethodA", "()I", true, null); // should succeed + + testInvokePos(m, ref, vm().mirrorOf(RESULT_A), false); + testInvokePos(m, ref, vm().mirrorOf(RESULT_A), true); + // Test non-virtual calls on InterfaceA - ReferenceType ifaceClass = (ReferenceType)vm().classesByName(INTERFACEA_NAME).get(0); /* Default method calls */ // invoke the InterfaceA's "defaultMethodA" @@ -185,39 +202,48 @@ // "defaultMethodD" from InterfaceB is not accessible from here testInvokeNeg(ifaceClass, ref, "defaultMethodD", "()I", vm().mirrorOf(RESULT_B), - "Attempted to invoke non-existing method"); + "Attempted to invoke non-existing method"); - // trying to invoke the asbtract method "implementedMethod" + // non-virtual invoke of the abstract method "implementedMethod" fails testInvokeNeg(ifaceClass, ref, "implementedMethod", "()I", vm().mirrorOf(TARGET_CLASS_NAME), - "Invocation of non-default methods is not supported"); - + "Invocation of abstract methods is not supported"); /* Static method calls */ - // invoke interface static method A + // invoke static interface method A testInvokePos(ifaceClass, null, "staticMethodA", "()I", vm().mirrorOf(RESULT_A)); // invoking static method A on the instance fails because static method A is // not inherited by TargetClass. testInvokeNeg(ifaceClass, ref, "staticMethodA", "()I", vm().mirrorOf(RESULT_A), - "Invalid MethodID"); + "Invalid MethodID"); - // invoke interface static method B + // invoke static interface method B testInvokePos(ifaceClass, null, "staticMethodB", "()I", vm().mirrorOf(RESULT_A)); // invoking static method B on the instance fails because static method B is // not inherited by TargetClass. testInvokeNeg(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_A), - "Invalid MethodID"); + "Invalid MethodID"); // try to invoke a virtual method - testInvokePos(ifaceClass, ref, "implementedMethod", "()I", vm().mirrorOf(RESULT_A), true); + testInvokePos(ifaceClass, ref, "implementedMethod", "()I", vm().mirrorOf(RESULT_TARGET), true); } private void testInterfaceB(ObjectReference ref) { // Test non-virtual calls on InterfaceB ReferenceType ifaceClass = (ReferenceType)vm().classesByName(INTERFACEB_NAME).get(0); + /* private method calls */ + + /* These should fail but won't because of JDK-8167416 + testLookup(ifaceClass, "privateMethodA", "()I", true, NoSuchMethodError.class); // should fail + testLookup(ifaceClass, "privateMethodA", "()I", false, NoSuchMethodError.class); // should fail + */ + Method m = testLookup(ifaceClass, "privateMethodB", "()I", true, null); // should succeed + testInvokePos(m, ref, vm().mirrorOf(RESULT_B), false); + testInvokePos(m, ref, vm().mirrorOf(RESULT_B), true); + /* Default method calls */ // invoke the inherited "defaultMethodA" @@ -267,19 +293,21 @@ private void testImplementationClass(ReferenceType targetClass, ObjectReference thisObject) { // Test invocations on the implementation object + // Note: private interface calls have already been tested + /* Default method calls */ // "defaultMethodA" is accessible and not overridden - testInvokePos(targetClass, thisObject, "defaultMethodA", "()I", vm().mirrorOf(RESULT_TARGET)); + testInvokePos(targetClass, thisObject, "defaultMethodA", "()I", vm().mirrorOf(RESULT_A)); // "defaultMethodB" is accessible and overridden in TargetClass testInvokePos(targetClass, thisObject, "defaultMethodB", "()I", vm().mirrorOf(RESULT_TARGET)); // "defaultMethodC" is accessible and overridden in InterfaceB - testInvokePos(targetClass, thisObject, "defaultMethodC", "()I", vm().mirrorOf(RESULT_TARGET)); + testInvokePos(targetClass, thisObject, "defaultMethodC", "()I", vm().mirrorOf(RESULT_B)); // "defaultMethodD" is accessible - testInvokePos(targetClass, thisObject, "defaultMethodD", "()I", vm().mirrorOf(RESULT_TARGET)); + testInvokePos(targetClass, thisObject, "defaultMethodD", "()I", vm().mirrorOf(RESULT_B)); /* Non-default instance method calls */ @@ -314,11 +342,16 @@ "Static interface methods are not inheritable"); } + // Non-virtual invocation private void testInvokePos(ReferenceType targetClass, ObjectReference ref, String methodName, String methodSig, Value value) { testInvokePos(targetClass, ref, methodName, methodSig, value, false); } + // Lookup the named method in the targetClass and invoke on the given object (for instance methods) + // using virtual, or non-virtual, invocation mode as specified, for instance methods. Verify the + // expected return value. + // Should succeed. private void testInvokePos(ReferenceType targetClass, ObjectReference ref, String methodName, String methodSig, Value value, boolean virtual) { logInvocation(ref, methodName, methodSig, targetClass); @@ -331,11 +364,31 @@ } } + // Invoke the given Method on the given object (for instance methods) + // using virtual, or non-virtual, invocation mode as specified, for instance methods. Verify the + // expected return value. + // Should succeed. + private void testInvokePos(Method method, ObjectReference ref, Value value, boolean virtual) { + logInvocation(ref, method.name(), method.signature(), method.declaringType()); + try { + invoke(method.declaringType(), ref, method, value, virtual); + System.err.println("--- PASSED"); + } catch (Exception e) { + System.err.println("--- FAILED"); + failure("FAILED: Invocation failed with error message " + e.getLocalizedMessage()); + } + } + + // Non-virtual invocation - with lookup in targetClass private void testInvokeNeg(ReferenceType targetClass, ObjectReference ref, String methodName, String methodSig, Value value, String msg) { testInvokeNeg(targetClass, ref, methodName, methodSig, value, msg, false); } + // Lookup the named method in the targetClass and invoke on the given object (for instance methods) + // using virtual, or non-virtual, invocation mode as specified, for instance methods. Verify the + // expected return value. + // Should fail - with msg decribing why failure was expected private void testInvokeNeg(ReferenceType targetClass, ObjectReference ref, String methodName, String methodSig, Value value, String msg, boolean virtual) { logInvocation(ref, methodName, methodSig, targetClass); @@ -350,12 +403,17 @@ } private void invoke(ReferenceType targetClass, ObjectReference ref, String methodName, - String methodSig, Value value, boolean virtual) - throws Exception { + String methodSig, Value value, boolean virtual) throws Exception { + Method method = getMethod(targetClass, methodName, methodSig); if (method == null) { throw new Exception("Can't find method: " + methodName + " for class = " + targetClass); } + invoke(targetClass, ref, method, value, virtual); + } + + private void invoke(ReferenceType targetClass, ObjectReference ref, Method method, + Value value, boolean virtual) throws Exception { println("Invoking " + (method.isAbstract() ? "abstract " : " ") + "method: " + method); println(method.declaringType().toString()); @@ -365,7 +423,7 @@ if (virtual) { returnValue = invokeVirtual(ref, method); } else { - returnValue = invokeInstance(ref, method); + returnValue = invokeNonVirtual(ref, method); } } else { returnValue = invokeStatic(targetClass, method); @@ -387,7 +445,7 @@ } } - private Value invokeInstance(ObjectReference ref, Method method) throws Exception { + private Value invokeNonVirtual(ObjectReference ref, Method method) throws Exception { return ref.invokeMethod(mainThread, method, Collections.emptyList(), ObjectReference.INVOKE_NONVIRTUAL); } @@ -449,4 +507,58 @@ methodName + methodSig); } } + + private Method testLookup(ReferenceType targetClass, String methodName, String methodSig, + boolean declaredOnly, Class expectedException) { + + System.err.println("Looking up " + targetClass.name() + "." + methodName + methodSig); + try { + Method m = declaredOnly ? + lookupDeclaredMethod(targetClass, methodName, methodSig) : + lookupMethod(targetClass, methodName, methodSig); + + if (expectedException == null) { + System.err.println("--- PASSED"); + return m; + } + else { + System.err.println("--- FAILED"); + failure("FAILED: lookup succeeded but expected exception " + + expectedException.getSimpleName()); + return null; + } + } + catch (Throwable t) { + if (t.getClass() != expectedException) { + System.err.println("--- FAILED"); + failure("FAILED: got exception " + t + " but expected exception " + + expectedException.getSimpleName()); + return null; + } + else { + System.err.println("--- PASSED"); + return null; + } + } + } + + private Method lookupMethod(ReferenceType targetClass, String methodName, String methodSig) { + List methods = targetClass.allMethods(); + Iterator iter = methods.iterator(); + while (iter.hasNext()) { + Method method = (Method)iter.next(); + if (method.name().equals(methodName) && + method.signature().equals(methodSig)) { + return method; + } + } + throw new NoSuchMethodError(); + } + + private Method lookupDeclaredMethod(ReferenceType targetClass, String methodName, String methodSig) { + Method m = findMethod(targetClass, methodName, methodSig); + if (m == null) + throw new NoSuchMethodError(); + return m; + } } diff -r f71b844f33d1 -r 95af45781076 jdk/test/com/sun/jndi/dns/Parser.java --- a/jdk/test/com/sun/jndi/dns/Parser.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/com/sun/jndi/dns/Parser.java Fri Nov 11 16:44:36 2016 +0100 @@ -26,6 +26,7 @@ * @bug 8035105 * @summary DNS resource record parsing * @modules jdk.naming.dns/com.sun.jndi.dns + * @compile --add-modules jdk.naming.dns Parser.java */ import com.sun.jndi.dns.ResourceRecord; diff -r f71b844f33d1 -r 95af45781076 jdk/test/com/sun/jndi/rmi/registry/RegistryContext/ContextWithNullProperties.java --- a/jdk/test/com/sun/jndi/rmi/registry/RegistryContext/ContextWithNullProperties.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/com/sun/jndi/rmi/registry/RegistryContext/ContextWithNullProperties.java Fri Nov 11 16:44:36 2016 +0100 @@ -28,7 +28,7 @@ * @modules jdk.naming.rmi/com.sun.jndi.rmi.registry java.rmi/sun.rmi.registry * java.rmi/sun.rmi.server java.rmi/sun.rmi.transport java.rmi/sun.rmi.transport.tcp * @library ../../../../../../java/rmi/testlibrary - * @build TestLibrary + * @compile --add-modules jdk.naming.rmi ContextWithNullProperties.java * @run main ContextWithNullProperties */ diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/FileDialog/8017487/bug8017487.java --- a/jdk/test/java/awt/FileDialog/8017487/bug8017487.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/awt/FileDialog/8017487/bug8017487.java Fri Nov 11 16:44:36 2016 +0100 @@ -22,7 +22,7 @@ */ /* @test - @bug 8017487 + @bug 8017487 8167988 @summary filechooser in Windows-Libraries folder: columns are mixed up @author Semyon Sadetsky @modules java.desktop/sun.awt.shell diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/Focus/RequestFocusByCause/RequestFocusByCauseTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Focus/RequestFocusByCause/RequestFocusByCauseTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 8154434 + @summary Open the request focus methods of the java.awt.Component which accept + FocusEvent.Cause + @run main RequestFocusByCauseTest +*/ + +import java.awt.*; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; + +public class RequestFocusByCauseTest { + static boolean success; + + public static void main(String[] args) throws Exception { + testRequestFocusCause(); + testRequestFocusTemporaryCause(); + testRequestFocusInWindowCause(); + System.out.println("ok"); + } + + private static void testRequestFocusCause() throws AWTException { + Frame frame = new Frame(); + Component c = new Button(); + frame.add(new Button()); + frame.add(c); + c.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + success = e.getCause() == FocusEvent.Cause.UNEXPECTED; + } + + @Override + public void focusLost(FocusEvent e) {} + }); + Robot robot = new Robot(); + + try { + frame.setVisible(true); + robot.waitForIdle(); + robot.delay(200); + success = false; + + c.requestFocus(FocusEvent.Cause.UNEXPECTED); + robot.waitForIdle(); + robot.delay(200); + if(!success) { + throw new RuntimeException("request failed"); + } + } finally { + frame.dispose(); + } + } + + private static void testRequestFocusTemporaryCause() throws AWTException { + Frame frame = new Frame(); + frame.add(new Button() { + @Override + protected boolean requestFocus(boolean temporary, + FocusEvent.Cause cause) { + success = cause == FocusEvent.Cause.ROLLBACK; + return super.requestFocus(temporary, cause); + } + }); + Component c = new Button() { + @Override + public void requestFocus() { + super.requestFocus(); + setFocusable(false); + } + }; + frame.add(c); + Robot robot = new Robot(); + + try { + frame.setVisible(true); + robot.waitForIdle(); + robot.delay(200); + + success = false; + c.requestFocus(); + robot.waitForIdle(); + robot.delay(200); + + + if(!success) { + throw new RuntimeException("rollback request is not triggered"); + } + } finally { + frame.dispose(); + } + } + + private static void testRequestFocusInWindowCause() throws AWTException { + Frame frame = new Frame(); + Component c = new Button(); + frame.add(new Button()); + frame.add(c); + c.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + success = e.getCause() == FocusEvent.Cause.UNEXPECTED; + } + + @Override + public void focusLost(FocusEvent e) { + } + }); + Robot robot = new Robot(); + + try { + frame.setVisible(true); + robot.waitForIdle(); + robot.delay(200); + success = false; + + c.requestFocusInWindow(FocusEvent.Cause.UNEXPECTED); + robot.waitForIdle(); + robot.delay(200); + if (!success) { + throw new RuntimeException("request in window failed"); + } + } finally { + frame.dispose(); + } + } +} \ No newline at end of file diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/Frame/SetIconImagesCrashTest/SetIconImagesCrashTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Frame/SetIconImagesCrashTest/SetIconImagesCrashTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @key headful + * @bug 8166980 + * @summary Test to check Window.setIconImages() does not result in crash when + * a frame is shown + * @run main/othervm SetIconImagesCrashTest + * @run main/othervm -Dsun.java2d.uiScale=2 SetIconImagesCrashTest + */ + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Window; +import java.awt.Frame; +import java.util.List; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import javax.swing.SwingUtilities; + +public class SetIconImagesCrashTest { + + public static void main(String[] args) throws Exception { + + List imageList = new ArrayList(); + imageList.add(new BufferedImage(200, 200, + BufferedImage.TYPE_BYTE_BINARY)); + + for (int i = 0; i < 10; i++) { + Frame f = new Frame(); + test(f, imageList); + } + } + + public static void test(final Window window, + final List imageList) throws Exception { + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + for (BufferedImage image : imageList) { + Graphics graphics = image.getGraphics(); + graphics.setColor(Color.RED); + graphics.fillRect( + 0, 0, image.getWidth(), image.getHeight()); + graphics.dispose(); + } + + window.setIconImages(imageList); + window.setSize(200, 200); + window.setVisible(true); + } + }); + + while (!window.isVisible()) { + Thread.sleep((long) (20)); + } + + Thread.sleep((long) (50)); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + window.setVisible(false); + window.dispose(); + } + }); + } +} + diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/FullScreen/CurrentDisplayModeTest/CurrentDisplayModeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/FullScreen/CurrentDisplayModeTest/CurrentDisplayModeTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8022810 + * @summary Device.getDisplayMode() doesn't report refresh rate on Linux in case + * of dual screen + * @run main CurrentDisplayModeTest + */ + +import java.awt.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class CurrentDisplayModeTest { + public static void main(String[] args) { + GraphicsDevice[] screenDevices = GraphicsEnvironment. + getLocalGraphicsEnvironment().getScreenDevices(); + for (GraphicsDevice screenDevice : screenDevices) { + DisplayMode currentMode = screenDevice.getDisplayMode(); + System.out.println("current mode " + currentMode); + Set set = new HashSet<>( + Arrays.asList(screenDevice.getDisplayModes())); + if (!set.contains(currentMode)) { + throw new RuntimeException("Mode " + currentMode + + " is not found in the modes list " + set); + } + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/Graphics/IncorrectFractionalClip/IncorrectFractionalClip.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Graphics/IncorrectFractionalClip/IncorrectFractionalClip.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.geom.Area; +import java.awt.image.BufferedImage; +import java.io.File; + +import javax.imageio.ImageIO; + +import static java.awt.RenderingHints.KEY_STROKE_CONTROL; +import static java.awt.RenderingHints.VALUE_STROKE_PURE; +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; + +/** + * @test + * @key headful + * @bug 8167310 + * @summary The clip should be correct if the scale is fractional + */ +public final class IncorrectFractionalClip { + + private static final int SIZE = 128; + + public static final Color RED = new Color(255, 0, 0, 100); + + public static final Color GREEN = new Color(0, 255, 0, 100); + + public static final Color WHITE = new Color(0, 0, 0, 0); + + public static final BasicStroke STROKE = new BasicStroke(2.01f); + + private static final double[] SCALES = { + 0.1, 0.25, 0.4, 0.5, 0.6, 1, 1.4, 1.5, 1.6, 2.0, 2.4, 2.5, 2.6, 4 + }; + + static BufferedImage bi; + + static BufferedImage gold; + + static BufferedImage redI; + + static BufferedImage greenI; + + public static void main(final String[] args) throws Exception { + bi = new BufferedImage(SIZE, SIZE, TYPE_INT_ARGB); + gold = new BufferedImage(SIZE, SIZE, TYPE_INT_ARGB); + redI = createImage(RED); + greenI = createImage(GREEN); + + System.out.println("Will test fillRect"); + test(0, true); + test(0, false); + System.out.println("Will test DrawImage"); + test(1, true); + test(1, false); + System.out.println("Will test drawLine"); + test(2, true); + test(2, false); + } + + /** + * This method draws/fills a number of rectangle, images and lines. Each + * time the clip is set as one vertical/horizontal line. The resulted image + * should not have any overlapping of different colors. The clip is set via + * rectangle(test) and via shape(gold). Both images should be identical. + */ + private static void test(final int testId, final boolean horiz) + throws Exception { + for (final double scale : SCALES) { + // Initialize the test and gold images + drawToImage(testId, horiz, scale, bi, /* Rectangle */ false); + drawToImage(testId, horiz, scale, gold, /* Shape */ true); + validate(bi, gold, testId); + } + } + + private static void drawToImage(int testId, boolean horiz, double scale, + BufferedImage image, boolean shape) { + Graphics2D g = image.createGraphics(); + g.setComposite(AlphaComposite.Src); + g.setColor(WHITE); + g.fillRect(0, 0, bi.getWidth(), bi.getHeight()); + g.setComposite(AlphaComposite.SrcOver); + g.setRenderingHint(KEY_STROKE_CONTROL, VALUE_STROKE_PURE); + + // set the scale in one direction + if (horiz) { + g.scale(scale, 1); + } else { + g.scale(1, scale); + } + // cover all units in the user space to touch all pixels in the + // image after transform + final int destSize = (int) Math.ceil(SIZE / scale); + final int destW; + final int destH; + if (horiz) { + destW = destSize; + destH = SIZE; + } else { + destW = SIZE; + destH = destSize; + } + for (int step = 0; step < destSize; ++step) { + if (horiz) { + if (!shape) { + g.setClip(step, 0, 1, SIZE); + } else{ + g.setClip(new Area(new Rectangle(step, 0, 1, SIZE))); + } + } else { + if (!shape) { + g.setClip(0, step, SIZE, 1); + }else{ + g.setClip(new Area(new Rectangle(0, step, SIZE, 1))); + } + } + switch (testId) { + case 0: + g.setColor(step % 2 == 0 ? RED : GREEN); + g.fillRect(0, 0, destW, destH); + break; + case 1: + g.drawImage(step % 2 == 0 ? redI : greenI, 0, 0, + destW, destH, null); + break; + case 2: + g.setColor(step % 2 == 0 ? RED : GREEN); + g.setStroke(STROKE); + if (horiz) { + g.drawLine(step, 0, step, SIZE); + } else { + g.drawLine(0, step, SIZE, step); + } + break; + default: + throw new RuntimeException(); + } + } + g.dispose(); + } + + private static void validate(final BufferedImage bi, BufferedImage gold, + final int testID) throws Exception { + for (int x = 0; x < SIZE; ++x) { + for (int y = 0; y < SIZE; ++y) { + int rgb = bi.getRGB(x, y); + int goldRGB = gold.getRGB(x, y); + if ((rgb != GREEN.getRGB() && rgb != RED.getRGB()) + || rgb != goldRGB) { + ImageIO.write(bi, "png", new File("image.png")); + ImageIO.write(gold, "png", new File("gold.png")); + throw new RuntimeException("Test failed."); + } + } + } + } + + private static BufferedImage createImage(final Color color) { + BufferedImage bi = new BufferedImage(SIZE, SIZE, TYPE_INT_ARGB); + Graphics2D g = bi.createGraphics(); + g.setComposite(AlphaComposite.Src); + g.setColor(color); + g.fillRect(0, 0, bi.getWidth(), bi.getHeight()); + g.dispose(); + return bi; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java --- a/jdk/test/java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. 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 @@ -23,7 +23,7 @@ /* test - @bug 6380743 + @bug 6380743 8158380 @summary Submenu should be shown by mnemonic key press. @author anton.tarasov@...: area=awt.focus @run applet SubMenuShowTest.html @@ -55,6 +55,8 @@ public void init() { robot = Util.createRobot(); + robot.setAutoDelay(200); + robot.setAutoWaitForIdle(true); // Create instructions for the user here, as well as set up // the environment -- set the layout manager, add buttons, @@ -85,35 +87,24 @@ }); frame.setVisible(true); - Util.waitForIdle(robot); boolean isMacOSX = (OSInfo.getOSType() == OSInfo.OSType.MACOSX); if (isMacOSX) { robot.keyPress(KeyEvent.VK_CONTROL); - robot.delay(20); } robot.keyPress(KeyEvent.VK_ALT); - robot.delay(20); robot.keyPress(KeyEvent.VK_F); - robot.delay(20); robot.keyRelease(KeyEvent.VK_F); - robot.delay(20); robot.keyRelease(KeyEvent.VK_ALT); + if (isMacOSX) { robot.keyRelease(KeyEvent.VK_CONTROL); - robot.delay(20); } - Util.waitForIdle(robot); robot.keyPress(KeyEvent.VK_M); - robot.delay(20); robot.keyRelease(KeyEvent.VK_M); - Util.waitForIdle(robot); - robot.keyPress(KeyEvent.VK_SPACE); - robot.delay(20); robot.keyRelease(KeyEvent.VK_SPACE); - Util.waitForIdle(robot); if (!Util.waitForCondition(activated, 2000)) { throw new TestFailedException("a submenu wasn't activated by mnemonic key press"); diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/List/ActionEventTest/ActionEventTest.java --- a/jdk/test/java/awt/List/ActionEventTest/ActionEventTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/awt/List/ActionEventTest/ActionEventTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. 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 @@ -24,7 +24,7 @@ /* * @test * @key headful - * @bug 6191390 + * @bug 6191390 8158380 * @summary Verify that ActionEvent is received with correct modifiers set. * @run main ActionEventTest */ @@ -45,6 +45,8 @@ public ActionEventTest() { try { robot = new Robot(); + robot.setAutoDelay(100); + robot.setAutoWaitForIdle(true); } catch(AWTException e) { throw new RuntimeException(e.getMessage()); } @@ -56,7 +58,6 @@ setLayout(new FlowLayout()); pack(); setVisible(true); - robot.waitForIdle(); } void performTest() { @@ -86,11 +87,9 @@ // Press Enter on list item, to generate action event. robot.keyPress(KeyEvent.VK_ENTER); robot.keyRelease(KeyEvent.VK_ENTER); - robot.waitForIdle(); robot.keyRelease(KeyEvent.VK_ALT); robot.keyRelease(KeyEvent.VK_SHIFT); robot.keyRelease(KeyEvent.VK_CONTROL); - robot.waitForIdle(); } public static void main(String args[]) { diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/Modal/InvisibleParentTest/InvisibleParentTest.html --- a/jdk/test/java/awt/Modal/InvisibleParentTest/InvisibleParentTest.html Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ - - - - - - InvisibleParentTest - - - -

    InvisibleParentTest
    Bug ID: 6401700, 6412803

    - -

    See the dialog box (usually in upper left corner) for instructions

    - - - - diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/Modal/InvisibleParentTest/InvisibleParentTest.java --- a/jdk/test/java/awt/Modal/InvisibleParentTest/InvisibleParentTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/awt/Modal/InvisibleParentTest/InvisibleParentTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. 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 @@ -22,214 +22,187 @@ */ /* - test - @bug 6401700 6412803 - @summary Tests that modal dialog is shown on the screen and -iconified/restored correctly if some of its blocked windows are invisible - @author artem.ananiev: area=awt.modal - @run applet/manual=yesno InvisibleParentTest.html -*/ - -import java.applet.Applet; -import java.awt.BorderLayout; -import java.awt.Button; -import java.awt.Component; + * @test + * @key headful + * @bug 6401700 6412803 8058950 + * @summary Tests that modal dialog is shown on the screen and + * iconified/restored correctly if some of its blocked windows are invisible + * @requires (os.family == "linux" | os.family == "solaris") + * @run main/manual InvisibleParentTest + */ import java.awt.Dialog; import java.awt.Frame; -import java.awt.TextArea; -import java.awt.Window; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; + +public class InvisibleParentTest { -public class InvisibleParentTest extends Applet -{ - public void init() - { - setLayout(new BorderLayout()); + public static void main(String args[]) throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + TestUI test = new TestUI(latch); + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + try { + test.createUI(); + } catch (Exception ex) { + throw new RuntimeException("Exception while creating test UI"); + } + } + }); + + boolean status = latch.await(5, TimeUnit.MINUTES); - String[] instructions = - { - "If your system is Windows, press PASS button.", - "When the test starts two windows should appear: frame G1 and", - " dialog D1. Another one frame F1 should be minimized.", - " If the dialog is not shown (minimizied), press FAIL button.", - "Then minimize frame G1 and restore F1. If the dialog D1 is not", - " restored together with F1, press FAIL, else PASS" - }; - Sysout.createDialogWithInstructions( instructions ); + if (!status) { + System.out.println("Test timed out."); + } + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + test.disposeUI(); + } catch (Exception ex) { + throw new RuntimeException("Exception while disposing test UI"); + } + } + }); + + if (test.testResult == false) { + throw new RuntimeException("Test Failed."); + } + } +} + +class TestUI { + + private static JFrame mainFrame; + private static JPanel mainControlPanel; + + private static JTextArea instructionTextArea; + + private static JPanel resultButtonPanel; + private static JButton passButton; + private static JButton failButton; + + private static GridBagLayout layout; + private final CountDownLatch latch; + public boolean testResult = false; + + public TestUI(CountDownLatch latch) throws Exception { + this.latch = latch; } - public void start () - { - Button b; + public final void createUI() throws Exception { + + mainFrame = new JFrame("InvisibleParentTest"); + mainFrame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE); + + layout = new GridBagLayout(); + mainControlPanel = new JPanel(layout); + resultButtonPanel = new JPanel(layout); + + GridBagConstraints gbc = new GridBagConstraints(); + + // Create Test instructions + String instructions + = "When the test starts two windows should appear: frame G1 and\n" + + " dialog D1. Another one frame F1 should be minimized.\n" + + " If the dialog is not shown (minimizied), press FAIL button.\n" + + "Then minimize frame G1 and restore F1. If the dialog D1 is not\n" + + " restored together with F1, press FAIL, else PASS"; - setSize (200,200); - setVisible(true); - validate(); + instructionTextArea = new JTextArea(); + instructionTextArea.setText(instructions); + instructionTextArea.setEditable(false); + instructionTextArea.setBorder(BorderFactory. + createTitledBorder("Test Instructions")); + + gbc.gridx = 0; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + mainControlPanel.add(instructionTextArea, gbc); + + // Create resultButtonPanel with Pass, Fail buttons + passButton = new JButton("Pass"); + passButton.setActionCommand("Pass"); + passButton.addActionListener((ActionEvent e) -> { + System.out.println("Pass Button pressed!"); + testResult = true; + latch.countDown(); - Component c = this; - while ((c != null) && !(c instanceof Window)) - { - c = c.getParent(); - } - if (c != null) - { - ((Window)c).setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE); - } + }); + + failButton = new JButton("Fail"); + failButton.setActionCommand("Fail"); + failButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + System.out.println("Fail Button pressed!"); + testResult = false; + latch.countDown(); + } + }); + + gbc.gridx = 0; + gbc.gridy = 0; + resultButtonPanel.add(passButton, gbc); + gbc.gridx = 1; + gbc.gridy = 0; + resultButtonPanel.add(failButton, gbc); + gbc.gridx = 0; + gbc.gridy = 1; + mainControlPanel.add(resultButtonPanel, gbc); + + mainFrame.add(mainControlPanel); + + mainFrame.pack(); + mainFrame.setVisible(true); + + // Create AWT frames and modal dialog + createAWTComponents(); + } + + public void disposeUI() { + mainFrame.setVisible(false); + mainFrame.dispose(); + } + + private void createAWTComponents() { Frame f1 = new Frame("F1"); f1.setBounds(100, 300, 100, 100); f1.setVisible(true); + + try { + Thread.sleep(500); + } catch (Exception ex) { + } + f1.setExtendedState(Frame.ICONIFIED); Frame g1 = new Frame("G1"); g1.setBounds(150, 350, 100, 100); g1.setVisible(true); - final Dialog d1 = new Dialog((Frame)null, "D1", Dialog.ModalityType.APPLICATION_MODAL); + final Dialog d1 = new Dialog((Frame) null, "D1", Dialog.ModalityType.APPLICATION_MODAL); d1.setBounds(200, 400, 100, 100); - new Thread(new Runnable() - { - public void run() - { + new Thread(new Runnable() { + public void run() { d1.setVisible(true); } }).start(); } } -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); - } - -}// TestDialog class diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/Robot/WaitForIdleSyncroizedOnString/WaitForIdleSyncroizedOnString.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Robot/WaitForIdleSyncroizedOnString/WaitForIdleSyncroizedOnString.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Robot; +import java.util.concurrent.CountDownLatch; + +import javax.swing.SwingUtilities; + +/** + * @test + * @key headful + * @bug 8166673 + */ +public final class WaitForIdleSyncroizedOnString { + + private static final String WAIT_LOCK = "Wait Lock"; + + private static volatile boolean passed = true; + + public static void main(final String[] args) throws Exception { + CountDownLatch go = new CountDownLatch(1); + Robot r = new Robot(); + SwingUtilities.invokeLater(() -> System.out.println("some work")); + Thread t = new Thread(() -> { + synchronized (WAIT_LOCK) { + go.countDown(); + try { + Thread.sleep(30000); + passed = false; + } catch (InterruptedException e) { + System.out.println("e = " + e); + } + } + }); + t.start(); + go.await(); + r.waitForIdle(); + t.interrupt(); + if (!passed) { + throw new RuntimeException("Test failed"); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java --- a/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -43,7 +43,7 @@ /** * @test * @key headful - * @bug 8043869 8075244 8078082 8145173 + * @bug 8043869 8075244 8078082 8145173 8151787 * @summary Tests the HiDPI splash screen support for windows and MAC * @modules java.desktop/sun.java2d * @run main MultiResolutionSplashTest GENERATE_IMAGES @@ -56,27 +56,20 @@ private static final int IMAGE_WIDTH = 300; private static final int IMAGE_HEIGHT = 200; + private static boolean isMac; - private static final ImageInfo[] macTests = { + static { + isMac = System.getProperty("os.name").contains("OS X"); + } + private static final ImageInfo[] tests = { new ImageInfo("splash1.png", "splash1@2x.png", Color.BLUE, Color.GREEN), new ImageInfo("splash2", "splash2@2x", Color.WHITE, Color.BLACK), new ImageInfo("splash3.", "splash3@2x.", Color.YELLOW, Color.RED) }; - private static final ImageInfo[] windowsTests = { - new ImageInfo("splash1.png", "splash1.scale-120.png", Color.BLUE, Color.GREEN), - new ImageInfo("splash2", "splash2.scale-120", Color.WHITE, Color.BLACK), - new ImageInfo("splash3.", "splash3.scale-120.", Color.YELLOW, Color.RED) - }; - private static ImageInfo[] tests; public static void main(String[] args) throws Exception { String test = args[0]; - tests = windowsTests; - String osName = System.getProperty("os.name"); - if (osName.contains("OS X")) { - tests = macTests; - } switch (test) { case "GENERATE_IMAGES": generateImages(); @@ -104,12 +97,10 @@ Rectangle splashBounds = splashScreen.getBounds(); int screenX = (int) splashBounds.getCenterX(); int screenY = (int) splashBounds.getCenterY(); - if (splashBounds.width != IMAGE_WIDTH) { throw new RuntimeException( "SplashScreen#getBounds has wrong width"); } - if (splashBounds.height != IMAGE_HEIGHT) { throw new RuntimeException( "SplashScreen#getBounds has wrong height"); @@ -117,7 +108,6 @@ Robot robot = new Robot(); Color splashScreenColor = robot.getPixelColor(screenX, screenY); - float scaleFactor = getScaleFactor(); Color testColor = (1 < scaleFactor) ? test.color2x : test.color1x; @@ -129,7 +119,6 @@ static void testFocus() throws Exception { - System.out.println("Focus Test!"); Robot robot = new Robot(); robot.setAutoDelay(50); @@ -150,18 +139,18 @@ frame.dispose(); - if(!textField.getText().equals("ab")){ + if (!textField.getText().equals("ab")) { throw new RuntimeException("Focus is lost!"); } } - static boolean compare(Color c1, Color c2){ + static boolean compare(Color c1, Color c2) { return compare(c1.getRed(), c2.getRed()) && compare(c1.getGreen(), c2.getGreen()) && compare(c1.getBlue(), c2.getBlue()); } - static boolean compare(int n, int m){ + static boolean compare(int n, int m) { return Math.abs(n - m) <= 50; } @@ -177,10 +166,7 @@ public void paint(Graphics g) { float scaleFactor = 1; if (g instanceof SunGraphics2D) { - scaleFactor = (float)GraphicsEnvironment. - getLocalGraphicsEnvironment(). - getDefaultScreenDevice().getDefaultConfiguration(). - getDefaultTransform().getScaleX(); + scaleFactor = getScreenScaleFactor(); } scaleFactors[0] = scaleFactor; dialog.setVisible(false); @@ -197,23 +183,30 @@ static void generateImages() throws Exception { for (ImageInfo test : tests) { generateImage(test.name1x, test.color1x, 1); - generateImage(test.name2x, test.color2x, 2); + generateImage(test.name2x, test.color2x, getScreenScaleFactor()); } } - static void generateImage(String name, Color color, int scale) throws Exception { + static void generateImage(String name, Color color, float scale) throws Exception { File file = new File(name); if (file.exists()) { return; } - BufferedImage image = new BufferedImage(scale * IMAGE_WIDTH, scale * IMAGE_HEIGHT, - BufferedImage.TYPE_INT_RGB); + BufferedImage image = new BufferedImage((int) (scale * IMAGE_WIDTH), + (int) (scale * IMAGE_HEIGHT), BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); g.setColor(color); - g.fillRect(0, 0, scale * IMAGE_WIDTH, scale * IMAGE_HEIGHT); + g.fillRect(0, 0, (int) (scale * IMAGE_WIDTH), (int) (scale * IMAGE_HEIGHT)); ImageIO.write(image, "png", file); } + static float getScreenScaleFactor() { + return (float) GraphicsEnvironment. + getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(). + getDefaultTransform().getScaleX(); + } + static class ImageInfo { final String name1x; @@ -223,9 +216,32 @@ public ImageInfo(String name1x, String name2x, Color color1x, Color color2x) { this.name1x = name1x; - this.name2x = name2x; + if (!isMac) { + float scale = getScreenScaleFactor(); + StringBuffer buff = new StringBuffer(); + if (scale - (int) scale > 0) { + buff.append("@").append((int) (scale * 100)).append("pct"); + } else { + buff.append("@").append((int) scale).append("x"); + } + StringBuffer buffer = new StringBuffer(); + String[] splitStr = name1x.split("\\."); + if (splitStr.length == 2) { + this.name2x = buffer.append(splitStr[0]).append(buff) + .append(".").append(splitStr[1]).toString(); + } else { + if (name1x.indexOf(".") > 0) { + this.name2x = buffer.append(splitStr[0]).append(buff).append(".").toString(); + } else { + this.name2x = buffer.append(splitStr[0]).append(buff).toString(); + } + } + } else { + this.name2x = name2x; + } this.color1x = color1x; this.color2x = color2x; } } } + diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java --- a/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -44,7 +44,7 @@ import javax.imageio.ImageIO; /** - * @test @bug 8145174 + * @test @bug 8145174 8151787 * @summary HiDPI splash screen support on Linux * @modules java.desktop/sun.java2d * @run main UnixMultiResolutionSplashTest @@ -55,9 +55,9 @@ private static final int IMAGE_HEIGHT = 200; private static int inx = 0; private static final ImageInfo[] tests = { - new ImageInfo("splash1.png", "splash1.java-scale2x.png", Color.BLUE, Color.GREEN), - new ImageInfo("splash2", "splash2.java-scale2x", Color.WHITE, Color.BLACK), - new ImageInfo("splash3.", "splash3.java-scale2x.", Color.YELLOW, Color.RED) + new ImageInfo("splash1.png", "splash1@200pct.png", Color.BLUE, Color.GREEN), + new ImageInfo("splash2", "splash2@2x", Color.WHITE, Color.BLACK), + new ImageInfo("splash3.", "splash3@200pct.", Color.YELLOW, Color.RED) }; public static void main(String[] args) throws Exception { @@ -96,8 +96,6 @@ Rectangle splashBounds = splashScreen.getBounds(); int screenX = (int) splashBounds.getCenterX(); int screenY = (int) splashBounds.getCenterY(); - System.out.println(screenX); - System.out.println(screenY); Robot robot = new Robot(); Color splashScreenColor = robot.getPixelColor(screenX, screenY); diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/TrayIcon/DragEventSource/DragEventSource.java --- a/jdk/test/java/awt/TrayIcon/DragEventSource/DragEventSource.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/awt/TrayIcon/DragEventSource/DragEventSource.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. 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 @@ -23,8 +23,8 @@ /* @test - @bug 6565779 - @library ../../../regtesthelpers + @bug 6565779 8168292 + @library ../../regtesthelpers @compile DragEventSource.java @summary Exception if source of some event is TrayIcon @author Andrei Dmitriev: area=awt.tray @@ -38,9 +38,19 @@ * instance as source. */ -import java.awt.*; -import java.awt.event.*; -import java.awt.image.*; +import java.awt.Button; +import java.awt.Dialog; +import java.awt.FileDialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Image; +import java.awt.Panel; +import java.awt.SystemTray; +import java.awt.TextArea; +import java.awt.TrayIcon; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.image.BufferedImage; public class DragEventSource { @@ -81,11 +91,10 @@ String[] instructions = { - "Use see a Frame with a button in it.", - "Press the button. FileDialog should appear.", - "Drag the mouse from the Tray icon to FileDialog ", - "using left mouse button.", - "If exception happens, the test fails.", + "Click 'Open file dialog' button. FileDialog should appear.", + "Using left mouse button,", + "Drag the mouse from the Tray icon to FileDialog.", + "If exception is thrown, the test fails.", "Otherwise, pass." }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java --- a/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. 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 @@ -21,7 +21,11 @@ * questions. */ -import java.awt.*; +import java.awt.EventQueue; +import java.awt.Image; +import java.awt.Point; +import java.awt.SystemTray; +import java.awt.TrayIcon; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; @@ -31,9 +35,10 @@ /* * @test + * @bug 8161473 + * @key headful * @summary Check if MouseEvent has the proper modifiers when * TrayIcon is clicked pressing the modifier keys - * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com) * @library /java/awt/patchlib * @library ../../../../lib/testlibrary ../ * @build java.desktop/java.awt.Helper @@ -213,6 +218,7 @@ mousePressed = false; robot.keyPress(keyTypes[j]); + robot.waitForIdle(); robot.mousePress(buttonTypes[i]); if (! mousePressed) { diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/Window/ChangeWindowResizabilty/ChangeWindowResizabiltyTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Window/ChangeWindowResizabilty/ChangeWindowResizabiltyTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @key headful + @bug 8166897 + @summary Some font overlap in the Optionpane dialog. + @run main ChangeWindowResizabiltyTest +*/ + +import java.awt.Component; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Robot; + +public class ChangeWindowResizabiltyTest { + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + for(int i = 0; i < 10; i++) { + Dialog dialog = new Dialog((Frame) null); + Component panel = new Panel(); + panel.setPreferredSize(new Dimension(200, 100)); + dialog.add(panel); + dialog.pack(); + dialog.setVisible(true); + + dialog.setResizable(false); + robot.waitForIdle(); + robot.delay(200); + + System.out.println(panel.getLocationOnScreen()); + System.out.println(dialog.getLocationOnScreen()); + if (panel.getLocationOnScreen().y < + dialog.getLocationOnScreen().y + dialog.getInsets().top) { + dialog.dispose(); + throw new RuntimeException( + "Wrong content position after setResizable(false)"); + } + + dialog.setResizable(true); + robot.waitForIdle(); + robot.delay(200); + System.out.println(panel.getLocationOnScreen()); + System.out.println(dialog.getLocationOnScreen()); + if (panel.getLocationOnScreen().y < + dialog.getLocationOnScreen().y + dialog.getInsets().top) { + dialog.dispose(); + throw new RuntimeException( + "Wrong content position after setResizable(true)"); + } + + dialog.dispose(); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/event/KeyEvent/RobotCrash/RobotCrash.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/event/KeyEvent/RobotCrash/RobotCrash.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @key headful + * @bug 8165555 + * @summary VM crash after creating Robot second time and accessing key codes in + * single JVM mode. + * @run main RobotCrash + */ +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import javax.swing.SwingUtilities; + +public class RobotCrash implements Runnable { + + private Frame frame; + + public void robotKeyPressTest() throws Exception { + + SwingUtilities.invokeAndWait(() -> { + frame = new Frame(); + frame.setSize(300, 300); + frame.setVisible(true); + }); + + Robot robot = new Robot(); + robot.waitForIdle(); + Point pt = frame.getLocationOnScreen(); + robot.mouseMove(((int) pt.getX() + frame.getWidth()) / 2, + ((int) pt.getY() + frame.getHeight()) / 2); + robot.waitForIdle(); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.waitForIdle(); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_ENTER); + robot.waitForIdle(); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(() -> { + frame.dispose(); + }); + } + + @Override + public void run() { + try { + robotKeyPressTest(); + } catch (Exception e) { + throw new RuntimeException("Test Failed" + e.getMessage()); + } + } + + public static void main(String[] args) throws Exception { + + for (int i = 0; i < 10; i++) { + Thread t1 = new Thread(new RobotCrash()); + t1.start(); + t1.join(); + Thread t2 = new Thread(new RobotCrash()); + t2.start(); + t2.join(); + Thread.sleep(1000); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/jdk/TestJDKAWTUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/jdk/TestJDKAWTUtils.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8167126 + */ +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.Rectangle; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +public class TestJDKAWTUtils { + + static JFrame f; + public static void main(String[] args) throws Exception { + + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("test"); + JPanel p = new JPanel(); + JButton b = new JButton("Hello"); + b.setFont(new Font(Font.DIALOG, Font.PLAIN, 80)); + p.setLayout(new BorderLayout()); + p.add("Center", b); + f.getContentPane().add(p); + f.pack(); + f.setVisible(true); + Rectangle r = new Rectangle(0, 0, 50, 50); + jdk.awt.AWTUtils.setComponentMixingCutoutShape(b, r); + }); + Thread.sleep(2000); + SwingUtilities.invokeAndWait(() -> f.dispose()); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/print/PrinterJob/LinearGradientPrintingTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/print/PrinterJob/LinearGradientPrintingTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * @test + * @bug 8162796 + * @summary Verifies if LinearGradientPaint is printed in osx + * @run main/manual LinearGradientPrintingTest + */ +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.LinearGradientPaint; +import java.awt.Shape; +import java.awt.event.ActionEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +public class LinearGradientPrintingTest extends Component implements Printable { + private static Thread mainThread; + private static boolean testPassed; + private static boolean testGeneratedInterrupt; + private static JFrame f = null; + + public static void main(String[] args) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + //createUI(); + doTest(LinearGradientPrintingTest::createUI); + } + }); + mainThread = Thread.currentThread(); + try { + Thread.sleep(120000); + } catch (InterruptedException e) { + if (!testPassed && testGeneratedInterrupt) { + throw new RuntimeException("LinearGradientPaint did not print"); + } + } + if (!testGeneratedInterrupt) { + throw new RuntimeException("user has not executed the test"); + } + } + + public static void createUI() { + f = new JFrame("LinearGradient Printing Test"); + f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + final LinearGradientPrintingTest gpt = new LinearGradientPrintingTest(); + Container c = f.getContentPane(); + c.add(BorderLayout.CENTER, gpt); + + final JButton print = new JButton("Print"); + print.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + PrinterJob job = PrinterJob.getPrinterJob(); + job.setPrintable(gpt); + final boolean doPrint = job.printDialog(); + if (doPrint) { + try { + job.print(); + } catch (PrinterException ex) { + throw new RuntimeException(ex); + } + } + } + }); + c.add(print, BorderLayout.SOUTH); + + f.pack(); + f.setVisible(true); + } + + public Dimension getPreferredSize() { + return new Dimension(500,500); + } + + public void paint(Graphics g) { + doPaint((Graphics2D)g); + } + + public int print( Graphics graphics, PageFormat format, int index ) { + Graphics2D g2d = (Graphics2D)graphics; + g2d.translate(format.getImageableX(), format.getImageableY()); + doPaint(g2d); + return index == 0 ? PAGE_EXISTS : NO_SUCH_PAGE; + } + + static final float DIM = 100; + public void doPaint(Graphics2D g2d) { + + g2d.translate(DIM*0.2, DIM*0.2); + Shape s = new Rectangle2D.Float(0, 0, DIM*2, DIM*2); + Point2D.Double p1 = new Point2D.Double(0.0, 0.0); + Point2D.Double p2 = new Point2D.Double(DIM/2.0, DIM/2.0); + + // LinearGradientPaint + //g2d.translate(DIM*2.2, 0); + Color colors[] = { Color.red, Color.blue} ; + float fractions[] = { 0.0f, 1.0f }; + + LinearGradientPaint lgp = + new LinearGradientPaint(p1, p2, fractions, colors, + LinearGradientPaint.CycleMethod.NO_CYCLE); + g2d.setPaint(lgp); + g2d.fill(s); + + g2d.translate(DIM*2.2, 0); + Color colors1[] = { Color.red, Color.blue, Color.green, Color.white} ; + float fractions1[] = { 0.0f, 0.3f, 0.6f, 1.0f }; + + LinearGradientPaint lgp1 = + new LinearGradientPaint(p1, p2, fractions1, colors1, + LinearGradientPaint.CycleMethod.REFLECT); + g2d.setPaint(lgp1); + g2d.fill(s); + + g2d.translate(-DIM*2.2, DIM*2.2); + Color colors2[] = { Color.red, Color.blue, Color.green, Color.white} ; + float fractions2[] = { 0.0f, 0.3f, 0.6f, 1.0f }; + + LinearGradientPaint lgp2 = + new LinearGradientPaint(p1, p2, fractions2, colors2, + LinearGradientPaint.CycleMethod.REPEAT); + g2d.setPaint(lgp2); + g2d.fill(s); + } + + public static synchronized void pass() { + testPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } + + public static synchronized void fail() { + testPassed = false; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } + + private static void doTest(Runnable action) { + String description + = " A LinearGradientPaint graphics will be shown on console.\n" + + " The same graphics is sent to printer.\n" + + " Please verify if LinearGradientPaint shading is printed.\n" + + " If none is printed, press FAIL else press PASS"; + + final JDialog dialog = new JDialog(); + dialog.setTitle("printSelectionTest"); + JTextArea textArea = new JTextArea(description); + textArea.setEditable(false); + final JButton testButton = new JButton("Start Test"); + final JButton passButton = new JButton("PASS"); + passButton.setEnabled(false); + passButton.addActionListener((e) -> { + f.dispose(); + dialog.dispose(); + pass(); + }); + final JButton failButton = new JButton("FAIL"); + failButton.setEnabled(false); + failButton.addActionListener((e) -> { + f.dispose(); + dialog.dispose(); + fail(); + }); + testButton.addActionListener((e) -> { + testButton.setEnabled(false); + action.run(); + passButton.setEnabled(true); + failButton.setEnabled(true); + }); + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(textArea, BorderLayout.CENTER); + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(testButton); + buttonPanel.add(passButton); + buttonPanel.add(failButton); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + dialog.add(mainPanel); + + dialog.pack(); + dialog.setVisible(true); + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + System.out.println("main dialog closing"); + testGeneratedInterrupt = false; + mainThread.interrupt(); + } + }); + } + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/print/PrinterJob/RadialGradientPrintingTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/print/PrinterJob/RadialGradientPrintingTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * @test + * @bug 8162796 + * @summary Verifies if RadialGradientPaint is printed in osx + * @run main/manual RadialGradientPrintingTest + */ +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RadialGradientPaint; +import java.awt.Shape; +import java.awt.event.ActionEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import static java.awt.print.Printable.NO_SUCH_PAGE; +import static java.awt.print.Printable.PAGE_EXISTS; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +public class RadialGradientPrintingTest extends Component implements Printable { + private static Thread mainThread; + private static boolean testPassed; + private static boolean testGeneratedInterrupt; + private static JFrame f = null; + + public static void main(String[] args) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + //createUI(); + doTest(RadialGradientPrintingTest::createUI); + } + }); + mainThread = Thread.currentThread(); + try { + Thread.sleep(120000); + } catch (InterruptedException e) { + if (!testPassed && testGeneratedInterrupt) { + throw new RuntimeException("LinearGradientPaint did not print"); + } + } + if (!testGeneratedInterrupt) { + throw new RuntimeException("user has not executed the test"); + } + } + + public static void createUI() { + f = new JFrame("RadialGradient Printing Test"); + f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + final RadialGradientPrintingTest gpt = new RadialGradientPrintingTest(); + Container c = f.getContentPane(); + c.add(BorderLayout.CENTER, gpt); + + final JButton print = new JButton("Print"); + print.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + PrinterJob job = PrinterJob.getPrinterJob(); + job.setPrintable(gpt); + final boolean doPrint = job.printDialog(); + if (doPrint) { + try { + job.print(); + } catch (PrinterException ex) { + throw new RuntimeException(ex); + } + } + } + }); + c.add(print, BorderLayout.SOUTH); + + f.pack(); + f.setVisible(true); + } + + public Dimension getPreferredSize() { + return new Dimension(500,500); + } + + public void paint(Graphics g) { + doPaint((Graphics2D)g); + } + + public int print( Graphics graphics, PageFormat format, int index ) { + Graphics2D g2d = (Graphics2D)graphics; + g2d.translate(format.getImageableX(), format.getImageableY()); + doPaint(g2d); + return index == 0 ? PAGE_EXISTS : NO_SUCH_PAGE; + } + + static final float DIM = 100; + public void doPaint(Graphics2D g2d) { + + g2d.translate(DIM*0.2, DIM*0.2); + Shape s = new Rectangle2D.Float(0, 0, DIM*2, DIM*2); + + // RadialGradientPaint + Point2D centre = new Point2D.Float(DIM/2.0f, DIM/2.0f); + float radius = DIM/2.0f; + Point2D focus = new Point2D.Float(DIM/3.0f, DIM/3.0f); + float stops[] = {0.0f, 1.0f}; + Color colors[] = { Color.red, Color.white} ; + + RadialGradientPaint rgp = + new RadialGradientPaint(centre, radius, focus, stops, colors, + RadialGradientPaint.CycleMethod.NO_CYCLE); + g2d.setPaint(rgp); + g2d.fill(s); + + g2d.translate(DIM*2.2, 0); + Color colors1[] = { Color.red, Color.blue, Color.green} ; + float stops1[] = {0.0f, 0.5f, 1.0f}; + RadialGradientPaint rgp1 = + new RadialGradientPaint(centre, radius, focus, stops1, colors1, + RadialGradientPaint.CycleMethod.REFLECT); + g2d.setPaint(rgp1); + g2d.fill(s); + + g2d.translate(-DIM*2.2, DIM*2.2); + Color colors2[] = { Color.red, Color.blue, Color.green, Color.white} ; + float stops2[] = {0.0f, 0.3f, 0.6f, 1.0f}; + RadialGradientPaint rgp2 = + new RadialGradientPaint(centre, radius, focus, stops2, colors2, + RadialGradientPaint.CycleMethod.REPEAT); + g2d.setPaint(rgp2); + g2d.fill(s); + + } + + public static synchronized void pass() { + testPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } + + public static synchronized void fail() { + testPassed = false; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } + + private static void doTest(Runnable action) { + String description + = " A RadialGradientPaint graphics will be shown on console.\n" + + " The same graphics is sent to printer.\n" + + " Please verify if RadialGradientPaint shading is printed.\n" + + " If none is printed, press FAIL else press PASS"; + + final JDialog dialog = new JDialog(); + dialog.setTitle("printSelectionTest"); + JTextArea textArea = new JTextArea(description); + textArea.setEditable(false); + final JButton testButton = new JButton("Start Test"); + final JButton passButton = new JButton("PASS"); + passButton.setEnabled(false); + passButton.addActionListener((e) -> { + f.dispose(); + dialog.dispose(); + pass(); + }); + final JButton failButton = new JButton("FAIL"); + failButton.setEnabled(false); + failButton.addActionListener((e) -> { + f.dispose(); + dialog.dispose(); + fail(); + }); + testButton.addActionListener((e) -> { + testButton.setEnabled(false); + action.run(); + passButton.setEnabled(true); + failButton.setEnabled(true); + }); + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(textArea, BorderLayout.CENTER); + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(testButton); + buttonPanel.add(passButton); + buttonPanel.add(failButton); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + dialog.add(mainPanel); + + dialog.pack(); + dialog.setVisible(true); + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + System.out.println("main dialog closing"); + testGeneratedInterrupt = false; + mainThread.interrupt(); + } + }); + } + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/awt/security/WarningWindowDisposeTest/WarningWindowDisposeTest.java --- a/jdk/test/java/awt/security/WarningWindowDisposeTest/WarningWindowDisposeTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/awt/security/WarningWindowDisposeTest/WarningWindowDisposeTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. 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 @@ -23,9 +23,9 @@ /* @test - @bug 8037776 + @key headful + @bug 8037776 8167288 @summary tests that the WarningWindow is properly disposed - @author Petr Pchelko @library ../../regtesthelpers/process @build ProcessResults ProcessCommunicator @run main WarningWindowDisposeTest @@ -45,13 +45,17 @@ public static void main(String[] args) { final AtomicBoolean passed = new AtomicBoolean(false); new Thread(() -> { - try { - Thread.sleep(5000); - } catch (InterruptedException e) { - throw new RuntimeException("Test FAILED!", e); - } - if (!passed.get()) { - throw new RuntimeException("Test FAILED! The child process never exits"); + for (int trial = 0; trial < 5; ++trial) { + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + throw new RuntimeException("Test FAILED!", e); + } + if (passed.get()) { + break; + } else if (trial == 4) { + throw new RuntimeException("Child process never exits"); + } } }, "TimeoutThread").start(); diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/io/FilePermission/FilePermissionCollectionMerge.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/FilePermission/FilePermissionCollectionMerge.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * + * @test + * @bug 8168127 + * @summary FilePermissionCollection merges incorrectly + * @modules java.base/sun.security.util + * @library /test/lib + */ + +import sun.security.util.FilePermCompat; +import java.io.FilePermission; +import java.security.Permissions; +import jdk.test.lib.Asserts; + +public class FilePermissionCollectionMerge { + + public static void main(String[] args) throws Exception { + test("x"); + test("x/*"); + test("x/-"); + test("*"); + test("-"); + test("/x"); + test("/x/*"); + test("/x/-"); + } + + static void test(String arg) { + + FilePermission fp1 = new FilePermission(arg, "read"); + FilePermission fp2 = (FilePermission) + FilePermCompat.newPermUsingAltPath(fp1); + FilePermission fp3 = (FilePermission) + FilePermCompat.newPermPlusAltPath(fp1); + + // All 3 are different + Asserts.assertNE(fp1, fp2); + Asserts.assertNE(fp1.hashCode(), fp2.hashCode()); + + Asserts.assertNE(fp1, fp3); + Asserts.assertNE(fp1.hashCode(), fp3.hashCode()); + + Asserts.assertNE(fp2, fp3); + Asserts.assertNE(fp2.hashCode(), fp3.hashCode()); + + // The plus one implies the other 2 + Asserts.assertTrue(fp3.implies(fp1)); + Asserts.assertTrue(fp3.implies(fp2)); + + // The using one different from original + Asserts.assertFalse(fp2.implies(fp1)); + Asserts.assertFalse(fp1.implies(fp2)); + + // FilePermssionCollection::implies always works + testMerge(fp1); + testMerge(fp2); + testMerge(fp3); + testMerge(fp1, fp2); + testMerge(fp1, fp3); + testMerge(fp2, fp1); + testMerge(fp2, fp3); + testMerge(fp3, fp1); + testMerge(fp3, fp2); + testMerge(fp1, fp2, fp3); + testMerge(fp2, fp3, fp1); + testMerge(fp3, fp1, fp2); + } + + // Add all into a collection, and check if it implies the last one. + static void testMerge(FilePermission... fps) { + java.security.Permissions perms = new Permissions(); + FilePermission last = null; + for (FilePermission fp : fps) { + perms.add(fp); + last = fp; + } + Asserts.assertTrue(perms.implies(last)); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/io/FilePermission/Invalid.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/FilePermission/Invalid.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * + * @test + * @bug 8167646 + * @summary Better invalid FilePermission + * @library /test/lib + */ + +import jdk.test.lib.Asserts; + +import java.io.FilePermission; + +public class Invalid { + + public static void main(String args[]) throws Exception { + + // Normal + FilePermission fp = new FilePermission("a", "read"); + + // Invalid + FilePermission fp1 = new FilePermission("a\000", "read"); + FilePermission fp2 = new FilePermission("a\000", "read"); + FilePermission fp3 = new FilePermission("b\000", "read"); + + // Invalid equals to itself + Asserts.assertEQ(fp1, fp1); + + // and not equals to anything else, including other invalid ones + Asserts.assertNE(fp, fp1); + Asserts.assertNE(fp1, fp); + Asserts.assertNE(fp1, fp2); + Asserts.assertNE(fp1, fp3); + + // Invalid implies itself + Asserts.assertTrue(fp1.implies(fp1)); + + // and not implies or implied by anything else, including other + // invalid ones + Asserts.assertFalse(fp.implies(fp1)); + Asserts.assertFalse(fp1.implies(fp)); + Asserts.assertFalse(fp1.implies(fp2)); + Asserts.assertFalse(fp1.implies(fp3)); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/io/Serializable/serialFilter/SerialFilterTest.java --- a/jdk/test/java/io/Serializable/serialFilter/SerialFilterTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/io/Serializable/serialFilter/SerialFilterTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -40,7 +40,7 @@ import java.util.Set; import java.util.concurrent.atomic.LongAdder; -import javax.lang.model.SourceVersion; +import javax.net.ssl.SSLEngineResult; import org.testng.Assert; import org.testng.annotations.Test; @@ -82,8 +82,8 @@ Object[][] patterns = new Object[][]{ {"java.util.Hashtable"}, {"java.util.Hash*"}, - {"javax.lang.model.*"}, - {"javax.lang.**"}, + {"javax.net.ssl.*"}, + {"javax.net.**"}, {"*"}, {"maxarray=47"}, {"maxdepth=5"}, @@ -543,20 +543,20 @@ static Object genTestObjectWildcard(String pattern, boolean allowed) { if (pattern.endsWith(".**")) { // package hierarchy wildcard - if (pattern.startsWith("javax.lang.")) { - return SourceVersion.RELEASE_5; + if (pattern.startsWith("javax.net.")) { + return SSLEngineResult.Status.BUFFER_OVERFLOW; } if (pattern.startsWith("java.")) { return 4; } if (pattern.startsWith("javax.")) { - return SourceVersion.RELEASE_6; + return SSLEngineResult.Status.BUFFER_UNDERFLOW; } return otherObject; } else if (pattern.endsWith(".*")) { // package wildcard - if (pattern.startsWith("javax.lang.model")) { - return SourceVersion.RELEASE_6; + if (pattern.startsWith("javax.net.ssl")) { + return SSLEngineResult.Status.BUFFER_UNDERFLOW; } } else { // class wildcard diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/ClassLoader/IsParallelCapable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/ClassLoader/IsParallelCapable.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8165793 + * @summary Test ClassLoader.isParallelCapable() method + * @run main IsParallelCapable + */ + +import java.util.stream.Stream; + +public class IsParallelCapable { + public abstract static class TestCL extends ClassLoader { + static { + ClassLoader.registerAsParallelCapable(); + } + public abstract boolean expectCapable(); + public Class findClass(String name) throws ClassNotFoundException { + throw new ClassNotFoundException("Why are you using this?"); + } + } + + public static class ParaCL extends TestCL { + static { + ClassLoader.registerAsParallelCapable(); + } + @Override + public boolean expectCapable() { return true; } + } + + public static class NonParaCL extends TestCL { + @Override + public boolean expectCapable() { + // Doesn't call registerAsParallelCapable() + return false; + } + } + + public static class NonParaSubCL1 extends ParaCL { + @Override + public boolean expectCapable() { + // Doesn't call registerAsParallelCapable() + return false; + } + } + + public static class NonParaSubCL2 extends NonParaCL { + static { + ClassLoader.registerAsParallelCapable(); + } + @Override + public boolean expectCapable() { + // Superclass is not parallel capable + return false; + } + } + + public static class ParaSubCL extends ParaCL { + static { + ClassLoader.registerAsParallelCapable(); + } + @Override + public boolean expectCapable() { return true; } + } + + public static void main(String[] args) throws Exception { + if (!ClassLoader.getSystemClassLoader().isParallelCapable()) { + throw new RuntimeException("System classloader not parallel capable!?"); + } + + Stream.of(ParaCL.class, + NonParaCL.class, + NonParaSubCL1.class, + NonParaSubCL2.class, + ParaSubCL.class) + .forEach(IsParallelCapable::testClassLoaderClass); + } + + private static void testClassLoaderClass(Class klazz) { + try { + TestCL cl = (TestCL)klazz.newInstance(); + if (cl.expectCapable() != cl.isParallelCapable()) { + throw new RuntimeException(klazz + " expectCapable: " + + cl.expectCapable() + ", isParallelCapable: " + + cl.isParallelCapable()); + } else { + System.out.println(klazz + " passed"); + } + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/ClassLoader/platformClassLoader/DefinePlatformClass.java --- a/jdk/test/java/lang/ClassLoader/platformClassLoader/DefinePlatformClass.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/lang/ClassLoader/platformClassLoader/DefinePlatformClass.java Fri Nov 11 16:44:36 2016 +0100 @@ -24,8 +24,9 @@ /* * @test * @summary Test java.* class defined by the platform class loader - * @build jdk.zipfs/java.fake.Fake * @modules jdk.zipfs/java.fake + * @build jdk.zipfs/java.fake.Fake + * @compile --add-modules jdk.zipfs DefinePlatformClass.java * @run main DefinePlatformClass */ diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/ProcessBuilder/Basic.java --- a/jdk/test/java/lang/ProcessBuilder/Basic.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/lang/ProcessBuilder/Basic.java Fri Nov 11 16:44:36 2016 +0100 @@ -2404,16 +2404,6 @@ fail("Test failed: waitFor didn't take long enough (" + (end - start) + "ns)"); p.destroy(); - - start = System.nanoTime(); - p.waitFor(8, TimeUnit.SECONDS); - end = System.nanoTime(); - - int exitValue = p.exitValue(); - - if ((end - start) > TimeUnit.SECONDS.toNanos(7)) - fail("Test failed: waitFor took too long on a dead process. (" + (end - start) + "ns)" - + ", exitValue: " + exitValue); } catch (Throwable t) { unexpected(t); } //---------------------------------------------------------------- diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/StackTraceElement/PublicConstructor.java --- a/jdk/test/java/lang/StackTraceElement/PublicConstructor.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/lang/StackTraceElement/PublicConstructor.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 @@ -23,43 +23,74 @@ /* * @test - * @bug 4712607 + * @bug 4712607 6479237 * @summary Basic test for StackTraceElementPublic constructor * @author Josh Bloch */ -import java.util.*; +import java.lang.module.ModuleDescriptor; +import java.lang.reflect.Module; public class PublicConstructor { - public static void main(String args[]) { + public static void main(String... args) { + testConstructor(); + testConstructorWithModule(); + } + + static void testConstructor() { StackTraceElement ste = new StackTraceElement("com.acme.Widget", - "frobnicate", "Widget.java", 42); + "frobnicate", + "Widget.java", 42); if (!(ste.getClassName().equals("com.acme.Widget") && - ste.getFileName().equals("Widget.java") && - ste.getMethodName().equals("frobnicate") && - ste.getLineNumber() == 42)) + ste.getFileName().equals("Widget.java") && + ste.getMethodName().equals("frobnicate") && + ste.getLineNumber() == 42)) throw new RuntimeException("1"); + if (ste.isNativeMethod()) throw new RuntimeException("2"); - StackTraceElement ste2 - = new StackTraceElement("jdk.module", - "9.0", - "com.acme.Widget", - "frobnicate", - "Widget.java", - 42); - if (!(ste2.getClassName().equals("com.acme.Widget") && - ste2.getModuleName().equals("jdk.module") && - ste2.getModuleVersion().equals("9.0") && - ste2.getFileName().equals("Widget.java") && - ste2.getMethodName().equals("frobnicate") && - ste2.getLineNumber() == 42)) + + assertEquals(ste.toString(), + "com.acme.Widget.frobnicate(Widget.java:42)"); + + StackTraceElement ste1 = new StackTraceElement("com.acme.Widget", + "frobnicate", + "Widget.java", + -2); + if (!ste1.isNativeMethod()) throw new RuntimeException("3"); - if (ste2.isNativeMethod()) + + assertEquals(ste1.toString(), + "com.acme.Widget.frobnicate(Native Method)"); + } + + static void testConstructorWithModule() { + StackTraceElement ste = new StackTraceElement("app", + "jdk.module", + "9.0", + "com.acme.Widget", + "frobnicate", + "Widget.java", + 42); + if (!(ste.getClassName().equals("com.acme.Widget") && + ste.getModuleName().equals("jdk.module") && + ste.getModuleVersion().equals("9.0") && + ste.getClassLoaderName().equals("app") && + ste.getFileName().equals("Widget.java") && + ste.getMethodName().equals("frobnicate") && + ste.getLineNumber() == 42)) + throw new RuntimeException("3"); + + if (ste.isNativeMethod()) throw new RuntimeException("4"); - StackTraceElement ste3 = new StackTraceElement("com.acme.Widget", - "frobnicate", "Widget.java", -2); - if (!ste3.isNativeMethod()) - throw new RuntimeException("5"); + + assertEquals(ste.toString(), + "app/jdk.module@9.0/com.acme.Widget.frobnicate(Widget.java:42)"); + } + + static void assertEquals(String s, String expected) { + if (!s.equals(expected)) { + throw new RuntimeException("Expected: " + expected + " but found: " + s); + } } } diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/StackTraceElement/SerialTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/StackTraceElement/SerialTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6479237 + * @summary Test the format of StackTraceElement::toString and its serial form + * @modules java.logging + * java.xml.bind + * @run main SerialTest + */ + +import javax.xml.bind.JAXBElement; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.logging.Logger; + +public class SerialTest { + private static final Path SER_DIR = Paths.get("sers"); + private static final String JAVA_BASE = "java.base"; + private static final String JAVA_LOGGING = "java.logging"; + private static final String JAVA_XML_BIND = "java.xml.bind"; + + private static boolean isImage; + + public static void main(String... args) throws Exception { + Files.createDirectories(SER_DIR); + + // detect if exploded image build + Path home = Paths.get(System.getProperty("java.home")); + isImage = Files.exists(home.resolve("lib").resolve("modules")); + + // test stack trace from built-in loaders + try { + Logger.getLogger(null); + } catch (NullPointerException e) { + Arrays.stream(e.getStackTrace()) + .filter(ste -> ste.getClassName().startsWith("java.util.logging.") || + ste.getClassName().equals("SerialTest")) + .forEach(SerialTest::test); + } + + // test stack trace with upgradeable module + try { + new JAXBElement(null, null, null); + } catch (IllegalArgumentException e) { + Arrays.stream(e.getStackTrace()) + .filter(ste -> ste.getModuleName() != null) + .forEach(SerialTest::test); + } + + // test stack trace with class loader name from other class loader + Loader loader = new Loader("myloader"); + Class cls = Class.forName("SerialTest", true, loader); + Method method = cls.getMethod("throwException"); + StackTraceElement ste = (StackTraceElement)method.invoke(null); + test(ste, loader); + + // verify the class loader name and in the stack trace + if (!cls.getClassLoader().getName().equals("myloader.hacked")) { + throw new RuntimeException("Unexpected loader name: " + + cls.getClassLoader().getName()); + } + if (!ste.getClassLoaderName().equals("myloader")) { + throw new RuntimeException("Unexpected loader name: " + + ste.getClassLoaderName()); + } + } + + private static void test(StackTraceElement ste) { + test(ste, null); + } + + private static void test(StackTraceElement ste, ClassLoader loader) { + try { + SerialTest serialTest = new SerialTest(ste); + StackTraceElement ste2 = serialTest.serialize().deserialize(); + System.out.println(ste2); + // verify StackTraceElement::toString returns the same string + if (!ste.equals(ste2) || !ste.toString().equals(ste2.toString())) { + throw new RuntimeException(ste + " != " + ste2); + } + + String mn = ste.getModuleName(); + if (mn != null) { + switch (mn) { + case JAVA_BASE: + case JAVA_LOGGING: + checkNamedModule(ste, loader, false); + break; + case JAVA_XML_BIND: + // for exploded build, no version is shown + checkNamedModule(ste, loader, isImage); + break; + default: // ignore + } + } else { + checkUnnamedModule(ste, loader); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private static void checkUnnamedModule(StackTraceElement ste, ClassLoader loader) { + String mn = ste.getModuleName(); + String s = ste.toString(); + int i = s.indexOf('/'); + + if (mn != null) { + throw new RuntimeException("expected null but got " + mn); + } + + if (loader != null) { + // Expect //.(:) + if (i <= 0) { + throw new RuntimeException("loader name missing: " + s); + } + if (!getLoaderName(loader).equals(s.substring(0, i))) { + throw new RuntimeException("unexpected loader name: " + s); + } + int j = s.substring(i+1).indexOf('/'); + if (j != 0) { + throw new RuntimeException("unexpected element for unnamed module: " + s); + } + } + } + + /* + * Loader::getName is overridden to return some other name + */ + private static String getLoaderName(ClassLoader loader) { + if (loader == null) + return ""; + + if (loader instanceof Loader) { + return ((Loader) loader).name; + } else { + return loader.getName(); + } + } + + private static void checkNamedModule(StackTraceElement ste, + ClassLoader loader, + boolean showVersion) { + String loaderName = getLoaderName(loader); + String mn = ste.getModuleName(); + String s = ste.toString(); + int i = s.indexOf('/'); + + if (mn == null) { + throw new RuntimeException("expected module name: " + s); + } + + if (i <= 0) { + throw new RuntimeException("module name missing: " + s); + } + + // Expect /.(:) + if (!loaderName.isEmpty()) { + throw new IllegalArgumentException(loaderName); + } + + // : name@version + int j = s.indexOf('@'); + if ((showVersion && j <= 0) || (!showVersion && j >= 0)) { + throw new RuntimeException("unexpected version: " + s); + } + + String name = j < 0 ? s.substring(0, i) : s.substring(0, j); + if (!name.equals(mn)) { + throw new RuntimeException("unexpected module name: " + s); + } + } + + private final Path ser; + private final StackTraceElement ste; + SerialTest(StackTraceElement ste) throws IOException { + this.ser = Files.createTempFile(SER_DIR, "SerialTest", ".ser"); + this.ste = ste; + } + + private StackTraceElement deserialize() throws IOException { + try (InputStream in = Files.newInputStream(ser); + BufferedInputStream bis = new BufferedInputStream(in); + ObjectInputStream ois = new ObjectInputStream(bis)) { + return (StackTraceElement)ois.readObject(); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + private SerialTest serialize() throws IOException { + try (OutputStream out = Files.newOutputStream(ser); + BufferedOutputStream bos = new BufferedOutputStream(out); + ObjectOutputStream oos = new ObjectOutputStream(bos)) { + oos.writeObject(ste); + } + return this; + } + + + public static StackTraceElement throwException() { + try { + Integer.parseInt(null); + } catch (NumberFormatException e) { + return Arrays.stream(e.getStackTrace()) + .filter(ste -> ste.getMethodName().equals("throwException")) + .findFirst().get(); + } + return null; + } + + public static class Loader extends URLClassLoader { + final String name; + Loader(String name) throws MalformedURLException { + super(name, new URL[] { testClassesURL() } , null); + this.name = name; + } + + private static URL testClassesURL() throws MalformedURLException { + Path path = Paths.get(System.getProperty("test.classes")); + return path.toUri().toURL(); + } + + public String getName() { + return name + ".hacked"; + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/StackTraceElement/WithClassLoaderName.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/StackTraceElement/WithClassLoaderName.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6479237 + * @summary Basic test StackTraceElement with class loader names + * @library lib /lib/testlibrary + * @build m1/* WithClassLoaderName + * @run main/othervm m1/com.app.Main + * @run main/othervm WithClassLoaderName + */ + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.nio.file.Paths; + +import com.app.Utils; + +public class WithClassLoaderName { + private static final String TEST_SRC = System.getProperty("test.src"); + private static final String SRC_FILENAME = "WithClassLoaderName.java"; + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path CLASSES_DIR = Paths.get("classes"); + private static final String THROW_EXCEPTION_CLASS = "p.ThrowException"; + + public static void main(String... args) throws Exception { + /* + * Test the following frames both have the same class loader name "app" + * com.app.Test::test + * WithClassLoaderName::test + */ + Utils.verify(WithClassLoaderName.class, "app", "main", SRC_FILENAME); + + /* + * Test StackTraceElement for a class loaded by a named URLClassLoader + */ + compile(); + testURLClassLoader("myloader"); + + // loader name same as application class loader + testURLClassLoader("app"); + } + + private static void compile() throws Exception { + boolean rc = CompilerUtils.compile(SRC_DIR, CLASSES_DIR); + if (!rc) { + throw new RuntimeException("compilation fails"); + } + } + + public static void testURLClassLoader(String loaderName) throws Exception { + System.err.println("---- test URLClassLoader name: " + loaderName); + + URL[] urls = new URL[] { CLASSES_DIR.toUri().toURL() }; + ClassLoader parent = ClassLoader.getSystemClassLoader(); + URLClassLoader loader = new URLClassLoader(loaderName, urls, parent); + + Class c = Class.forName(THROW_EXCEPTION_CLASS, true, loader); + Method method = c.getMethod("throwError"); + try { + // invoke p.ThrowException::throwError + method.invoke(null); + } catch (InvocationTargetException x) { + Throwable e = x.getCause(); + e.printStackTrace(); + + StackTraceElement[] stes = e.getStackTrace(); + StackWalker.StackFrame[] frames = new StackWalker.StackFrame[] { + Utils.makeStackFrame(c, "throwError", "ThrowException.java"), + Utils.makeStackFrame(WithClassLoaderName.class, "testURLClassLoader", + SRC_FILENAME), + Utils.makeStackFrame(WithClassLoaderName.class, "main", SRC_FILENAME), + }; + + // p.ThrowException.throwError + Utils.checkFrame(loaderName, frames[0], stes[0]); + // skip reflection frames + int i = 1; + while (i < stes.length) { + String cn = stes[i].getClassName(); + if (!cn.startsWith("java.lang.reflect.") && + !cn.startsWith("jdk.internal.reflect.")) + break; + i++; + } + // WithClassLoaderName.testURLClassLoader + Utils.checkFrame("app", frames[1], stes[i]); + + // WithClassLoaderName.main + Utils.checkFrame("app", frames[2], stes[i+1]); + + } + } + +} + diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/StackTraceElement/lib/m1/com/app/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/StackTraceElement/lib/m1/com/app/Main.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.app; + +import java.lang.StackWalker.StackFrame; + +public class Main { + public static void main(String... args) throws Exception { + StackFrame frame = Utils.makeStackFrame(Main.class, "main", "Main.java"); + Utils.checkFrame("app", frame, caller()); + } + + private static StackTraceElement caller() { + StackTraceElement[] stes = Thread.currentThread().getStackTrace(); + return stes[2]; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/StackTraceElement/lib/m1/com/app/Utils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/StackTraceElement/lib/m1/com/app/Utils.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.app; + +import java.lang.StackWalker.StackFrame; +import java.lang.module.ModuleDescriptor; +import java.lang.reflect.Module; +import java.util.Objects; + +public class Utils { + public static void verify(Class caller, String loaderName, + String methodname, String filename) { + StackTraceElement[] stes = Thread.currentThread().getStackTrace(); + StackWalker.StackFrame[] frames = new StackFrame[] { + makeStackFrame(Utils.class, "verify", "Utils.java"), + makeStackFrame(caller, methodname, filename) + }; + + checkFrame("app", frames[0], stes[1]); + checkFrame(loaderName, frames[1], stes[2]); + } + + public static StackFrame makeStackFrame(Class c, String methodname, String filename) { + return new StackFrame() { + @Override + public String getClassName() { + return c.getName(); + } + @Override + public String getMethodName() { + return methodname; + } + @Override + public Class getDeclaringClass() { + return c; + } + @Override + public int getByteCodeIndex() { + return 0; + } + @Override + public String getFileName() { + return filename; + } + + @Override + public int getLineNumber() { + return 0; + } + @Override + public boolean isNativeMethod() { + return false; + } + @Override + public StackTraceElement toStackTraceElement() { + return null; + } + + private String getClassLoaderName(Class c) { + ClassLoader loader = c.getClassLoader(); + String name = ""; + if (loader == null) { + name = "boot"; + } else if (loader.getName() != null) { + name = loader.getName(); + } + return name; + } + + @Override + public String toString() { + String mid = getClassLoaderName(c); + Module module = c.getModule(); + if (module.isNamed()) { + ModuleDescriptor md = module.getDescriptor(); + mid = md.name(); + if (md.version().isPresent()) + mid += "@" + md.version().get().toString(); + mid += "/"; + } + String fileName = getFileName(); + int lineNumber = getLineNumber(); + String sourceinfo = "Unknown Source"; + if (isNativeMethod()) { + sourceinfo = "Native Method"; + } else if (fileName != null && lineNumber >= 0) { + sourceinfo = fileName + ":" + lineNumber; + } + return String.format("%s/%s.%s(%s)", mid, getClassName(), getMethodName(), + sourceinfo); + + } + }; + } + + public static void checkFrame(String loaderName, StackFrame frame, + StackTraceElement ste) { + System.err.println("checking " + ste.toString() + " expected: " + frame.toString()); + Class c = frame.getDeclaringClass(); + Module module = c.getModule(); + assertEquals(ste.getModuleName(), module.getName(), "module name"); + assertEquals(ste.getClassLoaderName(), loaderName, "class loader name"); + assertEquals(ste.getClassLoaderName(), c.getClassLoader().getName(), + "class loader name"); + assertEquals(ste.getClassName(), c.getName(), "class name"); + assertEquals(ste.getMethodName(), frame.getMethodName(), "method name"); + assertEquals(ste.getFileName(), frame.getFileName(), "file name"); + + } + private static void assertEquals(String actual, String expected, String msg) { + if (!Objects.equals(actual, expected)) + throw new AssertionError("Actual: " + actual + " Excepted: " + + expected + " mismatched " + msg); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/StackTraceElement/lib/m1/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/StackTraceElement/lib/m1/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module m1 { + exports com.app; +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/StackTraceElement/src/p/ThrowException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/StackTraceElement/src/p/ThrowException.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +import java.lang.StackWalker.StackFrame; + +public class ThrowException { + public static void throwError() { + throw new Error("testing"); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/StackWalker/VerifyStackTrace.java --- a/jdk/test/java/lang/StackWalker/VerifyStackTrace.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/lang/StackWalker/VerifyStackTrace.java Fri Nov 11 16:44:36 2016 +0100 @@ -71,7 +71,7 @@ "3: VerifyStackTrace$Handle.run(VerifyStackTrace.java:158)\n" + "4: VerifyStackTrace.invoke(VerifyStackTrace.java:188)\n" + "5: VerifyStackTrace$1.run(VerifyStackTrace.java:218)\n" + - "6: java.security.AccessController.doPrivileged(java.base/Native Method)\n" + + "6: java.base/java.security.AccessController.doPrivileged(Native Method)\n" + "7: VerifyStackTrace.test(VerifyStackTrace.java:227)\n" + "8: VerifyStackTrace.main(VerifyStackTrace.java:182)\n"; @@ -100,12 +100,12 @@ "2: VerifyStackTrace$Handle.execute(VerifyStackTrace.java:147)\n" + "3: VerifyStackTrace$Handle.run(VerifyStackTrace.java:160)\n" + "4: VerifyStackTrace.invoke(VerifyStackTrace.java:190)\n" + - "5: jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base/Native Method)\n" + - "6: jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base/NativeMethodAccessorImpl.java:62)\n" + - "7: jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base/DelegatingMethodAccessorImpl.java:43)\n" + - "8: java.lang.reflect.Method.invoke(java.base/Method.java:520)\n" + + "5: java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" + + "6: java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n" + + "7: java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n" + + "8: java.base/java.lang.reflect.Method.invoke(Method.java:520)\n" + "9: VerifyStackTrace$1.run(VerifyStackTrace.java:220)\n" + - "10: java.security.AccessController.doPrivileged(java.base/Native Method)\n" + + "10: java.base/java.security.AccessController.doPrivileged(Native Method)\n" + "11: VerifyStackTrace.test(VerifyStackTrace.java:229)\n" + "12: VerifyStackTrace.main(VerifyStackTrace.java:185)\n"; @@ -133,16 +133,16 @@ "1: VerifyStackTrace.lambda$test$1(VerifyStackTrace.java:213)\n" + "2: VerifyStackTrace$$Lambda$1/662441761.run(Unknown Source)\n" + "3: VerifyStackTrace$Handle.execute(VerifyStackTrace.java:149)\n" + - "4: java.lang.invoke.LambdaForm$DMH/2008017533.invokeVirtual_LL_V(java.base/LambdaForm$DMH)\n" + - "5: java.lang.invoke.LambdaForm$MH/1395089624.invoke_MT(java.base/LambdaForm$MH)\n" + + "4: java.base/java.lang.invoke.LambdaForm$DMH/2008017533.invokeVirtual_LL_V(LambdaForm$DMH)\n" + + "5: java.base/java.lang.invoke.LambdaForm$MH/1395089624.invoke_MT(LambdaForm$MH)\n" + "6: VerifyStackTrace$Handle.run(VerifyStackTrace.java:162)\n" + "7: VerifyStackTrace.invoke(VerifyStackTrace.java:192)\n" + - "8: jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base/Native Method)\n" + - "9: jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base/NativeMethodAccessorImpl.java:62)\n" + - "10: jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base/DelegatingMethodAccessorImpl.java:43)\n" + - "11: java.lang.reflect.Method.invoke(java.base/Method.java:520)\n" + + "8: java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" + + "9: java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n" + + "10: java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n" + + "11: java.base/java.lang.reflect.Method.invoke(Method.java:520)\n" + "12: VerifyStackTrace$1.run(VerifyStackTrace.java:222)\n" + - "13: java.security.AccessController.doPrivileged(java.base/Native Method)\n" + + "13: java.base/java.security.AccessController.doPrivileged(Native Method)\n" + "14: VerifyStackTrace.test(VerifyStackTrace.java:231)\n" + "15: VerifyStackTrace.main(VerifyStackTrace.java:188)\n"; @@ -201,8 +201,6 @@ // out before comparing. We also erase the hash-like names of // synthetic frames introduced by lambdas & method handles return produced.replaceAll(":[1-9][0-9]*\\)", ":00)") - .replaceAll("-internal/", "/").replaceAll("-ea/", "/") - .replaceAll("java.base@(\\d+\\.){0,3}(\\d+)/", "java.base/") .replaceAll("/[0-9]+\\.run", "/xxxxxxxx.run") .replaceAll("/[0-9]+\\.invoke", "/xxxxxxxx.invoke") // LFs may or may not be pre-generated, making frames differ diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * @test 8163162 + * @summary Checks that LazyLoggers are returned for System.Logger instances + * created by modules in the platform class loader. + * @build systempkg.log.SystemLoggerAccessor SystemLoggerInPlatformLoader + * @run main/othervm SystemLoggerInPlatformLoader + * @author danielfuchs + */ +public class SystemLoggerInPlatformLoader { + + static final class PlatformClassLoaderChild extends ClassLoader { + private PlatformClassLoaderChild() { + super(ClassLoader.getPlatformClassLoader()); + } + public Class definePlatformClass(String name) throws IOException { + String testClasses = System.getProperty("test.classes", "./build/classes"); + String fname = name.replace('.', '/').concat(".class"); + try (InputStream is = new FileInputStream(new File(testClasses, fname))) { + byte[] b = is.readAllBytes(); + ClassLoader parent = getParent(); + try { + Method m = ClassLoader.class.getDeclaredMethod("defineClass", + String.class, byte[].class, int.class, int.class); + m.setAccessible(true); + return (Class)m.invoke(parent, name, b, 0, b.length); + } catch (NoSuchMethodException + | IllegalAccessException + | InvocationTargetException ex) { + throw new IOException(ex); + } + } + } + static final PlatformClassLoaderChild INSTANCE = new PlatformClassLoaderChild(); + static Class loadLoggerAccessor() throws IOException { + return INSTANCE.definePlatformClass("systempkg.log.SystemLoggerAccessor"); + } + } + + static final Class LOGGER_ACCESSOR_CLASS; + static { + try { + LOGGER_ACCESSOR_CLASS = PlatformClassLoaderChild.loadLoggerAccessor(); + ClassLoader platformCL = ClassLoader.getPlatformClassLoader(); + if (LOGGER_ACCESSOR_CLASS.getClassLoader() != platformCL) { + throw new ExceptionInInitializerError( + "Could not load accessor class in platform class loader: " + + LOGGER_ACCESSOR_CLASS.getClassLoader()); + } + } catch (IOException ex) { + throw new ExceptionInInitializerError(ex); + } + } + + // Returns a system logger created on behalf of a class loaded by the + // Platform ClassLoader + static System.Logger getSystemLogger(String name) { + try { + return (System.Logger)LOGGER_ACCESSOR_CLASS.getMethod( + "getSystemLogger", String.class).invoke(null, name); + } catch (NoSuchMethodException + | IllegalAccessException + | InvocationTargetException ex) { + throw new RuntimeException("Failed to invoke LoggerAccessor.getJULLogger", ex); + } + } + + public static void main(String[] args) { + System.Logger splogger = getSystemLogger("bar"); // for a platform class + System.Logger slogger = System.getLogger("bar"); // for an application class + if (slogger == splogger) { + throw new RuntimeException("Same loggers"); + } + Class sploggerType = splogger.getClass(); + System.out.println("splogger: " + sploggerType); + if (!sploggerType.getSimpleName().equals("JdkLazyLogger")) { + throw new RuntimeException(sploggerType.getSimpleName() + + ": unexpected class for splogger" + + " (expected a lazy logger for a platform class)"); + } + Class sloggerType = slogger.getClass(); + System.out.println("slogger: " + sloggerType); + if (sloggerType.equals(sploggerType)) { + throw new RuntimeException(sloggerType + + ": unexpected class for slogger" + + " (a lazy logger was not expected" + + " for a non platform class)"); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/systempkg/log/SystemLoggerAccessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/systempkg/log/SystemLoggerAccessor.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package systempkg.log; + + +/** + * Utility class that returns loggers created for classes in the + * systempkg.log package; + * This class should be loaded in the {@linkplain + * ClassLoader#getPlatformClassLoader() platform class loader} + * for the purpose of the test. + * @author danielfuchs + */ +public class SystemLoggerAccessor { + public static System.Logger getSystemLogger(String name) { + return System.getLogger(name); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/annotation/AnnotationToStringTest.java --- a/jdk/test/java/lang/annotation/AnnotationToStringTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/lang/annotation/AnnotationToStringTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -23,7 +23,7 @@ /* * @test - * @bug 8162817 + * @bug 8162817 8168921 * @summary Test of toString on normal annotations */ @@ -70,6 +70,8 @@ "d1=1.0/0.0, " + "l0=5, " + "l1=9223372036854775807L, " + + "l2=-9223372036854775808L, " + + "l3=-2147483648, " + "s0=\"Hello world.\", " + "s1=\"a\\\"b\", " + "class0=Obj[].class)") @@ -84,6 +86,8 @@ d1=2.0/0.0, l0=5, l1=Long.MAX_VALUE, + l2=Long.MIN_VALUE, + l3=Integer.MIN_VALUE, s0="Hello world.", s1="a\"b", class0=Obj[].class @@ -185,8 +189,10 @@ public int[] f6; @ExpectedString( - "@LongArray(value={-2147483647, 2147483648L, 9223372036854775807L})") - @LongArray(value={-Integer.MAX_VALUE, Integer.MAX_VALUE+1L, Long.MAX_VALUE}) + "@LongArray(value={-9223372036854775808L, -2147483649L, -2147483648," + + " -2147483647, 2147483648L, 9223372036854775807L})") + @LongArray(value={Long.MIN_VALUE, Integer.MIN_VALUE-1L, Integer.MIN_VALUE, + -Integer.MAX_VALUE, Integer.MAX_VALUE+1L, Long.MAX_VALUE}) public long[] f7; @ExpectedString( @@ -287,6 +293,8 @@ double d1(); long l0(); long l1(); + long l2(); + long l3(); String s0(); String s1(); Class class0(); diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/instrument/DaemonThread/TestDaemonThreadLauncher.java --- a/jdk/test/java/lang/instrument/DaemonThread/TestDaemonThreadLauncher.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/lang/instrument/DaemonThread/TestDaemonThreadLauncher.java Fri Nov 11 16:44:36 2016 +0100 @@ -29,7 +29,7 @@ public class TestDaemonThreadLauncher { public static void main(String args[]) throws Exception { for(int i=0; i<50; i++) { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-javaagent:DummyAgent.jar", "TestDaemonThread", "."); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, "-javaagent:DummyAgent.jar", "TestDaemonThread", "."); OutputAnalyzer analyzer = ProcessTools.executeProcess(pb); analyzer.shouldNotContain("ASSERTION FAILED"); analyzer.shouldHaveExitValue(0); diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/invoke/LoopCombinatorTest.java --- a/jdk/test/java/lang/invoke/LoopCombinatorTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/lang/invoke/LoopCombinatorTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -33,6 +33,7 @@ * @bug 8153637 * @bug 8154751 * @bug 8154754 + * @bug 8167974 * @run testng/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest */ @@ -800,7 +801,8 @@ {l_it, l_i, isl_i, ""}, {l_it, null, sl_v, ""}, {li_it, li_i, isli_i, ""}, - {il_it, null, sil_v, "inferred first loop argument must inherit from Iterable: int"}, + {null, null, sil_v, "inferred first loop argument must inherit from Iterable: int"}, + {il_it, null, sil_v, ""}, {li_it, null, sli_v, ""}, {sl_v, null, sl_v, "iteratedLoop first argument must have Iterator return type"}, {li_it, l_it, sl_v, diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/management/CompositeData/ThreadInfoCompositeData.java --- a/jdk/test/java/lang/management/CompositeData/ThreadInfoCompositeData.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/lang/management/CompositeData/ThreadInfoCompositeData.java Fri Nov 11 16:44:36 2016 +0100 @@ -337,9 +337,10 @@ }; private static final String[] steItemNames = { - "className", + "classLoaderName", "moduleName", "moduleVersion", + "className", "methodName", "fileName", "lineNumber", @@ -362,9 +363,10 @@ validItemTypes[STACK_TRACE] = new ArrayType(1, steCType); final Object[] steValue = { - ste[0].getClassName(), + ste[0].getClassLoaderName(), ste[0].getModuleName(), ste[0].getModuleVersion(), + ste[0].getClassName(), ste[0].getMethodName(), ste[0].getFileName(), new Integer(ste[0].getLineNumber()), diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest.java --- a/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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,6 +34,7 @@ * @modules java.management * @build jdk.testlibrary.* LowMemoryTest MemoryUtil RunUtil * @run main/timeout=600 LowMemoryTest + * @requires vm.gc == "null" * @requires vm.opt.ExplicitGCInvokesConcurrent != "true" * @requires vm.opt.ExplicitGCInvokesConcurrentAndUnloadsClasses != "true" * @requires vm.opt.DisableExplicitGC != "true" diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/module/AutomaticModulesTest.java --- a/jdk/test/java/lang/module/AutomaticModulesTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/lang/module/AutomaticModulesTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -158,40 +158,85 @@ */ public void testPackages() throws IOException { Path dir = Files.createTempDirectory(USER_DIR, "mods"); - createDummyJarFile(dir.resolve("m1.jar"), + createDummyJarFile(dir.resolve("m.jar"), "p/C1.class", "p/C2.class", "q/C1.class"); ModuleFinder finder = ModuleFinder.of(dir); + Optional mref = finder.find("m"); + assertTrue(mref.isPresent(), "m not found"); - Configuration parent = Layer.boot().configuration(); - Configuration cf = resolve(parent, finder, "m1"); + ModuleDescriptor descriptor = mref.get().descriptor(); - ModuleDescriptor m1 = findDescriptor(cf, "m1"); + assertTrue(descriptor.packages().size() == 2); + assertTrue(descriptor.packages().contains("p")); + assertTrue(descriptor.packages().contains("q")); - Set exports - = m1.exports().stream().map(Exports::source).collect(Collectors.toSet()); - + Set exports = descriptor.exports().stream() + .map(Exports::source) + .collect(Collectors.toSet()); assertTrue(exports.size() == 2); assertTrue(exports.contains("p")); assertTrue(exports.contains("q")); - assertTrue(m1.conceals().isEmpty()); + } + + /** + * Test class files in JAR file where the entry does not correspond to a + * legal package name. + */ + public void testBadPackage() throws IOException { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createDummyJarFile(dir.resolve("m.jar"), "p/C1.class", "p-/C2.class"); + + ModuleFinder finder = ModuleFinder.of(dir); + Optional mref = finder.find("m"); + assertTrue(mref.isPresent(), "m not found"); + + ModuleDescriptor descriptor = mref.get().descriptor(); + + assertTrue(descriptor.packages().size() == 1); + assertTrue(descriptor.packages().contains("p")); + + Set exports = descriptor.exports().stream() + .map(Exports::source) + .collect(Collectors.toSet()); + assertTrue(exports.size() == 1); + assertTrue(exports.contains("p")); } + /** + * Test non-class resources in a JAR file. + */ + public void testNonClassResources() throws IOException { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createDummyJarFile(dir.resolve("m.jar"), + "LICENSE", + "README", + "WEB-INF/tags", + "p/Type.class", + "p/resources/m.properties"); + + ModuleFinder finder = ModuleFinder.of(dir); + Optional mref = finder.find("m"); + assertTrue(mref.isPresent(), "m not found"); + + ModuleDescriptor descriptor = mref.get().descriptor(); + + assertTrue(descriptor.packages().size() == 2); + assertTrue(descriptor.packages().contains("p")); + assertTrue(descriptor.packages().contains("p.resources")); + } /** - * Test class file in JAR file where the entry does not correspond to a - * legal package name. + * Test .class file in unnamed package (top-level directory) */ @Test(expectedExceptions = FindException.class) - public void testBadPackage() throws IOException { + public void testClassInUnnamedPackage() throws IOException { Path dir = Files.createTempDirectory(USER_DIR, "mods"); - createDummyJarFile(dir.resolve("m1.jar"), "p-/T.class"); - - // should throw FindException - ModuleFinder.of(dir).findAll(); + createDummyJarFile(dir.resolve("m.jar"), "Mojo.class"); + ModuleFinder finder = ModuleFinder.of(dir); + finder.findAll(); } - /** * Test JAR file with META-INF/services configuration file */ @@ -204,12 +249,12 @@ Files.createDirectories(services); Files.write(services.resolve(service), Set.of(provider)); Path dir = Files.createTempDirectory(USER_DIR, "mods"); - JarUtils.createJarFile(dir.resolve("m1.jar"), tmpdir); + JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir); ModuleFinder finder = ModuleFinder.of(dir); - Optional mref = finder.find("m1"); - assertTrue(mref.isPresent(), "m1 not found"); + Optional mref = finder.find("m"); + assertTrue(mref.isPresent(), "m not found"); ModuleDescriptor descriptor = mref.get().descriptor(); assertTrue(descriptor.provides().size() == 1); @@ -220,17 +265,12 @@ } - // META-INF/services configuration file/entries that are not legal - @DataProvider(name = "badproviders") - public Object[][] createProviders() { + // META-INF/services files that don't map to legal service names + @DataProvider(name = "badservices") + public Object[][] createBadServices() { return new Object[][] { // service type provider type - - { "p.S", "-" }, - { "p.S", ".S1" }, - { "p.S", "S1." }, - { "-", "p.S1" }, { ".S", "p.S1" }, }; @@ -240,8 +280,8 @@ * Test JAR file with META-INF/services configuration file with bad * values or names. */ - @Test(dataProvider = "badproviders", expectedExceptions = FindException.class) - public void testBadServicesConfiguration(String service, String provider) + @Test(dataProvider = "badservices") + public void testBadServicesNames(String service, String provider) throws IOException { Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp"); @@ -249,7 +289,41 @@ Files.createDirectories(services); Files.write(services.resolve(service), Set.of(provider)); Path dir = Files.createTempDirectory(USER_DIR, "mods"); - JarUtils.createJarFile(dir.resolve("m1.jar"), tmpdir); + JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir); + + Optional omref = ModuleFinder.of(dir).find("m"); + assertTrue(omref.isPresent()); + ModuleDescriptor descriptor = omref.get().descriptor(); + assertTrue(descriptor.provides().isEmpty()); + } + + + // META-INF/services configuration file entries that are not legal + @DataProvider(name = "badproviders") + public Object[][] createBadProviders() { + return new Object[][] { + + // service type provider type + { "p.S", "-" }, + { "p.S", ".S1" }, + { "p.S", "S1." }, + }; + } + + /** + * Test JAR file with META-INF/services configuration file with bad + * values or names. + */ + @Test(dataProvider = "badproviders", expectedExceptions = FindException.class) + public void testBadProvideNames(String service, String provider) + throws IOException + { + Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp"); + Path services = tmpdir.resolve("META-INF").resolve("services"); + Files.createDirectories(services); + Files.write(services.resolve(service), Set.of(provider)); + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir); // should throw FindException ModuleFinder.of(dir).findAll(); diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/module/ModuleFinderTest.java --- a/jdk/test/java/lang/module/ModuleFinderTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/lang/module/ModuleFinderTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -29,6 +29,7 @@ * @summary Basic tests for java.lang.module.ModuleFinder */ +import java.io.File; import java.io.OutputStream; import java.lang.module.FindException; import java.lang.module.InvalidModuleDescriptorException; @@ -38,6 +39,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Optional; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; @@ -317,6 +319,111 @@ /** + * Test ModuleFinder with a JAR file containing a mix of class and + * non-class resources. + */ + public void testOfOneJarFileWithResources() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + Path jar = createModularJar(dir.resolve("m.jar"), "m", + "LICENSE", + "README", + "WEB-INF/tags", + "p/Type.class", + "p/resources/m.properties", + "q-/Type.class", // not a legal package name + "q-/resources/m/properties"); + + ModuleFinder finder = ModuleFinder.of(jar); + Optional mref = finder.find("m"); + assertTrue(mref.isPresent(), "m not found"); + + ModuleDescriptor descriptor = mref.get().descriptor(); + + assertTrue(descriptor.packages().size() == 2); + assertTrue(descriptor.packages().contains("p")); + assertTrue(descriptor.packages().contains("p.resources")); + } + + + /** + * Test ModuleFinder with an exploded module containing a mix of class + * and non-class resources + */ + public void testOfOneExplodedModuleWithResources() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + Path m_dir = createExplodedModule(dir.resolve("m"), "m", + "LICENSE", + "README", + "WEB-INF/tags", + "p/Type.class", + "p/resources/m.properties", + "q-/Type.class", // not a legal package name + "q-/resources/m/properties"); + + ModuleFinder finder = ModuleFinder.of(m_dir); + Optional mref = finder.find("m"); + assertTrue(mref.isPresent(), "m not found"); + + ModuleDescriptor descriptor = mref.get().descriptor(); + + assertTrue(descriptor.packages().size() == 2); + assertTrue(descriptor.packages().contains("p")); + assertTrue(descriptor.packages().contains("p.resources")); + } + + + /** + * Test ModuleModule with a JAR file containing a .class file in the top + * level directory. + */ + public void testOfOneJarFileWithTopLevelClass() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + Path jar = createModularJar(dir.resolve("m.jar"), "m", "Mojo.class"); + + ModuleFinder finder = ModuleFinder.of(jar); + try { + finder.find("m"); + assertTrue(false); + } catch (FindException e) { + assertTrue(e.getCause() instanceof InvalidModuleDescriptorException); + } + + finder = ModuleFinder.of(jar); + try { + finder.findAll(); + assertTrue(false); + } catch (FindException e) { + assertTrue(e.getCause() instanceof InvalidModuleDescriptorException); + } + } + + /** + * Test ModuleModule with a JAR file containing a .class file in the top + * level directory. + */ + public void testOfOneExplodedModuleWithTopLevelClass() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + Path m_dir = createExplodedModule(dir.resolve("m"), "m", "Mojo.class"); + + ModuleFinder finder = ModuleFinder.of(m_dir); + try { + finder.find("m"); + assertTrue(false); + } catch (FindException e) { + assertTrue(e.getCause() instanceof InvalidModuleDescriptorException); + } + + finder = ModuleFinder.of(m_dir); + try { + finder.findAll(); + assertTrue(false); + } catch (FindException e) { + assertTrue(e.getCause() instanceof InvalidModuleDescriptorException); + } + } + + + /** * Test ModuleFinder.of with a path to a file that does not exist. */ public void testOfWithDoesNotExistEntry() throws Exception { @@ -641,7 +748,7 @@ vs = mid.substring(i+1); } ModuleDescriptor.Builder builder - = new ModuleDescriptor.Builder(mn).requires("java.base"); + = new ModuleDescriptor.Builder(mn).requires("java.base"); if (vs != null) builder.version(vs); return builder.build(); @@ -651,13 +758,22 @@ * Creates an exploded module in the given directory and containing a * module descriptor with the given module name/version. */ - static Path createExplodedModule(Path dir, String mid) throws Exception { + static Path createExplodedModule(Path dir, String mid, String... entries) + throws Exception + { ModuleDescriptor descriptor = newModuleDescriptor(mid); Files.createDirectories(dir); Path mi = dir.resolve("module-info.class"); try (OutputStream out = Files.newOutputStream(mi)) { ModuleInfoWriter.write(descriptor, out); } + + for (String entry : entries) { + Path file = dir.resolve(entry.replace('/', File.separatorChar)); + Files.createDirectories(file.getParent()); + Files.createFile(file); + } + return dir; } diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java --- a/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -24,9 +24,8 @@ /** * @test * @library /lib/testlibrary - * @modules java.base/jdk.internal.module + * @modules java.base/jdk.internal.misc * jdk.compiler - * jdk.jlink * @build ModuleReaderTest CompilerUtils JarUtils * @run testng ModuleReaderTest * @summary Basic tests for java.lang.module.ModuleReader @@ -47,11 +46,14 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; +import java.util.HashSet; +import java.util.List; import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; import java.util.spi.ToolProvider; -import jdk.internal.module.ConfigurableModuleFinder; -import jdk.internal.module.ConfigurableModuleFinder.Phase; +import jdk.internal.misc.SharedSecrets; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; @@ -101,7 +103,7 @@ /** * Test ModuleReader to module in runtime image */ - public void testImage() throws Exception { + public void testImage() throws IOException { ModuleFinder finder = ModuleFinder.ofSystem(); ModuleReference mref = finder.find(BASE_MODULE).get(); @@ -119,6 +121,7 @@ testFind(reader, name, expectedBytes); testOpen(reader, name, expectedBytes); testRead(reader, name, expectedBytes); + testList(reader, name); } @@ -168,7 +171,7 @@ /** * Test ModuleReader to exploded module */ - public void testExplodedModule() throws Exception { + public void testExplodedModule() throws IOException { test(MODS_DIR); } @@ -176,7 +179,7 @@ /** * Test ModuleReader to modular JAR */ - public void testModularJar() throws Exception { + public void testModularJar() throws IOException { Path dir = Files.createTempDirectory(USER_DIR, "mlib"); // jar cf mlib/${TESTMODULE}.jar -C mods . @@ -190,7 +193,7 @@ /** * Test ModuleReader to JMOD */ - public void testJMod() throws Exception { + public void testJMod() throws IOException { Path dir = Files.createTempDirectory(USER_DIR, "mlib"); // jmod create --class-path mods/${TESTMODULE} mlib/${TESTMODULE}.jmod @@ -211,13 +214,10 @@ * The test module is found on the given module path. Open a ModuleReader * to the test module and test the reader. */ - void test(Path mp) throws Exception { + void test(Path mp) throws IOException { - ModuleFinder finder = ModuleFinder.of(mp); - if (finder instanceof ConfigurableModuleFinder) { - // need ModuleFinder to be in the phase to find JMOD files - ((ConfigurableModuleFinder)finder).configurePhase(Phase.LINK_TIME); - } + ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess() + .newModulePath(Runtime.version(), true, mp); ModuleReference mref = finder.find(TEST_MODULE).get(); ModuleReader reader = mref.open(); @@ -234,6 +234,7 @@ testFind(reader, name, expectedBytes); testOpen(reader, name, expectedBytes); testRead(reader, name, expectedBytes); + testList(reader, name); } // test "not found" @@ -275,13 +276,18 @@ reader.read(TEST_RESOURCES[0]); assertTrue(false); } catch (IOException expected) { } + + try { + reader.list(); + assertTrue(false); + } catch (IOException expected) { } } /** * Test ModuleReader#find */ void testFind(ModuleReader reader, String name, byte[] expectedBytes) - throws Exception + throws IOException { Optional ouri = reader.find(name); assertTrue(ouri.isPresent()); @@ -301,7 +307,7 @@ * Test ModuleReader#open */ void testOpen(ModuleReader reader, String name, byte[] expectedBytes) - throws Exception + throws IOException { Optional oin = reader.open(name); assertTrue(oin.isPresent()); @@ -317,7 +323,7 @@ * Test ModuleReader#read */ void testRead(ModuleReader reader, String name, byte[] expectedBytes) - throws Exception + throws IOException { Optional obb = reader.read(name); assertTrue(obb.isPresent()); @@ -334,4 +340,24 @@ } } + /** + * Test ModuleReader#list + */ + void testList(ModuleReader reader, String name) throws IOException { + List list = reader.list().collect(Collectors.toList()); + Set names = new HashSet<>(list); + assertTrue(names.size() == list.size()); // no duplicates + + assertTrue(names.contains("module-info.class")); + assertTrue(names.contains(name)); + + // all resources should be locatable via find + for (String e : names) { + assertTrue(reader.find(e).isPresent()); + } + + // should not contain directories + names.forEach(e -> assertFalse(e.endsWith("/"))); + } + } diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/module/ModuleReader/MultiReleaseJarTest.java --- a/jdk/test/java/lang/module/ModuleReader/MultiReleaseJarTest.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @test - * @library /lib/testlibrary - * @modules java.base/jdk.internal.module - * @build MultiReleaseJarTest JarUtils - * @run testng MultiReleaseJarTest - * @run testng/othervm -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarTest - * @summary Basic test of ModuleReader with a modular JAR that is also a - * multi-release JAR - */ - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleFinder; -import java.lang.module.ModuleReader; -import java.lang.module.ModuleReference; -import java.net.URI; -import java.net.URLConnection; -import java.nio.ByteBuffer; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Optional; -import java.util.Set; -import java.util.jar.Attributes; -import java.util.jar.Manifest; -import java.util.stream.Collectors; - -import jdk.internal.module.ModuleInfoWriter; - -import org.testng.annotations.Test; -import static org.testng.Assert.*; - -/** - * Exercises ModuleReader with a modular JAR containing the following files: - * - *
    {@code
    - *     module-info.class
    - *     META-INF/versions//module.class
    - * }
    - * - * The module-info.class in the top-level directory is the binary form of: - *
    {@code
    - *     module jdk.test {
    - *         requires java.base;
    - *     }
    - * }
    - * - * The module-info.class in the versioned section is the binary form of: - *
    {@code
    - *     module jdk.test {
    - *         requires java.base;
    - *         requires jdk.unsupported;
    - *     }
    - * }
    - */ - -@Test -public class MultiReleaseJarTest { - - // Java SE/JDK major release - private static final int RELEASE = Runtime.version().major(); - - // the name of the test module - private static final String MODULE_NAME = "jdk.test"; - - private static final String MODULE_INFO_CLASS = "module-info.class"; - - /** - * Uses the ModuleFinder API to locate the module packaged as a modular - * and mutli-release JAR and then creates a ModuleReader to access the - * contents of the module. - */ - public void testMultiReleaseJar() throws IOException { - - // are multi-release JARs enabled? - String s = System.getProperty("jdk.util.jar.enableMultiRelease"); - boolean multiRelease = (s == null || Boolean.parseBoolean(s)); - - // create the multi-release modular JAR - Path jarfile = createJarFile(); - - // find the module - ModuleFinder finder = ModuleFinder.of(jarfile); - Optional omref = finder.find(MODULE_NAME); - assertTrue((omref.isPresent())); - ModuleReference mref = omref.get(); - - // test that correct module-info.class was read - checkDescriptor(mref.descriptor(), multiRelease); - - // test ModuleReader - try (ModuleReader reader = mref.open()) { - - // open resource - Optional oin = reader.open(MODULE_INFO_CLASS); - assertTrue(oin.isPresent()); - try (InputStream in = oin.get()) { - checkDescriptor(ModuleDescriptor.read(in), multiRelease); - } - - // read resource - Optional obb = reader.read(MODULE_INFO_CLASS); - assertTrue(obb.isPresent()); - ByteBuffer bb = obb.get(); - try { - checkDescriptor(ModuleDescriptor.read(bb), multiRelease); - } finally { - reader.release(bb); - } - - // find resource - Optional ouri = reader.find(MODULE_INFO_CLASS); - assertTrue(ouri.isPresent()); - URI uri = ouri.get(); - - String expectedTail = "!/"; - if (multiRelease) - expectedTail += "META-INF/versions/" + RELEASE + "/"; - expectedTail += MODULE_INFO_CLASS; - assertTrue(uri.toString().endsWith(expectedTail)); - - URLConnection uc = uri.toURL().openConnection(); - uc.setUseCaches(false); - try (InputStream in = uc.getInputStream()) { - checkDescriptor(ModuleDescriptor.read(in), multiRelease); - } - - } - - } - - /** - * Checks that the module descriptor is the expected module descriptor. - * When the multi release JAR feature is enabled then the module - * descriptor is expected to have been read from the versioned section - * of the JAR file. - */ - private void checkDescriptor(ModuleDescriptor descriptor, boolean multiRelease) { - Set requires = descriptor.requires().stream() - .map(ModuleDescriptor.Requires::name) - .collect(Collectors.toSet()); - assertTrue(requires.contains("java.base")); - assertTrue(requires.contains("jdk.unsupported") == multiRelease); - } - - /** - * Creates the modular JAR for the test, returning the Path to the JAR file. - */ - private Path createJarFile() throws IOException { - - // module descriptor for top-level directory - ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder(MODULE_NAME) - .requires("java.base") - .build(); - - // module descriptor for versioned section - ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder(MODULE_NAME) - .requires("java.base") - .requires("jdk.unsupported") - .build(); - - Path top = Paths.get(MODULE_NAME); - Files.createDirectories(top); - - Path mi1 = Paths.get(MODULE_INFO_CLASS); - try (OutputStream out = Files.newOutputStream(top.resolve(mi1))) { - ModuleInfoWriter.write(descriptor1, out); - } - - Path vdir = Paths.get("META-INF", "versions", Integer.toString(RELEASE)); - Files.createDirectories(top.resolve(vdir)); - - Path mi2 = vdir.resolve(MODULE_INFO_CLASS); - try (OutputStream out = Files.newOutputStream(top.resolve(mi2))) { - ModuleInfoWriter.write(descriptor2, out); - } - - Manifest man = new Manifest(); - Attributes attrs = man.getMainAttributes(); - attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0"); - attrs.put(Attributes.Name.MULTI_RELEASE, "true"); - - Path jarfile = Paths.get(MODULE_NAME + ".jar"); - JarUtils.createJarFile(jarfile, man, top, mi1, mi2); - - return jarfile; - } -} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/lang/module/MultiReleaseJarTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/module/MultiReleaseJarTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /lib/testlibrary + * @modules java.base/jdk.internal.module + * @build MultiReleaseJarTest JarUtils + * @run testng MultiReleaseJarTest + * @run testng/othervm -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarTest + * @summary Basic test of modular JARs as multi-release JARs + */ + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.net.URI; +import java.net.URLConnection; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import jdk.internal.module.ModuleInfoWriter; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + + +@Test +public class MultiReleaseJarTest { + + private static final String MODULE_INFO = "module-info.class"; + + private static final int RELEASE = Runtime.version().major(); + + // are multi-release JARs enabled? + private static final boolean MULTI_RELEASE; + static { + String s = System.getProperty("jdk.util.jar.enableMultiRelease"); + MULTI_RELEASE = (s == null || Boolean.parseBoolean(s)); + } + + /** + * Basic test of a multi-release JAR. + */ + public void testBasic() throws Exception { + String name = "m1"; + + ModuleDescriptor descriptor = new ModuleDescriptor.Builder(name) + .requires("java.base") + .build(); + + Path jar = new JarBuilder(name) + .moduleInfo("module-info.class", descriptor) + .resource("p/Main.class") + .resource("p/Helper.class") + .resource("META-INF/versions/9/p/Helper.class") + .resource("META-INF/versions/9/p/internal/Helper9.class") + .build(); + + // find the module + ModuleFinder finder = ModuleFinder.of(jar); + Optional omref = finder.find(name); + assertTrue((omref.isPresent())); + ModuleReference mref = omref.get(); + + // check module packages + descriptor = mref.descriptor(); + Set packages = descriptor.packages(); + assertTrue(packages.contains("p")); + if (MULTI_RELEASE) { + assertTrue(packages.size() == 2); + assertTrue(packages.contains("p.internal")); + } else { + assertTrue(packages.size() == 1); + } + } + + /** + * Test a multi-release JAR with a module-info.class in the versioned + * section of the JAR. + */ + public void testModuleInfoInVersionedSection() throws Exception { + String name = "m1"; + + ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder(name) + .requires("java.base") + .build(); + + // module descriptor for versioned section + ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder(name) + .requires("java.base") + .requires("jdk.unsupported") + .build(); + + Path jar = new JarBuilder(name) + .moduleInfo(MODULE_INFO, descriptor1) + .resource("p/Main.class") + .resource("p/Helper.class") + .moduleInfo("META-INF/versions/9/" + MODULE_INFO, descriptor2) + .resource("META-INF/versions/9/p/Helper.class") + .resource("META-INF/versions/9/p/internal/Helper9.class") + .build(); + + // find the module + ModuleFinder finder = ModuleFinder.of(jar); + Optional omref = finder.find(name); + assertTrue((omref.isPresent())); + ModuleReference mref = omref.get(); + + // ensure that the right module-info.class is loaded + ModuleDescriptor descriptor = mref.descriptor(); + assertEquals(descriptor.name(), name); + if (MULTI_RELEASE) { + assertEquals(descriptor.requires(), descriptor2.requires()); + } else { + assertEquals(descriptor.requires(), descriptor1.requires()); + } + } + + /** + * Test multi-release JAR as an automatic module. + */ + public void testAutomaticModule() throws Exception { + String name = "m"; + + Path jar = new JarBuilder(name) + .resource("p/Main.class") + .resource("p/Helper.class") + .resource("META-INF/versions/9/p/Helper.class") + .resource("META-INF/versions/9/p/internal/Helper9.class") + .build(); + + // find the module + ModuleFinder finder = ModuleFinder.of(jar); + Optional omref = finder.find(name); + assertTrue((omref.isPresent())); + ModuleReference mref = omref.get(); + + // check module packages + ModuleDescriptor descriptor = mref.descriptor(); + Set packages = descriptor.packages(); + if (MULTI_RELEASE) { + assertTrue(packages.size() == 2); + assertTrue(packages.contains("p.internal")); + } else { + assertTrue(packages.size() == 1); + } + } + + /** + * Exercise ModuleReader on a multi-release JAR + */ + public void testModuleReader() throws Exception { + String name = "m1"; + + ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder(name) + .requires("java.base") + .build(); + + // module descriptor for versioned section + ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder(name) + .requires("java.base") + .requires("jdk.unsupported") + .build(); + + Path jar = new JarBuilder(name) + .moduleInfo(MODULE_INFO, descriptor1) + .moduleInfo("META-INF/versions/9/" + MODULE_INFO, descriptor2) + .build(); + + // find the module + ModuleFinder finder = ModuleFinder.of(jar); + Optional omref = finder.find(name); + assertTrue((omref.isPresent())); + ModuleReference mref = omref.get(); + + ModuleDescriptor expected; + if (MULTI_RELEASE) { + expected = descriptor2; + } else { + expected = descriptor1; + } + + // test ModuleReader by reading module-info.class resource + try (ModuleReader reader = mref.open()) { + + // open resource + Optional oin = reader.open(MODULE_INFO); + assertTrue(oin.isPresent()); + try (InputStream in = oin.get()) { + checkRequires(ModuleDescriptor.read(in), expected); + } + + // read resource + Optional obb = reader.read(MODULE_INFO); + assertTrue(obb.isPresent()); + ByteBuffer bb = obb.get(); + try { + checkRequires(ModuleDescriptor.read(bb), expected); + } finally { + reader.release(bb); + } + + // find resource + Optional ouri = reader.find(MODULE_INFO); + assertTrue(ouri.isPresent()); + URI uri = ouri.get(); + + String expectedTail = "!/"; + if (MULTI_RELEASE) + expectedTail += "META-INF/versions/" + RELEASE + "/"; + expectedTail += MODULE_INFO; + assertTrue(uri.toString().endsWith(expectedTail)); + + URLConnection uc = uri.toURL().openConnection(); + uc.setUseCaches(false); + try (InputStream in = uc.getInputStream()) { + checkRequires(ModuleDescriptor.read(in), expected); + } + + } + } + + /** + * Check that two ModuleDescriptor have the same requires + */ + static void checkRequires(ModuleDescriptor md1, ModuleDescriptor md2) { + assertEquals(md1.requires(), md2.requires()); + } + + /** + * A builder of multi-release JAR files. + */ + static class JarBuilder { + private String name; + private Set resources = new HashSet<>(); + private Map descriptors = new HashMap<>(); + + JarBuilder(String name) { + this.name = name; + } + + /** + * Adds a module-info.class to the JAR file. + */ + JarBuilder moduleInfo(String name, ModuleDescriptor descriptor) { + descriptors.put(name, descriptor); + return this; + } + + /** + * Adds a dummy resource to the JAR file. + */ + JarBuilder resource(String name) { + resources.add(name); + return this; + } + + /** + * Create the multi-release JAR, returning its file path. + */ + Path build() throws Exception { + Path dir = Files.createTempDirectory(Paths.get(""), "jar"); + List files = new ArrayList<>(); + + // write the module-info.class + for (Map.Entry e : descriptors.entrySet()) { + String name = e.getKey(); + ModuleDescriptor descriptor = e.getValue(); + Path mi = Paths.get(name.replace('/', File.separatorChar)); + Path parent = dir.resolve(mi).getParent(); + if (parent != null) + Files.createDirectories(parent); + try (OutputStream out = Files.newOutputStream(dir.resolve(mi))) { + ModuleInfoWriter.write(descriptor, out); + } + files.add(mi); + } + + // write the dummy resources + for (String name : resources) { + Path file = Paths.get(name.replace('/', File.separatorChar)); + // create dummy resource + Path parent = dir.resolve(file).getParent(); + if (parent != null) + Files.createDirectories(parent); + Files.createFile(dir.resolve(file)); + files.add(file); + } + + Manifest man = new Manifest(); + Attributes attrs = man.getMainAttributes(); + attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0"); + attrs.put(Attributes.Name.MULTI_RELEASE, "true"); + + Path jarfile = Paths.get(name + ".jar"); + JarUtils.createJarFile(jarfile, man, dir, files.toArray(new Path[0])); + return jarfile; + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/net/URLClassLoader/NullURLTest.java --- a/jdk/test/java/net/URLClassLoader/NullURLTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/net/URLClassLoader/NullURLTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -109,7 +109,7 @@ failures++; } try { - loader = new URLClassLoader(null, null, null); + loader = new URLClassLoader((URL[])null, null, null); System.err.println("URLClassLoader(null, null, null) did not throw NPE"); failures++; } catch (NullPointerException e) { diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/net/URLPermission/nstest/LookupTest.java --- a/jdk/test/java/net/URLPermission/nstest/LookupTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/net/URLPermission/nstest/LookupTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -22,124 +22,195 @@ */ /** - * This is a simple smoke test of the HttpURLPermission mechanism, which - * checks for either IOException (due to unknown host) or SecurityException - * due to lack of permission to connect + * @test + * @summary A simple smoke test of the HttpURLPermission mechanism, which checks + * for either IOException (due to unknown host) or SecurityException + * due to lack of permission to connect + * @run main/othervm LookupTest */ -import java.net.*; -import java.io.*; -import jdk.testlibrary.Utils; +import java.io.BufferedWriter; +import java.io.FilePermission; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.net.NetPermission; +import java.net.ProxySelector; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketPermission; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLPermission; +import java.security.CodeSource; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.security.Policy; +import java.security.ProtectionDomain; +import static java.nio.charset.StandardCharsets.US_ASCII; public class LookupTest { - static void test( - String url, boolean throwsSecException, boolean throwsIOException) - { + static int port; + static volatile ServerSocket serverSocket; + + static void test(String url, + boolean throwsSecException, + boolean throwsIOException) { + ProxySelector.setDefault(null); + URL u; + InputStream is = null; try { - ProxySelector.setDefault(null); - URL u = new URL(url); - System.err.println ("Connecting to " + u); + u = new URL(url); + System.err.println("Connecting to " + u); URLConnection urlc = u.openConnection(); - InputStream is = urlc.getInputStream(); + is = urlc.getInputStream(); } catch (SecurityException e) { if (!throwsSecException) { - throw new RuntimeException ("(1) was not expecting ", e); + throw new RuntimeException("Unexpected SecurityException:", e); + } + return; + } catch (IOException e) { + if (!throwsIOException) { + System.err.println("Unexpected IOException:" + e.getMessage()); + throw new RuntimeException(e); } return; - } catch (IOException ioe) { - if (!throwsIOException) { - throw new RuntimeException ("(2) was not expecting ", ioe); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + System.err.println("Unexpected IOException:" + e.getMessage()); + throw new RuntimeException(e); + } } - return; } + if (throwsSecException || throwsIOException) { - System.err.printf ("was expecting a %s\n", throwsSecException ? - "security exception" : "IOException"); + System.err.printf("was expecting a %s\n", throwsSecException + ? "security exception" : "IOException"); throw new RuntimeException("was expecting an exception"); } } - static int port; - static ServerSocket serverSocket; + static final String CWD = System.getProperty("user.dir", "."); public static void main(String args[]) throws Exception { - - - String cmd = args[0]; - if (cmd.equals("-getport")) { - port = Utils.getFreePort(); - System.out.print(port); - } else if (cmd.equals("-runtest")) { - port = Integer.parseInt(args[1]); - String hostsFileName = System.getProperty("user.dir", ".") + "/LookupTestHosts"; - System.setProperty("jdk.net.hosts.file", hostsFileName); - addMappingToHostsFile("allowedAndFound.com", "127.0.0.1", hostsFileName, false); - addMappingToHostsFile("notAllowedButFound.com", "99.99.99.99", hostsFileName, true); - // name "notAllowedAndNotFound.com" is not in map - // name "allowedButNotfound.com" is not in map - try { - startServer(); - - System.setSecurityManager(new SecurityManager()); - - test("http://allowedAndFound.com:" + port + "/foo", false, false); - - test("http://notAllowedButFound.com:" + port + "/foo", true, false); - - test("http://allowedButNotfound.com:" + port + "/foo", false, true); - - test("http://notAllowedAndNotFound.com:" + port + "/foo", true, false); - } finally { - serverSocket.close(); - } - } else { - throw new RuntimeException("Bad invocation: " + cmd); + String hostsFileName = CWD + "/LookupTestHosts"; + System.setProperty("jdk.net.hosts.file", hostsFileName); + addMappingToHostsFile("allowedAndFound.com", + "127.0.0.1", + hostsFileName, + false); + addMappingToHostsFile("notAllowedButFound.com", + "99.99.99.99", + hostsFileName, + true); + // name "notAllowedAndNotFound.com" is not in map + // name "allowedButNotfound.com" is not in map + Server server = new Server(); + try { + Policy.setPolicy(new LookupTestPolicy()); + System.setSecurityManager(new SecurityManager()); + server.start(); + test("http://allowedAndFound.com:" + port + "/foo", false, false); + test("http://notAllowedButFound.com:" + port + "/foo", true, false); + test("http://allowedButNotfound.com:" + port + "/foo", false, true); + test("http://notAllowedAndNotFound.com:" + port + "/foo", true, false); + } finally { + server.terminate(); } } - static Thread server; + static class Server extends Thread { + private volatile boolean done; - static class Server extends Thread { + public Server() throws IOException { + serverSocket = new ServerSocket(0); + port = serverSocket.getLocalPort(); + } + public void run() { - byte[] buf = new byte[1000]; try { - while (true) { - Socket s = serverSocket.accept(); - InputStream i = s.getInputStream(); - i.read(buf); - OutputStream o = s.getOutputStream(); - String rsp = "HTTP/1.1 200 Ok\r\n" + - "Connection: close\r\nContent-length: 0\r\n\r\n"; - o.write(rsp.getBytes()); - o.close(); + while (!done) { + try (Socket s = serverSocket.accept()) { + readOneRequest(s.getInputStream()); + OutputStream o = s.getOutputStream(); + String rsp = "HTTP/1.1 200 Ok\r\n" + + "Connection: close\r\n" + + "Content-length: 0\r\n\r\n"; + o.write(rsp.getBytes(US_ASCII)); + } } } catch (IOException e) { - return; + if (!done) + e.printStackTrace(); } - } - } + } + + void terminate() { + done = true; + try { serverSocket.close(); } + catch (IOException unexpected) { unexpected.printStackTrace(); } + } + + static final byte[] requestEnd = new byte[] {'\r', '\n', '\r', '\n' }; - static void startServer() { - try { - serverSocket = new ServerSocket(port); - server = new Server(); - server.start(); - } catch (Exception e) { - throw new RuntimeException ("Test failed to initialize", e); + // Read until the end of a HTTP request + void readOneRequest(InputStream is) throws IOException { + int requestEndCount = 0, r; + while ((r = is.read()) != -1) { + if (r == requestEnd[requestEndCount]) { + requestEndCount++; + if (requestEndCount == 4) { + break; + } + } else { + requestEndCount = 0; + } + } } } - private static void addMappingToHostsFile (String host, - String addr, - String hostsFileName, - boolean append) - throws Exception { + private static void addMappingToHostsFile(String host, + String addr, + String hostsFileName, + boolean append) + throws IOException + { String mapping = addr + " " + host; - try (PrintWriter hfPWriter = new PrintWriter(new BufferedWriter( - new FileWriter(hostsFileName, append)))) { + try (FileWriter fr = new FileWriter(hostsFileName, append); + PrintWriter hfPWriter = new PrintWriter(new BufferedWriter(fr))) { hfPWriter.println(mapping); -} + } } + static class LookupTestPolicy extends Policy { + final PermissionCollection perms = new Permissions(); + + LookupTestPolicy() throws Exception { + perms.add(new NetPermission("setProxySelector")); + perms.add(new SocketPermission("localhost:1024-", "resolve,accept")); + perms.add(new URLPermission("http://allowedAndFound.com:" + port + "/-", "*:*")); + perms.add(new URLPermission("http://allowedButNotfound.com:" + port + "/-", "*:*")); + perms.add(new FilePermission("<>", "read,write,delete")); + //perms.add(new PropertyPermission("java.io.tmpdir", "read")); + } + + public PermissionCollection getPermissions(ProtectionDomain domain) { + return perms; + } + + public PermissionCollection getPermissions(CodeSource codesource) { + return perms; + } + + public boolean implies(ProtectionDomain domain, Permission perm) { + return perms.implies(perm); + } + } } diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/net/URLPermission/nstest/lookup.sh --- a/jdk/test/java/net/URLPermission/nstest/lookup.sh Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2013, 2016 Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# @test -# @library /lib/testlibrary -# @build jdk.testlibrary.* -# @compile -XDignore.symbol.file=true LookupTest.java -# @run shell/timeout=50 lookup.sh -# @key intermittent -# - -OS=`uname -s` -case ${OS} in -Windows_* | CYGWIN*) - PS=";" - FS="\\" - ;; -*) - PS=":" - FS="/" - ;; -esac - -port=`${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} LookupTest -getport` - -cat << POLICY > policy -grant { - permission java.net.URLPermission "http://allowedAndFound.com:${port}/-", "*:*"; - permission java.net.URLPermission "http://allowedButNotfound.com:${port}/-", "*:*"; - permission java.net.NetPermission "setProxySelector"; - permission java.io.FilePermission "<>", "read,write,delete"; - permission java.util.PropertyPermission "java.io.tmpdir", "read"; - - // needed for HttpServer - permission "java.net.SocketPermission" "localhost:1024-", "resolve,accept"; -}; -POLICY - -${TESTJAVA}/bin/java ${TESTVMOPTS} \ - -Djava.security.policy=file:./policy \ - -Dtest.src=${TESTSRC} \ - -cp ${TESTCLASSPATH}${PS}${TESTSRC} LookupTest -runtest ${port} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/net/httpclient/APIErrors.java --- a/jdk/test/java/net/httpclient/APIErrors.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/net/httpclient/APIErrors.java Fri Nov 11 16:44:36 2016 +0100 @@ -21,10 +21,11 @@ * questions. */ -/** +/* * @test * @bug 8087112 * @modules java.httpclient + * java.logging * jdk.httpserver * @library /lib/testlibrary/ * @build jdk.testlibrary.SimpleSSLContext ProxyServer @@ -35,13 +36,23 @@ */ //package javaapplication16; -import com.sun.net.httpserver.*; +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsServer; import java.io.IOException; -import java.net.*; -import java.net.http.*; +import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; +import java.net.ProxySelector; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.util.LinkedList; import java.util.List; -import java.util.concurrent.*; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; import java.util.function.Supplier; /** diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/net/httpclient/ManyRequests.java --- a/jdk/test/java/net/httpclient/ManyRequests.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/net/httpclient/ManyRequests.java Fri Nov 11 16:44:36 2016 +0100 @@ -21,10 +21,11 @@ * questions. */ -/** +/* * @test * @bug 8087112 * @modules java.httpclient + * java.logging * jdk.httpserver * @library /lib/testlibrary/ / * @build jdk.testlibrary.SimpleSSLContext EchoHandler @@ -36,7 +37,9 @@ //package javaapplication16; -import com.sun.net.httpserver.*; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsParameters; +import com.sun.net.httpserver.HttpsServer; import java.io.IOException; import java.io.UncheckedIOException; import java.net.http.HttpClient; @@ -48,9 +51,10 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.Random; -import java.util.logging.*; +import java.util.logging.Logger; +import java.util.logging.Level; import java.util.concurrent.CompletableFuture; -import javax.net.ssl.*; +import javax.net.ssl.SSLContext; import jdk.testlibrary.SimpleSSLContext; public class ManyRequests { diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/net/httpclient/RequestBodyTest.java --- a/jdk/test/java/net/httpclient/RequestBodyTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/net/httpclient/RequestBodyTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -21,9 +21,10 @@ * questions. */ -/** +/* * @test @bug 8087112 * @modules java.httpclient + * java.logging * jdk.httpserver * @library /lib/testlibrary/ / * @compile ../../../com/sun/net/httpserver/LogFilter.java diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/net/httpclient/SmokeTest.java --- a/jdk/test/java/net/httpclient/SmokeTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/net/httpclient/SmokeTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -21,10 +21,11 @@ * questions. */ -/** +/* * @test * @bug 8087112 * @modules java.httpclient + * java.logging * jdk.httpserver * @library /lib/testlibrary/ / * @build jdk.testlibrary.SimpleSSLContext ProxyServer EchoHandler @@ -33,13 +34,40 @@ * @run main/othervm SmokeTest */ -import com.sun.net.httpserver.*; -import java.net.*; -import java.net.http.*; -import java.io.*; -import java.util.concurrent.*; -import javax.net.ssl.*; -import java.nio.file.*; +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsParameters; +import com.sun.net.httpserver.HttpsServer; +import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; +import java.net.ProxySelector; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.HashSet; import java.util.LinkedList; import java.util.List; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/net/httpclient/security/Driver.java --- a/jdk/test/java/net/httpclient/security/Driver.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/net/httpclient/security/Driver.java Fri Nov 11 16:44:36 2016 +0100 @@ -28,6 +28,7 @@ * @bug 8087112 * @library /lib/testlibrary/ * @modules java.httpclient + * java.logging * jdk.httpserver * @build jdk.testlibrary.SimpleSSLContext jdk.testlibrary.Utils * @compile ../../../../com/sun/net/httpserver/LogFilter.java diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/net/httpclient/security/Security.java --- a/jdk/test/java/net/httpclient/security/Security.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/net/httpclient/security/Security.java Fri Nov 11 16:44:36 2016 +0100 @@ -23,10 +23,11 @@ * questions. */ -/** +/* * @test * @bug 8087112 * @modules java.httpclient + * java.logging * jdk.httpserver * @library /lib/testlibrary/ * @build jdk.testlibrary.SimpleSSLContext @@ -50,14 +51,27 @@ // Tests 1, 10, 11 and 12 executed from Driver -import com.sun.net.httpserver.*; +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsServer; import java.io.IOException; import java.io.InputStream; import java.io.File; import java.io.OutputStream; import java.lang.reflect.Constructor; -import java.net.*; -import java.net.http.*; +import java.net.BindException; +import java.net.InetSocketAddress; +import java.net.ProxySelector; +import java.net.URI; +import java.net.URLClassLoader; +import java.net.URL; +import java.net.http.HttpHeaders; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -66,13 +80,15 @@ import java.nio.file.StandardCopyOption; import java.util.LinkedList; import java.util.List; -import java.util.concurrent.*; -import java.util.function.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.function.LongConsumer; import java.util.logging.ConsoleHandler; import java.util.logging.Level; import java.util.logging.Logger; import java.lang.reflect.InvocationTargetException; -import java.net.BindException; /** * Security checks test diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/net/ipv6tests/Tests.java --- a/jdk/test/java/net/ipv6tests/Tests.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/net/ipv6tests/Tests.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 @@ -139,11 +139,17 @@ /* check the time got is within 50% of the time expected */ public static void checkTime (long got, long expected) { - dprintln ("checkTime: got " + got + " expected " + expected); - long upper = expected + (expected / 2); - long lower = expected - (expected / 2); + checkTime(got, expected, expected); + } + + /* check the time got is between start and end, given 50% tolerance */ + public static void checkTime(long got, long start, long end) { + dprintln("checkTime: got = " + got + " start = " + start + " end = " + end); + long upper = end + (end / 2); + long lower = start - (start / 2); if (got > upper || got < lower) { - throw new RuntimeException ("checkTime failed: got " + got + " expected " + expected); + throw new RuntimeException("checkTime failed: got " + got + + ", expected between " + start + " and " + end); } } diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/net/ipv6tests/UdpTest.java --- a/jdk/test/java/net/ipv6tests/UdpTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/net/ipv6tests/UdpTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -24,7 +24,6 @@ /* * @test * @bug 4868820 - * @key intermittent * @summary IPv6 support for Windows XP and 2003 server */ @@ -159,7 +158,7 @@ }); t1 = System.currentTimeMillis(); s1.receive (new DatagramPacket (new byte [128], 128)); - checkTime (System.currentTimeMillis() - t1, 4000); + checkTime (System.currentTimeMillis() - t1, 2000, 10000); s1.close (); s2.close (); System.out.println ("Test2: OK"); diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java --- a/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java Fri Nov 11 16:44:36 2016 +0100 @@ -40,7 +40,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID ActivateMe CheckActivateRef_Stub + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider ActivateMe CheckActivateRef_Stub * @run main/othervm/policy=security.policy/timeout=240 -Djava.rmi.server.ignoreStubClasses=true CheckActivateRef * @run main/othervm/policy=security.policy/timeout=240 -Djava.rmi.server.ignoreStubClasses=false CheckActivateRef * @key intermittent @@ -118,7 +119,7 @@ // start an rmid. RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/checkActivateRef/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/checkActivateRef/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/checkActivateRef/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -2,4 +2,6 @@ permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.rmi.server.useDynamicProxies=*"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/checkActivateRef/security.policy --- a/jdk/test/java/rmi/activation/Activatable/checkActivateRef/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/checkActivateRef/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -38,4 +38,6 @@ permission java.net.SocketPermission "*:1024-", "connect,accept,listen"; permission java.lang.RuntimePermission "getClassLoader"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/checkAnnotations/CheckAnnotations.java --- a/jdk/test/java/rmi/activation/Activatable/checkAnnotations/CheckAnnotations.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/checkAnnotations/CheckAnnotations.java Fri Nov 11 16:44:36 2016 +0100 @@ -32,7 +32,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID MyRMI CheckAnnotations_Stub + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider MyRMI CheckAnnotations_Stub * @run main/othervm/policy=security.policy/timeout=480 CheckAnnotations */ @@ -77,7 +78,7 @@ // start an rmid. RMID.removeLog(); - rmid = RMID.createRMID(rmidOut, rmidErr, false); + rmid = RMID.createRMIDOnEphemeralPort(rmidOut, rmidErr, false); rmid.start(); /* Cause activation groups to have a security policy that will @@ -228,6 +229,7 @@ return false; } + // just make sure that last two strings are what we expect. if (execOut.equals("ExecGroup-" + iteration) && (new String(destOut.substring(0,4)).equals("out" + diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/checkAnnotations/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/checkAnnotations/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/checkAnnotations/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -1,4 +1,6 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/checkAnnotations/security.policy --- a/jdk/test/java/rmi/activation/Activatable/checkAnnotations/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/checkAnnotations/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -28,4 +28,7 @@ // test needs to export rmid and communicate with objects on arbitrary ports permission java.net.SocketPermission "*:1024-", "connect,accept,listen"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/CheckImplClassLoader.java --- a/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/CheckImplClassLoader.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/CheckImplClassLoader.java Fri Nov 11 16:44:36 2016 +0100 @@ -31,7 +31,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider * MyRMI ActivatableImpl ActivatableImpl ActivatableImpl_Stub * @run main/othervm/policy=security.policy/timeout=150 CheckImplClassLoader */ @@ -80,7 +81,7 @@ TestParams.defaultSecurityManager); RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); System.err.println("Create activation group in this VM"); diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -1,4 +1,6 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/security.policy --- a/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -39,4 +39,7 @@ // test needs to export rmid and communicate with objects on arbitrary ports permission java.net.SocketPermission "*:1024-", "connect,accept,listen"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/CheckRegisterInLog.java --- a/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/CheckRegisterInLog.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/CheckRegisterInLog.java Fri Nov 11 16:44:36 2016 +0100 @@ -31,7 +31,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID ActivationLibrary + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider ActivationLibrary * ActivateMe CheckRegisterInLog_Stub * @run main/othervm/policy=security.policy/timeout=240 CheckRegisterInLog */ @@ -99,7 +100,7 @@ * Start up activation system daemon "rmid". */ RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -1,4 +1,6 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/security.policy --- a/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -31,4 +31,7 @@ // allow exporting object with non-public remote interface permission java.rmi.RMIPermission "exportRemoteInterface.ActivateMe"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/createPrivateActivable/CreatePrivateActivatable.java --- a/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/CreatePrivateActivatable.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/CreatePrivateActivatable.java Fri Nov 11 16:44:36 2016 +0100 @@ -31,7 +31,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID ActivateMe + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider ActivateMe * @run main/othervm/policy=security.policy/timeout=240 CreatePrivateActivatable */ @@ -103,7 +104,7 @@ // start an rmid. RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/createPrivateActivable/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -1,4 +1,6 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/createPrivateActivable/security.policy --- a/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -31,4 +31,7 @@ // allow exporting object with non-public remote interface permission java.rmi.RMIPermission "exportRemoteInterface.ActivateMe"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/downloadParameterClass/DownloadParameterClass.java --- a/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/DownloadParameterClass.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/DownloadParameterClass.java Fri Nov 11 16:44:36 2016 +0100 @@ -35,7 +35,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID ActivationLibrary + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider ActivationLibrary * Foo FooReceiverImpl FooReceiverImpl_Stub Bar * @run main/othervm/policy=security.policy/timeout=240 DownloadParameterClass */ @@ -90,7 +91,7 @@ try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/downloadParameterClass/manual.security.policy --- a/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/manual.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/manual.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -34,4 +34,7 @@ // allow exporting of remote objects on an arbitrary port. permission java.net.SocketPermission "*:1024-", "connect,accept,listen"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/downloadParameterClass/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -1,4 +1,6 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/downloadParameterClass/security.policy --- a/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -35,4 +35,7 @@ // allow exporting of remote objects on an arbitrary port. permission java.net.SocketPermission "*:1024-", "connect,accept,listen"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/ElucidateNoSuchMethod.java --- a/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/ElucidateNoSuchMethod.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/ElucidateNoSuchMethod.java Fri Nov 11 16:44:36 2016 +0100 @@ -31,7 +31,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID ActivateMe ElucidateNoSuchMethod_Stub + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider ActivateMe ElucidateNoSuchMethod_Stub * @run main/othervm/policy=security.policy/timeout=240 ElucidateNoSuchMethod */ @@ -91,7 +92,7 @@ try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -1,4 +1,7 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/security.policy --- a/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -37,4 +37,7 @@ // allow exporting of remote objects on an arbitrary port. permission java.net.SocketPermission "*:1024-", "connect,accept,listen"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ExtLoadedImplTest.java --- a/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ExtLoadedImplTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ExtLoadedImplTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -37,7 +37,7 @@ try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); Properties p = new Properties(); p.put("java.security.policy", diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh --- a/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh Fri Nov 11 16:44:36 2016 +0100 @@ -27,7 +27,7 @@ # loader, the context class loader should remain unchanged (i.e., not be # set to the impl's class loader) when the impl is activated. # @library ../../../testlibrary -# @build TestLibrary RMID ActivationLibrary +# @build TestLibrary RMID RMIDSelectorProvider ActivationLibrary # @build ExtLoadedImplTest ExtLoadedImpl ExtLoadedImpl_Stub CheckLoader # @run shell ext.sh diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/ForceLogSnapshot.java --- a/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/ForceLogSnapshot.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/ForceLogSnapshot.java Fri Nov 11 16:44:36 2016 +0100 @@ -31,7 +31,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID ActivationLibrary + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider ActivationLibrary * ActivateMe ForceLogSnapshot_Stub * @run main/othervm/policy=security.policy/timeout=640 ForceLogSnapshot */ @@ -129,7 +130,7 @@ SNAPSHOT_INTERVAL; RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.addOptions(new String[] {option, "-Djava.compiler="}); rmid.start(); diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -1,4 +1,6 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/security.policy --- a/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -31,4 +31,7 @@ // allow exporting object with non-public remote interface permission java.rmi.RMIPermission "exportRemoteInterface.ActivateMe"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/inactiveGroup/InactiveGroup.java --- a/jdk/test/java/rmi/activation/Activatable/inactiveGroup/InactiveGroup.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/inactiveGroup/InactiveGroup.java Fri Nov 11 16:44:36 2016 +0100 @@ -33,7 +33,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID ActivationLibrary ActivateMe InactiveGroup_Stub + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider ActivationLibrary ActivateMe InactiveGroup_Stub * @run main/othervm/policy=security.policy/timeout=240 InactiveGroup */ @@ -101,7 +102,7 @@ try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/inactiveGroup/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/inactiveGroup/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/inactiveGroup/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -1,4 +1,6 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/inactiveGroup/security.policy --- a/jdk/test/java/rmi/activation/Activatable/inactiveGroup/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/inactiveGroup/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -31,4 +31,7 @@ // allow exporting object with non-public remote interface permission java.rmi.RMIPermission "exportRemoteInterface.ActivateMe"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/lookupActivationSystem/LookupActivationSystem.java --- a/jdk/test/java/rmi/activation/Activatable/lookupActivationSystem/LookupActivationSystem.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/lookupActivationSystem/LookupActivationSystem.java Fri Nov 11 16:44:36 2016 +0100 @@ -33,7 +33,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID ActivationLibrary + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider ActivationLibrary * @run main/othervm/timeout=240 LookupActivationSystem */ @@ -55,7 +56,7 @@ try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); System.err.println("look up activation system"); diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/lookupActivationSystem/rmid.security.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/activation/Activatable/lookupActivationSystem/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,4 @@ +grant { + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; +}; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/nestedActivate/NestedActivate.java --- a/jdk/test/java/rmi/activation/Activatable/nestedActivate/NestedActivate.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/nestedActivate/NestedActivate.java Fri Nov 11 16:44:36 2016 +0100 @@ -31,7 +31,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID ActivationLibrary ActivateMe NestedActivate_Stub + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider ActivationLibrary ActivateMe NestedActivate_Stub * @run main/othervm/policy=security.policy/timeout=240 NestedActivate */ @@ -101,7 +102,7 @@ try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/nestedActivate/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/nestedActivate/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/nestedActivate/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -1,4 +1,6 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/nestedActivate/security.policy --- a/jdk/test/java/rmi/activation/Activatable/nestedActivate/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/nestedActivate/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -31,4 +31,7 @@ // allow exporting of non-public remote interface permission java.rmi.RMIPermission "exportRemoteInterface.ActivateMe"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/NonExistentActivatable.java --- a/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/NonExistentActivatable.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/NonExistentActivatable.java Fri Nov 11 16:44:36 2016 +0100 @@ -32,7 +32,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID ActivationLibrary + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider ActivationLibrary * ActivateMe NonExistentActivatable_Stub * @run main/othervm/policy=security.policy/timeout=240 NonExistentActivatable */ @@ -91,7 +92,7 @@ try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -1,4 +1,6 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/security.policy --- a/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -32,4 +32,6 @@ // allow exporting object with non-public remote interface permission java.rmi.RMIPermission "exportRemoteInterface.ActivateMe"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/restartCrashedService/RestartCrashedService.java --- a/jdk/test/java/rmi/activation/Activatable/restartCrashedService/RestartCrashedService.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/restartCrashedService/RestartCrashedService.java Fri Nov 11 16:44:36 2016 +0100 @@ -32,7 +32,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID ActivateMe RestartCrashedService_Stub + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider ActivateMe RestartCrashedService_Stub * @run main/othervm/policy=security.policy/timeout=240 RestartCrashedService */ @@ -119,7 +120,7 @@ try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/restartCrashedService/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/restartCrashedService/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/restartCrashedService/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -1,4 +1,6 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/restartCrashedService/security.policy --- a/jdk/test/java/rmi/activation/Activatable/restartCrashedService/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/restartCrashedService/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -28,4 +28,7 @@ // test needs to export rmid and communicate with objects on arbitrary ports permission java.net.SocketPermission "*:1024-", "connect,accept,listen"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/restartLatecomer/RestartLatecomer.java --- a/jdk/test/java/rmi/activation/Activatable/restartLatecomer/RestartLatecomer.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/restartLatecomer/RestartLatecomer.java Fri Nov 11 16:44:36 2016 +0100 @@ -31,7 +31,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID ActivationLibrary + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider ActivationLibrary * RestartLatecomer RestartLatecomer_Stub * @run main/othervm/policy=security.policy/timeout=240 RestartLatecomer */ @@ -166,7 +167,7 @@ try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/restartLatecomer/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/restartLatecomer/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/restartLatecomer/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -1,4 +1,6 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/restartLatecomer/security.policy --- a/jdk/test/java/rmi/activation/Activatable/restartLatecomer/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/restartLatecomer/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -33,4 +33,7 @@ // allow exporting of remote objects on an arbitrary port. permission java.net.SocketPermission "*:1024-", "connect,accept,listen"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/restartService/RestartService.java --- a/jdk/test/java/rmi/activation/Activatable/restartService/RestartService.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/restartService/RestartService.java Fri Nov 11 16:44:36 2016 +0100 @@ -32,7 +32,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID ActivationLibrary ActivateMe RestartService_Stub + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider ActivationLibrary ActivateMe RestartService_Stub * @run main/othervm/policy=security.policy/timeout=240 RestartService */ @@ -129,7 +130,7 @@ try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/restartService/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/restartService/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/restartService/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -1,4 +1,6 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/restartService/security.policy --- a/jdk/test/java/rmi/activation/Activatable/restartService/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/restartService/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -33,4 +33,7 @@ // allow exporting of remote objects on an arbitrary port. permission java.net.SocketPermission "*:1024-", "connect,accept,listen"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java --- a/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java Fri Nov 11 16:44:36 2016 +0100 @@ -32,7 +32,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider * TestSecurityManager RegisteringActivatable ShutdownGracefully_Stub * @run main/othervm/policy=security.policy/timeout=700 ShutdownGracefully */ @@ -76,7 +77,7 @@ // start an rmid. RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); // rmid needs to run with a security manager that // simulates a log problem; rmid should also snapshot diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/shutdownGracefully/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -2,4 +2,6 @@ permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=java.lang.SecurityManager"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; permission com.sun.rmi.rmid.ExecOptionPermission "-Ddummyname=dummyvalue"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/shutdownGracefully/security.policy --- a/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -25,4 +25,7 @@ // allow exporting of remote objects on an arbitrary port. permission java.net.SocketPermission "*:1024-", "connect,accept,listen"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/unregisterInactive/UnregisterInactive.java --- a/jdk/test/java/rmi/activation/Activatable/unregisterInactive/UnregisterInactive.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/unregisterInactive/UnregisterInactive.java Fri Nov 11 16:44:36 2016 +0100 @@ -32,7 +32,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID ActivationLibrary ActivateMe UnregisterInactive_Stub + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider ActivationLibrary ActivateMe UnregisterInactive_Stub * @run main/othervm/policy=security.policy/timeout=240 UnregisterInactive */ @@ -89,7 +90,7 @@ try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); System.err.println("Creating descriptor"); diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/unregisterInactive/rmid.security.policy --- a/jdk/test/java/rmi/activation/Activatable/unregisterInactive/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/unregisterInactive/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -1,4 +1,6 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/Activatable/unregisterInactive/security.policy --- a/jdk/test/java/rmi/activation/Activatable/unregisterInactive/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/Activatable/unregisterInactive/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -28,4 +28,7 @@ // allow exporting of remote objects on an arbitrary port. permission java.net.SocketPermission "*:1024-", "connect,accept,listen"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/ActivateFailedException/activateFails/ActivateFails.java --- a/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/ActivateFails.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/ActivateFails.java Fri Nov 11 16:44:36 2016 +0100 @@ -35,7 +35,8 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary RMID ActivationLibrary + * java.base/sun.nio.ch + * @build TestLibrary RMID RMIDSelectorProvider ActivationLibrary * ActivateMe ActivateFails_Stub ShutdownThread * @run main/othervm/java.security.policy=security.policy/timeout=240 ActivateFails */ @@ -93,7 +94,7 @@ * First run "rmid" and wait for it to start up. */ RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/ActivateFailedException/activateFails/rmid.security.policy --- a/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/rmid.security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/rmid.security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -1,4 +1,6 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=default"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/ActivateFailedException/activateFails/security.policy --- a/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/security.policy Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/security.policy Fri Nov 11 16:44:36 2016 +0100 @@ -28,4 +28,7 @@ // test needs to export rmid and communicate with objects on arbitrary ports permission java.net.SocketPermission "*:1024-", "connect,accept,listen"; + + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; }; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java --- a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java Fri Nov 11 16:44:36 2016 +0100 @@ -51,6 +51,8 @@ import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; +import static java.net.StandardSocketOptions.SO_REUSEADDR; +import static java.net.StandardSocketOptions.SO_REUSEPORT; public class RmidViaInheritedChannel implements Callback { private static final Object lock = new Object(); @@ -185,6 +187,15 @@ */ channel = ServerSocketChannel.open(); ServerSocket serverSocket = channel.socket(); + + // Enable SO_REUSEADDR before binding + serverSocket.setOption(SO_REUSEADDR, true); + + // Enable SO_REUSEPORT, if supported, before binding + if (serverSocket.supportedOptions().contains(SO_REUSEPORT)) { + serverSocket.setOption(SO_REUSEPORT, true); + } + serverSocket.bind( new InetSocketAddress(InetAddress.getLocalHost(), TestLibrary.RMIDVIAINHERITEDCHANNEL_ACTIVATION_PORT)); diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/testlibrary/JavaVM.java --- a/jdk/test/java/rmi/testlibrary/JavaVM.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/testlibrary/JavaVM.java Fri Nov 11 16:44:36 2016 +0100 @@ -21,8 +21,11 @@ * questions. */ +import java.io.BufferedReader; +import java.io.DataInputStream; import java.io.File; import java.io.IOException; +import java.io.InputStreamReader; import java.io.OutputStream; import java.util.Arrays; import java.util.StringTokenizer; @@ -39,8 +42,8 @@ protected Process vm = null; private String classname = ""; - private String args = ""; - private String options = ""; + protected String args = ""; + protected String options = ""; private OutputStream outputStream = System.out; private OutputStream errorStream = System.err; private String policyFileName = null; @@ -113,7 +116,7 @@ /** * Exec the VM as specified in this object's constructor. */ - public void start() throws IOException { + private void start0() throws IOException { if (vm != null) throw new IllegalStateException("JavaVM already started"); @@ -152,12 +155,50 @@ mesg("command = " + Arrays.asList(javaCommand).toString()); vm = Runtime.getRuntime().exec(javaCommand); + } - /* output from the execed process may optionally be captured. */ + public void start() throws IOException { + start0(); + + /* output from the exec'ed process may optionally be captured. */ outPipe = StreamPipe.plugTogether(vm.getInputStream(), this.outputStream); errPipe = StreamPipe.plugTogether(vm.getErrorStream(), this.errorStream); } + public int startAndGetPort() throws IOException { + start0(); + + int port = -1; + if (options.contains("java.nio.channels.spi.SelectorProvider=RMIDSelectorProvider")) { + // Obtain the server socket channel's ephemeral port number of the + // child rmid process. + BufferedReader reader = new BufferedReader( + new InputStreamReader(vm.getInputStream())); + String s; + while ((s = reader.readLine()) != null) { + System.out.println(s); + int i = s.indexOf(RMID.EPHEMERAL_MSG); + if (i != -1) { + String v = s.substring(RMID.EPHEMERAL_MSG.length()); + port = Integer.valueOf(v); + break; + } + } + if (port == -1) { + // something failed + reader = new BufferedReader(new InputStreamReader(vm.getErrorStream())); + while ((s = reader.readLine()) != null) + System.err.println(s); + } + } + + /* output from the exec'ed process may optionally be captured. */ + outPipe = StreamPipe.plugTogether(vm.getInputStream(), this.outputStream); + errPipe = StreamPipe.plugTogether(vm.getErrorStream(), this.errorStream); + + return port; + } + public void destroy() { if (vm != null) { vm.destroy(); diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/testlibrary/RMID.java --- a/jdk/test/java/rmi/testlibrary/RMID.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/testlibrary/RMID.java Fri Nov 11 16:44:36 2016 +0100 @@ -49,20 +49,31 @@ public static String MANAGER_OPTION="-Djava.security.manager="; - /** Test port for rmid */ - private final int port; + /** + * Test port for rmid. + * + * May initially be 0, which means that the child rmid process will choose + * an ephemeral port and report it back to the parent process. This field + * will then be set to the child rmid's ephemeral port value. + */ + private volatile int port; + //private final boolean ephemeralPort /** Initial log name */ protected static String log = "log"; /** rmid's logfile directory; currently must be "." */ protected static String LOGDIR = "."; + /** The output message from the child rmid process that directly precedes + * the ephemeral port number.*/ + public static final String EPHEMERAL_MSG = "RmidSelectorProvider-listening-On:"; + private static void mesg(Object mesg) { System.err.println("RMID: " + mesg.toString()); } /** make test options and arguments */ - private static String makeOptions(boolean debugExec) { + private static String makeOptions(int port, boolean debugExec) { String options = " -Dsun.rmi.server.activation.debugExec=" + debugExec; @@ -87,6 +98,17 @@ // to avoid spurious timeouts on slow machines. options += " -Dsun.rmi.activation.execTimeout=60000"; + if (port == 0) { + // Ephemeral port, so have the rmid child process create the + // server socket channel and report its port number, over stdin. + options += " -classpath " + TestParams.testClassPath; + options += " --add-exports=java.base/sun.nio.ch=ALL-UNNAMED"; + options += " -Djava.nio.channels.spi.SelectorProvider=RMIDSelectorProvider"; + + // Disable redirection of System.err to /tmp + options += " -Dsun.rmi.server.activation.disableErrRedirect=true"; + } + return options; } @@ -107,7 +129,8 @@ String args = " -log " + (new File(LOGDIR, log)).getAbsolutePath(); - if (includePortArg) { + // 0 = ephemeral port, do not include an explicit port number + if (includePortArg && port != 0) { args += " -port " + port; } @@ -160,7 +183,7 @@ boolean debugExec, boolean includePortArg, int port) { - String options = makeOptions(debugExec); + String options = makeOptions(port, debugExec); String args = makeArgs(includePortArg, port); RMID rmid = new RMID("sun.rmi.server.Activation", options, args, out, err, port); @@ -169,6 +192,17 @@ return rmid; } + public static RMID createRMIDOnEphemeralPort() { + return createRMID(System.out, System.err, true, true, 0); + } + + public static RMID createRMIDOnEphemeralPort(OutputStream out, + OutputStream err, + boolean debugExec) + { + return createRMID(out, err, debugExec, true, 0); + } + /** * Private constructor. RMID instances should be created @@ -247,7 +281,10 @@ // a well recognized exception (port already in use...). mesg("Starting rmid on port " + port + "."); - super.start(); + int p = super.startAndGetPort(); + if (p != -1) + port = p; + mesg("Started rmid on port " + port + "."); // int slopFactor = 1; // try { @@ -271,8 +308,11 @@ try { int status = vm.exitValue(); + waitFor(TIMEOUT_SHUTDOWN_MS); TestLibrary.bomb("Rmid process exited with status " + status + " after " + (System.currentTimeMillis() - startTime) + "ms."); + } catch (InterruptedException | TimeoutException e) { + mesg(e); } catch (IllegalThreadStateException ignore) { } // The rmid process is alive; check to see whether @@ -307,6 +347,8 @@ */ public void restart() throws IOException { destroy(); + options = makeOptions(port, true); + args = makeArgs(true, port); start(); } diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/testlibrary/RMIDSelectorProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/testlibrary/RMIDSelectorProvider.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.*; +import java.net.InetSocketAddress; +import java.net.ProtocolFamily; +import java.nio.channels.Channel; +import java.nio.channels.DatagramChannel; +import java.nio.channels.Pipe; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.nio.channels.spi.AbstractSelector; +import java.nio.channels.spi.SelectorProvider; +import static java.net.StandardSocketOptions.SO_REUSEADDR; +import static java.net.StandardSocketOptions.SO_REUSEPORT; + +/** + * A SelectorProvider, that can be loaded by the child rmid process, whose + * inheritedChannel method will create a new server socket channel and report + * it back to the parent process, over stdout. + */ +public class RMIDSelectorProvider extends SelectorProvider { + + private final SelectorProvider provider; + private ServerSocketChannel channel; + + public RMIDSelectorProvider() { + provider = sun.nio.ch.DefaultSelectorProvider.create(); + } + + public DatagramChannel openDatagramChannel() + throws IOException + { + return provider.openDatagramChannel(); + } + + public DatagramChannel openDatagramChannel(ProtocolFamily family) + throws IOException + { + return provider.openDatagramChannel(family); + } + + public Pipe openPipe() + throws IOException + { + return provider.openPipe(); + } + + public AbstractSelector openSelector() + throws IOException + { + return provider.openSelector(); + } + + public ServerSocketChannel openServerSocketChannel() + throws IOException + { + return provider.openServerSocketChannel(); + } + + public SocketChannel openSocketChannel() + throws IOException + { + return provider.openSocketChannel(); + } + + public synchronized Channel inheritedChannel() throws IOException { + System.out.println("RMIDSelectorProvider.inheritedChannel"); + if (channel == null) { + // Create and bind a new server socket channel + channel = ServerSocketChannel.open(); + + // Enable SO_REUSEADDR before binding + channel.setOption(SO_REUSEADDR, true); + + // Enable SO_REUSEPORT, if supported, before binding + if (channel.supportedOptions().contains(SO_REUSEPORT)) { + channel.setOption(SO_REUSEPORT, true); + } + + channel.bind(new InetSocketAddress(0)); + + System.out.println(RMID.EPHEMERAL_MSG + channel.socket().getLocalPort()); + } + return channel; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/rmi/testlibrary/TestParams.java --- a/jdk/test/java/rmi/testlibrary/TestParams.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/rmi/testlibrary/TestParams.java Fri Nov 11 16:44:36 2016 +0100 @@ -34,6 +34,7 @@ /** variables that hold value property values */ public static final String testSrc; public static final String testClasses; + public static final String testClassPath; /** name of default security policy for test JVM */ public static final String defaultPolicy; @@ -57,6 +58,7 @@ static { testSrc = TestLibrary.getProperty("test.src", "."); testClasses = TestLibrary.getProperty("test.classes", "."); + testClassPath = TestLibrary.getProperty("test.class.path", "."); String dp = TestLibrary.getProperty("java.security.policy", null); if (dp == null) { diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/security/misc/GetInstanceNullsEmpties.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/security/misc/GetInstanceNullsEmpties.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,696 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.security.*; +import java.security.cert.*; +import javax.crypto.*; +import javax.net.ssl.*; +import javax.security.auth.login.*; +import java.lang.reflect.*; +import java.util.Arrays; + +/* + * @test + * @bug 4985694 + * @summary Incomplete spec for most of the getInstances + */ +/** + * A simple test to see what is being thrown when null Strings are passed + * to the various getInstance() methods. + * + * These tests use various algorithm names that don't exist (e.g. "FOO" + * Ciphers). Just need something non-null for testing, as the tests will throw + * exceptions before trying to instantiate a real object. + */ +public class GetInstanceNullsEmpties { + + private static final Provider SUN = Security.getProvider("SUN"); + + /* + * See if there are more than "expected" number of getInstance() methods, + * which will indicate to developers that this test needs an update. + */ + private static void checkNewMethods(Class clazz, int expected) + throws Exception { + + long found = Arrays.stream(clazz.getMethods()) + .filter(name -> name.getName().equals("getInstance")) + .count(); + + if (found != expected) { + throw new Exception("Number of getInstance() mismatch: " + + expected + " expected, " + found + " found"); + } + } + + /** + * Main loop. + */ + public static void main(String[] args) throws Exception { + + /* + * JCA + */ + testAlgorithmParameterGenerator(); + testAlgorithmParameters(); + testCertificateFactory(); + testCertPathBuilder(); + testCertPathValidator(); + testCertStore(); + testKeyFactory(); + testKeyPairGenerator(); + testKeyStore(); + testMessageDigest(); + testPolicy(); + testSecureRandom(); + testSignature(); + + /* + * JCE + */ + testCipher(); + testExemptionMechanism(); + testKeyAgreement(); + testKeyGenerator(); + testMac(); + testSecretKeyFactory(); + + /* + * JSSE + */ + testKeyManagerFactory(); + testSSLContext(); + testTrustManagerFactory(); + + /* + * JGSS + * + * KeyTab.getInstance doesn't take algorithm names, so we'll + * ignore this one. + */ + testConfiguration(); + + System.out.println("\nTEST PASSED!"); + } + + private static Method getInstance(Class clazz, Class... args) + throws Exception { + boolean firstPrinted = false; + + System.out.print("\n" + clazz.getName() + "("); + for (Class c : args) { + System.out.print(firstPrinted + ? ", " + c.getName() : c.getName()); + firstPrinted = true; + } + System.out.println("):"); + + return clazz.getMethod("getInstance", args); + } + + private static void run(Method m, Class expectedException, + Object... args) throws Exception { + + try { + m.invoke(null, args); + throw new Exception("Didn't throw exception"); + } catch (InvocationTargetException ite) { + Throwable root = ite.getCause(); + if (root instanceof Exception) { + Exception e = (Exception) root; + if (expectedException.isInstance(e)) { + System.out.print("OK "); + return; + } else { + System.out.println( + "Unexpected InvocationTargetException!"); + throw e; + } + } + throw ite; + } + } + + /* + * Constants so lines aren't so long. + */ + private static final Class STRING = String.class; + private static final Class PROVIDER = Provider.class; + + private static void testAlgorithmParameterGenerator() throws Exception { + Class clazz = AlgorithmParameterGenerator.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testAlgorithmParameters() throws Exception { + Class clazz = AlgorithmParameters.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testCertPathBuilder() throws Exception { + Class clazz = CertPathBuilder.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testCertPathValidator() throws Exception { + Class clazz = CertPathValidator.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testCertStore() throws Exception { + Class clazz = CertStore.class; + Method m; + CertStoreParameters csp = () -> null; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING, CertStoreParameters.class); + run(m, NullPointerException.class, (Object) null, csp); + run(m, NoSuchAlgorithmException.class, "", csp); + + m = getInstance(clazz, STRING, CertStoreParameters.class, STRING); + run(m, NullPointerException.class, null, csp, "SUN"); + run(m, NoSuchAlgorithmException.class, "", csp, "SUN"); + run(m, IllegalArgumentException.class, "FOO", csp, null); + run(m, IllegalArgumentException.class, "FOO", csp, ""); + + m = getInstance(clazz, STRING, CertStoreParameters.class, PROVIDER); + run(m, NullPointerException.class, null, csp, SUN); + run(m, NoSuchAlgorithmException.class, "", csp, SUN); + run(m, IllegalArgumentException.class, "FOO", csp, null); + } + + private static void testCertificateFactory() throws Exception { + Class clazz = CertificateFactory.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, CertificateException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, CertificateException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, CertificateException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testCipher() throws Exception { + Class clazz = Cipher.class; + Method m; + + checkNewMethods(clazz, 3); + + /* + * Note the Cipher API is spec'd to throw a NoSuchAlgorithmException + * for a null transformation. + */ + m = getInstance(clazz, STRING); + run(m, NoSuchAlgorithmException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NoSuchAlgorithmException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NoSuchAlgorithmException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testConfiguration() throws Exception { + Class clazz = Configuration.class; + Method m; + Configuration.Parameters cp = new Configuration.Parameters() { + }; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING, Configuration.Parameters.class); + run(m, NullPointerException.class, (Object) null, cp); + run(m, NoSuchAlgorithmException.class, "", cp); + + m = getInstance(clazz, STRING, Configuration.Parameters.class, STRING); + run(m, NullPointerException.class, null, cp, "SUN"); + run(m, NoSuchAlgorithmException.class, "", cp, "SUN"); + run(m, IllegalArgumentException.class, "FOO", cp, null); + run(m, IllegalArgumentException.class, "FOO", cp, ""); + + m = getInstance(clazz, STRING, Configuration.Parameters.class, + PROVIDER); + run(m, NullPointerException.class, null, cp, SUN); + run(m, NoSuchAlgorithmException.class, "", cp, SUN); + run(m, IllegalArgumentException.class, "FOO", cp, null); + } + + private static void testExemptionMechanism() throws Exception { + Class clazz = ExemptionMechanism.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testKeyAgreement() throws Exception { + Class clazz = KeyAgreement.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testKeyFactory() throws Exception { + Class clazz = KeyFactory.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testKeyGenerator() throws Exception { + Class clazz = KeyGenerator.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testKeyManagerFactory() throws Exception { + Class clazz = KeyManagerFactory.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testKeyPairGenerator() throws Exception { + Class clazz = KeyPairGenerator.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testKeyStore() throws Exception { + Class clazz = KeyStore.class; + Method m; + + /* + * There are actually two additional getInstance() methods with File + * as the first parameter. + */ + checkNewMethods(clazz, 5); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, KeyStoreException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, KeyStoreException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, KeyStoreException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testMac() throws Exception { + Class clazz = Mac.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testMessageDigest() throws Exception { + Class clazz = MessageDigest.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testPolicy() throws Exception { + Class clazz = Policy.class; + Method m; + Policy.Parameters pp = new Policy.Parameters() { + }; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING, Policy.Parameters.class); + run(m, NullPointerException.class, (Object) null, pp); + run(m, NoSuchAlgorithmException.class, "", pp); + + m = getInstance(clazz, STRING, Policy.Parameters.class, STRING); + run(m, NullPointerException.class, null, pp, "SUN"); + run(m, NoSuchAlgorithmException.class, "", pp, "SUN"); + run(m, IllegalArgumentException.class, "FOO", pp, null); + run(m, IllegalArgumentException.class, "FOO", pp, ""); + + m = getInstance(clazz, STRING, Policy.Parameters.class, PROVIDER); + run(m, NullPointerException.class, null, pp, SUN); + run(m, NoSuchAlgorithmException.class, "", pp, SUN); + run(m, IllegalArgumentException.class, "FOO", pp, null); + } + + private static void testSSLContext() throws Exception { + Class clazz = SSLContext.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testSecretKeyFactory() throws Exception { + Class clazz = SecretKeyFactory.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testSecureRandom() throws Exception { + Class clazz = SecureRandom.class; + Method m; + SecureRandomParameters srp = new SecureRandomParameters() { + }; + + checkNewMethods(clazz, 6); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + + m = getInstance(clazz, STRING, SecureRandomParameters.class); + run(m, NullPointerException.class, (Object) null, srp); + run(m, NoSuchAlgorithmException.class, "", srp); + + m = getInstance(clazz, STRING, SecureRandomParameters.class, STRING); + run(m, NullPointerException.class, null, srp, "SUN"); + run(m, NoSuchAlgorithmException.class, "", srp, "SUN"); + run(m, IllegalArgumentException.class, "FOO", srp, null); + run(m, IllegalArgumentException.class, "FOO", srp, ""); + + m = getInstance(clazz, STRING, SecureRandomParameters.class, PROVIDER); + run(m, NullPointerException.class, null, srp, SUN); + run(m, NoSuchAlgorithmException.class, "", srp, SUN); + run(m, IllegalArgumentException.class, "FOO", srp, null); + } + + private static void testSignature() throws Exception { + Class clazz = Signature.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } + + private static void testTrustManagerFactory() throws Exception { + Class clazz = TrustManagerFactory.class; + Method m; + + checkNewMethods(clazz, 3); + + m = getInstance(clazz, STRING); + run(m, NullPointerException.class, (Object) null); + run(m, NoSuchAlgorithmException.class, ""); + + m = getInstance(clazz, STRING, STRING); + run(m, NullPointerException.class, null, "SUN"); + run(m, NoSuchAlgorithmException.class, "", "SUN"); + run(m, IllegalArgumentException.class, "FOO", null); + run(m, IllegalArgumentException.class, "FOO", ""); + + m = getInstance(clazz, STRING, PROVIDER); + run(m, NullPointerException.class, null, SUN); + run(m, NoSuchAlgorithmException.class, "", SUN); + run(m, IllegalArgumentException.class, "FOO", null); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/security/testlibrary/Proc.java --- a/jdk/test/java/security/testlibrary/Proc.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/security/testlibrary/Proc.java Fri Nov 11 16:44:36 2016 +0100 @@ -243,16 +243,23 @@ // Starts the proc public Proc start() throws IOException { List cmd = new ArrayList<>(); + boolean hasModules; if (launcher != null) { cmd.add(launcher); + File base = new File(launcher).getParentFile().getParentFile(); + hasModules = new File(base, "modules").exists() || + new File(base, "jmods").exists(); } else { cmd.add(new File(new File(System.getProperty("java.home"), "bin"), "java").getPath()); + hasModules = true; } - Stream.of(jdk.internal.misc.VM.getRuntimeArguments()) - .filter(arg -> arg.startsWith("--add-exports=")) - .forEach(cmd::add); + if (hasModules) { + Stream.of(jdk.internal.misc.VM.getRuntimeArguments()) + .filter(arg -> arg.startsWith("--add-exports=")) + .forEach(cmd::add); + } Collections.addAll(cmd, splitProperty("test.vm.opts")); Collections.addAll(cmd, splitProperty("test.java.opts")); diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/Arrays/ParallelPrefix.java --- a/jdk/test/java/util/Arrays/ParallelPrefix.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/util/Arrays/ParallelPrefix.java Fri Nov 11 16:44:36 2016 +0100 @@ -26,7 +26,6 @@ * @summary unit test for Arrays.ParallelPrefix(). * @author Tristan Yan * @run testng ParallelPrefix - * @key intermittent */ import java.util.Arrays; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.java --- a/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. 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 @@ -89,7 +89,7 @@ String[] jresResult = new String[4]; if (jreSupportsLocale) { for (int i = 0; i < 4; i++) { - jresResult[i] = "sun.util.locale.provider."+classNames[i]; + jresResult[i] = "sun.text." + classNames[i]; } } diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.sh --- a/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.sh Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.sh Fri Nov 11 16:44:36 2016 +0100 @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 2016, Oracle and/or its affiliates. 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 @@ -23,6 +23,6 @@ # # # @test -# @bug 4052440 8062588 +# @bug 4052440 8062588 8165804 # @summary BreakIteratorProvider tests # @run shell ExecTest.sh foo BreakIteratorProviderTest diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/MyResources_ja_JP.properties --- a/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/MyResources_ja_JP.properties Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -# -# Copyright (c) 2015, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# This resource bundle is located at jdk/test/resources to demonstrate -# the unique package requirement is not applicable to .properties bundles. - -key=ja-JP: message diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_ja_JP.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_ja_JP.properties Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,27 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# This resource bundle is located at jdk/test/resources to demonstrate +# the unique package requirement is not applicable to .properties bundles. + +key=ja-JP: message diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesProvider.java --- a/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesProvider.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesProvider.java Fri Nov 11 16:44:36 2016 +0100 @@ -62,9 +62,7 @@ @Override protected String toBundleName(String baseName, Locale locale) { - // The resource bundle for Locale.JAPAN is loccated at jdk.test.resources - // in module "asiabundles". - String name = locale.equals(Locale.JAPAN) ? baseName : addRegion(baseName); + String name = addRegion(baseName); return Control.getControl(Control.FORMAT_DEFAULT).toBundleName(name, locale); } diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/Scanner/ScanTest.java --- a/jdk/test/java/util/Scanner/ScanTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/util/Scanner/ScanTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -24,7 +24,7 @@ /** * @test * @bug 4313885 4926319 4927634 5032610 5032622 5049968 5059533 6223711 6277261 6269946 6288823 - * 8072722 8139414 + * 8072722 8139414 8166261 * @summary Basic tests of java.util.Scanner methods * @key randomness * @modules jdk.localedata @@ -36,6 +36,7 @@ import java.nio.*; import java.text.*; import java.util.*; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.regex.*; import java.util.stream.*; @@ -79,6 +80,7 @@ resetTest(); streamCloseTest(); streamComodTest(); + outOfRangeRadixTest(); for (int j = 0; j < NUM_SOURCE_TYPES; j++) { hasNextTest(j); @@ -1509,6 +1511,48 @@ report("Reset test"); } + static List> methodWRList = Arrays.asList( + (s, r) -> s.hasNextByte(r), + (s, r) -> s.nextByte(r), + (s, r) -> s.hasNextShort(r), + (s, r) -> s.nextShort(r), + (s, r) -> s.hasNextInt(r), + (s, r) -> s.nextInt(r), + (s, r) -> s.hasNextLong(r), + (s, r) -> s.nextLong(r), + (s, r) -> s.hasNextBigInteger(r), + (s, r) -> s.nextBigInteger(r) + ); + + /* + * Test that setting the radix to an out of range value triggers + * an IllegalArgumentException + */ + public static void outOfRangeRadixTest() throws Exception { + int[] bad = new int[] { -1, 0, 1, 37, 38 }; + int[] good = IntStream.rangeClosed(Character.MIN_RADIX, Character.MAX_RADIX) + .toArray(); + + methodWRList.stream().forEach( m -> { + for (int r : bad) { + try (Scanner sc = new Scanner("10 10 10 10")) { + m.accept(sc, r); + failCount++; + } catch (IllegalArgumentException ise) {} + } + }); + methodWRList.stream().forEach( m -> { + for (int r : good) { + try (Scanner sc = new Scanner("10 10 10 10")) { + m.accept(sc, r); + } catch (Exception x) { + failCount++; + } + } + }); + report("Radix out of range test"); + } + /* * Test that closing the stream also closes the underlying Scanner. * The cases of attempting to open streams on a closed Scanner are diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/logging/LogManager/LinkageErrorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/logging/LogManager/LinkageErrorTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +/** + * @test 8152515 + * @summary Checks that LinkageError are ignored when closing handlers + * during Shutdown. + * @build LinkageErrorTest + * @run main/othervm LinkageErrorTest + */ + +public class LinkageErrorTest { + + public static class TestHandler extends Handler { + + private volatile boolean closed; + public TestHandler() { + INSTANCES.add(this); + } + + @Override + public void publish(LogRecord record) { + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + closed = true; + try { + System.out.println(INSTANCES); + } catch (Throwable t) { + // ignore + } + throw new LinkageError(); + } + + @Override + public String toString() { + return super.toString() + "{closed=" + closed + '}'; + } + + private static final CopyOnWriteArrayList INSTANCES + = new CopyOnWriteArrayList<>(); + } + + private static final Logger LOGGER = Logger.getLogger("test"); + private static final Logger GLOBAL = Logger.getGlobal(); + + public static void main(String[] args) { + LOGGER.addHandler(new TestHandler()); + LOGGER.addHandler(new TestHandler()); + GLOBAL.addHandler(new TestHandler()); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/stream/bootlib/java.base/java/util/stream/ThowableHelper.java --- a/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/ThowableHelper.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package java.util.stream; - -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - -public final class ThowableHelper { - - public static void checkException(Class ce, Runnable r) { - Exception caught = null; - try { - r.run(); - } catch (Exception e) { - caught = e; - } - - assertNotNull(caught); - assertTrue(ce.isInstance(caught)); - } - - public static void checkNPE(Runnable r) { - checkException(NullPointerException.class, r); - } - - public static void checkISE(Runnable r) { - checkException(IllegalStateException.class, r); - } -} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/stream/bootlib/java.base/java/util/stream/ThrowableHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/ThrowableHelper.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.stream; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +public final class ThrowableHelper { + + public static void checkException(Class ce, Runnable r) { + Exception caught = null; + try { + r.run(); + } catch (Exception e) { + caught = e; + } + + assertNotNull(caught); + assertTrue(ce.isInstance(caught)); + } + + public static void checkNPE(Runnable r) { + checkException(NullPointerException.class, r); + } + + public static void checkISE(Runnable r) { + checkException(IllegalStateException.class, r); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectAndSummaryStatisticsTest.java --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectAndSummaryStatisticsTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectAndSummaryStatisticsTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. 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 @@ -43,7 +43,7 @@ import java.util.stream.OpTestCase; import static java.util.stream.LambdaTestHelpers.countTo; -import static java.util.stream.ThowableHelper.checkNPE; +import static java.util.stream.ThrowableHelper.checkNPE; @Test public class CollectAndSummaryStatisticsTest extends OpTestCase { diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectionAndMapModifyStreamTest.java --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectionAndMapModifyStreamTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectionAndMapModifyStreamTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. 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 @@ -113,7 +113,7 @@ Map>> maps = new HashMap<>(); maps.put(HashMap.class.getName(), () -> new HashMap<>(content)); - maps.put(HashMap.class.getName(), () -> new LinkedHashMap<>(content)); + maps.put(LinkedHashMap.class.getName(), () -> new LinkedHashMap<>(content)); maps.put(IdentityHashMap.class.getName(), () -> new IdentityHashMap<>(content)); maps.put(WeakHashMap.class.getName(), () -> new WeakHashMap<>(content)); diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/FlatMapOpTest.java --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/FlatMapOpTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/FlatMapOpTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -49,7 +49,7 @@ import java.util.stream.TestData; import static java.util.stream.LambdaTestHelpers.*; -import static java.util.stream.ThowableHelper.checkNPE; +import static java.util.stream.ThrowableHelper.checkNPE; @Test public class FlatMapOpTest extends OpTestCase { diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IterateTest.java --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IterateTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IterateTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -38,7 +38,7 @@ import java.util.stream.TestData; import java.util.stream.TestData.Factory; -import static java.util.stream.ThowableHelper.checkNPE; +import static java.util.stream.ThrowableHelper.checkNPE; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamBuilderTest.java --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamBuilderTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamBuilderTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. 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 @@ -38,7 +38,7 @@ import java.util.stream.TestData; import static java.util.stream.Collectors.toList; -import static java.util.stream.ThowableHelper.checkISE; +import static java.util.stream.ThrowableHelper.checkISE; @Test public class StreamBuilderTest extends OpTestCase { diff -r f71b844f33d1 -r 95af45781076 jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamCloseTest.java --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamCloseTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamCloseTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -36,8 +36,8 @@ import org.testng.annotations.Test; import static java.util.stream.LambdaTestHelpers.countTo; -import static java.util.stream.ThowableHelper.checkNPE; -import static java.util.stream.ThowableHelper.checkISE; +import static java.util.stream.ThrowableHelper.checkNPE; +import static java.util.stream.ThrowableHelper.checkISE; @Test(groups = { "serialization-hostile" }) public class StreamCloseTest extends OpTestCase { diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/imageio/ImageCompressionTypesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/imageio/ImageCompressionTypesTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @bug 6294607 + * @summary Test verifies whether ImageWriteParam.getCompressionTypes() + * returns any duplicate compression type for ImageIO plugins. + * @run main ImageCompressionTypesTest + */ + +import java.util.Iterator; +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; + +public class ImageCompressionTypesTest { + + static ImageWriter writer = null; + + public ImageCompressionTypesTest(String format) { + Iterator it = ImageIO.getImageWritersByFormatName(format); + while (it.hasNext()) { + writer = (ImageWriter) it.next(); + break; + } + ImageWriteParam param = writer.getDefaultWriteParam(); + + param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + System.out.println("Checking compression types for : " + format); + String compTypes[] = param.getCompressionTypes(); + if (compTypes.length > 1) { + for (int i = 0; i < compTypes.length; i++) { + for (int j = i + 1; j < compTypes.length; j++) { + if (compTypes[i].equalsIgnoreCase(compTypes[j])) { + throw new RuntimeException("Duplicate compression" + + " type exists for image format " + format); + } + } + } + } + } + + public static void main(String args[]) { + final String[] formats = {"bmp", "png", "gif", "jpg", "tiff"}; + for (String format : formats) { + new ImageCompressionTypesTest(format); + } + } +} + diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/imageio/metadata/GetElementsByTagNameTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/imageio/metadata/GetElementsByTagNameTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8167281 + * @summary Test verifies that Element.getElementsByTagName("*") is not empty + * for valid image. + * @run main GetElementsByTagNameTest + */ + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.metadata.IIOMetadataFormatImpl; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.MemoryCacheImageInputStream; +import org.w3c.dom.Element; + +public class GetElementsByTagNameTest { + + public static void main(String[] args) throws IOException { + // Generate some trivial image and save it to a temporary array + ByteArrayOutputStream tmp = new ByteArrayOutputStream(); + ImageIO.write(new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB), + "gif", tmp); + + // Read the stream + ImageInputStream in = new MemoryCacheImageInputStream( + new ByteArrayInputStream(tmp.toByteArray())); + ImageReader reader = ImageIO.getImageReaders(in).next(); + reader.setInput(in); + + // Retrieve standard image metadata tree + IIOMetadata meta = reader.getImageMetadata(0); + if (meta == null || !meta.isStandardMetadataFormatSupported()) { + throw new Error("Test failure: Missing metadata"); + } + Element root = (Element) meta. + getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName); + + // Test getElementsByTagName("*") + if (root.getElementsByTagName("*").getLength() == 0) { + throw new RuntimeException("getElementsByTagName(\"*\") returns" + + " nothing"); + } + } +} + diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/imageio/metadata/NthItemNodeListTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/imageio/metadata/NthItemNodeListTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8167281 + * @summary Test verifies that accessing nth item in NodeList doesn't throw + * IndexOutOfBoundsException. + * @run main NthItemNodeListTest + */ + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.metadata.IIOMetadataFormatImpl; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.MemoryCacheImageInputStream; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class NthItemNodeListTest { + + public static void main(String[] args) throws IOException { + // Generate some trivial image and save it to a temporary array + ByteArrayOutputStream tmp = new ByteArrayOutputStream(); + ImageIO.write(new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB), + "gif", tmp); + + // Read it back in + ImageInputStream in = new MemoryCacheImageInputStream( + new ByteArrayInputStream(tmp.toByteArray())); + ImageReader reader = ImageIO.getImageReaders(in).next(); + reader.setInput(in); + + // Retrieve standard image metadata tree + IIOMetadata meta = reader.getImageMetadata(0); + if (meta == null || !meta.isStandardMetadataFormatSupported()) { + throw new Error("Test failure: Missing metadata"); + } + Element root = (Element) meta. + getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName); + + NodeList nodeList = root. + getElementsByTagName(root.getFirstChild().getNodeName()); + /* + * Accessing the nth node should return null and not throw + * IndexOutOfBoundsException. + */ + Node n = (nodeList.item(nodeList.getLength())); + } +} + diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java --- a/jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java Fri Nov 11 16:44:36 2016 +0100 @@ -48,10 +48,6 @@ */ public class DTLSOverDatagram { - static { - System.setProperty("javax.net.debug", "ssl"); - } - private static int MAX_HANDSHAKE_LOOPS = 200; private static int MAX_APP_READ_LOOPS = 60; private static int SOCKET_TIMEOUT = 10 * 1000; // in millis @@ -160,6 +156,7 @@ } SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus(); + log(side, "=======handshake(" + loops + ", " + hs + ")======="); if (hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP || hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN) { @@ -239,6 +236,7 @@ boolean finished = produceHandshakePackets( engine, peerAddr, side, packets); + log(side, "Produced " + packets.size() + " packets"); for (DatagramPacket p : packets) { socket.send(p); } @@ -252,14 +250,16 @@ } else if (hs == SSLEngineResult.HandshakeStatus.NEED_TASK) { runDelegatedTasks(engine); } else if (hs == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { - log(side, "Handshake status is NOT_HANDSHAKING, finish the loop"); + log(side, + "Handshake status is NOT_HANDSHAKING, finish the loop"); endLoops = true; } else if (hs == SSLEngineResult.HandshakeStatus.FINISHED) { throw new Exception( "Unexpected status, SSLEngine.getHandshakeStatus() " + "shouldn't return FINISHED"); } else { - throw new Exception("Can't reach here, handshake status is " + hs); + throw new Exception( + "Can't reach here, handshake status is " + hs); } } @@ -279,7 +279,9 @@ log(side, "Negotiated cipher suite is " + session.getCipherSuite()); // handshake status should be NOT_HANDSHAKING - // according to the spec, SSLEngine.getHandshakeStatus() can't return FINISHED + // + // According to the spec, SSLEngine.getHandshakeStatus() can't + // return FINISHED. if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { throw new Exception("Unexpected handshake status " + hs); } @@ -348,13 +350,16 @@ SSLEngineResult.Status rs = r.getStatus(); SSLEngineResult.HandshakeStatus hs = r.getHandshakeStatus(); + log(side, "====packet(" + loops + ", " + rs + ", " + hs + ")===="); if (rs == SSLEngineResult.Status.BUFFER_OVERFLOW) { // the client maximum fragment size config does not work? throw new Exception("Buffer overflow: " + "incorrect server maximum fragment size"); } else if (rs == SSLEngineResult.Status.BUFFER_UNDERFLOW) { - log(side, "Produce handshake packets: BUFFER_UNDERFLOW occured"); - log(side, "Produce handshake packets: Handshake status: " + hs); + log(side, + "Produce handshake packets: BUFFER_UNDERFLOW occured"); + log(side, + "Produce handshake packets: Handshake status: " + hs); // bad packet, or the client maximum fragment size // config does not work? if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { @@ -453,6 +458,53 @@ return packets; } + // Get a datagram packet for the specified handshake type. + static DatagramPacket getPacket( + List packets, byte handshakeType) { + boolean matched = false; + for (DatagramPacket packet : packets) { + byte[] data = packet.getData(); + int offset = packet.getOffset(); + int length = packet.getLength(); + + // Normally, this pakcet should be a handshake message + // record. However, even if the underlying platform + // splits the record more, we don't really worry about + // the improper packet loss because DTLS implementation + // should be able to handle packet loss properly. + // + // See RFC 6347 for the detailed format of DTLS records. + if (handshakeType == -1) { // ChangeCipherSpec + // Is it a ChangeCipherSpec message? + matched = (length == 14) && (data[offset] == 0x14); + } else if ((length >= 25) && // 25: handshake mini size + (data[offset] == 0x16)) { // a handshake message + + // check epoch number for initial handshake only + if (data[offset + 3] == 0x00) { // 3,4: epoch + if (data[offset + 4] == 0x00) { // plaintext + matched = + (data[offset + 13] == handshakeType); + } else { // cipherext + // The 1st ciphertext is a Finished message. + // + // If it is not proposed to loss the Finished + // message, it is not necessary to check the + // following packets any mroe as a Finished + // message is the last handshake message. + matched = (handshakeType == 20); + } + } + } + + if (matched) { + return packet; + } + } + + return null; + } + // run delegated tasks void runDelegatedTasks(SSLEngine engine) throws Exception { Runnable runnable; diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/net/ssl/DTLS/PacketLossRetransmission.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/PacketLossRetransmission.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. + +/* + * @test + * @bug 8161086 + * @summary DTLS handshaking fails if some messages were lost + * @modules java.base/sun.security.util + * @build DTLSOverDatagram + * + * @run main/othervm PacketLossRetransmission client 0 hello_request + * @run main/othervm PacketLossRetransmission client 1 client_hello + * @run main/othervm PacketLossRetransmission client 2 server_hello + * @run main/othervm PacketLossRetransmission client 3 hello_verify_request + * @run main/othervm PacketLossRetransmission client 4 new_session_ticket + * @run main/othervm PacketLossRetransmission client 11 certificate + * @run main/othervm PacketLossRetransmission client 12 server_key_exchange + * @run main/othervm PacketLossRetransmission client 13 certificate_request + * @run main/othervm PacketLossRetransmission client 14 server_hello_done + * @run main/othervm PacketLossRetransmission client 15 certificate_verify + * @run main/othervm PacketLossRetransmission client 16 client_key_exchange + * @run main/othervm PacketLossRetransmission client 20 finished + * @run main/othervm PacketLossRetransmission client 21 certificate_url + * @run main/othervm PacketLossRetransmission client 22 certificate_status + * @run main/othervm PacketLossRetransmission client 23 supplemental_data + * @run main/othervm PacketLossRetransmission client -1 change_cipher_spec + * @run main/othervm PacketLossRetransmission server 0 hello_request + * @run main/othervm PacketLossRetransmission server 1 client_hello + * @run main/othervm PacketLossRetransmission server 2 server_hello + * @run main/othervm PacketLossRetransmission server 3 hello_verify_request + * @run main/othervm PacketLossRetransmission server 4 new_session_ticket + * @run main/othervm PacketLossRetransmission server 11 certificate + * @run main/othervm PacketLossRetransmission server 12 server_key_exchange + * @run main/othervm PacketLossRetransmission server 13 certificate_request + * @run main/othervm PacketLossRetransmission server 14 server_hello_done + * @run main/othervm PacketLossRetransmission server 15 certificate_verify + * @run main/othervm PacketLossRetransmission server 16 client_key_exchange + * @run main/othervm PacketLossRetransmission server 20 finished + * @run main/othervm PacketLossRetransmission server 21 certificate_url + * @run main/othervm PacketLossRetransmission server 22 certificate_status + * @run main/othervm PacketLossRetransmission server 23 supplemental_data + * @run main/othervm PacketLossRetransmission server -1 change_cipher_spec + */ + +import java.util.List; +import java.util.ArrayList; +import java.net.DatagramPacket; +import java.net.SocketAddress; +import javax.net.ssl.SSLEngine; + +/** + * Test that DTLS implementation is able to do retransmission internally + * automatically if packet get lost. + */ +public class PacketLossRetransmission extends DTLSOverDatagram { + private static boolean isClient; + private static byte handshakeType; + + private boolean needPacketLoss = true; + + public static void main(String[] args) throws Exception { + isClient = args[0].equals("client"); + handshakeType = Byte.valueOf(args[1]); + + PacketLossRetransmission testCase = new PacketLossRetransmission(); + testCase.runTest(testCase); + } + + @Override + boolean produceHandshakePackets(SSLEngine engine, SocketAddress socketAddr, + String side, List packets) throws Exception { + + boolean finished = super.produceHandshakePackets( + engine, socketAddr, side, packets); + + if (needPacketLoss && (!(isClient ^ engine.getUseClientMode()))) { + DatagramPacket packet = getPacket(packets, handshakeType); + if (packet != null) { + needPacketLoss = false; + + System.out.println("Loss a packet of handshake messahe"); + packets.remove(packet); + } + } + + return finished; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/net/ssl/DTLS/RespondToRetransmit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/RespondToRetransmit.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. + +/* + * @test + * @bug 8161086 + * @summary DTLS handshaking fails if some messages were lost + * @modules java.base/sun.security.util + * @build DTLSOverDatagram + * + * @run main/othervm RespondToRetransmit client 0 hello_request + * @run main/othervm RespondToRetransmit client 1 client_hello + * @run main/othervm RespondToRetransmit client 2 server_hello + * @run main/othervm RespondToRetransmit client 3 hello_verify_request + * @run main/othervm RespondToRetransmit client 4 new_session_ticket + * @run main/othervm RespondToRetransmit client 11 certificate + * @run main/othervm RespondToRetransmit client 12 server_key_exchange + * @run main/othervm RespondToRetransmit client 13 certificate_request + * @run main/othervm RespondToRetransmit client 14 server_hello_done + * @run main/othervm RespondToRetransmit client 15 certificate_verify + * @run main/othervm RespondToRetransmit client 16 client_key_exchange + * @run main/othervm RespondToRetransmit client 20 finished + * @run main/othervm RespondToRetransmit client 21 certificate_url + * @run main/othervm RespondToRetransmit client 22 certificate_status + * @run main/othervm RespondToRetransmit client 23 supplemental_data + * @run main/othervm RespondToRetransmit client -1 change_cipher_spec + * @run main/othervm RespondToRetransmit server 0 hello_request + * @run main/othervm RespondToRetransmit server 1 client_hello + * @run main/othervm RespondToRetransmit server 2 server_hello + * @run main/othervm RespondToRetransmit server 3 hello_verify_request + * @run main/othervm RespondToRetransmit server 4 new_session_ticket + * @run main/othervm RespondToRetransmit server 11 certificate + * @run main/othervm RespondToRetransmit server 12 server_key_exchange + * @run main/othervm RespondToRetransmit server 13 certificate_request + * @run main/othervm RespondToRetransmit server 14 server_hello_done + * @run main/othervm RespondToRetransmit server 15 certificate_verify + * @run main/othervm RespondToRetransmit server 16 client_key_exchange + * @run main/othervm RespondToRetransmit server 20 finished + * @run main/othervm RespondToRetransmit server 21 certificate_url + * @run main/othervm RespondToRetransmit server 22 certificate_status + * @run main/othervm RespondToRetransmit server 23 supplemental_data + * @run main/othervm RespondToRetransmit server -1 change_cipher_spec + */ + +import java.util.List; +import java.util.ArrayList; +import java.net.DatagramPacket; +import java.net.SocketAddress; +import javax.net.ssl.SSLEngine; + +/** + * Test that DTLS implementation is able to do retransmission internally + * automatically if packet get lost. + */ +public class RespondToRetransmit extends DTLSOverDatagram { + private static boolean isClient; + private static byte handshakeType; + + private boolean needPacketDuplicate = true; + + public static void main(String[] args) throws Exception { + isClient = args[0].equals("client"); + handshakeType = Byte.valueOf(args[1]); + + RespondToRetransmit testCase = new RespondToRetransmit(); + testCase.runTest(testCase); + } + + @Override + boolean produceHandshakePackets(SSLEngine engine, SocketAddress socketAddr, + String side, List packets) throws Exception { + + boolean finished = super.produceHandshakePackets( + engine, socketAddr, side, packets); + + if (needPacketDuplicate && (!(isClient ^ engine.getUseClientMode()))) { + DatagramPacket packet = getPacket(packets, handshakeType); + if (packet != null) { + needPacketDuplicate = false; + + System.out.println("Duplicate the flight."); + List duplicates = new ArrayList<>(); + finished = super.produceHandshakePackets( + engine, socketAddr, side, duplicates); + packets.addAll(duplicates); + } + } + + return finished; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/net/ssl/SSLEngine/EngineCloseOnAlert.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/net/ssl/SSLEngine/EngineCloseOnAlert.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8133632 + * @summary javax.net.ssl.SSLEngine does not properly handle received + * SSL fatal alerts + * @run main/othervm EngineCloseOnAlert + */ + +import java.io.FileInputStream; +import java.io.IOException; +import javax.net.ssl.*; +import java.nio.ByteBuffer; +import java.util.*; +import java.security.*; +import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*; + +public class EngineCloseOnAlert { + + private static final String pathToStores = "../etc"; + private static final String keyStoreFile = "keystore"; + private static final String trustStoreFile = "truststore"; + private static final String passwd = "passphrase"; + private static final String keyFilename = + System.getProperty("test.src", ".") + "/" + pathToStores + + "/" + keyStoreFile; + private static final String trustFilename = + System.getProperty("test.src", ".") + "/" + pathToStores + + "/" + trustStoreFile; + + private static KeyManagerFactory KMF; + private static TrustManagerFactory TMF; + private static TrustManagerFactory EMPTY_TMF; + + private static final String[] TLS10ONLY = { "TLSv1" }; + private static final String[] TLS12ONLY = { "TLSv1.2" }; + private static final String[] ONECIPHER = + { "TLS_RSA_WITH_AES_128_CBC_SHA" }; + + public interface TestCase { + public void runTest() throws Exception; + } + + public static void main(String[] args) throws Exception { + int failed = 0; + List testMatrix = new LinkedList() {{ + add(clientReceivesAlert); + add(serverReceivesAlert); + }}; + + // Create the various key/trust manager factories we'll need + createManagerFactories(); + + for (TestCase test : testMatrix) { + try { + test.runTest(); + } catch (Exception e) { + System.out.println("Exception in test:\n" + e); + e.printStackTrace(System.out); + failed++; + } + } + + System.out.println("Total tests: " + testMatrix.size() + ", passed: " + + (testMatrix.size() - failed) + ", failed: " + failed); + if (failed > 0) { + throw new RuntimeException("One or more tests failed."); + } + } + + private static final TestCase clientReceivesAlert = new TestCase() { + @Override + public void runTest() throws Exception { + System.out.println(""); + System.out.println("======================================="); + System.out.println("Test: Client receives alert from server"); + System.out.println("======================================="); + + // For this test, we won't initialize any keystore so the + // server will throw an exception because it has no key/cert to + // match the requested ciphers offered by the client. This + // will generate an alert from the server to the client. + + SSLContext context = SSLContext.getDefault(); + SSLEngine client = context.createSSLEngine(); + SSLEngine server = context.createSSLEngine(); + client.setUseClientMode(true); + server.setUseClientMode(false); + SSLEngineResult clientResult; + SSLEngineResult serverResult; + + ByteBuffer raw = ByteBuffer.allocate(32768); + ByteBuffer plain = ByteBuffer.allocate(32768); + + // Generate the client hello and have the server unwrap it + client.wrap(plain, raw); + checkEngineState(client, NEED_UNWRAP, false, false); + raw.flip(); + System.out.println("Client-to-Server:\n-----------------\n" + + dumpHexBytes(raw, 16, "\n", ":")); + + + // The server should need to run a delegated task while processing + // the client hello data. + serverResult = server.unwrap(raw, plain); + checkEngineState(server, NEED_TASK, false, false); + System.out.println("Server result: " + serverResult); + runDelegatedTasks(serverResult, server); + checkEngineState(server, NEED_WRAP, true, false); + + try { + raw.clear(); + serverResult = server.wrap(plain, raw); + System.out.println("Server result: " + serverResult); + runDelegatedTasks(serverResult, server); + } catch (SSLException e) { + // This is the expected code path + System.out.println("Server throws exception: " + e); + System.out.println("Server engine state: " + + "isInboundDone = "+ server.isInboundDone() + + ", isOutboundDone = " + server.isOutboundDone() + + ", handshake status = " + server.getHandshakeStatus()); + checkEngineState(server, NEED_WRAP, true, false); + } + raw.clear(); + + // The above should show that isInboundDone returns true, and + // handshake status is NEED_WRAP. That is the correct behavior, + // wrap will put a fatal alert message in the buffer. + serverResult = server.wrap(plain, raw); + System.out.println("Server result (wrap after exception): " + + serverResult); + System.out.println("Server engine closure state: isInboundDone=" + + server.isInboundDone() + ", isOutboundDone=" + + server.isOutboundDone()); + checkEngineState(server, NEED_UNWRAP, true, true); + raw.flip(); + + System.out.println("Server-to-Client:\n-----------------\n" + + dumpHexBytes(raw, 16, "\n", ":")); + + // Client side will read the fatal alert and throw exception. + try { + clientResult = client.unwrap(raw, plain); + System.out.println("Client result (unwrap alert): " + + clientResult); + } catch (SSLException e) { + System.out.println("Client throws exception: " + e); + System.out.println("Engine closure status: isInboundDone=" + + client.isInboundDone() + ", isOutboundDone=" + + client.isOutboundDone() + ", handshake status=" + + client.getHandshakeStatus()); + checkEngineState(client, NOT_HANDSHAKING, true, true); + } + raw.clear(); + + // Last test, we try to unwrap + clientResult = client.unwrap(raw, plain); + checkEngineState(client, NOT_HANDSHAKING, true, true); + System.out.println("Client result (wrap after exception): " + + clientResult); + } + }; + + private static final TestCase serverReceivesAlert = new TestCase() { + @Override + public void runTest() throws Exception { + SSLContext cliContext = SSLContext.getDefault(); + SSLContext servContext = SSLContext.getInstance("TLS"); + servContext.init(KMF.getKeyManagers(), TMF.getTrustManagers(), + null); + SSLEngine client = cliContext.createSSLEngine(); + SSLEngine server = servContext.createSSLEngine(); + client.setUseClientMode(true); + client.setEnabledProtocols(TLS12ONLY); + client.setEnabledCipherSuites(ONECIPHER); + server.setUseClientMode(false); + server.setEnabledProtocols(TLS10ONLY); + SSLEngineResult clientResult; + SSLEngineResult serverResult; + ByteBuffer raw = ByteBuffer.allocate(32768); + ByteBuffer plain = ByteBuffer.allocate(32768); + + System.out.println(""); + System.out.println("======================================="); + System.out.println("Test: Server receives alert from client"); + System.out.println("======================================="); + + // Generate the client hello and have the server unwrap it + checkEngineState(client, NOT_HANDSHAKING, false, false); + client.wrap(plain, raw); + checkEngineState(client, NEED_UNWRAP, false, false); + raw.flip(); + System.out.println("Client-to-Server:\n-----------------\n" + + dumpHexBytes(raw, 16, "\n", ":")); + + // The server should need to run a delegated task while processing + // the client hello data. + serverResult = server.unwrap(raw, plain); + checkEngineState(server, NEED_TASK, false, false); + runDelegatedTasks(serverResult, server); + checkEngineState(server, NEED_WRAP, false, false); + raw.compact(); + + // The server should now wrap the response back to the client + server.wrap(plain, raw); + checkEngineState(server, NEED_UNWRAP, false, false); + raw.flip(); + System.out.println("Server-to-Client:\n-----------------\n" + + dumpHexBytes(raw, 16, "\n", ":")); + + // The client should parse this and throw an exception because + // It is unwiling to do TLS 1.0 + clientResult = client.unwrap(raw, plain); + checkEngineState(client, NEED_TASK, false, false); + runDelegatedTasks(clientResult, client); + checkEngineState(client, NEED_UNWRAP, false, false); + + try { + client.unwrap(raw, plain); + } catch (SSLException e) { + System.out.println("Client throws exception: " + e); + System.out.println("Engine closure status: isInboundDone=" + + client.isInboundDone() + ", isOutboundDone=" + + client.isOutboundDone() + ", handshake status=" + + client.getHandshakeStatus()); + checkEngineState(client, NEED_WRAP, true, false); + } + raw.clear(); + + // Now the client should wrap the exception + client.wrap(plain, raw); + checkEngineState(client, NEED_UNWRAP, true, true); + raw.flip(); + System.out.println("Client-to-Server:\n-----------------\n" + + dumpHexBytes(raw, 16, "\n", ":")); + + try { + server.unwrap(raw, plain); + checkEngineState(server, NEED_UNWRAP, false, false); + } catch (SSLException e) { + System.out.println("Server throws exception: " + e); + System.out.println("Engine closure status: isInboundDone=" + + server.isInboundDone() + ", isOutboundDone=" + + server.isOutboundDone() + ", handshake status=" + + server.getHandshakeStatus()); + checkEngineState(server, NOT_HANDSHAKING, true, true); + } + raw.clear(); + } + }; + + + /* + * If the result indicates that we have outstanding tasks to do, + * go ahead and run them in this thread. + */ + private static void runDelegatedTasks(SSLEngineResult result, + SSLEngine engine) throws Exception { + + if (result.getHandshakeStatus() == + SSLEngineResult.HandshakeStatus.NEED_TASK) { + Runnable runnable; + while ((runnable = engine.getDelegatedTask()) != null) { + System.out.println("\trunning delegated task..."); + runnable.run(); + } + SSLEngineResult.HandshakeStatus hsStatus = + engine.getHandshakeStatus(); + if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK) { + throw new Exception( + "handshake shouldn't need additional tasks"); + } + System.out.println("\tnew HandshakeStatus: " + hsStatus); + } + } + + /** + * + * @param data The array of bytes to dump to stdout. + * @param itemsPerLine The number of bytes to display per line + * if the {@code lineDelim} character is blank then all bytes will be + * printed on a single line. + * @param lineDelim The delimiter between lines + * @param itemDelim The delimiter between bytes + * + * @return The hexdump of the byte array + */ + private static String dumpHexBytes(ByteBuffer data, int itemsPerLine, + String lineDelim, String itemDelim) { + StringBuilder sb = new StringBuilder(); + + if (data != null) { + data.mark(); + for (int i = 0; i < data.limit(); i++) { + if (i % itemsPerLine == 0 && i != 0) { + sb.append(lineDelim); + } + sb.append(String.format("%02X", data.get(i))); + if (i % itemsPerLine != (itemsPerLine - 1) && + i != (data.limit() -1)) { + sb.append(itemDelim); + } + } + data.reset(); + } + + return sb.toString(); + } + + private static void createManagerFactories() + throws GeneralSecurityException, IOException { + KeyStore keystore = KeyStore.getInstance("PKCS12"); + KeyStore truststore = KeyStore.getInstance("PKCS12"); + KeyStore empty_ts = KeyStore.getInstance("PKCS12"); + char[] passphrase = passwd.toCharArray(); + + keystore.load(new FileInputStream(keyFilename), passphrase); + truststore.load(new FileInputStream(trustFilename), passphrase); + empty_ts.load(null, "".toCharArray()); + + KMF = KeyManagerFactory.getInstance("PKIX"); + KMF.init(keystore, passphrase); + TMF = TrustManagerFactory.getInstance("PKIX"); + TMF.init(truststore); + EMPTY_TMF = TrustManagerFactory.getInstance("PKIX"); + EMPTY_TMF.init(truststore); + } + + private static void checkEngineState(SSLEngine engine, + SSLEngineResult.HandshakeStatus expectedHSStat, + boolean expectedInboundDone, boolean expectedOutboundDone) { + if (engine.getHandshakeStatus() != expectedHSStat || + engine.isInboundDone() != expectedInboundDone || + engine.isOutboundDone() != expectedOutboundDone) { + throw new RuntimeException("Error: engine not in expected state\n" + + "Expected: state = " + expectedHSStat + + ", inDone = " + expectedInboundDone + + ", outDone = " + expectedOutboundDone + "\n" + + "Actual: state = " + engine.getHandshakeStatus() + + ", inDone = " + engine.isInboundDone() + + ", outDone = " + engine.isOutboundDone()); + } else { + System.out.println((engine.getUseClientMode() ? + "Client" : "Server") + " handshake status: " + + engine.getHandshakeStatus() + ", inDone = " + + engine.isInboundDone() + ", outDone = " + + engine.isOutboundDone()); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/net/ssl/TLSCommon/SSLEngineTestCase.java --- a/jdk/test/javax/net/ssl/TLSCommon/SSLEngineTestCase.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/javax/net/ssl/TLSCommon/SSLEngineTestCase.java Fri Nov 11 16:44:36 2016 +0100 @@ -27,7 +27,9 @@ import javax.net.ssl.SNIServerName; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLSession; import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLException; import javax.net.ssl.SSLParameters; import javax.net.ssl.TrustManagerFactory; @@ -57,19 +59,21 @@ public enum Ciphers { /** - * Ciphers supported by the tested SSLEngine without those with kerberos - * authentication. + * Ciphers supported by the tested SSLEngine without those with + * kerberos authentication. */ SUPPORTED_NON_KRB_CIPHERS(SSLEngineTestCase.SUPPORTED_NON_KRB_CIPHERS, "Supported non kerberos"), /** - * Ciphers supported by the tested SSLEngine without those with kerberos - * authentication and without those with SHA256 ans SHA384. + * Ciphers supported by the tested SSLEngine without those with + * kerberos authentication and without those with SHA256 ans SHA384. */ - SUPPORTED_NON_KRB_NON_SHA_CIPHERS(SSLEngineTestCase.SUPPORTED_NON_KRB_NON_SHA_CIPHERS, + SUPPORTED_NON_KRB_NON_SHA_CIPHERS( + SSLEngineTestCase.SUPPORTED_NON_KRB_NON_SHA_CIPHERS, "Supported non kerberos non SHA256 and SHA384"), /** - * Ciphers supported by the tested SSLEngine with kerberos authentication. + * Ciphers supported by the tested SSLEngine with kerberos + * authentication. */ SUPPORTED_KRB_CIPHERS(SSLEngineTestCase.SUPPORTED_KRB_CIPHERS, "Supported kerberos"), @@ -147,13 +151,13 @@ = System.getProperty("test.src", ".") + FS + PATH_TO_STORES + FS + TRUST_STORE_FILE; + // Need an enhancement to use none-static mutable global variables. private static ByteBuffer net; - private static ByteBuffer netReplicatedClient; - private static ByteBuffer netReplicatedServer; + private static boolean doUnwrapForNotHandshakingStatus; + private static boolean endHandshakeLoop = false; + private static final int MAX_HANDSHAKE_LOOPS = 100; private static final String EXCHANGE_MSG_SENT = "Hello, peer!"; - private static boolean doUnwrapForNotHandshakingStatus; - private static boolean endHandshakeLoop = false; private static final String TEST_SRC = System.getProperty("test.src", "."); private static final String KTAB_FILENAME = "krb5.keytab.data"; private static final String KRB_REALM = "TEST.REALM"; @@ -179,11 +183,13 @@ List supportedCiphersList = new LinkedList<>(); for (String cipher : allSupportedCiphers) { if (!cipher.contains("KRB5") - && !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) { + && !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) { + supportedCiphersList.add(cipher); } } - SUPPORTED_NON_KRB_CIPHERS = supportedCiphersList.toArray(new String[0]); + SUPPORTED_NON_KRB_CIPHERS = + supportedCiphersList.toArray(new String[0]); } catch (Exception ex) { throw new Error("Unexpected issue", ex); } @@ -220,7 +226,7 @@ List supportedCiphersList = new LinkedList<>(); for (String cipher : allSupportedCiphers) { if (cipher.contains("KRB5") - && !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) { + && !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) { supportedCiphersList.add(cipher); } } @@ -240,11 +246,12 @@ List enabledCiphersList = new LinkedList<>(); for (String cipher : enabledCiphers) { if (!cipher.contains("anon") && !cipher.contains("KRB5") - && !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) { + && !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) { enabledCiphersList.add(cipher); } } - ENABLED_NON_KRB_NOT_ANON_CIPHERS = enabledCiphersList.toArray(new String[0]); + ENABLED_NON_KRB_NOT_ANON_CIPHERS = + enabledCiphersList.toArray(new String[0]); } catch (Exception ex) { throw new Error("Unexpected issue", ex); } @@ -300,10 +307,10 @@ * Wraps data with the specified engine. * * @param engine - SSLEngine that wraps data. - * @param wrapper - Set wrapper id, e.g. "server" of "client". Used for - * logging only. - * @param maxPacketSize - Max packet size to check that MFLN extension works - * or zero for no check. + * @param wrapper - Set wrapper id, e.g. "server" of "client". + * Used for logging only. + * @param maxPacketSize - Max packet size to check that MFLN extension + * works or zero for no check. * @param app - Buffer with data to wrap. * @return - Buffer with wrapped data. * @throws SSLException - thrown on engine errors. @@ -319,13 +326,13 @@ * Wraps data with the specified engine. * * @param engine - SSLEngine that wraps data. - * @param wrapper - Set wrapper id, e.g. "server" of "client". Used for - * logging only. - * @param maxPacketSize - Max packet size to check that MFLN extension works - * or zero for no check. + * @param wrapper - Set wrapper id, e.g. "server" of "client". + * Used for logging only. + * @param maxPacketSize - Max packet size to check that MFLN extension + * works or zero for no check. * @param app - Buffer with data to wrap. - * @param result - Array which first element will be used to output wrap - * result object. + * @param result - Array which first element will be used to + * output wrap result object. * @return - Buffer with wrapped data. * @throws SSLException - thrown on engine errors. */ @@ -341,10 +348,10 @@ * Wraps data with the specified engine. * * @param engine - SSLEngine that wraps data. - * @param wrapper - Set wrapper id, e.g. "server" of "client". Used for - * logging only. - * @param maxPacketSize - Max packet size to check that MFLN extension works - * or zero for no check. + * @param wrapper - Set wrapper id, e.g. "server" of "client". + * Used for logging only. + * @param maxPacketSize - Max packet size to check that MFLN extension + * works or zero for no check. * @param app - Buffer with data to wrap. * @param wantedStatus - Specifies expected result status of wrapping. * @return - Buffer with wrapped data. @@ -362,14 +369,14 @@ * Wraps data with the specified engine. * * @param engine - SSLEngine that wraps data. - * @param wrapper - Set wrapper id, e.g. "server" of "client". Used for - * logging only. - * @param maxPacketSize - Max packet size to check that MFLN extension works - * or zero for no check. + * @param wrapper - Set wrapper id, e.g. "server" of "client". + * Used for logging only. + * @param maxPacketSize - Max packet size to check that MFLN extension + * works or zero for no check. * @param app - Buffer with data to wrap. * @param wantedStatus - Specifies expected result status of wrapping. - * @param result - Array which first element will be used to output wrap - * result object. + * @param result - Array which first element will be used to output + * wrap result object. * @return - Buffer with wrapped data. * @throws SSLException - thrown on engine errors. */ @@ -409,9 +416,9 @@ * @throws SSLException - thrown on engine errors. */ public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper, - ByteBuffer net) - throws SSLException { - return doUnWrap(engine, unwrapper, net, SSLEngineResult.Status.OK, null); + ByteBuffer net) throws SSLException { + return doUnWrap(engine, unwrapper, + net, SSLEngineResult.Status.OK, null); } /** @@ -427,26 +434,25 @@ * @throws SSLException - thrown on engine errors. */ public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper, - ByteBuffer net, SSLEngineResult[] result) - throws SSLException { - return doUnWrap(engine, unwrapper, net, SSLEngineResult.Status.OK, result); + ByteBuffer net, SSLEngineResult[] result) throws SSLException { + return doUnWrap(engine, unwrapper, + net, SSLEngineResult.Status.OK, result); } /** * Unwraps data with the specified engine. * * @param engine - SSLEngine that unwraps data. - * @param unwrapper - Set unwrapper id, e.g. "server" of "client". Used for - * logging only. + * @param unwrapper - Set unwrapper id, e.g. "server" of "client". + * Used for logging only. * @param net - Buffer with data to unwrap. * @param wantedStatus - Specifies expected result status of wrapping. * @return - Buffer with unwrapped data. * @throws SSLException - thrown on engine errors. */ public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper, - ByteBuffer net, - SSLEngineResult.Status wantedStatus) - throws SSLException { + ByteBuffer net, + SSLEngineResult.Status wantedStatus) throws SSLException { return doUnWrap(engine, unwrapper, net, wantedStatus, null); } @@ -454,25 +460,23 @@ * Unwraps data with the specified engine. * * @param engine - SSLEngine that unwraps data. - * @param unwrapper - Set unwrapper id, e.g. "server" of "client". Used for - * logging only. + * @param unwrapper - Set unwrapper id, e.g. "server" of "client". + * Used for logging only. * @param net - Buffer with data to unwrap. * @param wantedStatus - Specifies expected result status of wrapping. - * @param result - Array which first element will be used to output wrap - * result object. + * @param result - Array which first element will be used to output + * wrap result object. * @return - Buffer with unwrapped data. * @throws SSLException - thrown on engine errors. */ public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper, - ByteBuffer net, - SSLEngineResult.Status wantedStatus, - SSLEngineResult[] result) - throws SSLException { - ByteBuffer app = ByteBuffer.allocate(engine.getSession() - .getApplicationBufferSize()); + ByteBuffer net, SSLEngineResult.Status wantedStatus, + SSLEngineResult[] result) throws SSLException { + + ByteBuffer app = ByteBuffer.allocate( + engine.getSession().getApplicationBufferSize()); int length = net.remaining(); - System.out.println(unwrapper + " unwrapping " - + length + " bytes..."); + System.out.println(unwrapper + " unwrapping " + length + " bytes..."); SSLEngineResult r = engine.unwrap(net, app); app.flip(); System.out.println(unwrapper + " handshake status is " @@ -491,13 +495,14 @@ * @param clientEngine - Client SSLEngine. * @param serverEngine - Server SSLEngine. * @param maxPacketSize - Maximum packet size for MFLN of zero for no limit. - * @param mode - Handshake mode according to {@link HandshakeMode} enum. + * @param mode - Handshake mode according to + * {@link HandshakeMode} enum. * @throws SSLException - thrown on engine errors. */ public static void doHandshake(SSLEngine clientEngine, - SSLEngine serverEngine, - int maxPacketSize, HandshakeMode mode) - throws SSLException { + SSLEngine serverEngine, + int maxPacketSize, HandshakeMode mode) throws SSLException { + doHandshake(clientEngine, serverEngine, maxPacketSize, mode, false); } @@ -507,19 +512,20 @@ * * @param clientEngine - Client SSLEngine. * @param serverEngine - Server SSLEngine. - * @param maxPacketSize - Maximum packet size for MFLN of zero for no limit. - * @param mode - Handshake mode according to {@link HandshakeMode} enum. + * @param maxPacketSize - Maximum packet size for MFLN of zero + * for no limit. + * @param mode - Handshake mode according to + * {@link HandshakeMode} enum. * @param enableReplicatedPacks - Set {@code true} to enable replicated - * packet sending. + * packet sending. * @throws SSLException - thrown on engine errors. */ public static void doHandshake(SSLEngine clientEngine, - SSLEngine serverEngine, int maxPacketSize, - HandshakeMode mode, - boolean enableReplicatedPacks) - throws SSLException { - System.out.println("=================================================" - + "==========="); + SSLEngine serverEngine, int maxPacketSize, + HandshakeMode mode, + boolean enableReplicatedPacks) throws SSLException { + + System.out.println("============================================="); System.out.println("Starting handshake " + mode.name()); int loop = 0; if (maxPacketSize < 0) { @@ -561,18 +567,16 @@ if (++loop > MAX_HANDSHAKE_LOOPS) { throw new Error("Too much loops for handshaking"); } - System.out.println("=============================================="); - System.out.println("Handshake loop " + loop); - SSLEngineResult.HandshakeStatus clientHSStatus - = clientEngine.getHandshakeStatus(); - SSLEngineResult.HandshakeStatus serverHSStatus - = serverEngine.getHandshakeStatus(); - System.out.println("Client handshake status " - + clientHSStatus.name()); - System.out.println("Server handshake status " - + serverHSStatus.name()); + System.out.println("============================================"); + System.out.println("Handshake loop " + loop + ": round 1"); + System.out.println("=========================="); handshakeProcess(firstEngine, secondEngine, maxPacketSize, enableReplicatedPacks); + if (endHandshakeLoop) { + break; + } + System.out.println("Handshake loop " + loop + ": round 2"); + System.out.println("=========================="); handshakeProcess(secondEngine, firstEngine, maxPacketSize, enableReplicatedPacks); } @@ -596,15 +600,15 @@ sender = "Client"; reciever = "Server"; excMsgSent += " Client."; - } else if (toEngine.getUseClientMode() && !fromEngine.getUseClientMode()) { + } else if (toEngine.getUseClientMode() && + !fromEngine.getUseClientMode()) { sender = "Server"; reciever = "Client"; excMsgSent += " Server."; } else { throw new Error("Test issue: both engines are in the same mode"); } - System.out.println("=================================================" - + "==========="); + System.out.println("============================================="); System.out.println("Trying to send application data from " + sender + " to " + reciever); ByteBuffer clientAppSent @@ -643,20 +647,24 @@ if (fromEngine.getUseClientMode() && !toEngine.getUseClientMode()) { from = "Client"; to = "Server"; - } else if (toEngine.getUseClientMode() && !fromEngine.getUseClientMode()) { + } else if (toEngine.getUseClientMode() && + !fromEngine.getUseClientMode()) { from = "Server"; to = "Client"; } else { throw new Error("Both engines are in the same mode"); } - System.out.println("========================================================="); - System.out.println("Trying to close engines from " + from + " to " + to); + System.out.println("============================================="); + System.out.println( + "Trying to close engines from " + from + " to " + to); // Sending close outbound request to peer fromEngine.closeOutbound(); - app = ByteBuffer.allocate(fromEngine.getSession().getApplicationBufferSize()); + app = ByteBuffer.allocate( + fromEngine.getSession().getApplicationBufferSize()); net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED); doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED); - app = ByteBuffer.allocate(fromEngine.getSession().getApplicationBufferSize()); + app = ByteBuffer.allocate( + fromEngine.getSession().getApplicationBufferSize()); net = doWrap(toEngine, to, 0, app, SSLEngineResult.Status.CLOSED); doUnWrap(fromEngine, from, net, SSLEngineResult.Status.CLOSED); if (!toEngine.isInboundDone()) { @@ -665,7 +673,8 @@ } // Executing close inbound fromEngine.closeInbound(); - app = ByteBuffer.allocate(fromEngine.getSession().getApplicationBufferSize()); + app = ByteBuffer.allocate( + fromEngine.getSession().getApplicationBufferSize()); net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED); doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED); if (!toEngine.isOutboundDone()) { @@ -712,7 +721,8 @@ runTests(Ciphers.SUPPORTED_KRB_CIPHERS); break; default: - throw new Error("Test error: unexpected test mode: " + TEST_MODE); + throw new Error( + "Test error: unexpected test mode: " + TEST_MODE); } } @@ -743,28 +753,36 @@ } /** - * Returns SSLContext with TESTED_SECURITY_PROTOCOL protocol and sets up keys. + * Returns SSLContext with TESTED_SECURITY_PROTOCOL protocol and + * sets up keys. * - * @return - SSLContext with a protocol specified by TESTED_SECURITY_PROTOCOL. + * @return - SSLContext with a protocol specified by + * TESTED_SECURITY_PROTOCOL. */ public static SSLContext getContext() { try { - java.security.Security.setProperty("jdk.tls.disabledAlgorithms", ""); - java.security.Security.setProperty("jdk.certpath.disabledAlgorithms", ""); + java.security.Security.setProperty( + "jdk.tls.disabledAlgorithms", ""); + java.security.Security.setProperty( + "jdk.certpath.disabledAlgorithms", ""); KeyStore ks = KeyStore.getInstance("JKS"); KeyStore ts = KeyStore.getInstance("JKS"); char[] passphrase = PASSWD.toCharArray(); - try (FileInputStream keyFileStream = new FileInputStream(KEY_FILE_NAME)) { + try (FileInputStream keyFileStream = + new FileInputStream(KEY_FILE_NAME)) { ks.load(keyFileStream, passphrase); } - try (FileInputStream trustFileStream = new FileInputStream(TRUST_FILE_NAME)) { + try (FileInputStream trustFileStream = + new FileInputStream(TRUST_FILE_NAME)) { ts.load(trustFileStream, passphrase); } KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, passphrase); - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + TrustManagerFactory tmf = + TrustManagerFactory.getInstance("SunX509"); tmf.init(ts); - SSLContext sslCtx = SSLContext.getInstance(TESTED_SECURITY_PROTOCOL); + SSLContext sslCtx = + SSLContext.getInstance(TESTED_SECURITY_PROTOCOL); sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); return sslCtx; } catch (KeyStoreException | IOException | NoSuchAlgorithmException | @@ -791,7 +809,8 @@ } /** - * Sets up and starts kerberos KDC server if SSLEngineTestCase.TEST_MODE is "krb". + * Sets up and starts kerberos KDC server if + * SSLEngineTestCase.TEST_MODE is "krb". */ public static void setUpAndStartKDCIfNeeded() { if (TEST_MODE.equals("krb")) { @@ -806,7 +825,9 @@ * @param useSNI - flag used to enable or disable using SNI extension. * Needed for Kerberos. */ - public static SSLEngine getClientSSLEngine(SSLContext context, boolean useSNI) { + public static SSLEngine getClientSSLEngine( + SSLContext context, boolean useSNI) { + SSLEngine clientEngine = context.createSSLEngine(HOST, 80); clientEngine.setUseClientMode(true); if (useSNI) { @@ -827,7 +848,9 @@ * @param useSNI - flag used to enable or disable using SNI extension. * Needed for Kerberos. */ - public static SSLEngine getServerSSLEngine(SSLContext context, boolean useSNI) { + public static SSLEngine getServerSSLEngine( + SSLContext context, boolean useSNI) { + SSLEngine serverEngine = context.createSSLEngine(); serverEngine.setUseClientMode(false); if (useSNI) { @@ -860,18 +883,20 @@ protected int testSomeCiphers(Ciphers ciphers) { int failedNum = 0; String description = ciphers.description; - System.out.println("===================================================" - + "========="); + System.out.println("==============================================="); System.out.println(description + " ciphers testing"); - System.out.println("===================================================" - + "========="); + System.out.println("==========================================="); for (String cs : ciphers.ciphers) { - System.out.println("-----------------------------------------------" - + "-------------"); + System.out.println("---------------------------------------"); System.out.println("Testing cipher suite " + cs); - System.out.println("-----------------------------------------------" - + "-------------"); + System.out.println("---------------------------------------"); Throwable error = null; + + // Reset global mutable static variables + net = null; + doUnwrapForNotHandshakingStatus = false; + endHandshakeLoop = false; + try { testOneCipher(cs); } catch (Throwable t) { @@ -894,8 +919,9 @@ case UNSUPPORTED_CIPHERS: if (error == null) { System.out.println("Test Failed: " + cs); - System.err.println("Test for " + cs + " should have thrown" - + " IllegalArgumentException, but it has not!"); + System.err.println("Test for " + cs + + " should have thrown " + + "IllegalArgumentException, but it has not!"); failedNum++; } else if (!(error instanceof IllegalArgumentException)) { System.out.println("Test Failed: " + cs); @@ -911,6 +937,7 @@ + ciphers.name()); } } + return failedNum; } @@ -919,20 +946,20 @@ * * @param wrapingEngine - Engine that is expected to wrap data. * @param unwrapingEngine - Engine that is expected to unwrap data. - * @param maxPacketSize - Maximum packet size for MFLN of zero for no limit. + * @param maxPacketSize - Maximum packet size for MFLN of zero + * for no limit. * @param enableReplicatedPacks - Set {@code true} to enable replicated - * packet sending. + * packet sending. * @throws SSLException - thrown on engine errors. */ private static void handshakeProcess(SSLEngine wrapingEngine, - SSLEngine unwrapingEngine, - int maxPacketSize, - boolean enableReplicatedPacks) - throws SSLException { - SSLEngineResult.HandshakeStatus wrapingHSStatus = wrapingEngine - .getHandshakeStatus(); - SSLEngineResult.HandshakeStatus unwrapingHSStatus = unwrapingEngine - .getHandshakeStatus(); + SSLEngine unwrapingEngine, + int maxPacketSize, + boolean enableReplicatedPacks) throws SSLException { + + HandshakeStatus wrapingHSStatus = wrapingEngine.getHandshakeStatus(); + HandshakeStatus unwrapingHSStatus = + unwrapingEngine.getHandshakeStatus(); SSLEngineResult r; String wrapper, unwrapper; if (wrapingEngine.getUseClientMode() @@ -946,6 +973,13 @@ } else { throw new Error("Both engines are in the same mode"); } + System.out.println( + wrapper + " handshake (wrap) status " + wrapingHSStatus); + System.out.println( + unwrapper + " handshake (unwrap) status " + unwrapingHSStatus); + + ByteBuffer netReplicatedClient = null; + ByteBuffer netReplicatedServer = null; switch (wrapingHSStatus) { case NEED_WRAP: if (enableReplicatedPacks) { @@ -960,9 +994,11 @@ } } } - ByteBuffer app = ByteBuffer.allocate(wrapingEngine.getSession() - .getApplicationBufferSize()); + ByteBuffer app = ByteBuffer.allocate( + wrapingEngine.getSession().getApplicationBufferSize()); net = doWrap(wrapingEngine, wrapper, maxPacketSize, app); + wrapingHSStatus = wrapingEngine.getHandshakeStatus(); + // No break, falling into unwrapping. case NOT_HANDSHAKING: switch (unwrapingHSStatus) { case NEED_TASK: @@ -970,12 +1006,12 @@ case NEED_UNWRAP: doUnWrap(unwrapingEngine, unwrapper, net); if (enableReplicatedPacks) { - System.out.println("Unwrapping replicated packet..."); + System.out.println(unwrapper + + " unwrapping replicated packet..."); if (unwrapingEngine.getHandshakeStatus() - .equals(SSLEngineResult.HandshakeStatus.NEED_TASK)) { + .equals(HandshakeStatus.NEED_TASK)) { runDelegatedTasks(unwrapingEngine); } - runDelegatedTasks(unwrapingEngine); ByteBuffer netReplicated; if (unwrapingEngine.getUseClientMode()) { netReplicated = netReplicatedClient; @@ -983,7 +1019,8 @@ netReplicated = netReplicatedServer; } if (netReplicated != null) { - doUnWrap(unwrapingEngine, unwrapper, netReplicated); + doUnWrap(unwrapingEngine, + unwrapper, netReplicated); } else { net.flip(); doUnWrap(unwrapingEngine, unwrapper, net); @@ -994,15 +1031,39 @@ break; case NOT_HANDSHAKING: if (doUnwrapForNotHandshakingStatus) { + System.out.println("Not handshake status unwrap"); doUnWrap(unwrapingEngine, unwrapper, net); doUnwrapForNotHandshakingStatus = false; break; } else { - endHandshakeLoop = true; + if (wrapingHSStatus == + HandshakeStatus.NOT_HANDSHAKING) { + System.out.println("Handshake is completed"); + endHandshakeLoop = true; + } } break; + case NEED_WRAP: + SSLSession session = unwrapingEngine.getSession(); + int bufferSize = session.getApplicationBufferSize(); + ByteBuffer b = ByteBuffer.allocate(bufferSize); + net = doWrap(unwrapingEngine, + unwrapper, maxPacketSize, b); + unwrapingHSStatus = + unwrapingEngine.getHandshakeStatus(); + if ((wrapingHSStatus == + HandshakeStatus.NOT_HANDSHAKING) && + (unwrapingHSStatus == + HandshakeStatus.NOT_HANDSHAKING)) { + + System.out.println("Handshake is completed"); + endHandshakeLoop = true; + } + + break; default: - throw new Error("Unexpected unwraping engine handshake status " + throw new Error( + "Unexpected unwraping engine handshake status " + unwrapingHSStatus.name()); } break; @@ -1027,8 +1088,8 @@ while ((runnable = engine.getDelegatedTask()) != null) { runnable.run(); } - SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus(); - if (hs == SSLEngineResult.HandshakeStatus.NEED_TASK) { + HandshakeStatus hs = engine.getHandshakeStatus(); + if (hs == HandshakeStatus.NEED_TASK) { throw new Error("Handshake shouldn't need additional tasks."); } } diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/print/attribute/Services_getDocFl.java --- a/jdk/test/javax/print/attribute/Services_getDocFl.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/javax/print/attribute/Services_getDocFl.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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,7 +28,7 @@ /* * @test - * @bug 4901243 8040139 + * @bug 4901243 8040139 8167291 * @summary JPG, GIF, and PNG DocFlavors (URL) should be supported if Postscript is supported. * @run main Services_getDocFl */ @@ -58,6 +58,7 @@ pngImagesSupported = false; gifImagesSupported = false; jpgImagesSupported = false; + psSupported = false; for (int j=0; j opening Transmitter from "+infos[devNum]); + inDev = MidiSystem.getMidiDevice(infos[devNum]); + inDev.open(); + transmitter = inDev.getTransmitter(); + Receiver testReceiver = new TestReceiver(); + transmitter.setReceiver(testReceiver); + + devNum = Integer.decode(args[1]).intValue(); + out("-> opening Receiver from "+infos[devNum]); + outDev = MidiSystem.getMidiDevice(infos[devNum]); + outDev.open(); + receiver = outDev.getReceiver(); + + } catch (Exception e) { + System.out.println(e); + System.out.println("Cannot test!"); + return; + } + + // test + sMsg.setMessage(ShortMessage.NOTE_OFF | 0, 27, 100); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.NOTE_OFF | 0, 0, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.NOTE_OFF | 15, 127, 127); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.NOTE_ON | 4, 27, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.NOTE_ON | 0, 0, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.NOTE_ON | 15, 127, 127); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.POLY_PRESSURE | 11, 98, 99); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.POLY_PRESSURE | 0, 0, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.POLY_PRESSURE | 15, 127, 127); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.CONTROL_CHANGE | 13, 1, 63); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.CONTROL_CHANGE | 0, 0, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.CONTROL_CHANGE | 15, 127, 127); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.PROGRAM_CHANGE | 2, 120, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.PROGRAM_CHANGE | 0, 0, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.PROGRAM_CHANGE | 15, 127, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.CHANNEL_PRESSURE | 6, 30, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.CHANNEL_PRESSURE | 0, 0, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.CHANNEL_PRESSURE | 15, 127, 0); + isTestPassed &= testMessage(sMsg); + + sMsg.setMessage(ShortMessage.PITCH_BEND | 6, 56, 4); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.PITCH_BEND | 0, 0, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.PITCH_BEND | 15, 127, 127); + isTestPassed &= testMessage(sMsg); + + sMsg.setMessage(ShortMessage.MIDI_TIME_CODE, 0, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.MIDI_TIME_CODE, 127, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.SONG_POSITION_POINTER, 1, 77); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.SONG_POSITION_POINTER, 0, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.SONG_POSITION_POINTER, 127, 127); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.SONG_SELECT, 51, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.SONG_SELECT, 0, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.SONG_SELECT, 127, 0); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.TUNE_REQUEST); + isTestPassed &= testMessage(sMsg); + + sMsg.setMessage(ShortMessage.TIMING_CLOCK); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.START); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.CONTINUE); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.STOP); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.ACTIVE_SENSING); + isTestPassed &= testMessage(sMsg); + sMsg.setMessage(ShortMessage.SYSTEM_RESET); + isTestPassed &= testMessage(sMsg); + + syMsg.setMessage(new byte[]{(byte) 0xF0, (byte) 0xF7}, 2); + isTestPassed &= testMessage(syMsg); + syMsg.setMessage(new byte[]{(byte) 0xF0, 0x01, (byte) 0xF7}, 3); + isTestPassed &= testMessage(syMsg); + syMsg.setMessage(new byte[]{(byte) 0xF0, 0x02, 0x03, (byte) 0xF7}, 4); + isTestPassed &= testMessage(syMsg); + syMsg.setMessage(new byte[]{(byte) 0xF0, 0x04, 0x05, 0x06, (byte) 0xF7}, 5); + isTestPassed &= testMessage(syMsg); + + if (isTestPassed) { + byte[] sysexArray = new byte[LONG_SYSEX_LENGTH]; + sysexArray[0] = (byte) 0xF0; + for (int i = 1; i < sysexArray.length; i++) { + sysexArray[i] = (byte) (i % 0x80); + } +// syMsg.setMessage(new byte[]{(byte) 0xF7, (byte) ShortMessage.START}, 2); +// sMsg.setMessage(ShortMessage.START); +// isTestPassed &= testMessage(syMsg, sMsg, DEFAULT_SLEEP_INTERVALL); + for (int trial = sysexArray.length; trial > 4; trial -= 1234) { + sleep(500); + sysexArray[trial - 1] = (byte) 0xF7; + syMsg.setMessage(sysexArray, trial); + sysExTestPassed &= testMessage(syMsg); + break; + } + } + + // cleanup + receiver.close(); + transmitter.close(); + inDev.close(); + outDev.close(); + + if (isTestExecuted) { + if (isTestPassed && sysExTestPassed) { + + out("Test PASSED."); + } else { + if (isTestPassed + && !sysExTestPassed + && (System.getProperty("os.name").startsWith("Windows"))) { + out("Some Windows MIDI i/o drivers have a problem with larger "); + out("sys ex messages. The failing sys ex cases are OK, therefore."); + out("Test PASSED."); + } else { + throw new Exception("Test FAILED."); + } + } + } else { + out("Test NOT FAILED"); + } + } + + private static boolean testMessage(MidiMessage message) { + receivedMessage = null; + baos = new ByteArrayOutputStream(); + expectedBytes = message.getLength(); + receivedBytes = 0; + System.out.print("Sending message " + getMessageString(message.getMessage())+"..."); + receiver.send(message, -1); + /* sending 3 bytes can roughly be done in 1 millisecond, + * so this estimate waits at max 3 times longer than the message takes, + * plus a little offset to allow the MIDI subsystem some processing time + */ + int offset = 300; // standard offset 100 millis + if (message instanceof SysexMessage) { + // add a little processing time to sysex messages + offset += 1000; + } + if (receivedBytes < expectedBytes) { + sleep(expectedBytes + offset); + } + boolean equal; + byte[] data = baos.toByteArray(); + if (data.length > 0) { + equal = messagesEqual(message.getMessage(), data); + } else { + equal = messagesEqual(message, receivedMessage); + if (receivedMessage != null) { + data = receivedMessage.getMessage(); + } else { + data = null; + } + } + if (!equal) { + if ((message.getStatus() & 0xF0) == ShortMessage.PITCH_BEND) { + out("NOT failed (may expose a bug in ALSA)"); + equal = true; + sleep(100); + } + if ((message.getStatus() == 0xF6) && (message.getLength() == 1)) { + out("NOT failed (may expose an issue on Solaris)"); + equal = true; + sleep(100); + } + else if ((message.getStatus()) == 0xF0 && message.getLength() < 4) { + out("NOT failed (not a correct sys ex message)"); + equal = true; + sleep(200); + } else { + out("FAILED:"); + out(" received as " + getMessageString(data)); + } + } else { + System.out.println("OK"); + } + return equal; + } + + private static void sleep(int milliseconds) { + synchronized(lock) { + try { + lock.wait(milliseconds); + } catch (InterruptedException e) { + } + } + } + + private static String getMessageString(byte[] data) { + String s; + if (data == null) { + s = ""; + } else if (data.length == 0) { + s = "0-sized array"; + } else { + int status = data[0] & 0xFF; + if (data.length <= 3) { + if (status < 240) { + s = "command 0x" + Integer.toHexString(status & 0xF0) + " channel " + (status & 0x0F); + } else { + s = "status 0x" + Integer.toHexString(status); + } + if (data.length > 1) { + s += " data 0x" + Integer.toHexString(data[1] & 0xFF); + if (data.length > 2) { + s += " 0x" + Integer.toHexString(data[2] & 0xFF); + } + } + } else { + s = "status " + Integer.toHexString(status)+" and length "+data.length+" bytes"; + } + } + return s; + } + + private static boolean messagesEqual(MidiMessage m1, MidiMessage m2) { + if (m1 == null || m2 == null) { + return false; + } + if (m1.getLength() != m2.getLength()) { + return false; + } + byte[] array1 = m1.getMessage(); + byte[] array2 = m2.getMessage(); + return messagesEqual(array1, array2); + } + + private static boolean messagesEqual(byte[] a1, byte[] a2) { + if (a1.length != a2.length) return false; + for (int i = 0; i < a1.length; i++) { + if (a1[i] != a2[i]) { + return false; + } + } + return true; + } + + private static void out(String s) { + System.out.println(s); + System.out.flush(); + } + + private static String canIn(MidiDevice dev) { + if (dev.getMaxTransmitters() != 0) { + return "IN "; + } + return " "; + } + + private static String canOut(MidiDevice dev) { + if (dev.getMaxReceivers() != 0) { + return "OUT "; + } + return " "; + } + + + private static void checkTimestamp(long timestamp) { + // out("checking timestamp..."); + if (timestamp < 1) { + out("timestamp 0 or negative!"); + } + if (timestamp < lastTimestamp) { + out("timestamp not progressive!"); + } + lastTimestamp = timestamp; + } + + private static class TestReceiver implements Receiver { + public void send(MidiMessage message, long timestamp) { + //System.out.print(""+message.getLength()+".."); + checkTimestamp(timestamp); + try { + receivedMessage = message; + if (message.getStatus() == 0xF0 + || (message.getLength() > 3 && message.getStatus() != 0xF7)) { + // sys ex message + byte[] data = message.getMessage(); + baos.write(data); + receivedBytes += data.length; + } + else if (message.getStatus() == 0xF7) { + // sys ex cont'd message + byte[] data = message.getMessage(); + // ignore the prepended 0xF7 + baos.write(data, 1, data.length-1); + receivedBytes += (data.length - 1); + } else { + receivedBytes += message.getLength(); + } + if (receivedBytes >= expectedBytes) { + synchronized(lock) { + lock.notify(); + } + } + System.out.print(""+receivedBytes+".."); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void close() { + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Devices/MidiDeviceGetReceivers.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Devices/MidiDeviceGetReceivers.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.List; + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Transmitter; + +/** + * @test + * @bug 4931387 + * @summary Add methods to MidiDevice to get list of Transmitters and Receivers + */ +public class MidiDeviceGetReceivers { + + private static boolean executed = false; + private static boolean failed = false; + + public static void main(String[] args) throws Exception { + out("unit test 4931387: Add methods to MidiDevice to get list of Transmitters and Receivers"); + doAllTests(); + if (executed) { + if (failed) throw new Exception("Test FAILED!"); + out("Test PASSED."); + } else { + out("Test NOT failed."); + } + } + + private static void doAllTests() { + MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); + for (int i = 0; i < infos.length; i++) { + MidiDevice device = null; + try { + device = MidiSystem.getMidiDevice(infos[i]); + doTest(device); + } catch (MidiUnavailableException e) { + out("Exception occured when retrieving device "+infos[i]+": "+e); + } + } + if (infos.length == 0) { + out("No MIDI devices exist or sound drivers not installed!"); + } + } + + private static boolean containsReceiver(MidiDevice dev, Receiver rec) { + List recvs = dev.getReceivers(); + return recvs.contains(rec); + } + + private static boolean containsTransmitter(MidiDevice dev, Transmitter tra) { + List tras = dev.getTransmitters(); + return tras.contains(tra); + } + + private static void doTest(MidiDevice device) { + boolean thisFailed = false; + out1("Testing: " + device+"..."); + try { + device.open(); + } catch (Exception e) { + out2("device.open threw exception: "+e); + out2("cannot test this device."); + return; + } + if (device.getMaxReceivers() != 0) { + // device offers receivers + try { + List origList = device.getReceivers(); + Receiver rec = device.getReceiver(); + if (!containsReceiver(device, rec)) { + out2("Getting a receiver did not add it to device list!"); + thisFailed = true; + } + if (origList.contains(rec)) { + out2("Original unmodifiable list was modified by adding a receiver!"); + thisFailed = true; + } + rec.close(); + if (containsReceiver(device, rec)) { + out2("Closing a receiver did not remove it from device list!"); + thisFailed = true; + } + // add a new receiver so that the device.close will really test + // that the receiver is removed + rec = device.getReceiver(); + if (!containsReceiver(device, rec)) { + out2("Getting a receiver again did not add it to device list!"); + thisFailed = true; + } + } catch (MidiUnavailableException e) { + out2("Exception on getting Receiver: " + e); + } + } + if (device.getMaxTransmitters() != 0) { + // device offers transmitters + try { + List origList = device.getTransmitters(); + Transmitter tra = device.getTransmitter(); + if (!containsTransmitter(device, tra)) { + out2("Getting a transmitter did not add it to device list!"); + thisFailed = true; + } + if (origList.contains(tra)) { + out2("Original unmodifiable list was modified by adding a transmitter!"); + thisFailed = true; + } + tra.close(); + if (containsTransmitter(device, tra)) { + out2("Closing a transmitter did not remove it from device list!"); + thisFailed = true; + } + tra = device.getTransmitter(); + if (!containsTransmitter(device, tra)) { + out2("Getting a transmitter again did not add it to device list!"); + thisFailed = true; + } + } catch (MidiUnavailableException e) { + out("Exception on getting Transmitter: " + e); + } + } + try { + device.close(); + if (device.getTransmitters().size() > 0) { + out2(" Device still has transmitters after close() was called!"); + thisFailed = true; + } + if (device.getReceivers().size() > 0) { + out2(" Device still has receivers after close() was called!"); + thisFailed = true; + } + } catch (Exception e) { + out2("device.close threw exception: "+e); + } + if (!thisFailed) { + out("OK"); + } else { + failed = true; + } + executed = true; + } + + static boolean lfMissing = false; + + private static void out(String message) { + lfMissing = true; + System.out.println(message); + } + + /* don't print LF at end */ + private static void out1(String message) { + System.out.print(message); + lfMissing = true; + } + + /* print at a new line, indented */ + private static void out2(String message) { + if (lfMissing) { + System.out.println(); + lfMissing = false; + } + System.out.println(" "+message); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Devices/MidiIO.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Devices/MidiIO.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; + +/** + * @test + * @bug 4356787 + * @summary MIDI device I/O is not working + */ +public class MidiIO { + + public static void main(String[] args) throws Exception { + out("4356787: MIDI device I/O is not working (windows)"); + + if (System.getProperty("os.name").startsWith("Windows")) { + boolean forInput=true; + boolean forOutput=true; + int outOnlyCount=0; + int inOnlyCount=0; + out(" available MIDI devices:"); + MidiDevice.Info[] aInfos = MidiSystem.getMidiDeviceInfo(); + for (int i = 0; i < aInfos.length; i++) { + try { + MidiDevice device = MidiSystem.getMidiDevice(aInfos[i]); + boolean bAllowsInput = (device.getMaxTransmitters() != 0); + boolean bAllowsOutput = (device.getMaxReceivers() != 0); + if (bAllowsInput && !bAllowsOutput) { + inOnlyCount++; + } + if (!bAllowsInput && bAllowsOutput) { + outOnlyCount++; + } + if ((bAllowsInput && forInput) || (bAllowsOutput && forOutput)) { + out(""+i+" " + +(bAllowsInput?"IN ":" ") + +(bAllowsOutput?"OUT ":" ") + +aInfos[i].getName()+", " + +aInfos[i].getVendor()+", " + +aInfos[i].getVersion()+", " + +aInfos[i].getDescription()); + } + } + catch (MidiUnavailableException e) { + // device is obviously not available... + } + } + if (aInfos.length == 0) { + out("No devices available. Test should be run on systems with MIDI drivers installed."); + } else { + if (outOnlyCount>1) { + if (inOnlyCount==0) { + //throw new Exception("No input devices! test fails."); + out("System provides out devices, but no input devices. This means either"); + out("a bug in Java Sound, or the drivers are not set up correctly."); + } + out("Test passed."); + } else { + out("no MIDI I/O installed. Test should be run on systems with MIDI drivers installed."); + } + } + } else { + out(" -- not on Windows. Test doesn't apply."); + } + } + + static void out(String s) { + System.out.println(s); System.out.flush(); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Devices/MidiOutGetMicrosecondPositionBug.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Devices/MidiOutGetMicrosecondPositionBug.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequencer; +import javax.sound.midi.Synthesizer; + +/** + * @test + * @bug 4903786 + * @summary MIDI OUT does not implement getMicrosecondPosition() consistently + */ +public class MidiOutGetMicrosecondPositionBug { + static int successfulTests = 0; + + private static void testDevice(MidiDevice device) throws Exception { + boolean timestampsAvailable = false; + boolean timestampPrecisionOk = false; + try { + // expected behaviour if not opened? + device.open(); + /* First, we're testing if timestamps are provided at all. + Returning -1 (unsupported), while allowed by the API + specification, is not sufficient to pass this test. */ + long timestamp = device.getMicrosecondPosition(); + timestampsAvailable = (timestamp != -1); + + /* Then, we're testing the precision. Note that the system time + is measured in milliseconds, while the device time is measured + in microseconds. */ + + long systemTime1 = System.currentTimeMillis(); + long deviceTime1 = device.getMicrosecondPosition(); + // rest for 5 seconds + Thread.sleep(5000); + long systemTime2 = System.currentTimeMillis(); + long deviceTime2 = device.getMicrosecondPosition(); + + // now both period measurements are calculated in milliseconds. + long systemDuration = systemTime2 - systemTime1; + long deviceDuration = (deviceTime2 - deviceTime1) / 1000; + long delta = Math.abs(systemDuration - deviceDuration); + // a deviation of 0.5 seconds (= 500 ms) is allowed. + timestampPrecisionOk = (delta <= 500); + } catch (Throwable t) { + System.out.println(" - Caught exception. Not failed."); + System.out.println(" - " + t.toString()); + return; + } finally { + device.close(); + } + if (! timestampsAvailable) { + throw new Exception("timestamps are not supported"); + } + if (! timestampPrecisionOk) { + throw new Exception("device timer not precise enough"); + } + successfulTests++; + } + + private static void doAll() throws Exception { + MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); + for (int i=0; i < infos.length; i++) { + MidiDevice device = MidiSystem.getMidiDevice(infos[i]); + if ((! (device instanceof Sequencer)) && + (! (device instanceof Synthesizer)) && + (device.getMaxReceivers() > 0 || device.getMaxReceivers() == -1)) { + + System.out.println("--------------"); + System.out.println("Testing MIDI device: " + infos[i]); + testDevice(device); + } + if (infos.length==0) { + System.out.println("No MIDI devices available!"); + } + } + } + + public static void main(String[] args) throws Exception { + if (!isMidiInstalled()) { + return; + } + doAll(); + if (successfulTests==0) { + System.out.println("Could not execute any of the tests. Test NOT failed."); + } else { + System.out.println("Test PASSED."); + } + } + + /** + * Returns true if at least one MIDI (port) device is correctly installed on + * the system. + */ + public static boolean isMidiInstalled() { + boolean result = false; + MidiDevice.Info[] devices = MidiSystem.getMidiDeviceInfo(); + for (int i = 0; i < devices.length; i++) { + try { + MidiDevice device = MidiSystem.getMidiDevice(devices[i]); + result = ! (device instanceof Sequencer) && ! (device instanceof Synthesizer); + } catch (Exception e1) { + System.err.println(e1); + } + if (result) + break; + } + if (!result) { + System.err.println("Soundcard does not exist or sound drivers not installed!"); + System.err.println("This test requires sound drivers for execution."); + } + return result; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Devices/OpenClose.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Devices/OpenClose.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,611 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Sequencer; +import javax.sound.midi.Synthesizer; +import javax.sound.midi.Transmitter; + +/** + * @test + * @bug 4616517 + * @summary Receiver.send() does not work properly. Tests open/close behaviour + * of MidiDevices. For this test, it is essential that the MidiDevice + * picked from the list of devices (MidiSystem.getMidiDeviceInfo()) is + * the same as the one used by + * MidiSystem.getReceiver()/getTransmitter(). To achieve this, default + * provider properties for Receivers/Transmitters are used. + */ +public class OpenClose { + + private static boolean isTestExecuted; + private static boolean isTestPassed; + + public static void main(String[] args) throws Exception { + boolean failed = false; + out("#4616517: Receiver.send() does not work properly"); + if (!isMidiInstalled()) { + out("Soundcard does not exist or sound drivers not installed!"); + out("This test requires sound drivers for execution."); + return; + } + MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); + MidiDevice outDevice = null; + MidiDevice inDevice = null; + for (int i = 0; i < infos.length; i++) { + MidiDevice device = MidiSystem.getMidiDevice(infos[i]); + if (! (device instanceof Synthesizer) && + ! (device instanceof Sequencer)) { + if (device.getMaxReceivers() != 0) { + outDevice = device; + } + if (device.getMaxTransmitters() != 0) { + inDevice = device; + } + } + } + if (outDevice != null) { + // set the default provider properties + System.setProperty(Receiver.class.getName(), + "#" + outDevice.getDeviceInfo().getName()); + } + if (inDevice != null) { + System.setProperty(Transmitter.class.getName(), + "#" + inDevice.getDeviceInfo().getName()); + } + out("Using MIDI OUT Device: " + outDevice); + out("Using MIDI IN Device: " + inDevice); + + isTestExecuted = false; + if (outDevice != null) { + isTestExecuted = true; + TestHelper testHelper = new ReceiverTestHelper(outDevice); + try { + doTest("Receiver", testHelper); + failed |= testHelper.hasFailed(); + } catch (Exception e) { + out("Exception occured, cannot test!"); + isTestExecuted = false; + } + } + + if (inDevice != null) { + isTestExecuted = true; + TestHelper testHelper = new TransmitterTestHelper(inDevice); + try { + doTest("Transmitter", testHelper); + failed |= testHelper.hasFailed(); + } catch (Exception e) { + out("Exception occured, cannot test!"); + isTestExecuted = false; + } + } + + isTestPassed = ! failed; + + if (isTestExecuted) { + if (isTestPassed) { + out("Test PASSED."); + } else { + throw new Exception("Test FAILED."); + } + } else { + out("Test NOT FAILED"); + } + } + + private static void doTest(String type, + TestHelper testHelper) throws Exception { + /* Case 1: + - MidiDevice.open() + - MidiDevice.close() + */ + out("checking " + type + " case 1..."); + testHelper.checkClosed(); + + testHelper.openDevice(); + testHelper.checkOpen(); + + testHelper.closeDevice(); + testHelper.checkClosed(); + + out("...OK"); + + /* Case 2a: + - MidiSystem.get[Receiver|Transmitter]() + - [Receiver|Transmitter].close() + */ + out("checking " + type + " case 2a..."); + testHelper.checkClosed(); + + testHelper.fetchObjectMidiSystem(); + testHelper.checkOpen(); + + testHelper.closeObjectMidiSystem(); + testHelper.checkClosed(); + + out("...OK"); + + /* Case 2b: + - MidiDevice.get[Receiver|Transmitter]() + - [Receiver|Transmitter].close() + */ + out("checking " + type + " case 2b..."); + testHelper.checkClosed(); + + testHelper.fetchObjectDevice(); + testHelper.checkClosed(); + + testHelper.closeObjectDevice(); + testHelper.checkClosed(); + + out("...OK"); + + /* Case 3a: + - MidiSystem.get[Receiver|Transmitter]() + - MidiDevice.open() + - MidiDevice.close() + - [Receiver|Transmitter].close() + */ + out("checking " + type + " case 3a..."); + testHelper.checkClosed(); + + testHelper.fetchObjectMidiSystem(); + testHelper.checkOpen(); + + testHelper.openDevice(); + testHelper.checkOpen(); + + testHelper.closeDevice(); + testHelper.checkClosed(); + + testHelper.closeObjectMidiSystem(); + testHelper.checkClosed(); + + out("...OK"); + + /* Case 3b: + - MidiDevice.get[Receiver|Transmitter]() + - MidiDevice.open() + - MidiDevice.close() + - [Receiver|Transmitter].close() + */ + out("checking " + type + " case 3b..."); + testHelper.checkClosed(); + + testHelper.fetchObjectDevice(); + testHelper.checkClosed(); + + testHelper.openDevice(); + testHelper.checkOpen(); + + testHelper.closeDevice(); + testHelper.checkClosed(); + + testHelper.closeObjectDevice(); + testHelper.checkClosed(); + + out("...OK"); + + /* Case 4a: + - MidiSystem.get[Receiver|Transmitter]() + - MidiDevice.open() + - [Receiver|Transmitter].close() + - MidiDevice.close() + */ + out("checking " + type + " case 4a..."); + testHelper.checkClosed(); + + testHelper.fetchObjectMidiSystem(); + testHelper.checkOpen(); + + testHelper.openDevice(); + testHelper.checkOpen(); + + testHelper.closeObjectMidiSystem(); + testHelper.checkOpen(); + + testHelper.closeDevice(); + testHelper.checkClosed(); + + out("...OK"); + + /* Case 4b: + - MidiDevice.get[Receiver|Transmitter]() + - MidiDevice.open() + - [Receiver|Transmitter].close() + - MidiDevice.close() + */ + out("checking " + type + " case 4b..."); + testHelper.checkClosed(); + + testHelper.fetchObjectDevice(); + testHelper.checkClosed(); + + testHelper.openDevice(); + testHelper.checkOpen(); + + testHelper.closeObjectDevice(); + testHelper.checkOpen(); + + testHelper.closeDevice(); + testHelper.checkClosed(); + + out("...OK"); + + /* Case 5a: + - MidiDevice.open() + - MidiSystem.get[Receiver|Transmitter]() + - MidiDevice.close() + - [Receiver|Transmitter].close() + */ + out("checking " + type + " case 5a..."); + testHelper.checkClosed(); + + testHelper.openDevice(); + testHelper.checkOpen(); + + testHelper.fetchObjectMidiSystem(); + testHelper.checkOpen(); + + testHelper.closeDevice(); + testHelper.checkClosed(); + + testHelper.closeObjectMidiSystem(); + testHelper.checkClosed(); + + out("...OK"); + + /* Case 5b: + - MidiDevice.open() + - MidiDevice.get[Receiver|Transmitter]() + - MidiDevice.close() + - [Receiver|Transmitter].close() + */ + out("checking " + type + " case 5b..."); + testHelper.checkClosed(); + + testHelper.openDevice(); + testHelper.checkOpen(); + + testHelper.fetchObjectDevice(); + testHelper.checkOpen(); + + testHelper.closeDevice(); + testHelper.checkClosed(); + + testHelper.closeObjectDevice(); + testHelper.checkClosed(); + + out("...OK"); + + /* Case 6a: + - MidiDevice.open() + - MidiSystem.get[Receiver|Transmitter]() + - [Receiver|Transmitter].close() + - MidiDevice.close() + */ + out("checking " + type + " case 6a..."); + testHelper.checkClosed(); + + testHelper.openDevice(); + testHelper.checkOpen(); + + testHelper.fetchObjectMidiSystem(); + testHelper.checkOpen(); + + testHelper.closeObjectMidiSystem(); + testHelper.checkOpen(); + + testHelper.closeDevice(); + testHelper.checkClosed(); + + out("...OK"); + + /* Case 6b: + - MidiDevice.open() + - MidiDevice.get[Receiver|Transmitter]() + - [Receiver|Transmitter].close() + - MidiDevice.close() + */ + out("checking " + type + " case 6b..."); + testHelper.checkClosed(); + + testHelper.openDevice(); + testHelper.checkOpen(); + + testHelper.fetchObjectDevice(); + testHelper.checkOpen(); + + testHelper.closeObjectDevice(); + testHelper.checkOpen(); + + testHelper.closeDevice(); + testHelper.checkClosed(); + + out("...OK"); + + /* Case 7: + - MidiSystem.get[Receiver|Transmitter]() // 1 + - MidiDevice.get[Receiver|Transmitter]() // 2 + - [Receiver|Transmitter].close() // 2 + - [Receiver|Transmitter].close() // 1 + */ + out("checking " + type + " case 7..."); + testHelper.checkClosed(); + + testHelper.fetchObjectMidiSystem(); + testHelper.checkOpen(); + + testHelper.fetchObjectDevice(); + testHelper.checkOpen(); + + testHelper.closeObjectDevice(); + testHelper.checkOpen(); + + testHelper.closeObjectMidiSystem(); + testHelper.checkClosed(); + + out("...OK"); + + /* Case 8: + - MidiSystem.get[Receiver|Transmitter]() // 1 + - MidiDevice.get[Receiver|Transmitter]() // 2 + - [Receiver|Transmitter].close() // 1 + - [Receiver|Transmitter].close() // 2 + */ + out("checking " + type + " case 8..."); + testHelper.checkClosed(); + + testHelper.fetchObjectMidiSystem(); + testHelper.checkOpen(); + + testHelper.fetchObjectDevice(); + testHelper.checkOpen(); + + testHelper.closeObjectMidiSystem(); + testHelper.checkClosed(); + + testHelper.closeObjectDevice(); + testHelper.checkClosed(); + + out("...OK"); + + /* Case 9: + - MidiDevice.get[Receiver|Transmitter]() // 2 + - MidiSystem.get[Receiver|Transmitter]() // 1 + - [Receiver|Transmitter].close() // 2 + - [Receiver|Transmitter].close() // 1 + */ + out("checking " + type + " case 9..."); + testHelper.checkClosed(); + + testHelper.fetchObjectDevice(); + testHelper.checkClosed(); + + testHelper.fetchObjectMidiSystem(); + testHelper.checkOpen(); + + testHelper.closeObjectDevice(); + testHelper.checkOpen(); + + testHelper.closeObjectMidiSystem(); + testHelper.checkClosed(); + + out("...OK"); + + /* Case 10: + - MidiDevice.get[Receiver|Transmitter]() // 2 + - MidiSystem.get[Receiver|Transmitter]() // 1 + - [Receiver|Transmitter].close() // 1 + - [Receiver|Transmitter].close() // 2 + */ + out("checking " + type + " case 10..."); + testHelper.checkClosed(); + + testHelper.fetchObjectDevice(); + testHelper.checkClosed(); + + testHelper.fetchObjectMidiSystem(); + testHelper.checkOpen(); + + testHelper.closeObjectMidiSystem(); + testHelper.checkClosed(); + + testHelper.closeObjectDevice(); + testHelper.checkClosed(); + + out("...OK"); + + /* Case N - 1: + - 10 x MidiSystem.get[Receiver|Transmitter]() + - 10 x [Receiver|Transmitter].close() + */ + out("checking " + type + " case N - 1..."); + TestHelper[] testHelpers = new TestHelper[10]; + for (int i = 0; i < 10; i++) { + testHelpers[i] = (TestHelper) testHelper.clone(); + } + testHelper.checkClosed(); + + for (int i = 0; i < 10; i++) { + testHelpers[i].fetchObjectMidiSystem(); + testHelper.checkOpen(); + } + + + for (int i = 0; i < 9; i++) { + testHelpers[i].closeObjectMidiSystem(); + testHelper.checkOpen(); + } + + testHelpers[9].closeObjectMidiSystem(); + testHelper.checkClosed(); + + out("...OK"); + } + + private static void out(String message) { + System.out.println(message); + } + + private static abstract class TestHelper implements Cloneable { + private MidiDevice device; + private boolean failed; + + protected TestHelper(MidiDevice device) { + this.device = device; + failed = false; + } + + protected MidiDevice getDevice() { + return device; + } + + public boolean hasFailed() { + return failed; + } + + public void openDevice() throws MidiUnavailableException { + getDevice().open(); + } + + public void closeDevice() { + getDevice().close(); + } + + public void checkOpen(){ + checkOpen(getDevice(), true); + } + + public void checkClosed(){ + checkOpen(getDevice(), false); + } + + private void checkOpen(MidiDevice device, boolean desiredState) { + if (device.isOpen() != desiredState) { + out("device should be " + + getStateString(desiredState) + ", but isn't!"); + failed = true; + } + } + + + private String getStateString(boolean state) { + return state ? "open" : "closed"; + } + + + public abstract void fetchObjectMidiSystem() throws MidiUnavailableException; + public abstract void fetchObjectDevice() throws MidiUnavailableException; + public abstract void closeObjectMidiSystem(); + public abstract void closeObjectDevice(); + + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + return null; + } + } + } + + private static class ReceiverTestHelper extends TestHelper { + private Receiver receiverMidiSystem; + private Receiver receiverDevice; + + public ReceiverTestHelper(MidiDevice device) { + super(device); + } + + public void fetchObjectMidiSystem() throws MidiUnavailableException { + receiverMidiSystem = MidiSystem.getReceiver(); + } + + + public void fetchObjectDevice() throws MidiUnavailableException { + receiverDevice = getDevice().getReceiver(); + } + + + public void closeObjectMidiSystem() { + receiverMidiSystem.close(); + } + + + public void closeObjectDevice() { + receiverDevice.close(); + } + } + + private static class TransmitterTestHelper extends TestHelper { + private Transmitter transmitterMidiSystem; + private Transmitter transmitterDevice; + + public TransmitterTestHelper(MidiDevice device) { + super(device); + } + + public void fetchObjectMidiSystem() throws MidiUnavailableException { + transmitterMidiSystem = MidiSystem.getTransmitter(); + } + + + public void fetchObjectDevice() throws MidiUnavailableException { + transmitterDevice = getDevice().getTransmitter(); + } + + + public void closeObjectMidiSystem() { + transmitterMidiSystem.close(); + } + + + public void closeObjectDevice() { + transmitterDevice.close(); + } + } + + /** + * Returns true if at least one MIDI (port) device is correctly installed on + * the system. + */ + public static boolean isMidiInstalled() { + boolean result = false; + MidiDevice.Info[] devices = MidiSystem.getMidiDeviceInfo(); + for (int i = 0; i < devices.length; i++) { + try { + MidiDevice device = MidiSystem.getMidiDevice(devices[i]); + result = ! (device instanceof Sequencer) && ! (device instanceof Synthesizer); + } catch (Exception e1) { + System.err.println(e1); + } + if (result) + break; + } + return result; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Devices/ReceiverTransmitterAvailable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Devices/ReceiverTransmitterAvailable.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Transmitter; + +/** + * @test + * @bug 4616517 + * @summary Receiver.send() does not work properly + */ +public class ReceiverTransmitterAvailable { + + private static boolean isTestExecuted; + private static boolean isTestPassed; + + public static void main(String[] args) throws Exception { + out("#4616517: Receiver.send() does not work properly"); + doAllTests(); + if (isTestExecuted) { + if (isTestPassed) { + out("Test PASSED."); + } else { + throw new Exception("Test FAILED."); + } + } else { + out("Test NOT FAILED"); + } + } + + private static void doAllTests() { + boolean problemOccured = false; + boolean succeeded = true; + MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); + for (int i = 0; i < infos.length; i++) { + MidiDevice device = null; + try { + device = MidiSystem.getMidiDevice(infos[i]); + succeeded &= doTest(device); + } catch (MidiUnavailableException e) { + out("exception occured; cannot test"); + problemOccured = true; + } + } + if (infos.length == 0) { + out("Soundcard does not exist or sound drivers not installed!"); + out("This test requires sound drivers for execution."); + } + isTestExecuted = !problemOccured; + isTestPassed = succeeded; + } + + private static boolean doTest(MidiDevice device) { + boolean succeeded = true; + out("Testing: " + device); + boolean expectingReceivers = (device.getMaxReceivers() != 0); + boolean expectingTransmitters = (device.getMaxTransmitters() != 0); + try { + Receiver rec = device.getReceiver(); + rec.close(); + if (! expectingReceivers) { + out("no exception on getting Receiver"); + succeeded = false; + } + } catch (MidiUnavailableException e) { + if (expectingReceivers) { + out("Exception on getting Receiver: " + e); + succeeded = false; + } + } + try { + Transmitter trans = device.getTransmitter(); + trans.close(); + if (! expectingTransmitters) { + out("no exception on getting Transmitter"); + succeeded = false; + } + } catch (MidiUnavailableException e) { + if (expectingTransmitters) { + out("Exception on getting Transmitter: " + e); + succeeded = false; + } + } + return succeeded; + } + + private static void out(String message) { + System.out.println(message); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Devices/Reopen.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Devices/Reopen.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequencer; +import javax.sound.midi.Synthesizer; + +/** + * @test + * @bug 4914667 + * @summary Closing and reopening MIDI IN device on Linux throws + * MidiUnavailableException + */ +public class Reopen { + + private static boolean isTestExecuted; + private static boolean isTestPassed; + + /* + * run manually: + * java Reopen 100 in for 100 iterations on the MIDI IN device + * java Reopen 16 out for 16 iterations on the MIDI OUT device + */ + public static void main(String[] args) throws Exception { + if (args.length == 0) { + doAllTests(); + } else if (args.length == 2) { + int numIterations = Integer.parseInt(args[0]); + if (args[1].equals("in")) { + doTest(numIterations, true); + } else { + doTest(numIterations, false); + } + } else { + out("usage: java Reopen in|out"); + } + } + + private static void doAllTests() throws Exception { + out("#4914667: Closing and reopening MIDI IN device on Linux throws MidiUnavailableException"); + boolean success = true; + try { + success &= doTest(20, true); // MIDI IN + success &= doTest(20, false); // MIDI OUT + isTestExecuted = true; + } catch (Exception e) { + out(e); + isTestExecuted = false; + } + isTestPassed = success; + if (isTestExecuted) { + if (isTestPassed) { + out("Test PASSED."); + } else { + throw new Exception("Test FAILED."); + } + } else { + out("Test NOT FAILED"); + } + } + + private static boolean doTest(int numIterations, boolean input) throws Exception { + MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); + MidiDevice outDevice = null; + MidiDevice inDevice = null; + for (int i = 0; i < infos.length; i++) { + MidiDevice device = MidiSystem.getMidiDevice(infos[i]); + if (! (device instanceof Sequencer) && + ! (device instanceof Synthesizer)) { + if (device.getMaxReceivers() != 0) { + outDevice = device; + } + if (device.getMaxTransmitters() != 0) { + inDevice = device; + } + } + } + MidiDevice testDevice = null; + if (input) { + testDevice = inDevice; + } else { + testDevice = outDevice; + } + if (testDevice == null) { + out("Cannot test: device not available."); + return true; + } + out("Using Device: " + testDevice); + + for (int i = 0; i < numIterations; i++) { + out("@@@ ITERATION: " + i); + testDevice.open(); + // This sleep ensures that the thread of MidiInDevice is started. + sleep(50); + testDevice.close(); + } + return true; + } + + private static void sleep(int milliseconds) { + try { + Thread.sleep(milliseconds); + } catch (InterruptedException e) { + } + } + + private static void out(Throwable t) { + t.printStackTrace(System.out); + } + + private static void out(String message) { + System.out.println(message); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/File/SMFCp037.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/File/SMFCp037.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; + +import javax.sound.midi.MidiSystem; + +/** + * @test + * @bug 4303933 + * @summary MidiSystem fails to load MIDI file on systems with EBCDIC simulation + */ +public class SMFCp037 { + + public static void main(String args[]) throws Exception { + // Test to read MIDI files with Cp037 character set - close enough + // for EBCDIC simulation + System.setProperty("file.encoding", "Cp037"); + // try to read this file with Cp037 encoding + MidiSystem.getSequence(new ByteArrayInputStream(SHORT_SMF)); + System.out.println(" test passed."); + } + +public static byte[] SHORT_SMF = { + 77, 84, 104, 100, 0, 0, 0, 6, 0, 1, 0, 2, 0, 120, 77, 84, 114, 107, 0, 0, + 0, 27, 0, -1, 3, 19, 77, 73, 68, 73, 32, 116, 101, 115, 116, 32, 45, 32, + 116, 114, 97, 99, 107, 32, 48, 0, -1, 47, 0, 77, 84, 114, 107, 0, 0, 0, -44, + 0, -1, 3, 19, 77, 73, 68, 73, 32, 116, 101, 115, 116, 32, 45, 32, 116, 114, + 97, 99, 107, 32, 49, 0, -64, 30, 0, -112, 68, 126, 0, -32, 6, 67, 0, 14, + 71, 0, 20, 74, 0, 26, 77, 0, 32, 80, 0, 42, 85, 6, 50, 89, 6, 56, 92, 5, + 66, 97, 6, 74, 101, 6, 80, 104, 11, 84, 106, 20, 76, 102, 6, 70, 99, 5, 60, + 94, 6, 52, 90, 5, 44, 86, 4, 34, 81, 5, 26, 77, 5, 20, 74, 6, 10, 69, 5, + 2, 65, 7, 0, 64, 42, -112, 66, 123, 11, 68, 0, 72, 63, 126, 4, 66, 0, 43, + -32, 0, 63, 6, 0, 60, 7, 0, 56, 6, 0, 53, 5, 0, 49, 5, 0, 43, 4, 0, 37, 3, + 0, 30, 3, 0, 25, 3, 0, 19, 3, 0, 13, 4, 0, 8, 4, 0, 2, 4, 0, 0, 70, 0, 3, + 5, 0, 9, 3, 0, 14, 7, 0, 16, 25, 0, 21, 5, 0, 25, 7, 0, 28, 5, 0, 32, 5, + 0, 36, 5, 0, 41, 6, 0, 46, 5, 0, 50, 5, 0, 53, 4, 0, 58, 7, 0, 61, 7, 0, + 64, 117, -112, 63, 0, 0, -1, 47, 0 + }; +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/File/SMFParserBreak.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/File/SMFParserBreak.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequence; + +/** + * @test + * @bug 4910986 + * @summary MIDI file parser breaks up on http connection + */ +public class SMFParserBreak { + + public static void main(String[] args) throws Exception { + + InputStream is = new ByteArrayInputStream(midifile); + // create a buffered input stream that seems + // to be on an unfortunate boundary for the + // 1.4.2 SMF parser implementation + is = new ChunkInputStream(is, 32); + Sequence sequence = MidiSystem.getSequence(is); + + long duration = sequence.getMicrosecondLength() / 10000; + System.out.println("Duration: "+duration+" deciseconds "); + + // the test is passed if no exception thrown + System.out.println("Test passed"); + } + + // A MIDI file + static byte[] midifile = { + 77, 84, 104, 100, 0, 0, 0, 6, 0, 1, 0, 3, -30, 120, 77, 84, 114, 107, 0, + 0, 0, 123, 0, -112, 30, 100, -113, 49, -128, 50, 100, -114, 69, -112, 31, + 100, -114, 33, -128, 51, 100, -114, 55, -112, 32, 100, -114, 120, -128, 52, + 100, -114, 40, -112, 33, 100, -114, 26, -128, 53, 100, -114, 26, -112, 34, + 100, -114, 76, -128, 54, 100, -114, 12, -112, 35, 100, -114, 91, -128, 55, + 100, -114, 69, -112, 36, 100, -114, 33, -128, 56, 100, -114, 55, -112, 37, + 100, -114, 84, -128, 57, 100, -114, 40, -112, 38, 100, -114, 26, -128, 58, + 100, -114, 26, -112, 39, 100, -113, 24, -128, 59, 100, -113, 60, -112, 40, + 100, -113, 110, -128, 60, 100, -113, 96, -112, 41, 100, -113, 39, -128, 61, + 100, 0, -1, 47, 0, 77, 84, 114, 107, 0, 0, 0, 4, 0, -1, 47, 0, 77, 84, 114, + 107, 0, 0, 0, 4, 0, -1, 47, 0 + }; +} + +/* an input stream that always returns data in chunks */ +class ChunkInputStream extends FilterInputStream { + int chunkSize; + int p = 0; // position + + public ChunkInputStream(InputStream is, int chunkSize) { + super(is); + this.chunkSize = chunkSize; + } + + // override to increase counter + public int read() throws IOException { + int ret = super.read(); + if (ret >= 0) { + p++; + } + return ret; + } + + // override to make sure that read(byte[], int, int) is used + public int read(byte[] b) throws IOException { + return read(b, 0, b.length); + } + + // override to split the data in chunks + public int read(byte[] b, int off, int len) throws IOException { + // if we would pass a chunk boundary, + // only return up to the chunk boundary + if ( (p / chunkSize) < ( (p+len) / chunkSize)) { + // p+len is in the next chunk + len -= ((p+len) % chunkSize); + } + int ret = super.read(b, off, len); + if (ret >= 0) { + p += ret; + } + return ret; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/File/WriteRealTimeMessageNPE.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/File/WriteRealTimeMessageNPE.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequence; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Track; + +/** + * @test + * @bug 5048381 + * @summary NPE when writing a sequence with a realtime MIDI message + */ +public class WriteRealTimeMessageNPE { + + public static void main(String args[]) throws Exception { + System.out.println("5048381: NullPointerException when saving a MIDI sequence"); + boolean npeThrown = false; + boolean noEx = false; + + Sequence seq = new Sequence(Sequence.PPQ, 384, 1); + Track t = seq.getTracks()[0]; + ShortMessage msg = new ShortMessage(); + msg.setMessage(0xF8, 0, 0); + t.add(new MidiEvent(msg, 0)); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try { + MidiSystem.write(seq, 0, out); + noEx = true; + } catch (NullPointerException npe) { + npeThrown = true; + System.out.println("## Failed: Threw unexpected NPE: "+npe); + throw new Exception("Test FAILED!"); + } catch (Exception e) { + System.out.println("Threw unexpected Exception: "+e); + System.out.println("But at least did not throw NPE..."); + } + if (noEx) { + InputStream is = new ByteArrayInputStream(out.toByteArray()); + seq = MidiSystem.getSequence(is); + System.out.println("Sequence has "+seq.getTracks().length+" tracks."); + if (seq.getTracks().length > 0) { + System.out.println("Track 0 has "+seq.getTracks()[0].size()+" events."); + } + } + System.out.println("Test passed."); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/MetaMessage/MetaMessageClone.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/MetaMessage/MetaMessageClone.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MetaMessage; + +/** + * @test + * @bug 4511796 + * @summary Check that MetaMessage.clone() works correctly + */ +public class MetaMessageClone { + + private static void printMsg(MetaMessage msg, byte[] data) { + System.out.println(""+msg.getLength()+" total bytes, type="+msg.getType()+", dataLength="+data.length); + } + + private static void checkClone(MetaMessage msg) throws Exception { + System.out.print("Original: "); + byte[] msgData=msg.getData(); + printMsg(msg, msgData); + MetaMessage msg2=(MetaMessage) msg.clone(); + byte[] msg2Data=msg2.getData(); + System.out.print("Clone: "); + printMsg(msg2, msg2Data); + + if (msg2.getLength()!=msg.getLength() + || msg.getType()!=msg2.getType() + || msgData.length!=msg2Data.length) { + throw new Exception("cloned MetaMessage is not equal."); + } + int max=Math.min(msgData.length, 10); + for (int i=0; i 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + //else just print + else + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn ) + { + messageText.append( messageIn + "\n" ); + } + + //catch presses of the passed and failed buttons. + //simply call the standard pass() or fail() static methods of + //DialogOrient + public void actionPerformed( ActionEvent e ) + { + if( e.getActionCommand() == "pass" ) + { + Test6411624.pass(); + } + else + { + Test6411624.fail(); + } + } + + }// TestDialog class diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/MidiSystem/6411624/bug6411624.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/MidiSystem/6411624/bug6411624.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Sequencer; +import javax.sound.midi.Synthesizer; +import javax.sound.midi.Transmitter; + +/** + * This test should be run on specific environment (solaris or linux w/o + * audio card installed). + */ +public class bug6411624 { + + public static void main(String args[]) throws Exception { + log("This test should only be run on solaris or linux system"); + log("without audio card installed (to test on SunRay set"); + log("incorrect $AUDIODEV value)."); + readln(); + + boolean testRecv = false; + boolean testTrans = false; + boolean testSeq = true; + + // print add info (midi device list) + try { + MidiDevice.Info[] midis = MidiSystem.getMidiDeviceInfo(); + log("MidiDevices (total " + midis.length + "):"); + for (int i=0; i transmitters = seq.getTransmitters(); + int size = transmitters.size(); + out(" transmitters.size()="+size); + if (size != 1 && connected) { + out(" should have 1 connection! Failed."); + failed = true; + } + if (size != 0 && !connected) { + out(" should have 0 connections! Failed."); + failed = true; + } + out(" closing..."); + seq.close(); + transmitters = seq.getTransmitters(); + size = transmitters.size(); + out(" transmitters.size()="+size); + if (size != 0) { + out(" should have 0 connections! Failed."); + failed = true; + } + + out(" opening again..."); + seq.open(); + transmitters = seq.getTransmitters(); + size = transmitters.size(); + out(" transmitters.size()="+size); + if (size != 1 && connected) { + out(" should have 1 connection! Failed."); + failed = true; + } + if (size != 0 && !connected) { + out(" should have 0 connections! Failed."); + failed = true; + } + } catch (Exception e) { + System.err.println(" unexpectedException was thrown: " + e); + System.err.println(" causes this test to FAIL."); + failed = true; + } + seq.close(); + } + + static void out(String s) { + System.out.println(s); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/MidiSystem/MidiFileTypeUniqueness.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/MidiSystem/MidiFileTypeUniqueness.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MidiSystem; + +/** + * @test + * @bug 4883060 + * @summary AudioSystem.getAudioFileTypes returns duplicates + */ +public class MidiFileTypeUniqueness { + + public static void main(String[] args) throws Exception { + boolean foundDuplicates = false; + int[] aTypes = MidiSystem.getMidiFileTypes(); + for (int i = 0; i < aTypes.length; i++) + { + for (int j = 0; j < aTypes.length; j++) + { + if (aTypes[i] == aTypes[j] && i != j) { + foundDuplicates = true; + } + } + } + if (foundDuplicates) { + throw new Exception("Test failed"); + } else { + System.out.println("Test passed"); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/MidiSystem/ProviderCacheing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/MidiSystem/ProviderCacheing.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.List; + +import com.sun.media.sound.JDK13Services; + +/** + * @test + * @bug 4776511 + * @summary RFE: Setting the default MixerProvider. Test the cacheing of + * providers. This is a part of the test for 4776511. + * @modules java.desktop/com.sun.media.sound + */ +public class ProviderCacheing { + + private static final Class[] providerClasses = { + javax.sound.midi.spi.MidiDeviceProvider.class, + javax.sound.midi.spi.MidiFileReader.class, + javax.sound.midi.spi.MidiFileWriter.class, + javax.sound.midi.spi.SoundbankReader.class, + }; + + public static void main(String[] args) throws Exception { + boolean allCached = true; + for (int i = 0; i < providerClasses.length; i++) { + List list0 = JDK13Services.getProviders(providerClasses[i]); + List list1 = JDK13Services.getProviders(providerClasses[i]); + if (list0 == list1) { + out("Providers should not be cached for " + providerClasses[i]); + allCached = false; + } + } + + if (! allCached) { + throw new Exception("Test failed"); + } else { + out("Test passed"); + } + } + + private static void out(String message) { + System.out.println(message); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/MidiSystem/testdata/conf/sound.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/MidiSystem/testdata/conf/sound.properties Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,27 @@ +# +# Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +javax.sound.midi.Receiver=xyz#123 +javax.sound.midi.Transmitter=xyz#123 +javax.sound.midi.Sequencer=xyz#123 +javax.sound.midi.Synthesizer=xyz#123 diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Sequence/GetMicrosecondLength.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Sequence/GetMicrosecondLength.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.Sequence; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Track; + +/** + * @test + * @bug 4929955 + * @summary Sequence.getMicrosecondLength() returns wrong value + */ +public class GetMicrosecondLength { + + public static boolean failed = false; + //private static Sequencer seq = null; + + public static void main(String[] args) throws Exception { + /* + try { + seq = MidiSystem.getSequencer(); + } catch (Exception e) { + e.printStackTrace(); + } + */ + for (int sec = 1; sec < 10; sec += 4) { + for (int tempo=0; tempo < 1000; tempo+=120) { + for (int resolution=1; resolution < 480; ) { + testSequence(sec, tempo, resolution); + if (resolution == 1) { + resolution = 120; + } else { + resolution += 120; + } + } + } + } + if (failed) throw new Exception("Test FAILED!"); + out("Test Passed."); + } + + /** + * Create a new Sequence for testing. + */ + private static void testSequence(int lengthInSeconds, int tempoInBPM, int resolution) { + Sequence sequence = null; + long lengthInMicroseconds = lengthInSeconds * 1000000; + boolean createTempoEvent = true; + if (tempoInBPM == 0) { + tempoInBPM = 120; + createTempoEvent = false; + System.out.print("Creating sequence: "+lengthInSeconds+"sec, " + +"resolution="+resolution+" ticks/beat..."); + } else { + System.out.print("Creating sequence: "+lengthInSeconds+"sec, " + +tempoInBPM+" beats/min, " + +"resolution="+resolution+" ticks/beat..."); + } + //long lengthInTicks = (lengthInMicroseconds * resolution) / tempoInBPM; + long lengthInTicks = (lengthInMicroseconds * tempoInBPM * resolution) / 60000000l; + //out("expected length in ticks: " + lengthInTicks); + try { + sequence = new Sequence(Sequence.PPQ, resolution); + Track track = sequence.createTrack(); + if (createTempoEvent) { + int tempoInMPQ = (int) (60000000l / tempoInBPM); + MetaMessage tm = new MetaMessage(); + byte[] msg = new byte[3]; + msg[0] = (byte) (tempoInMPQ >> 16); + msg[1] = (byte) ((tempoInMPQ >> 8) & 0xFF); + msg[2] = (byte) (tempoInMPQ & 0xFF); + + tm.setMessage(0x51 /* Meta Tempo */, msg, msg.length); + track.add(new MidiEvent(tm, 0)); + //out("regtest: tempoInMPQ="+tempoInMPQ); + //out("Added tempo event: new size="+track.size()); + } + ShortMessage mm = new ShortMessage(); + mm.setMessage(0xF6, 0, 0); + MidiEvent me = new MidiEvent(mm, lengthInTicks); + track.add(me); + //out("Added realtime event: new size="+track.size()); + } catch (InvalidMidiDataException e) { + out(e); + } + boolean thisFailed = false; + long actualLengthInTicks = sequence.getTickLength(); + // allow +/- 5% + if (Math.abs(actualLengthInTicks - lengthInTicks) > lengthInTicks / 20) { + out("FAILED:"); + out(" expected length in ticks: " + lengthInTicks); + out(" actual length in ticks : " + actualLengthInTicks); + thisFailed = true; + } + long actualLengthInUs = sequence.getMicrosecondLength(); + // allow +/- 5% + if (Math.abs(actualLengthInUs - lengthInMicroseconds) > lengthInMicroseconds / 20) { + if (!thisFailed) { + out("FAILED:"); + } + out(" expected length in microsecs: " + lengthInMicroseconds); + out(" actual length in microsecs : " + actualLengthInUs); + thisFailed = true; + } + if (!thisFailed) { + out("OK"); + } + /*if (seq != null) { + try { + seq.setSequence(sequence); + out("Sequencer tempo="+seq.getTempoInBPM()); + } catch (Exception e) { + e.printStackTrace(); + } + } + */ + failed |= thisFailed; + } + + + private static void out(Throwable t) { + t.printStackTrace(System.out); + } + + private static void out(String message) { + System.out.println(message); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Sequence/MidiSMPTE.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Sequence/MidiSMPTE.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequence; + +/** + * @test + * @bug 4291250 + * @summary Midi files with SMPTE time do not play properly + */ +public class MidiSMPTE { + + public static void main(String[] args) throws Exception { + Sequence s = null; + //File midiFile = new File("outsmpte.mid"); + //InputStream is = new FileInputStream(midiFile); + //is = new BufferedInputStream(is); + InputStream is = new ByteArrayInputStream(smptemidifile); + s = MidiSystem.getSequence(is); + long duration = s.getMicrosecondLength() / 1000000; + System.out.println("Duration: "+duration+" seconds "); + if (duration > 14) { + throw new Exception("SMPTE time reader is broken! Test FAILED"); + } + System.out.println("Test passed"); + } + + public static void printFile(String filename) throws Exception { + File file = new File(filename); + FileInputStream fis = new FileInputStream(file); + byte[] data = new byte[(int) file.length()]; + fis.read(data); + String s = ""; + for (int i=0; i72) { + System.out.println(s); + s=""; + } + } + System.out.println(s); + } + + // A MIDI file with SMPTE timing + static byte[] smptemidifile = { + 77, 84, 104, 100, 0, 0, 0, 6, 0, 1, 0, 3, -30, 120, 77, 84, 114, 107, 0, + 0, 0, 123, 0, -112, 30, 100, -113, 49, -128, 50, 100, -114, 69, -112, 31, + 100, -114, 33, -128, 51, 100, -114, 55, -112, 32, 100, -114, 120, -128, 52, + 100, -114, 40, -112, 33, 100, -114, 26, -128, 53, 100, -114, 26, -112, 34, + 100, -114, 76, -128, 54, 100, -114, 12, -112, 35, 100, -114, 91, -128, 55, + 100, -114, 69, -112, 36, 100, -114, 33, -128, 56, 100, -114, 55, -112, 37, + 100, -114, 84, -128, 57, 100, -114, 40, -112, 38, 100, -114, 26, -128, 58, + 100, -114, 26, -112, 39, 100, -113, 24, -128, 59, 100, -113, 60, -112, 40, + 100, -113, 110, -128, 60, 100, -113, 96, -112, 41, 100, -113, 39, -128, 61, + 100, 0, -1, 47, 0, 77, 84, 114, 107, 0, 0, 0, 4, 0, -1, 47, 0, 77, 84, 114, + 107, 0, 0, 0, 4, 0, -1, 47, 0 + }; + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Sequence/SMPTEDuration.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Sequence/SMPTEDuration.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.Sequence; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Track; + +/** + * @test + * @bug 4702328 + * @summary Wrong time in sequence for SMPTE based types + */ +public class SMPTEDuration { + + public static void main(String args[]) throws Exception { + int[][] dataMes = { {ShortMessage.NOTE_ON, 10, 0x24, 0x50} , + { ShortMessage.NOTE_OFF, 10, 0x24, 0x44 }, + { ShortMessage.NOTE_ON, 10, 0x24, 0x50 }, + { ShortMessage.NOTE_ON, 10, 0x26, 0x50 }, + { ShortMessage.NOTE_OFF, 10, 0x26, 0x53 } }; + long[] ticks = { 0, 68, 240, 240, 286}; + int res = 240; + ShortMessage msg; + Sequence midiData = null; + Track track; + boolean failed = false; + + + try { + midiData = new Sequence(Sequence.SMPTE_24 , res); + } catch (InvalidMidiDataException invMidiEx) { + invMidiEx.printStackTrace(System.out); + System.out.println("Unexpected InvalidMidiDataException: " + + invMidiEx.getMessage()); + failed = true; + } + track = midiData.createTrack(); + for (int i = 0; i < dataMes.length; i++) { + msg = new ShortMessage(); + try { + msg.setMessage(dataMes[i][0], dataMes[i][1], dataMes[i][2], + dataMes[i][3]); + } catch (InvalidMidiDataException invMidiEx) { + invMidiEx.printStackTrace(System.out); + System.out.println("Unexpected InvalidMidiDataException: " + + invMidiEx.getMessage()); + failed = true; + } + track.add(new MidiEvent(msg, ticks[i])); + } + // lengthInMs = (tickLength*1000000)/(divType*Res) + long micros = (long) ((midiData.getTickLength() * 1000000) / (res * Sequence.SMPTE_24)); + if (midiData.getMicrosecondLength() != micros) { + failed = true; + System.out.println("getMicrosecondLength() returns wrong length: " + + midiData.getMicrosecondLength()); + System.out.println("getMicrosecondLength() must return length: " + + micros); + } + if (midiData.getTickLength() != 286) { + failed = true; + System.out.println("getTickLength() returns wrong length: " + + midiData.getTickLength()); + } + + if( failed == true ) { + throw new Exception("test failed"); + } else { + System.out.println("Passed."); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Sequencer/LoopIAE.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Sequencer/LoopIAE.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Track; + +/** + * @test + * @bug 5025549 + * @summary Verify that setLoopEndPoint throws IAE + */ +public class LoopIAE { + + static ShortMessage MidiMsg3(int a, int b, int c) { + try { + ShortMessage msg = new ShortMessage(); + msg.setMessage((byte)a,(byte)b,(byte)c); + return msg; + } catch(InvalidMidiDataException ex) { + throw new RuntimeException(); + } + } + + static boolean failed = false; + + public static void main(String[] argv) throws Exception { + if (!hasSequencer()) { + return; + } + Sequencer sequencer = MidiSystem.getSequencer(); + Sequence sequence = new Sequence(Sequence.PPQ, 240); + Track track = sequence.createTrack(); + + track.add(new MidiEvent(MidiMsg3(ShortMessage.NOTE_ON+0,45,100),0)); + track.add(new MidiEvent(MidiMsg3(ShortMessage.NOTE_ON+0,45,0),0 + 240)); + track.add(new MidiEvent(MidiMsg3(ShortMessage.NOTE_ON+9,45,100),10*20)); + track.add(new MidiEvent(MidiMsg3(ShortMessage.NOTE_ON+9,45,0),10*20 + 10)); + + try { + sequencer.open(); + sequencer.setSequence(sequence); + sequencer.setTempoInBPM(100); + + System.out.println("Setting loop end point to 1"); + sequencer.setLoopEndPoint(1); + System.out.println(" -> effectively: "+sequencer.getLoopEndPoint()); + System.out.println("Setting loop start point to 2 -- should throw IAE"); + sequencer.setLoopStartPoint(2); + System.out.println(" -> effectively: "+sequencer.getLoopStartPoint()); + System.out.println("No IllegalArgumentException was thrown!"); + failed = true; + } catch (IllegalArgumentException iae) { + System.out.println("IAE was thrown correctly."); + } catch (MidiUnavailableException mue) { + System.out.println("MidiUnavailableException was thrown: " + mue); + System.out.println("Cannot execute test."); + } catch (InvalidMidiDataException imEx) { + System.out.println("InvalidMidiDataException was thrown."); + imEx.printStackTrace(); + System.out.println("Cannot execute test."); + } finally { + if (sequencer != null && sequencer.isOpen()) { + sequencer.close(); + } + } + if (failed) { + throw new Exception("Test FAILED!"); + } + System.out.println("test passed."); + } + + static boolean hasSequencer() { + try { + Sequencer seq = MidiSystem.getSequencer(); + if (seq != null) { + if (seq.isOpen()) { + seq.close(); + } + return true; + } + } catch (Exception e) { + e.printStackTrace(); + } + System.out.println("No sequencer available! Cannot execute test."); + return false; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Sequencer/Looping.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Sequencer/Looping.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaEventListener; +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Track; + +/** + * @test + * @bug 4204105 + * @summary RFE: add loop() method(s) to Sequencer + * @key intermittent + */ +public class Looping { + + public static void main(String[] args) throws Exception { + out("4204105: RFE: add loop() method(s) to Sequencer"); + boolean passed = testAll(); + if (passed) { + out("Test PASSED."); + } else { + throw new Exception("Test FAILED."); + } + } + + /** + * Execute the test on all available Sequencers. + * + * @return true if the test passed for all Sequencers, false otherwise + */ + private static boolean testAll() throws Exception { + boolean result = true; + MidiDevice.Info[] devices = MidiSystem.getMidiDeviceInfo(); + for (int i = 0; i < devices.length; i++) { + MidiDevice device = MidiSystem.getMidiDevice(devices[i]); + if (device instanceof Sequencer) { + result &= testSequencer((Sequencer) device); + } + } + return result; + } + + /** + * Execute the test on the passed Sequencer. + * + * @return true if the test is passed this Sequencer, false otherwise + */ + private static boolean testSequencer(Sequencer seq) throws Exception{ + boolean result = true; + out("testing: " + seq); + + result &= testGetSet(seq); + + seq.setSequence(createSequence()); + + result &= testGetSet(seq); + + result &= testPlay(seq); + + return result; + } + + private static boolean testGetSet(Sequencer seq) { + boolean result = true; + Sequence sequence = seq.getSequence(); + boolean isSequenceLoaded = (sequence != null); + + out("TestGetSet"); + + try { + if (seq.getLoopStartPoint() != 0) { + out("start point", isSequenceLoaded, + "isn't 0!"); + result = false; + } + } catch (IllegalArgumentException iae) { + if (!isSequenceLoaded) { + out("Caught permissable IllegalArgumentException:"); + } else { + out("Threw unacceptable IllegalArgumentException! FAILED"); + result = false; + } + out(iae.toString()); + } + + if (seq.getLoopEndPoint() != -1) { + out("end point", isSequenceLoaded, + "isn't -1!"); + result = false; + } + + try { + seq.setLoopStartPoint(25); + if (seq.getLoopStartPoint() != 25) { + out("setLoopStartPoint()", isSequenceLoaded, + "doesn't set the start point correctly!"); + result = false; + } + } catch (IllegalArgumentException iae) { + if (!isSequenceLoaded) { + out("Caught permissable IllegalArgumentException:"); + } else { + out("Threw unacceptable IllegalArgumentException! FAILED"); + result = false; + } + out(iae.toString()); + } + + try { + seq.setLoopEndPoint(26); + if (seq.getLoopEndPoint() != 26) { + out("setLoopEndPoint()", isSequenceLoaded, + "doesn't set the end point correctly!"); + result = false; + } + } catch (IllegalArgumentException iae) { + if (!isSequenceLoaded) { + out("Caught permissable IllegalArgumentException:"); + } else { + out("Threw unacceptable IllegalArgumentException! FAILED"); + result = false; + } + out(iae.toString()); + } + + try { + seq.setLoopStartPoint(0); + if (seq.getLoopStartPoint() != 0) { + out("setLoopStartPoint()", isSequenceLoaded, + "doesn't set the start point correctly!"); + result = false; + } + } catch (IllegalArgumentException iae) { + if (!isSequenceLoaded) { + out("Caught permissable IllegalArgumentException:"); + } else { + out("Threw unacceptable IllegalArgumentException! FAILED"); + result = false; + } + out(iae.toString()); + } + + if (isSequenceLoaded) { + seq.setLoopEndPoint(sequence.getTickLength()); + if (seq.getLoopEndPoint() != sequence.getTickLength()) { + out("setLoopEndPoint()", isSequenceLoaded, + "doesn't set the end point correctly!"); + result = false; + } + } else { + // fails + seq.setLoopEndPoint(-1); + if (seq.getLoopEndPoint() != -1) { + out("setLoopEndPoint()", isSequenceLoaded, + "doesn't set the end point correctly!"); + result = false; + } + } + + if (seq.getLoopCount() != 0) { + out("loop count", isSequenceLoaded, + "isn't 0!"); + result = false; + } + + seq.setLoopCount(1001); + if (seq.getLoopCount() != 1001) { + out("setLoopCount()", isSequenceLoaded, + "doesn't set the loop count correctly!"); + result = false; + } + + seq.setLoopCount(Sequencer.LOOP_CONTINUOUSLY); + if (seq.getLoopCount() != Sequencer.LOOP_CONTINUOUSLY) { + out("setLoopCount(Sequencer.LOOP_CONTINUOUSLY)", isSequenceLoaded, + "doesn't set the loop count correctly!"); + result = false; + } + + try { + seq.setLoopCount(-55); + out("setLoopCount()", isSequenceLoaded, + "doesn't throw IllegalArgumentException on illegal value!"); + result = false; + } catch (IllegalArgumentException e) { + // EXCEPTION IS EXPECTED + out("Caught permissable IAE"); + } + + seq.setLoopCount(0); + if (seq.getLoopCount() != 0) { + out("setLoopCount()", isSequenceLoaded, + "doesn't set the loop count correctly!"); + result = false; + } + + return result; + } + + private static boolean testPlay(Sequencer seq) { + boolean result = true; + long stopTime; + + out("TestPlay"); + + TestMetaEventListener listener = new TestMetaEventListener(); + seq.addMetaEventListener(listener); + long startTime = System.currentTimeMillis(); + try { + seq.open(); + out("Playing sequence, length="+(seq.getMicrosecondLength()/1000)+"millis"); + seq.start(); + while (true) { + stopTime = listener.getStopTime(); + if (stopTime != 0) { + break; + } + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + long measuredDuration = stopTime - startTime; + out("play duration (us): " + measuredDuration); + } catch (Exception e) { + out("test not executed; exception:"); + e.printStackTrace(); + } + seq.close(); + return result; + } + + /** + * Create a new Sequence for testing. + * + * @return a dummy Sequence, or null, if a problem occured while creating + * the Sequence + */ + private static Sequence createSequence() { + Sequence sequence = null; + int lengthInSeconds = 2; + long lengthInMicroseconds = lengthInSeconds * 1000000; + int resolution = 480; + long lengthInTicks = (lengthInMicroseconds * 120 * resolution) / 60000000l; + out("length in ticks: " + lengthInTicks); + try { + sequence = new Sequence(Sequence.PPQ, resolution, 1); + Track track = sequence.createTrack(); + ShortMessage mm = new ShortMessage(); + mm.setMessage(0xF6, 0, 0); + MidiEvent me = new MidiEvent(mm, lengthInTicks); + track.add(me); + } catch (InvalidMidiDataException e) { + // DO NOTHING + } + out("sequence length (ticks): " + sequence.getTickLength()); + out("sequence length (us): " + sequence.getMicrosecondLength()); + return sequence; + } + + + private static void out(String m1, boolean isSequenceLoaded, String m2) { + out(m1 + (isSequenceLoaded ? " with Sequence " : " without Sequence ") + m2); + } + + private static void out(String message) { + System.out.println(message); + } + + private static class TestMetaEventListener implements MetaEventListener { + private long stopTime; + + + public void meta(MetaMessage m) { + System.out.print(" Got MetaMessage: "); + if (m.getType() == 47) { + stopTime = System.currentTimeMillis(); + System.out.println(" End Of Track -- OK"); + } else { + System.out.println(" unknown. Ignored."); + } + } + + public long getStopTime() { + return stopTime; + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Sequencer/MetaCallback.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Sequencer/MetaCallback.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.Instrument; +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaEventListener; +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Track; + +/** + * @test + * @bug 4347135 + * @summary MIDI MetaMessage callback inconsistent + * @run main/othervm MetaCallback + */ +public class MetaCallback implements MetaEventListener { + + static ShortMessage MidiMsg3(int a, int b, int c) { + try { + ShortMessage msg = new ShortMessage(); + msg.setMessage((byte)a,(byte)b,(byte)c); + return msg; + } catch(InvalidMidiDataException ex) { + throw new RuntimeException(); + } + } + + //Synthesizer synth; + Instrument[] instruments; + Sequencer sequencer; + Sequence sequence; + Track track; + + public static int TOTAL_COUNT = 100; + + int metaCount = 0; + boolean finished = false; + + MetaCallback() throws Exception { + + sequencer=MidiSystem.getSequencer(); + sequence=new Sequence(Sequence.PPQ,240); + track=sequence.createTrack(); + sequencer.addMetaEventListener(this); + + byte[] data = new byte[1]; + + track.add(new MidiEvent(MidiMsg3(ShortMessage.NOTE_ON+0,45,100),0)); + track.add(new MidiEvent(MidiMsg3(ShortMessage.NOTE_ON+0,45,0),0 + 240)); + int c; + for(c=0; c < TOTAL_COUNT; c++) { + data[0]=(byte)(c+1); + MetaMessage meta = new MetaMessage(); + meta.setMessage(1, data, 1); // type, data, length + track.add(new MidiEvent(meta,c*20)); + } + track.add(new MidiEvent(MidiMsg3(ShortMessage.NOTE_ON+9,45,100),c*20)); + track.add(new MidiEvent(MidiMsg3(ShortMessage.NOTE_ON+9,45,0),c*20 + 10)); + + sequencer.setSlaveSyncMode(Sequencer.SyncMode.INTERNAL_CLOCK); + sequencer.setMasterSyncMode(Sequencer.SyncMode.INTERNAL_CLOCK); + sequencer.open(); + sequencer.setSequence(sequence); + sequencer.setTempoInBPM(100); + System.out.println("Starting playback..."); + this.start(); + while (!finished && sequencer.getTickPosition() < sequencer.getTickLength()) { + System.out.println("Tick "+sequencer.getTickPosition()+"..."); + Thread.sleep(1000); + } + System.out.println("Stopping playback..."); + this.stop(); + if (metaCount != TOTAL_COUNT) { + throw new Exception("Expected "+TOTAL_COUNT+" callbacks, but got "+metaCount+"!"); + } + } + void start() {sequencer.start();} + void stop() {sequencer.stop();} + + public void meta(MetaMessage msg) { + System.out.println(""+metaCount+": got "+msg); + if (msg.getType() == 0x2F) { + finished = true; + } else if (msg.getData().length > 0 && msg.getType() == 1) { + metaCount++; + } + } + + public static void main(String[] argv) throws Exception { + if (hasSequencer()) { + new MetaCallback(); + System.out.println("Test passed"); + } + } + + static boolean hasSequencer() { + try { + Sequencer seq = MidiSystem.getSequencer(); + if (seq != null) { + seq.open(); + seq.close(); + return true; + } + } catch (Exception e) {} + System.out.println("No sequencer available! Cannot execute test."); + return false; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Sequencer/Recording.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Sequencer/Recording.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Receiver; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Track; + +/** + * @test + * @bug 4932841 + * @key intermittent + * @summary Sequencer's recording feature does not work + */ +public class Recording { + + public static boolean failed = false; + public static boolean passed = false; + private static Sequencer seq = null; + + public static void main(String[] args) throws Exception { + try { + seq = MidiSystem.getSequencer(); + + // create an arbitrary sequence which lasts 10 seconds + Sequence sequence = createSequence(10, 120, 240); + + seq.setSequence(sequence); + out("Set Sequence to Sequencer. Tempo="+seq.getTempoInBPM()); + + Track track = sequence.createTrack(); + int oldSize = track.size(); + seq.recordEnable(track, -1); + + seq.open(); + + // if getReceiver throws Exception, failed! + failed = true; + Receiver rec = seq.getReceiver(); + + // start recording and add various events + seq.startRecording(); + + // is exception from here on, not failed + failed = false; + + if (!seq.isRecording()) { + failed = true; + throw new Exception("Sequencer did not start recording!"); + } + if (!seq.isRunning()) { + failed = true; + throw new Exception("Sequencer started recording, but is not running!"); + } + + // first: add an event to the middle of the sequence + ShortMessage msg = new ShortMessage(); + msg.setMessage(0xC0, 80, 00); + rec.send(msg, 5l * 1000l * 1000l); + + Thread.sleep(1000); + + // then add a real-time event + msg = new ShortMessage(); + msg.setMessage(0xC0, 81, 00); + long secondEventTick = seq.getTickPosition(); + rec.send(msg, -1); + + seq.stopRecording(); + if (seq.isRecording()) { + failed = true; + throw new Exception("Stopped recording, but Sequencer is still recording!"); + } + if (!seq.isRunning()) { + failed = true; + throw new Exception("Stopped recording, but Sequencer but is not running anymore!"); + } + + seq.stop(); + if (seq.isRunning()) { + failed = true; + throw new Exception("Stopped Sequencer, but it is still running!"); + } + + // now examine the contents of the recorded track: + // 1) number of events: should be 2 more + int newSize = track.size(); + int addedEventCount = newSize - oldSize; + + out("Added "+addedEventCount+" events to recording track."); + if (addedEventCount != 2) { + failed = true; + throw new Exception("Did not add 2 events!"); + } + + // 2) the first event should be at roughly "secondEventTick" + MidiEvent ev = track.get(0); + msg = (ShortMessage) ev.getMessage(); + out("The first recorded event is at tick position: "+ev.getTick()); + if (Math.abs(ev.getTick() - secondEventTick) > 1000) { + out(" -> but expected something like: "+secondEventTick+"! FAILED."); + failed = true; + } + + ev = track.get(1); + msg = (ShortMessage) ev.getMessage(); + out("The 2nd recorded event is at tick position: "+ev.getTick()); + out(" -> sequence's tick length is "+seq.getTickLength()); + if (Math.abs(ev.getTick() - (sequence.getTickLength() / 2)) > 1000) { + out(" -> but expected something like: "+(seq.getTickLength()/2)+"! FAILED."); + failed = true; + } + + passed = true; + } catch (Exception e) { + out(e.toString()); + if (!failed) out("Test not failed."); + } + if (seq != null) { + seq.close(); + } + + if (failed) { + throw new Exception("Test FAILED!"); + } + else if (passed) { + out("Test Passed."); + } + } + + /** + * Create a new Sequence for testing. + */ + private static Sequence createSequence(int lengthInSeconds, int tempoInBPM, + int resolution) { + Sequence sequence = null; + long lengthInMicroseconds = lengthInSeconds * 1000000; + boolean createTempoEvent = true; + if (tempoInBPM == 0) { + tempoInBPM = 120; + createTempoEvent = false; + System.out.print("Creating sequence: "+lengthInSeconds+"sec, " + +"resolution="+resolution+" ticks/beat..."); + } else { + System.out.print("Creating sequence: "+lengthInSeconds+"sec, " + +tempoInBPM+" beats/min, " + +"resolution="+resolution+" ticks/beat..."); + } + //long lengthInTicks = (lengthInMicroseconds * resolution) / tempoInBPM; + long lengthInTicks = (lengthInMicroseconds * tempoInBPM * resolution) / 60000000l; + //out("expected length in ticks: " + lengthInTicks); + try { + sequence = new Sequence(Sequence.PPQ, resolution); + Track track = sequence.createTrack(); + if (createTempoEvent) { + int tempoInMPQ = (int) (60000000l / tempoInBPM); + MetaMessage tm = new MetaMessage(); + byte[] msg = new byte[3]; + msg[0] = (byte) (tempoInMPQ >> 16); + msg[1] = (byte) ((tempoInMPQ >> 8) & 0xFF); + msg[2] = (byte) (tempoInMPQ & 0xFF); + + tm.setMessage(0x51 /* Meta Tempo */, msg, msg.length); + track.add(new MidiEvent(tm, 0)); + //out("regtest: tempoInMPQ="+tempoInMPQ); + //out("Added tempo event: new size="+track.size()); + } + ShortMessage mm = new ShortMessage(); + mm.setMessage(0xF6, 0, 0); + MidiEvent me = new MidiEvent(mm, lengthInTicks); + track.add(me); + //out("Added realtime event: new size="+track.size()); + } catch (InvalidMidiDataException e) { + out(e); + } + out("OK"); + + return sequence; + } + + private static void out(Throwable t) { + t.printStackTrace(System.out); + } + + private static void out(String message) { + System.out.println(message); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Sequencer/SeqRecordDoesNotCopy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Sequencer/SeqRecordDoesNotCopy.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiMessage; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Receiver; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Track; + +/** + * @test + * @bug 5048381 + * @summary Sequencer doesn't create distinct messages when recording events. + * @key headful + */ +public class SeqRecordDoesNotCopy { + public static void main(String argv[]) throws Exception { + Sequencer s = MidiSystem.getSequencer(); + s.open(); + try { + Sequence seq = new Sequence(Sequence.PPQ, 384, 2); + s.setSequence(seq); + Track t = seq.getTracks()[0]; + ShortMessage msg = new ShortMessage(); + msg.setMessage(0x90, 0x40, 0x7F); + t.add(new MidiEvent(msg, 11000)); + msg.setMessage(0x90, 0x40, 0x00); + t.add(new MidiEvent(msg, 12000)); + t = seq.getTracks()[1]; + s.recordEnable(t, -1); + System.out.println("Started recording..."); + s.startRecording(); + Receiver r = s.getReceiver(); + Thread.sleep(100); + // send a normal message + System.out.println("Recording a normal NOTE ON message..."); + msg.setMessage(0x90, 0x40, 0x6F); + r.send(msg, -1); + Thread.sleep(100); + // send a normal message + System.out.println("Recording a normal NOTE OFF message..."); + msg.setMessage(0x90, 0x40, 0x00); + r.send(msg, -1); + Thread.sleep(100); + s.stop(); + // now see if the messages were recorded + System.out.println("Recorded messages:"); + int sameMessage = 0; + for (int i = 0; i < t.size(); i++) { + System.out.print(" "+(i+1)+". "); + printEvent(t.get(i)); + if (t.get(i).getMessage() == msg) { + System.out.println("## Failed: Same Message reference!"); + sameMessage++; + } + } + if (sameMessage > 0) { + System.out.println("## Failed: The same instance was recorded!"); + throw new Exception("Test FAILED!"); + } + System.out.println("Did not detect any duplicate messages."); + System.out.println("Test passed."); + } catch (Exception e) { + System.out.println("Unexpected Exception: "+e); + //e.printStackTrace(); + throw new Exception("Test FAILED!"); + } finally { + s.close(); + } + } + public static void printEvent(MidiEvent event) + { + MidiMessage message = event.getMessage(); + long tick = event.getTick(); + byte[] data = message.getMessage(); + + StringBuffer sb = new StringBuffer((data.length * 3) - 1); + + for (int i = 0; i < data.length; i++) + { + sb.append(toHexByteString(data[i])); + if (i < data.length - 1) sb.append(' '); + } + System.out.printf("%5d: %s%n", tick, sb); + } + + private static String toHexByteString(int n) + { + if (n < 0) n &= 0xFF; + String s = Integer.toHexString(n).toUpperCase(); + if (s.length() == 1) s = '0' + s; + return s; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Sequencer/SeqRecordsRealTimeEvents.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Sequencer/SeqRecordsRealTimeEvents.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiMessage; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Receiver; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Track; + +/** + * @test + * @bug 5048381 + * @summary Sequencer records real time messages into the sequence + * @key headful + */ +public class SeqRecordsRealTimeEvents { + public static void main(String argv[]) throws Exception { + Sequencer s = MidiSystem.getSequencer(); + s.open(); + try { + Sequence seq = new Sequence(Sequence.PPQ, 384, 2); + s.setSequence(seq); + Track t = seq.getTracks()[0]; + ShortMessage msg = new ShortMessage(); + msg.setMessage(0x90, 0x40, 0x7F); + t.add(new MidiEvent(msg, 11000)); + msg = new ShortMessage(); + msg.setMessage(0x90, 0x40, 0x00); + t.add(new MidiEvent(msg, 12000)); + t = seq.getTracks()[1]; + s.recordEnable(t, -1); + System.out.println("Started recording..."); + s.startRecording(); + Receiver r = s.getReceiver(); + Thread.sleep(100); + int oldTrackSize = t.size(); + // send a realtime message to the track + System.out.println("Recording real time message..."); + msg = new ShortMessage(); + msg.setMessage(0xF8, 0, 0); + r.send(msg, -1); + Thread.sleep(100); + // send a normal message + msg = new ShortMessage(); + System.out.println("Recording a normal NOTE ON message..."); + msg.setMessage(0x90, 0x40, 0x6F); + r.send(msg, -1); + Thread.sleep(100); + s.stop(); + // now see if the messages were recorded + int newMessages = t.size() - oldTrackSize; + System.out.println("Recorded messages:"); + for (int i = 0; i < t.size(); i++) { + System.out.print(" "+(i+1)+". "); + printEvent(t.get(i)); + } + if (newMessages == 0) { + System.out.println("## Failed: No messages were recorded!"); + throw new Exception("Test FAILED!"); + } else if (newMessages == 1) { + System.out.println("Only one message was recorded. Correct!"); + } else if (newMessages > 1) { + System.out.println("## Failed: 2 or more messages were recorded!"); + throw new Exception("Test FAILED!"); + } + System.out.println("Test passed."); + } catch (Exception e) { + System.out.println("Unexpected Exception: "+e); + //e.printStackTrace(); + throw new Exception("Test FAILED!"); + } finally { + s.close(); + } + } + public static void printEvent(MidiEvent event) + { + MidiMessage message = event.getMessage(); + long tick = event.getTick(); + byte[] data = message.getMessage(); + + StringBuffer sb = new StringBuffer((data.length * 3) - 1); + + for (int i = 0; i < data.length; i++) + { + sb.append(toHexByteString(data[i])); + if (i < data.length - 1) sb.append(' '); + } + System.out.printf("%5d: %s%n", tick, sb); + } + + private static String toHexByteString(int n) + { + if (n < 0) n &= 0xFF; + String s = Integer.toHexString(n).toUpperCase(); + if (s.length() == 1) s = '0' + s; + return s; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Sequencer/SeqStartRecording.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Sequencer/SeqStartRecording.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequencer; + +/** + * @test + * @bug 5001943 + * @summary Sequencer.startRecording throws unexpected NPE + * @key headful + */ +public class SeqStartRecording { + public static void main(String argv[]) throws Exception { + Sequencer seq = MidiSystem.getSequencer(); + seq.open(); + try { + seq.startRecording(); + System.out.println("Test passed."); + } catch (NullPointerException npe) { + System.out.println("Caught NPE: "+npe); + npe.printStackTrace(); + throw new Exception("Test FAILED!"); + } catch (Exception e) { + System.out.println("Unexpected Exception: "+e); + e.printStackTrace(); + System.out.println("Test NOT failed."); + } finally { + seq.close(); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Sequencer/SequencerCacheValues.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Sequencer/SequencerCacheValues.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Sequencer; + +/** + * @test + * @bug 4716740 + * @summary default sequencer does not set the tempo factor + */ +public class SequencerCacheValues { + + static boolean failed = false; + + public static void main(String args[]) throws Exception { + Sequencer seq = null; + int totalNumberOfSequencers = 0; + + MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); + for (int device=0; device72) { + System.out.println(s); + s=""; + } + } + System.out.println(s); + } + + public static Sequence getSequence() throws Exception { + ByteArrayInputStream bais = new ByteArrayInputStream(pitchbend); + Sequence seq = MidiSystem.getSequence(bais); + return seq; + } + + public static byte[] pitchbend = { + 77, 84, 104, 100, 0, 0, 0, 6, 0, 1, 0, 2, 0, 120, 77, 84, 114, 107, 0, 0, + 0, 27, 0, -1, 3, 19, 77, 73, 68, 73, 32, 116, 101, 115, 116, 32, 45, 32, + 116, 114, 97, 99, 107, 32, 48, 0, -1, 47, 0, 77, 84, 114, 107, 0, 0, 0, -44, + 0, -1, 3, 19, 77, 73, 68, 73, 32, 116, 101, 115, 116, 32, 45, 32, 116, 114, + 97, 99, 107, 32, 49, 0, -64, 30, 0, -112, 68, 126, 0, -32, 6, 67, 0, 14, + 71, 0, 20, 74, 0, 26, 77, 0, 32, 80, 0, 42, 85, 6, 50, 89, 6, 56, 92, 5, + 66, 97, 6, 74, 101, 6, 80, 104, 11, 84, 106, 20, 76, 102, 6, 70, 99, 5, 60, + 94, 6, 52, 90, 5, 44, 86, 4, 34, 81, 5, 26, 77, 5, 20, 74, 6, 10, 69, 5, + 2, 65, 7, 0, 64, 42, -112, 66, 123, 11, 68, 0, 72, 63, 126, 4, 66, 0, 43, + -32, 0, 63, 6, 0, 60, 7, 0, 56, 6, 0, 53, 5, 0, 49, 5, 0, 43, 4, 0, 37, 3, + 0, 30, 3, 0, 25, 3, 0, 19, 3, 0, 13, 4, 0, 8, 4, 0, 2, 4, 0, 0, 70, 0, 3, + 5, 0, 9, 3, 0, 14, 7, 0, 16, 25, 0, 21, 5, 0, 25, 7, 0, 28, 5, 0, 32, 5, + 0, 36, 5, 0, 41, 6, 0, 46, 5, 0, 50, 5, 0, 53, 4, 0, 58, 7, 0, 61, 7, 0, + 64, 117, -112, 63, 0, 0, -1, 47, 0 + }; + + static boolean hasSequencer() { + try { + Sequencer seq = MidiSystem.getSequencer(); + if (seq != null) { + seq.open(); + seq.close(); + return true; + } + } catch (Exception e) {} + System.out.println("No sequencer available! Cannot execute test."); + return false; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Sequencer/SequencerState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Sequencer/SequencerState.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; + +/** + * @test + * @bug 4913027 + * @summary several Sequencer methods should specify behaviour on closed Sequencer + */ +public class SequencerState { + + private static boolean hasSequencer() { + try { + Sequencer seq = MidiSystem.getSequencer(); + if (seq != null) { + seq.open(); + seq.close(); + return true; + } + } catch (Exception e) {} + System.out.println("No sequencer available! Cannot execute test."); + return false; + } + + + public static void main(String[] args) throws Exception { + out("4913027: several Sequencer methods should should specify behaviour on closed Sequencer"); + if (hasSequencer()) { + boolean passed = testAll(); + if (passed) { + out("Test PASSED."); + } else { + throw new Exception("Test FAILED."); + } + } + } + + /** + * Execute the test on all available Sequencers. + * + * @return true if the test passed for all Sequencers, false otherwise + */ + private static boolean testAll() throws Exception { + boolean result = true; + MidiDevice.Info[] devices = MidiSystem.getMidiDeviceInfo(); + for (int i = 0; i < devices.length; i++) { + MidiDevice device = MidiSystem.getMidiDevice(devices[i]); + if (device instanceof Sequencer) { + result &= testSequencer((Sequencer) device); + } + } + return result; + } + + /** + * Execute the test on the passed Sequencer. + * + * @return true if the test is passed this Sequencer, false otherwise + */ + private static boolean testSequencer(Sequencer seq) throws Exception { + boolean result = true; + + out("testing: " + seq); + /* test calls in closed state. + */ + if (seq.isOpen()) { + out("Sequencer is already open, cannot test!"); + return result; + } + + try { + seq.start(); + out("closed state: start() does not throw IllegalStateException!"); + result = false; + } catch (IllegalStateException e) { + } + + try { + seq.stop(); + out("closed state: stop() does not throw IllegalStateException!"); + result = false; + } catch (IllegalStateException e) { + } + + try { + seq.startRecording(); + out("closed state: startRecording() does not throw IllegalStateException!"); + result = false; + } catch (IllegalStateException e) { + } + + try { + seq.stopRecording(); + out("closed state: stopRecording() does not throw IllegalStateException!"); + result = false; + } catch (IllegalStateException e) { + } + + Sequence sequence = createSequence(); + if (sequence == null) { + out("created Sequence is null, cannot test!"); + return result; + } + try { + seq.setSequence(sequence); + } catch (IllegalStateException e) { + out("closed state: setSequence(Sequence) throws IllegalStateException!"); + result = false; + } + + InputStream inputStream = createSequenceInputStream(); + if (inputStream == null) { + out("created InputStream is null, cannot test!"); + return result; + } + try { + seq.setSequence(inputStream); + } catch (IllegalStateException e) { + out("closed state: setSequence(InputStream) throws IllegalStateException!"); + result = false; + } + + try { + seq.getSequence(); + } catch (IllegalStateException e) { + out("closed state: getSequence() throws IllegalStateException!"); + result = false; + } + + /* test calls in open state. + */ + seq.open(); + if (! seq.isOpen()) { + out("Sequencer is not open, cannot test!"); + return result; + } + + try { + seq.start(); + } catch (IllegalStateException e) { + out("open state: start() throws IllegalStateException!"); + result = false; + } + + try { + seq.stop(); + } catch (IllegalStateException e) { + out("open state: stop() throws IllegalStateException!"); + result = false; + } + + try { + seq.startRecording(); + } catch (IllegalStateException e) { + out("open state: startRecording() throws IllegalStateException!"); + result = false; + } + + try { + seq.stopRecording(); + } catch (IllegalStateException e) { + out("open state: stopRecording() throws IllegalStateException!"); + result = false; + } + + sequence = createSequence(); + if (sequence == null) { + out("created Sequence is null, cannot test!"); + return result; + } + try { + seq.setSequence(sequence); + } catch (IllegalStateException e) { + out("open state: setSequence(Sequence) throws IllegalStateException!"); + result = false; + } + + inputStream = createSequenceInputStream(); + if (inputStream == null) { + out("created InputStream is null, cannot test!"); + return result; + } + try { + seq.setSequence(inputStream); + } catch (IllegalStateException e) { + out("open state: setSequence(InputStream) throws IllegalStateException!"); + result = false; + } + + try { + seq.getSequence(); + } catch (IllegalStateException e) { + out("open state: getSequence() throws IllegalStateException!"); + result = false; + } + + seq.close(); + return result; + } + + /** + * Create a new Sequence for testing. + * + * @return a dummy Sequence, or null, if a problem occured while creating + * the Sequence + */ + private static Sequence createSequence() { + Sequence sequence = null; + try { + sequence = new Sequence(Sequence.PPQ, 480, 1); + } catch (InvalidMidiDataException e) { + // DO NOTHING + } + return sequence; + } + + /** + * Create a new InputStream containing a Sequence for testing. + * + * @return an InputStream containing a dummy Sequence, or null, if a problem + * occured while creating the InputStream + */ + private static InputStream createSequenceInputStream() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Sequence sequence = createSequence(); + if (sequence == null) { + return null; + } + try { + MidiSystem.write(sequence, 0, baos); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + return bais; + } catch (IOException e) { + return null; + } + } + + + private static void out(String message) { + System.out.println(message); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Sequencer/SetTickPosition.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Sequencer/SetTickPosition.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Track; + +/** + * @test + * @bug 4493775 + * @summary Sequncer method, setTickPosition(long) doesnot set the Tick position + */ +public class SetTickPosition { + private static boolean testPassed = true; + + public void runTest() + { + Sequencer theSequencer = null; + try + { + System.out.print("Getting Sequencer..."); + theSequencer = MidiSystem.getSequencer(); + System.out.println("got "+theSequencer); + + if(!(theSequencer.isOpen())) + { + System.out.println("Opening Sequencer..."); + theSequencer.open(); + + if(!(theSequencer.isOpen())) + { + System.out.println("Unable to open the Sequencer. Test NOT FAILED."); + return; + } + } + + System.out.println("theSequencer is open!\n"); + + System.out.println("Creating New Sequence..."); + Sequence theSequence = new Sequence(Sequence.PPQ, 120); + + System.out.println("Adding Track To Sequence..."); + Track theTrack = theSequence.createTrack(); + + int theChannel = 0; + + int theNote = 60; + int theVelocity = 100; + ShortMessage theShortMessage = new ShortMessage(); + + for (int tick=0; tick<2000; tick+=120) { + //System.out.println("Adding NOTE_ON To Track At Tick: " + tick + "...\n"); + theShortMessage.setMessage(ShortMessage.NOTE_ON, theChannel, theNote, theVelocity); + MidiEvent theMidiEvent = new MidiEvent(theShortMessage, tick); + theTrack.add(theMidiEvent); + + //System.out.println("Adding NOTE_OFF To Track At Tick: " + (tick+60) + "...\n"); + theShortMessage.setMessage(ShortMessage.NOTE_OFF, theChannel, theNote, theVelocity); + theMidiEvent = new MidiEvent(theShortMessage, tick+60); + theTrack.add(theMidiEvent); + } + theSequencer.setSequence(theSequence); + + float theTempoInBPM = 120; + theSequencer.setTempoInBPM(theTempoInBPM); + long theTickLengthOfSequence = theSequencer.getTickLength(); + System.out.println("Length Of Sequence In Ticks: " + theTickLengthOfSequence); + System.out.println("Sequence resolution: " + theSequencer.getSequence().getResolution()); + + theSequencer.start(); + for(long theTickPosition = 0; theTickPosition < theTickLengthOfSequence; theTickPosition += (theTickLengthOfSequence / 10)) + { + System.out.println("Now Setting Tick Position To: " + theTickPosition); + theSequencer.setTickPosition(theTickPosition); + + long theCurrentTickPosition = theSequencer.getTickPosition(); + long theCurrentMsPosition = (long) (theSequencer.getMicrosecondPosition()/1000); + System.out.println("IsRunning()=" + theSequencer.isRunning()); + System.out.println("Now Current Tick Position Is: " + theCurrentTickPosition); + //System.out.println("Now Current micro Position Is: " + theCurrentMsPosition); + System.out.println(""); + + try { + Thread.sleep(800); + } catch (InterruptedException ie) {} + + // last time, set tick pos to 0 + if (theTickPosition>0 && theTickPosition<(theTickLengthOfSequence / 10)) { + theTickPosition=(theTickLengthOfSequence / 10); + } + + // 30 = 1/4 * 120, the resolution of the sequence + if(Math.abs(theCurrentTickPosition - theTickPosition) > 30) { + System.out.println("theCurrentTickPosition != theTickPosition!"); + testPassed = false; + } + } + + } + catch (Exception ex) { ex.printStackTrace(); } + if (theSequencer != null) { + theSequencer.close(); + } + if (testPassed) { + System.out.println("Test Passed."); + } + } + + public static void main(String[] args) throws Exception { + SetTickPosition thisTest = new SetTickPosition(); + thisTest.runTest(); + if (!testPassed) { + throw new Exception("Test FAILED"); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Sequencer/TickLength.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Sequencer/TickLength.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaEventListener; +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Track; + +/** + * @test + * @bug 4427890 + * @run main/othervm TickLength + * @summary Sequencer.getTickLength() and Sequence.getTickLength() report the + * wrong length + */ +public class TickLength implements MetaEventListener { + private Sequence theSequence; + private Sequencer theSequencer; + + public TickLength() { + this.initMidiCompoments(); + System.out.println("Got Sequencer "+theSequencer); + theSequence = this.generateSequence(); + try { + theSequencer.setSequence(theSequence); + } + catch(Exception e) { + System.out.println(this.getClass()+"\tCannot set sequence to sequencer ("+e+")"); + return; + } + } + + public void start() { + theSequencer.start(); + } + + /* + instantiate the necessary midi components + */ + private boolean initMidiCompoments() { + + + try { + theSequencer = MidiSystem.getSequencer(); + } + catch(Exception e) { + System.out.println(this.getClass()+"\tSequencer Device not supported"+e+")"); + return false; + } + + try { + theSequencer.open(); + } + catch(Exception e) { + System.out.println(this.getClass()+"Cannot open Sequencer Device"); + return false; + } + if(!theSequencer.addMetaEventListener(this)) { + System.out.println(this.getClass()+"\tCould not register MetaEventListener - there will be problems with scrolling! "); + return false; + } + return true; + } + + static int lastTick = 0; + + private Sequence generateSequence() { + MidiEvent dummyMidiEvent; + ShortMessage dummyShortMessage; + Sequence dummySequence = null; + Track[] allTracks ; + Track theTrack; + + try { + dummySequence = new Sequence(Sequence.PPQ,1500); + } + catch(InvalidMidiDataException e) { + System.out.println("O o "+e); + } + + dummySequence.createTrack(); + allTracks = dummySequence.getTracks(); + theTrack = allTracks[0]; + lastTick = 0; + for(int i=0;i<20; i++) { + theTrack.add(this.createShortMidiEvent(ShortMessage.NOTE_ON, 2, 30+i, 100,100+1000*i)); + theTrack.add(this.createMetaMidiEvent(1,"start",100+1000*i)); + lastTick = (1000*i)+600; + theTrack.add(this.createShortMidiEvent(ShortMessage.NOTE_OFF, 2, 30+i, 100, lastTick)); + theTrack.add(this.createMetaMidiEvent(1,"end",lastTick)); + } + + return dummySequence; + } + + /* + A method to create a short midi event (sound) + */ + + public MidiEvent createShortMidiEvent(int theCommand, int theChannel, int theData1, int theData2, long theTime) { + ShortMessage dummyShortMessage; + MidiEvent dummyMidiEvent; + + try { + dummyShortMessage = new ShortMessage(); + dummyShortMessage.setMessage(theCommand, theChannel, theData1, theData2); + dummyMidiEvent = new MidiEvent(dummyShortMessage,theTime); + } + catch (Exception e) { + System.out.println(this.getClass()+"\t"+e); + return null; + } + + return dummyMidiEvent; + } + + /* + A method to create a meta midi event (used in meta() method) + */ + public MidiEvent createMetaMidiEvent(int theType, String theData1, long theTime) { + MetaMessage dummyMetaMessage; + MidiEvent dummyMidiEvent; + + try { + dummyMetaMessage = new MetaMessage(); + dummyMetaMessage.setMessage(theType, theData1.getBytes(), theData1.length()); + dummyMidiEvent = new MidiEvent(dummyMetaMessage,theTime); + } + catch (Exception e) { + System.out.println(e); + return null; + } + + return dummyMidiEvent; + } + + /* + the method is activated by each meta midi event + it puts out the actual tick position, as well as the WRONG total tick length and the RIGHT + tick length using the work around by dividing the total length by 64 + */ + public void meta(MetaMessage p1) { + if(p1.getType() ==47) { + return; + } + System.out.println("getTickPosition:\t"+theSequencer.getTickPosition() + +"\t Sequencer.getTickLength:\t"+theSequencer.getTickLength() + +"\tReal Length:\t"+lastTick + +"\t Sequence.getTickLength:\t"+theSequence.getTickLength() + //(theSequencer.getTickLength()/64)); + ); + } + + public void checkLengths() throws Exception { + System.out.println("Sequencer.getTickLength() = "+theSequencer.getTickLength()); + System.out.println("Sequence.getTickLength() = "+theSequence.getTickLength()); + long diff = theSequencer.getTickLength() - theSequence.getTickLength(); + if (diff > 100 || diff < -100) { + throw new Exception("Difference too large! Failed."); + } + System.out.println("Passed"); + } + + public static void main(String[] args) throws Exception { + if (!hasSequencer()) { + return; + } + TickLength tlt = new TickLength(); + //tlt.start(); + tlt.checkLengths(); + } + + static boolean hasSequencer() { + try { + Sequencer seq = MidiSystem.getSequencer(); + if (seq != null) { + seq.open(); + seq.close(); + return true; + } + } catch (Exception e) {} + System.out.println("No sequencer available! Cannot execute test."); + return false; + } + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/ShortMessage/FastShortMessage.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/ShortMessage/FastShortMessage.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequence; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Track; + +/** + * @test + * @bug 4851018 + * @summary MidiMessage.getLength and .getData return wrong values. + * also: 4890405: Reading MidiMessage byte array fails in 1.4.2 + */ +public class FastShortMessage { + public static void main(String args[]) throws Exception { + int[] dataMes = {ShortMessage.NOTE_ON | 9, 0x24, 0x50}; + int res = 240; + Sequence midiData = new Sequence(Sequence.PPQ, res); + + Track track = midiData.createTrack(); + ShortMessage msg = new ShortMessage(); + msg.setMessage(dataMes[0], dataMes[1], dataMes[2]); + track.add(new MidiEvent(msg, 0)); + + // save sequence to outputstream + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + MidiSystem.write(midiData, 0, baos); + + // reload that sequence + InputStream is = new ByteArrayInputStream(baos.toByteArray()); + Sequence seq = MidiSystem.getSequence(is); + + track = seq.getTracks()[0]; + msg = (ShortMessage) (track.get(0).getMessage()); + byte[] msgData = msg.getMessage(); + + if (msgData.length != dataMes.length + || (msgData[0] & 0xFF) != dataMes[0] + || (msgData[1] & 0xFF) != dataMes[1] + || (msgData[2] & 0xFF) != dataMes[2]) { + throw new Exception("test failed. read length="+msgData.length); + } + System.out.println("Test Passed."); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/ShortMessage/FastShortMessage2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/ShortMessage/FastShortMessage2.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequence; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Track; + +/** + * @test + * @bug 5011306 + * @summary FastShortMessage.setMessage does not use the data2 parameter + */ +public class FastShortMessage2 { + + public static void main(String args[]) throws Exception { + int[] dataMes = {ShortMessage.NOTE_ON | 9, 0x24, 0x50}; + + Sequence midiData = new Sequence(Sequence.PPQ, 240); + Track track = midiData.createTrack(); + ShortMessage msg = new ShortMessage(); + msg.setMessage(dataMes[0], dataMes[1], dataMes[2]); + track.add(new MidiEvent(msg, 0)); + // save sequence to outputstream + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + MidiSystem.write(midiData, 0, baos); + // reload that sequence + InputStream is = new ByteArrayInputStream(baos.toByteArray()); + Sequence seq = MidiSystem.getSequence(is); + track = seq.getTracks()[0]; + msg = (ShortMessage) (track.get(0).getMessage()); + if (!msg.getClass().toString().contains("FastShortMessage")) { + System.out.println("msg is not FastShortMessage, this test is useless then..."+msg.getClass()); + } + + msg.setMessage(dataMes[0], dataMes[1], dataMes[2]); + byte[] msgData = msg.getMessage(); + + if (msgData.length != dataMes.length + || (msgData[0] & 0xFF) != dataMes[0] + || (msgData[1] & 0xFF) != dataMes[1] + || (msgData[2] & 0xFF) != dataMes[2]) { + System.out.println("status="+(msgData[0] & 0xFF)+" and expected "+dataMes[0]); + System.out.println("data1="+(msgData[1] & 0xFF)+" and expected "+dataMes[1]); + System.out.println("data2="+(msgData[2] & 0xFF)+" and expected "+dataMes[2]); + throw new Exception("Test FAILED!"); + } + System.out.println("Test Passed."); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Soundbanks/ExtraCharInSoundbank.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Soundbanks/ExtraCharInSoundbank.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.Instrument; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Soundbank; +import javax.sound.midi.Synthesizer; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Mixer; + +/** + * @test + * @bug 4429762 + * @summary Some instrument names in some soundbanks include bad extra characters + */ +public class ExtraCharInSoundbank { + + private static void printName(String loadedName) + { + System.out.println("Loaded Name: " + loadedName); + byte[] theLoadedNameByteArray = loadedName.getBytes(); + + System.out.print("Name Bytes: "); + for(int i = 0; i < theLoadedNameByteArray.length; i++) + System.out.print((Integer.toHexString((int)theLoadedNameByteArray[i]).toUpperCase()) + " "); + System.out.println(""); + System.out.println(""); + } + + private static boolean containsControlChar(String name) { + byte[] bytes = name.getBytes(); + for (int i = 0; i < bytes.length; i++) { + if (bytes[i] < 32) { + return true; + } + } + return false; + } + + public static boolean checkInstrumentNames(Synthesizer theSynthesizer) + { + boolean containsControlCharacters = false; + + Instrument[] theLoadedInstruments = theSynthesizer.getLoadedInstruments(); + + System.out.println("Checking soundbank..."); + for(int theInstrumentIndex = 0; theInstrumentIndex < theLoadedInstruments.length; theInstrumentIndex++) { + String name = theLoadedInstruments[theInstrumentIndex].getName(); + if (containsControlChar(name)) { + containsControlCharacters = true; + System.out.print("Instrument[" + theInstrumentIndex + "] contains unexpected control characters: "); + printName(name); + } + } + return !containsControlCharacters; + } + + public static void main(String[] args) throws Exception { + // the internal synthesizer needs a soundcard to work properly + if (!isSoundcardInstalled()) { + return; + } + Synthesizer theSynth = MidiSystem.getSynthesizer(); + System.out.println("Got synth: "+theSynth); + theSynth.open(); + try { + Soundbank theSoundbank = theSynth.getDefaultSoundbank(); + System.out.println("Got soundbank: "+theSoundbank); + theSynth.loadAllInstruments(theSoundbank); + try { + if (!checkInstrumentNames(theSynth)) { + throw new Exception("Test failed"); + } + } finally { + theSynth.unloadAllInstruments(theSoundbank); + } + } finally { + theSynth.close(); + } + System.out.println("Test passed."); + } + + /** + * Returns true if at least one soundcard is correctly installed + * on the system. + */ + public static boolean isSoundcardInstalled() { + boolean result = false; + try { + Mixer.Info[] mixers = AudioSystem.getMixerInfo(); + if (mixers.length > 0) { + result = AudioSystem.getSourceDataLine(null) != null; + } + } catch (Exception e) { + System.err.println("Exception occured: "+e); + } + if (!result) { + System.err.println("Soundcard does not exist or sound drivers not installed!"); + System.err.println("This test requires sound drivers for execution."); + } + return result; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Soundbanks/GetSoundBankIOException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Soundbanks/GetSoundBankIOException.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MidiSystem; + +/** + * @test + * @bug 4629810 + * @summary MidiSystem.getSoundbank() throws unexpected IOException + */ +public class GetSoundBankIOException { + + public static void main(String args[]) throws Exception { + boolean failed = false; + try { + String filename = "GetSoundBankIOException.java"; + System.out.println("Opening "+filename+" as soundbank..."); + File midiFile = new File(System.getProperty("test.src", "."), filename); + MidiSystem.getSoundbank(midiFile); + //Soundbank sBank = MidiSystem.getSoundbank(new NonMarkableIS()); + System.err.println("InvalidMidiDataException was not thrown!"); + failed = true; + } catch (InvalidMidiDataException invMidiEx) { + System.err.println("InvalidMidiDataException was thrown. OK."); + } catch (IOException ioEx) { + System.err.println("Unexpected IOException was caught!"); + System.err.println(ioEx.getMessage()); + ioEx.printStackTrace(); + failed = true; + } + + if (failed) throw new Exception("Test FAILED!"); + System.out.println("Test passed."); + } + + private static class NonMarkableIS extends InputStream { + int counter = 0; + + public NonMarkableIS() { + } + + public int read() throws IOException { + if (counter > 1000) return -1; + return (++counter) % 256; + } + + public synchronized void mark(int readlimit) { + System.out.println("Called mark with readlimit= "+readlimit); + } + + public synchronized void reset() throws IOException { + throw new IOException("mark/reset not supported"); + } + + public boolean markSupported() { + return false; + } + + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Synthesizer/AsynchronousMidiChannel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Synthesizer/AsynchronousMidiChannel.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.PrintStream; + +import javax.sound.midi.Instrument; +import javax.sound.midi.MidiChannel; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Soundbank; +import javax.sound.midi.Synthesizer; + +/** + * @test + * @bug 4987585 + * @summary Some MidiChannel methods are asynchronous + */ +public class AsynchronousMidiChannel { + static PrintStream log = System.err; + static PrintStream ref = System.out; + + public static void main(String args[]) { + doIt(args); + } + + public static void doIt(String args[]) { + Synthesizer synth = null; + MidiChannel mChanArr[]; + MidiChannel chan = null; + boolean failed = false; + int i = 0; + int chanNum = 0; + + int val = 1; + int contr = 0; + Soundbank sBank; + Instrument[] insArr; + Instrument instr = null; + Object ev = new Object(); + + try { + synth = MidiSystem.getSynthesizer(); + System.out.println("Got synth: "+synth); + synth.open(); + + int latency = (int) synth.getLatency(); + System.out.println(" -> latency: " + +latency + +" microseconds"); + + mChanArr = synth.getChannels(); + while ((i < mChanArr.length) && (chan == null)) { + chanNum = i; + chan = mChanArr[i++]; + } + if (chan == null) { + System.out.println("No channels in " + +"this synthesizer!"); + return; + } + System.out.println("Got MidiChannel: "+chan); + + + sBank = synth.getDefaultSoundbank(); + if (sBank == null) { + System.out.println("No default sound bank!"); + return; + } + + + insArr = sBank.getInstruments(); + for (int j = 0; j < insArr.length; j++) { + if (insArr[j].getPatch().getBank() == val) { + instr = insArr[j]; + synth.loadInstrument(instr); + } + } + if (instr == null) { + System.out.println("No instr. with this bank!"); + return; + } + + chan.controlChange(contr, val); + + // need to respect the synthesizer's latency + if (latency > 0) { + try { + Thread.sleep(latency/1000); + } catch (InterruptedException inEx) { + } + } + + if (chan.getController(contr) != val) { + failed = true; + System.err.println("getController() does not " + +"return proper value: " + + chan.getController(contr)); + } else { + System.out.println("getController(" + + contr + ") returns proper value: " + + chan.getController(contr)); + } + + } catch (MidiUnavailableException mue) { + System.err.println("MidiUnavailableException was " + +"thrown: " + mue); + System.out.println("could not test."); + return; + } catch(SecurityException se) { + se.printStackTrace(); + System.err.println("Sound access is not denied but " + + "SecurityException was thrown!"); + return; + + } finally { + if (synth != null) synth.close(); + } + + + if (failed == true) { + System.out.println("test failed"); + } else { + System.out.println("OKAY"); + } + return; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Synthesizer/Receiver/bug6186488.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Synthesizer/Receiver/bug6186488.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiMessage; +import javax.sound.midi.MidiSystem; + +/** + * @test + * @bug 6186488 + * @summary Tests that software Java Syntesizer processed + * non-ShortMessage-derived messages + * @run main/manual=yesno bug6186488 + */ +public class bug6186488 { + public static void main(String[] args) throws Exception { + MidiDevice/*Synthesizer*/ synth = null; + + try { + synth = MidiSystem.getSynthesizer(); + //synth = MidiSystem.getMidiDevice(infos[0]); + + System.out.println("Synthesizer: " + synth.getDeviceInfo()); + synth.open(); + MidiMessage msg = new GenericMidiMessage(0x90, 0x3C, 0x40); + //ShortMessage msg = new ShortMessage(); + //msg.setMessage(0x90, 0x3C, 0x40); + + synth.getReceiver().send(msg, 0); + Thread.sleep(2000); + + } catch (Exception ex) { + ex.printStackTrace(); + throw ex; + } finally { + if (synth != null && synth.isOpen()) + synth.close(); + } + System.out.print("Did you heard a note? (enter 'y' or 'n') "); + int result = System.in.read(); + System.in.skip(1000); + if (result == 'y' || result == 'Y') + { + System.out.println("Test passed sucessfully."); + } + else + { + System.out.println("Test FAILED."); + throw new RuntimeException("Test failed."); + } + } + + private static class GenericMidiMessage extends MidiMessage { + GenericMidiMessage(int... message) { + super(new byte[message.length]); + for (int i=0; i latency: " + +latency + +" microseconds"); + if (latency < 5000 && latency > 0) { + System.out.println("## This latency is VERY small, probably due to this bug."); + System.out.println("## This causes failure of this test."); + failed = true; + } + } catch (MidiUnavailableException mue) { + System.err.println("MidiUnavailableException was " + +"thrown: " + mue); + System.out.println("could not test."); + notexec = true; + } catch(SecurityException se) { + se.printStackTrace(); + System.err.println("Sound access is not denied but " + + "SecurityException was thrown!"); + notexec = true; + } finally { + if (synth != null) synth.close(); + } + + + if (failed) { + throw new Exception("Test FAILED!"); + } + if (notexec) { + System.out.println("Test not failed."); + } else { + System.out.println("Test Passed."); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Synthesizer/bug4685396.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Synthesizer/bug4685396.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.Instrument; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Soundbank; +import javax.sound.midi.Synthesizer; + +/** + * @test + * @bug 4685396 + * @summary Tests that Synthesizer.remapInstrument works + * @run main bug4685396 + * @key headful + */ +public class bug4685396 { + + static Synthesizer synth = null; + + public static boolean isInstrumentExist(Instrument inst, Instrument[] insts) { + for (int i = 0; i < insts.length; i++) { + if (inst.equals(insts[i])) + return true; + } + return false; + } + + static boolean test( + boolean reloadInstr, // reload all instruments? + boolean unloadFrom, // unload "from" instrument? + boolean unloadTo // unload "to" instrument? + ) throws Exception + { + log("Starting test: reloadInstr=" + reloadInstr + + ", unloadFrom=" + unloadFrom + + ", unloadTo=" + unloadTo + + ""); + + log(" creating synthesizer..."); + synth = MidiSystem.getSynthesizer(); + log(" opening synthesizer..."); + synth.open(); + + Soundbank sbank = synth.getDefaultSoundbank(); + if (sbank == null) + throw new RuntimeException("ERROR: Could not get default soundbank"); + + if (reloadInstr) { + synth.unloadAllInstruments(sbank); + synth.loadAllInstruments(sbank); + } + + Instrument[] instrs = synth.getLoadedInstruments(); + + log(" " + instrs.length + " instruments loaded."); + + if (instrs.length < 2) + throw new RuntimeException("ERROR: need at least 2 loaded instruments"); + + Instrument from = instrs[0]; + Instrument to = instrs[instrs.length - 1]; + + if (unloadFrom) + synth.unloadInstrument(from); + if (unloadTo) + synth.unloadInstrument(to); + + log(" from instrument (" + (unloadFrom ? "UNLOADED" : "LOADED") + + "): " + from.toString()); + log(" to instrument (" + (unloadTo ? "UNLOADED" : "LOADED") + + "): " + to.toString()); + + boolean result = false; + boolean excepted = false; + try { + result = synth.remapInstrument(from, to); + log(" remapInstrument(from, to) returns " + result); + } catch (IllegalArgumentException ex) { + excepted = true; + log(" EXCEPTION:"); + ex.printStackTrace(System.out); + } + + instrs = synth.getLoadedInstruments(); + log(" " + instrs.length + " instruments remains loaded."); + + boolean toUnloaded = !isInstrumentExist(to, instrs); + boolean fromUnloaded = !isInstrumentExist(from, instrs); + + log(" from instrument is " + (fromUnloaded ? "UNLOADED" : "LOADED")); + log(" to instrument is " + (toUnloaded ? "UNLOADED" : "LOADED")); + + boolean bOK = true; + if (result) { + if (unloadTo) { + bOK = false; + log("ERROR: unloaded to, but sucessfull remap"); + } + if (!fromUnloaded) { + bOK = false; + log("ERROR: sucessfull remap, but from hasn't been unloaded"); + } + if (toUnloaded) { + bOK = false; + log("ERROR: to has been unloaded!"); + } + } else { + if (!excepted) { + bOK = false; + log("ERROR: remap returns false, exception hasn't been thrown"); + } + if (!unloadTo) { + bOK = false; + log("ERROR: to is loaded, but remap returns false"); + } + if (unloadFrom != fromUnloaded) { + bOK = false; + log("ERROR: remap returns false, but status of from has been changed"); + } + } + + if (bOK) { + log("Test result: OK\n"); + } else { + log("Test result: FAIL\n"); + } + + return bOK; + } + + static void cleanup() { + if (synth != null) { + synth.close(); + synth = null; + } + } + + static boolean runTest( + boolean reloadInstr, // reload all instruments? + boolean unloadTo, // unload "to" instrument? + boolean unloadFrom // unload "from" instrument? + ) + { + boolean success = false; + try { + success = test(reloadInstr, unloadFrom, unloadTo); + } catch (Exception ex) { + log("Exception: " + ex.toString()); + } + cleanup(); + return success; + } + + public static void main(String args[]) throws Exception { + boolean failed = false; + if (!runTest(true, false, false)) + failed = true; + if (!runTest(true, false, true)) + failed = true; + if (!runTest(true, true, false)) + failed = true; + if (!runTest(true, true, true)) + failed = true; + + if (failed) { + throw new RuntimeException("Test FAILED."); + } + log("Test sucessfully passed."); + } + + + // helper routines + static long startTime = currentTimeMillis(); + static long currentTimeMillis() { + //return System.nanoTime() / 1000000L; + return System.currentTimeMillis(); + } + static void log(String s) { + long time = currentTimeMillis() - startTime; + long ms = time % 1000; + time /= 1000; + long sec = time % 60; + time /= 60; + long min = time % 60; + time /= 60; + System.out.println("" + + (time < 10 ? "0" : "") + time + + ":" + (min < 10 ? "0" : "") + min + + ":" + (sec < 10 ? "0" : "") + sec + + "." + (ms < 10 ? "00" : (ms < 100 ? "0" : "")) + ms + + " (" + Thread.currentThread().getName() + ") " + s); + } + static void delay(int millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) {} + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Track/TrackAddSameTick.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Track/TrackAddSameTick.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MidiEvent; +import javax.sound.midi.Sequence; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Track; + +/** + * @test + * @bug 4941944 + * @summary Track may not have a determined order for inserting events at same + * tick time + */ +public class TrackAddSameTick { + + static boolean failed = false; + static MidiEvent[] evs = new MidiEvent[10]; + + public static void main(String argv[]) throws Exception { + Sequence seq = new Sequence(Sequence.PPQ, 240); + Track t = seq.createTrack(); + + log("add 10 events in random order"); + t.add(createEvent(10, 5)); + t.add(createEvent(0, 0)); + t.add(createEvent(10, 6)); + t.add(createEvent(11, 8)); + t.add(createEvent(10, 7)); + t.add(createEvent(0, 1)); + t.add(createEvent(0, 2)); + t.add(createEvent(15, 9)); + t.add(createEvent(0, 3)); + t.add(createEvent(1, 4)); + + // now compare the events. + // The note param will tell us the + // the expected position + long lastTick = 0; + for (int i = 0; i < t.size(); i++) { + MidiEvent ev = t.get(i); + if (ev.getMessage() instanceof ShortMessage) { + ShortMessage msg = (ShortMessage) ev.getMessage(); + log(""+i+": ShortMessage at tick "+ev.getTick() + +" with expected position "+msg.getData1()); + if (ev.getTick() < lastTick) { + log(" FAILED: last tick is larger than this event's tick!"); + failed = true; + } + if (i != msg.getData1()) { + log(" FAILED: Track did not order correctly."); + failed = true; + } + } + } + + if (failed) throw new Exception("Test FAILED!"); + log("Test passed."); + } + + public static MidiEvent createEvent(long tick, int expectedPos) + throws Exception { + ShortMessage msg = new ShortMessage(); + msg.setMessage(0x90, (int) expectedPos, 00); + MidiEvent ev = new MidiEvent(msg, tick); + return ev; + } + + public static void log(String s) { + System.out.println(s); + } + + public static void log(Exception e) { + //System.out.println(s); + e.printStackTrace(); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Track/bug6416024.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Track/bug6416024.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.Sequence; +import javax.sound.midi.Track; + +/** + * @test + * @bug 6416024 + * @summary Tests that sequence correctly handle removing of EndOfTrack event + * @run main bug6416024 + */ +public class bug6416024 { + + boolean test() { + Sequence sequence = null; + Track track = null; + MidiEvent event = null; + + log("creating sequence..."); + try { + sequence = new Sequence(Sequence.PPQ, 10); + log(" - OK: " + sequence); + } catch(InvalidMidiDataException e ) { + log(" - FAILED: got exception"); + e.printStackTrace(System.out); + return false; + } + + log("creating track..."); + track = sequence.createTrack(); + log(" - OK: " + track); + log("initial track size=" + track.size()); + + log("removing all track events..."); + while (track.size() > 0) { + try { + event = track.get(0); + log(" ..removing event " + event); + track.remove(event); + log(" - OK, track size=" + track.size()); + } catch (Exception e) { + log(" - FAILED: got exception"); + e.printStackTrace(System.out); + return false; + } + } + + MetaMessage newMsg = new MetaMessage(); + MidiEvent newEvent = new MidiEvent(newMsg, 10); + log("adding new event..."); + try { + if (!track.add(newEvent)) { + log("event hasn't been added"); + return false; + } + log(" - OK, track size=" + track.size()); + } catch (Exception e) { + log(" - FAILED: got exception"); + e.printStackTrace(System.out); + return false; + } + + return true; + } + + public static void main(String args[]) throws Exception { + bug6416024 This = new bug6416024(); + if (This.test()) { + log("Test passed sucessfully."); + } else { + log("Test FAILED!"); + delay(1000); + throw new RuntimeException("Test failed!"); + } + } + + // helper routines + static long startTime = currentTimeMillis(); + static long currentTimeMillis() { + //return System.nanoTime() / 1000000L; + return System.currentTimeMillis(); + } + static void log(String s) { + long time = currentTimeMillis() - startTime; + long ms = time % 1000; + time /= 1000; + long sec = time % 60; + time /= 60; + long min = time % 60; + time /= 60; + System.out.println("" + + (time < 10 ? "0" : "") + time + + ":" + (min < 10 ? "0" : "") + min + + ":" + (sec < 10 ? "0" : "") + sec + + "." + (ms < 10 ? "00" : (ms < 100 ? "0" : "")) + ms + + " (" + Thread.currentThread().getName() + ") " + s); + } + static void delay(int millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) {} + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/midi/Transmitter/bug6415669.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Transmitter/bug6415669.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Transmitter; + +/** + * @test + * @bug 6415669 + * @summary Tests that terminating thread which got transmitter doesn't cause + * JVM crash (windows) + * @run main bug6415669 + */ +public class bug6415669 { + + public static void main(String args[]) throws Exception { + String osStr = System.getProperty("os.name"); + boolean isWin = osStr.toLowerCase().startsWith("windows"); + log("OS: " + osStr); + log("Arch: " + System.getProperty("os.arch")); + if (!isWin) { + log("The test is for Windows only"); + return; + } + + bug6415669 This = new bug6415669(); + if (This.test()) { + log("Test sucessfully passed."); + } else { + log("Test FAILED!"); + throw new RuntimeException("Test FAILED!"); + } + } + + volatile Transmitter transmitter = null; + Thread openThread = null; + boolean test() { + openThread = new Thread(new Runnable() { + public void run() { + try { + log("openThread: getting transmitter..."); + transmitter = MidiSystem.getTransmitter(); + log("openThread: - OK: " + transmitter); + } catch (MidiUnavailableException ex) { + log("openThread: - Exception: "); + ex.printStackTrace(System.out); + log("openThread: skipping..."); + } + log("openThread: exiting..."); + } + }); + log("starting openThread..."); + openThread.start(); + + while (openThread.isAlive()) + delay(500); + // make additional delay + delay(500); + + if (transmitter == null) { + return true; // midi is not available, just ignore + } + + log("closing transmitter"); + transmitter.close(); + log(" - OK"); + + return true; + } + + // helper routines + static long startTime = currentTimeMillis(); + static long currentTimeMillis() { + //return System.nanoTime() / 1000000L; + return System.currentTimeMillis(); + } + static void log(String s) { + long time = currentTimeMillis() - startTime; + long ms = time % 1000; + time /= 1000; + long sec = time % 60; + time /= 60; + long min = time % 60; + time /= 60; + System.out.println("" + + (time < 10 ? "0" : "") + time + + ":" + (min < 10 ? "0" : "") + min + + ":" + (sec < 10 ? "0" : "") + sec + + "." + (ms < 10 ? "00" : (ms < 100 ? "0" : "")) + ms + + " (" + Thread.currentThread().getName() + ") " + s); + } + static void delay(int millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) {} + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/AudioFileFormat/AudioFileFormatToString.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/AudioFileFormat/AudioFileFormatToString.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; + +/** + * @test + * @bug 4672864 + * @summary AudioFileFormat.toString() throws unexpected NullPointerException + */ +public class AudioFileFormatToString { + + static final int STATUS_PASSED = 0; + static final int STATUS_FAILED = 2; + static final int STATUS_TEMP = 95; + + public static void main(String argv[]) throws Exception { + int testExitStatus = run(argv, System.out); + if (testExitStatus != STATUS_PASSED) { + throw new Exception("Test FAILED " + testExitStatus); + } + System.out.println("Test passed."); + } + + public static int run(String argv[], java.io.PrintStream out) { + int testResult = STATUS_PASSED; + + out.println("\n==> Test for AudioFileFormat class:"); + + AudioFormat testAudioFormat = + new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, // AudioFormat.Encoding + (float) 44100.0, // float SampleRate + (int) 8, // int sampleSizeInBits + (int) 2, // int channels + (int) 2, // int frameSize + (float) 110.0, // float frameRate + true // boolean bigEndian + ); + AudioFormat nullAudioFormat = null; + + AudioFileFormat.Type testAudioFileFormatType = AudioFileFormat.Type.WAVE; + AudioFileFormat.Type nullAudioFileFormatType = null; + + AudioFileFormat testedAudioFileFormat = null; + out.println("\n>> public AudioFileFormat constructor for AudioFileFormat.Type = null: "); + try { + testedAudioFileFormat = + new AudioFileFormat(nullAudioFileFormatType, // AudioFileFormat.Type + testAudioFormat, // AudioFormat + (int) 1024 // int frameLength + ); + out.println("> No any Exception was thrown!"); + out.println("> testedAudioFileFormat.getType():"); + try { + AudioFileFormat.Type producedType = testedAudioFileFormat.getType(); + out.println("> PASSED: producedType = " + producedType); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + out.println("> testedAudioFileFormat.toString():"); + try { + String producedString = testedAudioFileFormat.toString(); + out.println("> PASSED: producedString = " + producedString); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + } catch (IllegalArgumentException illegArgExcept) { + out.println("> PASSED: expected IllegalArgumentException was thrown:"); + illegArgExcept.printStackTrace(out); + } catch (NullPointerException nullPE) { + out.println("> PASSED: expected NullPointerException was thrown:"); + nullPE.printStackTrace(out); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + + out.println("\n>> public AudioFileFormat constructor for AudioFormat = null: "); + try { + testedAudioFileFormat = + new AudioFileFormat(testAudioFileFormatType, // AudioFileFormat.Type + nullAudioFormat, // AudioFormat + (int) 1024 // int frameLength + ); + out.println("> No any Exception was thrown!"); + out.println("> testedAudioFileFormat.getFormat():"); + try { + AudioFormat producedFormat = testedAudioFileFormat.getFormat(); + out.println("> PASSED: producedFormat = " + producedFormat); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + out.println("> testedAudioFileFormat.toString():"); + try { + String producedString = testedAudioFileFormat.toString(); + out.println("> PASSED: producedString = " + producedString); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + } catch (IllegalArgumentException illegArgExcept) { + out.println("> PASSED: expected IllegalArgumentException was thrown:"); + illegArgExcept.printStackTrace(out); + } catch (NullPointerException nullPE) { + out.println("> PASSED: expected NullPointerException was thrown:"); + nullPE.printStackTrace(out); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + + out.println("\n>> protected AudioFileFormat constructor for AudioFileFormat.Type = null: "); + try { + testedAudioFileFormat = + new TestAudioFileFormat(nullAudioFileFormatType, // AudioFileFormat.Type + (int) 1024, // byteLength + testAudioFormat, // AudioFormat + (int) 1024 // int frameLength + ); + out.println("> No any Exception was thrown!"); + out.println("> testedAudioFileFormat.getType():"); + try { + AudioFileFormat.Type producedType = testedAudioFileFormat.getType(); + out.println("> PASSED: producedType = " + producedType); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + out.println("> testedAudioFileFormat.toString():"); + try { + String producedString = testedAudioFileFormat.toString(); + out.println("> PASSED: producedString = " + producedString); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + } catch (IllegalArgumentException illegArgExcept) { + out.println("> PASSED: expected IllegalArgumentException was thrown:"); + illegArgExcept.printStackTrace(out); + } catch (NullPointerException nullPE) { + out.println("> PASSED: expected NullPointerException was thrown:"); + nullPE.printStackTrace(out); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + + out.println("\n>> protected AudioFileFormat constructor for AudioFormat = null: "); + try { + testedAudioFileFormat = + new TestAudioFileFormat(testAudioFileFormatType, // AudioFileFormat.Type + (int) 1024, // byteLength + nullAudioFormat, // AudioFormat + (int) 1024 // int frameLength + ); + out.println("> No any Exception was thrown!"); + out.println("> testedAudioFileFormat.getFormat():"); + try { + AudioFormat producedFormat = testedAudioFileFormat.getFormat(); + out.println("> PASSED: producedFormat = " + producedFormat); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + out.println("> testedAudioFileFormat.toString():"); + try { + String producedString = testedAudioFileFormat.toString(); + out.println("> PASSED: producedString = " + producedString); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + } catch (IllegalArgumentException illegArgExcept) { + out.println("> PASSED: expected IllegalArgumentException was thrown:"); + illegArgExcept.printStackTrace(out); + } catch (NullPointerException nullPE) { + out.println("> PASSED: expected NullPointerException was thrown:"); + nullPE.printStackTrace(out); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + + if (testResult == STATUS_FAILED) { + out.println("\n==> test FAILED!"); + } else { + out.println("\n==> test PASSED!"); + } + return testResult; + } +} + +class TestAudioFileFormat extends AudioFileFormat { + + TestAudioFileFormat(AudioFileFormat.Type type, int byteLength, + AudioFormat format, int frameLength) { + super(type, byteLength, format, frameLength); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/AudioFileFormat/Properties.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/AudioFileFormat/Properties.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.sound.midi.MidiFileFormat; +import javax.sound.midi.Sequence; +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; + +/** + * @test + * @bug 4666845 + * @summary RFE: Add properties to AudioFileFormat and MidiFileFormat + */ +public class Properties { + + static boolean g_failed = false; + + // all of p1 need to be in p2 + static boolean compare(Map p1, Map p2) { + boolean failed = false; + for(String key: (Set) p1.keySet()) { + out(" testing key: "+key); + if (!p2.containsKey(key)) { + out(" missing property: '"+key+"'. Failed"); + failed = true; + } + Object v1 = p1.get(key); + Object v2 = p2.get(key); + if (((v1 == null) && (v2 != null)) + || ((v1 != null) && (v2 == null)) + || !(v1.equals(v2))) { + out(" property '"+key+"' is different: " + +"expected='"+v1+"' " + +"actual='"+v2+"'. Failed"); + failed = true; + } + } + // test if we can modify p2 + try { + int oldSize = p2.size(); + p2.clear(); + if (oldSize > 0 && p2.size() == 0) { + out(" could clear the properties! Failed."); + failed = true; + } + } catch (Exception e) { + // correct + } + return failed; + } + + public static void main(String argv[]) throws Exception { + // don't need to catch exceptions: any exception is a + // failure of this test + + Map p = new HashMap(); + p.put("author", "Florian"); + p.put("duration", new Long(1000)); + p.put("MyProp", "test"); + + out("Testing AudioFileFormat properties:"); + // create an AudioFileFormat with properties + AudioFormat format = new AudioFormat( 44100.0f, 16, 2, true, false); + AudioFileFormat aff = + new AudioFileFormat(AudioFileFormat.Type.WAVE, + format, 1000, p); + // test that it has the properties + boolean failed = compare(p, aff.properties()); + // test getProperty() + Object o = aff.getProperty("author"); + if (o == null || !o.equals("Florian")) { + out(" getProperty did not report an existing property!"); + failed = true; + } + o = aff.getProperty("does not exist"); + if (o != null) { + out(" getProperty returned something for a non-existing property!"); + failed = true; + } + if (!failed) { + out(" OK"); + } else { + g_failed = true; + } + + + + out("Testing MidiFileFormat properties:"); + // create a MidiFileFormat with properties + MidiFileFormat mff = + new MidiFileFormat(0, Sequence.PPQ, 240, + 1000, 100, p); + // test that it has the properties + failed = compare(p, mff.properties()); + // test getProperty() + o = mff.getProperty("author"); + if (o == null || !o.equals("Florian")) { + out(" getProperty did not report an existing property!"); + failed = true; + } + o = mff.getProperty("does not exist"); + if (o != null) { + out(" getProperty returned something for a non-existing property!"); + failed = true; + } + if (!failed) { + out(" OK"); + } else { + g_failed = true; + } + + + if (g_failed) throw new Exception("Test FAILED!"); + System.out.println("Test passed."); + } + + static void out(String s) { + System.out.println(s); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/AudioFileFormat/TypeEquals.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/AudioFileFormat/TypeEquals.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFileFormat; + +/** + * @test + * @bug 4925483 + * @summary RFE: equals() should compare string in Encoding and Type + */ +public class TypeEquals { + + public static void main(String argv[]) throws Exception { + // first test that we can create our own type + // (the constructor was made public) + AudioFileFormat.Type myType = new AudioFileFormat.Type("WAVE", "wav"); + + // then check if this one equals this new one + // with the static instance in AudioFileFormat.Type + if (!myType.equals(AudioFileFormat.Type.WAVE)) { + throw new Exception("Types do not equal!"); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/AudioFormat/AudioFormatBitSize.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/AudioFormat/AudioFormatBitSize.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 4754759 + * @summary AudioFormat does not handle uncommon bit sizes correctly + */ + +import javax.sound.sampled.AudioFormat; + +public class AudioFormatBitSize { + + public static void main(String[] args) throws Exception { + int bits = 18; + AudioFormat format = new AudioFormat(44100.0f, bits, 1, true, false); + if (format.getFrameSize() * 8 < bits) { + System.out.println("bits = "+bits+" do not fit into a "+format.getFrameSize()+" bytes sample!"); + throw new Exception("Test failed"); + } else + System.out.println("bits = "+bits+" fit OK into a "+format.getFrameSize()+" bytes sample!"); + System.out.println("Test passed"); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/AudioFormat/EncodingEquals.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/AudioFormat/EncodingEquals.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFormat; + +/** + * @test + * @bug 4925483 + * @summary RFE: equals() should compare string in Encoding and Type + */ +public class EncodingEquals { + + public static void main(String argv[]) throws Exception { + // first test that we can create our own encoding + // (the constructor was made public) + AudioFormat.Encoding myType = new AudioFormat.Encoding("PCM_SIGNED"); + + // then check if this one equals this new one + // with the static instance in AudioFormat.Encoding + if (!myType.equals(AudioFormat.Encoding.PCM_SIGNED)) { + throw new Exception("Encodings do not equal!"); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/AudioFormat/Properties.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/AudioFormat/Properties.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.sound.sampled.AudioFormat; + +/** + * @test + * @bug 4925767 + * @summary RFE: Add Properties to AudioFormat + */ +public class Properties { + + static boolean g_failed = false; + + // all of p1 need to be in p2 + static boolean compare(Map p1, Map p2) { + boolean failed = false; + for(String key: (Set) p1.keySet()) { + out(" testing key: "+key); + if (!p2.containsKey(key)) { + out(" missing property: '"+key+"'. Failed"); + failed = true; + } + Object v1 = p1.get(key); + Object v2 = p2.get(key); + if (((v1 == null) && (v2 != null)) + || ((v1 != null) && (v2 == null)) + || !(v1.equals(v2))) { + out(" property '"+key+"' is different: " + +"expected='"+v1+"' " + +"actual='"+v2+"'. Failed"); + failed = true; + } + } + // test if we can modify p2 + try { + int oldSize = p2.size(); + p2.clear(); + if (oldSize > 0 && p2.size() == 0) { + out(" could clear the properties! Failed."); + failed = true; + } + } catch (Exception e) { + // correct + } + return failed; + } + + + public static void main(String argv[]) throws Exception { + // don't need to catch exceptions: any exception is a + // failure of this test + + Map p = new HashMap(); + p.put("bitrate", new Integer(128)); + p.put("quality", new Integer(10)); + p.put("MyProp", "test"); + + out("Testing AudioFileFormat properties:"); + // create an AudioFileFormat with properties + AudioFormat format = + new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, + 44100.0f, 16, 2, 4, 44100.0f, false, p); + // test that it has the properties + boolean failed = compare(p, format.properties()); + // test getProperty() + Object o = format.getProperty("MyProp"); + if (o == null || !o.equals("test")) { + out(" getProperty did not report an existing property!"); + failed = true; + } + o = format.getProperty("does not exist"); + if (o != null) { + out(" getProperty returned something for a non-existing property!"); + failed = true; + } + if (!failed) { + out(" OK"); + } else { + g_failed = true; + } + + if (g_failed) throw new Exception("Test FAILED!"); + System.out.println("Test passed."); + } + + static void out(String s) { + System.out.println(s); + } + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/AudioInputStream/AISReadFraction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/AudioInputStream/AISReadFraction.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.io.InputStream; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 4948663 + * @summary AudioInputStream does not use the original stream passed to its constructor + */ +public class AISReadFraction { + + static int failed = 0; + static byte[] testData = new byte[256]; + static boolean DEBUG = false; + + static AudioFormat[] formats = { + new AudioFormat(44100.0f, 8, 1, false, false), // frameSize = 1 + new AudioFormat(44100.0f, 8, 2, false, false), // frameSize = 2 + new AudioFormat(44100.0f, 16, 1, true, false), // frameSize = 2 + new AudioFormat(44100.0f, 24, 1, true, false), // frameSize = 3 + new AudioFormat(44100.0f, 16, 2, true, false), // frameSize = 4 + new AudioFormat(44100.0f, 8, 5, false, false), // frameSize = 5 + new AudioFormat(44100.0f, 16, 3, true, false), // frameSize = 6 + new AudioFormat(44100.0f, 8, 7, false, false), // frameSize = 7 + new AudioFormat(44100.0f, 32, 2, true, false) // frameSize = 8 + }; + + + public static void main(String args[]) throws Exception { + for (int i = 0; i0) throw new Exception("Test FAILED!"); + out("Test passed."); + } + + static void doTest(AudioFormat format, boolean doMark) { + out("Test with"+(doMark?"":"out")+" marking. Audio format: " + +"sampleSize="+format.getSampleSizeInBits()+"bits " + +"channels="+format.getChannels()+" " + +"frameSize="+format.getFrameSize()+"byte(s)"); + int maxReadBytes = (testData.length / format.getFrameSize()) * format.getFrameSize(); + InputStream is = new FractionalIS(testData, doMark); + AudioInputStream ais = new AudioInputStream(is, format, AudioSystem.NOT_SPECIFIED); + // first some general tests + if (ais.markSupported() && !doMark) { + out(" #AIS reports markSupported, but underlying stream cannot! FAILED"); + failed ++; + } + if (!ais.markSupported() && doMark) { + out(" #AIS does not report markSupported, but underlying stream can mark! FAILED"); + failed++; + } + byte[] data = new byte[1000]; + int frameSize = format.getFrameSize(); + int counter = 5; + int totalReadBytes = 0; + boolean hasRead0 = false; + boolean hasMarked = false; + boolean hasReset = false; + int markPos = 0; + while (true) { + try { + int toBeRead = frameSize * counter; + counter += 3; + if (counter > 14) { + counter -= 14; + } + int read = ais.read(data, 0, toBeRead); + if (DEBUG) out(" -> ais.read(data, 0, "+toBeRead+"): "+read+" (frameSize="+frameSize+")"); + if ((totalReadBytes == maxReadBytes) && (read != -1) + && ((read > 0) || hasRead0)) { + if (read == 0) { + out(" #stream was read to the end ("+maxReadBytes+"), but ais.read returned repeatedly 0 bytes. FAILED"); + } else { + out(" #stream was read to the end ("+maxReadBytes+"), but ais.read returned "+read+" bytes... FAILED"); + } + failed++; + break; + } + if (read > 0) { + verifyReadBytes(data, totalReadBytes, read); + if ((read % frameSize) != 0) { + out(" #Read non-integral number of frames: "+read+" bytes, frameSize="+frameSize+" bytes. FAILED"); + failed++; + } + totalReadBytes += read; + hasRead0 = false; + } + else if (read == 0) { + //out(" wanted to read "+toBeRead+" at position "+totalReadBytes+", but got 0 bytes!"); + if (hasRead0) { + out(" read 0 twice in a row! FAILED"); + failed++; + break; + } + hasRead0 = true; + } else { + // end of stream + out(" End of stream reached. Total read bytes: "+totalReadBytes); + if (totalReadBytes != maxReadBytes) { + out(" #Failed: should have read "+maxReadBytes+" bytes! FAILED."); + failed++; + } + break; + } + + // test marking + if (totalReadBytes > 50 && !hasMarked && !hasReset && doMark) { + out(" Marking at position "+totalReadBytes); + hasMarked = true; + ais.mark(0); + markPos = totalReadBytes; + } + if (totalReadBytes > 100 && hasMarked && !hasReset && doMark) { + out(" Resetting at position "+totalReadBytes+" back to "+markPos); + hasReset = true; + ais.reset(); + totalReadBytes = markPos; + } + + } catch (IOException e) { + out(" #caught unexpected exception:"); + e.printStackTrace(); + failed++; + } + } + } + + static void verifyReadBytes(byte[] data, int offset, int len) { + int firstWrongByte = -1; + for (int i = 0; i < len; i++) { + int expected = ((offset + i) % 128); + if (data[i] != expected) { + out(" read data is not correct! offset="+offset+" expected="+expected+" actual="+data[i]); + failed++; + break; + } + } + } + + + public static void out(String s) { + System.out.println(s); + } + + + static class FractionalIS extends InputStream { + byte[] data; + int pos = 0; + boolean canMark; + // a counter how many bytes are not returned + int missingBytes = 0; + int markPos = -1; + + FractionalIS(byte[] data, boolean canMark) { + this.data = data; + this.canMark = canMark; + } + + public int read() throws IOException { + if (pos >= data.length) { + return -1; + } + return data[pos++] & 0xFF; + } + + public int read(byte[] b, int off, int len) throws IOException { + if (++missingBytes > 5) { + missingBytes = 0; + } + int reducedLen = len - missingBytes; + if (reducedLen <= 0) reducedLen = 1; + if (DEBUG) out(" FIS.read(data, 0, "+len+"): reducing len to "+reducedLen+" bytes."); + int ret = super.read(b, off, reducedLen); + if (DEBUG) out(" returning "+ret+" bytes. Now at pos="+pos); + return ret; + } + + public void mark(int readlimit) { + markPos = pos; + if (DEBUG) out(" FIS.mark(): marking at "+pos); + } + + public void reset() throws IOException { + if (!canMark) { + throw new IOException("reset not supported!"); + } + if (markPos == -1) { + throw new IOException("Mark position not set!"); + } + pos = markPos; + if (DEBUG) out(" FIS.reset(): now back at "+pos); + } + + public boolean markSupported() { + return canMark; + } + + } + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/AudioInputStream/bug6188860.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/AudioInputStream/bug6188860.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.io.InputStream; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 6188860 + * @summary Tests that method AudioInputStream.read() returns right value + */ +public class bug6188860 { + + public static void main(String[] args) throws Exception { + byte[] testData = new byte[256]; + + // fill data + for (int i = 0; i < testData.length; i++) + testData[i] = (byte) (i % 128); + + InputStream streamSrc = new TestInputStream(testData); + AudioFormat format = new AudioFormat(44100.0f, 8, 1, false, false); // frameSize = 1 + AudioInputStream streamAudio = new AudioInputStream(streamSrc, format, AudioSystem.NOT_SPECIFIED); + + int nErrCount = 0; + int nTotal = 0; + + int dataSrc, dataRead; + while (nTotal < (testData.length - 1)) { + dataRead = streamAudio.read(); + if (dataRead < 0) { + System.out.println("end of stream"); + break; + } + + dataSrc = testData[nTotal]; + + if (dataRead != dataSrc) { + System.out.println("" + nTotal + " - mismatch :" + dataRead + " <> " + dataSrc); + nErrCount++; + } + nTotal++; + } + + System.out.println("Total: " + nTotal + "; Mismatches: " + nErrCount); + + if (nErrCount > 0) { + throw new RuntimeException("test failed: " + nErrCount + " mismatches of total " + nTotal + " bytes."); + } + System.out.println("Test sucessfully passed."); + } + + + static class TestInputStream extends InputStream { + byte[] data; + int pos = 0; + + TestInputStream(byte[] data) { + this.data = data; + } + + public int read() throws IOException { + if (pos >= data.length) { + return -1; + } + return data[pos++] & 0xFF; + } + } + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/AudioSystem/AudioFileTypes/AudioFileTypeUniqueness.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/AudioSystem/AudioFileTypes/AudioFileTypeUniqueness.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 4883060 + * @summary AudioSystem.getAudioFileTypes returns duplicates + */ +public class AudioFileTypeUniqueness { + + public static void main(String[] args) throws Exception { + boolean foundDuplicates = false; + AudioFileFormat.Type[] aTypes = AudioSystem.getAudioFileTypes(); + for (int i = 0; i < aTypes.length; i++) + { + for (int j = 0; j < aTypes.length; j++) + { + if (aTypes[i].equals(aTypes[j]) && i != j) { + foundDuplicates = true; + } + } + } + if (foundDuplicates) { + throw new Exception("Test failed"); + } else { + System.out.println("Test passed"); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/AudioSystem/AudioFileTypes/ShowAudioFileTypes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/AudioSystem/AudioFileTypes/ShowAudioFileTypes.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 4303037 + * @summary Shows the existing audio file types of AudioSystem and checks + * whether there are some at all + */ +public class ShowAudioFileTypes { + + public static void main(String[] args) throws Exception { + AudioFileFormat.Type[] aTypes = AudioSystem.getAudioFileTypes(); + System.out.println(aTypes.length+" supported target types:"); + for (int i = 0; i < aTypes.length; i++) + { + System.out.println(" "+(i+1)+". " + aTypes[i]+" with ext. '"+aTypes[i].getExtension()+"'"); + } + if (aTypes.length<3) { + throw new Exception("Test failed"); + } else { + System.out.println("Test passed"); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/AudioSystem/DefaultMixers.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/AudioSystem/DefaultMixers.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.List; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.Line; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.Port; +import javax.sound.sampled.SourceDataLine; +import javax.sound.sampled.TargetDataLine; +import javax.sound.sampled.spi.MixerProvider; + +import com.sun.media.sound.JDK13Services; + +/** + * @test + * @bug 4776511 + * @summary RFE: Setting the default MixerProvider. Test the retrieving of lines + * with defaut mixer properties. + * @modules java.desktop/com.sun.media.sound + */ +public class DefaultMixers { + + private static final String ERROR_PROVIDER_CLASS_NAME = "abc"; + private static final String ERROR_INSTANCE_NAME = "def"; + + private static final Class[] lineClasses = { + SourceDataLine.class, + TargetDataLine.class, + Clip.class, + Port.class, + }; + + public static void main(String[] args) throws Exception { + boolean allOk = true; + Mixer.Info[] infos; + + out("Testing Mixers retrieved via AudioSystem"); + infos = AudioSystem.getMixerInfo(); + allOk &= testMixers(infos, null); + + out("Testing MixerProviders"); + List providers = JDK13Services.getProviders(MixerProvider.class); + for (int i = 0; i < providers.size(); i++) { + MixerProvider provider = (MixerProvider) providers.get(i); + infos = provider.getMixerInfo(); + allOk &= testMixers(infos, provider.getClass().getName()); + } + + if (! allOk) { + throw new Exception("Test failed"); + } else { + out("Test passed"); + } + } + + private static boolean testMixers(Mixer.Info[] infos, + String providerClassName) { + boolean allOk = true; + + for (int i = 0; i < infos.length; i++) { + Mixer mixer = null; + try { + mixer = AudioSystem.getMixer(infos[i]); + } catch (NullPointerException e) { + out("Exception thrown; Test NOT failed."); + e.printStackTrace(); + } + for (int j = 0; j < lineClasses.length; j++) { + if (mixer.isLineSupported(new Line.Info(lineClasses[j]))) { + allOk &= testMixer(mixer, lineClasses[j], + providerClassName); + } + } + } + return allOk; + } + + private static boolean testMixer(Mixer mixer, Class lineType, + String providerClassName) { + boolean allOk = true; + String instanceName = mixer.getMixerInfo().getName(); + + // no error + allOk &= testMixer(mixer, lineType, + providerClassName, instanceName); + + // erroneous provider class name, correct instance name + allOk &= testMixer(mixer, lineType, + ERROR_PROVIDER_CLASS_NAME, instanceName); + + // erroneous provider class name, no instance name + allOk &= testMixer(mixer, lineType, + ERROR_PROVIDER_CLASS_NAME, ""); + + // erroneous provider class name, erroneous instance name + allOk &= testMixer(mixer, lineType, + ERROR_PROVIDER_CLASS_NAME, ERROR_INSTANCE_NAME); + + return allOk; + } + + private static boolean testMixer(Mixer mixer, Class lineType, + String providerClassName, + String instanceName) { + boolean allOk = true; + + try { + String propertyValue = (providerClassName != null) ? providerClassName: "" ; + propertyValue += "#" + instanceName; + out("property value: " + propertyValue); + System.setProperty(lineType.getName(), propertyValue); + Line line = null; + Line.Info info = null; + Line.Info[] infos; + AudioFormat format = null; + if (lineType == SourceDataLine.class || lineType == Clip.class) { + infos = mixer.getSourceLineInfo(); + format = getFirstLinearFormat(infos); + info = new DataLine.Info(lineType, format); + } else if (lineType == TargetDataLine.class) { + infos = mixer.getTargetLineInfo(); + format = getFirstLinearFormat(infos); + info = new DataLine.Info(lineType, format); + } else if (lineType == Port.class) { + /* Actually, a Ports Mixer commonly has source infos + as well as target infos. We ignore this here, since we + just need a random one. */ + infos = mixer.getSourceLineInfo(); + for (int i = 0; i < infos.length; i++) { + if (infos[i] instanceof Port.Info) { + info = infos[i]; + break; + } + } + } + out("Line.Info: " + info); + line = AudioSystem.getLine(info); + out("line: " + line); + if (! lineType.isInstance(line)) { + out("type " + lineType + " failed: class should be '" + + lineType + "' but is '" + line.getClass() + "'!"); + allOk = false; + } + } catch (Exception e) { + out("Exception thrown; Test NOT failed."); + e.printStackTrace(); + } + return allOk; + } + + private static AudioFormat getFirstLinearFormat(Line.Info[] infos) { + for (int i = 0; i < infos.length; i++) { + if (infos[i] instanceof DataLine.Info) { + AudioFormat[] formats = ((DataLine.Info) infos[i]).getFormats(); + for (int j = 0; j < formats.length; j++) { + AudioFormat.Encoding encoding = formats[j].getEncoding(); + int sampleSizeInBits = formats[j].getSampleSizeInBits(); + if (encoding.equals(AudioFormat.Encoding.PCM_SIGNED) && + sampleSizeInBits == 16 || + encoding.equals(AudioFormat.Encoding.PCM_UNSIGNED) && + sampleSizeInBits == 16) { + return formats[j]; + } + } + } + } + return null; + } + + private static void out(String message) { + System.out.println(message); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/AudioSystem/DefaultProperties.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/AudioSystem/DefaultProperties.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; + +import com.sun.media.sound.JDK13Services; + +/** + * @test + * @bug 4776511 + * @build DefaultProperties + * @run main/othervm DefaultProperties + * @summary RFE: Setting the default MixerProvider. Test the retrieving and + * parsing of properties. + * @modules java.desktop/com.sun.media.sound + */ +public class DefaultProperties { + + private static final Class[] lineTypeClasses = { + javax.sound.sampled.SourceDataLine.class, + javax.sound.sampled.TargetDataLine.class, + javax.sound.sampled.Clip.class, + javax.sound.sampled.Port.class, + }; + + public static void main(String[] args) throws Exception { + boolean allOk = true; + File file = new File(System.getProperty("test.src", "."), "testdata"); + System.setProperty("java.home", file.getCanonicalPath()); + + for (int i = 0; i < lineTypeClasses.length; i++) { + Class cls = lineTypeClasses[i]; + String propertyName = cls.getName(); + String result; + String provClassName; + String instanceName; + + // properties file, both provider class name and instance name + provClassName = "xyz"; + instanceName = "123"; + result = JDK13Services.getDefaultProviderClassName(cls); + if (! provClassName.equals(result)) { + out("type " + cls + " failed: provider class should be '" + + provClassName + "' but is '" + result + "'!"); + allOk = false; + } + result = JDK13Services.getDefaultInstanceName(cls); + if (! instanceName.equals(result)) { + out("type " + cls + " failed: instance name should be '" + + instanceName + "' but is '" + result + "'!"); + allOk = false; + } + + // system property, provider class name only, no trailing hash + provClassName = "abc"; + System.setProperty(propertyName, provClassName); + result = JDK13Services.getDefaultProviderClassName(cls); + if (! provClassName.equals(result)) { + out("type " + cls + " failed: provider class should be '" + + provClassName + "' but is '" + result + "'!"); + allOk = false; + } + result = JDK13Services.getDefaultInstanceName(cls); + if (result != null) { + out("type " + cls + " failed: instance name should be " + + "null but is '" + result + "'!"); + allOk = false; + } + + // system property, provider class name only, trailing hash + provClassName = "def"; + System.setProperty(propertyName, provClassName + "#"); + result = JDK13Services.getDefaultProviderClassName(cls); + if (! provClassName.equals(result)) { + out("type " + cls + " failed: provider class should be '" + + provClassName + "' but is '" + result + "'!"); + allOk = false; + } + result = JDK13Services.getDefaultInstanceName(cls); + if (result != null) { + out("type " + cls + " failed: instance name should be " + + "null but is '" + result + "'!"); + allOk = false; + } + + // system property, instance name only + instanceName = "ghi"; + System.setProperty(propertyName, "#" + instanceName); + result = JDK13Services.getDefaultProviderClassName(cls); + if (result != null) { + out("type " + cls + " failed: provider class should be " + + "null but is '" + result + "'!"); + allOk = false; + } + result = JDK13Services.getDefaultInstanceName(cls); + if (! instanceName.equals(result)) { + out("type " + cls + " failed: instance name should be '" + + instanceName + "' but is '" + result + "'!"); + allOk = false; + } + + // system property, both provider class and instance name + provClassName = "jkl"; + instanceName = "mno"; + System.setProperty(propertyName, provClassName + "#" + instanceName); + result = JDK13Services.getDefaultProviderClassName(cls); + if (! provClassName.equals(result)) { + out("type " + cls + " failed: provider class should be '" + + provClassName + "' but is '" + result + "'!"); + allOk = false; + } + result = JDK13Services.getDefaultInstanceName(cls); + if (! instanceName.equals(result)) { + out("type " + cls + " failed: instance name should be '" + + instanceName + "' but is '" + result + "'!"); + allOk = false; + } + + // system property, empty + System.setProperty(propertyName, ""); + result = JDK13Services.getDefaultProviderClassName(cls); + if (result != null) { + out("type " + cls + " failed: provider class should be " + + "null but is '" + result + "'!"); + allOk = false; + } + result = JDK13Services.getDefaultInstanceName(cls); + if (result != null) { + out("type " + cls + " failed: instance name should be " + + "null but is '" + result + "'!"); + allOk = false; + } + } + if (! allOk) { + throw new Exception("Test failed"); + } else { + out("Test passed"); + } + } + + private static void out(String message) { + System.out.println(message); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/AudioSystem/ProviderCacheing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/AudioSystem/ProviderCacheing.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.List; +import com.sun.media.sound.JDK13Services; + +/** + * @test + * @bug 4776511 + * @summary RFE: Setting the default MixerProvider. Test the cacheing of + * providers. + * @modules java.desktop/com.sun.media.sound + */ +public class ProviderCacheing { + + private static final Class[] providerClasses = { + javax.sound.sampled.spi.AudioFileReader.class, + javax.sound.sampled.spi.AudioFileWriter.class, + javax.sound.sampled.spi.FormatConversionProvider.class, + javax.sound.sampled.spi.MixerProvider.class, + }; + + public static void main(String[] args) throws Exception { + boolean allCached = true; + for (int i = 0; i < providerClasses.length; i++) { + List list0 = JDK13Services.getProviders(providerClasses[i]); + List list1 = JDK13Services.getProviders(providerClasses[i]); + if (list0 == list1) { + out("Providers should not be cached for " + providerClasses[i]); + allCached = false; + } + } + + if (! allCached) { + throw new Exception("Test failed"); + } else { + out("Test passed"); + } + } + + private static void out(String message) { + System.out.println(message); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/AudioSystem/testdata/conf/sound.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/AudioSystem/testdata/conf/sound.properties Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,27 @@ +# +# Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +javax.sound.sampled.SourceDataLine=xyz#123 +javax.sound.sampled.TargetDataLine=xyz#123 +javax.sound.sampled.Clip=xyz#123 +javax.sound.sampled.Port=xyz#123 diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Clip/ClipCloseLoss.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Clip/ClipCloseLoss.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; + +/** + * @test + * @bug 4946913 + * @summary DirectClip doesn't kill the thread correctly, sometimes + * @run main/othervm ClipCloseLoss + * @key headful + */ +public class ClipCloseLoss { + static int frameCount = 441000; // lets say 10 seconds + static AudioFormat format = new AudioFormat(44100.0f, 16, 2, true, false); + static ByteArrayInputStream bais = + new ByteArrayInputStream(new byte[frameCount * format.getFrameSize()]); + + static int success = 0; + static boolean failed = false; + + public static void run(Mixer m) { + Clip clip = null; + try { + if (m == null) { + out("Using default mixer"); + clip = (Clip) AudioSystem.getClip(); + } else { + out("Using mixer: "+m); + DataLine.Info info = new DataLine.Info(Clip.class, format, AudioSystem.NOT_SPECIFIED); + clip = (Clip) m.getLine(info); + } + out(" got clip: "+clip); + if (!clip.getClass().toString().contains("Direct")) { + out(" no direct audio clip -> do not test."); + return; + } + + out(" open"); + bais.reset(); + clip.open(new AudioInputStream(bais, format, frameCount)); + + out(" clip.close()"); + //long t = System.currentTimeMillis(); + clip.close(); + //if (System.currentTimeMillis() - t > 1950) { + // out(" clip.close needed more than 2 seconds! Causes failure of this test."); + // failed = true; + //} + out(" clip closed"); + success++; + } catch (LineUnavailableException luae) { + // line not available, test not failed + System.err.println(luae); + } catch (IllegalArgumentException iae) { + // line not available, test not failed + System.err.println(iae); + } catch (Throwable t) { + t.printStackTrace(); + } + } + + public static int getClipThreadCount() { + int ret = 0; + ThreadGroup tg = Thread.currentThread().getThreadGroup(); + while (tg.getParent() != null) { tg = tg.getParent(); } + Thread[] threads = new Thread[500]; + int count = tg.enumerate(threads, true); + for (int i = 0; i < count; i++) { + if (threads[i].getName().contains("Direct") + && threads[i].getName().contains("Clip")) { + out("Found Direct Clip thread object: "+threads[i]); + ret++; + } + } + return ret; + } + + public static void main(String[] args) throws Exception { + if (isSoundcardInstalled()) { + bais.mark(0); + run(null); + Mixer.Info[] infos = AudioSystem.getMixerInfo(); + for (int i = 0; i 0) { + out("Unused clip threads exist! Causes test failure"); + failed = true; + } + if (failed) throw new Exception("Test FAILED!"); + if (success > 0) { + out("Test passed."); + } else { + System.err.println("Test could not execute: please install an audio device"); + } + } + } + + /** + * Returns true if at least one soundcard is correctly installed + * on the system. + */ + public static boolean isSoundcardInstalled() { + boolean result = false; + try { + Mixer.Info[] mixers = AudioSystem.getMixerInfo(); + if (mixers.length > 0) { + result = AudioSystem.getSourceDataLine(null) != null; + } + } catch (Exception e) { + System.err.println("Exception occured: "+e); + } + if (!result) { + System.err.println("Soundcard does not exist or sound drivers not installed!"); + System.err.println("This test requires sound drivers for execution."); + } + return result; + } + + public static void out(String s) { + /*long t = System.nanoTime() / 1000000l; + String ts = ""+(t % 1000); + while (ts.length() < 3) ts = "0"+ts; + System.out.println(""+(t/1000)+":"+ts+" "+s); + System.out.flush();*/ + System.out.println(s); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Clip/ClipFlushCrash.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Clip/ClipFlushCrash.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; + +/** + * @test + * @bug 4946945 + * @summary Crash in javasound while running TicTacToe demo applet tiger b26 + */ +public class ClipFlushCrash { + static int frameCount = 441000; // lets say 10 seconds + static AudioFormat format = new AudioFormat(44100.0f, 16, 2, true, false); + static ByteArrayInputStream bais = + new ByteArrayInputStream(new byte[frameCount * format.getFrameSize()]); + + static int success = 0; + + public static void run(Mixer m) { + Clip clip = null; + try { + if (m == null) { + out("Using default mixer"); + clip = (Clip) AudioSystem.getClip(); + } else { + out("Using mixer: "+m); + DataLine.Info info = new DataLine.Info(Clip.class, format, AudioSystem.NOT_SPECIFIED); + clip = (Clip) m.getLine(info); + } + out(" got clip: "+clip); + if (!clip.getClass().toString().contains("Direct")) { + out(" no direct audio clip -> do not test."); + return; + } + + out(" open"); + bais.reset(); + clip.open(new AudioInputStream(bais, format, frameCount)); + + AT at1 = new AT(clip, "flush thread", 123) { + public void doAction() throws Exception { + log("flush"); + clip.flush(); + } + }; + AT at2 = new AT(clip, "setFramePosition thread", 67) { + public void doAction() throws Exception { + int pos = (int) (Math.random() * clip.getFrameLength()); + log("setPosition to frame "+pos); + clip.setFramePosition(pos); + } + }; + AT at3 = new AT(clip, "start/stop thread", 300) { + public void doAction() throws Exception { + if (clip.isRunning()) { + log("stop"); + clip.stop(); + } else { + log("start"); + clip.setFramePosition(0); + clip.start(); + } + } + }; + AT at4 = new AT(clip, "open/close thread", 600) { + public synchronized void doAction() throws Exception { + log("close"); + clip.close(); + wait(50); + if (!terminated) { + log("open"); + bais.reset(); + clip.open(new AudioInputStream(bais, format, frameCount)); + } + } + }; + + out(" clip.start"); + clip.start(); + out(" for 10 seconds, call start/stop, setFramePosition, and flush from other threads"); + at1.start(); + at2.start(); + at3.start(); + at4.start(); + try { + Thread.sleep(10000); + } catch (InterruptedException ie) {} + out(" finished."); + at1.terminate(); + at2.terminate(); + at3.terminate(); + at4.terminate(); + out(" clip.close()"); + clip.close(); + success++; + } catch (LineUnavailableException luae) { + // line not available, test not failed + System.err.println(luae); + } catch (IllegalArgumentException iae) { + // line not available, test not failed + System.err.println(iae); + } catch (Throwable t) { + t.printStackTrace(); + } + } + + public static void main(String[] args) throws Exception { + if (isSoundcardInstalled()) { + bais.mark(0); + run(null); + Mixer.Info[] infos = AudioSystem.getMixerInfo(); + for (int i = 0; i 0) { + out("No crash -> Test passed"); + } else { + System.err.println("Test could not execute: please install an audio device"); + } + } + } + + /** + * Returns true if at least one soundcard is correctly installed + * on the system. + */ + public static boolean isSoundcardInstalled() { + boolean result = false; + try { + Mixer.Info[] mixers = AudioSystem.getMixerInfo(); + if (mixers.length > 0) { + result = AudioSystem.getSourceDataLine(null) != null; + } + } catch (Exception e) { + System.err.println("Exception occured: "+e); + } + if (!result) { + System.err.println("Soundcard does not exist or sound drivers not installed!"); + System.err.println("This test requires sound drivers for execution."); + } + return result; + } + + public static void out(String s) { + /*long t = System.nanoTime() / 1000000l; + String ts = ""+(t % 1000); + while (ts.length() < 3) ts = "0"+ts; + System.out.println(""+(t/1000)+":"+ts+" "+s); + System.out.flush();*/ + System.out.println(s); + } + + private abstract static class AT extends Thread { + protected boolean terminated = false; + protected Clip clip; + private int waitTime; + + public AT(Clip clip, String name, int waitTime) { + super(name); + this.clip = clip; + this.waitTime = waitTime; + } + + public abstract void doAction() throws Exception; + + public void run() { + log("start"); + while (!terminated) { + try { + synchronized(this) { + wait(waitTime); + } + if (!terminated) { + doAction(); + } + } catch(Exception e) { + log("exception: "+e); + } + } + log("exit"); + } + + public synchronized void terminate() { + log("terminate"); + terminated = true; + notifyAll(); + } + + protected void log(String s) { + //out(" "+Thread.currentThread().getId()+" "+getName()+": "+s); + out(" "+getName()+": "+s); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Clip/Drain/ClipDrain.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Clip/Drain/ClipDrain.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.Mixer; + +/** + * @test + * @bug 4732218 + * @summary Clip.drain does not actually block until all I/O is complete as + * documented. + */ +public class ClipDrain { + static int successfulTests = 0; + static AudioFormat format = new AudioFormat(8000, 16, 1, true, false); + // create a 10-second file + static byte[] soundData = new byte[(int) (format.getFrameRate() * format.getFrameSize() * 10)]; + + static int TOLERANCE_MS = 2500; // how many milliseconds too short is tolerated... + + private static void doMixerClip(Mixer mixer) throws Exception { + boolean waitedEnough=false; + try { + DataLine.Info info = new DataLine.Info(Clip.class, format); + Clip clip = (Clip) mixer.getLine(info); + clip.open(format, soundData, 0, soundData.length); + + // sanity + if (clip.getMicrosecondLength()/1000 < 9900) { + throw new Exception("clip's microsecond length should be at least 9900000, but it is "+clip.getMicrosecondLength()); + } + long start = System.currentTimeMillis(); + + System.out.println(" ---------- start --------"); + clip.start(); + // give time to actually start it. ALSA implementation needs that... + Thread.sleep(300); + System.out.println("drain ... "); + clip.drain(); + long elapsedTime = System.currentTimeMillis() - start; + System.out.println("close ... "); + clip.close(); + System.out.println("... done"); + System.out.println("Playback duration: "+elapsedTime+" milliseconds."); + waitedEnough = elapsedTime >= ((clip.getMicrosecondLength() / 1000) - TOLERANCE_MS); + } catch (Throwable t) { + System.out.println(" - Caught exception. Not failed."); + System.out.println(" - "+t.toString()); + return; + } + if (!waitedEnough) { + throw new Exception("Drain did not wait long enough to play entire clip."); + } + successfulTests++; + } + + + private static void doAll() throws Exception { + Mixer.Info[] mixers = AudioSystem.getMixerInfo(); + for (int i=0; i 0) { + result = AudioSystem.getSourceDataLine(null) != null; + } + } catch (Exception e) { + System.err.println("Exception occured: "+e); + } + if (!result) { + System.err.println("Soundcard does not exist or sound drivers not installed!"); + System.err.println("This test requires sound drivers for execution."); + } + return result; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Clip/Duration/ClipDuration.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Clip/Duration/ClipDuration.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; + +/** + * @test + * @bug 4237703 + * @summary Check that Clip.getMicrosecondLength() returns correct value. + */ +public class ClipDuration { + + public static int run(Mixer m) { + int res=1; // failed + int frameCount = 441000; // lets say 10 seconds + AudioFormat f = new AudioFormat(44100.0f, 16, 2, true, false); + AudioInputStream audioInputStream = + new AudioInputStream(new ByteArrayInputStream(new byte[frameCount * f.getFrameSize()]), + f, frameCount); + AudioFormat format = audioInputStream.getFormat(); + Clip m_clip = null; + try { + if (m == null) { + m_clip = (Clip) AudioSystem.getClip(); + } else { + DataLine.Info info = new DataLine.Info(Clip.class, format, AudioSystem.NOT_SPECIFIED); + m_clip = (Clip) m.getLine(info); + } + System.out.println("Got clip: "+m_clip); + m_clip.open(audioInputStream); + long microseconds=m_clip.getMicrosecondLength(); + System.out.println("getFrameLength()="+m_clip.getFrameLength()+" frames"); + System.out.println("getMicrosecondLength()="+microseconds+" us"); + if (Math.abs(microseconds-10000000)<50) { + System.out.println("->Clip OK"); + res=0; // passes if less than 50us error + } + } catch (LineUnavailableException luae) { + System.err.println(luae); + res = 3; // line not available, test not failed + } catch (Throwable t) { + System.out.println("->Exception:"+t); + t.printStackTrace(); + res=2; // exception + } + if (m_clip != null) { + m_clip.close(); + } + return res; + } + + + + public static void main(String[] args) throws Exception { + if (isSoundcardInstalled()) { + int res=3; + res = run(null); + Mixer.Info[] infos = AudioSystem.getMixerInfo(); + for (int i = 0; i 0) { + result = AudioSystem.getSourceDataLine(null) != null; + } + } catch (Exception e) { + System.err.println("Exception occured: "+e); + } + if (!result) { + System.err.println("Soundcard does not exist or sound drivers not installed!"); + System.err.println("This test requires sound drivers for execution."); + } + return result; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Clip/Endpoint/ClipSetEndPoint.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Clip/Endpoint/ClipSetEndPoint.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; + +/** + * @test + * @bug 4385928 + * @summary Verify that an endpoint -1 in Clip does not throw an exception + */ +//public class test048 extends TRTest +public class ClipSetEndPoint { + + private Clip theClip; + + boolean testPassed = true; + + //_______________________________________________ + // Method: runTest + //_______________________________________________ + public boolean runTest() { + AudioInputStream theAudioInputStream = new AudioInputStream( + new ByteArrayInputStream(new byte[2000]), + new AudioFormat(8000.0f, 8, 1, false, false), 2000); // + + AudioFormat theAudioFormat = theAudioInputStream.getFormat(); + + DataLine.Info info = new DataLine.Info(Clip.class, theAudioFormat, + AudioSystem.NOT_SPECIFIED); + try { + theClip = (Clip) AudioSystem.getLine(info); + theClip.open(theAudioInputStream); + + int theStartLoopPoint = 0; + int theEndLoopPoint = -1; // -1 signifies the last frame + + theClip.setLoopPoints(theStartLoopPoint, theEndLoopPoint); + //theClip.start(); + } catch (LineUnavailableException e) { + e.printStackTrace(); + testPassed = true; + } catch (Exception e) { + e.printStackTrace(); + testPassed = false; + } + return testPassed; + } + + //_______________________________________________ + // Method: main + //_______________________________________________ + public static void main(String[] args) throws Exception { + if (isSoundcardInstalled()) { + ClipSetEndPoint thisTest = new ClipSetEndPoint(); + boolean testResult = thisTest.runTest(); + if (testResult) { + System.out.println("Test passed"); + } else { + System.out.println("Test failed"); + throw new Exception("Test failed"); + } + } + } + + /** + * Returns true if at least one soundcard is correctly installed + * on the system. + */ + public static boolean isSoundcardInstalled() { + boolean result = false; + try { + Mixer.Info[] mixers = AudioSystem.getMixerInfo(); + if (mixers.length > 0) { + result = AudioSystem.getSourceDataLine(null) != null; + } + } catch (Exception e) { + System.err.println("Exception occured: " + e); + } + if (!result) { + System.err.println( + "Soundcard does not exist or sound drivers not installed!"); + System.err.println( + "This test requires sound drivers for execution."); + } + return result; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Clip/Open/ClipOpenBug.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Clip/Open/ClipOpenBug.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.FloatControl; + +/** + * @test + * @bug 4479444 + * @summary Verify that the error string of Clip.open() is meaningful + */ +public class ClipOpenBug { + + public static void main(String args[]) throws Exception { + boolean res = true; + try { + AudioInputStream ais = new AudioInputStream( + new ByteArrayInputStream(new byte[2000]), + new AudioFormat(8000.0f, 8, 1, false, false), 2000); // + AudioFormat format = ais.getFormat(); + DataLine.Info info = new DataLine.Info(Clip.class, format, + ((int) ais.getFrameLength() + * format + .getFrameSize())); + Clip clip = (Clip) AudioSystem.getLine(info); + clip.open(); + FloatControl rateControl = (FloatControl) clip.getControl( + FloatControl.Type.SAMPLE_RATE); + int c = 0; + while (c++ < 10) { + clip.stop(); + clip.setFramePosition(0); + clip.start(); + for (float frq = 22000; frq < 44100; frq = frq + 100) { + try { + Thread.currentThread().sleep(20); + } catch (Exception e) { + break; + } + rateControl.setValue(frq); + } + } + } catch (Exception ex) { + ex.printStackTrace(); + res = ex.getMessage().indexOf( + "This method should not have been invoked!") < 0; + } + if (res) { + System.out.println("Test passed"); + } else { + System.out.println("Test failed"); + throw new Exception("Test failed"); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.ArrayList; +import java.util.List; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.LineUnavailableException; + +/** + * @test + * @bug 8167435 + */ +public final class OpenNonIntegralNumberOfSampleframes { + + /** + * We will try to use all formats, in this case all our providers will be + * covered by supported/unsupported formats. + */ + private static final List formats = new ArrayList<>(2900); + + private static final Encoding[] encodings = { + Encoding.ALAW, Encoding.ULAW, Encoding.PCM_SIGNED, + Encoding.PCM_UNSIGNED, Encoding.PCM_FLOAT + }; + + private static final int[] sampleRates = { + 8000, 11025, 16000, 32000, 44100 + }; + + private static final int[] sampleBits = { + 4, 8, 11, 16, 20, 24, 32, 48, 64, 128 + }; + + private static final int[] channels = { + 1, 2, 3, 4, 5, 6 + }; + + static { + for (final Boolean end : new boolean[]{false, true}) { + for (final int sampleSize : sampleBits) { + for (final int sampleRate : sampleRates) { + for (final int channel : channels) { + final int frameSize = ((sampleSize + 7) / 8) * channel; + if (frameSize == 1) { + // frameSize=1 is ok for any buffers, skip it + continue; + } + for (final Encoding enc : encodings) { + formats.add( + new AudioFormat(enc, sampleRate, sampleSize, + channel, frameSize, + sampleRate, end)); + } + } + } + } + } + } + + public static void main(final String[] args) { + for (final AudioFormat af : formats) { + try (Clip clip = AudioSystem.getClip()) { + final int bufferSize = af.getFrameSize() + 1; + try { + clip.open(af, new byte[100], 0, bufferSize); + } catch (final IllegalArgumentException ignored) { + // expected exception + continue; + } catch (final LineUnavailableException e) { + // should not occur, we passed incorrect bufferSize + e.printStackTrace(); + } + System.err.println("af = " + af); + System.err.println("bufferSize = " + bufferSize); + throw new RuntimeException("Expected exception is not thrown"); + } catch (final LineUnavailableException ignored) { + // the test is not applicable + } + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Clip/bug5070081.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Clip/bug5070081.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; + +/* + * @test + * @bug 5070081 + * @summary Tests that javax.sound.sampled.Clip does not loses position through + * stop/start + * @key headful + */ +public class bug5070081 { + + static AudioFormat format = new AudioFormat(22050, 8, 1, false, false); + // create a 3-second file + static byte[] soundData = new byte[(int) (format.getFrameRate() * format.getFrameSize() * 3)]; + + static final int LOOP_COUNT = 5; + + static boolean test() throws Exception { + DataLine.Info info = new DataLine.Info(Clip.class, format); + Clip clip = (Clip)AudioSystem.getLine(info); + clip.open(format, soundData, 0, soundData.length); + + boolean bSuccess = true; + + long nLengthMS = clip.getMicrosecondLength()/1000; + + System.out.println(" Clip length:"); + System.out.println(" frames: " + clip.getFrameLength()); + System.out.println(" seconds: " + nLengthMS/1000.0); + + clip.start(); // start playing + Thread.sleep(1000); // wait a sec + long time1 = System.currentTimeMillis(); + long pos1 = clip.getFramePosition(); // store the position + System.out.println(" Position before stop: " + pos1); + clip.stop(); // and then stop + long pos2 = clip.getFramePosition(); // 2nd try + long time2 = System.currentTimeMillis(); + System.out.println(" Position after stop: " + pos2); + + System.out.println(" d(time): " + Math.abs(time2-time1) + " ms;" + + "d(clip pos): " + Math.abs(pos2 - pos1) + " ms."); + + long nDerivation = Math.abs(pos2 - pos1) - Math.abs(time2-time1); + // add 50 ms for deviation (delay for stopping and errors due timer precision) + if (nDerivation > 50) { + System.out.println(" ERROR(1): The deviation is too much: " + nDerivation + " ms"); + bSuccess = false; + } + + Thread.sleep(1000); + clip.start(); // start again + Thread.sleep(100); + while(clip.isRunning()); // wait for the sound to finish + + int nEndPos = clip.getFramePosition(); + System.out.println(" Position at end: " + nEndPos); + if (nEndPos > clip.getFrameLength()) { + System.out.println(" ERROR(2): end position if out of range"); + bSuccess = false; + } + + clip.close(); + + return bSuccess; + } + + public static void main(String[] args) throws Exception { + for (int count=1; count <= LOOP_COUNT; count++) + { + System.out.println("loop " + count + "/" + LOOP_COUNT); + if (!test()) + { + System.out.println("Test FAILED"); + throw new RuntimeException("Test FAILED."); + } + } + + System.out.println("Test passed sucessfully"); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Clip/bug6251460.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Clip/bug6251460.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineEvent; +import javax.sound.sampled.LineListener; +import javax.sound.sampled.LineUnavailableException; + +/** + * @test + * @bug 6251460 8047222 + * @requires (os.family == "windows" | os.family == "mac") + * @summary Tests that JavaSound plays short sounds (less then 1 second) + */ +public class bug6251460 { + private static final class MutableBoolean { + public boolean value; + + public MutableBoolean(boolean initialValue) { + value = initialValue; + } + } + + // static helper routines + static long startTime = currentTimeMillis(); + static long currentTimeMillis() { + return System.nanoTime() / 1000000L; + } + static void log(String s) { + long time = currentTimeMillis() - startTime; + long ms = time % 1000; + time /= 1000; + long sec = time % 60; + time /= 60; + long min = time % 60; + time /= 60; + System.out.println("" + + (time < 10 ? "0" : "") + time + + ":" + (min < 10 ? "0" : "") + min + + ":" + (sec < 10 ? "0" : "") + sec + + "." + (ms < 10 ? "00" : (ms < 100 ? "0" : "")) + ms + + " " + s); + } + + + static private int countErrors = 0; + static private final int LOOP_COUNT = 30; + + static AudioFormat format = new AudioFormat(8000, 16, 1, true, false); + // create a 250-ms clip + static byte[] soundData = new byte[(int) (format.getFrameRate() * format.getFrameSize() * 0.25)]; + + static protected void test() + throws LineUnavailableException, InterruptedException { + DataLine.Info info = new DataLine.Info(Clip.class, format); + Clip clip = (Clip)AudioSystem.getLine(info); + final MutableBoolean clipStoppedEvent = new MutableBoolean(false); + clip.addLineListener(new LineListener() { + @Override + public void update(LineEvent event) { + if (event.getType() == LineEvent.Type.STOP) { + synchronized (clipStoppedEvent) { + clipStoppedEvent.value = true; + clipStoppedEvent.notifyAll(); + } + } + } + }); + clip.open(format, soundData, 0, soundData.length); + + long lengthClip = clip.getMicrosecondLength() / 1000; + log("Clip length " + lengthClip + " ms"); + log("Playing..."); + for (int i=1; i<=LOOP_COUNT; i++) { + long startTime = currentTimeMillis(); + log(" Loop " + i); + clip.start(); + + synchronized (clipStoppedEvent) { + while (!clipStoppedEvent.value) { + clipStoppedEvent.wait(); + } + clipStoppedEvent.value = false; + } + + long endTime = currentTimeMillis(); + long lengthPlayed = endTime - startTime; + + if (lengthClip > lengthPlayed + 20) { + log(" ERR: Looks like sound didn't play: played " + lengthPlayed + " ms instead " + lengthClip); + countErrors++; + } else { + log(" OK: played " + lengthPlayed + " ms"); + } + clip.setFramePosition(0); + + } + log("Played " + LOOP_COUNT + " times, " + countErrors + " errors detected."); + } + + public static void main(String[] args) throws InterruptedException { + try { + test(); + } catch (LineUnavailableException | IllegalArgumentException + | IllegalStateException ignored) { + System.out.println("Test is not applicable. Automatically passed"); + return; + } + if (countErrors > 0) { + throw new RuntimeException( + "Test FAILED: " + countErrors + " error detected (total " + + LOOP_COUNT + ")"); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Controls/CompoundControl/ToString.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Controls/CompoundControl/ToString.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.CompoundControl; +import javax.sound.sampled.Control; + +/** + * @test + * @bug 4629190 + * @summary CompoundControl: getMemberControls() and toString() throw + * NullPointerException + */ +public class ToString { + public static void main(String args[]) throws Exception { + System.out.println(); + System.out.println(); + System.out.println("4629190: CompoundControl: getMemberControls() and toString() throw NullPointerException"); + + String firstControlTypeName = "first_Control_Type_Name"; + String secondControlTypeName = "second_Control_Type_Name"; + String thirdControlTypeName = "third_Control_Type_Name"; + + Control.Type firstControlType = new TestControlType(firstControlTypeName); + Control.Type secondControlType = new TestControlType(secondControlTypeName); + Control.Type thirdControlType = new TestControlType(thirdControlTypeName); + + Control firstControl = new TestControl(firstControlType); + Control secondControl = new TestControl(secondControlType); + Control thirdControl = new TestControl(thirdControlType); + + String testCompoundControlTypeName = "CompoundControl_Type_Name"; + CompoundControl.Type testCompoundControlType + = new TestCompoundControlType(testCompoundControlTypeName); + + Control[] setControls = { firstControl, secondControl, thirdControl }; + CompoundControl testedCompoundControl + = new TestCompoundControl(testCompoundControlType, setControls); + + // this may throw exception if bug applies + Control[] producedControls = testedCompoundControl.getMemberControls(); + System.out.println("Got "+producedControls.length+" member controls."); + + // this may throw exception if bug applies + String producedString = testedCompoundControl.toString(); + System.out.println("toString() returned: "+producedString); + + System.out.println("Test passed."); + } + +} + +class TestControl extends Control { + + TestControl(Control.Type type) { + super(type); + } +} + +class TestControlType extends Control.Type { + + TestControlType(String name) { + super(name); + } +} + +class TestCompoundControl extends CompoundControl { + + TestCompoundControl(CompoundControl.Type type, Control[] memberControls) { + super(type, memberControls); + } +} + +class TestCompoundControlType extends CompoundControl.Type { + + TestCompoundControlType(String name) { + super(name); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Controls/FloatControl/FloatControlBug.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Controls/FloatControl/FloatControlBug.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.FloatControl; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; + +/** + * @test + * @bug 4385654 + * @summary Check that the MASTER_GAIN control has a valid precision + */ +//public class test047 extends TRTest +public class FloatControlBug { + + private Clip theClip; + + boolean testPassed = true; + + private AudioFormat.Encoding theEncoding = AudioFormat.Encoding.PCM_SIGNED; + + private float theSampleRate = 44100; + + private int theSampleSize = 16; + + private int theNumberOfChannels = 1; + + private int theFrameSize = 2; + + private float theFrameRate = 44100; + + private boolean isBigEndian = false; + + //_______________________________________________ + // Method: runTest + //_______________________________________________ + public boolean runTest() { + AudioInputStream theAudioInputStream = new AudioInputStream( + new ByteArrayInputStream(new byte[0]), + new AudioFormat(44100.0f, 16, 2, true, false), 441000); + + AudioFormat theAudioFormat = theAudioInputStream.getFormat(); + + DataLine.Info info = new DataLine.Info(Clip.class, theAudioFormat, + AudioSystem.NOT_SPECIFIED); + try { + theClip = (Clip) AudioSystem.getLine(info); + theClip.open(theAudioInputStream); + FloatControl theFloatControl = (FloatControl) (theClip.getControl( + FloatControl.Type.MASTER_GAIN)); + float theFloatControlPrecision = theFloatControl.getPrecision(); + System.out.println( + "theFloatControlPrecision: " + theFloatControlPrecision); + System.out.println("Minimum: " + theFloatControl.getMinimum()); + System.out.println("Maximum: " + theFloatControl.getMaximum()); + System.out.println("Value : " + theFloatControl.getValue()); + testPassed = theFloatControlPrecision > 0; + } catch (LineUnavailableException e) { + e.printStackTrace(); + testPassed = true; + } catch (Exception e) { + e.printStackTrace(); + testPassed = false; + } + return testPassed; + } + + //_______________________________________________ + // Method: main + //_______________________________________________ + public static void main(String[] args) throws Exception { + //test047 thisTest = new test047(); + if (isSoundcardInstalled()) { + FloatControlBug thisTest = new FloatControlBug(); + boolean testResult = thisTest.runTest(); + if (testResult) { + System.out.println("Test passed"); + } else { + System.out.println("Test failed"); + throw new Exception("Test failed"); + } + } + } + + /** + * Returns true if at least one soundcard is correctly installed + * on the system. + */ + public static boolean isSoundcardInstalled() { + boolean result = false; + try { + Mixer.Info[] mixers = AudioSystem.getMixerInfo(); + if (mixers.length > 0) { + result = AudioSystem.getSourceDataLine(null) != null; + } + } catch (Exception e) { + System.err.println("Exception occured: " + e); + } + if (!result) { + System.err.println( + "Soundcard does not exist or sound drivers not installed!"); + System.err.println( + "This test requires sound drivers for execution."); + } + return result; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/DataLine/DataLineInfoNegBufferSize.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/DataLine/DataLineInfoNegBufferSize.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; + +/** + * @test + * @bug 5021234 + * @summary Using -2 for buffer size will fail retrieval of lines + */ +public class DataLineInfoNegBufferSize { + + /** + * returns: + * 0: OK + * 1: IAE + * 2: other exception + * 3: line not available + */ + public static int run(Mixer m, int bufferSize) { + int res; + int frameCount = 441000; // lets say 10 seconds + AudioFormat f = new AudioFormat(44100.0f, 16, 2, true, false); + Clip clip = null; + try { + System.out.println("Requesting clip from Mixer " + +(m==null?"default":m.toString()) + +" with bufferSize"+bufferSize); + DataLine.Info info = new DataLine.Info(Clip.class, f, bufferSize); + if (m==null) { + clip = (Clip) AudioSystem.getLine(info); + } else { + clip = (Clip) m.getLine(info); + } + System.out.println("Got clip: "+clip+" with Buffer size "+clip.getBufferSize()); + + res = 0; + } catch (LineUnavailableException luae) { + System.out.println(luae); + res = 3; // line not available + } catch (IllegalArgumentException iae) { + System.out.println(iae); + res = 1; + } catch (Throwable t) { + System.out.println("->Exception:"+t); + t.printStackTrace(); + res=2; // other exception + } + return res; + } + + public static void main(String[] args) throws Exception { + if (isSoundcardInstalled()) { + int res=0; + int count = 0; + Mixer.Info[] infos = AudioSystem.getMixerInfo(); + for (int i = -1; i 0) { + result = AudioSystem.getSourceDataLine(null) != null; + } + } catch (Exception e) { + System.err.println("Exception occured: "+e); + } + if (!result) { + System.err.println("Soundcard does not exist or sound drivers not installed!"); + System.err.println("This test requires sound drivers for execution."); + } + return result; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/DataLine/LineDefFormat.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/DataLine/LineDefFormat.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; +import javax.sound.sampled.TargetDataLine; + +/** + * @test + * @bug 5053380 + * @summary Verify that getting a line initializes it with the format in + * DataLine.Info + */ +public class LineDefFormat { + + final static int samplerate = 22050; + static int passed = 0; + static int failed = 0; + + private static void doLine1(DataLine line, AudioFormat format) { + try { + System.out.println(" - got line: "+line); + System.out.println(" - line has format: "+line.getFormat()); + if (!line.getFormat().matches(format)) { + System.out.println(" ## Error: expected this format: "+format); + failed++; + } else { + passed++; + } + } catch (Throwable t) { + System.out.println(" - Caught exception. Not failed."); + System.out.println(" - "+t.toString()); + } + } + + private static void doLine2(DataLine line, AudioFormat format) { + try { + System.out.println(" - call to open()"); + line.open(); + try { + System.out.println(" - line has format: "+line.getFormat()); + if (!line.getFormat().matches(format)) { + System.out.println("## Error: expected this format: "+format); + failed++; + } else { + passed++; + } + } finally { + line.close(); + System.out.println(" - closed"); + } + } catch (Throwable t) { + System.out.println(" - Caught exception. Not failed."); + System.out.println(" - "+t.toString()); + } + } + + private static void doMixerClip(Mixer mixer, AudioFormat format) { + if (mixer==null) return; + try { + System.out.println("Clip from mixer "+mixer+":"); + System.out.println(" "+mixer.getMixerInfo()); + DataLine.Info info = new DataLine.Info( + Clip.class, + format); + + if (mixer.isLineSupported(info)) { + Clip clip = (Clip) mixer.getLine(info); + doLine1(clip, format); + } else { + System.out.println(" - Line not supported"); + } + } catch (Throwable t) { + System.out.println(" - Caught exception. Not failed."); + System.out.println(" - "+t.toString()); + } + } + + private static void doMixerSDL(Mixer mixer, AudioFormat format) { + if (mixer==null) return; + try { + System.out.println("SDL from mixer "+mixer+":"); + DataLine.Info info = new DataLine.Info( + SourceDataLine.class, + format); + + if (mixer.isLineSupported(info)) { + SourceDataLine sdl = (SourceDataLine) mixer.getLine(info); + doLine1(sdl, format); + doLine2(sdl, format); + } else { + System.out.println(" - Line not supported"); + } + } catch (Throwable t) { + System.out.println(" - Caught exception. Not failed."); + System.out.println(" - "+t.toString()); + } + } + + private static void doMixerTDL(Mixer mixer, AudioFormat format) { + if (mixer==null) return; + try { + System.out.println("TDL from mixer "+mixer+":"); + DataLine.Info info = new DataLine.Info( + TargetDataLine.class, + format); + if (mixer.isLineSupported(info)) { + TargetDataLine tdl = (TargetDataLine) mixer.getLine(info); + doLine1(tdl, format); + doLine2(tdl, format); + } else { + System.out.println(" - Line not supported"); + } + } catch (Throwable t) { + System.out.println(" - Caught exception. Not failed."); + System.out.println(" - "+t.toString()); + } + } + + private static void doAll() throws Exception { + Mixer.Info[] mixers = AudioSystem.getMixerInfo(); + AudioFormat pcm; + for (int i=0; i 100) { + failed = true; + System.out.println("## FAILED: frame positions are not the same!"); + } + } finally { + sdl.close(); + } + } catch(LineUnavailableException e){ + System.out.println(e); + System.out.println("Cannot execute test."); + return; + } + if (failed) throw new Exception("Test FAILED!"); + System.out.println("Test Passed."); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/DirectAudio/TickAtEndOfPlay.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/DirectAudio/TickAtEndOfPlay.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.SourceDataLine; + +/** + * @test + * @bug 5001959 + * @summary Short tick sound after finished playing with SourceDataLine + * @run main/manual TickAtEndOfPlay + */ +public class TickAtEndOfPlay { + + static boolean WorkAround1 = false; + static boolean WorkAround2 = false; + + public static void main(String[] args) throws Exception { + System.out.println("This test should only be run on Windows."); + System.out.println("Make sure that the speakers are connected and the volume is up."); + System.out.println("Close all other programs that may use the soundcard."); + + System.out.println("You'll hear a 2-second tone. when the tone finishes,"); + System.out.println(" there should be no noise. If you hear a short tick/noise,"); + System.out.println(" the bug still applies."); + + System.out.println("Press ENTER to continue."); + System.in.read(); + + for (int i = 0; i < args.length; i++) { + if (args[i].equals("1")) WorkAround1 = true; + if (args[i].equals("2")) WorkAround2 = true; + } + if (WorkAround1) System.out.println("Using work around1: appending silence"); + if (WorkAround2) System.out.println("Using work around2: waiting before close"); + + int zerolen = 0; // how many 0-bytes will be appended to playback + if (WorkAround1) zerolen = 1000; + int seconds = 2; + int sampleRate = 8000; + double frequency = 1000.0; + double RAD = 2.0 * Math.PI; + AudioFormat af = new AudioFormat((float)sampleRate,8,1,true,true); + System.out.println("Format: "+af); + DataLine.Info info = new DataLine.Info(SourceDataLine.class,af); + SourceDataLine source = (SourceDataLine)AudioSystem.getLine(info); + System.out.println("Line: "+source); + if (source.toString().indexOf("MixerSourceLine")>=0) { + System.out.println("This test only applies to non-Java Sound Audio Engine!"); + return; + } + System.out.println("Opening..."); + source.open(af); + System.out.println("Starting..."); + source.start(); + int datalen = sampleRate * seconds; + byte[] buf = new byte[datalen+zerolen]; + for (int i=0; i 0 && !stopRequested) { + int avail = line.available(); + if (avail > 0) { + if (avail > remaining) + avail = remaining; + int written = line.write(data, data.length - remaining, avail); + remaining -= written; + log("WriteThread: " + written + " bytes written"); + } else { + delay(100); + } + } + if (remaining == 0) { + log("WriteThread: all data has been written, draining"); + line.drain(); + } else { + log("WriteThread: stop requested"); + } + log("WriteThread: stopping"); + line.stop(); + log("WriteThread: exiting"); + } + + public boolean isCompleted() { + return (remaining <= 0); + } + + public void requestStop() { + stopRequested = true; + } + } + + void testPlayback() throws LineUnavailableException { + // prepare audio data + AudioFormat format = new AudioFormat(22050, 8, 1, false, false); + byte[] soundData = new byte[(int) (format.getFrameRate() * format.getFrameSize() * DATA_LENGTH)]; + + // create & open source data line + //SourceDataLine line = AudioSystem.getSourceDataLine(format); + DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); + SourceDataLine line = (SourceDataLine)AudioSystem.getLine(info); + + line.open(format); + + // start write data thread + WriteThread p1 = new WriteThread(line, soundData); + p1.start(); + + // start line + PlayThread p2 = new PlayThread(line); + p2.start(); + + // monitor line + long lineTime1 = line.getMicrosecondPosition() / 1000; + long realTime1 = currentTimeMillis(); + while (true) { + delay(500); + if (!line.isActive()) { + log("audio data played completely"); + break; + } + long lineTime2 = line.getMicrosecondPosition() / 1000; + long realTime2 = currentTimeMillis(); + long dLineTime = lineTime2 - lineTime1; + long dRealTime = realTime2 - realTime1; + log("line pos: " + lineTime2 + "ms" + ", thread is " + (p2.isAlive() ? "alive" : "DIED")); + if (dLineTime < 0) { + throw new RuntimeException("ERROR: line position have decreased from " + lineTime1 + " to " + lineTime2); + } + if (dRealTime < 450) { + // delay() has been interrupted? + continue; + } + lineTime1 = lineTime2; + realTime1 = realTime2; + } + } + + + // recording test classes/routines + + class RecordThread extends Thread { + TargetDataLine line; + public RecordThread(TargetDataLine line) { + this.line = line; + this.setDaemon(true); + } + + public void run() { + log("RecordThread: starting..."); + line.start(); + log("RecordThread: delaying " + (PLAYTHREAD_DELAY * 1000) + "ms..."); + delay(PLAYTHREAD_DELAY * 1000); + log("RecordThread: exiting..."); + } + } + + class ReadThread extends Thread { + TargetDataLine line; + byte[] data; + volatile int remaining; + public ReadThread(TargetDataLine line, byte[] data) { + this.line = line; + this.data = data; + remaining = data.length; + this.setDaemon(true); + } + + public void run() { + log("ReadThread: buffer size is " + data.length + " bytes"); + delay(200); + while ((remaining > 0) && line.isOpen()) { + int avail = line.available(); + if (avail > 0) { + if (avail > remaining) + avail = remaining; + int read = line.read(data, data.length - remaining, avail); + remaining -= read; + log("ReadThread: " + read + " bytes read"); + } else { + delay(100); + } + if (remaining <= 0) { + log("ReadThread: record buffer is full, exiting"); + break; + } + } + if (remaining > 0) { + log("ReadThread: line has been stopped, exiting"); + } + } + + public int getCount() { + return data.length - remaining; + } + public boolean isCompleted() { + return (remaining <= 0); + } + } + + void testRecord() throws LineUnavailableException { + // prepare audio data + AudioFormat format = new AudioFormat(22050, 8, 1, false, false); + + // create & open target data line + //TargetDataLine line = AudioSystem.getTargetDataLine(format); + DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); + TargetDataLine line = (TargetDataLine)AudioSystem.getLine(info); + + line.open(format); + + // start read data thread + byte[] data = new byte[(int) (format.getFrameRate() * format.getFrameSize() * DATA_LENGTH)]; + ReadThread p1 = new ReadThread(line, data); + p1.start(); + + // start line + //new RecordThread(line).start(); + RecordThread p2 = new RecordThread(line); + p2.start(); + + // monitor line + long endTime = currentTimeMillis() + DATA_LENGTH * 1000; + + long realTime1 = currentTimeMillis(); + long lineTime1 = line.getMicrosecondPosition() / 1000; + + while (realTime1 < endTime && !p1.isCompleted()) { + delay(100); + long lineTime2 = line.getMicrosecondPosition() / 1000; + long realTime2 = currentTimeMillis(); + long dLineTime = lineTime2 - lineTime1; + long dRealTime = realTime2 - realTime1; + log("line pos: " + lineTime2 + "ms" + ", thread is " + (p2.isAlive() ? "alive" : "DIED")); + if (dLineTime < 0) { + line.stop(); + line.close(); + throw new RuntimeException("ERROR: line position have decreased from " + lineTime1 + " to " + lineTime2); + } + if (dRealTime < 450) { + // delay() has been interrupted? + continue; + } + lineTime1 = lineTime2; + realTime1 = realTime2; + } + log("stopping line..."); + line.stop(); + line.close(); + + /* + log(""); + log(""); + log(""); + log("recording completed, delaying 5 sec"); + log("recorded " + p1.getCount() + " bytes, " + DATA_LENGTH + " seconds: " + (p1.getCount() * 8 / DATA_LENGTH) + " bit/sec"); + log(""); + log(""); + log(""); + delay(5000); + log("starting playing..."); + playRecorded(format, data); + */ + } + + void playRecorded(AudioFormat format, byte[] data) throws Exception { + //SourceDataLine line = AudioSystem.getSourceDataLine(format); + DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); + SourceDataLine line = (SourceDataLine)AudioSystem.getLine(info); + + line.open(); + line.start(); + + int remaining = data.length; + while (remaining > 0) { + int avail = line.available(); + if (avail > 0) { + if (avail > remaining) + avail = remaining; + int written = line.write(data, data.length - remaining, avail); + remaining -= written; + log("Playing: " + written + " bytes written"); + } else { + delay(100); + } + } + + line.drain(); + line.stop(); + } + + // helper routines + static long startTime = currentTimeMillis(); + static long currentTimeMillis() { + //return System.nanoTime() / 1000000L; + return System.currentTimeMillis(); + } + static void log(String s) { + long time = currentTimeMillis() - startTime; + long ms = time % 1000; + time /= 1000; + long sec = time % 60; + time /= 60; + long min = time % 60; + time /= 60; + System.out.println("" + + (time < 10 ? "0" : "") + time + + ":" + (min < 10 ? "0" : "") + min + + ":" + (sec < 10 ? "0" : "") + sec + + "." + (ms < 10 ? "00" : (ms < 100 ? "0" : "")) + ms + + " (" + Thread.currentThread().getName() + ") " + s); + } + static void delay(int millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) {} + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/FileTypeExtension/FileTypeExtensionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/FileTypeExtension/FileTypeExtensionTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFileFormat; + +/** + * @test + * @bug 4300529 + * @summary Filename extension test. The filename extensions for file types + * AIFF-C, SND, and WAVE should not include a ".". + */ +public class FileTypeExtensionTest { + + public static void main(String[] args) throws Exception { + + AudioFileFormat.Type[] types = { AudioFileFormat.Type.AIFC, + AudioFileFormat.Type.AIFF, + AudioFileFormat.Type.AU, + AudioFileFormat.Type.SND, + AudioFileFormat.Type.WAVE }; + + boolean failed = false; + + System.out.println("\nDefined file types and extensions:"); + + for (int i = 0; i < types.length; i++) { + System.out.println("\n"); + System.out.println(" file type: " + types[i]); + System.out.println(" extension: " + types[i].getExtension()); + if( types[i].getExtension().charAt(0) == '.' ) { + failed = true; + } + } + + if (failed) { + System.err.println("Failed!"); + throw new Exception("File type extensions begin with ."); + } else { + System.err.println("Passed!"); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/LineEvent/LineInfoNPE.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/LineEvent/LineInfoNPE.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.Control; +import javax.sound.sampled.Line; +import javax.sound.sampled.LineEvent; +import javax.sound.sampled.LineListener; + +/** + * @test + * @bug 4672865 + * @summary LineEvent.toString() throws unexpected NullPointerException + */ +public class LineInfoNPE { + + static final int STATUS_PASSED = 0; + static final int STATUS_FAILED = 2; + static final int STATUS_TEMP = 95; + + public static void main(String argv[]) throws Exception { + int testExitStatus = run(argv, System.out); + if (testExitStatus != STATUS_PASSED) { + throw new Exception("test FAILED!"); + } + } + + public static int run(String argv[], java.io.PrintStream out) { + int testResult = STATUS_PASSED; + + out.println("\n==> Test for LineEvent class:"); + + Line testLine = new TestLine(); + Line nullLine = null; + + LineEvent.Type testLineEventType = LineEvent.Type.OPEN; + LineEvent.Type nullLineEventType = null; + + LineEvent testedLineEvent = null; + out.println("\n>> LineEvent constructor for Line = null: "); + try { + testedLineEvent = + new LineEvent(nullLine, // the source Line of this event + testLineEventType, // LineEvent.Type - the event type + (long) 1000 // position - the number processed of sample frames + ); + out.println("> No any Exception was thrown!"); + out.println("> testedLineEvent.getType():"); + try { + Line producedLine = testedLineEvent.getLine(); + out.println("> PASSED: producedLine = " + producedLine); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + out.println("> testedLineEvent.toString():"); + try { + String producedString = testedLineEvent.toString(); + out.println("> PASSED: producedString = " + producedString); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + } catch (IllegalArgumentException illegArgExcept) { + out.println("> PASSED: expected IllegalArgumentException was thrown:"); + illegArgExcept.printStackTrace(out); + } catch (NullPointerException nullPE) { + out.println("> PASSED: expected NullPointerException was thrown:"); + nullPE.printStackTrace(out); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + + out.println("\n>> LineEvent constructor for LineEvent.Type = null: "); + try { + testedLineEvent = + new LineEvent(testLine, // the source Line of this event + nullLineEventType, // LineEvent.Type - the event type + (long) 1000 // position - the number processed of sample frames + ); + out.println("> No any Exception was thrown!"); + out.println("> testedLineEvent.getType():"); + try { + LineEvent.Type producedType = testedLineEvent.getType(); + out.println("> PASSED: producedType = " + producedType); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + out.println("> testedLineEvent.toString():"); + try { + String producedString = testedLineEvent.toString(); + out.println("> PASSED: producedString = " + producedString); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + } catch (IllegalArgumentException illegArgExcept) { + out.println("> PASSED: expected IllegalArgumentException was thrown:"); + illegArgExcept.printStackTrace(out); + } catch (NullPointerException nullPE) { + out.println("> PASSED: expected NullPointerException was thrown:"); + nullPE.printStackTrace(out); + } catch (Throwable thrown) { + out.println("## FAILED: unexpected Exception was thrown:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + + if ( testResult == STATUS_FAILED ) { + out.println("\n==> test FAILED!"); + } else { + out.println("\n==> test PASSED!"); + } + return testResult; + } +} // end of test class + +class TestLine implements Line { + + public void addLineListener(LineListener listener) { + } + + public void close() { + } + + public Control getControl(Control.Type control) { + return null; + } + + public Control[] getControls() { + return new Control[0]; + } + + public Line.Info getLineInfo() { + return null; + } + + public boolean isOpen() { + return false; + } + + public boolean isControlSupported(Control.Type control) { + return false; + } + + public void open() { + } + + public void removeLineListener(LineListener listener) { + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Lines/16and32KHz/Has16and32KHz.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Lines/16and32KHz/Has16and32KHz.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.Line; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; +import javax.sound.sampled.TargetDataLine; + +/** + * @test + * @bug 4479441 + * @summary Verify that the lines report 16KHz and 32KHz capability + */ +public class Has16and32KHz { + + public static boolean ok32=false; + public static boolean ok16=false; + + public static void showMixerLines(Line.Info[] lineinfo) { + for (int j = 0; j < lineinfo.length; j++) { + boolean isSDL=false; // SourceDataLine + Line.Info thisInfo=lineinfo[j]; + System.out.println(" " + thisInfo); + String impl=""; + if (thisInfo.getLineClass().equals(SourceDataLine.class)) { + isSDL=true; + impl+="SourceDataLine"; + } + if (thisInfo.getLineClass().equals(Clip.class)) { + impl+="Clip"; + } + if (thisInfo.getLineClass().equals(DataLine.class)) { + impl+="DataLine"; + } + if (thisInfo.getLineClass().equals(TargetDataLine.class)) { + impl+="TargetDataLine"; + } + if (thisInfo.getLineClass().equals(Mixer.class)) { + impl+="Mixer"; + } + System.out.println(" implements "+impl); + try { + AudioFormat[] formats = ((DataLine.Info)lineinfo[j]).getFormats(); + for (int k = 0; k < formats.length; k++) { + System.out.println(" " + formats[k] + ", "+ formats[k].getFrameSize()+" bytes/frame"); + if (isSDL) { + if ((formats[k].getSampleRate()==AudioSystem.NOT_SPECIFIED) + || (formats[k].getSampleRate()==32000.0f)) { + ok32=true; + } + if ((formats[k].getSampleRate()==AudioSystem.NOT_SPECIFIED) + || (formats[k].getSampleRate()==16000.0f)) { + ok16=true; + } + } + } + } catch (ClassCastException e) { + } + } + } + + public static void main(String[] args) throws Exception { + boolean res=true; + + Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo(); + System.out.println(mixerInfo.length+" mixers on system."); + if (mixerInfo.length == 0) { + System.out.println("Cannot execute test. Not Failed!"); + } else { + for (int i = 0; i < mixerInfo.length; i++) { + Mixer mixer = AudioSystem.getMixer(mixerInfo[i]); + System.out.println(); + System.out.println(mixer+":"); + showMixerLines(mixer.getSourceLineInfo()); + showMixerLines(mixer.getTargetLineInfo()); + + + } + res=ok16 && ok32; + } + if (res) { + System.out.println("Test passed"); + } else { + System.out.println("Test failed"); + throw new Exception("Test failed"); + } + //ystem.exit(res?0:1); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Lines/BufferSizeCheck.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Lines/BufferSizeCheck.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; + +/** + * @test + * @bug 4661602 + * @summary Buffersize is checked when re-opening line + */ +public class BufferSizeCheck { + + public static void main(String[] args) throws Exception { + boolean realTest = false; + if (!isSoundcardInstalled()) { + return; + } + + try { + out("4661602: Buffersize is checked when re-opening line"); + AudioFormat format = new AudioFormat(44100, 16, 2, true, false); + DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); + SourceDataLine sdl = (SourceDataLine) AudioSystem.getLine(info); + out("Opening with buffersize 12000..."); + sdl.open(format, 12000); + out("Opening with buffersize 11000..."); + realTest=true; + sdl.open(format, 11000); + try { + sdl.close(); + } catch(Throwable t) {} + } catch (Exception e) { + e.printStackTrace(); + // do not fail if no audio device installed - bug 4742021 + if (realTest || !(e instanceof LineUnavailableException)) { + throw e; + } + } + out("Test passed"); + } + + static void out(String s) { + System.out.println(s); System.out.flush(); + } + + /** + * Returns true if at least one soundcard is correctly installed + * on the system. + */ + public static boolean isSoundcardInstalled() { + boolean result = false; + try { + Mixer.Info[] mixers = AudioSystem.getMixerInfo(); + if (mixers.length > 0) { + result = AudioSystem.getSourceDataLine(null) != null; + } + } catch (Exception e) { + System.err.println("Exception occured: "+e); + } + if (!result) { + System.err.println("Soundcard does not exist or sound drivers not installed!"); + System.err.println("This test requires sound drivers for execution."); + } + return result; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Lines/ChangingBuffer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Lines/ChangingBuffer.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; + +/** + * @test + * @bug 4515126 + * @summary Verify that the buffer passed to SourceDataLine.write() and + * Clip.open() will not be changed + */ +public class ChangingBuffer { + + final static int samplerate = 44100; + final static byte[] buffer = new byte[16384]; + static int successfulTests = 0; + + private static void makeBuffer() { + for (int i=0; i passed for this line"); + System.out.println(""); + } + + private static void checkBufferClip() throws Exception { + for (int i=0; i passed for this clip"); + System.out.println(""); + } + + private static boolean doMixerClip(Mixer mixer, AudioFormat format) { + if (mixer==null) return false; + try { + System.out.println("Trying mixer "+mixer+":"); + DataLine.Info info = new DataLine.Info( + Clip.class, + format, + (int) samplerate); + + Clip clip = (Clip) mixer.getLine(info); + System.out.println(" - got clip: "+clip); + System.out.println(" - open with format "+format); + clip.open(format, buffer, 0, buffer.length); + System.out.println(" - playing..."); + clip.start(); + System.out.println(" - waiting while it's active..."); + while (clip.isActive()) + Thread.sleep(100); + System.out.println(" - waiting 100millis"); + Thread.sleep(100); + System.out.println(" - drain1"); + clip.drain(); + System.out.println(" - drain2"); + clip.drain(); + System.out.println(" - stop"); + clip.stop(); + System.out.println(" - close"); + clip.close(); + System.out.println(" - closed"); + } catch (Throwable t) { + System.out.println(" - Caught exception. Not failed."); + System.out.println(" - "+t.toString()); + return false; + } + return true; + } + + private static boolean doMixerSDL(Mixer mixer, AudioFormat format) { + if (mixer==null) return false; + try { + System.out.println("Trying mixer "+mixer+":"); + DataLine.Info info = new DataLine.Info( + SourceDataLine.class, + format, + (int) samplerate); + + SourceDataLine sdl = (SourceDataLine) mixer.getLine(info); + System.out.println(" - got sdl: "+sdl); + System.out.println(" - open with format "+format); + sdl.open(format); + System.out.println(" - start..."); + sdl.start(); + System.out.println(" - write..."); + sdl.write(buffer, 0, buffer.length); + Thread.sleep(200); + System.out.println(" - drain..."); + sdl.drain(); + System.out.println(" - stop..."); + sdl.stop(); + System.out.println(" - close..."); + sdl.close(); + System.out.println(" - closed"); + } catch (Throwable t) { + System.out.println(" - Caught exception. Not failed."); + System.out.println(" - "+t.toString()); + return false; + } + return true; + } + + private static void doAll(boolean bigEndian) throws Exception { + AudioFormat pcm = new AudioFormat( + AudioFormat.Encoding.PCM_SIGNED, + samplerate, 16, 1, 2, samplerate, bigEndian); + Mixer.Info[] mixers = AudioSystem.getMixerInfo(); + for (int i=0; i 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + //else just print + else + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn ) + { + messageText.append( messageIn + "\n" ); + } + + //catch presses of the passed and failed buttons. + //simply call the standard pass() or fail() static methods of + //DialogOrient + public void actionPerformed( ActionEvent e ) + { + if( e.getActionCommand() == "pass" ) + { + Test4218609.pass(); + } + else + { + Test4218609.fail(); + } + } + + }// TestDialog class diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Lines/ClipOpenException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Lines/ClipOpenException.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.Line; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; +import javax.sound.sampled.TargetDataLine; + +/** + * @test + * @bug 4679187 + * @summary Clip.open() throws unexpected Exceptions. verifies that clip, + * sourcedataline and targetdataline throw IllegalArgumentExcepotion if + * any field in the format is AudioFormat.NOT_SPECIFIED + */ +public class ClipOpenException { + static boolean failed = false; + + static byte[] audioData = new byte[2048]; + static AudioFormat[] formats = { + new AudioFormat(AudioSystem.NOT_SPECIFIED, + AudioSystem.NOT_SPECIFIED, + AudioSystem.NOT_SPECIFIED, + true, false), + new AudioFormat(0, 0, 0, true, false) + }; + static AudioFormat infoFormat = new AudioFormat(44100.0f, + 16, + 1, + true, false); + static DataLine.Info clipInfo = new DataLine.Info(Clip.class, infoFormat); + static DataLine.Info sdlInfo = new DataLine.Info(SourceDataLine.class, infoFormat); + static DataLine.Info tdlInfo = new DataLine.Info(TargetDataLine.class, infoFormat); + + + public static void print(String s) { + System.out.print(s); + } + public static void println(String s) { + System.out.println(s); + } + + public static void test(Line line) { + for (int format = 0; format < formats.length; format++) { + try { + println(" Opening the line with format "+(format+1)); + if (line instanceof Clip) { + ((Clip) line).open(formats[format], audioData, 0, audioData.length); + } else + if (line instanceof SourceDataLine) { + ((SourceDataLine) line).open(formats[format]); + } else + if (line instanceof TargetDataLine) { + ((TargetDataLine) line).open(formats[format]); + } else { + println(" Unknown type of line: "+line.getClass()); + return; + } + println(" No exception! not OK."); + failed = true; + } catch (IllegalArgumentException iae) { + println(" IllegalArgumentException: "+iae.getMessage()); + println(" OK"); + } catch (LineUnavailableException lue) { + println(" LineUnavailableException: "+lue.getMessage()); + println(" Probably incorrect, but may happen if the test system is correctly set up."); + } catch (Exception e) { + println(" Unexpected Exception: "+e.toString()); + println(" NOT OK!"); + failed = true; + } + println(" Closing line."); + line.close(); + } + } + + public static void main(String[] args) throws Exception { + Mixer.Info[] mixers = AudioSystem.getMixerInfo(); + int succMixers = 0; + println("Using formats: "); + for (int i = 0 ; i Test for SourceDataLine.write() method for not open and not started line:"); + + Mixer.Info[] installedMixersInfo = AudioSystem.getMixerInfo(); + + if ( installedMixersInfo == null ) { + out.println("## AudioSystem.getMixerInfo() returned unexpected result:"); + out.println("# expected: an array of Mixer.Info objects (may be array of length 0);"); + out.println("# produced: null;"); + return STATUS_FAILED; + } + + if ( installedMixersInfo.length == 0 ) { + // there are no mixers installed on the system - so this testcase can not be tested + return STATUS_PASSED; + } + + Mixer testedMixer = null; + for (int i=0; i < installedMixersInfo.length; i++) { + try { + testedMixer = AudioSystem.getMixer(installedMixersInfo[i]); + } catch (SecurityException securityException) { + // installed Mixer is unavailable because of security restrictions + continue; + } catch (Throwable thrown) { + out.println("## AudioSystem.getMixer() threw unexpected exception:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + continue; + } + + try { + testedMixer.open(); + } catch (LineUnavailableException lineUnavailableException) { + // testedMixer is not available due to resource restrictions + continue; + } catch (SecurityException securityException) { + // testedMixer is not available due to security restrictions + continue; + } catch (Throwable thrown) { + out.println("## Mixer.open() threw unexpected exception:"); + out.println("# Mixer = " + testedMixer); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + continue; + } + Line.Info supportedSourceLineInfo[] = null; + try { + supportedSourceLineInfo = testedMixer.getSourceLineInfo(); + } catch (Throwable thrown) { + out.println("## Mixer.getSourceLineInfo() threw unexpected exception:"); + out.println("# Mixer = " + testedMixer); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + testedMixer.close(); + continue; + } + if ( supportedSourceLineInfo == null ) { + out.println("## Mixer.getSourceLineInfo() returned null array"); + out.println("# Mixer = " + testedMixer); + testResult = STATUS_FAILED; + testedMixer.close(); + continue; + } + out.println("\n>>> testedMixer["+i+"] = " + testedMixer); + out.println("\n>> supportedSourceLineInfo.length = " + supportedSourceLineInfo.length); + + for (int j=0; j < supportedSourceLineInfo.length; j++) { + Line.Info testSourceLineInfo = supportedSourceLineInfo[j]; + + Line testSourceLine = null; + try { + testSourceLine = testedMixer.getLine(testSourceLineInfo); + } catch (LineUnavailableException lineUnavailableException) { + // line is not available due to resource restrictions + continue; + } catch (SecurityException securityException) { + // line is not available due to security restrictions + continue; + } catch (Throwable thrown) { + out.println("## Mixer.getLine(Line.Info) threw unexpected Exception:"); + out.println("# Mixer = " + testedMixer); + out.println("# Line.Info = " + testSourceLineInfo); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + continue; + } + + out.println("\n> testSourceLineInfo["+j+"] = " + testSourceLineInfo); + out.println("> testSourceLine = " + testSourceLine); + if ( ! (testSourceLine instanceof SourceDataLine) ) { + out.println("> testSourceLine is not SourceDataLine"); + continue; + } + + SourceDataLine testedSourceLine = (SourceDataLine)testSourceLine; + AudioFormat lineAudioFormat = testedSourceLine.getFormat(); + + int bufferSizeToWrite = 1; + if ( lineAudioFormat.getSampleSizeInBits() != AudioSystem.NOT_SPECIFIED ) { + bufferSizeToWrite = lineAudioFormat.getSampleSizeInBits()/8; + if ( lineAudioFormat.getSampleSizeInBits()%8 != 0 ) { + bufferSizeToWrite++; + } + } + if ( lineAudioFormat.getFrameSize() != AudioSystem.NOT_SPECIFIED ) { + bufferSizeToWrite = lineAudioFormat.getFrameSize(); + } + byte[] dataToWrite = new byte[bufferSizeToWrite]; + for (int k=0; k < bufferSizeToWrite; k++) { + dataToWrite[k] = (byte)1; + } + int offsetToWrite = 0; + + out.println + ("\n> check SourceDataLine.write() for not open line with correct length of data:"); + int writtenBytes = -1; + try { + writtenBytes = testedSourceLine.write(dataToWrite, offsetToWrite, bufferSizeToWrite); + out.println("> Bytes written: number of written bytes = " + writtenBytes); + } catch (Throwable thrown) { + out.println("## SourceDataLine.write(byte[] b, int off, int len) failed:"); + out.println("# Unexpected Exception is thrown"); + out.println("# Mixer = " + testedMixer); + out.println("# SourceDataLine = " + testedSourceLine); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + + out.println + ("\n> check SourceDataLine.write() for not open line with incorrect length of data:"); + writtenBytes = -1; + bufferSizeToWrite--; + try { + writtenBytes = testedSourceLine.write(dataToWrite, offsetToWrite, bufferSizeToWrite); + out.println("> Bytes written: number of written bytes = " + writtenBytes); + } catch (IllegalArgumentException illegalArgumentException) { + out.println("> Permissible IllegalArgumentException for the present instance is thrown:"); + illegalArgumentException.printStackTrace(out); + } catch (Throwable thrown) { + out.println("## SourceDataLine.write(byte[] b, int off, int len) failed:"); + out.println("# Unexpected Exception is thrown"); + out.println("# Mixer = " + testedMixer); + out.println("# SourceDataLine = " + testedSourceLine); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + + out.println + ("\n> open tested line:"); + bufferSizeToWrite++; + try { + testedSourceLine.open(lineAudioFormat, bufferSizeToWrite); + out.println("> OK - line is opened"); + } catch (LineUnavailableException lineUnavailableException) { + out.println("> Line is not available due to resource restrictions:"); + lineUnavailableException.printStackTrace(out); + continue; + } catch (SecurityException securityException) { + out.println("> Line is not available due to security restrictions:"); + securityException.printStackTrace(out); + continue; + } catch (Throwable thrown) { + out.println("## SourceDataLine.open(AudioFormat format) failed:"); + out.println("# Unexpected Exception is thrown"); + out.println("# Mixer = " + testedMixer); + out.println("# SourceDataLine = " + testedSourceLine); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + continue; + } + + out.println + ("\n> check SourceDataLine.write() for not started line with correct length of data:"); + writtenBytes = -1; + try { + writtenBytes = testedSourceLine.write(dataToWrite, offsetToWrite, bufferSizeToWrite); + out.println("> Bytes written: number of written bytes = " + writtenBytes); + } catch (Throwable thrown) { + out.println("## SourceDataLine.write(byte[] b, int off, int len) failed:"); + out.println("# Unexpected Exception is thrown"); + out.println("# Mixer = " + testedMixer); + out.println("# SourceDataLine = " + testedSourceLine); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + + out.println + ("\n> check SourceDataLine.write() for not started line with incorrect length of data:"); + writtenBytes = -1; + bufferSizeToWrite--; + try { + writtenBytes = testedSourceLine.write(dataToWrite, offsetToWrite, bufferSizeToWrite); + out.println("> Bytes written: number of written bytes = " + writtenBytes); + } catch (IllegalArgumentException illegalArgumentException) { + out.println("> Permissible IllegalArgumentException for the present instance is thrown:"); + illegalArgumentException.printStackTrace(out); + } catch (Throwable thrown) { + out.println("## SourceDataLine.write(byte[] b, int off, int len) failed:"); + out.println("# Unexpected Exception is thrown"); + out.println("# Mixer = " + testedMixer); + out.println("# SourceDataLine = " + testedSourceLine); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + testedSourceLine.close(); + + } // for (int j=0; j < supportedSourceLineInfo.length; j++) + testedMixer.close(); + + } // for (int i=0; i < installedMixersInfo.length; i++) + + if ( testResult == STATUS_FAILED ) { + out.println("\n==> test FAILED!"); + } else { + out.println("\n==> test PASSED!"); + } + return testResult; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Lines/SourceDataLineDefaultBufferSizeCrash.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Lines/SourceDataLineDefaultBufferSizeCrash.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Line; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; + +/** + * @test + * @bug 4681384 + * @summary SourceDataLine.write() causes Unexpected Signal 11 in native code + * outside the VM + */ +public class SourceDataLineDefaultBufferSizeCrash { + + static final int STATUS_PASSED = 0; + static final int STATUS_FAILED = 2; + static final int STATUS_TEMP = 95; + + public static void main(String argv[]) throws Exception { + int testExitStatus = run(argv, System.out) + STATUS_TEMP; + } + + public static int run(String argv[], java.io.PrintStream out) throws Exception { + int testResult = STATUS_PASSED; + + int framesNumberToExceed = 2; + if ( argv.length > 0 ) { + try { + framesNumberToExceed = Integer.parseInt(argv[0]); + } + catch (NumberFormatException e) { + } + } + + out.println + ("\n==> Test for SourceDataLine.write() method:"); + + Mixer.Info[] installedMixersInfo = AudioSystem.getMixerInfo(); + + if ( installedMixersInfo == null ) { + out.println("## AudioSystem.getMixerInfo() returned unexpected result:"); + out.println("# expected: an array of Mixer.Info objects (may be array of length 0);"); + out.println("# produced: null;"); + return STATUS_FAILED; + } + + if ( installedMixersInfo.length == 0 ) { + // there are no mixers installed on the system - + // so this testcase can not be tested + out.println("\n>>> There are no mixers installed on the system!"); + return STATUS_PASSED; + } + + out.println("\n>>> Number of mixers installed on the system = " + + installedMixersInfo.length); + Mixer installedMixer = null; + for (int i=0; i < installedMixersInfo.length; i++) { + try { + installedMixer = AudioSystem.getMixer(installedMixersInfo[i]); + } catch (SecurityException securityException) { + // installed Mixer is unavailable because of security restrictions + out.println("\n>>> installedMixer[" + i + + "] is unavailable because of security restrictions"); + continue; + } catch (Throwable thrown) { + out.println("\n## installedMixer[" + i + "] is unavailable because of"); + out.println("# AudioSystem.getMixer() threw unexpected exception:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + continue; + } + + out.println("\n>>> installedMixer["+i+"] = " + installedMixer); + try { + installedMixer.open(); + } catch (LineUnavailableException lineUnavailableException) { + // installedMixer is not available due to resource restrictions + out.println(">> installedMixer[" + i + + "] is not opened because of resource restrictions"); + continue; + } catch (SecurityException securityException) { + // installedMixer is not available due to security restrictions + out.println(">> installedMixer[" + i + + "] is not opened because of security restrictions"); + continue; + } catch (Throwable thrown) { + out.println("## installedMixer.open() throws unexpected exception:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + continue; + } + Line.Info supportedSourceLineInfo[] = null; + try { + supportedSourceLineInfo = installedMixer.getSourceLineInfo(); + } catch (Throwable thrown) { + out.println("## installedMixer.getSourceLineInfo() throws " + + "unexpected exception:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + installedMixer.close(); + continue; + } + if ( supportedSourceLineInfo == null ) { + out.println("## installedMixer.getSourceLineInfo() returned null array"); + out.println("# Mixer = " + installedMixer); + testResult = STATUS_FAILED; + installedMixer.close(); + continue; + } + out.println("\n>> Number of SourceLineInfo supported by installedMixer =" + + supportedSourceLineInfo.length); + + for (int j=0; j < supportedSourceLineInfo.length; j++) { + Line.Info testSourceLineInfo = supportedSourceLineInfo[j]; + + out.println("\n> testSourceLineInfo["+j+"] = " + testSourceLineInfo); + Line testSourceLine = null; + try { + testSourceLine = installedMixer.getLine(testSourceLineInfo); + } catch (LineUnavailableException lineUnavailableException) { + // line is not available due to resource restrictions + out.println("> Line for this SourceLine Info is not available " + + "due to resource restrictions"); + continue; + } catch (SecurityException securityException) { + // line is not available due to security restrictions + out.println("> Line for this SourceLine Info is not available " + + "due to security restrictions"); + continue; + } catch (Throwable thrown) { + out.println("## installedMixer.getLine(testSourceLineInfo) throws" + + "unexpected Exception:"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + continue; + } + + out.println("> testedSourceLine = " + testSourceLine); + if ( ! (testSourceLine instanceof SourceDataLine) ) { + out.println("> testSourceLine is not SourceDataLine"); + continue; + } + + SourceDataLine testedSourceLine = (SourceDataLine)testSourceLine; + AudioFormat lineAudioFormat = testedSourceLine.getFormat(); + + out.println("\n> opening tested SourceLine:"); + try { + //testedSourceLine.open(lineAudioFormat, 2048); + testedSourceLine.open(lineAudioFormat); + out.println("> OK - line is opened with "+testedSourceLine.getBufferSize()+" bytes buffer"); + } catch (LineUnavailableException lineUnavailableException) { + out.println("> Line is not available due to resource restrictions:"); + lineUnavailableException.printStackTrace(out); + continue; + } catch (SecurityException securityException) { + out.println("> Line is not available due to security restrictions:"); + securityException.printStackTrace(out); + continue; + } catch (Throwable thrown) { + out.println("## SourceDataLine.open(AudioFormat format) failed:"); + out.println("# Unexpected Exception is thrown"); + out.println("# Mixer = " + installedMixer); + out.println("# SourceDataLine = " + testedSourceLine); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + continue; + } + + testedSourceLine.start(); + + int frameSize = 1; + if ( lineAudioFormat.getFrameSize() != AudioSystem.NOT_SPECIFIED ) { + frameSize = lineAudioFormat.getFrameSize(); + } else { + if ( lineAudioFormat.getSampleSizeInBits() != AudioSystem.NOT_SPECIFIED ) { + frameSize = lineAudioFormat.getSampleSizeInBits()/8; + if ( lineAudioFormat.getSampleSizeInBits()%8 != 0 ) { + frameSize++; + } + } + } + int bufferSizeToWrite = testedSourceLine.available() + + (frameSize * framesNumberToExceed); + byte[] dataToWrite = new byte[bufferSizeToWrite]; + for (int k=0; k < bufferSizeToWrite; k++) { + dataToWrite[k] = (byte)1; + } + int offsetToWrite = 0; + + out.println("\n> check SourceDataLine.write() to write more data " + + "than can currently be written:"); + + out.println("> testedSourceLine.available() = " + testedSourceLine.available()); + out.println("> frame size = " + frameSize); + out.println("> number of bytes to write = " + bufferSizeToWrite); + int writtenBytes = -1; + try { + writtenBytes = + testedSourceLine.write(dataToWrite, offsetToWrite, bufferSizeToWrite); + out.println("> OK - number of written bytes = " + writtenBytes); + } catch (Throwable thrown) { + out.println("## SourceDataLine.write(byte[] b, int off, int len) failed:"); + out.println("# Unexpected Exception is thrown"); + thrown.printStackTrace(out); + testResult = STATUS_FAILED; + } + + testedSourceLine.close(); + + } // for (int j=0; j < supportedSourceLineInfo.length; j++) + installedMixer.close(); + + } // for (int i=0; i < installedMixersInfo.length; i++) + + if ( testResult == STATUS_FAILED ) { + throw new Exception("Test FAILED!"); + } else { + out.println("\n==> test PASSED!"); + } + return testResult; + } + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Lines/StopStart.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Lines/StopStart.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.util.Random; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; + +/** + * @test + * @bug 4828556 + * @summary stopping and starting sampled audio plays small chunk in infinite + * loop + */ +public class StopStart implements Runnable { + + static int sampleRate = 8000; + static double frequency = 2000.0; + static double RAD = 2.0 * Math.PI; + static Random random = new Random(); + + static byte[] audioData = new byte[sampleRate/2]; + static SourceDataLine source; + + static boolean terminated = false; + + static int buffersWritten = 0; + static long bytesWritten = 0; + static int buffersWrittenAfter5Seconds; + + static AudioInputStream ais = null; + static AudioFormat audioFormat; + static String filename; + + static int executedTests=0; + static int successfulTests = 0; + + public static void constructAIS() throws Exception { + ais = AudioSystem.getAudioInputStream(new File(filename)); + } + + public static void doStartStopTest1() throws Exception { + System.out.println("TEST 1: play for 3 seconds, stop/start/stop/start/play for 3 seconds..."); + source.start(); + Thread.sleep(100); + bytesWritten = 0; + System.out.println("Waiting for 3 seconds..."); + Thread.sleep(3000); + buffersWrittenAfter5Seconds = buffersWritten; + System.out.println("Buffers Written: "+buffersWritten); + System.out.println("stop()->start()->stop()->start()"); + source.stop(); + //System.out.println("start()"); + source.start(); + //System.out.println("stop()2 ----------------------------------------------------------"); + source.stop(); + //System.out.println("start()"); + source.start(); + System.out.println("Buffers Written: "+buffersWritten); + System.out.println("Waiting for 3 seconds..."); + Thread.sleep(3000); + System.out.println("Buffers Written: "+buffersWritten); + if (buffersWritten >= ((buffersWrittenAfter5Seconds * 2) - ((buffersWrittenAfter5Seconds / 4)))) { + successfulTests++; + } + } + + private static int nextWaitTime() { + int waitTime = random.nextInt(25); + waitTime*=waitTime; + if (waitTime<20) waitTime = 0; + return waitTime; + } + + + public static void doStartStopTest2() throws Exception { + System.out.println("TEST 2: start and stop 100 times with random wait in between"); + int max=100; + for (int i=0; i0) { + Thread.sleep(waitTime); + } + System.out.println("stop()"); + source.stop(); + waitTime = nextWaitTime(); + System.out.println("Waiting for "+waitTime+"ms..."); + if (waitTime>0) { + Thread.sleep(waitTime); + } + } + } + + public static void doStartStopTest3() throws Exception { + System.out.println("TEST 3: start and stop 100 times with random wait only every 10 rounds "); + int max=100; + for (int i=0; i0) { + Thread.sleep(waitTime); + } + } + System.out.println("stop()"); + source.stop(); + if (i % 13 == 12) { + int waitTime = nextWaitTime(); + System.out.println("Waiting for "+waitTime+"ms..."); + if (waitTime>0) { + Thread.sleep(waitTime); + } + } + } + } + + public static void runTest(int testNum) { + terminated = false; + Thread thread = null; + buffersWrittenAfter5Seconds = 0; + // make the tests reproduceable by always seeding with same value + random.setSeed(1); + try { + executedTests++; + thread = new Thread(new StopStart()); + thread.start(); + switch (testNum) { + case 1: doStartStopTest1(); break; + case 2: doStartStopTest2(); break; + case 3: doStartStopTest3(); break; + } + } catch (Exception e) { + e.printStackTrace(); + } + source.stop(); + source.close(); + if (thread!=null) { + terminated = true; + System.out.println("Waiting for thread to die..."); + try { + thread.join(); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + } + } + + public static void main(String[] args) throws Exception { + filename = null; + if (args.length>0) { + File f = new File(args[0]); + if (f.exists()) { + filename = args[0]; + System.out.println("Opening "+filename); + constructAIS(); + audioFormat = ais.getFormat(); + } + } + if (filename == null) { + audioFormat = new AudioFormat((float)sampleRate, 8, 1, true, true); + for (int i=0; i0) { + if (successfulTests == 0) { + if (args.length == 0) { + throw new Exception("Test FAILED"); + } + System.out.println("test FAILED."); + } else { + System.out.println("test successful."); + } + } else { + System.out.println("Could not execute any tests - are soundcards correctly installed?"); + System.out.println("Test NOT FAILED."); + } + } + + public void run() { + int len = audioData.length; + int offset = len; + System.out.println("Thread: started. Beginning audio i/o"); + while (!terminated) { + try { + //if (!source.isActive()) { + // Thread.sleep(50); + //} + if (offset >= len) { + offset = 0; + if (ais!=null) { + do { + len = ais.read(audioData, 0, audioData.length); + if (len < 0) { + constructAIS(); + } + } while (len < 0); + } + } + int toWrite = len - offset; + int written = source.write(audioData, offset, toWrite); + offset+=written; + bytesWritten += written; + buffersWritten = (int) (bytesWritten / audioData.length); + } catch (Exception e) { + e.printStackTrace(); + terminated = true; + } + } + System.out.println("Thread: closing line"); + source.stop(); + source.close(); + System.out.println("Thread finished"); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/LinuxBlock/PlaySine.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/LinuxBlock/PlaySine.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.io.IOException; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; + +/** + * @test + * @bug 4834461 + * @summary Applet hang when you load it during sound card is in use + * @run main/manual PlaySine + */ +public class PlaySine { + + static int sampleRate = 8000; + static double frequency = 2000.0; + static double RAD = 2.0 * Math.PI; + + static byte[] audioData = new byte[sampleRate/2]; + static SourceDataLine source; + static Mixer mixer = null; + + static AudioInputStream ais = null; + static AudioFormat audioFormat; + static String filename; + + public static void constructAIS() { + try { + ais = AudioSystem.getAudioInputStream(new File(filename)); + } catch (Exception e) { + println("ERROR: could not open "+filename+": "+e.getMessage()); + } + } + + public static void print(String s) { + System.out.print(s); + } + public static void println(String s) { + System.out.println(s); + } + + public static void key() { + println(""); + print("Press ENTER to continue..."); + try { + System.in.read(); + } catch (IOException ioe) { + } + } + + static int audioLen = -1; + static int audioOffset = -1; + + public static void writeData() { + if (audioLen == -1) { + audioLen = audioData.length; + } + if (audioOffset < 0) { + audioOffset = audioLen; + } + try { + if (audioOffset >= audioLen) { + audioOffset = 0; + if (ais!=null) { + do { + audioLen = ais.read(audioData, 0, audioData.length); + if (audioLen < 0) { + constructAIS(); + } + } while (audioLen < 0); + } + } + int toWrite = audioLen - audioOffset; + int written = source.write(audioData, audioOffset, toWrite); + audioOffset+=written; + } catch (Exception e) { + e.printStackTrace(); + } + } + + + public static int play(boolean shouldPlay) { + int res = 0; + DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat); + try { + println("Getting line from mixer..."); + source = (SourceDataLine) mixer.getLine(info); + println("Opening line..."); + println(" -- if the program is hanging here, kill the process that has blocks the audio device now."); + source.open(audioFormat); + println("Starting line..."); + source.start(); + println("Writing audio data for 1 second..."); + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < 1000) { + writeData(); + Thread.sleep(100); + } + res = 1; + } catch (IllegalArgumentException iae) { + println("IllegalArgumentException: "+iae.getMessage()); + println("Sound device cannot handle this audio format."); + println("ERROR: Test environment not correctly set up."); + if (source!=null) { + source.close(); + } + return 3; + } catch (LineUnavailableException lue) { + println("LineUnavailableException: "+lue.getMessage()); + if (shouldPlay) { + println("ERROR: the line should be available now!."); + println(" Verify that you killed the other audio process."); + } else { + println("Correct behavior! the bug is fixed."); + } + res = 2; + } catch (Exception e) { + println("Unexpected Exception: "+e.toString()); + } + if (source != null) { + println("Draining..."); + try { + source.drain(); + } catch (NullPointerException npe) { + println("(NullPointerException: bug fixed in J2SE 1.4.2"); + } + println("Stopping..."); + source.stop(); + println("Closing..."); + source.close(); + source = null; + } + return res; + } + + public static void main(String[] args) throws Exception { + println("This is an interactive test. You can run it with a filename as argument"); + println("It is only meant to be run on linux, with the (old) OSS kernel drivers (/dev/dsp)"); + println("This test should not be run on systems with ALSA installed, or kernel 2.6 or higher."); + println(""); + println("The test verifies that Java Sound fails correctly if another process is blocking"); + println("the audio device."); + println(""); + println("Checking sanity..."); + Mixer.Info[] mixers=null; + + mixers = AudioSystem.getMixerInfo(); + for (int i=0; i=0 + && mixerName.indexOf("Engine")>=0) { + mixer = thisMixer; + break; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + if (mixer == null) { + if (mixers.length==0) { + System.out.println("ERROR: No mixers available!"); + } else { + println("ERROR: Java Sound Engine could not be found."); + } + println("Cannot run this test."); + return; + } + println(" ...using mixer "+mixer.getMixerInfo()); + + String osname = System.getProperty("os.name"); + if ((osname == null) || (osname.toLowerCase().indexOf("linux")<0)) { + println("ERROR: not running on linux (you are running on "+osname+")"); + return; + } + println(" ...running on "+osname); + println(" ...sanity test OK."); + + filename = null; + if (args.length>0) { + File f = new File(args[0]); + if (f.exists()) { + filename = args[0]; + println("Opening "+filename); + constructAIS(); + if (ais!=null) { + audioFormat = ais.getFormat(); + } + } + } + if (ais == null) { + println("Using self-generated sine wave for playback"); + audioFormat = new AudioFormat((float)sampleRate, 8, 1, true, true); + for (int i=0; i /dev/dsp"); + key(); + println("After you press ENTER now, the mixer will be opened."); + println("There are 3 possible cases that can occur:"); + println("1) you'll hear a sine wave"); + println(" -> you are running with mixing OSS drivers. "); + println(" Some soundcards only provide mixing OSS drivers."); + println(" Test environment not valid. "); + println(" Repeat on another machine where you can reproduce the bug first."); + println("2) this program stops doing anything after 'Opening line...'"); + println(" -> this is the bug."); + println(" Kill the command on the other console with Ctrl-C, this program"); + println(" should continue working then."); + println("3) this program reports a LineUnavailableException"); + println(" -> bug is fixed."); + println(" OR you run with non-blocking OSS drivers."); + println(" make sure that you can reproduce this bug first with e.g. J2SE 1.4.1"); + key(); + int playedFirst = play(false); + int playedSecond = 0; + + if (playedFirst == 2) { + println(""); + println("Now kill the other process with Ctrl-C."); + println("After that, this program should be able to play "); + println("the sine wave without problems."); + key(); + playedSecond = play(true); + } + println(""); + if (playedFirst == 1) { + println("Test FAILED."); + } + else if (playedFirst == 2 && playedSecond == 1) { + println("Test SUCCESSFUL"); + } else { + println("Test not failed (but not successful either...)."); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/LinuxCrash/ClipLinuxCrash.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/LinuxCrash/ClipLinuxCrash.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineEvent; +import javax.sound.sampled.LineListener; + +/** + * @test + * @bug 4498848 + * @summary Sound causes crashes on Linux (part 1) + */ +public class ClipLinuxCrash { + + static Clip clip; + + public static long bytes2Ms(long bytes, AudioFormat format) { + return (long) (bytes / format.getFrameRate() * 1000 + / format.getFrameSize()); + } + + static int staticLen = 1000; + + static boolean addLen = true; + + public static long start() throws Exception { + AudioFormat fmt = new AudioFormat(44100, 16, 2, true, false); + if (addLen) { + staticLen += (int) (staticLen / 5) + 1000; + } else { + staticLen -= (int) (staticLen / 5) + 1000; + } + if (staticLen > 8 * 44100 * 4) { + staticLen = 8 * 44100 * 4; + addLen = !addLen; + } + if (staticLen < 1000) { + staticLen = 1000; + addLen = !addLen; + } + int len = staticLen; + len -= (len % 4); + byte[] fakedata = new byte[len]; + InputStream is = new ByteArrayInputStream(fakedata); + AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, + 44100, 16, 2, 4, 44100, false); + AudioInputStream ais = new AudioInputStream(is, format, fakedata.length + / format.getFrameSize()); + + out(" preparing to play back " + len + " bytes == " + bytes2Ms(len, + format) + + "ms audio..."); + + DataLine.Info info = new DataLine.Info(Clip.class, ais.getFormat()); + clip = (Clip) AudioSystem.getLine(info); + clip.addLineListener(new LineListener() { + public void update(LineEvent e) { + if (e.getType() == LineEvent.Type.STOP) { + out(" calling close() from event dispatcher thread"); + ((Clip) e.getSource()).close(); + } else if (e.getType() == LineEvent.Type.CLOSE) { + } + } + }); + + out(" opening..."); + try { + clip.open(ais); + } catch (Throwable t) { + t.printStackTrace(); + clip.close(); + clip = null; + } + ais.close(); + if (clip != null) { + out(" starting..."); + clip.start(); + } + return bytes2Ms(fakedata.length, format); + } + + public static void main(String[] args) throws Exception { + if (AudioSystem.getMixerInfo().length == 0) { + System.out.println("Cannot execute test: no mixers installed!"); + System.out.println("Not Failed."); + return; + } + try { + int COUNT = 10; + out(); + out("4498848 Sound causes crashes on Linux (testing with Clip)"); + if (args.length > 0) { + COUNT = Integer.parseInt(args[0]); + } + for (int i = 0; i < COUNT; i++) { + out(" trial " + (i + 1) + "/" + COUNT); + start(); + int waitTime = 500 + (1000 * (i + % 2)); // every second + // time wait 1500, rather than 500ms. + out(" waiting for " + waitTime + + " ms for audio playback to stop..."); + Thread.sleep(waitTime); + out(" calling close() from main thread"); + if (clip != null) { + clip.close(); + } + // let the subsystem enough time to actually close the soundcard + out(" waiting for 2 seconds..."); + Thread.sleep(2000); + out(); + } + out(" waiting for 1 second..."); + Thread.sleep(1000); + } catch (Exception e) { + e.printStackTrace(); + out(" waiting for 1 second"); + try { + Thread.sleep(1000); + } catch (InterruptedException ie) { + } + throw e; + } + out("Test passed"); + } + + static void out() { + out(""); + } + + static void out(String s) { + System.out.println(s); + System.out.flush(); + } + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/LinuxCrash/ClipLinuxCrash2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/LinuxCrash/ClipLinuxCrash2.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineEvent; +import javax.sound.sampled.LineListener; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; + +/** + * @test + * @bug 4498848 + * @summary Sound causes crashes on Linux (part 3) + */ +public class ClipLinuxCrash2 implements LineListener{ + Clip clip; + int stopOccured; + static final Object lock = new Object(); + + public static long bytes2Ms(long bytes, AudioFormat format) { + return (long) (bytes/format.getFrameRate()*1000/format.getFrameSize()); + } + + static int staticLen=1000; + static boolean addLen=true; + + ClipLinuxCrash2() { + } + + public void update(LineEvent e) { + if (e.getType() == LineEvent.Type.STOP) { + stopOccured++; + out(" Test program: receives STOP event for clip="+clip.toString()+" no."+stopOccured); + out(" Test program: Calling close() in event dispatcher thread"); + clip.close(); + synchronized (lock) { + lock.notifyAll(); + } + } + else if (e.getType() == LineEvent.Type.CLOSE) { + out(" Test program: receives CLOSE event for "+clip.toString()); + synchronized (lock) { + lock.notifyAll(); + } + } + else if (e.getType() == LineEvent.Type.START) { + out(" Test program: receives START event for "+clip.toString()); + } + else if (e.getType() == LineEvent.Type.OPEN) { + out(" Test program: receives OPEN event for "+clip.toString()); + } + } + + public long start() throws Exception { + AudioFormat format = new AudioFormat(44100, 16, 2, true, false); + + if (addLen) { + staticLen+=(int) (staticLen/5)+1000; + } else { + staticLen-=(int) (staticLen/5)+1000; + } + if (staticLen>8*44100*4) { + staticLen = 8*44100*4; + addLen=!addLen; + } + if (staticLen<1000) { + staticLen = 1000; + addLen=!addLen; + } + int len = staticLen; + len -= (len % 4); + out(" Test program: preparing to play back "+len+" bytes == "+bytes2Ms(len, format)+"ms audio..."); + + byte[] fakedata=new byte[len]; + InputStream is = new ByteArrayInputStream(fakedata); + AudioInputStream ais = new AudioInputStream(is, format, fakedata.length/format.getFrameSize()); + + DataLine.Info info = new DataLine.Info(Clip.class, ais.getFormat()); + clip = (Clip) AudioSystem.getLine(info); + clip.addLineListener(this); + + out(" Test program: opening clip="+((clip==null)?"null":clip.toString())); + clip.open(ais); + ais.close(); + out(" Test program: starting clip="+((clip==null)?"null":clip.toString())); + clip.start(); + return bytes2Ms(fakedata.length, format); + } + + public static void main(String[] args) throws Exception { + if (!isSoundcardInstalled()) { + return; + } + + try { + int COUNT=10; + out(); + out("4498848 Sound causes crashes on Linux"); + if (args.length>0) { + COUNT=Integer.parseInt(args[0]); + } + for (int i=0; i 0) { + result = AudioSystem.getSourceDataLine(null) != null; + } + } catch (Exception e) { + System.err.println("Exception occured: "+e); + } + if (!result) { + System.err.println("Soundcard does not exist or sound drivers not installed!"); + System.err.println("This test requires sound drivers for execution."); + } + return result; + } + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/LinuxCrash/SDLLinuxCrash.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/LinuxCrash/SDLLinuxCrash.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineEvent; +import javax.sound.sampled.LineListener; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; + +/** + * @test + * @bug 4498848 + * @summary Sound causes crashes on Linux (part 2) + */ +public class SDLLinuxCrash implements Runnable { + SourceDataLine sdl; + int size; + + SDLLinuxCrash(SourceDataLine sdl, int size) { + this.sdl = sdl; + this.size = size - (size % 4); + } + + public void run() { + int written=0; + //byte[] buffer = new byte[4096]; + byte[] buffer = data; + out(" starting data line feed thread."); + try { + while (written size) { + toWrite = size-written; + } + toWrite -= (toWrite % 4); + //out(" writing "+toWrite+" bytes."); + int thisWritten = sdl.write(buffer, 0, toWrite); + if (thisWritten8*44100*4) { + staticLen = 8*44100*4; + addLen=!addLen; + } + if (staticLen<1000) { + staticLen = 1000; + addLen=!addLen; + } + int len = staticLen; + len -= (len % 4); + out(" preparing to play back "+len+" bytes == "+bytes2Ms(len, format)+"ms audio..."); + + DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); + SourceDataLine sdl = (SourceDataLine) AudioSystem.getLine(info); + sdl.addLineListener(new LineListener() { + public void update(LineEvent e) { + if (e.getType() == LineEvent.Type.STOP) { + out(" calling close() from event dispatcher thread"); + ((SourceDataLine) e.getSource()).close(); + } + else if (e.getType() == LineEvent.Type.CLOSE) { + } + } + }); + + out(" opening..."); + sdl.open(); + out(" starting..."); + sdl.start(); + (new Thread(new SDLLinuxCrash(sdl, len))).start(); + return sdl; + } + + public static void main(String[] args) throws Exception { + if (!isSoundcardInstalled()) { + return; + } + + try { + int COUNT=10; + out(); + out("4498848 Sound causes crashes on Linux (testing with SourceDataLine)"); + if (args.length>0) { + COUNT=Integer.parseInt(args[0]); + } + for (int i=0; i 0) { + result = AudioSystem.getSourceDataLine(null) != null; + } + } catch (Exception e) { + System.err.println("Exception occured: "+e); + } + if (!result) { + System.err.println("Soundcard does not exist or sound drivers not installed!"); + System.err.println("This test requires sound drivers for execution."); + } + return result; + } + + + + static final byte[] data = new byte[] { + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, + 123, 110, 100, 60, 11, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 60, 100, 110, 120, 122, 122 + }; + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Mixers/BogusMixers.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Mixers/BogusMixers.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.Line; +import javax.sound.sampled.Mixer; + +/** + * @test + * @bug 4667064 + * @summary Java Sound provides bogus SourceDataLine and TargetDataLine + */ +public class BogusMixers { + + public static void main(String[] args) throws Exception { + try { + out("4667064: Java Sound provides bogus SourceDataLine and TargetDataLine"); + + Mixer.Info[] aInfos = AudioSystem.getMixerInfo(); + out(" available Mixers:"); + for (int i = 0; i < aInfos.length; i++) { + if (aInfos[i].getName().startsWith("Java Sound Audio Engine")) { + Mixer mixer = AudioSystem.getMixer(aInfos[i]); + Line.Info[] tlInfos = mixer.getTargetLineInfo(); + for (int ii = 0; ii 0) { + if (format.getSampleSizeInBits() == 8) { + // return the other signed'ness + if (isSigned) { + newEnc = AudioFormat.Encoding.PCM_UNSIGNED; + } else { + newEnc = AudioFormat.Encoding.PCM_SIGNED; + } + } else { + newEnc = format.getEncoding(); + newEndian = !newEndian; + } + if (newEnc != null) { + return new AudioFormat(newEnc, format.getSampleRate(), + format.getSampleSizeInBits(), + format.getChannels(), + format.getFrameSize(), + format.getFrameRate(), + newEndian); + } + } + return null; + } + + static void out(String s) { + System.out.println(s); System.out.flush(); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Mixers/DirectSoundRepeatingBuffer/DirectSoundRepeatingBuffer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Mixers/DirectSoundRepeatingBuffer/DirectSoundRepeatingBuffer.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; + +/** + * This is utility class for Test4997635. + */ +public class DirectSoundRepeatingBuffer { + + static int sampleRate = 8000; + static double frequency = 1000.0; + static double RAD = 2.0 * Math.PI; + + static byte[] audioData = new byte[sampleRate/8]; + static DataLine.Info info; + static SourceDataLine source; + + //static AudioInputStream ais = null; + static AudioFormat audioFormat; + //static String filename; + + public static void print(String s) { + System.out.print(s); + } + public static void println(String s) { + System.out.println(s); + } + + public static void key() { + println(""); + print("Press ENTER to continue..."); + try { + System.in.read(); + } catch (IOException ioe) { + } + println(""); + } + + public static void play(Mixer mixer) { + int res = 0; + try { + println("Getting SDL from mixer..."); + source = (SourceDataLine) mixer.getLine(info); + println("Opening SDL..."); + source.open(audioFormat); + println("Writing data to SDL..."); + source.write(audioData, 0, audioData.length); + println("Starting SDL..."); + source.start(); + println("Now open your ears:"); + println("- you should have heard a short tone,"); + println(" followed by silence."); + println("- if after a while you hear repeated tones,"); + println(" the bug is NOT fixed."); + println("- if the program remains silent after the "); + println(" initial tone, the bug is fixed."); + key(); + } catch (IllegalArgumentException iae) { + println("IllegalArgumentException: "+iae.getMessage()); + println("Sound device cannot handle this audio format."); + println("ERROR: Test environment not correctly set up."); + if (source!=null) { + source.close(); + source = null; + } + return; + } catch (LineUnavailableException lue) { + println("LineUnavailableException: "+lue.getMessage()); + println("This is normal for some mixers."); + } catch (Exception e) { + println("Unexpected Exception: "+e.toString()); + } + if (source != null) { + println("Stopping..."); + source.stop(); + println("Closing..."); + source.close(); + println("Closed."); + source = null; + } + } + + public static void main(String[] args) throws Exception { + println("This is an interactive test for DirectAudio."); + println("If the tone repeats, the test is failed."); + println(""); + println("Make sure that you have speakers connected"); + println("and that the system mixer is not muted."); + println(""); + println("Press a key to start the test."); + key(); + Mixer.Info[] mixers=null; + + println(" ...using self-generated sine wave for playback"); + audioFormat = new AudioFormat((float)sampleRate, 8, 1, true, true); + for (int i=0; inot a DirectAudio Mixer!"); + } else { + try { + Mixer mixer = AudioSystem.getMixer(mixers[i]); + if (!mixer.isLineSupported(info)) { + println(" ->doesn't support SourceDataLine!"); + } else { + succMixers++; + println(" -> is getting tested."); + play(mixer); + } + } catch (Exception e) { + println(" -> Exception occured: "+e); + e.printStackTrace(); + } + } + } + if (succMixers == 0) { + println("No DirectAudio mixers available! "); + println("Cannot run test."); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Mixers/DirectSoundRepeatingBuffer/Test4997635.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Mixers/DirectSoundRepeatingBuffer/Test4997635.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * @test + * @bug 4997635 + * @summary Win: SourceDataLine playback loops endlessly unless you manually + * stop() + * @build DirectSoundRepeatingBuffer + * @run main/manual Test4997635 + */ +public class Test4997635 { + + private static void init() throws Exception { + //*** Create instructions for the user here *** + + String[] instructions = + { + "To run the test follow these instructions:", + "1. Open a terminal window.", + "2. Type \"cd " + System.getProperty("test.classes") + "\".", + "3. Type \"" + System.getProperty("java.home") + "/bin/java DirectSoundRepeatingBuffer\".", + "4. Follow the instructions shown in the terminal window.", + "If no error occured during the test, and the java application ", + "in the termial exited successfully, press PASS, else press FAIL." + }; + + Sysout.createDialog( ); + Sysout.printInstructions( instructions ); + + } + + /***************************************************** + Standard Test Machinery Section + DO NOT modify anything in this section -- it's a + standard chunk of code which has all of the + synchronisation necessary for the test harness. + By keeping it the same in all tests, it is easier + to read and understand someone else's test, as + well as insuring that all tests behave correctly + with the test harness. + There is a section following this for test-defined + classes + ******************************************************/ + private static boolean theTestPassed = false; + private static boolean testGeneratedInterrupt = false; + private static String failureMessage = ""; + + private static Thread mainThread = null; + + private static int sleepTime = 300000; + + public static void main( String args[] ) throws Exception + { + mainThread = Thread.currentThread(); + try + { + init(); + } + catch( TestPassedException e ) + { + //The test passed, so just return from main and harness will + // interepret this return as a pass + return; + } + //At this point, neither test passed nor test failed has been + // called -- either would have thrown an exception and ended the + // test, so we know we have multiple threads. + + //Test involves other threads, so sleep and wait for them to + // called pass() or fail() + try + { + Thread.sleep( sleepTime ); + //Timed out, so fail the test + throw new RuntimeException( "Timed out after " + sleepTime/1000 + " seconds" ); + } + catch (InterruptedException e) + { + if( ! testGeneratedInterrupt ) throw e; + + //reset flag in case hit this code more than once for some reason (just safety) + testGeneratedInterrupt = false; + if ( theTestPassed == false ) + { + throw new RuntimeException( failureMessage ); + } + } + + }//main + + public static synchronized void setTimeoutTo( int seconds ) + { + sleepTime = seconds * 1000; + } + + public static synchronized void pass() + { + Sysout.println( "The test passed." ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //first check if this is executing in main thread + if ( mainThread == Thread.currentThread() ) + { + //Still in the main thread, so set the flag just for kicks, + // and throw a test passed exception which will be caught + // and end the test. + theTestPassed = true; + throw new TestPassedException(); + } + //pass was called from a different thread, so set the flag and interrupt + // the main thead. + theTestPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + }//pass() + + public static synchronized void fail() + { + //test writer didn't specify why test failed, so give generic + fail( "it just plain failed! :-)" ); + } + + public static synchronized void fail( String whyFailed ) + { + Sysout.println( "The test failed: " + whyFailed ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //check if this called from main thread + if ( mainThread == Thread.currentThread() ) + { + //If main thread, fail now 'cause not sleeping + throw new RuntimeException( whyFailed ); + } + theTestPassed = false; + testGeneratedInterrupt = true; + failureMessage = whyFailed; + mainThread.interrupt(); + }//fail() + + }// class Orient + +//This exception is used to exit from any level of call nesting +// when it's determined that the test has passed, and immediately +// end the test. +class TestPassedException extends RuntimeException + { + } + +//*********** End Standard Test Machinery Section ********** + + +//************ Begin classes defined for the test **************** + +// make listeners in a class defined here, and instantiate them in init() + +/* Example of a class which may be written as part of a test +class NewClass implements anInterface + { + static int newVar = 0; + + public void eventDispatched(AWTEvent e) + { + //Counting events to see if we get enough + eventCount++; + + if( eventCount == 20 ) + { + //got enough events, so pass + + Orient.pass(); + } + else if( tries == 20 ) + { + //tried too many times without getting enough events so fail + + Orient.fail(); + } + + }// eventDispatched() + + }// NewClass class + +*/ + + +//************** End classes defined for the test ******************* + + + + +/**************************************************** + Standard Test Machinery + DO NOT modify anything below -- it's a standard + chunk of code whose purpose is to make user + interaction uniform, and thereby make it simpler + to read and understand someone else's test. + ****************************************************/ + +/** + This is part of the standard test machinery. + It creates a dialog (with the instructions), and is the interface + for sending text messages to the user. + To print the instructions, send an array of strings to Sysout.createDialog + WithInstructions method. Put one line of instructions per array entry. + To display a message for the tester to see, simply call Sysout.println + with the string to be displayed. + This mimics System.out.println but works within the test harness as well + as standalone. + */ + +class Sysout + { + private static TestDialog dialog; + + public static void createDialogWithInstructions( String[] instructions ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + dialog.printInstructions( instructions ); + dialog.show(); + println( "Any messages for the tester will display here." ); + } + + public static void createDialog( ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + String[] defInstr = { "Instructions will appear here. ", "" } ; + dialog.printInstructions( defInstr ); + dialog.show(); + println( "Any messages for the tester will display here." ); + } + + + public static void printInstructions( String[] instructions ) + { + dialog.printInstructions( instructions ); + } + + + public static void println( String messageIn ) + { + dialog.displayMessage( messageIn ); + } + + }// Sysout class + +/** + This is part of the standard test machinery. It provides a place for the + test instructions to be displayed, and a place for interactive messages + to the user to be displayed. + To have the test instructions displayed, see Sysout. + To have a message to the user be displayed, see Sysout. + Do not call anything in this dialog directly. + */ +class TestDialog extends Dialog implements ActionListener + { + + TextArea instructionsText; + TextArea messageText; + int maxStringLength = 80; + Panel buttonP = new Panel(); + Button passB = new Button( "pass" ); + Button failB = new Button( "fail" ); + + //DO NOT call this directly, go through Sysout + public TestDialog( Frame frame, String name ) + { + super( frame, name ); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); + add( "North", instructionsText ); + + messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); + add("Center", messageText); + + passB = new Button( "pass" ); + passB.setActionCommand( "pass" ); + passB.addActionListener( this ); + buttonP.add( "East", passB ); + + failB = new Button( "fail" ); + failB.setActionCommand( "fail" ); + failB.addActionListener( this ); + buttonP.add( "West", failB ); + + add( "South", buttonP ); + pack(); + + show(); + }// TestDialog() + + //DO NOT call this directly, go through Sysout + public void printInstructions( String[] instructions ) + { + //Clear out any current instructions + instructionsText.setText( "" ); + + //Go down array of instruction strings + + String printStr, remainingStr; + for( int i=0; i < instructions.length; i++ ) + { + //chop up each into pieces maxSringLength long + remainingStr = instructions[ i ]; + while( remainingStr.length() > 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + //else just print + else + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn ) + { + messageText.append( messageIn + "\n" ); + } + + //catch presses of the passed and failed buttons. + //simply call the standard pass() or fail() static methods of + //DialogOrient + public void actionPerformed( ActionEvent e ) + { + if( e.getActionCommand() == "pass" ) + { + Test4997635.pass(); + } + else + { + Test4997635.fail(); + } + } + + }// TestDialog class diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Mixers/DirectSoundUnderrunSilence/DirectSoundUnderrunSilence.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Mixers/DirectSoundUnderrunSilence/DirectSoundUnderrunSilence.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; + +/** + * This is utility class for Test5032020. + */ +public class DirectSoundUnderrunSilence { + + static int sampleRate = 8000; + static double frequency = 1000.0; + static double RAD = 2.0 * Math.PI; + + static byte[] audioData = new byte[sampleRate/8]; + static DataLine.Info info; + static SourceDataLine source; + + //static AudioInputStream ais = null; + static AudioFormat audioFormat; + //static String filename; + + public static void print(String s) { + System.out.print(s); + } + public static void println(String s) { + System.out.println(s); + } + + public static void key() { + println(""); + print("Press ENTER to continue..."); + try { + System.in.read(); + } catch (IOException ioe) { + } + println(""); + } + + public static void play(Mixer mixer) { + int res = 0; + try { + println("Getting SDL from mixer..."); + source = (SourceDataLine) mixer.getLine(info); + println("Opening SDL..."); + source.open(audioFormat); + println("Writing data to SDL..."); + source.write(audioData, 0, audioData.length); + println("Starting SDL..."); + source.start(); + println("Now open your ears:"); + println("You should have heard a short tone,"); + println("followed by silence (no repeating tones)."); + key(); + source.write(audioData, 0, audioData.length); + println("Now you should have heard another short tone."); + println("If you did not hear a second tone, or more than 2 tones,"); + println("the test is FAILED."); + println("otherwise, if you heard a total of 2 tones, the bug is fixed."); + key(); + } catch (IllegalArgumentException iae) { + println("IllegalArgumentException: "+iae.getMessage()); + println("Sound device cannot handle this audio format."); + println("ERROR: Test environment not correctly set up."); + if (source!=null) { + source.close(); + source = null; + } + return; + } catch (LineUnavailableException lue) { + println("LineUnavailableException: "+lue.getMessage()); + println("This is normal for some mixers."); + } catch (Exception e) { + println("Unexpected Exception: "+e.toString()); + } + if (source != null) { + println("Stopping..."); + source.stop(); + println("Closing..."); + source.close(); + println("Closed."); + source = null; + } + } + + public static void main(String[] args) throws Exception { + println("This is an interactive test for DirectAudio."); + println("If it's impossible to play data after an underun, the test fails."); + println(""); + println("Make sure that you have speakers connected"); + println("and that the system mixer is not muted."); + println("Also stop all other programs playing sounds:"); + println("It has been seen that it alters the results."); + println(""); + println("Press a key to start the test."); + key(); + Mixer.Info[] mixers=null; + + println(" ...using self-generated sine wave for playback"); + audioFormat = new AudioFormat((float)sampleRate, 8, 1, true, true); + for (int i=0; inot a DirectAudio Mixer!"); + } else { + try { + Mixer mixer = AudioSystem.getMixer(mixers[i]); + if (!mixer.isLineSupported(info)) { + println(" ->doesn't support SourceDataLine!"); + } else { + succMixers++; + println(" -> is getting tested."); + play(mixer); + } + } catch (Exception e) { + println(" -> Exception occured: "+e); + e.printStackTrace(); + } + } + } + if (succMixers == 0) { + println("No DirectAudio mixers available! "); + println("Cannot run test."); + } + } + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Mixers/DirectSoundUnderrunSilence/Test5032020.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Mixers/DirectSoundUnderrunSilence/Test5032020.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * @test + * @bug 5032020 + * @summary Win: Direct Audio is silent after underrun + * @build DirectSoundUnderrunSilence + * @run main/manual Test5032020 + */ +public class Test5032020 { + + private static void init() throws Exception { + //*** Create instructions for the user here *** + + String[] instructions = + { + "To run the test follow these instructions:", + "1. Open a terminal window.", + "2. Type \"cd " + System.getProperty("test.classes") + "\".", + "3. Type \"" + System.getProperty("java.home") + "/bin/java DirectSoundUnderrunSilence\".", + "4. Follow the instructions shown in the terminal window.", + "If no error occured during the test, and the java application ", + "in the termial exited successfully, press PASS, else press FAIL." + }; + + Sysout.createDialog( ); + Sysout.printInstructions( instructions ); + + } + + /***************************************************** + Standard Test Machinery Section + DO NOT modify anything in this section -- it's a + standard chunk of code which has all of the + synchronisation necessary for the test harness. + By keeping it the same in all tests, it is easier + to read and understand someone else's test, as + well as insuring that all tests behave correctly + with the test harness. + There is a section following this for test-defined + classes + ******************************************************/ + private static boolean theTestPassed = false; + private static boolean testGeneratedInterrupt = false; + private static String failureMessage = ""; + + private static Thread mainThread = null; + + private static int sleepTime = 300000; + + public static void main( String args[] ) throws Exception + { + mainThread = Thread.currentThread(); + try + { + init(); + } + catch( TestPassedException e ) + { + //The test passed, so just return from main and harness will + // interepret this return as a pass + return; + } + //At this point, neither test passed nor test failed has been + // called -- either would have thrown an exception and ended the + // test, so we know we have multiple threads. + + //Test involves other threads, so sleep and wait for them to + // called pass() or fail() + try + { + Thread.sleep( sleepTime ); + //Timed out, so fail the test + throw new RuntimeException( "Timed out after " + sleepTime/1000 + " seconds" ); + } + catch (InterruptedException e) + { + if( ! testGeneratedInterrupt ) throw e; + + //reset flag in case hit this code more than once for some reason (just safety) + testGeneratedInterrupt = false; + if ( theTestPassed == false ) + { + throw new RuntimeException( failureMessage ); + } + } + + }//main + + public static synchronized void setTimeoutTo( int seconds ) + { + sleepTime = seconds * 1000; + } + + public static synchronized void pass() + { + Sysout.println( "The test passed." ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //first check if this is executing in main thread + if ( mainThread == Thread.currentThread() ) + { + //Still in the main thread, so set the flag just for kicks, + // and throw a test passed exception which will be caught + // and end the test. + theTestPassed = true; + throw new TestPassedException(); + } + //pass was called from a different thread, so set the flag and interrupt + // the main thead. + theTestPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + }//pass() + + public static synchronized void fail() + { + //test writer didn't specify why test failed, so give generic + fail( "it just plain failed! :-)" ); + } + + public static synchronized void fail( String whyFailed ) + { + Sysout.println( "The test failed: " + whyFailed ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //check if this called from main thread + if ( mainThread == Thread.currentThread() ) + { + //If main thread, fail now 'cause not sleeping + throw new RuntimeException( whyFailed ); + } + theTestPassed = false; + testGeneratedInterrupt = true; + failureMessage = whyFailed; + mainThread.interrupt(); + }//fail() + + }// class Orient + +//This exception is used to exit from any level of call nesting +// when it's determined that the test has passed, and immediately +// end the test. +class TestPassedException extends RuntimeException + { + } + +//*********** End Standard Test Machinery Section ********** + + +//************ Begin classes defined for the test **************** + +// make listeners in a class defined here, and instantiate them in init() + +/* Example of a class which may be written as part of a test +class NewClass implements anInterface + { + static int newVar = 0; + + public void eventDispatched(AWTEvent e) + { + //Counting events to see if we get enough + eventCount++; + + if( eventCount == 20 ) + { + //got enough events, so pass + + Orient.pass(); + } + else if( tries == 20 ) + { + //tried too many times without getting enough events so fail + + Orient.fail(); + } + + }// eventDispatched() + + }// NewClass class + +*/ + + +//************** End classes defined for the test ******************* + + + + +/**************************************************** + Standard Test Machinery + DO NOT modify anything below -- it's a standard + chunk of code whose purpose is to make user + interaction uniform, and thereby make it simpler + to read and understand someone else's test. + ****************************************************/ + +/** + This is part of the standard test machinery. + It creates a dialog (with the instructions), and is the interface + for sending text messages to the user. + To print the instructions, send an array of strings to Sysout.createDialog + WithInstructions method. Put one line of instructions per array entry. + To display a message for the tester to see, simply call Sysout.println + with the string to be displayed. + This mimics System.out.println but works within the test harness as well + as standalone. + */ + +class Sysout + { + private static TestDialog dialog; + + public static void createDialogWithInstructions( String[] instructions ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + dialog.printInstructions( instructions ); + dialog.show(); + println( "Any messages for the tester will display here." ); + } + + public static void createDialog( ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + String[] defInstr = { "Instructions will appear here. ", "" } ; + dialog.printInstructions( defInstr ); + dialog.show(); + println( "Any messages for the tester will display here." ); + } + + + public static void printInstructions( String[] instructions ) + { + dialog.printInstructions( instructions ); + } + + + public static void println( String messageIn ) + { + dialog.displayMessage( messageIn ); + } + + }// Sysout class + +/** + This is part of the standard test machinery. It provides a place for the + test instructions to be displayed, and a place for interactive messages + to the user to be displayed. + To have the test instructions displayed, see Sysout. + To have a message to the user be displayed, see Sysout. + Do not call anything in this dialog directly. + */ +class TestDialog extends Dialog implements ActionListener + { + + TextArea instructionsText; + TextArea messageText; + int maxStringLength = 80; + Panel buttonP = new Panel(); + Button passB = new Button( "pass" ); + Button failB = new Button( "fail" ); + + //DO NOT call this directly, go through Sysout + public TestDialog( Frame frame, String name ) + { + super( frame, name ); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); + add( "North", instructionsText ); + + messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); + add("Center", messageText); + + passB = new Button( "pass" ); + passB.setActionCommand( "pass" ); + passB.addActionListener( this ); + buttonP.add( "East", passB ); + + failB = new Button( "fail" ); + failB.setActionCommand( "fail" ); + failB.addActionListener( this ); + buttonP.add( "West", failB ); + + add( "South", buttonP ); + pack(); + + show(); + }// TestDialog() + + //DO NOT call this directly, go through Sysout + public void printInstructions( String[] instructions ) + { + //Clear out any current instructions + instructionsText.setText( "" ); + + //Go down array of instruction strings + + String printStr, remainingStr; + for( int i=0; i < instructions.length; i++ ) + { + //chop up each into pieces maxSringLength long + remainingStr = instructions[ i ]; + while( remainingStr.length() > 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + //else just print + else + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn ) + { + messageText.append( messageIn + "\n" ); + } + + //catch presses of the passed and failed buttons. + //simply call the standard pass() or fail() static methods of + //DialogOrient + public void actionPerformed( ActionEvent e ) + { + if( e.getActionCommand() == "pass" ) + { + Test5032020.pass(); + } + else + { + Test5032020.fail(); + } + } + + }// TestDialog class diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Mixers/DisabledAssertionCrash.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Mixers/DisabledAssertionCrash.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.Line; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.SourceDataLine; +import javax.sound.sampled.TargetDataLine; + +/** + * @test + * @bug 4991672 + * @summary disabled assertion at maximum thread priority causes audio crash + * @run main/timeout=600 DisabledAssertionCrash + */ +public class DisabledAssertionCrash { + private static final int bufferSize = 1024; + + public static void main(String[] args) { + + System.out.println("This program hangs if priority is set,"); + System.out.println("and assertion is in the code."); + System.out.println("The program crashes the entire Windows system"); + System.out.println("if assertions are disabled."); + try { + Thread.currentThread().setPriority(Thread.MAX_PRIORITY); + AudioFormat audioFormat = new AudioFormat(44100,16,1,true,true); + Line.Info sourceDataLineInfo = new DataLine.Info(SourceDataLine.class,audioFormat); + SourceDataLine sourceDataLine = + (SourceDataLine) AudioSystem.getLine(sourceDataLineInfo); + System.out.println("SourceDataLine: "+sourceDataLine); + sourceDataLine.open(audioFormat, bufferSize); + sourceDataLine.start(); + Line.Info targetDataLineInfo = + new DataLine.Info(TargetDataLine.class,audioFormat); + TargetDataLine targetDataLine = + (TargetDataLine) AudioSystem.getLine(targetDataLineInfo); + System.out.println("TargetDataLine: "+targetDataLine); + targetDataLine.open(audioFormat, bufferSize); + targetDataLine.start(); + byte[] data = new byte[bufferSize]; + + // execute for 20 seconds + float bufferTime = (((float) data.length) / audioFormat.getFrameSize()) / audioFormat.getFrameRate(); + int count = (int) (20.0f / bufferTime); + System.out.println("Buffer time: "+(bufferTime * 1000)+" millis. "+count+" iterations."); + for (int i = 0; i < count; i++) { + int cnt = targetDataLine.read(data,0,data.length); + sourceDataLine.write(data,0,cnt); + assert cnt == data.length; + } + System.out.println("Successfully recorded/played "+count+" buffers. Passed"); + } catch(LineUnavailableException lue) { + System.out.println("Audio hardware is not available!"); + lue.printStackTrace(); + System.out.println("Cannot execute test. NOT failed."); + } catch(IllegalArgumentException iae) { + System.out.println("No audio hardware is installed!"); + iae.printStackTrace(); + System.out.println("Test system not correctly setup."); + System.out.println("Cannot execute test. NOT failed."); + } catch(Exception e) { + System.out.println("Unexpected Exception: "+e); + e.printStackTrace(); + System.out.println("Cannot execute test. NOT failed."); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Mixers/NoSimpleInputDevice.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Mixers/NoSimpleInputDevice.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Mixer; + +/** + * @test + * @bug 4936397 + * @summary Verify that there'll be either SimpleInputDevice OR DirectAudioDevice + */ +public class NoSimpleInputDevice { + + public static void main(String[] args) throws Exception { + out("4936397: Verify that there'll be either SimpleInputDevice OR DirectAudioDevice"); + boolean foundSimpleInputDevice = false; + boolean foundDirectAudioDevice = false; + + Mixer.Info[] aInfos = AudioSystem.getMixerInfo(); + for (int i = 0; i < aInfos.length; i++) { + try { + Mixer mixer = AudioSystem.getMixer(aInfos[i]); + String mixerClass = mixer.getClass().toString(); + if (mixerClass.indexOf("SimpleInputDevice") >= 0) { + out("Found SimpleInputDevice: "+aInfos[i]); + foundSimpleInputDevice = true; + } + if (mixerClass.indexOf("DirectAudioDevice") >= 0) { + out("Found DirectAudioDevice: "+aInfos[i]); + foundDirectAudioDevice = true; + } + } catch (Exception e) { + out("Unexpected exception: "+e); + } + } + if (aInfos.length == 0) { + out("[No mixers available] - cannot exercise this test."); + } else { + if (foundSimpleInputDevice && foundDirectAudioDevice) { + out("Found both types of capture devices!"); + throw new Exception("Test FAILED!"); + } + out("Did not find both types of capture devices. Test passed"); + } + } + + static void out(String s) { + System.out.println(s); System.out.flush(); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Mixers/PhantomMixers.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Mixers/PhantomMixers.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.Line; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; +import javax.sound.sampled.TargetDataLine; + +/** + * @test + * @bug 4794104 + * @summary mixers are always present, independent of available soundcards + * @run main/manual PhantomMixers + */ +public class PhantomMixers { + + public static void main(String args[]) throws Exception { + int SDLformats = 0; + int TDLformats = 0; + Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo(); + for(int i=0; i " + (srcLineInfo.length + dstLineInfo.length) + " line"); + switch (count) { + case 0: System.out.println("s"); break; + case 1: System.out.println(""); break; + default: System.out.println("s:"); break; + } + int l; + for (l = 0; l < srcLineInfo.length; l++) { + System.out.println(" "+srcLineInfo[l].toString()); + if (srcLineInfo[l].getLineClass() == SourceDataLine.class + && (srcLineInfo[l] instanceof DataLine.Info)) { + SDLformats += ((DataLine.Info) srcLineInfo[l]).getFormats().length; + } + } + for (l = 0; l < dstLineInfo.length; l++) { + System.out.println(" "+dstLineInfo[l].toString()); + if (dstLineInfo[l].getLineClass() == TargetDataLine.class + && (dstLineInfo[l] instanceof DataLine.Info)) { + TDLformats += ((DataLine.Info) dstLineInfo[l]).getFormats().length; + } + } + } + if (mixerInfo.length == 0) { + System.out.println("[no mixers present]"); + } + System.out.println(""+SDLformats+" total formats for SourceDataLines"); + System.out.println(""+TDLformats+" total formats for TargetDataLines"); + System.out.println(""); + System.out.println("If there are audio devices correctly installed on your"); + System.out.println("system, you should see at least one Mixer, and in total"); + System.out.println("at least each one SourceDataLine and TargetDataLine, both"); + System.out.println("providing at least one format."); + System.out.println(""); + System.out.println("Now disable your soundcard and repeat the test."); + System.out.println("The corresponding mixer(s) should not provide any formats"); + System.out.println("anymore. If you disable all available soundcards"); + System.out.println("on your computer, the number of formats above should be"); + System.out.println("0 for both line types (although mixers are allowed to exist)."); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Mixers/PlugHwMonoAnd8bitAvailable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Mixers/PlugHwMonoAnd8bitAvailable.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.Line; +import javax.sound.sampled.Mixer; + +/** + * @test + * @bug 5013897 + * @summary Verify that plughw: provides mono and 8-bit lines + */ +public class PlugHwMonoAnd8bitAvailable { + static int failed = 0; + static int testedFormats = 0; + + public static void main(String[] args) throws Exception { + out("5013897: Verify that plughw: provides mono and 8-bit lines"); + + Mixer.Info[] aInfos = AudioSystem.getMixerInfo(); + for (int i = 0; i < aInfos.length; i++) { + try { + Mixer mixer = AudioSystem.getMixer(aInfos[i]); + out("Mixer "+aInfos[i]); + if (aInfos[i].getName().contains("plughw")) { + checkLines(mixer, mixer.getSourceLineInfo()); + checkLines(mixer, mixer.getTargetLineInfo()); + } else { + out(" -> not plughw, ignored."); + } + } catch (Exception e) { + out("Unexpected exception when getting a mixer: "+e); + } + } + if (testedFormats == 0) { + out("[No appropriate lines available] - cannot exercise this test."); + } else { + if (failed>0) { + throw new Exception("Test FAILED!"); + } + out("Successfully verified "+testedFormats+" formats."); + out("Test passed"); + } + } + + public static void checkLines(Mixer mixer, Line.Info[] infos) { + for (int i = 0; i 16) { + // if a bit size larger than 16 is available, also 16-bit must be there + checkFormat(formats, getOtherBits(formats[f], 16)); + } else + if (formats[f].getSampleSizeInBits() > 8) { + // if a bit size larger than 8 is available, also 8-bit must be there + checkFormat(formats, getOtherBits(formats[f], 8)); + } + if (formats[f].getChannels() > 2) { + // if more than 2 channels, also 2 channels must be there + checkFormat(formats, getOtherChannels(formats[f], 2)); + } else + if (formats[f].getChannels() > 1) { + // if more than 1 channel, also 1 channel must be there + checkFormat(formats, getOtherChannels(formats[f], 1)); + } + } catch (Exception e1) { + out(" Unexpected exception when getting a format: "+e1); + } + } + } + if (testedFormats - thisTestedFormats == 0) { + out(" -->could not test any formats"); + } else if (failed - thisFailed == 0) { + out(" -->"+(testedFormats - thisTestedFormats)+" formats tested OK"); + } + + } else { + out(" --> not a DataLine"); + } + } catch (Exception e) { + out(" Unexpected exception when getting a line: "+e); + } + } + } + + public static void checkFormat(AudioFormat[] formats, AudioFormat format) { + testedFormats++; + for (int i = 0; i < formats.length; i++) { + if (formats[i].matches(format)) { + return; + } + } + out(" ## expected this format: "+format + +" ("+format.getChannels()+" channels, " + +"frameSize="+format.getFrameSize()+", " + +(format.isBigEndian()?"big endian":"little endian") + +")"); + failed++; + } + + // only works for PCM encodings + public static AudioFormat getOtherBits(AudioFormat format, int newBits) { + boolean isSigned = format.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED); + return new AudioFormat(format.getSampleRate(), + newBits, + format.getChannels(), + isSigned, + (newBits>8)?format.isBigEndian():false); + } + + // only works for PCM encodings + public static AudioFormat getOtherChannels(AudioFormat format, int newChannels) { + int newFrameSize; + if (newChannels <= 0 || format.getChannels() <= 0 || format.getFrameSize() <= 0) { + newFrameSize = -1; + } else { + newFrameSize = format.getFrameSize() / format.getChannels() * newChannels; + } + return new AudioFormat(format.getEncoding(), + format.getSampleRate(), + format.getSampleSizeInBits(), + newChannels, + newFrameSize, + format.getFrameRate(), + format.isBigEndian()); + } + + + static void out(String s) { + System.out.println(s); System.out.flush(); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/Mixers/UnexpectedIAE.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/Mixers/UnexpectedIAE.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2004, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Line; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; + +/** + * @test + * @bug 4964288 + * @summary Unexpected IAE raised while getting TargetDataLine + */ +public class UnexpectedIAE { + + public static void main(String argv[]) throws Exception { + boolean success = true; + + Mixer.Info [] infos = AudioSystem.getMixerInfo(); + + for (int i=0; i 100) { + inLine.close(); + System.out.println("TargetDataLine does not support buffer size of "+bufferSize+" bytes!"); + return false; + }*/ + bufferSize = inLine.getBufferSize(); + /* 3/4 of buffer size ot wait */ + WAIT_MILLIS = (int) (bufferSize / format.getFrameSize() * 750 / format.getFrameRate()); + System.out.println("Buffer size: "+bufferSize+" bytes = " + +((int) (bufferSize / format.getFrameSize() * 750 / format.getFrameRate()))+" millis"); + return true; + } + + private String available() { + int avail = inLine.available(); + int availMillis = (int) (avail / format.getFrameSize() * 1000 / format.getFrameRate()); + return "available "+avail+" bytes = "+availMillis+" millis"; + } + + private boolean recordSound(int num) throws LineUnavailableException { + if (!openInputLine(num)) { + return false; + } + byte data[] = new byte[1000]; + try { + System.out.println("Got line: "+inLine); + System.out.println("Start recording" ); + inLine.start(); + System.out.print("Warm-up..."); + //System.out.print("Waiting 500 millis..."); + try { Thread.sleep(500); } catch (InterruptedException ie) {} + //System.out.println("done. "+available()); + //System.out.print("Reading all data..."); + int avail0 = inLine.available(); + if (avail0 == 0) { + System.out.println("Problem: TargetDataLine did not deliver any data!"); + System.out.println("Not a test failure, but serious failure nonetheless."); + } else { + while ((avail0 -= inLine.read(data, 0, Math.min(data.length, avail0))) > 0); + System.out.println("done. "+available()); + System.out.print("Waiting "+(WAIT_MILLIS)+" millis..."); + try { Thread.sleep(WAIT_MILLIS); } catch (InterruptedException ie) {} + int avail1 = inLine.available(); + System.out.println("done. "+available()); + + System.out.print("Flushing..."); + inLine.flush(); + System.out.println("done. "+available()); + System.out.print("Waiting "+(WAIT_MILLIS)+" millis..."); + try { Thread.sleep(WAIT_MILLIS); } catch (InterruptedException ie) {} + int avail2 = inLine.available(); + System.out.println("done. "+available()); + if (avail2 > avail1) { + failed = true; + System.out.println("Failed: Flushing with native flush() should " + +"result in fewer bytes available."); + } + if (avail2 == 0) { + failed = true; + System.out.println("Failed: Recording after flush() did not work at all!"); + } + } + } finally { + System.out.print("Closing line...."); + inLine.close(); + System.out.println("done"); + } + return true; + } + + public void runTests(int testRuns) { + if (mixers.length > 0) { + for (int num = -1; num < mixers.length; num++) { + try { + if (num<0) { + System.out.println("------Using default line...." ); + } else { + System.out.println("------Using line "+num+" from mixer "+mixers[num]+"..."); + } + for (int testRun = 0; testRun < testRuns; testRun++) { + if (testRuns>1) { + System.out.println("--Run "+(testRun+1)+"/"+testRuns+":"); + } + if (!recordSound(num)) { + break; + } + } + } catch (Exception ex) { + System.out.println("Caught " + ex ); + } + System.out.println("------------------------------------------------------"); + if (failed) { + break; + } + } + } else { + System.out.println("No mixers present. Cannot execute this test."); + } + } + + + public static void main(String[] args) throws Exception { + System.out.println("Test TargetDataLineFlush"); + System.out.println("This verifies that TargetDataLine.flush() actually"); + System.out.println("flushes the native buffers. This is done by"); + System.out.println("comparing a manual flush (i.e. just discarding"); + System.out.println("everything that is currently available in the TargetDataLine)"); + System.out.println("to a flushed line"); + TargetDataLineFlush app = new TargetDataLineFlush(); + int testRuns = 1; + if (args.length > 0) { + try { + testRuns = Integer.parseInt(args[0]); + } catch (NumberFormatException nfe) { + System.out.println("Usage: java TargetDataLineFlush [number of runs]"); + System.out.println("Parameters ignored."); + } + } + app.runTests(testRuns); + if (failed) { + throw new Exception("Test FAILED"); + } + // test always passes if it gets here + System.out.println("Test PASSED"); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/spi/AudioFileReader/AIFFCp037.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/AIFFCp037.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 4369044 + * @summary javax.sound.sampled.AudioSystem.getAudioInputStream() works wrong + * with Cp037 + */ +public class AIFFCp037 { + + public static void main(String args[]) throws Exception { + System.setProperty("file.encoding", "Cp037"); + // try to read this file with Cp037 encoding + AudioSystem.getAudioInputStream(new ByteArrayInputStream(SHORT_AIFF)); + System.out.println(" test passed."); + } + + public static String getString(byte b) { + //String res = Integer.toHexString(b & 0xFF).toUpperCase(); + //while (res.length()<2) res="0"+res; + //return res; + return String.valueOf(b); + } + + + public static void printFile(String filename) throws Exception { + File file = new File(filename); + FileInputStream fis = new FileInputStream(file); + byte[] data = new byte[(int) file.length()]; + fis.read(data); + String s = ""; + for (int i=0; i72) { + System.out.println(s); + s=""; + } + } + System.out.println(s); + } + + public static byte[] SHORT_AIFF = { + 70, 79, 82, 77, 0, 0, 4, -54, 65, 73, 70, 70, 67, 79, 77, 77, 0, 0, 0, 18, + 0, 1, 0, 0, 2, 78, 0, 16, 64, 12, -84, 68, 0, 0, 0, 0, 0, 0, 83, 83, 78, + 68, 0, 0, 4, -92, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -2, 0, 0, 0, 0, 0, + -3, 0, -5, 0, -2, 0, 3, 0, 1, 0, -3, 0, -5, 0, -6, 0, -6, 0, -5, 0, -2, 0, + -2, 0, -5, 0, -6, 0, -3, 0, 0, 0, 0, 0, -3, 0, -5, 0, -6, 0, -8, 0, -5, 0, + 1, 0, 4, 0, 1, 0, -5, 0, -8, 0, -3, 0, 3, 0, 4, 0, 0, 0, -8, 0, -11, 0, -8, + 0, -3, 0, 0, 0, 0, 0, 1, 0, 0, 0, -5, 0, -9, 0, -8, 0, 0, 0, 6, 0, 7, 0, + 0, 0, -8, 0, -11, 0, -8, 0, 0, 0, 4, 0, 6, 0, 3, 0, -2, 0, -5, 0, -5, 0, + 0, 0, 6, 0, 6, 0, 1, 0, -5, 0, -3, 0, 1, 0, 6, 0, 6, 0, 1, 0, -3, 0, -3, + 0, 0, 0, 3, 0, 3, 0, 0, 0, -3, 0, -2, 0, 3, 0, 6, 0, 4, 0, 0, 0, -2, 0, -2, + 0, 1, 0, 1, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -3, 0, 1, 0, 6, + 0, 6, 0, 1, 0, 0, 0, 1, 0, 0, 0, -2, 0, -2, 0, 3, 0, 4, 0, 0, 0, -5, 0, -3, + 0, 1, 0, 4, 0, 4, 0, 0, 0, -2, 0, 1, 0, 1, 0, -2, 0, -6, 0, -6, 0, -2, 0, + 6, 0, 7, 0, 4, 0, 0, 0, -5, 0, -6, 0, -5, 0, 0, 0, 4, 0, 4, 0, 0, 0, -5, + 0, -8, 0, -8, 0, -5, 0, 1, 0, 3, 0, 1, 0, -3, 0, -6, 0, -6, 0, -5, 0, -5, + 0, -3, 0, 1, 0, 3, 0, 1, 0, -2, 0, -5, 0, -5, 0, -5, 0, -3, 0, 3, 0, 6, 0, + 6, 0, 0, 0, -3, 0, -3, 0, 0, 0, 1, 0, 0, 0, 3, 0, 4, 0, 0, 0, -3, 0, -5, + 0, -2, 0, 1, 0, -2, 0, -2, 0, 1, 0, 4, 0, 1, 0, -3, 0, -2, 0, 0, 0, 0, 0, + -3, 0, -6, 0, -5, 0, 0, 0, 3, 0, 0, 0, -3, 0, -5, 0, -5, 0, -2, 0, -2, 0, + -5, 0, -6, 0, -3, 0, 1, 0, 1, 0, -2, 0, -8, 0, -8, 0, -3, 0, 1, 0, 3, 0, + 1, 0, -5, 0, -8, 0, -6, 0, -2, 0, 3, 0, 4, 0, -2, 0, -5, 0, -6, 0, -3, 0, + -2, 0, -2, 0, -2, 0, -2, 0, -3, 0, -5, 0, -6, 0, -5, 0, -2, 0, 0, 0, 0, 0, + -2, 0, -3, 0, -5, 0, -5, 0, -3, 0, -3, 0, -2, 0, -2, 0, 0, 0, 1, 0, 1, 0, + 0, 0, 1, 0, 1, 0, -2, 0, -5, 0, -3, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 0, 0, + 0, 0, 3, 0, 4, 0, 1, 0, -3, 0, -3, 0, 1, 0, 6, 0, 4, 0, 1, 0, -3, 0, -5, + 0, -2, 0, 3, 0, 6, 0, 7, 0, 1, 0, -5, 0, -5, 0, 1, 0, 7, 0, 6, 0, 3, 0, 1, + 0, -2, 0, -5, 0, -5, 0, -2, 0, 3, 0, 3, 0, 3, 0, 0, 0, -3, 0, -5, 0, -3, + 0, 0, 0, 6, 0, 9, 0, 4, 0, -2, 0, -6, 0, -5, 0, -2, 0, 3, 0, 4, 0, 3, 0, + -2, 0, -6, 0, -3, 0, 1, 0, 3, 0, -3, 0, -6, 0, 0, 0, 4, 0, 1, 0, -6, 0, -9, + 0, -5, 0, 1, 0, 1, 0, 0, 0, -2, 0, -3, 0, -5, 0, -6, 0, -5, 0, 0, 0, 3, 0, + 3, 0, -2, 0, -6, 0, -6, 0, -3, 0, -2, 0, -2, 0, -5, 0, -6, 0, -5, 0, -2, + 0, 0, 0, -2, 0, -3, 0, -3, 0, -3, 0, -2, 0, 0, 0, 1, 0, 0, 0, -2, 0, -2, + 0, -3, 0, -5, 0, -5, 0, -2, 0, 0, 0, 3, 0, 3, 0, 0, 0, -3, 0, -3, 0, 0, 0, + -2, 0, -5, 0, -3, 0, 0, 0, 1, 0, -3, 0, -8, 0, -6, 0, -2, 0, -2, 0, -6, 0, + -6, 0, -5, 0, -3, 0, -3, 0, -6, 0, -6, 0, -3, 0, -3, 0, -3, 0, -3, 0, 0, + 0, 1, 0, -3, 0, -6, 0, -3, 0, 1, 0, 0, 0, -6, 0, -9, 0, -9, 0, -6, 0, -2, + 0, 1, 0, 3, 0, -3, 0, -5, 0, -3, 0, -2, 0, -3, 0, -6, 0, -5, 0, -2, 0, -2, + 0, -5, 0, -5, 0, -2, 0, -2, 0, -5, 0, -6, 0, -6, 0, -2, 0, -2, 0, -2, 0, + -3, 0, -5, 0, -5, 0, -3, 0, 1, 0, 0, 0, 1, 0, 1, 0, 3, 0, 6, 0, 6, 0, 3, + 0, -6, 0, -12, 0, -8, 0, 1, 0, 9, 0, 7, 0, 1, 0, -3, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 3, 0, 6, 0, 7, 0, 3, 0, -3, 0, -5, 0, 0, 0, 4, 0, 4, 0, 3, 0, 1, 0, + 3, 0, 3, 0, 0, 0, -2, 0, 0, 0, 1, 0, 1, 0, 1, 0, 3, 0, 3, 0, 1, 0, 0, 0, + 0, 0, 3, 0, 1, 0, -2, 0, -2, 0, 1, 0, 1, 0, -3, 0, -3, 0, 0, 0, 4, 0, 6, + 0, 6, 0, 3, 0, -3, 0, -8, 0, -5, 0, 1, 0, 3, 0, 1, 0, 1, 0, 0, 0, -3, 0, + -6, 0, -5, 0, 1, 0, 3, 0, -2, 0, -3, 0, 0, 0, 1, 0, 1, 0, -3, 0, -5, 0, -2, + 0, -2, 0, -2, 0, 0, 0, 1, 0, 1, 0, -2, 0, -5, 0, -8, 0, -6, 0, -5, 0, -2, + 0, 1, 0, 0, 0, -5, 0, -6, 0, 0, 0, 4, 0, 1, 0, -5, 0, -5, 0, -3, 0, -2, 0, + -3, 0, -3, 0, 0, 0, 0, 0, -2, 0, -3, 0, -2, 0, 1, 0, -2, 0, -5, 0, -3, 0, + 0, 0, 3, 0, 0, 0, -3, 0, -3, 0, -3, 0, -3, 0, -3, 0, 0, 0, 3, 0, 4, 0, -2, + 0, -8, 0, -8, 0, -5, 0, 3, 0, 3, 0, -2, 0, -6, 0, -8, 0, -3, 0, 1, 0, 0, + 0, -5, 0, -5, 0, -2, 0, -2, 0, -3, 0, -5, 0, -3, 0, 0, 0, 0, 0, -2, 0, -5, + 0, -6, 0, -5, 0, -3, 0, 0, 0, 0, 0, -3, 0, -3, 0, -5, 0, -5, 0, -6, 0, -6, + 0, -6, 0, -5, 0, 0, 0, 1, 0, 0, 0, -5, 0, -6, 0, -5, 0, -2, 0, -2, 0, -3, + 0, -5, 0, -8, 0, -9, 0, -6, 0, -2, 0, 0, 0, -2, 0, -5, 0, -5, 0, -2, 0, 3, + 0, 4, 0, 0, 0, -2, 0, -2, 0, 1, 0, 1, 0, 1, 0, 3, 0 + }; + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/spi/AudioFileReader/AIFFLargeHeader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/AIFFLargeHeader.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 4399551 + * @summary Repost of bug candidate: cannot replay aif file. AIFF headers were + * checked for certain size also tests that ulaw encoded AIFC files can + * be read. + */ +public class AIFFLargeHeader { + + public static void main(String args[]) throws Exception { + System.out.println(); + System.out.println(); + System.out.println("4399551: Repost of bug candidate: cannot replay aif file (Review ID: 108108)"); + // try to read this file + AudioSystem.getAudioInputStream(new ByteArrayInputStream(SHORT_AIFC_ULAW)); + System.out.println(" test passed."); + } + + public static String getString(byte b) { + //String res = Integer.toHexString(b & 0xFF).toUpperCase(); + //while (res.length()<2) res="0"+res; + //return res; + return String.valueOf(b); + } + + + public static void printFile(String filename) throws Exception { + File file = new File(filename); + FileInputStream fis = new FileInputStream(file); + byte[] data = new byte[(int) file.length()]; + fis.read(data); + String s = ""; + for (int i=0; i72) { + System.out.println(s); + s=""; + } + } + System.out.println(s); + } + + public static byte[] SHORT_AIFC_ULAW = { + 70, 79, 82, 77, 0, 0, 2, 50, 65, 73, 70, 67, 70, 86, 69, 82, 0, 0, 0, 4, + -94, -128, 81, 64, 67, 79, 77, 77, 0, 0, 0, 30, 0, 1, 0, 1, 118, -9, 0, 16, + 64, 12, -84, 68, 0, 0, 0, 0, 0, 0, 117, 108, 97, 119, 7, 117, 110, 107, 110, + 111, 119, 110, 83, 83, 78, 68, 0, 0, 1, -13, 0, 0, 0, 0, 0, 0, 0, 0, 103, + 103, 103, -1, -1, 91, 77, 103, -45, -25, 91, 77, 73, 73, 77, 103, 103, 77, + 73, 91, -1, -1, 91, 77, 73, 65, 77, -25, -51, -25, 77, 65, 91, -45, -51, + -1, 65, 58, 65, 91, -1, -1, -25, -1, 77, 62, 65, -1, -59, -63, -1, 65, 58, + 65, -1, -51, -59, -45, 103, 77, 77, -1, -59, -59, -25, 77, 91, -25, -59, + -59, -25, 91, 91, -1, -45, -45, -1, 91, 103, -45, -59, -51, -1, 103, 103, + -25, -25, -45, -45, -1, -1, -1, -1, 103, 91, -25, -59, -59, -25, -1, -25, + -1, 103, 103, -45, -51, -1, 77, 91, -25, -51, -51, -1, 103, -25, -25, 103, + 73, 73, 103, -59, -63, -51, -1, 77, 73, 77, -1, -51, -51, -1, 77, 65, 65, + 77, -25, -45, -25, 91, 73, 73, 77, 77, 91, -25, -45, -25, 103, 77, 77, 77, + 91, -45, -59, -59, -1, 91, 91, -1, -25, -1, -45, -51, -1, 91, 77, 103, -25, + 103, 103, -25, -51, -25, 91, 103, -1, -1, 91, 73, 77, -1, -45, -1, 91, 77, + 77, 103, 103, 77, 73, 91, -25, -25, 103, 65, 65, 91, -25, -45, -25, 77, 65, + 73, 103, -45, -51, 103, 77, 73, 91, 103, 103, 103, 103, 91, 77, 73, 77, 103, + -1, -1, 103, 91, 77, 77, 91, 91, 103, 103, -1, -25, -25, -1, -25, -25, 103, + 77, 91, -25, -51, -59, -51, -25, -1, -1, -45, -51, -25, 91, 91, -25, -59, + -51, -25, 91, 77, 103, -45, -59, -63, -25, 77, 77, -25, -63, -59, -45, -25, + 103, 77, 77, 103, -45, -45, -45, -1, 91, 77, 91, -1, -59, -68, -51, 103, + 73, 77, 103, -45, -51, -45, 103, 73, 91, -25, -45, 91, 73, -1, -51, -25, + 73, 62, 77, -25, -25, -1, 103, 91, 77, 73, 77, -1, -45, -45, 103, 73, 73, + 91, 103, 103, 77, 73, 77, 103, -1, 103, 91, 91, 91, 103, -1, -25, -1, 103, + 103, 91, 77, 77, 103, -1, -45, -45, -1, 91, 91, -1, 103, 77, 91, -1, -25, + 91, 65, 73, 103, 103, 73, 73, 77, 91, 91, 73, 73, 91, 91, 91, 91, -1, -25, + 91, 73, 91, -25, -1, 73, 62, 62, 73, 103, -25, -45, 91, 77, 91, 103, 91, + 73, 77, 103, 103, 77, 77, 103, 103, 77, 73, 73, 103, 103, 103, 91, 77, 77, + 91, -25, -1, -25, -25, -45, -59, -59, -45, 73, 56, 65, -25, -68, -63, -25, + 91, -1, -45, -1, -1, -45, -59, -63, -1, 103, 103, -25, -25, 103, 91, -1, + -45, -51, -25, 103, 91, 91, 103, -25, -25, -25, 103, 73, 77, -1, -51, -45, + 103, 91, 103, -25, -1, 91, 91, 91, -1, -45, -51, -25, 91, 77, 103, -1, -1, + 91, -1, -1, -1, 103, 91, 91, 73, 77, 103, -25, -25, 103, 91, 103, 103, 103, + -1, -45, -1, 77, 77, -1 + }; + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/spi/AudioFileReader/Aiff12bit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/Aiff12bit.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 4895934 + * @summary AudioInputStream.getFrameLength returns wrong value for 12-bit AIFF + * file + */ +public class Aiff12bit { + + public static void test(byte[] file) throws Exception { + InputStream inputStream = new ByteArrayInputStream(file); + AudioFileFormat aff = AudioSystem.getAudioFileFormat(inputStream); + + if (aff.getFormat().getSampleSizeInBits() != 12) { + throw new Exception("Wrong sample size. test FAILED"); + } + if (aff.getFormat().getFrameSize() != 2) { + throw new Exception("Wrong frame size. test FAILED"); + } + if (aff.getFrameLength() != 100) { + throw new Exception("Wrong file length. test FAILED"); + } + } + + public static void main(String[] args) throws Exception { + test(AIFF_12BIT); + + System.out.println("Test passed."); + } + + public static byte[] AIFF_12BIT = { + 70, 79, 82, 77, 0, 0, 0, -10, 65, 73, 70, 70, 67, 79, 77, 77, + 0, 0, 0, 18, 0, 1, 0, 0, 0, 100, 0, 12, 64, 8, -6, 0, + 0, 0, 0, 0, 0, 0, 83, 83, 78, 68, 0, 0, 0, -48, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 32, 0, 48, 0, 64, + 0, 80, 0, 96, 0, 112, 0, -128, 0, -112, 0, -96, 0, -80, 0, -64, + 0, -48, 0, -32, 0, -16, 1, 0, 1, 16, 1, 32, 1, 48, 1, 64, + 1, 80, 1, 96, 1, 112, 1, -128, 1, -112, 1, -96, 1, -80, 1, -64, + 1, -48, 1, -32, 1, -16, 2, 0, 2, 16, 2, 32, 2, 48, 2, 64, + 2, 80, 2, 96, 2, 112, 2, -128, 2, -112, 2, -96, 2, -80, 2, -64, + 2, -48, 2, -32, 2, -16, 3, 0, 3, 16, 3, 32, 3, 48, 3, 64, + 3, 80, 3, 96, 3, 112, 3, -128, 3, -112, 3, -96, 3, -80, 3, -64, + 3, -48, 3, -32, 3, -16, 4, 0, 4, 16, 4, 32, 4, 48, 4, 64, + 4, 80, 4, 96, 4, 112, 4, -128, 4, -112, 4, -96, 4, -80, 4, -64, + 4, -48, 4, -32, 4, -16, 5, 0, 5, 16, 5, 32, 5, 48, 5, 64, + 5, 80, 5, 96, 5, 112, 5, -128, 5, -112, 5, -96, 5, -80, 5, -64, + 5, -48, 5, -32, 5, -16, 6, 0, 6, 16, 6, 32, 6, 48, + }; + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/spi/AudioFileReader/AuNotSpecified.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/AuNotSpecified.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 4940459 + * @summary AudioInputStream.getFrameLength() returns 0 instead of NOT_SPECIFIED + */ +public class AuNotSpecified { + public static boolean failed = false; + + public static void main(String[] params) throws Exception { + + AudioInputStream is = + AudioSystem.getAudioInputStream(new + ByteArrayInputStream(new byte[] { + (byte)0x2E, (byte)0x73, (byte)0x6E, (byte)0x64, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x18, + (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x03, + (byte)0x00, (byte)0x00, (byte)0x1F, (byte)0x40, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, + })); + if (is.getFrameLength() != AudioSystem.NOT_SPECIFIED) { + System.out.println("frame length should be NOT_SPECIFIED, but is: "+is.getFrameLength()); + failed=true; + } + //assertTrue(is.getFrameLength() == AudioSystem.NOT_SPECIFIED); + //assertTrue(is.read(new byte[8]) == 8); + //assertTrue(is.read(new byte[2]) == -1); + if (failed) throw new Exception("Test FAILED!"); + System.out.println("Test Passed."); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/spi/AudioFileReader/AuZeroLength.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/AuZeroLength.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 4629669 + * @summary AU file reader: problems with empty files + */ +public class AuZeroLength { + + public static String getString(byte b) { + //String res = Integer.toHexString(b & 0xFF).toUpperCase(); + //while (res.length()<2) res="0"+res; + //return res; + return String.valueOf(b); + } + + + public static void printFile(String filename) throws Exception { + File file = new File(filename); + FileInputStream fis = new FileInputStream(file); + byte[] data = new byte[(int) file.length()]; + fis.read(data); + String s = ""; + for (int i=0; i72) { + System.out.println(s); + s=""; + } + } + System.out.println(s); + } + + public static void test(byte[] file) throws Exception { + InputStream inputStream = new ByteArrayInputStream(file); + AudioFileFormat aff = AudioSystem.getAudioFileFormat(inputStream); + + if (aff.getFrameLength() != 0) { + throw new Exception("File length is "+aff.getFrameLength()+" instead of 0. test FAILED"); + } + System.out.println(aff.getType()+" file length is 0."); + } + + public static void main(String[] args) throws Exception { + test(ZERO_AU); + test(ZERO_WAV); + test(ZERO_AIFF); + + System.out.println("Test passed."); + } + + public static byte[] ZERO_AU = { + 46, 115, 110, 100, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, -84, 68, 0, + 0, 0, 1, 116, 101, 115, 116, 46, 119, 97, 118 + }; + + public static byte[] ZERO_WAV = { + 82, 73, 70, 70, 36, 0, 0, 0, 87, 65, 86, 69, 102, 109, 116, 32, 16, 0, 0, + 0, 1, 0, 1, 0, 68, -84, 0, 0, -120, 88, 1, 0, 2, 0, 16, 0, 100, 97, 116, + 97, 0, 0, 0, 0 + }; + + public static byte[] ZERO_AIFF = { + 70, 79, 82, 77, 0, 0, 0, 46, 65, 73, 70, 70, 67, 79, 77, 77, 0, 0, 0, 18, + 0, 1, 0, 0, 0, 0, 0, 16, 64, 14, -84, 68, 0, 0, 0, 0, 0, 0, 83, 83, 78, 68, + 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0 + }; + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/spi/AudioFileReader/OpenWaveFile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/OpenWaveFile.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.URL; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 4489272 + * @summary AudioSystem.getAudioFileFormat() fails for InputStream, but works + * for URL + */ +public class OpenWaveFile { + + static void check(Object source) throws Exception { + AudioFileFormat aff2 = null; + if (source instanceof File) { + aff2 = AudioSystem.getAudioFileFormat((File) source); + } + else if (source instanceof InputStream) { + aff2 = AudioSystem.getAudioFileFormat((InputStream) source); + } + else if (source instanceof URL) { + aff2 = AudioSystem.getAudioFileFormat((URL) source); + } else throw new Exception("wrong source. Test FAILED"); + System.out.println("Got: "+aff2); + if (aff2.getFormat().getSampleSizeInBits()==-1) { + throw new Exception("wrong audio format. Test FAILED"); + } + } + + public static void main(String args[]) throws Exception { + //check(new File(args[0])); + //check(new URL("file", "", args[0])); + check(new ByteArrayInputStream(SHORT_AU)); + check(new ByteArrayInputStream(SHORT_WAVE)); + check(new ByteArrayInputStream(SHORT_AIFF)); + System.out.println("Test passed."); + + //printFile(args[0]); + } + + public static String getString(byte b) { + //String res = Integer.toHexString(b & 0xFF).toUpperCase(); + //while (res.length()<2) res="0"+res; + //return res; + return String.valueOf(b); + } + + + public static void printFile(String filename) throws Exception { + File file = new File(filename); + FileInputStream fis = new FileInputStream(file); + byte[] data = new byte[(int) file.length()]; + fis.read(data); + String s = ""; + for (int i=0; i72) { + System.out.println(s); + s=""; + } + } + System.out.println(s); + } + + public static byte[] SHORT_WAVE = { + 82, 73, 70, 70, -120, 0, 0, 0, 87, 65, 86, 69, 102, 109, 116, 32, 16, 0, + 0, 0, 1, 0, 1, 0, 34, 86, 0, 0, 34, 86, 0, 0, 1, 0, 8, 0, 100, 97, 116, 97, + 100, 0, 0, 0, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, + -128, -128, -128, -128, -128, -128, -128, -128, -128, 127, 127, -128, 127, + 127, 127, -128, -128, -128, -128, 127, 127, -128, -128, 127, -128, -128, + -128, 127, 127, 127, -128, -128, -128, 127, 127, 127, 127, -128, -128, -128, + -128, -128, -128, 127, 127, 127, -128, -128, -128, -128, -128, 127, -128, + -128, 127, -128, -128, 127, 127, -128, -128, 127, 127, -128, -128, -128, + -128, -128, 127, 127, -128, -128, -128, 127, 127, 127, -128, 127, -128, -128, + 127, 127, 127, -128, -128, -128, 127, 127, -128, -128, + }; + + public static byte[] SHORT_AU = { + 46, 115, 110, 100, 0, 0, 0, 24, 0, 0, 0, 100, 0, 0, 0, 2, 0, 0, 86, 34, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, + 0, -1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, -1, 0, 0, 0, -1, -1, -1, 0, 0, 0, + -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, -1, -1, -1, 0, 0, 0, 0, 0, -1, 0, 0, -1, + 0, 0, -1, -1, 0, 0, -1, -1, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, -1, -1, -1, 0, + -1, 0, 0, -1, -1, -1, 0, 0, 0, -1, -1, 0, 0, + }; + + public static byte[] SHORT_AIFF = { + 70, 79, 82, 77, 0, 0, 0, -110, 65, 73, 70, 70, 67, 79, 77, 77, 0, 0, 0, 18, + 0, 1, 0, 0, 0, 100, 0, 8, 64, 13, -84, 68, 0, 0, 0, 0, 0, 0, 83, 83, 78, + 68, 0, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, -1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, + -1, 0, 0, 0, -1, -1, -1, 0, 0, 0, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, -1, -1, + -1, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, -1, 0, 0, -1, -1, 0, 0, 0, 0, + 0, -1, -1, 0, 0, 0, -1, -1, -1, 0, -1, 0, 0, -1, -1, -1, 0, 0, 0, -1, -1, + 0, 0, + }; +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/spi/AudioFileWriter/AUwithULAW.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/AUwithULAW.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 4391108 + * @summary Writing au files with ulaw encoding is broken + */ +public class AUwithULAW { + public static void main(String args[]) throws Exception { + System.out.println(); + System.out.println(); + System.out.println("4391108: Writing au files with ulaw encoding is broken"); + byte[] fakedata=new byte[1234]; + InputStream is = new ByteArrayInputStream(fakedata); + AudioFormat inFormat = new AudioFormat(AudioFormat.Encoding.ULAW, 8000, 8, 1, 1, 8000, false); + + AudioInputStream ais = new AudioInputStream(is, inFormat, fakedata.length); + + ByteArrayOutputStream out = new ByteArrayOutputStream(1500); + System.out.println(" ulaw data will be written as AU to stream..."); + int t = AudioSystem.write(ais, AudioFileFormat.Type.AU, out); + byte[] writtenData = out.toByteArray(); + is = new ByteArrayInputStream(writtenData); + System.out.println(" Get AudioFileFormat of written file"); + AudioFileFormat fileformat = AudioSystem.getAudioFileFormat(is); + AudioFileFormat.Type type = fileformat.getType(); + System.out.println(" The file format type: "+type); + if (fileformat.getFrameLength()!=fakedata.length + && fileformat.getFrameLength()!=AudioSystem.NOT_SPECIFIED) { + throw new Exception("The written file's frame length is "+fileformat.getFrameLength()+" but should be "+fakedata.length+" !"); + } + ais = AudioSystem.getAudioInputStream(is); + System.out.println(" Got Stream with format: "+ais.getFormat()); + System.out.println(" test passed."); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/spi/AudioFileWriter/AiffSampleRate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/AiffSampleRate.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 4914639 + * @summary JavaSound writes wrong sample rates to AIFF files + */ +public class AiffSampleRate { + + private static final float[] testSampleRates = + {8000.0F, 8000.0F + 0.011F, 8193.975F, 10000.0F, 11025.0F, 12000.0F, + 16000.0F, 22050.0F, 24000.0F, 32000.0F, 44100.0F - 1.22222F, 44100.0F, + 47888.888F, 48000.0F, 96000.0F, 192000.0F}; + + public static void main(String[] args) throws Exception { + boolean isTestPassed = true; + + out("#4914639: JavaSound writes wrong sample rates to AIFF files"); + for (int i = 0; i < testSampleRates.length; i++) { + isTestPassed &= testSampleRate(testSampleRates[i]); + } + if (isTestPassed) { + out("Test PASSED."); + } else { + throw new Exception("Test FAILED."); + } + } + + private static boolean testSampleRate(float sampleRate) { + boolean result = true; + + try { + // create AudioInputStream with sample rate of 10000 Hz + ByteArrayInputStream data = new ByteArrayInputStream(new byte[1]); + AudioFormat format = new AudioFormat(sampleRate, 8, 1, true, true); + AudioInputStream stream = new AudioInputStream(data, format, 1); + + // write to AIFF file + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + AudioSystem.write(stream, AudioFileFormat.Type.AIFF, outputStream); + byte[] fileData = outputStream.toByteArray(); + InputStream inputStream = new ByteArrayInputStream(fileData); + AudioFileFormat aff = AudioSystem.getAudioFileFormat(inputStream); + if (! equals(sampleRate, aff.getFormat().getFrameRate())) { + out("error for sample rate " + sampleRate); + result = false; + } + } catch (Exception e) { + out(e); + out("Test NOT FAILED"); + } + return result; + } + + private static boolean equals(float f1, float f2) { + return Math.abs(f2 - f1) < 1.0E-9; + } + + private static void out(Throwable t) { + t.printStackTrace(System.out); + } + + private static void out(String message) { + System.out.println(message); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/spi/AudioFileWriter/RIFFHeader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/RIFFHeader.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 4636355 + * @summary Check that RIFF headers are written with extra data length field. + */ +public class RIFFHeader { + + public static void main(String args[]) throws Exception { + System.out.println(); + System.out.println(); + System.out.println("4636355: Check that RIFF headers are written with extra data length field."); + byte[] fakedata=new byte[1234]; + MyByteArrayInputStream is = new MyByteArrayInputStream(fakedata); + AudioFormat inFormat = new AudioFormat(AudioFormat.Encoding.ULAW, 8000, 8, 1, 1, 8000, true); + + AudioInputStream ais = new AudioInputStream((InputStream) is, inFormat, fakedata.length); + ByteArrayOutputStream out = new ByteArrayOutputStream(1500); + System.out.println(" ulaw data will be written as WAVE to stream..."); + int t = AudioSystem.write(ais, AudioFileFormat.Type.WAVE, out); + byte[] writtenData = out.toByteArray(); + // now header must have at least 46 bytes + System.out.println(" Length should be "+(fakedata.length+46)+" bytes: "+writtenData.length); + // re-read this file + is = new MyByteArrayInputStream(writtenData); + System.out.println(" Get AudioFileFormat of written file"); + AudioFileFormat fileformat = AudioSystem.getAudioFileFormat(is); + AudioFileFormat.Type type = fileformat.getType(); + System.out.println(" The file format type: "+type); + if (fileformat.getFrameLength()!=fakedata.length + && fileformat.getFrameLength()!=AudioSystem.NOT_SPECIFIED) { + throw new Exception("The written file's frame length is "+fileformat.getFrameLength()+" but should be "+fakedata.length+" !"); + } + ais = AudioSystem.getAudioInputStream(is); + System.out.println(" Got Stream with format: "+ais.getFormat()); + if (is.getPos()<46) { + throw new Exception("After reading the header, stream position must be at least 46, but is "+is.getPos()+" !"); + } + System.out.println(" test passed."); + } + + static class MyByteArrayInputStream extends ByteArrayInputStream { + + MyByteArrayInputStream(byte[] data) { + super(data); + } + + int getPos() { + return pos; + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/spi/AudioFileWriter/WaveBigEndian.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/WaveBigEndian.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 5001952 + * @summary Writing WAVE with big endian data produces corrupt file. WAVE should + * always write signed 16-bit, little endian, regardless of the + * endianness of the input data. + */ +public class WaveBigEndian { + + static boolean failed = false; + + public static byte[] writeDataAndGetAIS(boolean bigEndian) throws Exception { + if (bigEndian) { + out("Create WAVE file from big endian data..."); + } else { + out("Create WAVE file from little endian data..."); + } + byte[] data = new byte[3000]; + for (int i = 0; i < data.length; i+=2) { + if (bigEndian) { + data[i] = (byte) i; + data[i+1] = (byte) (i+1); + } else { + data[i] = (byte) (i+1); + data[i+1] = (byte) i; + } + } + AudioFormat format = new AudioFormat(44100.0f, 16, 1, true, bigEndian); + InputStream is = new ByteArrayInputStream(data); + AudioInputStream ais = new AudioInputStream(is, format, data.length); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + int written = AudioSystem.write(ais, AudioFileFormat.Type.WAVE, os); + data = os.toByteArray(); + out("Wrote "+written+" bytes, got "+data.length+" bytes in written file."); + is = new ByteArrayInputStream(data); + ais = AudioSystem.getAudioInputStream(is); + out("Got AIS with length = "+ais.getFrameLength()+" frames."); + return data; + } + + + public static void main(String args[]) throws Exception { + byte[] data1 = writeDataAndGetAIS(false); + byte[] data2 = writeDataAndGetAIS(true); + + if (data1.length != data2.length) { + out("# data1.length != data2.length!"); + failed = true; + } else { + for (int i = 0 ; i < data1.length; i++) { + if (data1[i] != data2[i]) { + out("# At index "+i+": le="+(data1[i] & 0xFF)+" be="+(data2[i] & 0xFF)+" !"); + failed = true; + } + } + } + + if (failed) throw new Exception("Test FAILED!"); + out("Files are identical."); + out("test passed"); + } + + static void out(String s) { + System.out.println(s); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/spi/AudioFileWriter/WriteAuUnspecifiedLength.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/WriteAuUnspecifiedLength.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 4351296 + * @summary Cannot write AudioInputStream with unspecified length + */ +public class WriteAuUnspecifiedLength { + + public static void main(String argv[]) throws Exception { + AudioFormat format = new AudioFormat(44100, 16, 2, true, true); + InputStream is = new ByteArrayInputStream(new byte[1000]); + AudioInputStream ais = new AudioInputStream(is, format, AudioSystem.NOT_SPECIFIED); + AudioSystem.write(ais, AudioFileFormat.Type.AU, new ByteArrayOutputStream()); + System.out.println("Test passed."); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/sound/sampled/spi/FormatConversionProvider/AlawUlaw.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/sampled/spi/FormatConversionProvider/AlawUlaw.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; + +/** + * @test + * @bug 4714846 + * @summary JavaSound ULAW (8-bit) encoder erroneously depends on endian-ness + */ +public class AlawUlaw { + static ByteArrayInputStream in; + static int byteLength = 1000; + + static boolean failed = false; + + public static void main(String[] args) throws Exception { + // generate some random data + byte[] soundData = new byte[byteLength]; + for (int i=0; i { - scroll.getViewport().addChangeListener((e) -> cnt++); Insets insets = scroll.getInsets(); scroll.setSize(insets.left + insets.right + scroll.getVerticalScrollBar().getPreferredSize().width, 50); scroll.revalidate(); }); - + robot.delay(200); + SwingUtilities.invokeAndWait(() -> + scroll.getViewport().addChangeListener((e) -> cnt++)); robot.delay(1000); SwingUtilities.invokeLater(frame::dispose); - if (cnt > 2) { + if (cnt > 0) { throw new RuntimeException("Scroll bar flickers"); } } diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/swing/ToolTipManager/7123767/bug7123767.java --- a/jdk/test/javax/swing/ToolTipManager/7123767/bug7123767.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/javax/swing/ToolTipManager/7123767/bug7123767.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. 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 @@ -23,12 +23,25 @@ /* * @test - * @key headful - * @bug 7123767 - * @summary Wrong tooltip location in Multi-Monitor configurations - * @author Vladislav Karnaukhov - * @modules java.desktop/sun.awt - * @run main bug7123767 + * @bug 7123767 + * + * @summary Check if a tooltip location in Multi-Monitor + * configurations is correct. + * If the configurations number per device exceeds 5, + * then some 5 random configurations will be checked. + * Please Use -Dseed=X to set the random generator seed + * (if necessary). + * + * @author Vladislav Karnaukhov + * + * @key headful + * @key randomness + * + * @modules java.desktop/sun.awt + * @library /lib/testlibrary/ + * @build jdk.testlibrary.* + * + * @run main/timeout=300 bug7123767 */ import javax.swing.*; @@ -37,8 +50,50 @@ import java.awt.event.MouseEvent; import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Random; + +import jdk.testlibrary.RandomFactory; + + public class bug7123767 extends JFrame { + // maximum number of GraphicsConfigurations checked per GraphicsDevice + private static final int MAX_N_CONFIGS = 5; + private static final List CONFIGS = getConfigs(); + + private static List getConfigs() { + + Random rnd = RandomFactory.getRandom(); + + List configs = new ArrayList<>(); + + GraphicsEnvironment ge = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice[] devices = ge.getScreenDevices(); + + for (GraphicsDevice device : devices) { + GraphicsConfiguration[] allConfigs = device.getConfigurations(); + int nConfigs = allConfigs.length; + if (nConfigs <= MAX_N_CONFIGS) { + Collections.addAll(configs, allConfigs); + } else { // see JDK-8159454 + System.out.println("check only " + MAX_N_CONFIGS + + " configurations for device " + device); + configs.add(device.getDefaultConfiguration()); // check default + for (int j = 0; j < MAX_N_CONFIGS - 1; j++) { + int k = rnd.nextInt(nConfigs); + configs.add(allConfigs[k]); + } + } + } + + return configs; + } + + private static class TestFactory extends PopupFactory { private static TestFactory newFactory = new TestFactory(); @@ -62,15 +117,21 @@ } // Actual test happens here + @Override public Popup getPopup(Component owner, Component contents, int x, int y) { - GraphicsConfiguration mouseGC = testGC(MouseInfo.getPointerInfo().getLocation()); + + GraphicsConfiguration mouseGC = + testGC(MouseInfo.getPointerInfo().getLocation()); + if (mouseGC == null) { - throw new RuntimeException("Can't find GraphicsConfiguration that mouse pointer belongs to"); + throw new RuntimeException("Can't find GraphicsConfiguration " + + "that mouse pointer belongs to"); } GraphicsConfiguration tipGC = testGC(new Point(x, y)); if (tipGC == null) { - throw new RuntimeException("Can't find GraphicsConfiguration that tip belongs to"); + throw new RuntimeException( + "Can't find GraphicsConfiguration that tip belongs to"); } if (!mouseGC.equals(tipGC)) { @@ -81,17 +142,14 @@ } private static GraphicsConfiguration testGC(Point pt) { - GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment(); - GraphicsDevice[] devices = environment.getScreenDevices(); - for (GraphicsDevice device : devices) { - GraphicsConfiguration[] configs = device.getConfigurations(); - for (GraphicsConfiguration config : configs) { - Rectangle rect = config.getBounds(); - Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(config); - adjustInsets(rect, insets); - if (rect.contains(pt)) - return config; - } + + for (GraphicsConfiguration config: CONFIGS) { + + Rectangle rect = config.getBounds(); + Insets insets = + Toolkit.getDefaultToolkit().getScreenInsets(config); + adjustInsets(rect, insets); + if (rect.contains(pt)) { return config; } } return null; @@ -103,15 +161,18 @@ private static Robot robot; public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel(new MetalLookAndFeel()); setUp(); testToolTip(); TestFactory.uninstall(); + if (frame != null) { frame.dispose(); } } // Creates a window that is stretched across all available monitors // and adds itself as ContainerListener to track tooltips drawing private bug7123767() { + super(); ToolTipManager.sharedInstance().setInitialDelay(0); @@ -135,17 +196,16 @@ pack(); Rectangle rect = new Rectangle(); - GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment(); - GraphicsDevice[] devices = environment.getScreenDevices(); - for (GraphicsDevice device : devices) { - GraphicsConfiguration[] configs = device.getConfigurations(); - for (GraphicsConfiguration config : configs) { - Insets localInsets = Toolkit.getDefaultToolkit().getScreenInsets(config); - Rectangle localRect = config.getBounds(); - adjustInsets(localRect, localInsets); - rect.add(localRect); - } + + for (GraphicsConfiguration config: CONFIGS) { + + Insets localInsets = + Toolkit.getDefaultToolkit().getScreenInsets(config); + Rectangle localRect = config.getBounds(); + adjustInsets(localRect, localInsets); + rect.add(localRect); } + setBounds(rect); } @@ -166,35 +226,32 @@ robot.setAutoDelay(20); robot.waitForIdle(); - GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment(); - GraphicsDevice[] devices = environment.getScreenDevices(); - for (GraphicsDevice device : devices) { - GraphicsConfiguration[] configs = device.getConfigurations(); - for (GraphicsConfiguration config : configs) { - Rectangle rect = config.getBounds(); - Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(config); - adjustInsets(rect, insets); + for (GraphicsConfiguration config: CONFIGS) { - // Upper left - glide(rect.x + rect.width / 2, rect.y + rect.height / 2, - rect.x + MARGIN, rect.y + MARGIN); - robot.waitForIdle(); + Rectangle rect = config.getBounds(); + Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(config); + adjustInsets(rect, insets); + + // Upper left + glide(rect.x + rect.width / 2, rect.y + rect.height / 2, + rect.x + MARGIN, rect.y + MARGIN); + robot.waitForIdle(); - // Lower left - glide(rect.x + rect.width / 2, rect.y + rect.height / 2, - rect.x + MARGIN, rect.y + rect.height - MARGIN); - robot.waitForIdle(); + // Lower left + glide(rect.x + rect.width / 2, rect.y + rect.height / 2, + rect.x + MARGIN, rect.y + rect.height - MARGIN); + robot.waitForIdle(); - // Upper right - glide(rect.x + rect.width / 2, rect.y + rect.height / 2, - rect.x + rect.width - MARGIN, rect.y + MARGIN); - robot.waitForIdle(); + // Upper right + glide(rect.x + rect.width / 2, rect.y + rect.height / 2, + rect.x + rect.width - MARGIN, rect.y + MARGIN); + robot.waitForIdle(); - // Lower right - glide(rect.x + rect.width / 2, rect.y + rect.height / 2, - rect.x + rect.width - MARGIN, rect.y + rect.height - MARGIN); - robot.waitForIdle(); - } + // Lower right + glide(rect.x + rect.width / 2, rect.y + rect.height / 2, + rect.x + rect.width - MARGIN, rect.y + rect.height - MARGIN); + + robot.waitForIdle(); } } diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 8166591 + * @key headful + * @summary [macos 10.12] Trackpad scrolling of text on OS X 10.12 Sierra + * is very fast (Trackpad, Retina only) + * @run main/manual/othervm TooMuchWheelRotationEventsTest + */ +public class TooMuchWheelRotationEventsTest { + + private static volatile boolean testResult = false; + private static volatile CountDownLatch countDownLatch; + private static final String INSTRUCTIONS = "INSTRUCTIONS:\n" + + "Try to check the issue on Mac OS X 10.12 Sierra with trackpad" + + " on Retina display.\n" + + "\n" + + "If the trackpad is not supported, press PASS\n" + + "\n" + + "Use the trackpad to slightly scroll the JTextArea horizontally and vertically.\n" + + "If the text area is scrolled too fast press FAIL, else press PASS."; + + public static void main(String args[]) throws Exception { + countDownLatch = new CountDownLatch(1); + + SwingUtilities.invokeLater(TooMuchWheelRotationEventsTest::createUI); + countDownLatch.await(15, TimeUnit.MINUTES); + + if (!testResult) { + throw new RuntimeException("Test fails!"); + } + } + + private static void createUI() { + + final JFrame mainFrame = new JFrame("Trackpad scrolling test"); + GridBagLayout layout = new GridBagLayout(); + JPanel mainControlPanel = new JPanel(layout); + JPanel resultButtonPanel = new JPanel(layout); + + GridBagConstraints gbc = new GridBagConstraints(); + + JPanel testPanel = createTestPanel(); + + gbc.gridx = 0; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + mainControlPanel.add(testPanel, gbc); + + JTextArea instructionTextArea = new JTextArea(); + instructionTextArea.setText(INSTRUCTIONS); + instructionTextArea.setEditable(false); + instructionTextArea.setBackground(Color.white); + + gbc.gridx = 0; + gbc.gridy = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + mainControlPanel.add(instructionTextArea, gbc); + + JButton passButton = new JButton("Pass"); + passButton.setActionCommand("Pass"); + passButton.addActionListener((ActionEvent e) -> { + testResult = true; + mainFrame.dispose(); + countDownLatch.countDown(); + + }); + + JButton failButton = new JButton("Fail"); + failButton.setActionCommand("Fail"); + failButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + mainFrame.dispose(); + countDownLatch.countDown(); + } + }); + + gbc.gridx = 0; + gbc.gridy = 0; + resultButtonPanel.add(passButton, gbc); + + gbc.gridx = 1; + gbc.gridy = 0; + resultButtonPanel.add(failButton, gbc); + + gbc.gridx = 0; + gbc.gridy = 2; + mainControlPanel.add(resultButtonPanel, gbc); + + mainFrame.add(mainControlPanel); + mainFrame.pack(); + + mainFrame.addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + mainFrame.dispose(); + countDownLatch.countDown(); + } + }); + mainFrame.setVisible(true); + } + + private static JPanel createTestPanel() { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + JTextArea textArea = new JTextArea(20, 20); + textArea.setText(getLongString()); + JScrollPane scrollPane = new JScrollPane(textArea); + panel.add(scrollPane); + return panel; + } + + private static String getLongString() { + + String lowCaseString = getLongString('a', 'z'); + String upperCaseString = getLongString('A', 'Z'); + String digitsString = getLongString('0', '9'); + + int repeat = 30; + StringBuilder lowCaseBuilder = new StringBuilder(); + StringBuilder upperCaseBuilder = new StringBuilder(); + StringBuilder digitsBuilder = new StringBuilder(); + + for (int i = 0; i < repeat; i++) { + lowCaseBuilder.append(lowCaseString).append(' '); + upperCaseBuilder.append(upperCaseString).append(' '); + digitsBuilder.append(digitsString).append(' '); + } + + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < 200; i++) { + builder.append(upperCaseBuilder).append('\n') + .append(lowCaseBuilder).append('\n') + .append(digitsBuilder).append("\n\n\n"); + } + + return builder.toString(); + } + + private static String getLongString(char c1, char c2) { + + char[] chars = new char[c2 - c1 + 1]; + for (char i = c1; i <= c2; i++) { + chars[i - c1] = i; + } + return new String(chars); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/swing/plaf/motif/8165485/MotifHiDPIIconsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/plaf/motif/8165485/MotifHiDPIIconsTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.ScrollPaneConstants; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 8165485 + * @summary Bad rendering of Swing UI controls with Motif L&F on HiDPI display + * @run main/manual/othervm -Dsun.java2d.uiScale=2 + * -Dswing.defaultlaf=com.sun.java.swing.plaf.motif.MotifLookAndFeel MotifHiDPIIconsTest + */ +public class MotifHiDPIIconsTest { + + private static volatile boolean testResult = false; + private static volatile CountDownLatch countDownLatch; + private static final String INSTRUCTIONS = "INSTRUCTIONS:\n" + + "Check that the icons are painted smoothly on Swing UI controls:\n" + + " - JRadioButton\n" + + " - JCheckBox\n" + + " - JComboBox\n" + + " - JScrollPane (vertical and horizontal scroll bars)\n" + + "\n" + + "If so, press PASS, else press FAIL.\n"; + + public static void main(String args[]) throws Exception { + countDownLatch = new CountDownLatch(1); + + SwingUtilities.invokeLater(MotifHiDPIIconsTest::createUI); + countDownLatch.await(15, TimeUnit.MINUTES); + + if (!testResult) { + throw new RuntimeException("Test fails!"); + } + } + + private static void createUI() { + + final JFrame mainFrame = new JFrame("Motif L&F icons test"); + GridBagLayout layout = new GridBagLayout(); + JPanel mainControlPanel = new JPanel(layout); + JPanel resultButtonPanel = new JPanel(layout); + + GridBagConstraints gbc = new GridBagConstraints(); + + + JPanel testPanel = createJPanel(); + + gbc.gridx = 0; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + mainControlPanel.add(testPanel, gbc); + + JTextArea instructionTextArea = new JTextArea(); + instructionTextArea.setText(INSTRUCTIONS); + instructionTextArea.setEditable(false); + instructionTextArea.setBackground(Color.white); + + gbc.gridx = 0; + gbc.gridy = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + mainControlPanel.add(instructionTextArea, gbc); + + JButton passButton = new JButton("Pass"); + passButton.setActionCommand("Pass"); + passButton.addActionListener((ActionEvent e) -> { + testResult = true; + mainFrame.dispose(); + countDownLatch.countDown(); + + }); + + JButton failButton = new JButton("Fail"); + failButton.setActionCommand("Fail"); + failButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + mainFrame.dispose(); + countDownLatch.countDown(); + } + }); + + gbc.gridx = 0; + gbc.gridy = 0; + resultButtonPanel.add(passButton, gbc); + + gbc.gridx = 1; + gbc.gridy = 0; + resultButtonPanel.add(failButton, gbc); + + gbc.gridx = 0; + gbc.gridy = 2; + mainControlPanel.add(resultButtonPanel, gbc); + + mainFrame.add(mainControlPanel); + mainFrame.pack(); + + mainFrame.addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + mainFrame.dispose(); + countDownLatch.countDown(); + } + }); + mainFrame.setVisible(true); + } + + private static JPanel createJPanel() { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + + JPanel iconPanel = new JPanel(new FlowLayout()); + JRadioButton radioButton = new JRadioButton(); + radioButton.setSelected(false); + iconPanel.add(radioButton); + radioButton = new JRadioButton(); + radioButton.setSelected(true); + iconPanel.add(radioButton); + panel.add(iconPanel); + + iconPanel = new JPanel(new FlowLayout()); + JCheckBox checkBox = new JCheckBox(); + checkBox.setSelected(false); + iconPanel.add(checkBox); + checkBox = new JCheckBox(); + checkBox.setSelected(true); + iconPanel.add(checkBox); + panel.add(iconPanel); + + iconPanel = new JPanel(new FlowLayout()); + JComboBox comboBox = new JComboBox(new String[]{"111", "222"}); + iconPanel.add(comboBox); + panel.add(iconPanel); + + iconPanel = new JPanel(new FlowLayout()); + JTextArea textArea = new JTextArea(3, 7); + textArea.setText("AAA"); + JScrollPane scrollPane = new JScrollPane(textArea); + scrollPane.setHorizontalScrollBarPolicy( + ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); + scrollPane.setVerticalScrollBarPolicy( + ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); + iconPanel.add(scrollPane); + panel.add(iconPanel); + + return panel; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/swing/text/CSSBorder/6796710/bug6796710.java --- a/jdk/test/javax/swing/text/CSSBorder/6796710/bug6796710.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/javax/swing/text/CSSBorder/6796710/bug6796710.java Fri Nov 11 16:44:36 2016 +0100 @@ -24,11 +24,10 @@ /* * @test * @key headful - * @bug 6796710 7124242 + * @bug 6796710 7124242 8168540 * @summary Html content in JEditorPane is overlapping on swing components while resizing the application. * @library ../../../regtesthelpers * @build Util - * @author Pavel Porvatov @run main bug6796710 */ @@ -109,7 +108,7 @@ } }); - robot.waitForIdle(); + robot.delay(1000); // On Linux platforms realSync doesn't guaranties setSize completion Thread.sleep(1000); diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/swing/text/Caret/8163124/CaretFloatingPointAPITest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/text/Caret/8163124/CaretFloatingPointAPITest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.geom.Line2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.TextUI; +import javax.swing.text.BadLocationException; +import javax.swing.text.Caret; +import javax.swing.text.DefaultHighlighter; +import javax.swing.text.Document; +import javax.swing.text.Highlighter; +import javax.swing.text.JTextComponent; +import javax.swing.text.Position; + +/* + * @test + * @bug 8163175 + * @summary PlainView.modelToView() method should return Rectangle2D + * @run main/manual CaretFloatingPointAPITest + */ +public class CaretFloatingPointAPITest { + + private static volatile boolean testResult = false; + private static volatile CountDownLatch countDownLatch; + private static final String INSTRUCTIONS = "INSTRUCTIONS:\n\n" + + "Verify that cursor position is not rounded on HiDPI display.\n\n" + + "If the display does not support HiDPI mode press PASS.\n\n" + + "1. Press the Right-Arrow key several times to move the red caret" + + " in the text field.\n" + + "2. Check that the caret has the same position between chars" + + " in diffrent locations.\n\n" + + "If so, press PASS, else press FAIL.\n"; + + public static void main(String args[]) throws Exception { + countDownLatch = new CountDownLatch(1); + + SwingUtilities.invokeLater(CaretFloatingPointAPITest::createUI); + countDownLatch.await(15, TimeUnit.MINUTES); + + if (!testResult) { + throw new RuntimeException("Test fails!"); + } + } + + private static void createUI() { + + final JFrame mainFrame = new JFrame("Metal L&F icons test"); + GridBagLayout layout = new GridBagLayout(); + JPanel mainControlPanel = new JPanel(layout); + JPanel resultButtonPanel = new JPanel(layout); + + GridBagConstraints gbc = new GridBagConstraints(); + + JTextField textField = new JTextField("aaaaaaaaaaaaaaaaaaaaaaa"); + Dimension size = new Dimension(400, 100); + textField.setPreferredSize(size); + textField.setFont(textField.getFont().deriveFont(28.0f)); + textField.setCaretColor(Color.RED); + textField.setCaret(new CustomCaret()); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.insets = new Insets(5, 15, 5, 15); + gbc.fill = GridBagConstraints.HORIZONTAL; + mainControlPanel.add(textField, gbc); + + JTextArea instructionTextArea = new JTextArea(); + instructionTextArea.setText(INSTRUCTIONS); + instructionTextArea.setEditable(false); + instructionTextArea.setBackground(Color.white); + + gbc.gridx = 0; + gbc.gridy = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + mainControlPanel.add(instructionTextArea, gbc); + + JButton passButton = new JButton("Pass"); + passButton.setActionCommand("Pass"); + passButton.addActionListener((ActionEvent e) -> { + testResult = true; + mainFrame.dispose(); + countDownLatch.countDown(); + + }); + + JButton failButton = new JButton("Fail"); + failButton.setActionCommand("Fail"); + failButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + mainFrame.dispose(); + countDownLatch.countDown(); + } + }); + + gbc.gridx = 0; + gbc.gridy = 0; + + resultButtonPanel.add(passButton, gbc); + + gbc.gridx = 1; + gbc.gridy = 0; + resultButtonPanel.add(failButton, gbc); + + gbc.gridx = 0; + gbc.gridy = 2; + mainControlPanel.add(resultButtonPanel, gbc); + + mainFrame.add(mainControlPanel); + mainFrame.pack(); + + mainFrame.addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + mainFrame.dispose(); + countDownLatch.countDown(); + } + }); + mainFrame.setVisible(true); + } + + static class CustomCaret implements Caret { + + private JTextComponent component; + private boolean visible; + private boolean selectionVisible = true; + int blinkRate; + int dot; + int mark; + Position.Bias dotBias; + Position.Bias markBias; + Object selectionTag; + Point2D magicCaretPosition; + + private MouseListener mouseListener = new CaretMouseListener(); + + @Override + public void install(JTextComponent c) { + this.component = c; + c.addMouseListener(mouseListener); + } + + @Override + public void deinstall(JTextComponent c) { + c.removeMouseListener(mouseListener); + this.component = null; + } + + @Override + public void paint(Graphics g) { + + if (component == null) { + return; + } + + int dot = getDot(); + Rectangle2D r = null; + try { + r = component.modelToView2D(dot); + } catch (BadLocationException e) { + return; + } + + if (r == null) { + return; + } + + Rectangle2D cr = getCaretRectangle(r); + repaint(cr.getBounds()); + + g.setColor(component.getCaretColor()); + float cx = (float) cr.getX(); + float cy = (float) cr.getY(); + float cw = (float) cr.getWidth(); + float ch = (float) cr.getHeight(); + float c = cx + cw / 2; + + Graphics2D g2d = (Graphics2D) g; + g2d.draw(new Line2D.Float(c, cy, c, cy + ch)); + g2d.draw(new Line2D.Float(cx, cy, cx + cw, cy)); + g2d.draw(new Line2D.Float(cx, cy + ch, cx + cw, cy + ch)); + } + + void repaint(Rectangle r) { + component.repaint(r); + } + + Rectangle2D getCaretRectangle(Rectangle2D r) { + int d = 3; + double cx = r.getX() - d; + double cy = r.getY(); + double cw = 2 * d; + double ch = r.getHeight(); + return new Rectangle2D.Double(cx, cy, cw, ch); + } + + @Override + public void addChangeListener(ChangeListener l) { + } + + @Override + public void removeChangeListener(ChangeListener l) { + } + + @Override + public boolean isVisible() { + return visible; + } + + @Override + public void setVisible(boolean v) { + this.visible = true; + } + + @Override + public boolean isSelectionVisible() { + return selectionVisible; + } + + @Override + public void setSelectionVisible(boolean v) { + this.selectionVisible = v; + updateSelection(); + } + + @Override + public void setMagicCaretPosition(Point p) { + magicCaretPosition = p; + } + + @Override + public Point getMagicCaretPosition() { + if (magicCaretPosition != null) { + return new Point((int) magicCaretPosition.getX(), + (int) magicCaretPosition.getY()); + } + return null; + } + + @Override + public void setBlinkRate(int rate) { + this.blinkRate = rate; + } + + @Override + public int getBlinkRate() { + return blinkRate; + } + + @Override + public int getDot() { + return dot; + } + + @Override + public int getMark() { + return mark; + } + + @Override + public void setDot(int dot) { + setDot(dot, Position.Bias.Forward); + } + + private void setDot(int dot, Position.Bias bias) { + handleSetDot(dot, bias); + updateSelection(); + } + + @Override + public void moveDot(int dot) { + moveDot(dot, Position.Bias.Forward); + } + + private void moveDot(int dot, Position.Bias bias) { + changeCaretPosition(dot, bias); + updateSelection(); + } + + void handleSetDot(int dot, Position.Bias dotBias) { + + if (component == null) { + return; + } + + Document doc = component.getDocument(); + if (doc != null) { + dot = Math.min(dot, doc.getLength()); + } + + dot = Math.max(dot, 0); + + if (dot == 0) { + dotBias = Position.Bias.Forward; + } + + mark = dot; + + if (this.dot != dot || this.dotBias != dotBias) { + changeCaretPosition(dot, dotBias); + updateSelection(); + } + + this.markBias = this.dotBias; + } + + void changeCaretPosition(int dot, Position.Bias dotBias) { + this.dot = dot; + this.dotBias = dotBias; + setMagicCaretPosition(null); + SwingUtilities.invokeLater(this::repaintNewCaret); + } + + private void updateSelection() { + Highlighter h = component.getHighlighter(); + if (h != null) { + int p0 = Math.min(dot, mark); + int p1 = Math.max(dot, mark); + + if (p0 == p1 || !selectionVisible) { + if (selectionTag != null) { + h.removeHighlight(selectionTag); + selectionTag = null; + } + } else { + try { + if (selectionTag != null) { + h.changeHighlight(selectionTag, p0, p1); + } else { + Highlighter.HighlightPainter p = getSelectionPainter(); + selectionTag = h.addHighlight(p0, p1, p); + } + } catch (BadLocationException e) { + throw new RuntimeException(e); + } + } + } + } + + void repaintNewCaret() { + if (component != null) { + TextUI mapper = component.getUI(); + Document doc = component.getDocument(); + if ((mapper != null) && (doc != null)) { + Rectangle2D newLoc; + try { + newLoc = mapper.modelToView2D(component, this.dot, this.dotBias); + } catch (BadLocationException e) { + newLoc = null; + } + if (newLoc != null) { + adjustVisibility(newLoc.getBounds()); + if (getMagicCaretPosition() == null) { + setMagicCaretPosition(new Point((int) newLoc.getX(), + (int) newLoc.getY())); + } + } + damage(newLoc.getBounds()); + } + } + } + + protected Highlighter.HighlightPainter getSelectionPainter() { + return DefaultHighlighter.DefaultPainter; + } + + protected void adjustVisibility(Rectangle nloc) { + if (component == null) { + return; + } + if (SwingUtilities.isEventDispatchThread()) { + component.scrollRectToVisible(nloc); + } else { + SwingUtilities.invokeLater(() -> { + component.scrollRectToVisible(nloc); + }); + } + } + + protected synchronized void damage(Rectangle r) { + if (r != null && component != null) { + component.repaint(r); + } + } + + private class CaretMouseListener extends MouseAdapter { + + @Override + public void mousePressed(MouseEvent e) { + Point pt = new Point(e.getX(), e.getY()); + Position.Bias[] biasRet = new Position.Bias[1]; + int pos = component.getUI().viewToModel(component, pt, biasRet); + if (biasRet[0] == null) { + biasRet[0] = Position.Bias.Forward; + } + if (pos >= 0) { + setDot(pos); + } + } + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/swing/text/JTextComponent/8156217/TextSelectionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/text/JTextComponent/8156217/TextSelectionTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.text.JTextComponent; + +/** + * @test + * @bug 8156217 + * @summary Selected text is shifted on HiDPI display + * @run main/manual/othervm -Dsun.java2d.uiScale=2 TextSelectionTest + */ +public class TextSelectionTest { + + private static final String INSTRUCTIONS = "This is a manual test.\n" + + "\n" + + "Select the current text from the end to the beginning.\n" + + "\n" + + "If the text is slightly shiftted from one side to another\n" + + "and back during selection press Fail.\n" + + "Otherwise, press Pass."; + + private static final CountDownLatch latch = new CountDownLatch(1); + private static volatile boolean passed = false; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(TextSelectionTest::createAndShowGUI); + latch.await(3, TimeUnit.MINUTES); + System.out.println("passed: " + passed); + if (!passed) { + throw new RuntimeException("Test fails!"); + } + } + + private static void createAndShowGUI() { + + JFrame frame = new JFrame("Follow the instructions below:"); + frame.setSize(700, 500); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + JPanel panel = new JPanel(new BorderLayout()); + JTextComponent textComponent = new JTextArea(INSTRUCTIONS); + textComponent.setEditable(false); + Font font = textComponent.getFont(); + font = font.deriveFont(24.0f); + textComponent.setFont(font); + panel.add(textComponent, BorderLayout.CENTER); + + JPanel buttonsPanel = new JPanel(new FlowLayout()); + JButton passButton = new JButton("Pass"); + passButton.addActionListener((e) -> { + passed = true; + latch.countDown(); + frame.dispose(); + }); + JButton failsButton = new JButton("Fail"); + failsButton.addActionListener((e) -> { + passed = false; + latch.countDown(); + frame.dispose(); + }); + + buttonsPanel.add(passButton); + buttonsPanel.add(failsButton); + panel.add(buttonsPanel, BorderLayout.SOUTH); + + frame.getContentPane().add(panel); + + frame.addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + latch.countDown(); + } + }); + frame.setVisible(true); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/javax/swing/text/View/8156217/FPMethodCalledTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/text/View/8156217/FPMethodCalledTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,499 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Robot; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.plaf.metal.MetalLookAndFeel; +import javax.swing.plaf.metal.MetalTextFieldUI; +import javax.swing.text.BadLocationException; +import javax.swing.text.Element; +import javax.swing.text.PasswordView; +import javax.swing.text.PlainView; +import javax.swing.text.View; +import javax.swing.text.WrappedPlainView; + +/** + * @test + * @bug 8156217 + * @key headful + * @summary Selected text is shifted on HiDPI display + * @run main FPMethodCalledTest + */ +public class FPMethodCalledTest { + + private static JFrame frame; + private static JTextField textField; + + public static void main(String[] args) throws Exception { + + for (Test test : TESTS) { + test(test); + } + } + + static void test(final Test test) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(50); + SwingUtilities.invokeAndWait(() -> { + createAndShowGUI(test); + }); + + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(() -> { + textField.select(1, 3); + }); + + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(() -> { + Resultable resultable = test.resultable; + if (!resultable.getResult()) { + throw new RuntimeException("Test fails for: " + resultable); + } + }); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + static void createAndShowGUI(Test test) { + + try { + UIManager.setLookAndFeel(new MetalLookAndFeel()); + } catch (Exception e) { + throw new RuntimeException(e); + } + + frame = new JFrame(); + frame.setSize(300, 300); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + JPanel panel = new JPanel(new FlowLayout()); + + String text = "AAAAAAA"; + textField = test.isPasswordField() + ? new JPasswordField(text) + : new JTextField(text); + + textField.setUI(new MetalTextFieldUI() { + + @Override + public View create(Element elem) { + return test.createView(elem); + } + }); + + panel.add(textField); + frame.getContentPane().add(panel); + frame.setVisible(true); + } + + private static final Test[] TESTS = { + new Test() { + @Override + View createView(Element elem) { + PlainViewINTAPI view = new PlainViewINTAPI(elem); + resultable = view; + return view; + } + }, + new Test() { + @Override + View createView(Element elem) { + PlainViewFPAPI view = new PlainViewFPAPI(elem); + resultable = view; + return view; + } + }, + new Test() { + @Override + View createView(Element elem) { + PlainViewMixedAPI view = new PlainViewMixedAPI(elem); + resultable = view; + return view; + } + }, + new Test() { + @Override + View createView(Element elem) { + WrappedPlainViewINTAPI view = new WrappedPlainViewINTAPI(elem); + resultable = view; + return view; + } + }, + new Test() { + @Override + View createView(Element elem) { + WrappedPlainViewFPAPI view = new WrappedPlainViewFPAPI(elem); + resultable = view; + return view; + } + }, + new Test() { + @Override + View createView(Element elem) { + WrappedPlainViewMixedAPI view = new WrappedPlainViewMixedAPI(elem); + resultable = view; + return view; + } + }, + new Test(true) { + + @Override + View createView(Element elem) { + PasswordViewINTAPI view = new PasswordViewINTAPI(elem); + resultable = view; + return view; + } + }, + new Test(true) { + + @Override + View createView(Element elem) { + PasswordViewFPAPI view = new PasswordViewFPAPI(elem); + resultable = view; + return view; + } + }, + new Test(true) { + + @Override + View createView(Element elem) { + PasswordViewMixedAPI view = new PasswordViewMixedAPI(elem); + resultable = view; + return view; + } + } + }; + + static interface Resultable { + + boolean getResult(); + } + + static abstract class Test { + + Resultable resultable; + final boolean isPasswordField; + + public Test() { + this(false); + } + + public Test(boolean isPasswordField) { + this.isPasswordField = isPasswordField; + } + + boolean isPasswordField() { + return isPasswordField; + } + + abstract View createView(Element elem); + } + + static class PlainViewINTAPI extends PlainView implements Resultable { + + boolean drawLine = false; + boolean drawSelected = false; + boolean drawUnselected = false; + + public PlainViewINTAPI(Element elem) { + super(elem); + } + + @Override + protected void drawLine(int lineIndex, Graphics g, int x, int y) { + drawLine = true; + super.drawLine(lineIndex, g, x, y); + } + + @Override + protected int drawSelectedText(Graphics g, int x, int y, + int p0, int p1) throws BadLocationException { + drawSelected = true; + return super.drawSelectedText(g, x, y, p0, p1); + } + + @Override + protected int drawUnselectedText(Graphics g, int x, int y, + int p0, int p1) throws BadLocationException { + drawUnselected = true; + return super.drawUnselectedText(g, x, y, p0, p1); + } + + @Override + public boolean getResult() { + return drawLine && drawSelected && drawUnselected; + } + } + + static class PlainViewFPAPI extends PlainView implements Resultable { + + boolean drawLine = false; + boolean drawSelected = false; + boolean drawUnselected = false; + + public PlainViewFPAPI(Element elem) { + super(elem); + } + + @Override + protected void drawLine(int lineIndex, Graphics2D g, float x, float y) { + drawLine = true; + super.drawLine(lineIndex, g, x, y); + } + + @Override + protected float drawSelectedText(Graphics2D g, float x, float y, + int p0, int p1) throws BadLocationException { + drawSelected = true; + return super.drawSelectedText(g, x, y, p0, p1); + } + + @Override + protected float drawUnselectedText(Graphics2D g, float x, float y, + int p0, int p1) throws BadLocationException { + drawUnselected = true; + return super.drawUnselectedText(g, x, y, p0, p1); + } + + @Override + public boolean getResult() { + return drawSelected; + } + } + + static class PlainViewMixedAPI extends PlainView implements Resultable { + + boolean isIntMethodCalled = false; + boolean isFPMethodCalled = false; + + public PlainViewMixedAPI(Element elem) { + super(elem); + } + + @Override + protected int drawSelectedText(Graphics g, int x, int y, + int p0, int p1) throws BadLocationException { + isIntMethodCalled = true; + return super.drawSelectedText(g, x, y, p0, p1); + } + + @Override + protected float drawSelectedText(Graphics2D g, float x, float y, + int p0, int p1) throws BadLocationException { + isFPMethodCalled = true; + return super.drawSelectedText(g, x, y, p0, p1); + } + + @Override + public boolean getResult() { + return !isIntMethodCalled && isFPMethodCalled; + } + } + + static class WrappedPlainViewINTAPI extends WrappedPlainView implements Resultable { + + boolean drawLine = false; + boolean drawSelected = false; + boolean drawUnselected = false; + + public WrappedPlainViewINTAPI(Element elem) { + super(elem); + } + + @Override + protected void drawLine(int p0, int p1, Graphics g, int x, int y) { + drawLine = true; + super.drawLine(p0, p1, g, x, y); + } + + @Override + protected int drawSelectedText(Graphics g, int x, int y, + int p0, int p1) throws BadLocationException { + drawSelected = true; + return super.drawSelectedText(g, x, y, p0, p1); + } + + @Override + protected int drawUnselectedText(Graphics g, int x, int y, + int p0, int p1) throws BadLocationException { + drawUnselected = true; + return super.drawUnselectedText(g, x, y, p0, p1); + } + + @Override + public boolean getResult() { + return drawLine && drawSelected && drawUnselected; + } + } + + static class WrappedPlainViewFPAPI extends WrappedPlainView implements Resultable { + + boolean drawLine = false; + boolean drawSelected = false; + boolean drawUnselected = false; + + public WrappedPlainViewFPAPI(Element elem) { + super(elem); + } + + @Override + protected void drawLine(int p0, int p1, Graphics2D g, float x, float y) { + drawLine = true; + super.drawLine(p0, p1, g, x, y); + } + + @Override + protected float drawSelectedText(Graphics2D g, float x, float y, + int p0, int p1) throws BadLocationException { + drawSelected = true; + return super.drawSelectedText(g, x, y, p0, p1); + } + + @Override + protected float drawUnselectedText(Graphics2D g, float x, float y, + int p0, int p1) throws BadLocationException { + drawUnselected = true; + return super.drawUnselectedText(g, x, y, p0, p1); + } + + @Override + public boolean getResult() { + return drawLine && drawSelected && drawUnselected; + } + } + + static class WrappedPlainViewMixedAPI extends WrappedPlainView implements Resultable { + + boolean isIntMethodCalled = false; + boolean isFPMethodCalled = false; + + public WrappedPlainViewMixedAPI(Element elem) { + super(elem); + } + + @Override + protected int drawUnselectedText(Graphics g, int x, int y, + int p0, int p1) throws BadLocationException { + isIntMethodCalled = true; + return super.drawUnselectedText(g, x, y, p0, p1); + } + + @Override + protected float drawUnselectedText(Graphics2D g, float x, float y, + int p0, int p1) throws BadLocationException { + isFPMethodCalled = true; + return super.drawUnselectedText(g, x, y, p0, p1); + } + + @Override + public boolean getResult() { + return !isIntMethodCalled && isFPMethodCalled; + } + } + + static class PasswordViewINTAPI extends PasswordView implements Resultable { + + boolean isIntMethodCalled = false; + + public PasswordViewINTAPI(Element elem) { + super(elem); + + } + + @Override + protected int drawEchoCharacter(Graphics g, int x, int y, char c) { + isIntMethodCalled = true; + return super.drawEchoCharacter(g, x, y, c); + } + + @Override + public boolean getResult() { + return isIntMethodCalled; + } + } + + static class PasswordViewFPAPI extends PasswordView implements Resultable { + + boolean isFPMethodCalled = false; + + public PasswordViewFPAPI(Element elem) { + super(elem); + + } + + @Override + protected float drawEchoCharacter(Graphics2D g, float x, float y, char c) { + isFPMethodCalled = true; + return super.drawEchoCharacter(g, x, y, c); + } + + @Override + public boolean getResult() { + return isFPMethodCalled; + } + } + + static class PasswordViewMixedAPI extends PasswordView implements Resultable { + + boolean isIntMethodCalled = false; + boolean isFPMethodCalled = false; + + public PasswordViewMixedAPI(Element elem) { + super(elem); + + } + + @Override + protected int drawEchoCharacter(Graphics g, int x, int y, char c) { + isIntMethodCalled = true; + return super.drawEchoCharacter(g, x, y, c); + } + + @Override + protected float drawEchoCharacter(Graphics2D g, float x, float y, char c) { + isFPMethodCalled = true; + return super.drawEchoCharacter(g, x, y, c); + } + + @Override + public boolean getResult() { + return !isIntMethodCalled && isFPMethodCalled; + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/jdk/editpad/EditPadTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/editpad/EditPadTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8167636 8167639 8168972 + * @summary Testing built-in editor. + * @modules java.desktop/java.awt + * jdk.internal.ed/jdk.internal.editor.spi + * jdk.editpad/jdk.editpad + * @run testng EditPadTest + */ + +import java.awt.AWTException; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.GraphicsEnvironment; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.WindowEvent; +import java.lang.reflect.InvocationTargetException; +import java.util.ServiceLoader; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.function.Consumer; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JViewport; +import javax.swing.SwingUtilities; + +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import jdk.internal.editor.spi.BuildInEditorProvider; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +@Test +public class EditPadTest { + + private static final int DELAY = 500; + private static final String WINDOW_LABEL = "Test Edit Pad"; + + private static ExecutorService executor; + private static Robot robot; + private static JFrame frame = null; + private static JTextArea area = null; + private static JButton cancel = null; + private static JButton accept = null; + private static JButton exit = null; + + @BeforeClass + public static void setUpEditorPadTest() { + if (!GraphicsEnvironment.isHeadless()) { + try { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(DELAY); + } catch (AWTException e) { + throw new ExceptionInInitializerError(e); + } + } + } + + @AfterClass + public static void shutdown() { + executorShutdown(); + } + + public void testSimple() { + testEdit("abcdef", 1, "xyz", + () -> assertSource("abcdef"), + () -> writeSource("xyz"), + () -> accept(), + () -> assertSource("xyz"), + () -> shutdownEditor()); + } + + public void testCancel() { + testEdit("abcdef", 0, "abcdef", + () -> assertSource("abcdef"), + () -> writeSource("xyz"), + () -> cancel()); + } + + public void testAbort() { + testEdit("abcdef", 0, "abcdef", + () -> assertSource("abcdef"), + () -> writeSource("xyz"), + () -> shutdownEditor()); + } + + public void testAcceptCancel() { + testEdit("abcdef", 1, "xyz", + () -> assertSource("abcdef"), + () -> writeSource("xyz"), + () -> accept(), + () -> assertSource("xyz"), + () -> writeSource("!!!!!!!!!"), + () -> cancel()); + } + + public void testAcceptEdit() { + testEdit("abcdef", 2, "xyz", + () -> assertSource("abcdef"), + () -> writeSource("NoNo"), + () -> accept(), + () -> assertSource("NoNo"), + () -> writeSource("xyz"), + () -> exit()); + } + + private void testEdit(String initialText, + int savedCount, String savedText, Runnable... actions) { + class Handler { + + String text = null; + int count = 0; + + void handle(String s) { + ++count; + text = s; + } + } + Handler save = new Handler(); + Handler error = new Handler(); + + if (GraphicsEnvironment.isHeadless()) { + // Do not actually run if we are headless + return; + } + Future task = doActions(actions); + builtInEdit(initialText, save::handle, error::handle); + complete(task); + assertEquals(error.count, 0, "Error: " + error.text); + assertTrue(save.count != savedCount + || save.text == null + ? savedText != null + : savedText.equals(save.text), + "Expected " + savedCount + " saves, got " + save.count + + ", expected \"" + savedText + "\" got \"" + save.text + "\""); + } + + private static ExecutorService getExecutor() { + if (executor == null) { + executor = Executors.newSingleThreadExecutor(); + } + return executor; + } + + private static void executorShutdown() { + if (executor != null) { + executor.shutdown(); + executor = null; + } + } + + private void builtInEdit(String initialText, + Consumer saveHandler, Consumer errorHandler) { + ServiceLoader sl + = ServiceLoader.load(BuildInEditorProvider.class); + // Find the highest ranking provider + BuildInEditorProvider provider = null; + for (BuildInEditorProvider p : sl) { + if (provider == null || p.rank() > provider.rank()) { + provider = p; + } + } + if (provider != null) { + provider.edit(WINDOW_LABEL, + initialText, saveHandler, errorHandler); + } else { + throw new InternalError("Cannot find provider"); + } + } + + private Future doActions(Runnable... actions) { + return getExecutor().submit(() -> { + try { + waitForIdle(); + SwingUtilities.invokeLater(this::seekElements); + waitForIdle(); + for (Runnable act : actions) { + act.run(); + } + } catch (Throwable e) { + shutdownEditor(); + if (e instanceof AssertionError) { + throw (AssertionError) e; + } + throw new RuntimeException(e); + } + }); + } + + private void complete(Future task) { + try { + task.get(); + waitForIdle(); + } catch (ExecutionException e) { + if (e.getCause() instanceof AssertionError) { + throw (AssertionError) e.getCause(); + } + throw new RuntimeException(e); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + shutdownEditor(); + } + } + + private void writeSource(String s) { + SwingUtilities.invokeLater(() -> area.setText(s)); + } + + private void assertSource(String expected) { + String[] s = new String[1]; + try { + SwingUtilities.invokeAndWait(() -> s[0] = area.getText()); + } catch (InvocationTargetException | InterruptedException e) { + throw new RuntimeException(e); + } + assertEquals(s[0], expected); + } + + private void accept() { + clickOn(accept); + } + + private void exit() { + clickOn(exit); + } + + private void cancel() { + clickOn(cancel); + } + + private void shutdownEditor() { + SwingUtilities.invokeLater(this::clearElements); + waitForIdle(); + } + + private void waitForIdle() { + robot.waitForIdle(); + robot.delay(DELAY); + } + + private void seekElements() { + for (Frame f : Frame.getFrames()) { + if (f.getTitle().equals(WINDOW_LABEL)) { + frame = (JFrame) f; + // workaround + frame.setLocation(0, 0); + Container root = frame.getContentPane(); + for (Component c : root.getComponents()) { + if (c instanceof JScrollPane) { + JScrollPane scrollPane = (JScrollPane) c; + for (Component comp : scrollPane.getComponents()) { + if (comp instanceof JViewport) { + JViewport view = (JViewport) comp; + area = (JTextArea) view.getComponent(0); + } + } + } + if (c instanceof JPanel) { + JPanel p = (JPanel) c; + for (Component comp : p.getComponents()) { + if (comp instanceof JButton) { + JButton b = (JButton) comp; + switch (b.getText()) { + case "Cancel": + cancel = b; + break; + case "Exit": + exit = b; + break; + case "Accept": + accept = b; + break; + } + } + } + } + } + } + } + } + + private void clearElements() { + if (frame != null) { + frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING)); + frame = null; + } + area = null; + accept = null; + cancel = null; + exit = null; + } + + private void clickOn(JButton button) { + waitForIdle(); + waitForIdle(); + waitForIdle(); + waitForIdle(); + waitForIdle(); + waitForIdle(); + Point p = button.getLocationOnScreen(); + Dimension d = button.getSize(); + robot.mouseMove(p.x + d.width / 2, p.y + d.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/sun/reflect/ReflectionFactory/ReflectionFactoryTest.java --- a/jdk/test/sun/reflect/ReflectionFactory/ReflectionFactoryTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/sun/reflect/ReflectionFactory/ReflectionFactoryTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -45,7 +45,7 @@ /* * @test - * @bug 8137058 8164908 + * @bug 8137058 8164908 8168980 * @run testng ReflectionFactoryTest * @run testng/othervm/policy=security.policy ReflectionFactoryTest * @summary Basic test for the unsupported ReflectionFactory @@ -95,6 +95,47 @@ } } + @DataProvider(name = "NonSerialConstructors") + static Object[][] constructors() throws NoSuchMethodException { + return new Object[][] { + {Foo.class, Object.class.getDeclaredConstructor()}, + {Foo.class, Foo.class.getDeclaredConstructor()}, + {Baz.class, Object.class.getDeclaredConstructor()}, + {Baz.class, Foo.class.getDeclaredConstructor()}, + {Baz.class, Baz.class.getDeclaredConstructor()} + }; + } + + /** + * Tests that the given Constructor, in the hierarchy, is run. + */ + @Test(dataProvider="NonSerialConstructors") + static void testNonSerializableConstructor(Class cl, + Constructor constructorToCall) + throws ReflectiveOperationException + { + @SuppressWarnings("unchecked") + Constructor c = factory.newConstructorForSerialization(cl, + constructorToCall); + + Object o = c.newInstance(); + Assert.assertEquals(o.getClass(), cl, "Instance is wrong type"); + + int expectedFoo = 0; + int expectedBaz = 0; + if (constructorToCall.getName().equals("ReflectionFactoryTest$Foo")) { + expectedFoo = 1; + } else if (constructorToCall.getName().equals("ReflectionFactoryTest$Baz")) { + expectedFoo = 1; + expectedBaz = 4; + } + + Assert.assertEquals(((Foo)o).foo(), expectedFoo); + if (o instanceof Baz) { + Assert.assertEquals(((Baz)o).baz(), expectedBaz); + } + } + static class Foo { private int foo; public Foo() { @@ -109,6 +150,8 @@ int expectedFoo = 1; Assert.assertEquals(foo, expectedFoo, "foo() constructor not run"); } + + public int foo() { return foo; } } static class Bar extends Foo implements Serializable { @@ -128,6 +171,12 @@ } } + static class Baz extends Foo { + private final int baz; + public Baz() { this.baz = 4; } + public int baz() { return baz; } + } + /** * Test newConstructorForExternalization returns the constructor and it can be called. * @throws NoSuchMethodException - error diff -r f71b844f33d1 -r 95af45781076 jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java --- a/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ * java.rmi/sun.rmi.server * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp - * @build TestLibrary JavaVM + * @build JavaVM * @run main/othervm NoConsoleOutput */ @@ -43,8 +43,6 @@ import java.io.File; import java.rmi.Remote; import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; public class NoConsoleOutput { @@ -53,7 +51,7 @@ System.err.println("\nRegression test for bug 6409194\n"); /* - * Exdecute a subprocess VM that does a bunch of RMI activity + * Execute a subprocess VM that does a bunch of RMI activity * with a logging configuration file that does not specify a * ConsoleHandler and with no legacy sun.rmi.*.logLevel system * properties set. @@ -65,7 +63,7 @@ ByteArrayOutputStream err = new ByteArrayOutputStream(); // We instantiate a JavaVM that should not produce any console output - // (neither on standard output, nor on standard err streams). + // on standard err streams, where RMI logging messages are sent to. JavaVM vm = new JavaVM( DoRMIStuff.class.getName(), "--add-exports=java.rmi/sun.rmi.registry=ALL-UNNAMED" @@ -77,8 +75,7 @@ vm.execute(); /* - * Verify that the subprocess had no System.out or System.err - * output. + * Verify that the subprocess had no System.err output. */ String outString = out.toString(); String errString = err.toString(); @@ -89,7 +86,7 @@ System.err.print(err); System.err.println("---------------------------------------------"); - if (outString.length() > 0 || errString.length() > 0) { + if (errString.length() > 0) { throw new Error("TEST FAILED: unexpected subprocess output"); } @@ -105,13 +102,8 @@ public Object echo(Object obj) { return obj; } } public static void main(String[] args) throws Exception { - Registry registry = TestLibrary.createRegistryOnUnusedPort(); - int registryPort = TestLibrary.getRegistryPort(registry); - Registry reg = LocateRegistry.getRegistry("", registryPort); FooImpl fooimpl = new FooImpl(); - UnicastRemoteObject.exportObject(fooimpl, 0); - reg.rebind("foo", fooimpl); - Foo foostub = (Foo) reg.lookup("foo"); + Foo foostub = (Foo) UnicastRemoteObject.exportObject(fooimpl, 0); FooImpl fooimpl2 = new FooImpl(); UnicastRemoteObject.exportObject(fooimpl2, 0); foostub.echo(fooimpl2); diff -r f71b844f33d1 -r 95af45781076 jdk/test/sun/security/ec/TestEC.java --- a/jdk/test/sun/security/ec/TestEC.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/sun/security/ec/TestEC.java Fri Nov 11 16:44:36 2016 +0100 @@ -35,7 +35,7 @@ * @library ../pkcs11/sslecc * @library ../../../java/security/testlibrary * @modules jdk.crypto.pkcs11/sun.security.pkcs11.wrapper - * @compile -XDignore.symbol.file TestEC.java + * @compile --add-modules jdk.crypto.pkcs11 TestEC.java * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1" TestEC * @run main/othervm/java.security.policy=TestEC.policy -Djdk.tls.namedGroups="secp256r1,sect193r1" TestEC */ diff -r f71b844f33d1 -r 95af45781076 jdk/test/sun/security/krb5/auto/ReplayCacheExpunge.java --- a/jdk/test/sun/security/krb5/auto/ReplayCacheExpunge.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/sun/security/krb5/auto/ReplayCacheExpunge.java Fri Nov 11 16:44:36 2016 +0100 @@ -47,15 +47,15 @@ int count = Integer.parseInt(args[0]); ReplayCache cache = ReplayCache.getInstance("dfl:./"); AuthTimeWithHash a1 = - new AuthTimeWithHash(client, server, time(-400), 0, hash("1")); + new AuthTimeWithHash(client, server, time(-400), 0, "HASH", hash("1")); AuthTimeWithHash a2 = - new AuthTimeWithHash(client, server, time(0), 0, hash("4")); + new AuthTimeWithHash(client, server, time(0), 0, "HASH", hash("4")); KerberosTime now = new KerberosTime(time(0)*1000L); KerberosTime then = new KerberosTime(time(-300)*1000L); // Once upon a time, we added a lot of events for (int i=0; i=|J=) + * Default: J,N on Solaris and Linux where N is available, or J + * Example: J,N,N14=/krb5-1.14/lib/libgssapi_krb5.so,J8=/java8/bin/java + * + * - test.runs on manual runs. If empty, a iterate through all pattern + * Format: (req# | client# service#) acceptor# expected, ... + * Default: null + * Example: c0s0Jav,c1s1N14av,r0Jbx means 0th req is new c0->s0 sent to Ja, + * 1st req is new c1 to s1 sent to N14a, + * 2nd req is old (0th replayed) sent to Jb. + * a/b at the end of acceptor is different acceptors of the same lib + * + * - test.autoruns on number of automatic runs + * Format: number + * Default: 100 + */ public class ReplayCacheTestProc { - private static Proc[] ps; - private static Proc pc; + private static Proc[] pa; // all acceptors + private static Proc pi; // the single initiator private static List reqs = new ArrayList<>(); private static String HOST = "localhost"; @@ -59,119 +81,193 @@ "/var/krb5/rcache/" : System.getProperty("user.dir"); + private static MessageDigest md5, sha256; + + static { + try { + md5 = MessageDigest.getInstance("MD5"); + sha256 = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException nsae) { + throw new AssertionError("Impossible", nsae); + } + } private static long uid; public static void main0(String[] args) throws Exception { System.setProperty("java.security.krb5.conf", OneKDC.KRB5_CONF); if (args.length == 0) { // The controller - int ns = 5; // number of servers - int nu = 5; // number of users - int nx = 50; // number of experiments - int np = 5; // number of peers (services) - int mode = 0; // native(1), random(0), java(-1) - boolean random = true; // random experiments choreograph - - // Do not test interop with native GSS on some platforms - String os = System.getProperty("os.name", "???"); - if (!os.startsWith("SunOS") && !os.startsWith("Linux")) { - mode = -1; - } + int nc = 5; // number of clients + int ns = 5; // number of services + String[] libs; // available acceptor types: + // J: java + // J=: another java + // N: default native lib + // N=: another native lib + Ex[] result; + int numPerType = 2; // number of acceptors per type uid = jdk.internal.misc.VM.geteuid(); KDC kdc = KDC.create(OneKDC.REALM, HOST, 0, true); - for (int i=0; i p.debug().equals(run.acceptor())) + .findFirst() + .orElseThrow(() -> new Exception( + "no acceptor named " + run.acceptor())), + run.success()); } } - pc.println("END"); - for (int i=0; i s%s): ", j, + reqs.get(j).client, reqs.get(j).service); + } + System.out.printf("%s%s(%d)%s", + found ? " -> " : "", + result[i].acceptor.debug(), + i, + result[i].actual != result[i].expected ? + "xxx" : ""); + found = true; + } + } + System.out.println(); + if (!found) { + break; + } } if (!finalOut) throw new Exception(); - } else if (args[0].equals("N-1")) { + } else if (args[0].equals("Nsanity")) { // Native mode sanity check Proc.d("Detect start"); Context s = Context.fromUserKtab("*", OneKDC.KTAB, true); s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); - } else if (args[0].equals("client")) { + } else if (args[0].equals("initiator")) { while (true) { String title = Proc.textIn(); Proc.d("Client see " + title); @@ -185,22 +281,26 @@ Proc.binOut(token); } } else { + Proc.d(System.getProperty("java.vm.version")); + Proc.d(System.getProperty("sun.security.jgss.native")); + Proc.d(System.getProperty("sun.security.jgss.lib")); + Proc.d("---------------------------------\n"); Proc.d("Server start"); Context s = Context.fromUserKtab("*", OneKDC.KTAB, true); Proc.d("Server login"); while (true) { String title = Proc.textIn(); - Proc.d("Server " + args[0] + " sees " + title); + Proc.d("Server sees " + title); if (title.equals("END")) break; s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); byte[] token = Proc.binIn(); try { s.take(token); Proc.textOut("true"); - Proc.d(args[0] + " Good"); + Proc.d("Good"); } catch (Exception e) { Proc.textOut("false"); - Proc.d(args[0] + " Bad"); + Proc.d("Bad"); } } } @@ -215,79 +315,90 @@ } } - // returns the user name - private static String user(int p) { - return "USER" + p; + // returns the client name + private static String client(int p) { + return "client" + p; } - // returns the peer name - private static String peer(int p) { - return "host" + p + "/" + HOST; + + // returns the service name + private static String service(int p) { + return "service" + p + "/" + HOST; } - // returns the dfl name for a host + + // returns the dfl name for a service private static String dfl(int p) { - return cwd + "host" + p + (uid == -1 ? "" : ("_"+uid)); + return "service" + p + (uid == -1 ? "" : ("_"+uid)); } + // generates an ap-req and save into reqs, returns the index - private static int req(int user, int peer) throws Exception { - pc.println(user(user) + " " + peer(peer)); - Req req = new Req(user, peer, pc.readData()); + private static int req(int client, int service) throws Exception { + pi.println(client(client) + " " + service(service)); + Req req = new Req(client, service, pi.readData()); reqs.add(req); return reqs.size() - 1; } - // carries out a round of experiment - // i: ex#, old: which req, server: which server, expected: result? - private static Ex round(int i, int old, int server, boolean expected) - throws Exception { - ps[server].println("TEST"); - ps[server].println(reqs.get(old).msg); - String reply = ps[server].readData(); - Ex result = new Ex(); - result.i = i; - result.expected = expected; - result.server = ps[server].debug(); - result.actual = Boolean.valueOf(reply); - result.user = reqs.get(old).user; - result.peer = reqs.get(old).peer; - result.old = old; - result.csize = csize(result.peer); - result.hash = hash(reqs.get(old).msg); - if (new File(dfl(result.peer)).exists()) { - Files.copy(Paths.get(dfl(result.peer)), Paths.get( - String.format("%03d-USER%d-host%d-%s-%s", - i, result.user, result.peer, result.server, - result.actual) - + "-" + result.hash), - StandardCopyOption.COPY_ATTRIBUTES); + + // create a acceptor + private static Proc acceptor(String type, String suffix) throws Exception { + Proc p; + String label; + String lib; + int pos = type.indexOf('='); + if (pos < 0) { + label = type; + lib = null; + } else { + label = type.substring(0, pos); + lib = type.substring(pos + 1); } - return result; + if (type.startsWith("J")) { + if (lib == null) { + p = Proc.create("ReplayCacheTestProc"); + } else { + p = Proc.create("ReplayCacheTestProc", lib); + } + p.prop("sun.security.krb5.rcache", "dfl") + .prop("java.io.tmpdir", cwd); + String useMD5 = System.getProperty("jdk.krb5.rcache.useMD5"); + if (useMD5 != null) { + p.prop("jdk.krb5.rcache.useMD5", useMD5); + } + } else { + p = Proc.create("ReplayCacheTestProc") + .env("KRB5_CONFIG", OneKDC.KRB5_CONF) + .env("KRB5_KTNAME", OneKDC.KTAB) + .env("KRB5RCACHEDIR", cwd) + .prop("sun.security.jgss.native", "true") + .prop("javax.security.auth.useSubjectCredsOnly", "false") + .prop("sun.security.nativegss.debug", "true"); + if (lib != null) { + String libDir = lib.substring(0, lib.lastIndexOf('/')); + p.prop("sun.security.jgss.lib", lib) + .env("DYLD_LIBRARY_PATH", libDir) + .env("LD_LIBRARY_PATH", libDir); + } + } + Proc.d(label+suffix+" started"); + return p.args(label+suffix).debug(label+suffix).start(); } - // create a native server - private static Proc ns(int i) throws Exception { - return Proc.create("ReplayCacheTestProc") - .args("N"+i) - .env("KRB5_CONFIG", OneKDC.KRB5_CONF) - .env("KRB5_KTNAME", OneKDC.KTAB) - .env("KRB5RCACHEDIR", cwd) - .prop("sun.security.jgss.native", "true") - .prop("javax.security.auth.useSubjectCredsOnly", "false") - .prop("sun.security.nativegss.debug", "true") - .debug("N"+i) - .start(); + + // generates hash of authenticator inside ap-req inside initsectoken + private static void record(String label, Req req) throws Exception { + byte[] data = Base64.getDecoder().decode(req.msg); + data = Arrays.copyOfRange(data, 17, data.length); + + try (PrintStream ps = new PrintStream( + new FileOutputStream("log.txt", true))) { + ps.printf("%s:\nmsg: %s\nMD5: %s\nSHA-256: %s\n\n", + label, + req.msg, + hex(md5.digest(data)), + hex(sha256.digest(data))); + } } - // creates a java server - private static Proc js(int i) throws Exception { - return Proc.create("ReplayCacheTestProc") - .debug("S"+i) - .args("S"+i) - .prop("sun.security.krb5.rcache", "dfl") - .prop("java.io.tmpdir", cwd) - .start(); - } - // generates hash of authenticator inside ap-req inside initsectoken - private static String hash(String req) throws Exception { - byte[] data = Base64.getDecoder().decode(req); - data = Arrays.copyOfRange(data, 17, data.length); - byte[] hash = MessageDigest.getInstance("MD5").digest(new APReq(data).authenticator.getBytes()); + + // Returns a compact hexdump for a byte array + private static String hex(byte[] hash) { char[] h = new char[hash.length * 2]; char[] hexConst = "0123456789ABCDEF".toCharArray(); for (int i=0; i { + SSLServerSocketFactory sslssf = + (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); + SSLServerSocket sslServerSocket = + (SSLServerSocket) sslssf.createServerSocket(SSLTest.FREE_PORT); + test.setServerPort(sslServerSocket.getLocalPort()); + SSLTest.print("Server is listening on port " + + test.getServerPort()); - /* - * Primary constructor, used to drive remainder of the test. - * - * Fork off the other side, then do your work. - */ - AnonCipherWithWantClientAuth () throws Exception { - if (separateServerThread) { - startServer(true); - startClient(false); - } else { - startClient(true); - startServer(false); - } + String ciphers[] = { + "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA" }; + sslServerSocket.setEnabledCipherSuites(ciphers); + sslServerSocket.setWantClientAuth(true); + + // Signal the client, the server is ready to accept connection. + test.signalServerReady(); - /* - * Wait for other side to close down. - */ - if (separateServerThread) { - serverThread.join(); - } else { - clientThread.join(); - } + // Try to accept a connection in 30 seconds. + SSLSocket sslSocket = SSLTest.accept(sslServerSocket); + if (sslSocket == null) { + // Ignore the test case if no connection within 30 seconds. + SSLTest.print("No incoming client connection in 30 seconds." + + " Ignore in server side."); + return; + } + SSLTest.print("Server accepted connection"); - /* - * When we get here, the test is pretty much over. - * - * If the main thread excepted, that propagates back - * immediately. If the other thread threw an exception, we - * should report back. - */ - if (serverException != null) - throw serverException; - if (clientException != null) - throw clientException; - } + // handle the connection + try { + // Is it the expected client connection? + // + // Naughty test cases or third party routines may try to + // connection to this server port unintentionally. In + // order to mitigate the impact of unexpected client + // connections and avoid intermittent failure, it should + // be checked that the accepted connection is really linked + // to the expected client. + boolean clientIsReady = test.waitForClientSignal(); - void startServer(boolean newThread) throws Exception { - if (newThread) { - serverThread = new Thread() { - public void run() { - try { - doServerSide(); - } catch (Exception e) { - /* - * Our server thread just died. - */ - System.err.println("Server died..."); - serverReady = true; - serverException = e; + if (clientIsReady) { + // Run the application in server side. + SSLTest.print("Run server application"); + + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); + + sslIS.read(); + sslOS.write(85); + sslOS.flush(); + } else { + System.out.println( + "The client is not the expected one or timeout. " + + "Ignore in server side."); } + } finally { + sslSocket.close(); + sslServerSocket.close(); } - }; - serverThread.start(); - } else { - doServerSide(); - } - } + }) + .setClientApplication((socket, test) -> { + String ciphers[] = { + "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5" }; + socket.setEnabledCipherSuites(ciphers); + socket.setUseClientMode(true); - void startClient(boolean newThread) throws Exception { - if (newThread) { - clientThread = new Thread() { - public void run() { - try { - doClientSide(); - } catch (Exception e) { - /* - * Our client thread just died. - */ - System.err.println("Client died..."); - clientException = e; - } - } - }; - clientThread.start(); - } else { - doClientSide(); - } + InputStream sslIS = socket.getInputStream(); + OutputStream sslOS = socket.getOutputStream(); + + sslOS.write(280); + sslOS.flush(); + sslIS.read(); + }) + .runTest(); } } diff -r f71b844f33d1 -r 95af45781076 jdk/test/sun/util/calendar/zi/tzdata/VERSION --- a/jdk/test/sun/util/calendar/zi/tzdata/VERSION Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/sun/util/calendar/zi/tzdata/VERSION Fri Nov 11 16:44:36 2016 +0100 @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2016g +tzdata2016h diff -r f71b844f33d1 -r 95af45781076 jdk/test/sun/util/calendar/zi/tzdata/asia --- a/jdk/test/sun/util/calendar/zi/tzdata/asia Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/sun/util/calendar/zi/tzdata/asia Fri Nov 11 16:44:36 2016 +0100 @@ -2567,11 +2567,6 @@ # From Paul Eggert (2015-03-03): # http://www.timeanddate.com/time/change/west-bank/ramallah?year=2014 # says that the fall 2014 transition was Oct 23 at 24:00. -# For future dates, guess the last Friday in March at 24:00 through -# the first Friday on or after October 21 at 00:00. This is consistent with -# the predictions in today's editions of the following URLs: -# http://www.timeanddate.com/time/change/gaza-strip/gaza -# http://www.timeanddate.com/time/change/west-bank/hebron # From Hannah Kreitem (2016-03-09): # http://www.palestinecabinet.gov.ps/WebSite/ar/ViewDetails?ID=31728 @@ -2581,7 +2576,21 @@ # # From Paul Eggert (2016-03-12): # Predict spring transitions on March's last Saturday at 01:00 from now on. -# Leave fall predictions alone for now. + +# From Sharef Mustafa (2016-10-19): +# [T]he Palestinian cabinet decision (Mar 8th 2016) published on +# http://www.palestinecabinet.gov.ps/WebSite/Upload/Decree/GOV_17/16032016134830.pdf +# states that summer time will end on Oct 29th at 01:00. +# +# From Tim Parenti (2016-10-19): +# Predict fall transitions on October's last Saturday at 01:00 from now on. +# This is consistent with the 2016 transition as well as our spring +# predictions. +# +# From Paul Eggert (2016-10-19): +# It's also consistent with predictions in the following URLs today: +# http://www.timeanddate.com/time/change/gaza-strip/gaza +# http://www.timeanddate.com/time/change/west-bank/hebron # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule EgyptAsia 1957 only - May 10 0:00 1:00 S @@ -2610,9 +2619,10 @@ Rule Palestine 2012 2014 - Mar lastThu 24:00 1:00 S Rule Palestine 2012 only - Sep 21 1:00 0 - Rule Palestine 2013 only - Sep Fri>=21 0:00 0 - -Rule Palestine 2014 max - Oct Fri>=21 0:00 0 - +Rule Palestine 2014 2015 - Oct Fri>=21 0:00 0 - Rule Palestine 2015 only - Mar lastFri 24:00 1:00 S Rule Palestine 2016 max - Mar lastSat 1:00 1:00 S +Rule Palestine 2016 max - Oct lastSat 1:00 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Gaza 2:17:52 - LMT 1900 Oct @@ -2762,45 +2772,31 @@ # People who live in regions under Tamil control can use [TZ='Asia/Kolkata'], # as that zone has agreed with the Tamil areas since our cutoff date of 1970. -# From K Sethu (2006-04-25): -# I think the abbreviation LKT originated from the world of computers at -# the time of or subsequent to the time zone changes by SL Government -# twice in 1996 and probably SL Government or its standardization -# agencies never declared an abbreviation as a national standard. -# -# I recollect before the recent change the government announcements -# mentioning it as simply changing Sri Lanka Standard Time or Sri Lanka -# Time and no mention was made about the abbreviation. +# From Sadika Sumanapala (2016-10-19): +# According to http://www.sltime.org (maintained by Measurement Units, +# Standards & Services Department, Sri Lanka) abbreviation for Sri Lanka +# standard time is SLST. # -# If we look at Sri Lanka Department of Government's "Official News -# Website of Sri Lanka" ... http://www.news.lk/ we can see that they -# use SLT as abbreviation in time stamp at the beginning of each news -# item.... -# -# Within Sri Lanka I think LKT is well known among computer users and -# administrators. In my opinion SLT may not be a good choice because the -# nation's largest telcom / internet operator Sri Lanka Telcom is well -# known by that abbreviation - simply as SLT (there IP domains are -# slt.lk and sltnet.lk). -# -# But if indeed our government has adopted SLT as standard abbreviation -# (that we have not known so far) then it is better that it be used for -# all computers. - -# From Paul Eggert (2006-04-25): -# One possibility is that we wait for a bit for the dust to settle down -# and then see what people actually say in practice. +# From Paul Eggert (2016-10-18): +# "SLST" seems to be reasonably recent and rarely-used outside time +# zone nerd sources. I searched Google News and found three uses of +# it in the International Business Times of India in February and +# March of this year when discussing cricket match times, but nothing +# since then (though there has been a lot of cricket) and nothing in +# other English-language news sources. Our old abbreviation "LKT" is +# even worse. For now, let's use a numeric abbreviation; we can +# switch to "SLST" if it catches on. # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Colombo 5:19:24 - LMT 1880 5:19:32 - MMT 1906 # Moratuwa Mean Time - 5:30 - IST 1942 Jan 5 - 5:30 0:30 IHST 1942 Sep - 5:30 1:00 IST 1945 Oct 16 2:00 - 5:30 - IST 1996 May 25 0:00 - 6:30 - LKT 1996 Oct 26 0:30 - 6:00 - LKT 2006 Apr 15 0:30 - 5:30 - IST + 5:30 - +0530 1942 Jan 5 + 5:30 0:30 +0530/+06 1942 Sep + 5:30 1:00 +0530/+0630 1945 Oct 16 2:00 + 5:30 - +0530 1996 May 25 0:00 + 6:30 - +0630 1996 Oct 26 0:30 + 6:00 - +06 2006 Apr 15 0:30 + 5:30 - +0530 # Syria # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S diff -r f71b844f33d1 -r 95af45781076 jdk/test/sun/util/calendar/zi/tzdata/australasia --- a/jdk/test/sun/util/calendar/zi/tzdata/australasia Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/sun/util/calendar/zi/tzdata/australasia Fri Nov 11 16:44:36 2016 +0100 @@ -373,7 +373,13 @@ # commencing at 2.00 am on Sunday 1st November, 2015 and ending at # 3.00 am on Sunday 17th January, 2016. -# From Paul Eggert (2015-09-01): +# From Raymond Kumar (2016-10-04): +# http://www.fiji.gov.fj/Media-Center/Press-Releases/DAYLIGHT-SAVING-STARTS-ON-6th-NOVEMBER,-2016.aspx +# "Fiji's daylight savings will begin on Sunday, 6 November 2016, when +# clocks go forward an hour at 2am to 3am.... Daylight Saving will +# end at 3.00am on Sunday 15th January 2017." + +# From Paul Eggert (2016-10-03): # For now, guess DST from 02:00 the first Sunday in November to # 03:00 the third Sunday in January. Although ad hoc, it matches # transitions since late 2014 and seems more likely to match future diff -r f71b844f33d1 -r 95af45781076 jdk/test/sun/util/calendar/zi/tzdata/europe --- a/jdk/test/sun/util/calendar/zi/tzdata/europe Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/sun/util/calendar/zi/tzdata/europe Fri Nov 11 16:44:36 2016 +0100 @@ -1931,7 +1931,7 @@ # Amsterdam mean time. # The data entries before 1945 are taken from -# http://www.phys.uu.nl/~vgent/wettijd/wettijd.htm +# http://www.staff.science.uu.nl/~gent0113/idl/idl.htm # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Neth 1916 only - May 1 0:00 1:00 NST # Netherlands Summer Time @@ -3450,22 +3450,24 @@ # Turkey -# From Amar Devegowda (2007-01-03): -# The time zone rules for Istanbul, Turkey have not been changed for years now. -# ... The latest rules are available at: -# http://www.timeanddate.com/worldclock/timezone.html?n=107 -# From Steffen Thorsen (2007-01-03): -# I have been able to find press records back to 1996 which all say that -# DST started 01:00 local time and end at 02:00 local time. I am not sure -# what happened before that. One example for each year from 1996 to 2001: -# http://newspot.byegm.gov.tr/arsiv/1996/21/N4.htm -# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING97/03/97X03X25.TXT -# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING98/03/98X03X02.HTM -# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING99/10/99X10X26.HTM#%2016 -# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING2000/03/00X03X06.HTM#%2021 -# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING2001/03/23x03x01.HTM#%2027 -# From Paul Eggert (2007-01-03): -# Prefer the above source to Shanks & Pottenger for time stamps after 1990. +# From Kıvanç Yazan (2016-09-25): +# 1) For 1986-2006, DST started at 01:00 local and ended at 02:00 local, with +# no exceptions. +# 2) 1994's lastSun was overridden with Mar 20 ... +# Here are official papers: +# http://www.resmigazete.gov.tr/arsiv/19032.pdf - page 2 for 1986 +# http://www.resmigazete.gov.tr/arsiv/19400.pdf - page 4 for 1987 +# http://www.resmigazete.gov.tr/arsiv/19752.pdf - page 15 for 1988 +# http://www.resmigazete.gov.tr/arsiv/20102.pdf - page 6 for 1989 +# http://www.resmigazete.gov.tr/arsiv/20464.pdf - page 1 for 1990 - 1992 +# http://www.resmigazete.gov.tr/arsiv/21531.pdf - page 15 for 1993 - 1995 +# http://www.resmigazete.gov.tr/arsiv/21879.pdf - page 1 for overriding 1994 +# http://www.resmigazete.gov.tr/arsiv/22588.pdf - page 1 for 1996, 1997 +# http://www.resmigazete.gov.tr/arsiv/23286.pdf - page 10 for 1998 - 2000 +# http://www.resmigazete.gov.tr/eskiler/2001/03/20010324.htm#2 - for 2001 +# http://www.resmigazete.gov.tr/eskiler/2002/03/20020316.htm#2 - for 2002-2006 +# From Paul Eggert (2016-09-25): +# Prefer the above sources to Shanks & Pottenger for time stamps after 1985. # From Steffen Thorsen (2007-03-09): # Starting 2007 though, it seems that they are adopting EU's 1:00 UTC @@ -3574,10 +3576,10 @@ Rule Turkey 1983 only - Oct 2 0:00 0 - Rule Turkey 1985 only - Apr 20 0:00 1:00 S Rule Turkey 1985 only - Sep 28 0:00 0 - -Rule Turkey 1986 1990 - Mar lastSun 2:00s 1:00 S -Rule Turkey 1986 1990 - Sep lastSun 2:00s 0 - -Rule Turkey 1991 2006 - Mar lastSun 1:00s 1:00 S -Rule Turkey 1991 1995 - Sep lastSun 1:00s 0 - +Rule Turkey 1986 1993 - Mar lastSun 1:00s 1:00 S +Rule Turkey 1986 1995 - Sep lastSun 1:00s 0 - +Rule Turkey 1994 only - Mar 20 1:00s 1:00 S +Rule Turkey 1995 2006 - Mar lastSun 1:00s 1:00 S Rule Turkey 1996 2006 - Oct lastSun 1:00s 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Europe/Istanbul 1:55:52 - LMT 1880 diff -r f71b844f33d1 -r 95af45781076 jdk/test/sun/util/calendar/zi/tzdata/northamerica --- a/jdk/test/sun/util/calendar/zi/tzdata/northamerica Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/sun/util/calendar/zi/tzdata/northamerica Fri Nov 11 16:44:36 2016 +0100 @@ -47,8 +47,32 @@ # was the result of his proposals at the Convention of Railroad Trunk Lines # in New York City (1869-10). His 1870 proposal was based on Washington, DC, # but in 1872-05 he moved the proposed origin to Greenwich. -# His proposal was adopted by the railroads on 1883-11-18 at 12:00, -# and the most of the country soon followed suit. + +# From Paul Eggert (2016-09-21): +# Dowd's proposal left many details unresolved, such as where to draw +# lines between time zones. The key individual who made time zones +# work in the US was William Frederick Allen - railway engineer, +# managing editor of the Travelers' Guide, and secretary of the +# General Time Convention, a railway standardization group. Allen +# spent months in dialogs with scientific and railway leaders, +# developed a workable plan to institute time zones, and presented it +# to the General Time Convention on 1883-04-11, saying that his plan +# meant "local time would be practically abolished" - a plus for +# railway scheduling. By the next convention on 1883-10-11 nearly all +# railroads had agreed and it took effect on 1883-11-18 at 12:00. +# That Sunday was called the "day of two noons", as the eastern parts +# of the new zones observed noon twice. Allen witnessed the +# transition in New York City, writing: +# +# I heard the bells of St. Paul's strike on the old time. Four +# minutes later, obedient to the electrical signal from the Naval +# Observatory ... the time-ball made its rapid descent, the chimes +# of old Trinity rang twelve measured strokes, and local time was +# abandoned, probably forever. +# +# Most of the US soon followed suit. See: +# Bartky IR. The adoption of standard time. Technol Cult 1989 Jan;30(1):25-56. +# http://dx.doi.org/10.2307/3105430 # From Paul Eggert (2005-04-16): # That 1883 transition occurred at 12:00 new time, not at 12:00 old time. diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jar/mmrjar/ConcealedPackage.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/mmrjar/ConcealedPackage.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8146486 + * @summary Fail to create a MR modular JAR with a versioned entry in + * base-versioned empty package + * @library /lib/testlibrary + * @build jdk.testlibrary.FileUtils + * @run testng ConcealedPackage + */ + +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Set; +import java.util.spi.ToolProvider; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import jdk.testlibrary.FileUtils; + +public class ConcealedPackage { + private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") + .orElseThrow(() -> new RuntimeException("jar tool not found")); + private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac") + .orElseThrow(() -> new RuntimeException("javac tool not found")); + private final String linesep = System.lineSeparator(); + private final Path userdir; + private final ByteArrayOutputStream outbytes = new ByteArrayOutputStream(); + private final PrintStream out = new PrintStream(outbytes, true); + private final ByteArrayOutputStream errbytes = new ByteArrayOutputStream(); + private final PrintStream err = new PrintStream(errbytes, true); + + public ConcealedPackage() throws IOException { + Path testsrc = Paths.get(System.getProperty("test.src")); + userdir = Paths.get(System.getProperty("user.dir", ".")); + + // compile the classes directory + Path source = testsrc.resolve("src").resolve("classes"); + Path destination = Paths.get("classes"); + javac(source, destination); + + // compile the mr9 directory including module-info.java + source = testsrc.resolve("src").resolve("mr9"); + destination = Paths.get("mr9"); + javac(source, destination); + + // move module-info.class for later use + Files.move(destination.resolve("module-info.class"), + Paths.get("module-info.class")); + } + + private void javac(Path source, Path destination) throws IOException { + String[] args = Stream.concat( + Stream.of("-d", destination.toString()), + Files.walk(source) + .map(Path::toString) + .filter(s -> s.endsWith(".java")) + ).toArray(String[]::new); + JAVAC_TOOL.run(System.out, System.err, args); + } + + private int jar(String cmd) { + outbytes.reset(); + errbytes.reset(); + return JAR_TOOL.run(out, err, cmd.split(" +")); + } + + @AfterClass + public void cleanup() throws IOException { + Files.walk(userdir, 1) + .filter(p -> !p.equals(userdir)) + .forEach(p -> { + try { + if (Files.isDirectory(p)) { + FileUtils.deleteFileTreeWithRetry(p); + } else { + FileUtils.deleteFileIfExistsWithRetry(p); + } + } catch (IOException x) { + throw new UncheckedIOException(x); + } + }); + } + + // updates a valid multi-release jar with a new public class in + // versioned section and fails + @Test + public void test1() { + // successful build of multi-release jar + int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 p/Hi.class"); + Assert.assertEquals(rc, 0); + + jar("-tf mmr.jar"); + + String s = new String(outbytes.toByteArray()); + Set actual = Arrays.stream(s.split(linesep)).collect(Collectors.toSet()); + Set expected = Set.of( + "META-INF/", + "META-INF/MANIFEST.MF", + "p/", + "p/Hi.class", + "META-INF/versions/9/p/Hi.class" + ); + Assert.assertEquals(actual, expected); + + // failed build because of new public class + rc = jar("-uf mmr.jar --release 9 -C mr9 p/internal/Bar.class"); + Assert.assertEquals(rc, 1); + + s = new String(errbytes.toByteArray()); + Assert.assertTrue(s.contains("p/internal/Bar.class, contains a new public " + + "class not found in base entries") + ); + } + + // updates a valid multi-release jar with a module-info class and new + // concealed public class in versioned section and succeeds + @Test + public void test2() { + // successful build of multi-release jar + int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 p/Hi.class"); + Assert.assertEquals(rc, 0); + + // successful build because of module-info and new public class + rc = jar("-uf mmr.jar module-info.class --release 9 -C mr9 p/internal/Bar.class"); + Assert.assertEquals(rc, 0); + + String s = new String(errbytes.toByteArray()); + Assert.assertTrue(s.contains("p/internal/Bar.class is a public class in a " + + "concealed package, \nplacing this jar on the class path " + + "will result in incompatible public interfaces") + ); + + jar("-tf mmr.jar"); + + s = new String(outbytes.toByteArray()); + Set actual = Arrays.stream(s.split(linesep)).collect(Collectors.toSet()); + Set expected = Set.of( + "META-INF/", + "META-INF/MANIFEST.MF", + "p/", + "p/Hi.class", + "META-INF/versions/9/p/Hi.class", + "META-INF/versions/9/p/internal/Bar.class", + "module-info.class" + ); + Assert.assertEquals(actual, expected); + } + + // jar tool fails building mmr.jar because of new public class + @Test + public void test3() { + int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 ."); + Assert.assertEquals(rc, 1); + + String s = new String(errbytes.toByteArray()); + Assert.assertTrue(s.contains("p/internal/Bar.class, contains a new public " + + "class not found in base entries") + ); + } + + // jar tool succeeds building mmr.jar because of concealed package + @Test + public void test4() { + int rc = jar("-cf mmr.jar module-info.class -C classes . " + + "--release 9 module-info.class -C mr9 ."); + Assert.assertEquals(rc, 0); + + String s = new String(errbytes.toByteArray()); + Assert.assertTrue(s.contains("p/internal/Bar.class is a public class in a " + + "concealed package, \nplacing this jar on the class path " + + "will result in incompatible public interfaces") + ); + + jar("-tf mmr.jar"); + + s = new String(outbytes.toByteArray()); + Set actual = Arrays.stream(s.split(linesep)).collect(Collectors.toSet()); + Set expected = Set.of( + "META-INF/", + "META-INF/MANIFEST.MF", + "module-info.class", + "META-INF/versions/9/module-info.class", + "p/", + "p/Hi.class", + "META-INF/versions/9/p/", + "META-INF/versions/9/p/Hi.class", + "META-INF/versions/9/p/internal/", + "META-INF/versions/9/p/internal/Bar.class" + ); + Assert.assertEquals(actual, expected); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jar/mmrjar/src/classes/p/Hi.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/mmrjar/src/classes/p/Hi.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +public class Hi { + public void sayHi() { + System.out.println("Hi"); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jar/mmrjar/src/mr9/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/mmrjar/src/mr9/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module m1 { + exports p; +} + diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jar/mmrjar/src/mr9/p/Hi.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/mmrjar/src/mr9/p/Hi.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +public class Hi { + public void sayHi() { + System.out.println("Hello"); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jar/mmrjar/src/mr9/p/internal/Bar.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/mmrjar/src/mr9/p/internal/Bar.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p.internal; + +public class Bar { + @Override + public String toString() { + return "p.internal.Bar"; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jlink/JLinkPluginsTest.java --- a/jdk/test/tools/jlink/JLinkPluginsTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/tools/jlink/JLinkPluginsTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -83,5 +83,21 @@ Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); helper.checkImage(imageDir, moduleName, null, null); } + { + // disable generate jli classes - JDK-8160063 + String[] userOptions = {"--disable-plugin", "generate-jli-classes"}; + String moduleName = "jlidisabled"; + helper.generateDefaultJModule(moduleName, "composite2"); + Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); + helper.checkImage(imageDir, moduleName, null, null); + } + { + // disable invalid plugin - JDK-8160063 + String[] userOptions = {"--disable-plugin", "non-existent-plugin"}; + String moduleName = "invaliddisabled"; + helper.generateDefaultJModule(moduleName, "composite2"); + helper.generateDefaultImage(userOptions, moduleName). + assertFailure("Error: No such plugin: non-existent-plugin"); + } } } diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jlink/JLinkSigningTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/JLinkSigningTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8159393 + * @summary Test signed jars involved in image creation + * @modules java.base/jdk.internal.jimage + * jdk.jlink/jdk.tools.jlink.internal + * jdk.compiler/com.sun.tools.javac + * java.base/sun.security.tools.keytool + * jdk.jartool/sun.security.tools.jarsigner + * jdk.jartool/sun.tools.jar + * @run main/othervm JLinkSigningTest + */ + + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; + +public class JLinkSigningTest { + static final String[] MODULE_INFO = { + "module test {", + "}", + }; + + static final String[] TEST_CLASS = { + "package test;", + "public class test {", + " public static void main(String[] args) {", + " }", + "}", + }; + + static void report(String command, String[] args) { + System.out.println(command + " " + String.join(" ", Arrays.asList(args))); + } + + static void javac(String[] args) { + report("javac", args); + com.sun.tools.javac.Main javac = new com.sun.tools.javac.Main(); + + if (javac.compile(args) != 0) { + throw new RuntimeException("javac failed"); + } + } + + static void jar(String[] args) { + report("jar", args); + sun.tools.jar.Main jar = new sun.tools.jar.Main(System.out, System.err, "jar"); + + if (!jar.run(args)) { + throw new RuntimeException("jar failed"); + } + } + + static void keytool(String[] args) { + report("keytool", args); + + try { + sun.security.tools.keytool.Main.main(args); + } catch (Exception ex) { + throw new RuntimeException("keytool failed"); + } + } + + static void jarsigner(String[] args) { + report("jarsigner", args); + + try { + sun.security.tools.jarsigner.Main.main(args); + } catch (Exception ex) { + throw new RuntimeException("jarsigner failed"); + } + } + + static void jlink(String[] args) { + report("jlink", args); + + try { + jdk.tools.jlink.internal.Main.run(new PrintWriter(System.out, true), + new PrintWriter(System.err, true), + args); + } catch (Exception ex) { + throw new RuntimeException("jlink failed"); + } + } + + public static void main(String[] args) { + final String JAVA_HOME = System.getProperty("java.home"); + Path moduleInfoJavaPath = Paths.get("module-info.java"); + Path moduleInfoClassPath = Paths.get("module-info.class"); + Path testDirectoryPath = Paths.get("test"); + Path testJavaPath = testDirectoryPath.resolve("test.java"); + Path testClassPath = testDirectoryPath.resolve("test.class"); + Path testModsDirectoryPath = Paths.get("testmods"); + Path jmodsPath = Paths.get(JAVA_HOME, "jmods"); + Path testjarPath = testModsDirectoryPath.resolve("test.jar"); + String modulesPath = testjarPath.toString() + + File.pathSeparator + + jmodsPath.toString(); + + try { + Files.write(moduleInfoJavaPath, Arrays.asList(MODULE_INFO)); + Files.createDirectories(testDirectoryPath); + Files.write(testJavaPath, Arrays.asList(TEST_CLASS)); + Files.createDirectories(testModsDirectoryPath); + } catch (IOException ex) { + throw new RuntimeException("file construction failed"); + } + + javac(new String[] { + testJavaPath.toString(), + moduleInfoJavaPath.toString(), + }); + + jar(new String[] { + "-c", + "-f", testjarPath.toString(), + "--module-path", jmodsPath.toString(), + testClassPath.toString(), + moduleInfoClassPath.toString(), + }); + + keytool(new String[] { + "-genkey", + "-keyalg", "RSA", + "-dname", "CN=John Doe, OU=JPG, O=Oracle, L=Santa Clara, ST=California, C=US", + "-alias", "examplekey", + "-storepass", "password", + "-keypass", "password", + "-keystore", "examplekeystore", + "-validity", "365", + }); + + jarsigner(new String[] { + "-keystore", "examplekeystore", + "-verbose", testjarPath.toString(), + "-storepass", "password", + "-keypass", "password", + "examplekey", + }); + + try { + jlink(new String[] { + "--module-path", modulesPath, + "--add-modules", "test", + "--output", "foo", + }); + } catch (Throwable ex) { + System.out.println("Failed as should"); + } + + try { + jlink(new String[] { + "--module-path", modulesPath, + "--add-modules", "test", + "--ignore-signing-information", + "--output", "foo", + }); + System.out.println("Suceeded as should"); + } catch (Throwable ex) { + System.err.println("Should not have failed"); + throw new RuntimeException(ex); + } + + System.out.println("Done"); + } +} + diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jlink/JLinkTest.java --- a/jdk/test/tools/jlink/JLinkTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/tools/jlink/JLinkTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -109,19 +109,16 @@ .modulePath(helper.defaultModulePath()) .output(helper.createNewImageDir(moduleName)) .addMods("leaf1") - .option("") .call().assertSuccess(); JImageGenerator.getJLinkTask() .modulePath(helper.defaultModulePath()) .addMods("leaf1") .option("--output") - .option("") .call().assertFailure("Error: no value given for --output"); JImageGenerator.getJLinkTask() .modulePath("") .output(helper.createNewImageDir(moduleName)) .addMods("leaf1") - .option("") .call().assertFailure("Error: no value given for --module-path"); } @@ -132,7 +129,6 @@ .modulePath(helper.defaultModulePath()) .output(helper.createNewImageDir(moduleName)) .addMods("m") - .option("") .call().assertSuccess(); moduleName = "mod"; jmod = helper.generateDefaultJModule(moduleName).assertSuccess(); @@ -140,7 +136,6 @@ .modulePath(helper.defaultModulePath()) .output(helper.createNewImageDir(moduleName)) .addMods("m") - .option("") .call().assertSuccess(); } @@ -282,18 +277,21 @@ helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level invalid"); } - // @file + // orphan argument - JDK-8166810 { - Path path = Paths.get("embedded.properties"); - Files.write(path, Collections.singletonList("--strip-debug --add-modules " + - "toto.unknown --compress UNKNOWN\n")); - String[] userOptions = {"@", path.toAbsolutePath().toString()}; - String moduleName = "configembeddednocompresscomposite2"; + String[] userOptions = {"--compress", "2", "foo" }; + String moduleName = "orphanarg1"; helper.generateDefaultJModule(moduleName, "composite2"); - Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); - helper.checkImage(imageDir, moduleName, null, null); + helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: orphan argument: foo"); } + // orphan argument - JDK-8166810 + { + String[] userOptions = {"--output", "foo", "bar" }; + String moduleName = "orphanarg2"; + helper.generateDefaultJModule(moduleName, "composite2"); + helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: orphan argument: bar"); + } } private static void testCompress(Helper helper, String moduleName, String... userOptions) throws IOException { diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jlink/multireleasejar/JLinkMultiReleaseJarTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/multireleasejar/JLinkMultiReleaseJarTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8156499 + * @summary Test image creation from Multi-Release JAR + * @author Steve Drach + * @library /lib/testlibrary /test/lib + * @modules java.base/jdk.internal.jimage + * java.base/jdk.internal.module + * @build jdk.testlibrary.FileUtils jdk.test.lib.process.* + * @run testng JLinkMultiReleaseJarTest +*/ + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.module.ModuleDescriptor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.Arrays; +import java.util.Set; +import java.util.jar.JarFile; +import java.util.spi.ToolProvider; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import jdk.internal.jimage.BasicImageReader; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.testlibrary.FileUtils; + +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class JLinkMultiReleaseJarTest { + private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") + .orElseThrow(() -> new RuntimeException("jar tool not found")); + private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac") + .orElseThrow(() -> new RuntimeException("javac tool not found")); + private static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink") + .orElseThrow(() -> new RuntimeException("jlink tool not found")); + + private final Path userdir = Paths.get(System.getProperty("user.dir", ".")); + private final Path javahome = Paths.get(System.getProperty("java.home")); + private final Path jmodsdir = javahome.resolve("jmods"); + + private final String pathsep = System.getProperty("path.separator"); + + private byte[] resource = (Runtime.version().major() + " resource file").getBytes(); + + @BeforeClass + public void initialize() throws IOException { + Path srcdir = Paths.get(System.getProperty("test.src")); + + // create class files from source + Path base = srcdir.resolve("base"); + Path basemods = userdir.resolve("basemods"); + javac(base, basemods, base.toString()); + + Path rt = srcdir.resolve("rt"); + Path rtmods = userdir.resolve("rtmods"); + javac(rt, rtmods, rt.toString()); + + // create resources in basemods and rtmods + Path dest = basemods.resolve("m1").resolve("resource.txt"); + byte[] text = "base resource file".getBytes(); + ByteArrayInputStream is = new ByteArrayInputStream(text); + Files.copy(is, dest); + + dest = rtmods.resolve("m1").resolve("resource.txt"); + is = new ByteArrayInputStream(resource); + Files.copy(is, dest); + + // build multi-release jar file with different module-infos + String[] args = { + "-cf", "m1.jar", + "-C", basemods.resolve("m1").toString(), ".", + "--release ", String.valueOf(JarFile.runtimeVersion().major()), + "-C", rtmods.resolve("m1").toString(), "." + }; + JAR_TOOL.run(System.out, System.err, args); + + // now move the module-info that requires logging to temporary place + Files.move(rtmods.resolve("m1").resolve("module-info.class"), + userdir.resolve("module-info.class")); + + // and build another jar + args[1] = "m1-no-logging.jar"; + JAR_TOOL.run(System.out, System.err, args); + + // replace the no logging module-info with the logging module-info + Files.move(userdir.resolve("module-info.class"), + basemods.resolve("m1").resolve("module-info.class"), + StandardCopyOption.REPLACE_EXISTING); + + // and build another jar + args[1] = "m1-logging.jar"; + JAR_TOOL.run(System.out, System.err, args); + } + + private void javac(Path source, Path destination, String srcpath) throws IOException { + String[] args = Stream.concat( + Stream.of("-d", destination.toString(), "--module-source-path", srcpath), + Files.walk(source) + .map(Path::toString) + .filter(s -> s.endsWith(".java")) + ).toArray(String[]::new); + int rc = JAVAC_TOOL.run(System.out, System.err, args); + Assert.assertEquals(rc, 0); + } + + @AfterClass + public void close() throws IOException { + Files.walk(userdir, 1) + .filter(p -> !p.equals(userdir)) + .forEach(p -> { + try { + if (Files.isDirectory(p)) { + FileUtils.deleteFileTreeWithRetry(p); + } else { + FileUtils.deleteFileIfExistsWithRetry(p); + } + } catch (IOException x) { + throw new UncheckedIOException(x); + } + }); + } + + @Test + public void basicTest() throws Throwable { + if (ignoreTest()) return; + + // use jlink to build image from multi-release jar + jlink("m1.jar", "myimage"); + + // validate image + Path jimage = userdir.resolve("myimage").resolve("lib").resolve("modules"); + try (BasicImageReader reader = BasicImageReader.open(jimage)) { + + // do we have the right entry names? + Set names = Arrays.stream(reader.getEntryNames()) + .filter(n -> n.startsWith("/m1")) + .collect(Collectors.toSet()); + Assert.assertEquals(names, Set.of( + "/m1/module-info.class", + "/m1/p/Main.class", + "/m1/p/Type.class", + "/m1/q/PublicClass.class", + "/m1/META-INF/MANIFEST.MF", + "/m1/resource.txt")); + + // do we have the right module-info.class? + byte[] b = reader.getResource("/m1/module-info.class"); + Set requires = ModuleDescriptor + .read(new ByteArrayInputStream(b)) + .requires() + .stream() + .map(mdr -> mdr.name()) + .filter(nm -> !nm.equals("java.base")) + .collect(Collectors.toSet()); + Assert.assertEquals(requires, Set.of("java.logging")); + + // do we have the right resource? + b = reader.getResource("/m1/resource.txt"); + Assert.assertEquals(b, resource); + + // do we have the right class? + b = reader.getResource("/m1/p/Main.class"); + Class clazz = (new ByteArrayClassLoader()).loadClass("p.Main", b); + MethodHandle getVersion = MethodHandles.lookup() + .findVirtual(clazz, "getVersion", MethodType.methodType(int.class)); + int version = (int) getVersion.invoke(clazz.getConstructor().newInstance()); + Assert.assertEquals(version, JarFile.runtimeVersion().major()); + } + } + + @Test + public void noLoggingTest() throws Throwable { + if (ignoreTest()) return; + + jlink("m1-no-logging.jar", "no-logging-image"); + runImage("no-logging-image", false); + } + + @Test + public void loggingTest() throws Throwable { + if (ignoreTest()) return; + + jlink("m1-logging.jar", "logging-image"); + runImage("logging-image", true); + + } + + // java.base.jmod must exist for this test to make sense + private boolean ignoreTest() { + if (Files.isRegularFile(jmodsdir.resolve("java.base.jmod"))) { + return false; + } + System.err.println("Test skipped. NO jmods/java.base.jmod"); + return true; + } + + + private void jlink(String jar, String image) { + String args = "--output " + image + " --add-modules m1 --module-path " + + jar + pathsep + jmodsdir.toString(); + int exitCode = JLINK_TOOL.run(System.out, System.err, args.split(" +")); + Assert.assertEquals(exitCode, 0); + } + + public void runImage(String image, boolean expected) throws Throwable { + Path java = Paths.get(image, "bin", "java"); + OutputAnalyzer oa = ProcessTools.executeProcess(java.toString(), "-m", "m1/p.Main"); + String sout = oa.getStdout(); + boolean actual = sout.contains("logging found"); + Assert.assertEquals(actual, expected); + System.out.println(sout); + System.err.println(oa.getStderr()); + Assert.assertEquals(oa.getExitValue(), 0); + } + + private static class ByteArrayClassLoader extends ClassLoader { + public Class loadClass(String name, byte[] bytes) { + return defineClass(name, bytes, 0, bytes.length); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jlink/multireleasejar/base/m1/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/multireleasejar/base/m1/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module m1 { + exports p; +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jlink/multireleasejar/base/m1/p/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/multireleasejar/base/m1/p/Main.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +import java.lang.module.ModuleFinder; + +public class Main { + private String msg = "something to give this a different size"; + + public int getVersion() { + return 8; + } + + private void testForLogging() { + ModuleFinder.ofSystem().find("java.logging").ifPresentOrElse( + mr -> System.out.println("java.logging found in image"), + () -> System.out.println("java.logging not found in image") + ); + } + + public static void main(String[] args) { + Main main = new Main(); + main.testForLogging(); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jlink/multireleasejar/rt/m1/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/multireleasejar/rt/m1/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module m1 { + requires java.logging; + exports p; +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jlink/multireleasejar/rt/m1/p/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/multireleasejar/rt/m1/p/Main.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +import java.lang.module.ModuleFinder; +import java.util.jar.JarFile; + +public class Main { + public int getVersion() { + return JarFile.runtimeVersion().major(); + } + + private void testForLogging() { + ModuleFinder.ofSystem().find("java.logging").ifPresentOrElse( + mr -> System.out.println("java.logging found in image"), + () -> System.out.println("java.logging not found in image") + ); + } + + public static void main(String[] args) { + Main main = new Main(); + main.testForLogging(); + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jlink/multireleasejar/rt/m1/p/Type.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/multireleasejar/rt/m1/p/Type.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +class Type{} diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jlink/multireleasejar/rt/m1/q/PublicClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/multireleasejar/rt/m1/q/PublicClass.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package q; + +public class PublicClass { + public void doNothing() { + int i = 3 + 2; + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java --- a/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -40,7 +40,7 @@ /* * @test - * @bug 8152143 8152704 8155649 + * @bug 8152143 8152704 8155649 8165804 * @summary IncludeLocalesPlugin tests * @author Naoto Sato * @library ../../lib @@ -236,6 +236,7 @@ "/jdk.localedata/sun/text/resources/ext/thai_dict", "/jdk.localedata/sun/text/resources/ext/WordBreakIteratorData_th", "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class", + "/jdk.localedata/sun/text/resources/ext/BreakIteratorResources_th.class", "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class", "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class", "/jdk.localedata/sun/text/resources/ext/FormatData_th.class", @@ -261,6 +262,7 @@ "/jdk.localedata/sun/text/resources/ext/thai_dict", "/jdk.localedata/sun/text/resources/ext/WordBreakIteratorData_th", "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class", + "/jdk.localedata/sun/text/resources/ext/BreakIteratorResources_th.class", "/jdk.localedata/sun/text/resources/ext/FormatData_th.class"), List.of( "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class", @@ -431,13 +433,23 @@ for (Object[] data : testData) { // create image for each test data - System.out.println("Invoking jlink with \"" + data[INCLUDE_LOCALES_OPTION] + "\""); - Result result = JImageGenerator.getJLinkTask() + Result result; + if (data[INCLUDE_LOCALES_OPTION].toString().isEmpty()) { + System.out.println("Invoking jlink with no --include-locales option"); + result = JImageGenerator.getJLinkTask() + .modulePath(helper.defaultModulePath()) + .output(helper.createNewImageDir(moduleName)) + .addMods((String) data[ADDMODS_OPTION]) + .call(); + } else { + System.out.println("Invoking jlink with \"" + data[INCLUDE_LOCALES_OPTION] + "\""); + result = JImageGenerator.getJLinkTask() .modulePath(helper.defaultModulePath()) .output(helper.createNewImageDir(moduleName)) .addMods((String) data[ADDMODS_OPTION]) .option((String) data[INCLUDE_LOCALES_OPTION]) .call(); + } String errorMsg = (String) data[ERROR_MESSAGE]; if (errorMsg.isEmpty()) { diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jmod/JmodTest.java --- a/jdk/test/tools/jmod/JmodTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/tools/jmod/JmodTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -28,6 +28,7 @@ * jdk.jlink * @build jdk.testlibrary.FileUtils CompilerUtils * @run testng JmodTest + * @bug 8142968 * @summary Basic test for jmod */ @@ -85,6 +86,31 @@ Files.createDirectories(MODS_DIR); } + // JDK-8166286 - jmod fails on symlink to directory + @Test + public void testSymlinks() throws IOException { + Path apaDir = EXPLODED_DIR.resolve("apa"); + Path classesDir = EXPLODED_DIR.resolve("apa").resolve("classes"); + assertTrue(compileModule("apa", classesDir)); + Path libDir = apaDir.resolve("lib"); + createFiles(libDir, List.of("foo/bar/libfoo.so")); + try { + Path link = Files.createSymbolicLink( + libDir.resolve("baz"), libDir.resolve("foo").toAbsolutePath()); + assertTrue(Files.exists(link)); + } catch (UnsupportedOperationException uoe) { + // OS does not support symlinks. Nothing to test! + return; + } + + Path jmod = MODS_DIR.resolve("apa.jmod"); + jmod("create", + "--libs=", libDir.toString(), + "--class-path", classesDir.toString(), + jmod.toString()) + .assertSuccess(); + } + @Test public void testList() throws IOException { String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jmod/hashes/HashesTest.java --- a/jdk/test/tools/jmod/hashes/HashesTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/tools/jmod/hashes/HashesTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -26,7 +26,8 @@ * @summary Test the recording and checking of module hashes * @author Andrei Eremeev * @library /lib/testlibrary - * @modules java.base/jdk.internal.module + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.module * jdk.jlink * jdk.compiler * @build CompilerUtils @@ -39,7 +40,6 @@ import java.lang.module.ModuleFinder; import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; -import java.lang.reflect.Method; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; @@ -55,8 +55,10 @@ import java.util.spi.ToolProvider; import java.util.stream.Collectors; -import jdk.internal.module.ConfigurableModuleFinder; +import jdk.internal.misc.SharedSecrets; +import jdk.internal.misc.JavaLangModuleAccess; import jdk.internal.module.ModuleHashes; + import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; @@ -74,7 +76,6 @@ private final Path jmods = Paths.get("jmods"); private final String[] modules = new String[] { "m1", "m2", "m3"}; - private static Method hashesMethod; @BeforeTest private void setup() throws Exception { if (Files.exists(jmods)) { @@ -97,13 +98,6 @@ // compile org.bar and org.foo compileModule("org.bar", modSrc); compileModule("org.foo", modSrc); - - try { - hashesMethod = ModuleDescriptor.class.getDeclaredMethod("hashes"); - hashesMethod.setAccessible(true); - } catch (ReflectiveOperationException x) { - throw new InternalError(x); - } } @Test @@ -143,17 +137,14 @@ } private Optional hashes(String name) throws Exception { - ModuleFinder finder = ModuleFinder.of(jmods.resolve(name + ".jmod")); - if (finder instanceof ConfigurableModuleFinder) { - ((ConfigurableModuleFinder) finder) - .configurePhase(ConfigurableModuleFinder.Phase.LINK_TIME); - } + ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess() + .newModulePath(Runtime.version(), true, jmods.resolve(name + ".jmod")); ModuleReference mref = finder.find(name).orElseThrow(RuntimeException::new); ModuleReader reader = mref.open(); try (InputStream in = reader.open("module-info.class").get()) { ModuleDescriptor md = ModuleDescriptor.read(in); - Optional hashes = - (Optional) hashesMethod.invoke(md); + JavaLangModuleAccess jmla = SharedSecrets.getJavaLangModuleAccess(); + Optional hashes = jmla.hashes(md); System.out.format("hashes in module %s %s%n", name, hashes.isPresent() ? "present" : "absent"); if (hashes.isPresent()) { diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jmod/src/apa/jdk/test/apa/Apa.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jmod/src/apa/jdk/test/apa/Apa.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.apa; + +public class Apa { } diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/jmod/src/apa/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jmod/src/apa/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module apa { + exports jdk.test.apa; +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/launcher/MiscTests.java --- a/jdk/test/tools/launcher/MiscTests.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/tools/launcher/MiscTests.java Fri Nov 11 16:44:36 2016 +0100 @@ -69,8 +69,6 @@ static void test6856415() throws IOException { final String mainClass = "Foo6856415"; - final String exportOpts - = "--add-exports=jdk.crypto.pkcs11/sun.security.pkcs11=ALL-UNNAMED"; List scratch = new ArrayList<>(); scratch.add("public class Foo6856415 {"); @@ -81,7 +79,9 @@ scratch.add("}"); createFile(new File(mainClass + ".java"), scratch); - compile(mainClass + ".java", exportOpts); + compile(mainClass + ".java", + "--add-modules=jdk.crypto.pkcs11", + "--add-exports=jdk.crypto.pkcs11/sun.security.pkcs11=ALL-UNNAMED"); File testJar = new File("Foo.jar"); testJar.delete(); diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/launcher/modules/classpath/JavaClassPathTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/launcher/modules/classpath/JavaClassPathTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import jdk.testlibrary.OutputAnalyzer; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertTrue; +import static jdk.testlibrary.ProcessTools.*; + +/** + * @test + * @bug 8168205 + * @summary Test the default class path if -Djava.class.path is set + * @library /lib/testlibrary + * @modules jdk.compiler + * @build CompilerUtils jdk.testlibrary.* + * @run testng JavaClassPathTest + */ + +public class JavaClassPathTest { + private static final Path SRC_DIR = Paths.get(System.getProperty("test.src"), + "src"); + private static final Path MODS_DIR = Paths.get("mods"); + private static final String TEST_MODULE = "m"; + private static final String TEST_MAIN = "jdk.test.Main"; + + @BeforeTest + public void setup() throws Exception { + boolean compiled = CompilerUtils.compile(SRC_DIR.resolve(TEST_MODULE), + MODS_DIR.resolve(TEST_MODULE)); + assertTrue(compiled, "module " + TEST_MODULE + " did not compile"); + + // add the class and a resource to the current working directory + Path file = Paths.get("jdk/test/Main.class"); + Files.createDirectories(file.getParent()); + Files.copy(MODS_DIR.resolve(TEST_MODULE).resolve(file), file); + + Path res = Paths.get("jdk/test/res.properties"); + Files.createFile(res); + } + + @DataProvider(name = "classpath") + public Object[][] classpath() { + return new Object[][]{ + // true indicates that class path default to current working directory + { "", true }, + { "-Djava.class.path", true }, + { "-Djava.class.path=", true }, + { "-Djava.class.path=.", true }, + }; + } + + @Test(dataProvider = "classpath") + public void testUnnamedModule(String option, boolean expected) throws Throwable { + List args = new ArrayList<>(); + if (!option.isEmpty()) { + args.add(option); + } + args.add(TEST_MAIN); + args.add(Boolean.toString(expected)); + + assertTrue(execute(args).getExitValue() == 0); + } + + @DataProvider(name = "moduleAndClassPath") + public Object[][] moduleAndClassPath() { + return new Object[][]{ + // true indicates that class path default to current working directory + { "", false }, + { "-Djava.class.path", false }, + { "-Djava.class.path=", false }, + { "-Djava.class.path=.", true }, + }; + } + + @Test(dataProvider = "moduleAndClassPath") + public void testNamedModule(String option, boolean expected) throws Throwable { + List args = new ArrayList<>(); + if (!option.isEmpty()) { + args.add(option); + } + args.add("--module-path"); + args.add(MODS_DIR.toString()); + args.add("-m"); + args.add(TEST_MODULE + "/" + TEST_MAIN); + args.add(Boolean.toString(expected)); + + assertTrue(execute(args).getExitValue() == 0); + } + + private OutputAnalyzer execute(List options) throws Throwable { + ProcessBuilder pb = + createJavaProcessBuilder(options.toArray(new String[0])); + Map env = pb.environment(); + // remove CLASSPATH environment variable + String value = env.remove("CLASSPATH"); + return executeCommand(pb) + .outputTo(System.out) + .errorTo(System.out); + } + +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/launcher/modules/classpath/src/m/jdk/test/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/launcher/modules/classpath/src/m/jdk/test/Main.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test; + +import java.net.URL; + +public class Main { + static final String JAVA_CLASS_PATH = "java.class.path"; + + public static void main(String[] args) throws Exception { + String value = System.getProperty(JAVA_CLASS_PATH); + if (value == null) { + throw new RuntimeException(JAVA_CLASS_PATH + " is expected non-null" + + " for compatibility"); + } + + boolean expected = args[0].equals("true"); + ClassLoader loader = ClassLoader.getSystemClassLoader(); + URL url = loader.getResource("jdk/test/res.properties"); + if ((expected && url == null) || (!expected && url != null)) { + throw new RuntimeException("URL: " + url + " expected non-null: " + expected); + } + } +} diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/launcher/modules/classpath/src/m/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/launcher/modules/classpath/src/m/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module m { +} + diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/pack200/MultiRelease.java --- a/jdk/test/tools/pack200/MultiRelease.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/tools/pack200/MultiRelease.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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 @@ -60,6 +60,7 @@ } else { System.out.println("All tests(" + pass + ") passes"); } + Utils.cleanup(); } /* diff -r f71b844f33d1 -r 95af45781076 jdk/test/tools/pack200/Utils.java --- a/jdk/test/tools/pack200/Utils.java Mon Nov 14 11:15:43 2016 +0100 +++ b/jdk/test/tools/pack200/Utils.java Fri Nov 11 16:44:36 2016 +0100 @@ -94,7 +94,7 @@ } File srcDir = new File(getVerifierDir(), "src"); List javaFileList = findFiles(srcDir, createFilter(JAVA_FILE_EXT)); - File tmpFile = File.createTempFile("javac", ".tmp"); + File tmpFile = File.createTempFile("javac", ".tmp", new File(".")); XCLASSES.mkdirs(); FileOutputStream fos = null; PrintStream ps = null; @@ -208,6 +208,10 @@ Utils.createFilter(".idx"))); toDelete.addAll(Utils.findFiles(new File("."), Utils.createFilter(".gidx"))); + toDelete.addAll(Utils.findFiles(new File("."), + Utils.createFilter(".tmp"))); + toDelete.addAll(Utils.findFiles(new File("."), + Utils.createFilter(".class"))); for (File f : toDelete) { f.delete(); } diff -r f71b844f33d1 -r 95af45781076 langtools/.hgtags --- a/langtools/.hgtags Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/.hgtags Fri Nov 11 16:44:36 2016 +0100 @@ -384,3 +384,5 @@ 17a82cb0e4b480e97021691d39917f15e3f7b653 jdk-9+139 6842e63d6c3971172214b411f29965852ca175d1 jdk-9+140 296c875051187918f8f3f87e9432036d13013d39 jdk-9+141 +d245e56f4a79a8a8d18bd143c08f079ee98ab638 jdk-9+142 +6ef8a1453577832626b0efb7f70a3102b721ebbf jdk-9+143 diff -r f71b844f33d1 -r 95af45781076 langtools/make/build.xml --- a/langtools/make/build.xml Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/make/build.xml Fri Nov 11 16:44:36 2016 +0100 @@ -84,17 +84,21 @@ - + - + - + @@ -207,7 +211,9 @@ - + + + diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/doclint/Entity.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/doclint/Entity.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/doclint/Entity.java Fri Nov 11 16:44:36 2016 +0100 @@ -297,17 +297,21 @@ rsaquo(8250), euro(8364); - int code; + public final int code; private Entity(int code) { this.code = code; } - static boolean isValid(String name) { + public static boolean isValid(String name) { return names.containsKey(name); } - static boolean isValid(int code) { + public static Entity get(String name) { + return names.get(name); + } + + public static boolean isValid(int code) { // allow numeric codes for standard ANSI characters return codes.containsKey(code) || ( 32 <= code && code < 2127); } diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. 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 @@ -101,6 +101,8 @@ @Override public Main.Result call() throws Exception { prepareCompiler(false); + if (compiler.errorCount() > 0) + return Main.Result.ERROR; compiler.compile(args.getFileObjects(), args.getClassNames(), processors); return (compiler.errorCount() > 0) ? Main.Result.ERROR : Main.Result.OK; // FIXME? } diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Fri Nov 11 16:44:36 2016 +0100 @@ -1004,7 +1004,7 @@ List argtypes = msym.type.getParameterTypes(); return (msym.flags_field & NATIVE) != 0 && (msym.owner == syms.methodHandleType.tsym || msym.owner == syms.varHandleType.tsym) && - argtypes.tail.tail == null && + argtypes.length() == 1 && argtypes.head.hasTag(TypeTag.ARRAY) && ((ArrayType)argtypes.head).elemtype.tsym == syms.objectType.tsym; } @@ -2850,20 +2850,64 @@ return undef; } + public class CandidatesCache { + public Map> cache = new WeakHashMap<>(); + + class Entry { + Type site; + MethodSymbol msym; + + Entry(Type site, MethodSymbol msym) { + this.site = site; + this.msym = msym; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Entry) { + Entry e = (Entry)obj; + return e.msym == msym && isSameType(site, e.site); + } else { + return false; + } + } + + @Override + public int hashCode() { + return Types.this.hashCode(site) & ~msym.hashCode(); + } + } + + public List get(Entry e) { + return cache.get(e); + } + + public void put(Entry e, List msymbols) { + cache.put(e, msymbols); + } + } + + public CandidatesCache candidatesCache = new CandidatesCache(); //where public List interfaceCandidates(Type site, MethodSymbol ms) { - Filter filter = new MethodFilter(ms, site); - List candidates = List.nil(); + CandidatesCache.Entry e = candidatesCache.new Entry(site, ms); + List candidates = candidatesCache.get(e); + if (candidates == null) { + Filter filter = new MethodFilter(ms, site); + List candidates2 = List.nil(); for (Symbol s : membersClosure(site, false).getSymbols(filter)) { if (!site.tsym.isInterface() && !s.owner.isInterface()) { return List.of((MethodSymbol)s); - } else if (!candidates.contains(s)) { - candidates = candidates.prepend((MethodSymbol)s); + } else if (!candidates2.contains(s)) { + candidates2 = candidates2.prepend((MethodSymbol)s); } } - return prune(candidates); + candidates = prune(candidates2); + candidatesCache.put(e, candidates); } + return candidates; + } public List prune(List methods) { ListBuffer methodsMin = new ListBuffer<>(); diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Fri Nov 11 16:44:36 2016 +0100 @@ -853,9 +853,9 @@ List caughtPrev = caught; ListBuffer pendingExitsPrev = pendingExits; Lint lintPrev = lint; - + boolean anonymousClass = tree.name == names.empty; pendingExits = new ListBuffer<>(); - if (tree.name != names.empty) { + if (!anonymousClass) { caught = List.nil(); } classDef = tree; @@ -874,7 +874,7 @@ // add intersection of all thrown clauses of initial constructors // to set of caught exceptions, unless class is anonymous. - if (tree.name != names.empty) { + if (!anonymousClass) { boolean firstConstructor = true; for (List l = tree.defs; l.nonEmpty(); l = l.tail) { if (TreeInfo.isInitialConstructor(l.head)) { @@ -905,10 +905,11 @@ // Changing the throws clause on the fly is okay here because // the anonymous constructor can't be invoked anywhere else, // and its type hasn't been cached. - if (tree.name == names.empty) { + if (anonymousClass) { for (List l = tree.defs; l.nonEmpty(); l = l.tail) { - if (TreeInfo.isInitialConstructor(l.head)) { + if (TreeInfo.isConstructor(l.head)) { JCMethodDecl mdef = (JCMethodDecl)l.head; + scan(mdef); mdef.thrown = make.Types(thrown); mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown); } @@ -918,6 +919,8 @@ // process all the methods for (List l = tree.defs; l.nonEmpty(); l = l.tail) { + if (anonymousClass && TreeInfo.isConstructor(l.head)) + continue; // there can never be an uncaught exception. if (l.head.hasTag(METHODDEF)) { scan(l.head); errorUncaught(); diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java Fri Nov 11 16:44:36 2016 +0100 @@ -404,15 +404,11 @@ } else if (to.hasTag(NONE)) { to = from.isPrimitive() ? from : syms.objectType; } else if (qtype.hasTag(UNDETVAR)) { - if (resultInfo.pt.isReference()) { - if (needsEagerInstantiation((UndetVar)qtype, to, inferenceContext)) { - to = generateReferenceToTargetConstraint(tree, (UndetVar)qtype, to, resultInfo, inferenceContext); - } - } else { - if (to.isPrimitive()) { - to = generateReturnConstraintsPrimitive(tree, (UndetVar)qtype, to, - resultInfo, inferenceContext); - } + if (needsEagerInstantiation((UndetVar)qtype, to, inferenceContext) && + (allowGraphInference || !to.isPrimitive())) { + to = generateReferenceToTargetConstraint(tree, (UndetVar)qtype, to, resultInfo, inferenceContext); + } else if (to.isPrimitive()) { + to = types.boxedClass(to).type; } } else if (rsInfoInfContext.free(resultInfo.pt)) { //propagation - cache captured vars @@ -432,26 +428,21 @@ return from; } - private Type generateReturnConstraintsPrimitive(JCTree tree, UndetVar from, - Type to, Attr.ResultInfo resultInfo, InferenceContext inferenceContext) { - if (!allowGraphInference) { - //if legacy, just return boxed type - return types.boxedClass(to).type; + private boolean needsEagerInstantiation(UndetVar from, Type to, InferenceContext inferenceContext) { + if (to.isPrimitive()) { + /* T is a primitive type, and one of the primitive wrapper classes is an instantiation, + * upper bound, or lower bound for alpha in B2. + */ + for (Type t : from.getBounds(InferenceBound.values())) { + Type boundAsPrimitive = types.unboxedType(t); + if (boundAsPrimitive == null || boundAsPrimitive.hasTag(NONE)) { + continue; + } + return true; + } + return false; } - //if graph inference we need to skip conflicting boxed bounds... - for (Type t : from.getBounds(InferenceBound.EQ, InferenceBound.UPPER, - InferenceBound.LOWER)) { - Type boundAsPrimitive = types.unboxedType(t); - if (boundAsPrimitive == null || boundAsPrimitive.hasTag(NONE)) { - continue; - } - return generateReferenceToTargetConstraint(tree, from, to, - resultInfo, inferenceContext); - } - return types.boxedClass(to).type; - } - private boolean needsEagerInstantiation(UndetVar from, Type to, InferenceContext inferenceContext) { Type captureOfTo = types.capture(to); /* T is a reference type, but is not a wildcard-parameterized type, and either */ diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java Fri Nov 11 16:44:36 2016 +0100 @@ -36,7 +36,6 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.function.Consumer; import java.util.function.Predicate; @@ -59,6 +58,7 @@ import com.sun.tools.javac.code.Directive.UsesDirective; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Kinds; +import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.ModuleFinder; import com.sun.tools.javac.code.Source; import com.sun.tools.javac.code.Symbol; @@ -131,6 +131,7 @@ private final Types types; private final JavaFileManager fileManager; private final ModuleFinder moduleFinder; + private final Source source; private final boolean allowModules; public final boolean multiModuleMode; @@ -151,6 +152,8 @@ private final String limitModsOpt; private final Set extraLimitMods = new HashSet<>(); + private final boolean lintOptions; + private Set rootModules = null; public static Modules instance(Context context) { @@ -170,9 +173,12 @@ moduleFinder = ModuleFinder.instance(context); types = Types.instance(context); fileManager = context.get(JavaFileManager.class); - allowModules = Source.instance(context).allowModules(); + source = Source.instance(context); + allowModules = source.allowModules(); Options options = Options.instance(context); + lintOptions = options.isUnset(Option.XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option); + moduleOverride = options.get(Option.XMODULE); multiModuleMode = fileManager.hasLocation(StandardLocation.MODULE_SOURCE_PATH); @@ -487,7 +493,7 @@ ModuleSymbol msym = moduleFinder.findModule((ModuleSymbol) sym); if (msym.kind == Kinds.Kind.ERR) { - log.error(Errors.CantFindModule(msym)); + log.error(Errors.ModuleNotFound(msym)); //make sure the module is initialized: msym.directives = List.nil(); msym.exports = List.nil(); @@ -684,15 +690,10 @@ } private ModuleSymbol lookupModule(JCExpression moduleName) { - try { Name name = TreeInfo.fullName(moduleName); ModuleSymbol msym = moduleFinder.findModule(name); TreeInfo.setSymbol(moduleName, msym); return msym; - } catch (Throwable t) { - System.err.println("Module " + sym + "; lookup export " + moduleName); - throw t; - } } } @@ -776,8 +777,6 @@ log.error(tree.implName.pos(), Errors.ServiceImplementationIsAbstract(impl)); } else if (impl.isInner()) { log.error(tree.implName.pos(), Errors.ServiceImplementationIsInner(impl)); - } else if (service.isInner()) { - log.error(tree.serviceName.pos(), Errors.ServiceDefinitionIsInner(service)); } else { MethodSymbol constr = noArgsConstructor(impl); if (constr == null) { @@ -884,6 +883,8 @@ Set limitMods = new HashSet<>(); if (limitModsOpt != null) { for (String limit : limitModsOpt.split(",")) { + if (!isValidName(limit)) + continue; limitMods.add(syms.enterModule(names.fromString(limit))); } } @@ -892,6 +893,14 @@ } observable = computeTransitiveClosure(limitMods, null); observable.addAll(rootModules); + if (lintOptions) { + for (ModuleSymbol msym : limitMods) { + if (!observable.contains(msym)) { + log.warning(LintCategory.OPTIONS, + Warnings.ModuleForOptionNotFound(Option.LIMIT_MODULES, msym)); + } + } + } } Predicate observablePred = sym -> observable == null || observable.contains(sym); @@ -944,6 +953,8 @@ .filter(systemModulePred.negate().and(observablePred)); break; default: + if (!isValidName(added)) + continue; modules = Stream.of(syms.enterModule(names.fromString(added))); break; } @@ -1141,8 +1152,9 @@ addVisiblePackages(msym, seen, rm, rm.exports); } - for (Entry> addExportsEntry : addExports.entrySet()) - addVisiblePackages(msym, seen, addExportsEntry.getKey(), addExportsEntry.getValue()); + addExports.forEach((exportsFrom, exports) -> { + addVisiblePackages(msym, seen, exportsFrom, exports); + }); } private void addVisiblePackages(ModuleSymbol msym, @@ -1180,12 +1192,11 @@ return; addExports = new LinkedHashMap<>(); + Set unknownModules = new HashSet<>(); if (addExportsOpt == null) return; -// System.err.println("Modules.addExports:\n " + addExportsOpt.replace("\0", "\n ")); - Pattern ep = Pattern.compile("([^/]+)/([^=]+)=(.*)"); for (String s: addExportsOpt.split("\0+")) { if (s.isEmpty()) @@ -1203,7 +1214,15 @@ String packageName = em.group(2); String targetNames = em.group(3); + if (!isValidName(moduleName)) + continue; + ModuleSymbol msym = syms.enterModule(names.fromString(moduleName)); + if (!isKnownModule(msym, unknownModules)) + continue; + + if (!isValidName(packageName)) + continue; PackageSymbol p = syms.enterPackage(msym, names.fromString(packageName)); p.modle = msym; // TODO: do we need this? @@ -1213,11 +1232,11 @@ if (toModule.equals("ALL-UNNAMED")) { m = syms.unnamedModule; } else { - if (!SourceVersion.isName(toModule)) { - // TODO: error: invalid module name + if (!isValidName(toModule)) continue; - } m = syms.enterModule(names.fromString(toModule)); + if (!isKnownModule(m, unknownModules)) + continue; } targetModules = targetModules.prepend(m); } @@ -1228,6 +1247,21 @@ } } + private boolean isKnownModule(ModuleSymbol msym, Set unknownModules) { + if (allModules.contains(msym)) { + return true; + } + + if (!unknownModules.contains(msym)) { + if (lintOptions) { + log.warning(LintCategory.OPTIONS, + Warnings.ModuleForOptionNotFound(Option.ADD_EXPORTS, msym)); + } + unknownModules.add(msym); + } + return false; + } + private void initAddReads() { if (addReads != null) return; @@ -1237,8 +1271,6 @@ if (addReadsOpt == null) return; -// System.err.println("Modules.addReads:\n " + addReadsOpt.replace("\0", "\n ")); - Pattern rp = Pattern.compile("([^=]+)=(.*)"); for (String s : addReadsOpt.split("\0+")) { if (s.isEmpty()) @@ -1249,26 +1281,40 @@ } // Terminology comes from - // --add-reads target-module=source-module,... + // --add-reads source-module=target-module,... // Compare to - // module target-module { requires source-module; ... } - String targetName = rm.group(1); - String sources = rm.group(2); + // module source-module { requires target-module; ... } + String sourceName = rm.group(1); + String targetNames = rm.group(2); + + if (!isValidName(sourceName)) + continue; - ModuleSymbol msym = syms.enterModule(names.fromString(targetName)); - for (String source : sources.split("[ ,]+")) { - ModuleSymbol sourceModule; - if (source.equals("ALL-UNNAMED")) { - sourceModule = syms.unnamedModule; + ModuleSymbol msym = syms.enterModule(names.fromString(sourceName)); + if (!allModules.contains(msym)) { + if (lintOptions) { + log.warning(Warnings.ModuleForOptionNotFound(Option.ADD_READS, msym)); + } + continue; + } + + for (String targetName : targetNames.split("[ ,]+", -1)) { + ModuleSymbol targetModule; + if (targetName.equals("ALL-UNNAMED")) { + targetModule = syms.unnamedModule; } else { - if (!SourceVersion.isName(source)) { - // TODO: error: invalid module name + if (!isValidName(targetName)) + continue; + targetModule = syms.enterModule(names.fromString(targetName)); + if (!allModules.contains(targetModule)) { + if (lintOptions) { + log.warning(LintCategory.OPTIONS, Warnings.ModuleForOptionNotFound(Option.ADD_READS, targetModule)); + } continue; } - sourceModule = syms.enterModule(names.fromString(source)); } addReads.computeIfAbsent(msym, m -> new HashSet<>()) - .add(new RequiresDirective(sourceModule, EnumSet.of(RequiresFlag.EXTRA))); + .add(new RequiresDirective(targetModule, EnumSet.of(RequiresFlag.EXTRA))); } } } @@ -1301,6 +1347,10 @@ } } + private boolean isValidName(CharSequence name) { + return SourceVersion.isName(name, Source.toSourceVersion(source)); + } + // DEBUG private String toString(ModuleSymbol msym) { return msym.name + "[" diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Nov 11 16:44:36 2016 +0100 @@ -554,7 +554,8 @@ } else if (mt.hasTag(FORALL) && typeargtypes.nonEmpty()) { ForAll pmt = (ForAll) mt; if (typeargtypes.length() != pmt.tvars.length()) - throw inapplicableMethodException.setMessage("arg.length.mismatch"); // not enough args + // not enough args + throw inapplicableMethodException.setMessage("wrong.number.type.args", Integer.toString(pmt.tvars.length())); // Check type arguments are within bounds List formals = pmt.tvars; List actuals = typeargtypes; diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java Fri Nov 11 16:44:36 2016 +0100 @@ -39,6 +39,7 @@ import java.nio.file.FileSystemNotFoundException; import java.nio.file.FileSystems; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.ProviderNotFoundException; @@ -66,6 +67,7 @@ import javax.lang.model.SourceVersion; import javax.tools.JavaFileManager; import javax.tools.JavaFileManager.Location; +import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.StandardJavaFileManager.PathFactory; import javax.tools.StandardLocation; @@ -137,7 +139,11 @@ } Path getPath(String first, String... more) { - return pathFactory.getPath(first, more); + try { + return pathFactory.getPath(first, more); + } catch (InvalidPathException ipe) { + throw new IllegalArgumentException(ipe); + } } public void close() throws IOException { diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Nov 11 16:44:36 2016 +0100 @@ -1328,7 +1328,7 @@ } else { ((ClassType)sym.type).setEnclosingType(Type.noType); } - enterTypevars(self); + enterTypevars(self, self.type); if (!missingTypeVariables.isEmpty()) { ListBuffer typeVars = new ListBuffer<>(); for (Type typevar : missingTypeVariables) { @@ -2353,19 +2353,17 @@ /** Enter type variables of this classtype and all enclosing ones in * `typevars'. */ - protected void enterTypevars(Type t) { - if (t.getEnclosingType() != null && t.getEnclosingType().hasTag(CLASS)) - enterTypevars(t.getEnclosingType()); - for (List xs = t.getTypeArguments(); xs.nonEmpty(); xs = xs.tail) + protected void enterTypevars(Symbol sym, Type t) { + if (t.getEnclosingType() != null) { + if (!t.getEnclosingType().hasTag(TypeTag.NONE)) { + enterTypevars(sym.owner, t.getEnclosingType()); + } + } else if (sym.kind == MTH && !sym.isStatic()) { + enterTypevars(sym.owner, sym.owner.type); + } + for (List xs = t.getTypeArguments(); xs.nonEmpty(); xs = xs.tail) { typevars.enter(xs.head.tsym); - } - - protected void enterTypevars(Symbol sym) { - if (sym.owner.kind == MTH) { - enterTypevars(sym.owner); - enterTypevars(sym.owner.owner); } - enterTypevars(sym.type); } protected ClassSymbol enterClass(Name name) { @@ -2388,7 +2386,7 @@ // prepare type variable table typevars = typevars.dup(currentOwner); if (ct.getEnclosingType().hasTag(CLASS)) - enterTypevars(ct.getEnclosingType()); + enterTypevars(c.owner, ct.getEnclosingType()); // read flags, or skip if this is an inner class long f = nextChar(); @@ -2545,6 +2543,11 @@ types.subst(ct.supertype_field, missing, found); ct.interfaces_field = types.subst(ct.interfaces_field, missing, found); + ct.typarams_field = + types.substBounds(ct.typarams_field, missing, found); + for (List types = ct.typarams_field; types.nonEmpty(); types = types.tail) { + types.head.tsym.type = types.head; + } } else if (missingTypeVariables.isEmpty() != foundTypeVariables.isEmpty()) { Name name = missingTypeVariables.head.tsym.name; diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java Fri Nov 11 16:44:36 2016 +0100 @@ -43,6 +43,7 @@ import java.util.regex.Pattern; import java.util.stream.Stream; +import javax.lang.model.SourceVersion; import javax.tools.JavaFileManager; import javax.tools.JavaFileManager.Location; import javax.tools.JavaFileObject; @@ -400,7 +401,7 @@ /** * Validates the overall consistency of the options and operands * processed by processOptions. - * @return true if all args are successfully validating; false otherwise. + * @return true if all args are successfully validated; false otherwise. * @throws IllegalStateException if a problem is found and errorMode is set to * ILLEGAL_STATE */ @@ -610,62 +611,143 @@ if (obsoleteOptionFound) log.warning(LintCategory.OPTIONS, "option.obsolete.suppression"); + SourceVersion sv = Source.toSourceVersion(source); + validateAddExports(sv); + validateAddModules(sv); + validateAddReads(sv); + validateLimitModules(sv); + + return !errors && (log.nerrors == 0); + } + + private void validateAddExports(SourceVersion sv) { String addExports = options.get(Option.ADD_EXPORTS); if (addExports != null) { - // Each entry must be of the form module/package=target-list where target-list is a - // comma-separated list of module or ALL-UNNAMED. - // All module/package pairs must be unique. - Pattern p = Pattern.compile("([^/]+)/([^=]+)=(.*)"); - Map> map = new LinkedHashMap<>(); - for (String e: addExports.split("\0")) { + // Each entry must be of the form sourceModule/sourcePackage=target-list where + // target-list is a comma separated list of module or ALL-UNNAMED. + // Empty items in the target-list are ignored. + // There must be at least one item in the list; this is handled in Option.ADD_EXPORTS. + Pattern p = Option.ADD_EXPORTS.getPattern(); + for (String e : addExports.split("\0")) { Matcher m = p.matcher(e); - if (!m.matches()) { - log.error(Errors.XaddexportsMalformedEntry(e)); - continue; + if (m.matches()) { + String sourceModuleName = m.group(1); + if (!SourceVersion.isName(sourceModuleName, sv)) { + // syntactically invalid source name: e.g. --add-exports m!/p1=m2 + log.warning(Warnings.BadNameForOption(Option.ADD_EXPORTS, sourceModuleName)); + } + String sourcePackageName = m.group(2); + if (!SourceVersion.isName(sourcePackageName, sv)) { + // syntactically invalid source name: e.g. --add-exports m1/p!=m2 + log.warning(Warnings.BadNameForOption(Option.ADD_EXPORTS, sourcePackageName)); + } + + String targetNames = m.group(3); + for (String targetName : targetNames.split(",")) { + switch (targetName) { + case "": + case "ALL-UNNAMED": + break; + + default: + if (!SourceVersion.isName(targetName, sv)) { + // syntactically invalid target name: e.g. --add-exports m1/p1=m! + log.warning(Warnings.BadNameForOption(Option.ADD_EXPORTS, targetName)); + } + break; + } + } } - String eModule = m.group(1); // TODO: check a valid dotted identifier - String ePackage = m.group(2); // TODO: check a valid dotted identifier - String eTargets = m.group(3); // TODO: check a valid list of dotted identifier or ALL-UNNAMED - String eModPkg = eModule + '/' + ePackage; - List l = map.get(eModPkg); - map.put(eModPkg, (l == null) ? List.of(eTargets) : l.prepend(eTargets)); } - map.forEach((key, value) -> { - if (value.size() > 1) { - log.error(Errors.XaddexportsTooMany(key)); - // TODO: consider adding diag fragments for the entries - } - }); } + } + private void validateAddReads(SourceVersion sv) { String addReads = options.get(Option.ADD_READS); if (addReads != null) { - // Each entry must be of the form module=source-list where source-list is a - // comma separated list of module or ALL-UNNAMED. - // All target modules (i.e. on left of '=') must be unique. - Pattern p = Pattern.compile("([^=]+)=(.*)"); - Map> map = new LinkedHashMap<>(); - for (String e: addReads.split("\0")) { + // Each entry must be of the form source=target-list where target-list is a + // comma-separated list of module or ALL-UNNAMED. + // Empty items in the target list are ignored. + // There must be at least one item in the list; this is handled in Option.ADD_READS. + Pattern p = Option.ADD_READS.getPattern(); + for (String e : addReads.split("\0")) { Matcher m = p.matcher(e); - if (!m.matches()) { - log.error(Errors.XaddreadsMalformedEntry(e)); - continue; + if (m.matches()) { + String sourceName = m.group(1); + if (!SourceVersion.isName(sourceName, sv)) { + // syntactically invalid source name: e.g. --add-reads m!=m2 + log.warning(Warnings.BadNameForOption(Option.ADD_READS, sourceName)); + } + + String targetNames = m.group(2); + for (String targetName : targetNames.split(",", -1)) { + switch (targetName) { + case "": + case "ALL-UNNAMED": + break; + + default: + if (!SourceVersion.isName(targetName, sv)) { + // syntactically invalid target name: e.g. --add-reads m1=m! + log.warning(Warnings.BadNameForOption(Option.ADD_READS, targetName)); + } + break; + } + } } - String eModule = m.group(1); // TODO: check a valid dotted identifier - String eSources = m.group(2); // TODO: check a valid list of dotted identifier or ALL-UNNAMED - List l = map.get(eModule); - map.put(eModule, (l == null) ? List.of(eSources) : l.prepend(eSources)); } - map.forEach((key, value) -> { - if (value.size() > 1) { - log.error(Errors.XaddreadsTooMany(key)); - // TODO: consider adding diag fragments for the entries + } + } + + private void validateAddModules(SourceVersion sv) { + String addModules = options.get(Option.ADD_MODULES); + if (addModules != null) { + // Each entry must be of the form target-list where target-list is a + // comma separated list of module names, or ALL-DEFAULT, ALL-SYSTEM, + // or ALL-MODULE_PATH. + // Empty items in the target list are ignored. + // There must be at least one item in the list; this is handled in Option.ADD_MODULES. + for (String moduleName : addModules.split(",")) { + switch (moduleName) { + case "": + case "ALL-DEFAULT": + case "ALL-SYSTEM": + case "ALL-MODULE-PATH": + break; + + default: + if (!SourceVersion.isName(moduleName, sv)) { + // syntactically invalid module name: e.g. --add-modules m1,m! + log.warning(Warnings.BadNameForOption(Option.ADD_MODULES, moduleName)); + } + break; } - }); + } } + } + private void validateLimitModules(SourceVersion sv) { + String limitModules = options.get(Option.LIMIT_MODULES); + if (limitModules != null) { + // Each entry must be of the form target-list where target-list is a + // comma separated list of module names, or ALL-DEFAULT, ALL-SYSTEM, + // or ALL-MODULE_PATH. + // Empty items in the target list are ignored. + // There must be at least one item in the list; this is handled in Option.LIMIT_EXPORTS. + for (String moduleName : limitModules.split(",")) { + switch (moduleName) { + case "": + break; - return !errors; + default: + if (!SourceVersion.isName(moduleName, sv)) { + // syntactically invalid module name: e.g. --limit-modules m1,m! + log.warning(Warnings.BadNameForOption(Option.LIMIT_MODULES, moduleName)); + } + break; + } + } + } } /** diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java Fri Nov 11 16:44:36 2016 +0100 @@ -43,6 +43,7 @@ import java.util.ServiceLoader; import java.util.Set; import java.util.TreeSet; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -556,18 +557,44 @@ ADD_EXPORTS("--add-exports", "opt.arg.addExports", "opt.addExports", EXTENDED, BASIC) { @Override public boolean process(OptionHelper helper, String option, String arg) { - String prev = helper.get(ADD_EXPORTS); - helper.put(ADD_EXPORTS.primaryName, (prev == null) ? arg : prev + '\0' + arg); - return false; + if (arg.isEmpty()) { + helper.error("err.no.value.for.option", option); + return true; + } else if (getPattern().matcher(arg).matches()) { + String prev = helper.get(ADD_EXPORTS); + helper.put(ADD_EXPORTS.primaryName, (prev == null) ? arg : prev + '\0' + arg); + return false; + } else { + helper.error("err.bad.value.for.option", option, arg); + return true; + } + } + + @Override + public Pattern getPattern() { + return Pattern.compile("([^/]+)/([^=]+)=(,*[^,].*)"); } }, ADD_READS("--add-reads", "opt.arg.addReads", "opt.addReads", EXTENDED, BASIC) { @Override public boolean process(OptionHelper helper, String option, String arg) { - String prev = helper.get(ADD_READS); - helper.put(ADD_READS.primaryName, (prev == null) ? arg : prev + '\0' + arg); - return false; + if (arg.isEmpty()) { + helper.error("err.no.value.for.option", option); + return true; + } else if (getPattern().matcher(arg).matches()) { + String prev = helper.get(ADD_READS); + helper.put(ADD_READS.primaryName, (prev == null) ? arg : prev + '\0' + arg); + return false; + } else { + helper.error("err.bad.value.for.option", option, arg); + return true; + } + } + + @Override + public Pattern getPattern() { + return Pattern.compile("([^=]+)=(,*[^,].*)"); } }, @@ -577,6 +604,7 @@ String prev = helper.get(XMODULE); if (prev != null) { helper.error("err.option.too.many", XMODULE.primaryName); + return true; } helper.put(XMODULE.primaryName, arg); return false; @@ -585,9 +613,50 @@ MODULE("--module -m", "opt.arg.m", "opt.m", STANDARD, BASIC), - ADD_MODULES("--add-modules", "opt.arg.addmods", "opt.addmods", STANDARD, BASIC), + ADD_MODULES("--add-modules", "opt.arg.addmods", "opt.addmods", STANDARD, BASIC) { + @Override + public boolean process(OptionHelper helper, String option, String arg) { + if (arg.isEmpty()) { + helper.error("err.no.value.for.option", option); + return true; + } else if (getPattern().matcher(arg).matches()) { + String prev = helper.get(ADD_MODULES); + // since the individual values are simple names, we can simply join the + // values of multiple --add-modules options with ',' + helper.put(ADD_MODULES.primaryName, (prev == null) ? arg : prev + ',' + arg); + return false; + } else { + helper.error("err.bad.value.for.option", option, arg); + return true; + } + } - LIMIT_MODULES("--limit-modules", "opt.arg.limitmods", "opt.limitmods", STANDARD, BASIC), + @Override + public Pattern getPattern() { + return Pattern.compile(",*[^,].*"); + } + }, + + LIMIT_MODULES("--limit-modules", "opt.arg.limitmods", "opt.limitmods", STANDARD, BASIC) { + @Override + public boolean process(OptionHelper helper, String option, String arg) { + if (arg.isEmpty()) { + helper.error("err.no.value.for.option", option); + return true; + } else if (getPattern().matcher(arg).matches()) { + helper.put(LIMIT_MODULES.primaryName, arg); // last one wins + return false; + } else { + helper.error("err.bad.value.for.option", option, arg); + return true; + } + } + + @Override + public Pattern getPattern() { + return Pattern.compile(",*[^,].*"); + } + }, // This option exists only for the purpose of documenting itself. // It's actually implemented by the CommandLine class. @@ -963,20 +1032,24 @@ */ public boolean handleOption(OptionHelper helper, String arg, Iterator rest) { if (hasArg()) { + String option; String operand; int sep = findSeparator(arg); if (getArgKind() == Option.ArgKind.ADJACENT) { + option = primaryName; // aliases not supported operand = arg.substring(primaryName.length()); } else if (sep > 0) { + option = arg.substring(0, sep); operand = arg.substring(sep + 1); } else { if (!rest.hasNext()) { helper.error("err.req.arg", arg); return false; } + option = arg; operand = rest.next(); } - return !process(helper, arg, operand); + return !process(helper, option, operand); } else { return !process(helper, arg); } @@ -1033,6 +1106,15 @@ } /** + * Returns a pattern to analyze the value for an option. + * @return the pattern + * @throws UnsupportedOperationException if an option does not provide a pattern. + */ + public Pattern getPattern() { + throw new UnsupportedOperationException(); + } + + /** * Scans a word to find the first separator character, either colon or equals. * @param word the word to be scanned * @return the position of the first':' or '=' character in the word, diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Nov 11 16:44:36 2016 +0100 @@ -2124,6 +2124,10 @@ compiler.misc.arg.length.mismatch=\ actual and formal argument lists differ in length +# 0: string +compiler.misc.wrong.number.type.args=\ + wrong number of type arguments; required {0} + # 0: message segment compiler.misc.no.conforming.assignment.exists=\ argument mismatch; {0} @@ -2766,10 +2770,6 @@ the service implementation is an inner class: {0} # 0: symbol -compiler.err.service.definition.is.inner=\ - the service definition is an inner class: {0} - -# 0: symbol compiler.err.service.definition.is.enum=\ the service definition is an enum: {0} @@ -2844,21 +2844,13 @@ compiler.err.duplicate.module.on.path=\ duplicate module on {0}\nmodule in {1} -# 0: string -compiler.err.xaddexports.malformed.entry=\ - bad value for --add-exports {0} - -# 0: string -compiler.err.xaddexports.too.many=\ - multiple --add-exports options for {0} - -# 0: string -compiler.err.xaddreads.malformed.entry=\ - bad value for --add-reads {0} - -# 0: string -compiler.err.xaddreads.too.many=\ - multiple --add-reads options for {0} +# 0: option name, 1: string +compiler.warn.bad.name.for.option=\ + bad name in value for {0} option: ''{1}'' + +# 0: option name, 1: symbol +compiler.warn.module.for.option.not.found=\ + module name in {0} option not found: {1} compiler.err.addmods.all.module.path.invalid=\ --add-modules ALL-MODULE-PATH can only be used when compiling the unnamed module @@ -2878,10 +2870,6 @@ compiler.misc.cant.resolve.modules=\ cannot resolve modules -# 0: symbol -compiler.err.cant.find.module=\ - cannot find module: {0} - # 0: string compiler.err.invalid.module.specifier=\ module specifier not allowed: {0} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties Fri Nov 11 16:44:36 2016 +0100 @@ -357,6 +357,10 @@ not a file: {0} javac.err.cannot.access.runtime.env=\ cannot access runtime environment +javac.err.bad.value.for.option=\ + bad value for {0} option: ''{1}'' +javac.err.no.value.for.option=\ + no value for {0} option ## messages diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java Fri Nov 11 16:44:36 2016 +0100 @@ -48,6 +48,7 @@ import com.sun.tools.javac.code.Type.CapturedType; import com.sun.tools.javac.file.PathFileObject; import com.sun.tools.javac.jvm.Profile; +import com.sun.tools.javac.main.Option; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.tree.Pretty; @@ -204,6 +205,9 @@ else if (arg instanceof Profile) { return ((Profile)arg).name; } + else if (arg instanceof Option) { + return ((Option)arg).primaryName; + } else if (arg instanceof Formattable) { return ((Formattable)arg).toString(l, messages); } diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Iterators.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Iterators.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Iterators.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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 @@ -62,9 +62,9 @@ } public O next() { - if (!hasNext()) + if (currentIterator == EMPTY && !hasNext()) { throw new NoSuchElementException(); - + } return currentIterator.next(); } diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocFormatter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocFormatter.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,706 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.shellsupport.doc; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.Stack; + +import javax.lang.model.element.Name; +import javax.tools.JavaFileObject.Kind; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +import com.sun.source.doctree.AttributeTree; +import com.sun.source.doctree.DocCommentTree; +import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.EndElementTree; +import com.sun.source.doctree.EntityTree; +import com.sun.source.doctree.InlineTagTree; +import com.sun.source.doctree.LinkTree; +import com.sun.source.doctree.LiteralTree; +import com.sun.source.doctree.ParamTree; +import com.sun.source.doctree.ReturnTree; +import com.sun.source.doctree.StartElementTree; +import com.sun.source.doctree.TextTree; +import com.sun.source.doctree.ThrowsTree; +import com.sun.source.util.DocTreeScanner; +import com.sun.source.util.DocTrees; +import com.sun.source.util.JavacTask; +import com.sun.tools.doclint.Entity; +import com.sun.tools.doclint.HtmlTag; +import com.sun.tools.javac.util.DefinedBy; +import com.sun.tools.javac.util.DefinedBy.Api; +import com.sun.tools.javac.util.StringUtils; + +/**A javadoc to plain text formatter. + * + */ +public class JavadocFormatter { + + private static final String CODE_RESET = "\033[0m"; + private static final String CODE_HIGHLIGHT = "\033[1m"; + private static final String CODE_UNDERLINE = "\033[4m"; + + private final int lineLimit; + private final boolean escapeSequencesSupported; + + /** Construct the formatter. + * + * @param lineLimit maximum line length + * @param escapeSequencesSupported whether escape sequences are supported + */ + public JavadocFormatter(int lineLimit, boolean escapeSequencesSupported) { + this.lineLimit = lineLimit; + this.escapeSequencesSupported = escapeSequencesSupported; + } + + private static final int MAX_LINE_LENGTH = 95; + private static final int SHORTEST_LINE = 30; + private static final int INDENT = 4; + + /**Format javadoc to plain text. + * + * @param header element caption that should be used + * @param javadoc to format + * @return javadoc formatted to plain text + */ + public String formatJavadoc(String header, String javadoc) { + try { + StringBuilder result = new StringBuilder(); + + result.append(escape(CODE_HIGHLIGHT)).append(header).append(escape(CODE_RESET)).append("\n"); + + if (javadoc == null) { + return result.toString(); + } + + JavacTask task = (JavacTask) ToolProvider.getSystemJavaCompiler().getTask(null, null, null, null, null, null); + DocTrees trees = DocTrees.instance(task); + DocCommentTree docComment = trees.getDocCommentTree(new SimpleJavaFileObject(new URI("mem://doc.html"), Kind.HTML) { + @Override @DefinedBy(Api.COMPILER) + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return "" + javadoc + ""; + } + }); + + new FormatJavadocScanner(result, task).scan(docComment, null); + + addNewLineIfNeeded(result); + + return result.toString(); + } catch (URISyntaxException ex) { + throw new InternalError("Unexpected exception", ex); + } + } + + private class FormatJavadocScanner extends DocTreeScanner { + private final StringBuilder result; + private final JavacTask task; + private int reflownTo; + private int indent; + private int limit = Math.min(lineLimit, MAX_LINE_LENGTH); + private boolean pre; + private Map tableColumns; + + public FormatJavadocScanner(StringBuilder result, JavacTask task) { + this.result = result; + this.task = task; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Object visitDocComment(DocCommentTree node, Object p) { + tableColumns = countTableColumns(node); + reflownTo = result.length(); + scan(node.getFirstSentence(), p); + scan(node.getBody(), p); + reflow(result, reflownTo, indent, limit); + for (Sections current : docSections.keySet()) { + boolean seenAny = false; + for (DocTree t : node.getBlockTags()) { + if (current.matches(t)) { + if (!seenAny) { + seenAny = true; + if (result.charAt(result.length() - 1) != '\n') + result.append("\n"); + result.append("\n"); + result.append(escape(CODE_UNDERLINE)) + .append(docSections.get(current)) + .append(escape(CODE_RESET)) + .append("\n"); + } + + scan(t, null); + } + } + } + return null; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Object visitText(TextTree node, Object p) { + String text = node.getBody(); + if (!pre) { + text = text.replaceAll("[ \t\r\n]+", " ").trim(); + if (text.isEmpty()) { + text = " "; + } + } else { + text = text.replaceAll("\n", "\n" + indentString(indent)); + } + result.append(text); + return null; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Object visitLink(LinkTree node, Object p) { + if (!node.getLabel().isEmpty()) { + scan(node.getLabel(), p); + } else { + result.append(node.getReference().getSignature()); + } + return null; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Object visitParam(ParamTree node, Object p) { + return formatDef(node.getName().getName(), node.getDescription()); + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Object visitThrows(ThrowsTree node, Object p) { + return formatDef(node.getExceptionName().getSignature(), node.getDescription()); + } + + public Object formatDef(CharSequence name, List description) { + result.append(name); + result.append(" - "); + reflownTo = result.length(); + indent = name.length() + 3; + + if (limit - indent < SHORTEST_LINE) { + result.append("\n"); + result.append(indentString(INDENT)); + indent = INDENT; + reflownTo += INDENT; + } + try { + return scan(description, null); + } finally { + reflow(result, reflownTo, indent, limit); + result.append("\n"); + } + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Object visitLiteral(LiteralTree node, Object p) { + return scan(node.getBody(), p); + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Object visitReturn(ReturnTree node, Object p) { + reflownTo = result.length(); + try { + return super.visitReturn(node, p); + } finally { + reflow(result, reflownTo, 0, limit); + } + } + + Stack listStack = new Stack<>(); + Stack defStack = new Stack<>(); + Stack tableStack = new Stack<>(); + Stack> cellsStack = new Stack<>(); + Stack> headerStack = new Stack<>(); + + @Override @DefinedBy(Api.COMPILER_TREE) + public Object visitStartElement(StartElementTree node, Object p) { + switch (HtmlTag.get(node.getName())) { + case P: + if (lastNode!= null && lastNode.getKind() == DocTree.Kind.START_ELEMENT && + HtmlTag.get(((StartElementTree) lastNode).getName()) == HtmlTag.LI) { + //ignore + break; + } + reflowTillNow(); + addNewLineIfNeeded(result); + result.append(indentString(indent)); + reflownTo = result.length(); + break; + case BLOCKQUOTE: + reflowTillNow(); + indent += INDENT; + break; + case PRE: + reflowTillNow(); + pre = true; + break; + case UL: + reflowTillNow(); + listStack.push(-1); + indent += INDENT; + break; + case OL: + reflowTillNow(); + listStack.push(1); + indent += INDENT; + break; + case DL: + reflowTillNow(); + defStack.push(indent); + break; + case LI: + reflowTillNow(); + if (!listStack.empty()) { + addNewLineIfNeeded(result); + + int top = listStack.pop(); + + if (top == (-1)) { + result.append(indentString(indent - 2)); + result.append("* "); + } else { + result.append(indentString(indent - 3)); + result.append("" + top++ + ". "); + } + + listStack.push(top); + + reflownTo = result.length(); + } + break; + case DT: + reflowTillNow(); + if (!defStack.isEmpty()) { + addNewLineIfNeeded(result); + indent = defStack.peek(); + result.append(escape(CODE_HIGHLIGHT)); + } + break; + case DD: + reflowTillNow(); + if (!defStack.isEmpty()) { + if (indent == defStack.peek()) { + result.append(escape(CODE_RESET)); + } + addNewLineIfNeeded(result); + indent = defStack.peek() + INDENT; + result.append(indentString(indent)); + } + break; + case H1: case H2: case H3: + case H4: case H5: case H6: + reflowTillNow(); + addNewLineIfNeeded(result); + result.append("\n") + .append(escape(CODE_UNDERLINE)); + reflownTo = result.length(); + break; + case TABLE: + int columns = tableColumns.get(node); + + if (columns == 0) { + break; //broken input + } + + reflowTillNow(); + addNewLineIfNeeded(result); + reflownTo = result.length(); + + tableStack.push(limit); + + limit = (limit - 1) / columns - 3; + + for (int sep = 0; sep < (limit + 3) * columns + 1; sep++) { + result.append("-"); + } + + result.append("\n"); + + break; + case TR: + if (cellsStack.size() >= tableStack.size()) { + //unclosed : + handleEndElement(node.getName()); + } + cellsStack.push(new ArrayList<>()); + headerStack.push(new ArrayList<>()); + break; + case TH: + case TD: + if (cellsStack.isEmpty()) { + //broken code + break; + } + reflowTillNow(); + result.append("\n"); + reflownTo = result.length(); + cellsStack.peek().add(result.length()); + headerStack.peek().add(HtmlTag.get(node.getName()) == HtmlTag.TH); + break; + case IMG: + for (DocTree attr : node.getAttributes()) { + if (attr.getKind() != DocTree.Kind.ATTRIBUTE) { + continue; + } + AttributeTree at = (AttributeTree) attr; + if ("alt".equals(StringUtils.toLowerCase(at.getName().toString()))) { + addSpaceIfNeeded(result); + scan(at.getValue(), null); + addSpaceIfNeeded(result); + break; + } + } + break; + default: + addSpaceIfNeeded(result); + break; + } + return null; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Object visitEndElement(EndElementTree node, Object p) { + handleEndElement(node.getName()); + return super.visitEndElement(node, p); + } + + private void handleEndElement(Name name) { + switch (HtmlTag.get(name)) { + case BLOCKQUOTE: + indent -= INDENT; + break; + case PRE: + pre = false; + addNewLineIfNeeded(result); + reflownTo = result.length(); + break; + case UL: case OL: + if (listStack.isEmpty()) { //ignore stray closing tag + break; + } + reflowTillNow(); + listStack.pop(); + indent -= INDENT; + addNewLineIfNeeded(result); + break; + case DL: + if (defStack.isEmpty()) {//ignore stray closing tag + break; + } + reflowTillNow(); + if (indent == defStack.peek()) { + result.append(escape(CODE_RESET)); + } + indent = defStack.pop(); + addNewLineIfNeeded(result); + break; + case H1: case H2: case H3: + case H4: case H5: case H6: + reflowTillNow(); + result.append(escape(CODE_RESET)) + .append("\n"); + reflownTo = result.length(); + break; + case TABLE: + if (cellsStack.size() >= tableStack.size()) { + //unclosed : + handleEndElement(task.getElements().getName("tr")); + } + + if (tableStack.isEmpty()) { + break; + } + + limit = tableStack.pop(); + break; + case TR: + if (cellsStack.isEmpty()) { + break; + } + + reflowTillNow(); + + List cells = cellsStack.pop(); + List headerFlags = headerStack.pop(); + List content = new ArrayList<>(); + int maxLines = 0; + + result.append("\n"); + + while (!cells.isEmpty()) { + int currentCell = cells.remove(cells.size() - 1); + String[] lines = result.substring(currentCell, result.length()).split("\n"); + + result.delete(currentCell - 1, result.length()); + + content.add(lines); + maxLines = Math.max(maxLines, lines.length); + } + + Collections.reverse(content); + + for (int line = 0; line < maxLines; line++) { + for (int column = 0; column < content.size(); column++) { + String[] lines = content.get(column); + String currentLine = line < lines.length ? lines[line] : ""; + result.append("| "); + boolean header = headerFlags.get(column); + if (header) { + result.append(escape(CODE_HIGHLIGHT)); + } + result.append(currentLine); + if (header) { + result.append(escape(CODE_RESET)); + } + int padding = limit - currentLine.length(); + if (padding > 0) + result.append(indentString(padding)); + result.append(" "); + } + result.append("|\n"); + } + + for (int sep = 0; sep < (limit + 3) * content.size() + 1; sep++) { + result.append("-"); + } + + result.append("\n"); + + reflownTo = result.length(); + break; + case TD: + case TH: + break; + default: + addSpaceIfNeeded(result); + break; + } + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Object visitEntity(EntityTree node, Object p) { + String name = node.getName().toString(); + int code = -1; + if (name.startsWith("#")) { + try { + int v = StringUtils.toLowerCase(name).startsWith("#x") + ? Integer.parseInt(name.substring(2), 16) + : Integer.parseInt(name.substring(1), 10); + if (Entity.isValid(v)) { + code = v; + } + } catch (NumberFormatException ex) { + //ignore + } + } else { + Entity entity = Entity.get(name); + if (entity != null) { + code = entity.code; + } + } + if (code != (-1)) { + result.appendCodePoint(code); + } else { + result.append(node.toString()); + } + return super.visitEntity(node, p); + } + + private DocTree lastNode; + + @Override @DefinedBy(Api.COMPILER_TREE) + public Object scan(DocTree node, Object p) { + if (node instanceof InlineTagTree) { + addSpaceIfNeeded(result); + } + try { + return super.scan(node, p); + } finally { + if (node instanceof InlineTagTree) { + addSpaceIfNeeded(result); + } + lastNode = node; + } + } + + private void reflowTillNow() { + while (result.length() > 0 && result.charAt(result.length() - 1) == ' ') + result.delete(result.length() - 1, result.length()); + reflow(result, reflownTo, indent, limit); + reflownTo = result.length(); + } + }; + + private String escape(String sequence) { + return this.escapeSequencesSupported ? sequence : ""; + } + + private static final Map docSections = new LinkedHashMap<>(); + + static { + ResourceBundle bundle = + ResourceBundle.getBundle("jdk.internal.shellsupport.doc.resources.javadocformatter"); + docSections.put(Sections.TYPE_PARAMS, bundle.getString("CAP_TypeParameters")); + docSections.put(Sections.PARAMS, bundle.getString("CAP_Parameters")); + docSections.put(Sections.RETURNS, bundle.getString("CAP_Returns")); + docSections.put(Sections.THROWS, bundle.getString("CAP_Thrown_Exceptions")); + } + + private static String indentString(int indent) { + char[] content = new char[indent]; + Arrays.fill(content, ' '); + return new String(content); + } + + private static void reflow(StringBuilder text, int from, int indent, int limit) { + int lineStart = from; + + while (lineStart > 0 && text.charAt(lineStart - 1) != '\n') { + lineStart--; + } + + int lineChars = from - lineStart; + int pointer = from; + int lastSpace = -1; + + while (pointer < text.length()) { + if (text.charAt(pointer) == ' ') + lastSpace = pointer; + if (lineChars >= limit) { + if (lastSpace != (-1)) { + text.setCharAt(lastSpace, '\n'); + text.insert(lastSpace + 1, indentString(indent)); + lineChars = indent + pointer - lastSpace - 1; + pointer += indent; + lastSpace = -1; + } + } + lineChars++; + pointer++; + } + } + + private static void addNewLineIfNeeded(StringBuilder text) { + if (text.length() > 0 && text.charAt(text.length() - 1) != '\n') { + text.append("\n"); + } + } + + private static void addSpaceIfNeeded(StringBuilder text) { + if (text.length() == 0) + return ; + + char last = text.charAt(text.length() - 1); + + if (last != ' ' && last != '\n') { + text.append(" "); + } + } + + private static Map countTableColumns(DocCommentTree dct) { + Map result = new IdentityHashMap<>(); + + new DocTreeScanner() { + private StartElementTree currentTable; + private int currentMaxColumns; + private int currentRowColumns; + + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitStartElement(StartElementTree node, Void p) { + switch (HtmlTag.get(node.getName())) { + case TABLE: currentTable = node; break; + case TR: + currentMaxColumns = Math.max(currentMaxColumns, currentRowColumns); + currentRowColumns = 0; + break; + case TD: + case TH: currentRowColumns++; break; + } + return super.visitStartElement(node, p); + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitEndElement(EndElementTree node, Void p) { + if (HtmlTag.get(node.getName()) == HtmlTag.TABLE) { + closeTable(); + } + return super.visitEndElement(node, p); + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitDocComment(DocCommentTree node, Void p) { + try { + return super.visitDocComment(node, p); + } finally { + closeTable(); + } + } + + private void closeTable() { + if (currentTable != null) { + result.put(currentTable, Math.max(currentMaxColumns, currentRowColumns)); + currentTable = null; + } + } + }.scan(dct, null); + + return result; + } + + private enum Sections { + TYPE_PARAMS { + @Override public boolean matches(DocTree t) { + return t.getKind() == DocTree.Kind.PARAM && ((ParamTree) t).isTypeParameter(); + } + }, + PARAMS { + @Override public boolean matches(DocTree t) { + return t.getKind() == DocTree.Kind.PARAM && !((ParamTree) t).isTypeParameter(); + } + }, + RETURNS { + @Override public boolean matches(DocTree t) { + return t.getKind() == DocTree.Kind.RETURN; + } + }, + THROWS { + @Override public boolean matches(DocTree t) { + return t.getKind() == DocTree.Kind.THROWS; + } + }; + + public abstract boolean matches(DocTree t); + } +} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocHelper.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,661 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.shellsupport.doc; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.Stack; +import java.util.TreeMap; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.util.ElementFilter; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; + +import com.sun.source.doctree.DocCommentTree; +import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.InheritDocTree; +import com.sun.source.doctree.ParamTree; +import com.sun.source.doctree.ReturnTree; +import com.sun.source.doctree.ThrowsTree; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.MethodTree; +import com.sun.source.tree.VariableTree; +import com.sun.source.util.DocTreePath; +import com.sun.source.util.DocTreeScanner; +import com.sun.source.util.DocTrees; +import com.sun.source.util.JavacTask; +import com.sun.source.util.TreePath; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; +import com.sun.tools.javac.api.JavacTaskImpl; +import com.sun.tools.javac.util.DefinedBy; +import com.sun.tools.javac.util.DefinedBy.Api; +import com.sun.tools.javac.util.Pair; + +/**Helper to find javadoc and resolve @inheritDoc. + */ +public abstract class JavadocHelper implements AutoCloseable { + private static final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + + /**Create the helper. + * + * @param mainTask JavacTask from which the further Elements originate + * @param sourceLocations paths where source files should be searched + * @return a JavadocHelper + */ + public static JavadocHelper create(JavacTask mainTask, Collection sourceLocations) { + StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null); + try { + fm.setLocationFromPaths(StandardLocation.SOURCE_PATH, sourceLocations); + return new OnDemandJavadocHelper(mainTask, fm); + } catch (IOException ex) { + try { + fm.close(); + } catch (IOException closeEx) { + } + return new JavadocHelper() { + @Override + public String getResolvedDocComment(Element forElement) throws IOException { + return null; + } + @Override + public Element getSourceElement(Element forElement) throws IOException { + return forElement; + } + @Override + public void close() throws IOException {} + }; + } + } + + /**Returns javadoc for the given element, if it can be found, or null otherwise. The javadoc + * will have @inheritDoc resolved. + * + * @param forElement element for which the javadoc should be searched + * @return javadoc if found, null otherwise + * @throws IOException if something goes wrong in the search + */ + public abstract String getResolvedDocComment(Element forElement) throws IOException; + + /**Returns an element representing the same given program element, but the returned element will + * be resolved from source, if it can be found. Returns the original element if the source for + * the given element cannot be found. + * + * @param forElement element for which the source element should be searched + * @return source element if found, the original element otherwise + * @throws IOException if something goes wrong in the search + */ + public abstract Element getSourceElement(Element forElement) throws IOException; + + /**Closes the helper. + * + * @throws IOException if something foes wrong during the close + */ + @Override + public abstract void close() throws IOException; + + private static final class OnDemandJavadocHelper extends JavadocHelper { + private final JavacTask mainTask; + private final JavaFileManager baseFileManager; + private final StandardJavaFileManager fm; + private final Map> signature2Source = new HashMap<>(); + + private OnDemandJavadocHelper(JavacTask mainTask, StandardJavaFileManager fm) { + this.mainTask = mainTask; + this.baseFileManager = ((JavacTaskImpl) mainTask).getContext().get(JavaFileManager.class); + this.fm = fm; + } + + @Override + public String getResolvedDocComment(Element forElement) throws IOException { + Pair sourceElement = getSourceElement(mainTask, forElement); + + if (sourceElement == null) + return null; + + return getResolvedDocComment(sourceElement.fst, sourceElement.snd); + } + + @Override + public Element getSourceElement(Element forElement) throws IOException { + Pair sourceElement = getSourceElement(mainTask, forElement); + + if (sourceElement == null) + return forElement; + + Element result = Trees.instance(sourceElement.fst).getElement(sourceElement.snd); + + if (result == null) + return forElement; + + return result; + } + + private String getResolvedDocComment(JavacTask task, TreePath el) throws IOException { + DocTrees trees = DocTrees.instance(task); + Element element = trees.getElement(el); + String docComment = trees.getDocComment(el); + + if (docComment == null && element.getKind() == ElementKind.METHOD) { + ExecutableElement executableElement = (ExecutableElement) element; + Iterable superTypes = + () -> superTypeForInheritDoc(task, element.getEnclosingElement()).iterator(); + for (Element sup : superTypes) { + for (ExecutableElement supMethod : ElementFilter.methodsIn(sup.getEnclosedElements())) { + TypeElement clazz = (TypeElement) executableElement.getEnclosingElement(); + if (task.getElements().overrides(executableElement, supMethod, clazz)) { + Pair source = getSourceElement(task, supMethod); + + if (source != null) { + String overriddenComment = getResolvedDocComment(source.fst, source.snd); + + if (overriddenComment != null) { + return overriddenComment; + } + } + } + } + } + } + + DocCommentTree docCommentTree = parseDocComment(task, docComment); + IOException[] exception = new IOException[1]; + Map replace = new TreeMap<>((span1, span2) -> span2[0] - span1[0]); + + new DocTreeScanner() { + private Stack interestingParent = new Stack<>(); + private DocCommentTree dcTree; + private JavacTask inheritedJavacTask; + private TreePath inheritedTreePath; + private String inherited; + private Map syntheticTrees = new IdentityHashMap<>(); + private long lastPos = 0; + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitDocComment(DocCommentTree node, Void p) { + dcTree = node; + interestingParent.push(node); + try { + scan(node.getFirstSentence(), p); + scan(node.getBody(), p); + List augmentedBlockTags = new ArrayList<>(node.getBlockTags()); + if (element.getKind() == ElementKind.METHOD) { + ExecutableElement executableElement = (ExecutableElement) element; + List parameters = + executableElement.getParameters() + .stream() + .map(param -> param.getSimpleName().toString()) + .collect(Collectors.toList()); + List throwsList = + executableElement.getThrownTypes() + .stream() + .map(exc -> exc.toString()) + .collect(Collectors.toList()); + Set missingParams = new HashSet<>(parameters); + Set missingThrows = new HashSet<>(throwsList); + boolean hasReturn = false; + + for (DocTree dt : augmentedBlockTags) { + switch (dt.getKind()) { + case PARAM: + missingParams.remove(((ParamTree) dt).getName().getName().toString()); + break; + case THROWS: + missingThrows.remove(getThrownException(task, el, docCommentTree, (ThrowsTree) dt)); + break; + case RETURN: + hasReturn = true; + break; + } + } + + for (String missingParam : missingParams) { + DocTree syntheticTag = parseBlockTag(task, "@param " + missingParam + " {@inheritDoc}"); + syntheticTrees.put(syntheticTag, "@param " + missingParam + " "); + insertTag(augmentedBlockTags, syntheticTag, parameters, throwsList); + } + + for (String missingThrow : missingThrows) { + DocTree syntheticTag = parseBlockTag(task, "@throws " + missingThrow + " {@inheritDoc}"); + syntheticTrees.put(syntheticTag, "@throws " + missingThrow + " "); + insertTag(augmentedBlockTags, syntheticTag, parameters, throwsList); + } + + if (!hasReturn) { + DocTree syntheticTag = parseBlockTag(task, "@return {@inheritDoc}"); + syntheticTrees.put(syntheticTag, "@return "); + insertTag(augmentedBlockTags, syntheticTag, parameters, throwsList); + } + } + scan(augmentedBlockTags, p); + return null; + } finally { + interestingParent.pop(); + } + } + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitParam(ParamTree node, Void p) { + interestingParent.push(node); + try { + return super.visitParam(node, p); + } finally { + interestingParent.pop(); + } + } + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitThrows(ThrowsTree node, Void p) { + interestingParent.push(node); + try { + return super.visitThrows(node, p); + } finally { + interestingParent.pop(); + } + } + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitReturn(ReturnTree node, Void p) { + interestingParent.push(node); + try { + return super.visitReturn(node, p); + } finally { + interestingParent.pop(); + } + } + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitInheritDoc(InheritDocTree node, Void p) { + if (inherited == null) { + try { + if (element.getKind() == ElementKind.METHOD) { + ExecutableElement executableElement = (ExecutableElement) element; + Iterable superTypes = () -> superTypeForInheritDoc(task, element.getEnclosingElement()).iterator(); + OUTER: for (Element sup : superTypes) { + for (ExecutableElement supMethod : ElementFilter.methodsIn(sup.getEnclosedElements())) { + if (task.getElements().overrides(executableElement, supMethod, (TypeElement) executableElement.getEnclosingElement())) { + Pair source = getSourceElement(task, supMethod); + + if (source != null) { + String overriddenComment = getResolvedDocComment(source.fst, source.snd); + + if (overriddenComment != null) { + inheritedJavacTask = source.fst; + inheritedTreePath = source.snd; + inherited = overriddenComment; + break OUTER; + } + } + } + } + } + } + } catch (IOException ex) { + exception[0] = ex; + return null; + } + } + if (inherited == null) { + return null; + } + DocCommentTree inheritedDocTree = parseDocComment(inheritedJavacTask, inherited); + List> inheritedText = new ArrayList<>(); + DocTree parent = interestingParent.peek(); + switch (parent.getKind()) { + case DOC_COMMENT: + inheritedText.add(inheritedDocTree.getFullBody()); + break; + case PARAM: + String paramName = ((ParamTree) parent).getName().getName().toString(); + new DocTreeScanner() { + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitParam(ParamTree node, Void p) { + if (node.getName().getName().contentEquals(paramName)) { + inheritedText.add(node.getDescription()); + } + return super.visitParam(node, p); + } + }.scan(inheritedDocTree, null); + break; + case THROWS: + String thrownName = getThrownException(task, el, docCommentTree, (ThrowsTree) parent); + new DocTreeScanner() { + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitThrows(ThrowsTree node, Void p) { + if (Objects.equals(getThrownException(inheritedJavacTask, inheritedTreePath, inheritedDocTree, node), thrownName)) { + inheritedText.add(node.getDescription()); + } + return super.visitThrows(node, p); + } + }.scan(inheritedDocTree, null); + break; + case RETURN: + new DocTreeScanner() { + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitReturn(ReturnTree node, Void p) { + inheritedText.add(node.getDescription()); + return super.visitReturn(node, p); + } + }.scan(inheritedDocTree, null); + break; + } + if (!inheritedText.isEmpty()) { + long offset = trees.getSourcePositions().getStartPosition(null, inheritedDocTree, inheritedDocTree); + long start = Long.MAX_VALUE; + long end = Long.MIN_VALUE; + + for (DocTree t : inheritedText.get(0)) { + start = Math.min(start, trees.getSourcePositions().getStartPosition(null, inheritedDocTree, t) - offset); + end = Math.max(end, trees.getSourcePositions().getEndPosition(null, inheritedDocTree, t) - offset); + } + String text = inherited.substring((int) start, (int) end); + + if (syntheticTrees.containsKey(parent)) { + replace.put(new int[] {(int) lastPos + 1, (int) lastPos}, "\n" + syntheticTrees.get(parent) + text); + } else { + long inheritedStart = trees.getSourcePositions().getStartPosition(null, dcTree, node); + long inheritedEnd = trees.getSourcePositions().getEndPosition(null, dcTree, node); + + replace.put(new int[] {(int) inheritedStart, (int) inheritedEnd}, text); + } + } + return super.visitInheritDoc(node, p); + } + private boolean inSynthetic; + @Override @DefinedBy(Api.COMPILER_TREE) + public Void scan(DocTree tree, Void p) { + if (exception[0] != null) { + return null; + } + boolean prevInSynthetic = inSynthetic; + try { + inSynthetic |= syntheticTrees.containsKey(tree); + return super.scan(tree, p); + } finally { + if (!inSynthetic) { + lastPos = trees.getSourcePositions().getEndPosition(null, dcTree, tree); + } + inSynthetic = prevInSynthetic; + } + } + + private void insertTag(List tags, DocTree toInsert, List parameters, List throwsTypes) { + Comparator comp = (tag1, tag2) -> { + if (tag1.getKind() == tag2.getKind()) { + switch (toInsert.getKind()) { + case PARAM: { + ParamTree p1 = (ParamTree) tag1; + ParamTree p2 = (ParamTree) tag2; + int i1 = parameters.indexOf(p1.getName().getName().toString()); + int i2 = parameters.indexOf(p2.getName().getName().toString()); + + return i1 - i2; + } + case THROWS: { + ThrowsTree t1 = (ThrowsTree) tag1; + ThrowsTree t2 = (ThrowsTree) tag2; + int i1 = throwsTypes.indexOf(getThrownException(task, el, docCommentTree, t1)); + int i2 = throwsTypes.indexOf(getThrownException(task, el, docCommentTree, t2)); + + return i1 - i2; + } + } + } + + int i1 = tagOrder.indexOf(tag1.getKind()); + int i2 = tagOrder.indexOf(tag2.getKind()); + + return i1 - i2; + }; + + for (int i = 0; i < tags.size(); i++) { + if (comp.compare(tags.get(i), toInsert) >= 0) { + tags.add(i, toInsert); + return ; + } + } + tags.add(toInsert); + } + + private final List tagOrder = Arrays.asList(DocTree.Kind.PARAM, DocTree.Kind.THROWS, DocTree.Kind.RETURN); + }.scan(docCommentTree, null); + + if (replace.isEmpty()) + return docComment; + + StringBuilder replacedInheritDoc = new StringBuilder(docComment); + int offset = (int) trees.getSourcePositions().getStartPosition(null, docCommentTree, docCommentTree); + + for (Entry e : replace.entrySet()) { + replacedInheritDoc.delete(e.getKey()[0] - offset, e.getKey()[1] - offset + 1); + replacedInheritDoc.insert(e.getKey()[0] - offset, e.getValue()); + } + + return replacedInheritDoc.toString(); + } + + private Stream superTypeForInheritDoc(JavacTask task, Element type) { + TypeElement clazz = (TypeElement) type; + Stream result = interfaces(clazz); + result = Stream.concat(result, interfaces(clazz).flatMap(el -> superTypeForInheritDoc(task, el))); + + if (clazz.getSuperclass().getKind() == TypeKind.DECLARED) { + Element superClass = ((DeclaredType) clazz.getSuperclass()).asElement(); + result = Stream.concat(result, Stream.of(superClass)); + result = Stream.concat(result, superTypeForInheritDoc(task, superClass)); + } + + return result; + } + //where: + private Stream interfaces(TypeElement clazz) { + return clazz.getInterfaces() + .stream() + .filter(tm -> tm.getKind() == TypeKind.DECLARED) + .map(tm -> ((DeclaredType) tm).asElement()); + } + + private DocTree parseBlockTag(JavacTask task, String blockTag) { + DocCommentTree dc = parseDocComment(task, blockTag); + + return dc.getBlockTags().get(0); + } + + private DocCommentTree parseDocComment(JavacTask task, String javadoc) { + DocTrees trees = DocTrees.instance(task); + try { + return trees.getDocCommentTree(new SimpleJavaFileObject(new URI("mem://doc.html"), javax.tools.JavaFileObject.Kind.HTML) { + @Override @DefinedBy(Api.COMPILER) + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return "" + javadoc + ""; + } + }); + } catch (URISyntaxException ex) { + return null; + } + } + + private String getThrownException(JavacTask task, TreePath rootOn, DocCommentTree comment, ThrowsTree tt) { + DocTrees trees = DocTrees.instance(task); + Element exc = trees.getElement(new DocTreePath(new DocTreePath(rootOn, comment), tt.getExceptionName())); + return exc != null ? exc.toString() : null; + } + + private Pair getSourceElement(JavacTask origin, Element el) throws IOException { + String handle = elementSignature(el); + Pair cached = signature2Source.get(handle); + + if (cached != null) { + return cached.fst != null ? cached : null; + } + + TypeElement type = topLevelType(el); + + if (type == null) + return null; + + String binaryName = origin.getElements().getBinaryName(type).toString(); + Pair source = findSource(binaryName); + + if (source == null) + return null; + + fillElementCache(source.fst, source.snd); + + cached = signature2Source.get(handle); + + if (cached != null) { + return cached; + } else { + signature2Source.put(handle, Pair.of(null, null)); + return null; + } + } + //where: + private String elementSignature(Element el) { + switch (el.getKind()) { + case ANNOTATION_TYPE: case CLASS: case ENUM: case INTERFACE: + return ((TypeElement) el).getQualifiedName().toString(); + case FIELD: + return elementSignature(el.getEnclosingElement()) + "." + el.getSimpleName() + ":" + el.asType(); + case ENUM_CONSTANT: + return elementSignature(el.getEnclosingElement()) + "." + el.getSimpleName(); + case EXCEPTION_PARAMETER: case LOCAL_VARIABLE: case PARAMETER: case RESOURCE_VARIABLE: + return el.getSimpleName() + ":" + el.asType(); + case CONSTRUCTOR: case METHOD: + StringBuilder header = new StringBuilder(); + header.append(elementSignature(el.getEnclosingElement())); + if (el.getKind() == ElementKind.METHOD) { + header.append("."); + header.append(el.getSimpleName()); + } + header.append("("); + String sep = ""; + ExecutableElement method = (ExecutableElement) el; + for (Iterator i = method.getParameters().iterator(); i.hasNext();) { + VariableElement p = i.next(); + header.append(sep); + header.append(p.asType()); + sep = ", "; + } + header.append(")"); + return header.toString(); + default: + return el.toString(); + } + } + + private TypeElement topLevelType(Element el) { + if (el.getKind() == ElementKind.PACKAGE) + return null; + + while (el != null && el.getEnclosingElement().getKind() != ElementKind.PACKAGE) { + el = el.getEnclosingElement(); + } + + return el != null && (el.getKind().isClass() || el.getKind().isInterface()) ? (TypeElement) el : null; + } + + private void fillElementCache(JavacTask task, CompilationUnitTree cut) throws IOException { + Trees trees = Trees.instance(task); + + new TreePathScanner() { + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitMethod(MethodTree node, Void p) { + handleDeclaration(); + return null; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitClass(ClassTree node, Void p) { + handleDeclaration(); + return super.visitClass(node, p); + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitVariable(VariableTree node, Void p) { + handleDeclaration(); + return super.visitVariable(node, p); + } + + private void handleDeclaration() { + Element currentElement = trees.getElement(getCurrentPath()); + + if (currentElement != null) { + signature2Source.put(elementSignature(currentElement), Pair.of(task, getCurrentPath())); + } + } + }.scan(cut, null); + } + + private Pair findSource(String binaryName) throws IOException { + JavaFileObject jfo = fm.getJavaFileForInput(StandardLocation.SOURCE_PATH, + binaryName, + JavaFileObject.Kind.SOURCE); + + if (jfo == null) + return null; + + List jfos = Arrays.asList(jfo); + JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, baseFileManager, d -> {}, null, null, jfos); + Iterable cuts = task.parse(); + + task.enter(); + + return Pair.of(task, cuts.iterator().next()); + } + + @Override + public void close() throws IOException { + fm.close(); + } + } + +} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/resources/javadocformatter.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/resources/javadocformatter.properties Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,29 @@ +# +# Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +CAP_TypeParameters=Type Parameters: +CAP_Parameters=Parameters: +CAP_Returns=Returns: +CAP_Thrown_Exceptions=Thrown Exceptions: diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.compiler/share/classes/module-info.java --- a/langtools/src/jdk.compiler/share/classes/module-info.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.compiler/share/classes/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -65,6 +65,9 @@ jdk.jdeps, jdk.javadoc, jdk.jshell; + exports jdk.internal.shellsupport.doc to + jdk.jshell, + jdk.scripting.nashorn.shell; uses javax.annotation.processing.Processor; uses com.sun.source.util.Plugin; diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java Fri Nov 11 16:44:36 2016 +0100 @@ -638,6 +638,8 @@ // now the scanning phase + boolean scanStatus = true; + switch (scanMode) { case LIST: for (DeprData dd : deprList) { @@ -661,24 +663,22 @@ Scan scan = new Scan(out, err, cp, db, verbose); for (String a : args) { - boolean success; - + boolean s; if (a.endsWith(".jar")) { - success = scan.scanJar(a); + s = scan.scanJar(a); + } else if (a.endsWith(".class")) { + s = scan.processClassFile(a); } else if (Files.isDirectory(Paths.get(a))) { - success = scan.scanDir(a); + s = scan.scanDir(a); } else { - success = scan.processClassName(a.replace('.', '/')); + s = scan.processClassName(a.replace('.', '/')); } - - if (!success) { - return false; - } + scanStatus = scanStatus && s; } break; } - return true; + return scanStatus; } /** diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Messages.java --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Messages.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Messages.java Fri Nov 11 16:44:36 2016 +0100 @@ -34,6 +34,10 @@ * Message handling class for localization. */ public class Messages { + /** Indicates whether line separators in messages need replacement. */ + static final boolean REPLACE_LINESEP = ! System.lineSeparator().equals("\n"); + + /** The resource bundle, must be non-null. */ static final ResourceBundle bundle; static { @@ -41,13 +45,25 @@ try { bundle = ResourceBundle.getBundle("com.sun.tools.jdeprscan.resources.jdeprscan", locale); } catch (MissingResourceException e) { - throw new InternalError("Cannot find jdeps resource bundle for locale " + locale, e); + throw new InternalError("Cannot find jdeprscan resource bundle for locale " + locale, e); } } + /** + * Gets a message from the resource bundle. If necessary, translates "\n", + * the line break string used in the message file, to the system-specific + * line break string. + * + * @param key the message key + * @param args the message arguments + */ public static String get(String key, Object... args) { try { - return MessageFormat.format(bundle.getString(key), args); + String msg = MessageFormat.format(bundle.getString(key), args); + if (REPLACE_LINESEP) { + msg = msg.replace("\n", System.lineSeparator()); + } + return msg; } catch (MissingResourceException e) { throw new InternalError("Missing message: " + key, e); } diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md Fri Nov 11 16:44:36 2016 +0100 @@ -92,6 +92,9 @@ that jar file and report information about how those classes use deprecated APIs. +Given a class file, **jdeprscan** will scan that class and report +its use of deprecated APIs. + Given a class name, **jdeprscan** will search for that class on the classpath, scan that class, and report information about how that class uses deprecated APIs. The class name must use the fully diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties Fri Nov 11 16:44:36 2016 +0100 @@ -14,9 +14,9 @@ main.help=\ Scans each argument for usages of deprecated APIs. An argument\n\ may be a directory specifying the root of a package hierarchy,\n\ -a JAR file, or a class name. The class name must be specified\n\ -using a fully qualified class name using the $ separator character\n\ -for nested classes, for example,\n\ +a JAR file, a class file, or a class name. The class name must be\n\ +specified using a fully qualified class name using the $ separator\n\ +character for nested classes, for example,\n\ \n\ \ java.lang.Thread$State\n\ \n\ @@ -73,24 +73,26 @@ \ Prints a CSV file containing the loaded deprecation information\n\ \ instead of scanning any classes or JAR files. -error.prefix=Error: - scan.process.class=Processing class {0}... -scan.dep.normal=deprecated -scan.dep.removal=deprecated FOR REMOVAL +scan.dep.normal= +scan.dep.removal=(forRemoval=true) + +scan.err.exception=error: unexpected exception {0} +scan.err.noclass=error: cannot find class {0} +scan.err.nofile=error: cannot find file {0} +scan.err.nomethod=error: cannot resolve Methodref {0}.{1}:{2} + +scan.head.jar=Jar file {0}: +scan.head.dir=Directory {0}: -scan.out.extends={0} {1} extends class {2} {3} -scan.out.implements={0} {1} implements interface {2} {3} -scan.out.usestype={0} {1} uses type {2} {3} -scan.out.usesmethodintype={0} {1} uses method in type {2} {3} -scan.out.usesmethod={0} {1} uses method {2} {3} {4} {5} -scan.out.usesintfmethodintype={0} {1} uses interface method in type {2} {3} -scan.out.usesintfmethod={0} {1} uses interface method {2} {3} {4} {5} -scan.out.usesfieldintype={0} {1} uses field in type {2} {3} -scan.out.usesfield={0} {1} uses field {2} {3} {4} -scan.out.usesfieldoftype={0} {1} uses field of type {2} {3} {4} {5} -scan.out.hasfield={0} {1} has field {2} of type {3} {4} -scan.out.methodparmtype={0} {1} method {2} has parameter type {3} {4} -scan.out.methodrettype={0} {1} method {2} has return type {3} {4} -scan.out.methodoverride={0} {1} overrides method {2} {3} {4} {5} +scan.out.extends={0} {1} extends deprecated class {2} {3} +scan.out.implements={0} {1} implements deprecated interface {2} {3} +scan.out.usesclass={0} {1} uses deprecated class {2} {3} +scan.out.usesmethod={0} {1} uses deprecated method {2}::{3}{4} {5} +scan.out.usesintfmethod={0} {1} uses deprecated method {2}::{3}{4} {5} +scan.out.usesfield={0} {1} uses deprecated field {2}::{3} {4} +scan.out.hasfield={0} {1} has field named {2} of deprecated type {3} {4} +scan.out.methodparmtype={0} {1} has method named {2} having deprecated parameter type {3} {4} +scan.out.methodrettype={0} {1} has method named {2} having deprecated return type {3} {4} +scan.out.methodoverride={0} {1} overrides deprecated method {2}::{3}{4} {5} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/Scan.java --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/Scan.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/Scan.java Fri Nov 11 16:44:36 2016 +0100 @@ -28,6 +28,7 @@ import java.io.IOException; import java.io.PrintStream; import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayDeque; @@ -62,7 +63,7 @@ final boolean verbose; final ClassFinder finder; - boolean error = false; + boolean errorOccurred = false; public Scan(PrintStream out, PrintStream err, @@ -124,71 +125,72 @@ } } - void printType(String key, ClassFile cf, String cname, boolean forRemoval) + String dep(boolean forRemoval) { + return Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal"); + } + + void printType(String key, ClassFile cf, String cname, boolean r) throws ConstantPoolException { - String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal"); - out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, dep)); + out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, dep(r))); } void printMethod(String key, ClassFile cf, String cname, String mname, String rtype, - boolean forRemoval) throws ConstantPoolException { - String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal"); - out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, mname, rtype, dep)); + boolean r) throws ConstantPoolException { + out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, mname, rtype, dep(r))); } void printField(String key, ClassFile cf, String cname, String fname, - boolean forRemoval) throws ConstantPoolException { - String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal"); - out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, fname, dep)); + boolean r) throws ConstantPoolException { + out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, fname, dep(r))); } void printFieldType(String key, ClassFile cf, String cname, String fname, String type, - boolean forRemoval) throws ConstantPoolException { - String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal"); - out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, fname, type, dep)); + boolean r) throws ConstantPoolException { + out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, fname, type, dep(r))); } - void printHasField(ClassFile cf, String fname, String type, boolean forRemoval) + void printHasField(ClassFile cf, String fname, String type, boolean r) throws ConstantPoolException { - String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal"); - out.println(Messages.get("scan.out.hasfield", typeKind(cf), cf.getName(), fname, type, dep)); + out.println(Messages.get("scan.out.hasfield", typeKind(cf), cf.getName(), fname, type, dep(r))); } - void printHasMethodParmType(ClassFile cf, String mname, String parmType, boolean forRemoval) + void printHasMethodParmType(ClassFile cf, String mname, String parmType, boolean r) throws ConstantPoolException { - String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal"); - out.println(Messages.get("scan.out.methodparmtype", typeKind(cf), cf.getName(), mname, parmType, dep)); + out.println(Messages.get("scan.out.methodparmtype", typeKind(cf), cf.getName(), mname, parmType, dep(r))); } - void printHasMethodRetType(ClassFile cf, String mname, String retType, boolean forRemoval) + void printHasMethodRetType(ClassFile cf, String mname, String retType, boolean r) throws ConstantPoolException { - String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal"); - out.println(Messages.get("scan.out.methodrettype", typeKind(cf), cf.getName(), mname, retType, dep)); + out.println(Messages.get("scan.out.methodrettype", typeKind(cf), cf.getName(), mname, retType, dep(r))); } - void printHasOverriddenMethod(ClassFile cf, String overridden, String mname, String desc, boolean forRemoval) + void printHasOverriddenMethod(ClassFile cf, String overridden, String mname, String desc, boolean r) throws ConstantPoolException { - String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal"); out.println(Messages.get("scan.out.methodoverride", typeKind(cf), cf.getName(), overridden, - mname, desc, dep)); + mname, desc, dep(r))); + } + + void errorException(Exception ex) { + errorOccurred = true; + err.println(Messages.get("scan.err.exception", ex.toString())); + if (verbose) { + ex.printStackTrace(err); + } } - // format should not have a newline - void err(String format, Object... args) { - error = true; - err.print("error: "); - err.printf(format, args); - err.println(); + void errorNoClass(String className) { + errorOccurred = true; + err.println(Messages.get("scan.err.noclass", className)); } - void printException(Exception ex) { - err.print(Messages.get("error.prefix")); - err.print(" "); - if (verbose) { - ex.printStackTrace(err); - } else { - err.print(ex); - } + void errorNoFile(String fileName) { + errorOccurred = true; + err.println(Messages.get("scan.err.nofile", fileName)); + } + + void errorNoMethod(String className, String methodName, String desc) { + errorOccurred = true; + err.println(Messages.get("scan.err.nomethod", className, methodName, desc)); } /** @@ -271,7 +273,7 @@ } else { startClass = finder.find(startClassName); if (startClass == null) { - err("can't find class %s", startClassName); + errorNoClass(startClassName); return startClassName; } } @@ -295,7 +297,7 @@ String superName = curClass.getSuperclassName(); curClass = finder.find(superName); if (curClass == null) { - err("can't find class %s", superName); + errorNoClass(superName); break; } addInterfaces(intfs, curClass); @@ -310,7 +312,7 @@ String intf = intfs.removeFirst(); curClass = finder.find(intf); if (curClass == null) { - err("can't find interface %s", intf); + errorNoClass(intf); break; } @@ -324,8 +326,7 @@ if (curClass == null) { if (checkStartClass) { - err("can't resolve methodref %s %s %s", - startClassName, findName, findDesc); + errorNoMethod(startClassName, findName, findDesc); return startClassName; } else { // TODO: refactor this @@ -372,18 +373,18 @@ } /** - * Checks types referred to from the constant pool. + * Checks Class_info entries in the constant pool. * * @param cf the ClassFile of this class * @param entries constant pool entries collected from this class * @throws ConstantPoolException if a constant pool entry cannot be found */ - void checkTypes(ClassFile cf, CPEntries entries) throws ConstantPoolException { + void checkClasses(ClassFile cf, CPEntries entries) throws ConstantPoolException { for (ConstantPool.CONSTANT_Class_info ci : entries.classes) { - String typeName = ci.getName(); - DeprData dd = db.getTypeDeprecated(flatten(typeName)); + String className = ci.getName(); + DeprData dd = db.getTypeDeprecated(flatten(className)); if (dd != null) { - printType("scan.out.usestype", cf, typeName, dd.isForRemoval()); + printType("scan.out.usesclass", cf, className, dd.isForRemoval()); } } } @@ -394,26 +395,19 @@ * @param cf the ClassFile of this class * @param nti the NameAndType_info from a MethodRef or InterfaceMethodRef entry * @param clname the class name - * @param typeKey key for the type message - * @param methKey key for the method message + * @param msgKey message key for localization * @throws ConstantPoolException if a constant pool entry cannot be found */ void checkMethodRef(ClassFile cf, + String clname, CONSTANT_NameAndType_info nti, - String clname, - String typeKey, - String methKey) throws ConstantPoolException { - DeprData dd = db.getTypeDeprecated(flatten(clname)); - if (dd != null) { - printType(typeKey, cf, clname, dd.isForRemoval()); - } - + String msgKey) throws ConstantPoolException { String name = nti.getName(); String type = nti.getType(); clname = resolveMember(cf, flatten(clname), name, type, true, true); - dd = db.getMethodDeprecated(clname, name, type); + DeprData dd = db.getMethodDeprecated(clname, name, type); if (dd != null) { - printMethod(methKey, cf, clname, name, type, dd.isForRemoval()); + printMethod(msgKey, cf, clname, name, type, dd.isForRemoval()); } } @@ -425,26 +419,16 @@ */ void checkFieldRef(ClassFile cf, ConstantPool.CONSTANT_Fieldref_info fri) throws ConstantPoolException { + String clname = fri.getClassName(); CONSTANT_NameAndType_info nti = fri.getNameAndTypeInfo(); - String clname = fri.getClassName(); String name = nti.getName(); String type = nti.getType(); - DeprData dd = db.getTypeDeprecated(clname); - - if (dd != null) { - printType("scan.out.usesfieldintype", cf, clname, dd.isForRemoval()); - } clname = resolveMember(cf, flatten(clname), name, type, false, true); - dd = db.getFieldDeprecated(clname, name); + DeprData dd = db.getFieldDeprecated(clname, name); if (dd != null) { printField("scan.out.usesfield", cf, clname, name, dd.isForRemoval()); } - - dd = db.getTypeDeprecated(flatten(type)); - if (dd != null) { - printFieldType("scan.out.usesfieldoftype", cf, clname, name, type, dd.isForRemoval()); - } } /** @@ -515,18 +499,18 @@ checkSuper(cf); checkInterfaces(cf); - checkTypes(cf, entries); + checkClasses(cf, entries); for (ConstantPool.CONSTANT_Methodref_info mri : entries.methodRefs) { + String clname = mri.getClassName(); CONSTANT_NameAndType_info nti = mri.getNameAndTypeInfo(); - String clname = mri.getClassName(); - checkMethodRef(cf, nti, clname, "scan.out.usesmethodintype", "scan.out.usesmethod"); + checkMethodRef(cf, clname, nti, "scan.out.usesmethod"); } for (ConstantPool.CONSTANT_InterfaceMethodref_info imri : entries.intfMethodRefs) { + String clname = imri.getClassName(); CONSTANT_NameAndType_info nti = imri.getNameAndTypeInfo(); - String clname = imri.getClassName(); - checkMethodRef(cf, nti, clname, "scan.out.usesintfmethodintype", "scan.out.usesintfmethod"); + checkMethodRef(cf, clname, nti, "scan.out.usesintfmethod"); } for (ConstantPool.CONSTANT_Fieldref_info fri : entries.fieldRefs) { @@ -545,6 +529,7 @@ */ public boolean scanJar(String jarname) { try (JarFile jf = new JarFile(jarname)) { + out.println(Messages.get("scan.head.jar", jarname)); finder.addJar(jarname); Enumeration entries = jf.entries(); while (entries.hasMoreElements()) { @@ -557,10 +542,12 @@ } } return true; + } catch (NoSuchFileException nsfe) { + errorNoFile(jarname); } catch (IOException | ConstantPoolException ex) { - printException(ex); - return false; + errorException(ex); } + return false; } /** @@ -580,12 +567,15 @@ .filter(path -> !path.toString().endsWith("package-info.class")) .filter(path -> !path.toString().endsWith("module-info.class")) .collect(Collectors.toList()); + + out.println(Messages.get("scan.head.dir", dirname)); + for (Path p : classes) { processClass(ClassFile.read(p)); } return true; } catch (IOException | ConstantPoolException ex) { - printException(ex); + errorException(ex); return false; } } @@ -600,15 +590,35 @@ try { ClassFile cf = finder.find(className); if (cf == null) { - err("can't find class %s", className); + errorNoClass(className); return false; } else { processClass(cf); return true; } } catch (ConstantPoolException ex) { - printException(ex); + errorException(ex); return false; } } + + /** + * Scans the named class file for uses of deprecated APIs. + * + * @param fileName the class file to scan + * @return true on success, false on failure + */ + public boolean processClassFile(String fileName) { + Path path = Paths.get(fileName); + try { + ClassFile cf = ClassFile.read(path); + processClass(cf); + return true; + } catch (NoSuchFileException nsfe) { + errorNoFile(fileName); + } catch (IOException | ConstantPoolException ex) { + errorException(ex); + } + return false; + } } diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DepsAnalyzer.java --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DepsAnalyzer.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DepsAnalyzer.java Fri Nov 11 16:44:36 2016 +0100 @@ -50,7 +50,7 @@ * * Type of filters: * source filter: -include - * target filter: -package, -regex, -requires + * target filter: -package, -regex, --require * * The initial archive set for analysis includes * 1. archives specified in the command line arguments @@ -146,7 +146,9 @@ // analyze the dependencies collected analyzer.run(archives, finder.locationToArchive()); - writer.generateOutput(archives, analyzer); + if (writer != null) { + writer.generateOutput(archives, analyzer); + } } finally { finder.shutdown(); } @@ -156,7 +158,7 @@ /** * Returns the archives for reporting that has matching dependences. * - * If -requires is set, they should be excluded. + * If --require is set, they should be excluded. */ Set archives() { if (filter.requiresFilter().isEmpty()) { @@ -165,7 +167,7 @@ .filter(Archive::hasDependences) .collect(Collectors.toSet()); } else { - // use the archives that have dependences and not specified in -requires + // use the archives that have dependences and not specified in --require return archives.stream() .filter(filter::include) .filter(source -> !filter.requiresFilter().contains(source)) @@ -360,16 +362,17 @@ Archive source = dep.originArchive(); Archive target = dep.targetArchive(); String pn = dep.target(); - if ((verbose == CLASS || verbose == VERBOSE)) { + if (verbose == CLASS || verbose == VERBOSE) { int i = dep.target().lastIndexOf('.'); pn = i > 0 ? dep.target().substring(0, i) : ""; } final Info info; + Module targetModule = target.getModule(); if (source == target) { info = Info.MODULE_PRIVATE; - } else if (!target.getModule().isNamed()) { + } else if (!targetModule.isNamed()) { info = Info.EXPORTED_API; - } else if (target.getModule().isExported(pn)) { + } else if (targetModule.isExported(pn) && !targetModule.isJDKUnsupported()) { info = Info.EXPORTED_API; } else { Module module = target.getModule(); diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java Fri Nov 11 16:44:36 2016 +0100 @@ -397,6 +397,11 @@ } @Override + public Stream list() { + return Stream.empty(); + } + + @Override public void close() throws IOException { } }; diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java Fri Nov 11 16:44:36 2016 +0100 @@ -41,7 +41,7 @@ * 2. -filter:package to filter out same-package dependencies * This filter is applied when jdeps parses the class files * and filtered dependencies are not stored in the Analyzer. - * 3. -requires specifies to match target dependence from the given module + * 3. --require specifies to match target dependence from the given module * This gets expanded into package lists to be filtered. * 4. -filter:archive to filter out same-archive dependencies * This filter is applied later in the Analyzer as the @@ -166,7 +166,7 @@ // accepts target that is JDK class but not exported Module module = targetArchive.getModule(); return originArchive != targetArchive && - module.isJDK() && !module.isExported(target.getPackageName()); + isJDKInternalPackage(module, target.getPackageName()); } else if (filterSameArchive) { // accepts origin and target that from different archive return originArchive != targetArchive; @@ -174,6 +174,18 @@ return true; } + /** + * Tests if the package is an internal package of the given module. + */ + public boolean isJDKInternalPackage(Module module, String pn) { + if (module.isJDKUnsupported()) { + // its exported APIs are unsupported + return true; + } + + return module.isJDK() && !module.isExported(pn); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Fri Nov 11 16:44:36 2016 +0100 @@ -221,6 +221,12 @@ } } }, + new Option(false, "--list-deps", "--list-reduced-deps") { + void process(JdepsTask task, String opt, String arg) { + task.options.showModulesAddExports = true; + task.options.reduced = opt.equals("--list-reduced-deps"); + } + }, // ---- paths option ---- new Option(true, "-cp", "-classpath", "--class-path") { @@ -517,13 +523,13 @@ .forEach(e -> System.out.format("split package: %s %s%n", e.getKey(), e.getValue().toString())); - // check if any module specified in -requires is missing + // check if any module specified in --require is missing Stream.concat(options.addmods.stream(), options.requires.stream()) .filter(mn -> !config.isValidToken(mn)) .forEach(mn -> config.findModule(mn).orElseThrow(() -> new UncheckedBadArgs(new BadArgs("err.module.not.found", mn)))); - // --gen-module-info + // --generate-module-info if (options.genModuleInfo != null) { return genModuleInfo(config); } @@ -533,6 +539,13 @@ return new ModuleAnalyzer(config, log, options.checkModuleDeps).run(); } + if (options.showModulesAddExports) { + return new ModuleExportsAnalyzer(config, + dependencyFilter(config), + options.reduced, + log).run(); + } + if (options.dotOutputDir != null && (options.verbose == SUMMARY || options.verbose == MODULE) && !options.addmods.isEmpty() && inputArgs.isEmpty()) { @@ -555,7 +568,7 @@ .appModulePath(options.modulePath) .addmods(options.addmods); - if (options.checkModuleDeps != null) { + if (options.checkModuleDeps != null || options.showModulesAddExports) { // check all system modules in the image builder.allModules(); } @@ -597,10 +610,10 @@ // analyze the dependencies DepsAnalyzer analyzer = new DepsAnalyzer(config, - dependencyFilter(config), - writer, - options.verbose, - options.apiOnly); + dependencyFilter(config), + writer, + options.verbose, + options.apiOnly); boolean ok = analyzer.run(options.compileTimeView, options.depth); @@ -727,7 +740,7 @@ * Returns a filter used during dependency analysis */ private JdepsFilter dependencyFilter(JdepsConfiguration config) { - // Filter specified by -filter, -package, -regex, and -requires options + // Filter specified by -filter, -package, -regex, and --require options JdepsFilter.Builder builder = new JdepsFilter.Builder(); // source filters @@ -737,7 +750,7 @@ builder.filter(options.filterSamePackage, options.filterSameArchive); builder.findJDKInternals(options.findJDKInternals); - // -requires + // --require if (!options.requires.isEmpty()) { options.requires.stream() .forEach(mn -> { @@ -757,8 +770,8 @@ // check if system module is set config.rootModules().stream() - .map(Module::name) - .forEach(builder::includeIfSystemModule); + .map(Module::name) + .forEach(builder::includeIfSystemModule); return builder.build(); } @@ -886,6 +899,8 @@ String rootModule; Set addmods = new HashSet<>(); Runtime.Version multiRelease; + boolean showModulesAddExports; + boolean reduced; boolean hasFilter() { return numFilters() > 0; diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsWriter.java --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsWriter.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsWriter.java Fri Nov 11 16:44:36 2016 +0100 @@ -50,7 +50,7 @@ final boolean showProfile; final boolean showModule; - private JdepsWriter(Analyzer.Type type, boolean showProfile, boolean showModule) { + JdepsWriter(Analyzer.Type type, boolean showProfile, boolean showModule) { this.type = type; this.showProfile = showProfile; this.showModule = showModule; @@ -318,8 +318,7 @@ } // exported API - boolean jdkunsupported = Module.JDK_UNSUPPORTED.equals(module.name()); - if (module.isExported(pn) && !jdkunsupported) { + if (module.isExported(pn) && !module.isJDKUnsupported()) { return showProfileOrModule(module); } diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java Fri Nov 11 16:44:36 2016 +0100 @@ -126,12 +126,13 @@ * Tests if the package of the given name is exported. */ public boolean isExported(String pn) { - if (JDK_UNSUPPORTED.equals(this.name())) { - return false; - } return exports.containsKey(pn) ? exports.get(pn).isEmpty() : false; } + public boolean isJDKUnsupported() { + return JDK_UNSUPPORTED.equals(this.name()); + } + /** * Converts this module to a strict module with the given dependences * diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleAnalyzer.java --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleAnalyzer.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleAnalyzer.java Fri Nov 11 16:44:36 2016 +0100 @@ -41,10 +41,8 @@ import java.nio.file.Path; import java.util.Collections; import java.util.Comparator; -import java.util.Deque; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -179,50 +177,43 @@ return builder.build(); } - ModuleDescriptor reduced() { - Graph.Builder bd = new Graph.Builder<>(); + private Graph buildReducedGraph() { + ModuleGraphBuilder rpBuilder = new ModuleGraphBuilder(configuration); + rpBuilder.addModule(root); requiresPublic.stream() - .forEach(m -> { - bd.addNode(m); - bd.addEdge(root, m); - }); + .forEach(m -> rpBuilder.addEdge(root, m)); // requires public graph - Graph rbg = bd.build().reduce(); + Graph rbg = rpBuilder.build().reduce(); + + ModuleGraphBuilder gb = new ModuleGraphBuilder(configuration); + gb.addModule(root); + requires.stream() + .forEach(m -> gb.addEdge(root, m)); // transitive reduction - Graph newGraph = buildGraph(requires).reduce(rbg); + Graph newGraph = gb.buildGraph().reduce(rbg); if (DEBUG) { System.err.println("after transitive reduction: "); newGraph.printGraph(log); } - - return descriptor(requiresPublic, newGraph.adjacentNodes(root)); + return newGraph; } + /** + * Apply the transitive reduction on the module graph + * and returns the corresponding ModuleDescriptor + */ + ModuleDescriptor reduced() { + Graph g = buildReducedGraph(); + return descriptor(requiresPublic, g.adjacentNodes(root)); + } /** * Apply transitive reduction on the resulting graph and reports * recommended requires. */ private void analyzeDeps() { - Graph.Builder builder = new Graph.Builder<>(); - requiresPublic.stream() - .forEach(m -> { - builder.addNode(m); - builder.addEdge(root, m); - }); - - // requires public graph - Graph rbg = buildGraph(requiresPublic).reduce(); - - // transitive reduction - Graph newGraph = buildGraph(requires).reduce(builder.build().reduce()); - if (DEBUG) { - System.err.println("after transitive reduction: "); - newGraph.printGraph(log); - } - printModuleDescriptor(log, root); ModuleDescriptor analyzedDescriptor = descriptor(); @@ -277,45 +268,6 @@ /** - * Returns a graph of modules required by the specified module. - * - * Requires public edges of the dependences are added to the graph. - */ - private Graph buildGraph(Set deps) { - Graph.Builder builder = new Graph.Builder<>(); - builder.addNode(root); - Set visited = new HashSet<>(); - visited.add(root); - Deque deque = new LinkedList<>(); - deps.stream() - .forEach(m -> { - deque.add(m); - builder.addEdge(root, m); - }); - - // read requires public from ModuleDescription - Module source; - while ((source = deque.poll()) != null) { - if (visited.contains(source)) - continue; - - visited.add(source); - builder.addNode(source); - Module from = source; - source.descriptor().requires().stream() - .filter(req -> req.modifiers().contains(PUBLIC)) - .map(ModuleDescriptor.Requires::name) - .map(configuration::findModule) - .flatMap(Optional::stream) - .forEach(m -> { - deque.add(m); - builder.addEdge(from, m); - }); - } - return builder.build(); - } - - /** * Detects any qualified exports not used by the target module. */ private Map> unusedQualifiedExports() { diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleExportsAnalyzer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleExportsAnalyzer.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.jdeps; + +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.module.ModuleDescriptor; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static com.sun.tools.jdeps.Analyzer.NOT_FOUND; + +/** + * Analyze module dependences and any reference to JDK internal APIs. + * It can apply transition reduction on the resulting module graph. + * + * The result prints one line per module it depends on + * one line per JDK internal API package it references: + * $MODULE[/$PACKAGE] + * + */ +public class ModuleExportsAnalyzer extends DepsAnalyzer { + // source archive to its dependences and JDK internal APIs it references + private final Map>> deps = new HashMap<>(); + private final boolean reduced; + private final PrintWriter writer; + public ModuleExportsAnalyzer(JdepsConfiguration config, + JdepsFilter filter, + boolean reduced, + PrintWriter writer) { + super(config, filter, null, + Analyzer.Type.PACKAGE, + false /* all classes */); + this.reduced = reduced; + this.writer = writer; + } + + @Override + public boolean run() throws IOException { + // analyze dependences + boolean rc = super.run(); + + // A visitor to record the module-level dependences as well as + // use of JDK internal APIs + Analyzer.Visitor visitor = new Analyzer.Visitor() { + @Override + public void visitDependence(String origin, Archive originArchive, + String target, Archive targetArchive) + { + Set jdkInternals = + deps.computeIfAbsent(originArchive, _k -> new HashMap<>()) + .computeIfAbsent(targetArchive, _k -> new HashSet<>()); + + Module module = targetArchive.getModule(); + if (originArchive.getModule() != module && + module.isJDK() && !module.isExported(target)) { + // use of JDK internal APIs + jdkInternals.add(target); + } + } + }; + + // visit the dependences + archives.stream() + .filter(analyzer::hasDependences) + .sorted(Comparator.comparing(Archive::getName)) + .forEach(archive -> analyzer.visitDependences(archive, visitor)); + + + // print the dependences on named modules + printDependences(); + + // print the dependences on unnamed module + deps.values().stream() + .flatMap(map -> map.keySet().stream()) + .filter(archive -> !archive.getModule().isNamed()) + .map(archive -> archive != NOT_FOUND + ? "unnamed module: " + archive.getPathName() + : archive.getPathName()) + .distinct() + .sorted() + .forEach(archive -> writer.format(" %s%n", archive)); + + return rc; + } + + private void printDependences() { + // find use of JDK internals + Map> jdkinternals = new HashMap<>(); + deps.keySet().stream() + .filter(source -> !source.getModule().isNamed()) + .map(deps::get) + .flatMap(map -> map.entrySet().stream()) + .filter(e -> e.getValue().size() > 0) + .forEach(e -> jdkinternals.computeIfAbsent(e.getKey().getModule(), + _k -> new HashSet<>()) + .addAll(e.getValue())); + + + // build module graph + ModuleGraphBuilder builder = new ModuleGraphBuilder(configuration); + Module root = new RootModule("root"); + builder.addModule(root); + // find named module dependences + deps.keySet().stream() + .filter(source -> !source.getModule().isNamed()) + .map(deps::get) + .flatMap(map -> map.keySet().stream()) + .filter(m -> m.getModule().isNamed()) + .map(Archive::getModule) + .forEach(m -> builder.addEdge(root, m)); + + // module dependences + Set modules = builder.build().adjacentNodes(root); + + // if reduced is set, apply transition reduction + Set reducedSet = reduced ? builder.reduced().adjacentNodes(root) + : modules; + + modules.stream() + .sorted(Comparator.comparing(Module::name)) + .forEach(m -> { + if (jdkinternals.containsKey(m)) { + jdkinternals.get(m).stream() + .sorted() + .forEach(pn -> writer.format(" %s/%s%n", m, pn)); + } else if (reducedSet.contains(m)){ + // if the transition reduction is applied, show the reduced graph + writer.format(" %s%n", m); + } + }); + } + + + private class RootModule extends Module { + final ModuleDescriptor descriptor; + RootModule(String name) { + super(name); + + ModuleDescriptor.Builder builder = new ModuleDescriptor.Builder(name); + this.descriptor = builder.build(); + } + + @Override + public ModuleDescriptor descriptor() { + return descriptor; + } + } + +} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleGraphBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleGraphBuilder.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.jdeps; + +import java.io.PrintWriter; +import java.lang.module.ModuleDescriptor; +import java.util.Deque; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Stream; + +import static java.lang.module.ModuleDescriptor.Requires.Modifier.*; +import static com.sun.tools.jdeps.Module.*; + +/** + * A builder to create a Graph + */ +public class ModuleGraphBuilder extends Graph.Builder { + final JdepsConfiguration config; + + ModuleGraphBuilder(JdepsConfiguration config) { + this.config = config; + } + + /** + * Adds a module to the graph. + */ + ModuleGraphBuilder addModule(Module module) { + addNode(module); + return this; + } + + /** + * Apply transitive reduction on the resulting graph + */ + public Graph reduced() { + Graph graph = build(); + // transitive reduction + Graph newGraph = buildGraph(graph.edges()).reduce(); + + if (DEBUG) { + PrintWriter log = new PrintWriter(System.err); + System.err.println("before transitive reduction: "); + graph.printGraph(log); + System.err.println("after transitive reduction: "); + newGraph.printGraph(log); + } + + return newGraph; + } + + public Graph buildGraph() { + Graph graph = build(); + return buildGraph(graph.edges()); + } + + /** + * Build a graph of module from the given dependences. + * + * It transitively includes all implied read edges. + */ + private Graph buildGraph(Map> edges) { + Graph.Builder builder = new Graph.Builder<>(); + Set visited = new HashSet<>(); + Deque deque = new LinkedList<>(); + edges.entrySet().stream().forEach(e -> { + Module m = e.getKey(); + deque.add(m); + e.getValue().stream().forEach(v -> { + deque.add(v); + builder.addEdge(m, v); + }); + }); + + // read requires public from ModuleDescriptor + Module source; + while ((source = deque.poll()) != null) { + if (visited.contains(source)) + continue; + + visited.add(source); + builder.addNode(source); + Module from = source; + requiresPublic(from).forEach(m -> { + deque.add(m); + builder.addEdge(from, m); + }); + } + return builder.build(); + } + + /* + * Returns a stream of modules upon which the given module `requires public` + */ + public Stream requiresPublic(Module m) { + // find requires public + return m.descriptor() + .requires().stream() + .filter(req -> req.modifiers().contains(PUBLIC)) + .map(ModuleDescriptor.Requires::name) + .map(config::findModule) + .flatMap(Optional::stream); + } +} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Fri Nov 11 16:44:36 2016 +0100 @@ -149,6 +149,15 @@ \ used with -p, -e and -s options.\n\ \ WARNING: JDK internal APIs are inaccessible. +main.opt.list-deps=\ +\ --list-deps Lists the dependences and use of JDK internal\n\ +\ APIs.\n\ +\ --list-reduced-deps Same as --list-deps with not listing\n\ +\ the implied reads edges from the module graph\n\ +\ If module M1 depends on M2 and M3,\n\ +\ M2 requires public on M3, then M1 reading M3 is\n\ +\ implied and removed from the module graph. + main.opt.depth=\ \ -depth= Specify the depth of the transitive\n\ \ dependency analysis diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java Fri Nov 11 16:44:36 2016 +0100 @@ -25,36 +25,39 @@ package jdk.internal.jshell.tool; +import jdk.jshell.SourceCodeAnalysis.Documentation; import jdk.jshell.SourceCodeAnalysis.QualifiedNames; import jdk.jshell.SourceCodeAnalysis.Suggestion; -import java.awt.event.ActionListener; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import java.io.PrintStream; import java.io.UncheckedIOException; -import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.function.Supplier; +import java.util.function.Function; import java.util.prefs.BackingStoreException; import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.internal.shellsupport.doc.JavadocFormatter; import jdk.internal.jline.NoInterruptUnixTerminal; import jdk.internal.jline.Terminal; import jdk.internal.jline.TerminalFactory; import jdk.internal.jline.TerminalSupport; import jdk.internal.jline.WindowsTerminal; import jdk.internal.jline.console.ConsoleReader; +import jdk.internal.jline.console.CursorBuffer; import jdk.internal.jline.console.KeyMap; import jdk.internal.jline.console.UserInterruptException; import jdk.internal.jline.console.completer.Completer; @@ -167,10 +170,10 @@ return anchor[0]; } }); - bind(DOCUMENTATION_SHORTCUT, (ActionListener) evt -> documentation(repl)); + bind(DOCUMENTATION_SHORTCUT, (Runnable) () -> documentation(repl)); for (FixComputer computer : FIX_COMPUTERS) { for (String shortcuts : SHORTCUT_FIXES) { - bind(shortcuts + computer.shortcut, (ActionListener) evt -> fixes(computer)); + bind(shortcuts + computer.shortcut, (Runnable) () -> fixes(computer)); } } try { @@ -259,22 +262,118 @@ "\u001BO3P" //Alt-F1 (Linux) }; + private String lastDocumentationBuffer; + private int lastDocumentationCursor = (-1); + private void documentation(JShellTool repl) { String buffer = in.getCursorBuffer().buffer.toString(); int cursor = in.getCursorBuffer().cursor; - String doc; + boolean firstInvocation = !buffer.equals(lastDocumentationBuffer) || cursor != lastDocumentationCursor; + lastDocumentationBuffer = buffer; + lastDocumentationCursor = cursor; + List doc; + String seeMore; + Terminal term = in.getTerminal(); if (prefix.isEmpty() && buffer.trim().startsWith("/")) { - doc = repl.commandDocumentation(buffer, cursor); + doc = Arrays.asList(repl.commandDocumentation(buffer, cursor, firstInvocation)); + seeMore = "jshell.console.see.help"; } else { - doc = repl.analysis.documentation(prefix + buffer, cursor + prefix.length()); + JavadocFormatter formatter = new JavadocFormatter(term.getWidth(), + term.isAnsiSupported()); + Function convertor; + if (firstInvocation) { + convertor = d -> d.signature(); + } else { + convertor = d -> formatter.formatJavadoc(d.signature(), + d.javadoc() != null ? d.javadoc() + : repl.messageFormat("jshell.console.no.javadoc")); + } + doc = repl.analysis.documentation(prefix + buffer, cursor + prefix.length(), !firstInvocation) + .stream() + .map(convertor) + .collect(Collectors.toList()); + seeMore = "jshell.console.see.javadoc"; } try { - if (doc != null) { - in.println(); - in.println(doc); - in.redrawLine(); - in.flush(); + if (doc != null && !doc.isEmpty()) { + if (firstInvocation) { + in.println(); + in.println(doc.stream().collect(Collectors.joining("\n"))); + in.println(repl.messageFormat(seeMore)); + in.redrawLine(); + in.flush(); + } else { + in.println(); + + int height = term.getHeight(); + String lastNote = ""; + + PRINT_DOC: for (Iterator docIt = doc.iterator(); docIt.hasNext(); ) { + String currentDoc = docIt.next(); + String[] lines = currentDoc.split("\n"); + int firstLine = 0; + + PRINT_PAGE: while (true) { + int toPrint = height - 1; + + while (toPrint > 0 && firstLine < lines.length) { + in.println(lines[firstLine++]); + toPrint--; + } + + if (firstLine >= lines.length) { + break; + } + + lastNote = repl.getResourceString("jshell.console.see.next.page"); + in.print(lastNote + ConsoleReader.RESET_LINE); + in.flush(); + + while (true) { + int r = in.readCharacter(); + + switch (r) { + case ' ': continue PRINT_PAGE; + case 'q': + case 3: + break PRINT_DOC; + default: + in.beep(); + break; + } + } + } + + if (docIt.hasNext()) { + lastNote = repl.getResourceString("jshell.console.see.next.javadoc"); + in.print(lastNote + ConsoleReader.RESET_LINE); + in.flush(); + + while (true) { + int r = in.readCharacter(); + + switch (r) { + case ' ': continue PRINT_DOC; + case 'q': + case 3: + break PRINT_DOC; + default: + in.beep(); + break; + } + } + } + } + //clear the "press space" line: + in.getCursorBuffer().buffer.replace(0, buffer.length(), lastNote); + in.getCursorBuffer().cursor = 0; + in.killLine(); + in.getCursorBuffer().buffer.append(buffer); + in.getCursorBuffer().cursor = cursor; + in.redrawLine(); + in.flush(); + } } else { in.beep(); } diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/EditPad.java --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/EditPad.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.jshell.tool; - -import java.awt.BorderLayout; -import java.awt.FlowLayout; -import java.awt.event.KeyEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.concurrent.CountDownLatch; -import java.util.function.Consumer; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.SwingUtilities; - -/** - * A minimal Swing editor as a fallback when the user does not specify an - * external editor. - */ -@SuppressWarnings("serial") // serialVersionUID intentionally omitted -public class EditPad extends JFrame implements Runnable { - private final Consumer errorHandler; // For possible future error handling - private final String initialText; - private final CountDownLatch closeLock; - private final Consumer saveHandler; - - EditPad(Consumer errorHandler, String initialText, - CountDownLatch closeLock, Consumer saveHandler) { - super("JShell Edit Pad"); - this.errorHandler = errorHandler; - this.initialText = initialText; - this.closeLock = closeLock; - this.saveHandler = saveHandler; - } - - @Override - public void run() { - addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - EditPad.this.dispose(); - closeLock.countDown(); - } - }); - setLocationRelativeTo(null); - setLayout(new BorderLayout()); - JTextArea textArea = new JTextArea(initialText); - add(new JScrollPane(textArea), BorderLayout.CENTER); - add(buttons(textArea), BorderLayout.SOUTH); - - setSize(800, 600); - setVisible(true); - } - - private JPanel buttons(JTextArea textArea) { - FlowLayout flow = new FlowLayout(); - flow.setHgap(35); - JPanel buttons = new JPanel(flow); - JButton cancel = new JButton("Cancel"); - cancel.setMnemonic(KeyEvent.VK_C); - JButton accept = new JButton("Accept"); - accept.setMnemonic(KeyEvent.VK_A); - JButton exit = new JButton("Exit"); - exit.setMnemonic(KeyEvent.VK_X); - buttons.add(cancel); - buttons.add(accept); - buttons.add(exit); - - cancel.addActionListener(e -> { - close(); - }); - accept.addActionListener(e -> { - saveHandler.accept(textArea.getText()); - }); - exit.addActionListener(e -> { - saveHandler.accept(textArea.getText()); - close(); - }); - - return buttons; - } - - private void close() { - setVisible(false); - dispose(); - closeLock.countDown(); - } - - public static void edit(Consumer errorHandler, String initialText, - Consumer saveHandler) { - CountDownLatch closeLock = new CountDownLatch(1); - SwingUtilities.invokeLater( - new EditPad(errorHandler, initialText, closeLock, saveHandler)); - do { - try { - closeLock.await(); - break; - } catch (InterruptedException ex) { - // ignore and loop - } - } while (true); - } -} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ExternalEditor.java --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ExternalEditor.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.jshell.tool; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.ClosedWatchServiceException; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.WatchKey; -import java.nio.file.WatchService; -import java.util.Arrays; -import java.util.Scanner; -import java.util.function.Consumer; -import java.util.stream.Collectors; -import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; -import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; -import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; - -/** - * Wrapper for controlling an external editor. - */ -public class ExternalEditor { - private final Consumer errorHandler; - private final Consumer saveHandler; - private final Consumer printHandler; - private final IOContext input; - private final boolean wait; - - private WatchService watcher; - private Thread watchedThread; - private Path dir; - private Path tmpfile; - - ExternalEditor(Consumer errorHandler, Consumer saveHandler, - IOContext input, boolean wait, Consumer printHandler) { - this.errorHandler = errorHandler; - this.saveHandler = saveHandler; - this.printHandler = printHandler; - this.input = input; - this.wait = wait; - } - - private void edit(String[] cmd, String initialText) { - try { - setupWatch(initialText); - launch(cmd); - } catch (IOException ex) { - errorHandler.accept(ex.getMessage()); - } - } - - /** - * Creates a WatchService and registers the given directory - */ - private void setupWatch(String initialText) throws IOException { - this.watcher = FileSystems.getDefault().newWatchService(); - this.dir = Files.createTempDirectory("jshelltemp"); - this.tmpfile = Files.createTempFile(dir, null, ".java"); - Files.write(tmpfile, initialText.getBytes(Charset.forName("UTF-8"))); - dir.register(watcher, - ENTRY_CREATE, - ENTRY_DELETE, - ENTRY_MODIFY); - watchedThread = new Thread(() -> { - for (;;) { - WatchKey key; - try { - key = watcher.take(); - } catch (ClosedWatchServiceException ex) { - // The watch service has been closed, we are done - break; - } catch (InterruptedException ex) { - // tolerate an interrupt - continue; - } - - if (!key.pollEvents().isEmpty()) { - // Changes have occurred in temp edit directory, - // transfer the new sources to JShell (unless the editor is - // running directly in JShell's window -- don't make a mess) - if (!input.terminalEditorRunning()) { - saveFile(); - } - } - - boolean valid = key.reset(); - if (!valid) { - // The watch service has been closed, we are done - break; - } - } - }); - watchedThread.start(); - } - - private void launch(String[] cmd) throws IOException { - String[] params = Arrays.copyOf(cmd, cmd.length + 1); - params[cmd.length] = tmpfile.toString(); - ProcessBuilder pb = new ProcessBuilder(params); - pb = pb.inheritIO(); - - try { - input.suspend(); - Process process = pb.start(); - // wait to exit edit mode in one of these ways... - if (wait) { - // -wait option -- ignore process exit, wait for carriage-return - Scanner scanner = new Scanner(System.in); - printHandler.accept("jshell.msg.press.return.to.leave.edit.mode"); - scanner.nextLine(); - } else { - // wait for process to exit - process.waitFor(); - } - } catch (IOException ex) { - errorHandler.accept("process IO failure: " + ex.getMessage()); - } catch (InterruptedException ex) { - errorHandler.accept("process interrupt: " + ex.getMessage()); - } finally { - try { - watcher.close(); - watchedThread.join(); //so that saveFile() is finished. - saveFile(); - } catch (InterruptedException ex) { - errorHandler.accept("process interrupt: " + ex.getMessage()); - } finally { - input.resume(); - } - } - } - - private void saveFile() { - try { - saveHandler.accept(Files.lines(tmpfile).collect(Collectors.joining("\n", "", "\n"))); - } catch (IOException ex) { - errorHandler.accept("Failure in read edit file: " + ex.getMessage()); - } - } - - static void edit(String[] cmd, Consumer errorHandler, String initialText, - Consumer saveHandler, IOContext input, boolean wait, Consumer printHandler) { - ExternalEditor ed = new ExternalEditor(errorHandler, saveHandler, input, wait, printHandler); - ed.edit(cmd, initialText); - } -} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java Fri Nov 11 16:44:36 2016 +0100 @@ -116,6 +116,10 @@ name, type, value, unresolved, errorLines); } + public String truncateVarValue(String value) { + return mode.truncateVarValue(value); + } + public String getPrompt(String nextId) { return mode.getPrompt(nextId); } @@ -416,6 +420,45 @@ return sb.toString(); } + String truncateVarValue(String value) { + return truncateValue(value, + bits(FormatCase.VARVALUE, FormatAction.ADDED, + FormatWhen.PRIMARY, FormatResolve.OK, + FormatUnresolved.UNRESOLVED0, FormatErrors.ERROR0)); + } + + String truncateValue(String value, long bits) { + if (value==null) { + return ""; + } else { + // Retrieve the truncation length + String truncField = format(TRUNCATION_FIELD, bits); + if (truncField.isEmpty()) { + // No truncation set, use whole value + return value; + } else { + // Convert truncation length to int + // this is safe since it has been tested before it is set + int trunc = Integer.parseUnsignedInt(truncField); + int len = value.length(); + if (len > trunc) { + if (trunc <= 13) { + // Very short truncations have no room for "..." + return value.substring(0, trunc); + } else { + // Normal truncation, make total length equal truncation length + int endLen = trunc / 3; + int startLen = trunc - 5 - endLen; + return value.substring(0, startLen) + " ... " + value.substring(len -endLen); + } + } else { + // Within truncation length, use whole value + return value; + } + } + } + } + // Compute the display output given full context and values String format(FormatCase fc, FormatAction fa, FormatWhen fw, FormatResolve fr, FormatUnresolved fu, FormatErrors fe, @@ -425,33 +468,7 @@ String fname = name==null? "" : name; String ftype = type==null? "" : type; // Compute the representation of value - String fvalue; - if (value==null) { - fvalue = ""; - } else { - // Retrieve the truncation length - String truncField = format(TRUNCATION_FIELD, bits); - if (truncField.isEmpty()) { - // No truncation set, use whole value - fvalue = value; - } else { - // Convert truncation length to int - // this is safe since it has been tested before it is set - int trunc = Integer.parseUnsignedInt(truncField); - if (value.length() > trunc) { - if (trunc <= 5) { - // Very short truncations have no room for "..." - fvalue = value.substring(0, trunc); - } else { - // Normal truncation, make total length equal truncation length - fvalue = value.substring(0, trunc - 4) + " ..."; - } - } else { - // Within truncation length, use whole value - fvalue = value; - } - } - } + String fvalue = truncateValue(value, bits); String funresolved = unresolved==null? "" : unresolved; String errors = errorLines.stream() .map(el -> String.format( diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java Fri Nov 11 16:44:36 2016 +0100 @@ -89,6 +89,7 @@ import java.util.MissingResourceException; import java.util.Optional; import java.util.ResourceBundle; +import java.util.ServiceLoader; import java.util.Spliterators; import java.util.function.Function; import java.util.function.Supplier; @@ -99,6 +100,8 @@ import jdk.internal.jshell.tool.Feedback.FormatResolve; import jdk.internal.jshell.tool.Feedback.FormatUnresolved; import jdk.internal.jshell.tool.Feedback.FormatWhen; +import jdk.internal.editor.spi.BuildInEditorProvider; +import jdk.internal.editor.external.ExternalEditor; import static java.util.Arrays.asList; import static java.util.Arrays.stream; import static java.util.stream.Collectors.joining; @@ -323,7 +326,7 @@ } /** - * Print using resource bundle look-up and adding prefix and postfix + * Resource bundle look-up * * @param key the resource key */ @@ -523,7 +526,7 @@ runFile(loadFile, "jshell"); } - if (regenerateOnDeath) { + if (regenerateOnDeath && feedback.shouldDisplayCommandFluff()) { hardmsg("jshell.msg.welcome", version()); } @@ -565,6 +568,8 @@ private List processCommandArgs(String[] args) { OptionParser parser = new OptionParser(); OptionSpec cp = parser.accepts("class-path").withRequiredArg(); + OptionSpec mpath = parser.accepts("module-path").withRequiredArg(); + OptionSpec amods = parser.accepts("add-modules").withRequiredArg(); OptionSpec st = parser.accepts("startup").withRequiredArg(); parser.acceptsAll(asList("n", "no-startup")); OptionSpec fb = parser.accepts("feedback").withRequiredArg(); @@ -658,6 +663,18 @@ if (options.has(c)) { compilerOptions.addAll(options.valuesOf(c)); } + if (options.has(mpath)) { + compilerOptions.add("--module-path"); + compilerOptions.addAll(options.valuesOf(mpath)); + remoteVMOptions.add("--module-path"); + remoteVMOptions.addAll(options.valuesOf(mpath)); + } + if (options.has(amods)) { + compilerOptions.add("--add-modules"); + compilerOptions.addAll(options.valuesOf(amods)); + remoteVMOptions.add("--add-modules"); + remoteVMOptions.addAll(options.valuesOf(amods)); + } if (options.has(addExports)) { List exports = options.valuesOf(addExports).stream() @@ -1294,7 +1311,7 @@ return commandCompletions.completionSuggestions(code, cursor, anchor); } - public String commandDocumentation(String code, int cursor) { + public String commandDocumentation(String code, int cursor, boolean shortDescription) { code = code.substring(0, cursor); int space = code.indexOf(' '); @@ -1302,7 +1319,7 @@ String cmd = code.substring(0, space); Command command = commands.get(cmd); if (command != null) { - return getResourceString(command.helpKey + ".summary"); + return getResourceString(command.helpKey + (shortDescription ? ".summary" : "")); } } @@ -1964,20 +1981,59 @@ Consumer saveHandler = new SaveHandler(src, srcSet); Consumer errorHandler = s -> hard("Edit Error: %s", s); if (editor == BUILT_IN_EDITOR) { - try { - EditPad.edit(errorHandler, src, saveHandler); - } catch (RuntimeException ex) { - errormsg("jshell.err.cant.launch.editor", ex); - fluffmsg("jshell.msg.try.set.editor"); - return false; + return builtInEdit(src, saveHandler, errorHandler); + } else { + // Changes have occurred in temp edit directory, + // transfer the new sources to JShell (unless the editor is + // running directly in JShell's window -- don't make a mess) + String[] buffer = new String[1]; + Consumer extSaveHandler = s -> { + if (input.terminalEditorRunning()) { + buffer[0] = s; + } else { + saveHandler.accept(s); + } + }; + ExternalEditor.edit(editor.cmd, src, + errorHandler, extSaveHandler, + () -> input.suspend(), + () -> input.resume(), + editor.wait, + () -> hardrb("jshell.msg.press.return.to.leave.edit.mode")); + if (buffer[0] != null) { + saveHandler.accept(buffer[0]); } - } else { - ExternalEditor.edit(editor.cmd, errorHandler, src, saveHandler, input, - editor.wait, this::hardrb); } return true; } //where + // start the built-in editor + private boolean builtInEdit(String initialText, + Consumer saveHandler, Consumer errorHandler) { + try { + ServiceLoader sl + = ServiceLoader.load(BuildInEditorProvider.class); + // Find the highest ranking provider + BuildInEditorProvider provider = null; + for (BuildInEditorProvider p : sl) { + if (provider == null || p.rank() > provider.rank()) { + provider = p; + } + } + if (provider != null) { + provider.edit(getResourceString("jshell.label.editpad"), + initialText, saveHandler, errorHandler); + return true; + } else { + errormsg("jshell.err.no.builtin.editor"); + } + } catch (RuntimeException ex) { + errormsg("jshell.err.cant.launch.editor", ex); + } + fluffmsg("jshell.msg.try.set.editor"); + return false; + } + //where // receives editor requests to save private class SaveHandler implements Consumer { @@ -2184,7 +2240,7 @@ stream.forEachOrdered(vk -> { String val = state.status(vk) == Status.VALID - ? state.varValue(vk) + ? feedback.truncateVarValue(state.varValue(vk)) : getResourceString("jshell.msg.vars.not.active"); hard(" %s %s = %s", vk.typeName(), vk.name(), val); }); diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties Fri Nov 11 16:44:36 2016 +0100 @@ -54,10 +54,12 @@ jshell.err.command.ambiguous = Command: ''{0}'' is ambiguous: {1} jshell.msg.set.editor.set = Editor set to: {0} jshell.msg.set.editor.retain = Editor setting retained: {0} -jshell.err.cant.launch.editor = Cannot launch editor -- unexpected exception: {0} -jshell.msg.try.set.editor = Try /set editor to use external editor. +jshell.err.no.builtin.editor = Built-in editor not available. +jshell.err.cant.launch.editor = Cannot launch built-in editor -- unexpected exception: {0} +jshell.msg.try.set.editor = See ''/help /set editor'' to use external editor. jshell.msg.press.return.to.leave.edit.mode = Press return to leave edit mode. jshell.err.wait.applies.to.external.editor = -wait applies to external editors +jshell.label.editpad = JShell Edit Pad jshell.err.setting.to.retain.must.be.specified = The setting to retain must be specified -- {0} jshell.msg.set.show.mode.settings = \nTo show mode settings use ''/set prompt'', ''/set truncation'', ...\n\ @@ -145,6 +147,11 @@ jshell.err.retained.mode.failure = Failure in retained modes (modes cleared) -- {0} {1} jshell.console.see.more = +jshell.console.see.javadoc = +jshell.console.see.help = +jshell.console.see.next.page = -- Press space for next page, Q to quit. -- +jshell.console.see.next.javadoc = -- Press space for next javadoc, Q to quit. -- +jshell.console.no.javadoc = jshell.console.do.nothing = Do nothing jshell.console.choice = Choice: \ @@ -158,6 +165,10 @@ Usage: jshell \n\ where possible options include:\n\ \ --class-path Specify where to find user class files\n\ +\ --module-path Specify where to find application modules\n\ +\ --add-modules (,)*\n\ +\ Specify modules to resolve, or all modules on the\n\ +\ module path if is ALL-MODULE-PATHs\n\ \ --startup One run replacement for the start-up definitions\n\ \ --no-startup Do not run the start-up definitions\n\ \ --feedback Specify the initial feedback mode. The mode may be\n\ @@ -316,8 +327,8 @@ help.reload.summary = reset and replay relevant history -- current or previous (-restore) help.reload.args = [-restore] [-quiet] help.reload =\ -Reset the jshell tool code and execution state then replay each\n\ -jshell valid command and valid snippet in the order they were entered.\n\ +Reset the jshell tool code and execution state then replay each valid snippet\n\ +and any /drop or /classpath commands in the order they were entered.\n\ \n\ /reload\n\t\ Reset and replay the valid history since jshell was entered, or\n\t\ @@ -327,7 +338,7 @@ Reset and replay the valid history between the previous and most\n\t\ recent time that jshell was entered, or a /reset, or /reload\n\t\ command was executed. This can thus be used to restore a previous\n\t\ - jshell tool sesson.\n\n\ + jshell tool session.\n\n\ /reload [-restore] -quiet\n\t\ With the '-quiet' argument the replay is not shown. Errors will display. @@ -790,7 +801,7 @@ /set format verbose unrerr '{unresolved} is declared and these errors are corrected: {errors}' unresolved1-error2 \n\ /set format verbose unrerr '{unresolved} are declared and these errors are corrected: {errors}' unresolved2-error2 \n\ \n\ -/set format verbose resolve '{until}{unrerr}' added,modified,replaced,used \n\ +/set format verbose resolve '{until}{unrerr}' defined,notdefined-added,modified,replaced,used \n\ \n\ /set format verbose typeKind 'class' class \n\ /set format verbose typeKind 'interface' interface \n\ diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java Fri Nov 11 16:44:36 2016 +0100 @@ -855,6 +855,8 @@ case PUBLIC: case PROTECTED: case PRIVATE: + // quietly ignore, user cannot see effects one way or the other + break; case STATIC: case FINAL: list.add(mod); diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java Fri Nov 11 16:44:36 2016 +0100 @@ -47,7 +47,7 @@ import java.util.stream.Stream; import jdk.internal.jshell.debug.InternalDebugControl; import jdk.jshell.Snippet.Status; -import jdk.jshell.execution.JDIDefaultExecutionControl; +import jdk.jshell.execution.JdiDefaultExecutionControl; import jdk.jshell.spi.ExecutionControl.EngineTerminationException; import jdk.jshell.spi.ExecutionControl.ExecutionControlException; import jdk.jshell.spi.ExecutionEnv; @@ -117,10 +117,9 @@ this.extraRemoteVMOptions = b.extraRemoteVMOptions; this.extraCompilerOptions = b.extraCompilerOptions; this.executionControlGenerator = b.executionControlGenerator==null - ? failOverExecutionControlGenerator( - JDIDefaultExecutionControl.launch(), - JDIDefaultExecutionControl.listen("localhost"), - JDIDefaultExecutionControl.listen(null)) + ? failOverExecutionControlGenerator(JdiDefaultExecutionControl.launch(), + JdiDefaultExecutionControl.listen("localhost"), + JdiDefaultExecutionControl.listen(null)) : b.executionControlGenerator; this.maps = new SnippetMaps(this); @@ -506,6 +505,9 @@ if (!closed) { closeDown(); executionControl().close(); + if (sourceCodeAnalysis != null) { + sourceCodeAnalysis.close(); + } } } diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/MaskCommentsAndModifiers.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/MaskCommentsAndModifiers.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/MaskCommentsAndModifiers.java Fri Nov 11 16:44:36 2016 +0100 @@ -36,10 +36,14 @@ */ class MaskCommentsAndModifiers { - private final static Set IGNORED_MODIFERS = + private final static Set IGNORED_MODIFIERS = Stream.of( "public", "protected", "private", "static", "final" ) .collect( Collectors.toSet() ); + private final static Set OTHER_MODIFIERS = + Stream.of( "abstract", "strictfp", "transient", "volatile", "synchronized", "native", "default" ) + .collect( Collectors.toSet() ); + // Builder to accumulate non-masked characters private final StringBuilder sbCleared = new StringBuilder(); @@ -52,24 +56,28 @@ // Entire input string length private final int length; - // Should leading modifiers be masked away - private final boolean maskModifiers; - - // The next character + // The next character position private int next = 0; - // We have past any point where a top-level modifier could be - private boolean inside = false; + // The current character + private int c; + + // Do we mask-off ignored modifiers? Set by parameter and turned off after + // initial modifier section + private boolean maskModifiers; // Does the string end with an unclosed '/*' style comment? private boolean openComment = false; - @SuppressWarnings("empty-statement") MaskCommentsAndModifiers(String s, boolean maskModifiers) { this.str = s; this.length = s.length(); this.maskModifiers = maskModifiers; - do { } while (next()); + read(); + while (c >= 0) { + next(); + read(); + } } String cleared() { @@ -90,24 +98,33 @@ * Read the next character */ private int read() { - if (next >= length) { - return -1; - } - return str.charAt(next++); + return c = (next >= length) + ? -1 + : str.charAt(next++); } - private void write(StringBuilder sb, int ch) { + private void unread() { + if (c >= 0) { + --next; + } + } + + private void writeTo(StringBuilder sb, int ch) { sb.append((char)ch); } private void write(int ch) { - write(sbCleared, ch); - write(sbMask, Character.isWhitespace(ch) ? ch : ' '); + if (ch != -1) { + writeTo(sbCleared, ch); + writeTo(sbMask, Character.isWhitespace(ch) ? ch : ' '); + } } private void writeMask(int ch) { - write(sbMask, ch); - write(sbCleared, Character.isWhitespace(ch) ? ch : ' '); + if (ch != -1) { + writeTo(sbMask, ch); + writeTo(sbCleared, Character.isWhitespace(ch) ? ch : ' '); + } } private void write(CharSequence s) { @@ -122,99 +139,105 @@ } } - private boolean next() { - return next(read()); - } - - private boolean next(int c) { - if (c < 0) { - return false; - } - - if (c == '\'' || c == '"') { - inside = true; - write(c); - int match = c; - c = read(); - while (c != match) { - if (c < 0) { - return false; - } - if (c == '\n' || c == '\r') { - write(c); - return true; - } - if (c == '\\') { - write(c); - c = read(); - } + private void next() { + switch (c) { + case '\'': + case '"': + maskModifiers = false; write(c); - c = read(); - } - write(c); - return true; - } - - if (c == '/') { - c = read(); - if (c == '*') { - writeMask('/'); - writeMask(c); - int prevc = 0; - while ((c = read()) != '/' || prevc != '*') { - if (c < 0) { - openComment = true; - return false; - } - writeMask(c); - prevc = c; - } - writeMask(c); - return true; - } else if (c == '/') { - writeMask('/'); - writeMask(c); - while ((c = read()) != '\n' && c != '\r') { - if (c < 0) { - return false; - } - writeMask(c); - } - writeMask(c); - return true; - } else { - inside = true; - write('/'); - // read character falls through - } - } - - if (Character.isJavaIdentifierStart(c)) { - if (maskModifiers && !inside) { - StringBuilder sb = new StringBuilder(); - do { - write(sb, c); - c = read(); - } while (Character.isJavaIdentifierPart(c)); - String id = sb.toString(); - if (IGNORED_MODIFERS.contains(id)) { - writeMask(sb); - } else { - write(sb); - if (id.equals("import")) { - inside = true; + int match = c; + while (read() >= 0 && c != match && c != '\n' && c != '\r') { + write(c); + if (c == '\\') { + write(read()); } } - return next(c); // recurse to handle left-over character - } - } else if (!Character.isWhitespace(c)) { - inside = true; + write(c); // write match // line-end + break; + case '/': + read(); + switch (c) { + case '*': + writeMask('/'); + writeMask(c); + int prevc = 0; + while (read() >= 0 && (c != '/' || prevc != '*')) { + writeMask(c); + prevc = c; + } + writeMask(c); + openComment = c < 0; + break; + case '/': + writeMask('/'); + writeMask(c); + while (read() >= 0 && c != '\n' && c != '\r') { + writeMask(c); + } + writeMask(c); + break; + default: + maskModifiers = false; + write('/'); + unread(); + break; + } + break; + case '@': + do { + write(c); + read(); + } while (Character.isJavaIdentifierPart(c)); + while (Character.isWhitespace(c)) { + write(c); + read(); + } + // if this is an annotation with arguments, process those recursively + if (c == '(') { + write(c); + boolean prevMaskModifiers = maskModifiers; + int parenCnt = 1; + while (read() >= 0) { + if (c == ')') { + if (--parenCnt == 0) { + break; + } + } else if (c == '(') { + ++parenCnt; + } + next(); // recurse to handle quotes and comments + } + write(c); + // stuff in annotation arguments doesn't effect inside determination + maskModifiers = prevMaskModifiers; + } else { + unread(); + } + break; + default: + if (Character.isJavaIdentifierStart(c)) { + StringBuilder sb = new StringBuilder(); + do { + writeTo(sb, c); + read(); + } while (Character.isJavaIdentifierPart(c)); + unread(); + String id = sb.toString(); + if (maskModifiers && IGNORED_MODIFIERS.contains(id)) { + writeMask(sb); + } else { + write(sb); + if (maskModifiers && !OTHER_MODIFIERS.contains(id)) { + maskModifiers = false; + } + } + } else { + if (!Character.isWhitespace(c)) { + maskModifiers = false; + } + write(c); + } + break; } - - if (c < 0) { - return false; - } - write(c); - return true; } } diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java Fri Nov 11 16:44:36 2016 +0100 @@ -63,12 +63,16 @@ public abstract List completionSuggestions(String input, int cursor, int[] anchor); /** - * Compute a description/help string for the given user's input. + * Compute documentation for the given user's input. Multiple {@code Documentation} objects may + * be returned when multiple elements match the user's input (like for overloaded methods). * @param input the snippet the user wrote so far * @param cursor the current position of the cursors in the given {@code input} text - * @return description/help string for the given user's input + * @param computeJavadoc true if the javadoc for the given input should be computed in + * addition to the signature + * @return the documentations for the given user's input, if multiple elements match the input, + * multiple {@code Documentation} objects are returned. */ - public abstract String documentation(String input, int cursor); + public abstract List documentation(String input, int cursor, boolean computeJavadoc); /** * Infer the type of the given expression. The expression spans from the beginning of {@code code} @@ -266,6 +270,26 @@ } /** + * A documentation for a candidate for continuation of the given user's input. + */ + public interface Documentation { + + /** + * The signature of the given element. + * + * @return the signature + */ + String signature(); + + /** + * The javadoc of the given element. + * + * @return the javadoc, or null if not found or not requested + */ + String javadoc(); + } + + /** * List of possible qualified names. */ public static final class QualifiedNames { diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java Fri Nov 11 16:44:36 2016 +0100 @@ -42,19 +42,17 @@ import com.sun.source.tree.Tree.Kind; import com.sun.source.tree.TypeParameterTree; import com.sun.source.tree.VariableTree; -import com.sun.source.util.JavacTask; import com.sun.source.util.SourcePositions; import com.sun.source.util.TreePath; import com.sun.source.util.TreePathScanner; -import com.sun.source.util.Trees; import com.sun.tools.javac.api.JavacScope; -import com.sun.tools.javac.api.JavacTaskImpl; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol.CompletionFailure; import com.sun.tools.javac.code.Symbol.VarSymbol; import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type.ClassType; +import jdk.internal.shellsupport.doc.JavadocHelper; import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Names; import com.sun.tools.javac.util.Pair; @@ -105,6 +103,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import static java.util.stream.Collectors.collectingAndThen; +import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toCollection; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; @@ -123,15 +122,10 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Types; -import javax.tools.JavaCompiler; import javax.tools.JavaFileManager.Location; -import javax.tools.JavaFileObject; -import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; -import javax.tools.ToolProvider; import static jdk.jshell.Util.REPL_DOESNOTMATTER_CLASS_NAME; -import static java.util.stream.Collectors.joining; import static jdk.jshell.SourceCodeAnalysis.Completeness.DEFINITELY_INCOMPLETE; import static jdk.jshell.TreeDissector.printType; @@ -151,6 +145,7 @@ private final JShell proc; private final CompletenessAnalyzer ca; + private final List closeables = new ArrayList<>(); private final Map currentIndexes = new HashMap<>(); private int indexVersion; private int classpathVersion; @@ -1097,10 +1092,10 @@ } @Override - public String documentation(String code, int cursor) { + public List documentation(String code, int cursor, boolean computeJavadoc) { suspendIndexing(); try { - return documentationImpl(code, cursor); + return documentationImpl(code, cursor, computeJavadoc); } finally { resumeIndexing(); } @@ -1112,14 +1107,14 @@ "-parameters" }; - private String documentationImpl(String code, int cursor) { + private List documentationImpl(String code, int cursor, boolean computeJavadoc) { code = code.substring(0, cursor); if (code.trim().isEmpty()) { //TODO: comment handling code += ";"; } if (guessKind(code) == Kind.IMPORT) - return null; + return Collections.emptyList(); OuterWrap codeWrap = proc.outerMap.wrapInTrialClass(Wrap.methodWrap(code)); AnalyzeTask at = proc.taskFactory.new AnalyzeTask(codeWrap, keepParameterNames); @@ -1128,46 +1123,120 @@ TreePath tp = pathFor(topLevel, sp, codeWrap.snippetIndexToWrapIndex(cursor)); if (tp == null) - return null; + return Collections.emptyList(); TreePath prevPath = null; - while (tp != null && tp.getLeaf().getKind() != Kind.METHOD_INVOCATION && tp.getLeaf().getKind() != Kind.NEW_CLASS) { + while (tp != null && tp.getLeaf().getKind() != Kind.METHOD_INVOCATION && + tp.getLeaf().getKind() != Kind.NEW_CLASS && tp.getLeaf().getKind() != Kind.IDENTIFIER && + tp.getLeaf().getKind() != Kind.MEMBER_SELECT) { prevPath = tp; tp = tp.getParentPath(); } if (tp == null) - return null; + return Collections.emptyList(); + Stream elements; Iterable> candidates; List arguments; - if (tp.getLeaf().getKind() == Kind.METHOD_INVOCATION) { - MethodInvocationTree mit = (MethodInvocationTree) tp.getLeaf(); - candidates = methodCandidates(at, tp); - arguments = mit.getArguments(); + if (tp.getLeaf().getKind() == Kind.METHOD_INVOCATION || tp.getLeaf().getKind() == Kind.NEW_CLASS) { + if (tp.getLeaf().getKind() == Kind.METHOD_INVOCATION) { + MethodInvocationTree mit = (MethodInvocationTree) tp.getLeaf(); + candidates = methodCandidates(at, tp); + arguments = mit.getArguments(); + } else { + NewClassTree nct = (NewClassTree) tp.getLeaf(); + candidates = newClassCandidates(at, tp); + arguments = nct.getArguments(); + } + + if (!isEmptyArgumentsContext(arguments)) { + List actuals = computeActualInvocationTypes(at, arguments, prevPath); + List fullActuals = actuals != null ? actuals : Collections.emptyList(); + + candidates = + this.filterExecutableTypesByArguments(at, candidates, fullActuals) + .stream() + .filter(method -> parameterType(method.fst, method.snd, fullActuals.size(), true).findAny().isPresent()) + .collect(Collectors.toList()); + } + + elements = Util.stream(candidates).map(method -> method.fst); + } else if (tp.getLeaf().getKind() == Kind.IDENTIFIER || tp.getLeaf().getKind() == Kind.MEMBER_SELECT) { + Element el = at.trees().getElement(tp); + + if (el == null || + el.asType().getKind() == TypeKind.ERROR || + (el.getKind() == ElementKind.PACKAGE && el.getEnclosedElements().isEmpty())) { + //erroneous element: + return Collections.emptyList(); + } + + elements = Stream.of(el); } else { - NewClassTree nct = (NewClassTree) tp.getLeaf(); - candidates = newClassCandidates(at, tp); - arguments = nct.getArguments(); + return Collections.emptyList(); + } + + List result = Collections.emptyList(); + + try (JavadocHelper helper = JavadocHelper.create(at.task, findSources())) { + result = elements.map(el -> constructDocumentation(at, helper, el, computeJavadoc)) + .filter(r -> r != null) + .collect(Collectors.toList()); + } catch (IOException ex) { + proc.debug(ex, "JavadocHelper.close()"); } - if (!isEmptyArgumentsContext(arguments)) { - List actuals = computeActualInvocationTypes(at, arguments, prevPath); - List fullActuals = actuals != null ? actuals : Collections.emptyList(); + return result; + } + + private Documentation constructDocumentation(AnalyzeTask at, JavadocHelper helper, Element el, boolean computeJavadoc) { + String javadoc = null; + try { + if (hasSyntheticParameterNames(el)) { + el = helper.getSourceElement(el); + } + if (computeJavadoc) { + javadoc = helper.getResolvedDocComment(el); + } + } catch (IOException ex) { + proc.debug(ex, "SourceCodeAnalysisImpl.element2String(..., " + el + ")"); + } + String signature = Util.expunge(elementHeader(at, el, !hasSyntheticParameterNames(el), true)); + return new DocumentationImpl(signature, javadoc); + } - candidates = - this.filterExecutableTypesByArguments(at, candidates, fullActuals) - .stream() - .filter(method -> parameterType(method.fst, method.snd, fullActuals.size(), true).findAny().isPresent()) - .collect(Collectors.toList()); + public void close() { + for (AutoCloseable closeable : closeables) { + try { + closeable.close(); + } catch (Exception ex) { + proc.debug(ex, "SourceCodeAnalysisImpl.close()"); + } + } + } + + private static final class DocumentationImpl implements Documentation { + + private final String signature; + private final String javadoc; + + public DocumentationImpl(String signature, String javadoc) { + this.signature = signature; + this.javadoc = javadoc; } - try (SourceCache sourceCache = new SourceCache(at)) { - return Util.stream(candidates) - .map(method -> Util.expunge(element2String(sourceCache, method.fst))) - .collect(joining("\n")); + @Override + public String signature() { + return signature; } + + @Override + public String javadoc() { + return javadoc; + } + } private boolean isEmptyArgumentsContext(List arguments) { @@ -1178,18 +1247,6 @@ return false; } - private String element2String(SourceCache sourceCache, Element el) { - try { - if (hasSyntheticParameterNames(el)) { - el = sourceCache.getSourceMethod(el); - } - } catch (IOException ex) { - proc.debug(ex, "SourceCodeAnalysisImpl.element2String(..., " + el + ")"); - } - - return Util.expunge(elementHeader(sourceCache.originalTask, el, !hasSyntheticParameterNames(el))); - } - private boolean hasSyntheticParameterNames(Element el) { if (el.getKind() != ElementKind.CONSTRUCTOR && el.getKind() != ElementKind.METHOD) return false; @@ -1204,119 +1261,6 @@ .allMatch(param -> param.getSimpleName().toString().startsWith("arg")); } - private final class SourceCache implements AutoCloseable { - private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - private final Map> topLevelName2Signature2Method = new HashMap<>(); - private final AnalyzeTask originalTask; - private final StandardJavaFileManager fm; - - public SourceCache(AnalyzeTask originalTask) { - this.originalTask = originalTask; - List sources = findSources(); - if (sources.iterator().hasNext()) { - StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null); - try { - fm.setLocationFromPaths(StandardLocation.SOURCE_PATH, sources); - } catch (IOException ex) { - proc.debug(ex, "SourceCodeAnalysisImpl.SourceCache.(...)"); - try { - fm.close(); - } catch (IOException closeEx) { - proc.debug(closeEx, "SourceCodeAnalysisImpl.SourceCache.close()"); - } - fm = null; - } - this.fm = fm; - } else { - //don't waste time if there are no sources - this.fm = null; - } - } - - public Element getSourceMethod(Element method) throws IOException { - if (fm == null) - return method; - - TypeElement type = topLevelType(method); - - if (type == null) - return method; - - String binaryName = originalTask.task.getElements().getBinaryName(type).toString(); - - Map cache = topLevelName2Signature2Method.get(binaryName); - - if (cache == null) { - topLevelName2Signature2Method.put(binaryName, cache = createMethodCache(binaryName)); - } - - String handle = elementHeader(originalTask, method, false); - - return cache.getOrDefault(handle, method); - } - - private TypeElement topLevelType(Element el) { - while (el != null && el.getEnclosingElement().getKind() != ElementKind.PACKAGE) { - el = el.getEnclosingElement(); - } - - return el != null && (el.getKind().isClass() || el.getKind().isInterface()) ? (TypeElement) el : null; - } - - private Map createMethodCache(String binaryName) throws IOException { - Pair source = findSource(binaryName); - - if (source == null) - return Collections.emptyMap(); - - Map signature2Method = new HashMap<>(); - Trees trees = Trees.instance(source.fst); - - new TreePathScanner() { - @Override - public Void visitMethod(MethodTree node, Void p) { - Element currentMethod = trees.getElement(getCurrentPath()); - - if (currentMethod != null) { - signature2Method.put(elementHeader(originalTask, currentMethod, false), currentMethod); - } - - return null; - } - }.scan(source.snd, null); - - return signature2Method; - } - - private Pair findSource(String binaryName) throws IOException { - JavaFileObject jfo = fm.getJavaFileForInput(StandardLocation.SOURCE_PATH, - binaryName, - JavaFileObject.Kind.SOURCE); - - if (jfo == null) - return null; - - List jfos = Arrays.asList(jfo); - JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, fm, d -> {}, null, null, jfos); - Iterable cuts = task.parse(); - - task.enter(); - - return Pair.of(task, cuts.iterator().next()); - } - - @Override - public void close() { - try { - if (fm != null) { - fm.close(); - } - } catch (IOException ex) { - proc.debug(ex, "SourceCodeAnalysisImpl.SourceCache.close()"); - } - } - } - private List availableSources; private List findSources() { @@ -1328,25 +1272,59 @@ Path srcZip = home.resolve("src.zip"); if (!Files.isReadable(srcZip)) srcZip = home.getParent().resolve("src.zip"); - if (Files.isReadable(srcZip)) - result.add(srcZip); + if (Files.isReadable(srcZip)) { + boolean keepOpen = false; + FileSystem zipFO = null; + + try { + URI uri = URI.create("jar:" + srcZip.toUri()); + zipFO = FileSystems.newFileSystem(uri, Collections.emptyMap()); + Path root = zipFO.getRootDirectories().iterator().next(); + + if (Files.exists(root.resolve("java/lang/Object.java".replace("/", zipFO.getSeparator())))) { + //non-modular format: + result.add(srcZip); + } else if (Files.exists(root.resolve("java.base/java/lang/Object.java".replace("/", zipFO.getSeparator())))) { + //modular format: + try (DirectoryStream ds = Files.newDirectoryStream(root)) { + for (Path p : ds) { + if (Files.isDirectory(p)) { + result.add(p); + } + } + } + + keepOpen = true; + } + } catch (IOException ex) { + proc.debug(ex, "SourceCodeAnalysisImpl.findSources()"); + } finally { + if (zipFO != null) { + if (keepOpen) { + closeables.add(zipFO); + } else { + try { + zipFO.close(); + } catch (IOException ex) { + proc.debug(ex, "SourceCodeAnalysisImpl.findSources()"); + } + } + } + } + } return availableSources = result; } - private String elementHeader(AnalyzeTask at, Element el) { - return elementHeader(at, el, true); - } - - private String elementHeader(AnalyzeTask at, Element el, boolean includeParameterNames) { + private String elementHeader(AnalyzeTask at, Element el, boolean includeParameterNames, boolean useFQN) { switch (el.getKind()) { case ANNOTATION_TYPE: case CLASS: case ENUM: case INTERFACE: { TypeElement type = (TypeElement)el; String fullname = type.getQualifiedName().toString(); Element pkg = at.getElements().getPackageOf(el); - String name = pkg == null ? fullname : + String name = pkg == null || useFQN ? fullname : proc.maps.fullClassNameAndPackageToClass(fullname, ((PackageElement)pkg).getQualifiedName().toString()); - return name + typeParametersOpt(at, type.getTypeParameters()); + return name + typeParametersOpt(at, type.getTypeParameters(), includeParameterNames); } case TYPE_PARAMETER: { TypeParameterElement tp = (TypeParameterElement)el; @@ -1363,9 +1341,9 @@ .collect(joining(" & ")); } case FIELD: - return elementHeader(at, el.getEnclosingElement()) + "." + el.getSimpleName() + ":" + el.asType(); + return elementHeader(at, el.getEnclosingElement(), includeParameterNames, false) + "." + el.getSimpleName() + ":" + el.asType(); case ENUM_CONSTANT: - return elementHeader(at, el.getEnclosingElement()) + "." + el.getSimpleName(); + return elementHeader(at, el.getEnclosingElement(), includeParameterNames, false) + "." + el.getSimpleName(); case EXCEPTION_PARAMETER: case LOCAL_VARIABLE: case PARAMETER: case RESOURCE_VARIABLE: return el.getSimpleName() + ":" + el.asType(); case CONSTRUCTOR: case METHOD: { @@ -1379,20 +1357,20 @@ header.append(printType(at, proc, method.getReturnType())).append(" "); } else { // type parameters for the constructor - String typeParameters = typeParametersOpt(at, method.getTypeParameters()); + String typeParameters = typeParametersOpt(at, method.getTypeParameters(), includeParameterNames); if (!typeParameters.isEmpty()) { header.append(typeParameters).append(" "); } } // receiver type - String clazz = elementHeader(at, el.getEnclosingElement()); + String clazz = elementHeader(at, el.getEnclosingElement(), includeParameterNames, false); header.append(clazz); if (isMethod) { //method name with type parameters (clazz.isEmpty() ? header : header.append(".")) - .append(typeParametersOpt(at, method.getTypeParameters())) + .append(typeParametersOpt(at, method.getTypeParameters(), includeParameterNames)) .append(el.getSimpleName()); } @@ -1435,10 +1413,10 @@ } return arrayType; } - private String typeParametersOpt(AnalyzeTask at, List typeParameters) { + private String typeParametersOpt(AnalyzeTask at, List typeParameters, boolean includeParameterNames) { return typeParameters.isEmpty() ? "" : typeParameters.stream() - .map(tp -> elementHeader(at, tp)) + .map(tp -> elementHeader(at, tp, includeParameterNames, false)) .collect(joining(", ", "<", ">")); } diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIDefaultExecutionControl.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIDefaultExecutionControl.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,282 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jshell.execution; - -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInput; -import java.io.ObjectOutput; -import java.io.OutputStream; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; -import com.sun.jdi.BooleanValue; -import com.sun.jdi.ClassNotLoadedException; -import com.sun.jdi.Field; -import com.sun.jdi.IncompatibleThreadStateException; -import com.sun.jdi.InvalidTypeException; -import com.sun.jdi.ObjectReference; -import com.sun.jdi.StackFrame; -import com.sun.jdi.ThreadReference; -import com.sun.jdi.VMDisconnectedException; -import com.sun.jdi.VirtualMachine; -import jdk.jshell.spi.ExecutionControl; -import jdk.jshell.spi.ExecutionEnv; -import static jdk.jshell.execution.Util.remoteInputOutput; - -/** - * The implementation of {@link jdk.jshell.spi.ExecutionControl} that the - * JShell-core uses by default. - * Launches a remote process -- the "remote agent". - * Interfaces to the remote agent over a socket and via JDI. - * Designed to work with {@link RemoteExecutionControl}. - * - * @author Robert Field - * @author Jan Lahoda - */ -public class JDIDefaultExecutionControl extends JDIExecutionControl { - - private static final String REMOTE_AGENT = RemoteExecutionControl.class.getName(); - - private VirtualMachine vm; - private Process process; - - private final Object STOP_LOCK = new Object(); - private boolean userCodeRunning = false; - - /** - * Creates an ExecutionControl instance based on a JDI - * {@code LaunchingConnector}. - * - * @return the generator - */ - public static ExecutionControl.Generator launch() { - return env -> create(env, true, null); - } - - /** - * Creates an ExecutionControl instance based on a JDI - * {@code ListeningConnector}. - * - * @param host explicit hostname to use, if null use discovered - * hostname, applies to listening only (!isLaunch) - * @return the generator - */ - public static ExecutionControl.Generator listen(String host) { - return env -> create(env, false, host); - } - - /** - * Creates an ExecutionControl instance based on a JDI - * {@code ListeningConnector} or {@code LaunchingConnector}. - * - * Initialize JDI and use it to launch the remote JVM. Set-up a socket for - * commands and results. This socket also transports the user - * input/output/error. - * - * @param env the context passed by - * {@link jdk.jshell.spi.ExecutionControl#start(jdk.jshell.spi.ExecutionEnv) } - * @param isLaunch does JDI do the launch? That is, LaunchingConnector, - * otherwise we start explicitly and use ListeningConnector - * @param host explicit hostname to use, if null use discovered - * hostname, applies to listening only (!isLaunch) - * @return the channel - * @throws IOException if there are errors in set-up - */ - private static ExecutionControl create(ExecutionEnv env, - boolean isLaunch, String host) throws IOException { - try (final ServerSocket listener = new ServerSocket(0)) { - // timeout after 60 seconds - listener.setSoTimeout(60000); - int port = listener.getLocalPort(); - - // Set-up the JDI connection - JDIInitiator jdii = new JDIInitiator(port, - env.extraRemoteVMOptions(), REMOTE_AGENT, isLaunch, host); - VirtualMachine vm = jdii.vm(); - Process process = jdii.process(); - - List> deathListeners = new ArrayList<>(); - deathListeners.add(s -> env.closeDown()); - Util.detectJDIExitEvent(vm, s -> { - for (Consumer h : deathListeners) { - h.accept(s); - } - }); - - // Set-up the commands/reslts on the socket. Piggy-back snippet - // output. - Socket socket = listener.accept(); - // out before in -- match remote creation so we don't hang - OutputStream out = socket.getOutputStream(); - Map outputs = new HashMap<>(); - outputs.put("out", env.userOut()); - outputs.put("err", env.userErr()); - Map input = new HashMap<>(); - input.put("in", env.userIn()); - return remoteInputOutput(socket.getInputStream(), out, outputs, input, (objIn, objOut) -> new JDIDefaultExecutionControl(objOut, objIn, vm, process, deathListeners)); - } - } - - /** - * Create an instance. - * - * @param cmdout the output for commands - * @param cmdin the input for responses - */ - private JDIDefaultExecutionControl(ObjectOutput cmdout, ObjectInput cmdin, - VirtualMachine vm, Process process, List> deathListeners) { - super(cmdout, cmdin); - this.vm = vm; - this.process = process; - deathListeners.add(s -> disposeVM()); - } - - @Override - public String invoke(String classname, String methodname) - throws RunException, - EngineTerminationException, InternalException { - String res; - synchronized (STOP_LOCK) { - userCodeRunning = true; - } - try { - res = super.invoke(classname, methodname); - } finally { - synchronized (STOP_LOCK) { - userCodeRunning = false; - } - } - return res; - } - - /** - * Interrupts a running remote invoke by manipulating remote variables - * and sending a stop via JDI. - * - * @throws EngineTerminationException the execution engine has terminated - * @throws InternalException an internal problem occurred - */ - @Override - public void stop() throws EngineTerminationException, InternalException { - synchronized (STOP_LOCK) { - if (!userCodeRunning) { - return; - } - - vm().suspend(); - try { - OUTER: - for (ThreadReference thread : vm().allThreads()) { - // could also tag the thread (e.g. using name), to find it easier - for (StackFrame frame : thread.frames()) { - if (REMOTE_AGENT.equals(frame.location().declaringType().name()) && - ( "invoke".equals(frame.location().method().name()) - || "varValue".equals(frame.location().method().name()))) { - ObjectReference thiz = frame.thisObject(); - Field inClientCode = thiz.referenceType().fieldByName("inClientCode"); - Field expectingStop = thiz.referenceType().fieldByName("expectingStop"); - Field stopException = thiz.referenceType().fieldByName("stopException"); - if (((BooleanValue) thiz.getValue(inClientCode)).value()) { - thiz.setValue(expectingStop, vm().mirrorOf(true)); - ObjectReference stopInstance = (ObjectReference) thiz.getValue(stopException); - - vm().resume(); - debug("Attempting to stop the client code...\n"); - thread.stop(stopInstance); - thiz.setValue(expectingStop, vm().mirrorOf(false)); - } - - break OUTER; - } - } - } - } catch (ClassNotLoadedException | IncompatibleThreadStateException | InvalidTypeException ex) { - throw new InternalException("Exception on remote stop: " + ex); - } finally { - vm().resume(); - } - } - } - - @Override - public void close() { - super.close(); - disposeVM(); - } - - private synchronized void disposeVM() { - try { - if (vm != null) { - vm.dispose(); // This could NPE, so it is caught below - vm = null; - } - } catch (VMDisconnectedException ex) { - // Ignore if already closed - } catch (Throwable ex) { - debug(ex, "disposeVM"); - } finally { - if (process != null) { - process.destroy(); - process = null; - } - } - } - - @Override - protected synchronized VirtualMachine vm() throws EngineTerminationException { - if (vm == null) { - throw new EngineTerminationException("VM closed"); - } else { - return vm; - } - } - - /** - * Log debugging information. Arguments as for {@code printf}. - * - * @param format a format string as described in Format string syntax - * @param args arguments referenced by the format specifiers in the format - * string. - */ - private static void debug(String format, Object... args) { - // Reserved for future logging - } - - /** - * Log a serious unexpected internal exception. - * - * @param ex the exception - * @param where a description of the context of the exception - */ - private static void debug(Throwable ex, String where) { - // Reserved for future logging - } - -} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIEventHandler.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIEventHandler.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -/* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jshell.execution; - -import java.util.function.Consumer; -import com.sun.jdi.*; -import com.sun.jdi.event.*; - -/** - * Handler of Java Debug Interface events. - * Adapted from jdb EventHandler. - * Only exit and disconnect events processed. - */ -class JDIEventHandler implements Runnable { - - private final Thread thread; - private volatile boolean connected = true; - private boolean completed = false; - private final VirtualMachine vm; - private final Consumer reportVMExit; - - /** - * Creates an event handler. Start with {@code start()}. - * - * @param vm the virtual machine for which to handle events - * @param reportVMExit callback to report exit/disconnect - * (passed true if the VM has died) - */ - JDIEventHandler(VirtualMachine vm, Consumer reportVMExit) { - this.vm = vm; - this.reportVMExit = reportVMExit; - this.thread = new Thread(this, "event-handler"); - this.thread.setDaemon(true); - } - - /** - * Starts the event handler. - */ - void start() { - thread.start(); - } - - synchronized void shutdown() { - connected = false; // force run() loop termination - thread.interrupt(); - while (!completed) { - try {wait();} catch (InterruptedException exc) {} - } - } - - @Override - public void run() { - EventQueue queue = vm.eventQueue(); - while (connected) { - try { - EventSet eventSet = queue.remove(); - boolean resumeStoppedApp = false; - EventIterator it = eventSet.eventIterator(); - while (it.hasNext()) { - resumeStoppedApp |= handleEvent(it.nextEvent()); - } - - if (resumeStoppedApp) { - eventSet.resume(); - } - } catch (InterruptedException exc) { - // Do nothing. Any changes will be seen at top of loop. - } catch (VMDisconnectedException discExc) { - handleDisconnectedException(); - break; - } - } - synchronized (this) { - completed = true; - notifyAll(); - } - } - - private boolean handleEvent(Event event) { - handleExitEvent(event); - return true; - } - - private void handleExitEvent(Event event) { - if (event instanceof VMDeathEvent) { - reportVMExit.accept("VM Died"); - } else if (event instanceof VMDisconnectEvent) { - connected = false; - reportVMExit.accept("VM Disconnected"); - } else { - // ignore everything else - } - } - - private synchronized void handleDisconnectedException() { - /* - * A VMDisconnectedException has happened while dealing with - * another event. We need to flush the event queue, dealing only - * with exit events (VMDeath, VMDisconnect) so that we terminate - * correctly. - */ - EventQueue queue = vm.eventQueue(); - while (connected) { - try { - EventSet eventSet = queue.remove(); - EventIterator iter = eventSet.eventIterator(); - while (iter.hasNext()) { - handleExitEvent(iter.next()); - } - } catch (InterruptedException exc) { - // ignore - } catch (InternalError exc) { - // ignore - } - } - } -} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIExecutionControl.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIExecutionControl.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jshell.execution; - -import java.io.ObjectInput; -import java.io.ObjectOutput; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; -import com.sun.jdi.ReferenceType; -import com.sun.jdi.VirtualMachine; -import jdk.jshell.spi.ExecutionControl; -import static java.util.stream.Collectors.toMap; - -/** - * Abstract JDI implementation of {@link jdk.jshell.spi.ExecutionControl} - */ -public abstract class JDIExecutionControl extends StreamingExecutionControl implements ExecutionControl { - - /** - * Mapping from class names to JDI {@link ReferenceType}. - */ - private final Map toReferenceType = new HashMap<>(); - - /** - * Create an instance. - * @param out the output from the remote agent - * @param in the input to the remote agent - */ - protected JDIExecutionControl(ObjectOutput out, ObjectInput in) { - super(out, in); - } - - /** - * Returns the JDI {@link VirtualMachine} instance. - * - * @return the virtual machine - * @throws EngineTerminationException if the VM is dead/disconnected - */ - protected abstract VirtualMachine vm() throws EngineTerminationException; - - /** - * Redefine the specified classes. Where 'redefine' is, as in JDI and JVMTI, - * an in-place replacement of the classes (preserving class identity) -- - * that is, existing references to the class do not need to be recompiled. - * This implementation uses JDI - * {@link com.sun.jdi.VirtualMachine#redefineClasses(java.util.Map) }. - * It will be unsuccessful if - * the signature of the class has changed (see the JDI spec). The - * JShell-core is designed to adapt to unsuccessful redefine. - */ - @Override - public void redefine(ClassBytecodes[] cbcs) - throws ClassInstallException, EngineTerminationException { - try { - // Convert to the JDI ReferenceType to class bytes map form needed - // by JDI. - VirtualMachine vm = vm(); - Map rmp = Stream.of(cbcs) - .collect(toMap( - cbc -> referenceType(vm, cbc.name()), - cbc -> cbc.bytecodes())); - // Attempt redefine. Throws exceptions on failure. - vm().redefineClasses(rmp); - } catch (EngineTerminationException ex) { - throw ex; - } catch (Exception ex) { - throw new ClassInstallException("redefine: " + ex.getMessage(), new boolean[cbcs.length]); - } - } - - /** - * Returns the JDI {@link ReferenceType} corresponding to the specified - * class name. - * - * @param vm the current JDI {@link VirtualMachine} as returned by - * {@code vm()} - * @param name the class name to look-up - * @return the corresponding {@link ReferenceType} - */ - protected ReferenceType referenceType(VirtualMachine vm, String name) { - return toReferenceType.computeIfAbsent(name, n -> nameToRef(vm, n)); - } - - private static ReferenceType nameToRef(VirtualMachine vm, String name) { - List rtl = vm.classesByName(name); - if (rtl.size() != 1) { - return null; - } - return rtl.get(0); - } - -} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIInitiator.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIInitiator.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jshell.execution; - -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import com.sun.jdi.Bootstrap; -import com.sun.jdi.VirtualMachine; -import com.sun.jdi.connect.Connector; -import com.sun.jdi.connect.LaunchingConnector; -import com.sun.jdi.connect.ListeningConnector; - -/** - * Sets up a JDI connection, providing the resulting JDI {@link VirtualMachine} - * and the {@link Process} the remote agent is running in. - */ -public class JDIInitiator { - - private VirtualMachine vm; - private Process process = null; - private final Connector connector; - private final String remoteAgent; - private final Map connectorArgs; - - /** - * Start the remote agent and establish a JDI connection to it. - * - * @param port the socket port for (non-JDI) commands - * @param remoteVMOptions any user requested VM options - * @param remoteAgent full class name of remote agent to launch - * @param isLaunch does JDI do the launch? That is, LaunchingConnector, - * otherwise we start explicitly and use ListeningConnector - * @param host explicit hostname to use, if null use discovered - * hostname, applies to listening only (!isLaunch) - */ - public JDIInitiator(int port, List remoteVMOptions, String remoteAgent, - boolean isLaunch, String host) { - this.remoteAgent = remoteAgent; - String connectorName - = isLaunch - ? "com.sun.jdi.CommandLineLaunch" - : "com.sun.jdi.SocketListen"; - this.connector = findConnector(connectorName); - if (connector == null) { - throw new IllegalArgumentException("No connector named: " + connectorName); - } - Map argumentName2Value - = isLaunch - ? launchArgs(port, String.join(" ", remoteVMOptions)) - : new HashMap<>(); - if (host != null && !isLaunch) { - argumentName2Value.put("localAddress", host); - } - this.connectorArgs = mergeConnectorArgs(connector, argumentName2Value); - this.vm = isLaunch - ? launchTarget() - : listenTarget(port, remoteVMOptions); - - } - - /** - * Returns the resulting {@code VirtualMachine} instance. - * - * @return the virtual machine - */ - public VirtualMachine vm() { - return vm; - } - - /** - * Returns the launched process. - * - * @return the remote agent process - */ - public Process process() { - return process; - } - - /* launch child target vm */ - private VirtualMachine launchTarget() { - LaunchingConnector launcher = (LaunchingConnector) connector; - try { - VirtualMachine new_vm = launcher.launch(connectorArgs); - process = new_vm.process(); - return new_vm; - } catch (Exception ex) { - reportLaunchFail(ex, "launch"); - } - return null; - } - - /** - * Directly launch the remote agent and connect JDI to it with a - * ListeningConnector. - */ - private VirtualMachine listenTarget(int port, List remoteVMOptions) { - ListeningConnector listener = (ListeningConnector) connector; - try { - // Start listening, get the JDI connection address - String addr = listener.startListening(connectorArgs); - debug("Listening at address: " + addr); - - // Launch the RemoteAgent requesting a connection on that address - String javaHome = System.getProperty("java.home"); - List args = new ArrayList<>(); - args.add(javaHome == null - ? "java" - : javaHome + File.separator + "bin" + File.separator + "java"); - args.add("-agentlib:jdwp=transport=" + connector.transport().name() + - ",address=" + addr); - args.addAll(remoteVMOptions); - args.add(remoteAgent); - args.add("" + port); - ProcessBuilder pb = new ProcessBuilder(args); - process = pb.start(); - - // Forward out, err, and in - // Accept the connection from the remote agent - vm = listener.accept(connectorArgs); - listener.stopListening(connectorArgs); - return vm; - } catch (Exception ex) { - reportLaunchFail(ex, "listen"); - } - return null; - } - - private Connector findConnector(String name) { - for (Connector cntor - : Bootstrap.virtualMachineManager().allConnectors()) { - if (cntor.name().equals(name)) { - return cntor; - } - } - return null; - } - - private Map mergeConnectorArgs(Connector connector, Map argumentName2Value) { - Map arguments = connector.defaultArguments(); - - for (Entry argumentEntry : argumentName2Value.entrySet()) { - String name = argumentEntry.getKey(); - String value = argumentEntry.getValue(); - Connector.Argument argument = arguments.get(name); - - if (argument == null) { - throw new IllegalArgumentException("Argument is not defined for connector:" + - name + " -- " + connector.name()); - } - - argument.setValue(value); - } - - return arguments; - } - - /** - * The JShell specific Connector args for the LaunchingConnector. - * - * @param portthe socket port for (non-JDI) commands - * @param remoteVMOptions any user requested VM options - * @return the argument map - */ - private Map launchArgs(int port, String remoteVMOptions) { - Map argumentName2Value = new HashMap<>(); - argumentName2Value.put("main", remoteAgent + " " + port); - argumentName2Value.put("options", remoteVMOptions); - return argumentName2Value; - } - - private void reportLaunchFail(Exception ex, String context) { - throw new InternalError("Failed remote " + context + ": " + connector + - " -- " + connectorArgs, ex); - } - - /** - * Log debugging information. Arguments as for {@code printf}. - * - * @param format a format string as described in Format string syntax - * @param args arguments referenced by the format specifiers in the format - * string. - */ - private void debug(String format, Object... args) { - // Reserved for future logging - } - - /** - * Log a serious unexpected internal exception. - * - * @param ex the exception - * @param where a description of the context of the exception - */ - private void debug(Throwable ex, String where) { - // Reserved for future logging - } - -} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jshell.execution; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import com.sun.jdi.BooleanValue; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.Field; +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.StackFrame; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.VirtualMachine; +import jdk.jshell.spi.ExecutionControl; +import jdk.jshell.spi.ExecutionEnv; +import static jdk.jshell.execution.Util.remoteInputOutput; + +/** + * The implementation of {@link jdk.jshell.spi.ExecutionControl} that the + * JShell-core uses by default. + * Launches a remote process -- the "remote agent". + * Interfaces to the remote agent over a socket and via JDI. + * Designed to work with {@link RemoteExecutionControl}. + * + * @author Robert Field + * @author Jan Lahoda + */ +public class JdiDefaultExecutionControl extends JdiExecutionControl { + + private static final String REMOTE_AGENT = RemoteExecutionControl.class.getName(); + + private VirtualMachine vm; + private Process process; + + private final Object STOP_LOCK = new Object(); + private boolean userCodeRunning = false; + + /** + * Creates an ExecutionControl instance based on a JDI + * {@code LaunchingConnector}. + * + * @return the generator + */ + public static ExecutionControl.Generator launch() { + return env -> create(env, true, null); + } + + /** + * Creates an ExecutionControl instance based on a JDI + * {@code ListeningConnector}. + * + * @param host explicit hostname to use, if null use discovered + * hostname, applies to listening only (!isLaunch) + * @return the generator + */ + public static ExecutionControl.Generator listen(String host) { + return env -> create(env, false, host); + } + + /** + * Creates an ExecutionControl instance based on a JDI + * {@code ListeningConnector} or {@code LaunchingConnector}. + * + * Initialize JDI and use it to launch the remote JVM. Set-up a socket for + * commands and results. This socket also transports the user + * input/output/error. + * + * @param env the context passed by + * {@link jdk.jshell.spi.ExecutionControl#start(jdk.jshell.spi.ExecutionEnv) } + * @param isLaunch does JDI do the launch? That is, LaunchingConnector, + * otherwise we start explicitly and use ListeningConnector + * @param host explicit hostname to use, if null use discovered + * hostname, applies to listening only (!isLaunch) + * @return the channel + * @throws IOException if there are errors in set-up + */ + private static ExecutionControl create(ExecutionEnv env, + boolean isLaunch, String host) throws IOException { + try (final ServerSocket listener = new ServerSocket(0)) { + // timeout after 60 seconds + listener.setSoTimeout(60000); + int port = listener.getLocalPort(); + + // Set-up the JDI connection + JdiInitiator jdii = new JdiInitiator(port, + env.extraRemoteVMOptions(), REMOTE_AGENT, isLaunch, host); + VirtualMachine vm = jdii.vm(); + Process process = jdii.process(); + + List> deathListeners = new ArrayList<>(); + deathListeners.add(s -> env.closeDown()); + Util.detectJdiExitEvent(vm, s -> { + for (Consumer h : deathListeners) { + h.accept(s); + } + }); + + // Set-up the commands/reslts on the socket. Piggy-back snippet + // output. + Socket socket = listener.accept(); + // out before in -- match remote creation so we don't hang + OutputStream out = socket.getOutputStream(); + Map outputs = new HashMap<>(); + outputs.put("out", env.userOut()); + outputs.put("err", env.userErr()); + Map input = new HashMap<>(); + input.put("in", env.userIn()); + return remoteInputOutput(socket.getInputStream(), out, outputs, input, (objIn, objOut) -> new JdiDefaultExecutionControl(objOut, objIn, vm, process, deathListeners)); + } + } + + /** + * Create an instance. + * + * @param cmdout the output for commands + * @param cmdin the input for responses + */ + private JdiDefaultExecutionControl(ObjectOutput cmdout, ObjectInput cmdin, + VirtualMachine vm, Process process, List> deathListeners) { + super(cmdout, cmdin); + this.vm = vm; + this.process = process; + deathListeners.add(s -> disposeVM()); + } + + @Override + public String invoke(String classname, String methodname) + throws RunException, + EngineTerminationException, InternalException { + String res; + synchronized (STOP_LOCK) { + userCodeRunning = true; + } + try { + res = super.invoke(classname, methodname); + } finally { + synchronized (STOP_LOCK) { + userCodeRunning = false; + } + } + return res; + } + + /** + * Interrupts a running remote invoke by manipulating remote variables + * and sending a stop via JDI. + * + * @throws EngineTerminationException the execution engine has terminated + * @throws InternalException an internal problem occurred + */ + @Override + public void stop() throws EngineTerminationException, InternalException { + synchronized (STOP_LOCK) { + if (!userCodeRunning) { + return; + } + + vm().suspend(); + try { + OUTER: + for (ThreadReference thread : vm().allThreads()) { + // could also tag the thread (e.g. using name), to find it easier + for (StackFrame frame : thread.frames()) { + if (REMOTE_AGENT.equals(frame.location().declaringType().name()) && + ( "invoke".equals(frame.location().method().name()) + || "varValue".equals(frame.location().method().name()))) { + ObjectReference thiz = frame.thisObject(); + Field inClientCode = thiz.referenceType().fieldByName("inClientCode"); + Field expectingStop = thiz.referenceType().fieldByName("expectingStop"); + Field stopException = thiz.referenceType().fieldByName("stopException"); + if (((BooleanValue) thiz.getValue(inClientCode)).value()) { + thiz.setValue(expectingStop, vm().mirrorOf(true)); + ObjectReference stopInstance = (ObjectReference) thiz.getValue(stopException); + + vm().resume(); + debug("Attempting to stop the client code...\n"); + thread.stop(stopInstance); + thiz.setValue(expectingStop, vm().mirrorOf(false)); + } + + break OUTER; + } + } + } + } catch (ClassNotLoadedException | IncompatibleThreadStateException | InvalidTypeException ex) { + throw new InternalException("Exception on remote stop: " + ex); + } finally { + vm().resume(); + } + } + } + + @Override + public void close() { + super.close(); + disposeVM(); + } + + private synchronized void disposeVM() { + try { + if (vm != null) { + vm.dispose(); // This could NPE, so it is caught below + vm = null; + } + } catch (VMDisconnectedException ex) { + // Ignore if already closed + } catch (Throwable ex) { + debug(ex, "disposeVM"); + } finally { + if (process != null) { + process.destroy(); + process = null; + } + } + } + + @Override + protected synchronized VirtualMachine vm() throws EngineTerminationException { + if (vm == null) { + throw new EngineTerminationException("VM closed"); + } else { + return vm; + } + } + + /** + * Log debugging information. Arguments as for {@code printf}. + * + * @param format a format string as described in Format string syntax + * @param args arguments referenced by the format specifiers in the format + * string. + */ + private static void debug(String format, Object... args) { + // Reserved for future logging + } + + /** + * Log a serious unexpected internal exception. + * + * @param ex the exception + * @param where a description of the context of the exception + */ + private static void debug(Throwable ex, String where) { + // Reserved for future logging + } + +} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiEventHandler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiEventHandler.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 1998, 2014, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jshell.execution; + +import java.util.function.Consumer; +import com.sun.jdi.*; +import com.sun.jdi.event.*; + +/** + * Handler of Java Debug Interface events. + * Adapted from jdb EventHandler. + * Only exit and disconnect events processed. + */ +class JdiEventHandler implements Runnable { + + private final Thread thread; + private volatile boolean connected = true; + private boolean completed = false; + private final VirtualMachine vm; + private final Consumer reportVMExit; + + /** + * Creates an event handler. Start with {@code start()}. + * + * @param vm the virtual machine for which to handle events + * @param reportVMExit callback to report exit/disconnect + * (passed true if the VM has died) + */ + JdiEventHandler(VirtualMachine vm, Consumer reportVMExit) { + this.vm = vm; + this.reportVMExit = reportVMExit; + this.thread = new Thread(this, "event-handler"); + this.thread.setDaemon(true); + } + + /** + * Starts the event handler. + */ + void start() { + thread.start(); + } + + synchronized void shutdown() { + connected = false; // force run() loop termination + thread.interrupt(); + while (!completed) { + try {wait();} catch (InterruptedException exc) {} + } + } + + @Override + public void run() { + EventQueue queue = vm.eventQueue(); + while (connected) { + try { + EventSet eventSet = queue.remove(); + boolean resumeStoppedApp = false; + EventIterator it = eventSet.eventIterator(); + while (it.hasNext()) { + resumeStoppedApp |= handleEvent(it.nextEvent()); + } + + if (resumeStoppedApp) { + eventSet.resume(); + } + } catch (InterruptedException exc) { + // Do nothing. Any changes will be seen at top of loop. + } catch (VMDisconnectedException discExc) { + handleDisconnectedException(); + break; + } + } + synchronized (this) { + completed = true; + notifyAll(); + } + } + + private boolean handleEvent(Event event) { + handleExitEvent(event); + return true; + } + + private void handleExitEvent(Event event) { + if (event instanceof VMDeathEvent) { + reportVMExit.accept("VM Died"); + } else if (event instanceof VMDisconnectEvent) { + connected = false; + reportVMExit.accept("VM Disconnected"); + } else { + // ignore everything else + } + } + + private synchronized void handleDisconnectedException() { + /* + * A VMDisconnectedException has happened while dealing with + * another event. We need to flush the event queue, dealing only + * with exit events (VMDeath, VMDisconnect) so that we terminate + * correctly. + */ + EventQueue queue = vm.eventQueue(); + while (connected) { + try { + EventSet eventSet = queue.remove(); + EventIterator iter = eventSet.eventIterator(); + while (iter.hasNext()) { + handleExitEvent(iter.next()); + } + } catch (InterruptedException exc) { + // ignore + } catch (InternalError exc) { + // ignore + } + } + } +} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiExecutionControl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiExecutionControl.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jshell.execution; + +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.VirtualMachine; +import jdk.jshell.spi.ExecutionControl; +import static java.util.stream.Collectors.toMap; + +/** + * Abstract JDI implementation of {@link jdk.jshell.spi.ExecutionControl} + */ +public abstract class JdiExecutionControl extends StreamingExecutionControl implements ExecutionControl { + + /** + * Mapping from class names to JDI {@link ReferenceType}. + */ + private final Map toReferenceType = new HashMap<>(); + + /** + * Create an instance. + * @param out the output from the remote agent + * @param in the input to the remote agent + */ + protected JdiExecutionControl(ObjectOutput out, ObjectInput in) { + super(out, in); + } + + /** + * Returns the JDI {@link VirtualMachine} instance. + * + * @return the virtual machine + * @throws EngineTerminationException if the VM is dead/disconnected + */ + protected abstract VirtualMachine vm() throws EngineTerminationException; + + /** + * Redefine the specified classes. Where 'redefine' is, as in JDI and JVMTI, + * an in-place replacement of the classes (preserving class identity) -- + * that is, existing references to the class do not need to be recompiled. + * This implementation uses JDI + * {@link com.sun.jdi.VirtualMachine#redefineClasses(java.util.Map) }. + * It will be unsuccessful if + * the signature of the class has changed (see the JDI spec). The + * JShell-core is designed to adapt to unsuccessful redefine. + */ + @Override + public void redefine(ClassBytecodes[] cbcs) + throws ClassInstallException, EngineTerminationException { + try { + // Convert to the JDI ReferenceType to class bytes map form needed + // by JDI. + VirtualMachine vm = vm(); + Map rmp = Stream.of(cbcs) + .collect(toMap( + cbc -> referenceType(vm, cbc.name()), + cbc -> cbc.bytecodes())); + // Attempt redefine. Throws exceptions on failure. + vm().redefineClasses(rmp); + } catch (EngineTerminationException ex) { + throw ex; + } catch (Exception ex) { + throw new ClassInstallException("redefine: " + ex.getMessage(), new boolean[cbcs.length]); + } + } + + /** + * Returns the JDI {@link ReferenceType} corresponding to the specified + * class name. + * + * @param vm the current JDI {@link VirtualMachine} as returned by + * {@code vm()} + * @param name the class name to look-up + * @return the corresponding {@link ReferenceType} + */ + protected ReferenceType referenceType(VirtualMachine vm, String name) { + return toReferenceType.computeIfAbsent(name, n -> nameToRef(vm, n)); + } + + private static ReferenceType nameToRef(VirtualMachine vm, String name) { + List rtl = vm.classesByName(name); + if (rtl.size() != 1) { + return null; + } + return rtl.get(0); + } + +} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jshell.execution; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import com.sun.jdi.Bootstrap; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.LaunchingConnector; +import com.sun.jdi.connect.ListeningConnector; + +/** + * Sets up a JDI connection, providing the resulting JDI {@link VirtualMachine} + * and the {@link Process} the remote agent is running in. + */ +public class JdiInitiator { + + private VirtualMachine vm; + private Process process = null; + private final Connector connector; + private final String remoteAgent; + private final Map connectorArgs; + + /** + * Start the remote agent and establish a JDI connection to it. + * + * @param port the socket port for (non-JDI) commands + * @param remoteVMOptions any user requested VM options + * @param remoteAgent full class name of remote agent to launch + * @param isLaunch does JDI do the launch? That is, LaunchingConnector, + * otherwise we start explicitly and use ListeningConnector + * @param host explicit hostname to use, if null use discovered + * hostname, applies to listening only (!isLaunch) + */ + public JdiInitiator(int port, List remoteVMOptions, String remoteAgent, + boolean isLaunch, String host) { + this.remoteAgent = remoteAgent; + String connectorName + = isLaunch + ? "com.sun.jdi.CommandLineLaunch" + : "com.sun.jdi.SocketListen"; + this.connector = findConnector(connectorName); + if (connector == null) { + throw new IllegalArgumentException("No connector named: " + connectorName); + } + Map argumentName2Value + = isLaunch + ? launchArgs(port, String.join(" ", remoteVMOptions)) + : new HashMap<>(); + if (host != null && !isLaunch) { + argumentName2Value.put("localAddress", host); + } + this.connectorArgs = mergeConnectorArgs(connector, argumentName2Value); + this.vm = isLaunch + ? launchTarget() + : listenTarget(port, remoteVMOptions); + + } + + /** + * Returns the resulting {@code VirtualMachine} instance. + * + * @return the virtual machine + */ + public VirtualMachine vm() { + return vm; + } + + /** + * Returns the launched process. + * + * @return the remote agent process + */ + public Process process() { + return process; + } + + /* launch child target vm */ + private VirtualMachine launchTarget() { + LaunchingConnector launcher = (LaunchingConnector) connector; + try { + VirtualMachine new_vm = launcher.launch(connectorArgs); + process = new_vm.process(); + return new_vm; + } catch (Exception ex) { + reportLaunchFail(ex, "launch"); + } + return null; + } + + /** + * Directly launch the remote agent and connect JDI to it with a + * ListeningConnector. + */ + private VirtualMachine listenTarget(int port, List remoteVMOptions) { + ListeningConnector listener = (ListeningConnector) connector; + try { + // Start listening, get the JDI connection address + String addr = listener.startListening(connectorArgs); + debug("Listening at address: " + addr); + + // Launch the RemoteAgent requesting a connection on that address + String javaHome = System.getProperty("java.home"); + List args = new ArrayList<>(); + args.add(javaHome == null + ? "java" + : javaHome + File.separator + "bin" + File.separator + "java"); + args.add("-agentlib:jdwp=transport=" + connector.transport().name() + + ",address=" + addr); + args.addAll(remoteVMOptions); + args.add(remoteAgent); + args.add("" + port); + ProcessBuilder pb = new ProcessBuilder(args); + process = pb.start(); + + // Forward out, err, and in + // Accept the connection from the remote agent + vm = listener.accept(connectorArgs); + listener.stopListening(connectorArgs); + return vm; + } catch (Exception ex) { + reportLaunchFail(ex, "listen"); + } + return null; + } + + private Connector findConnector(String name) { + for (Connector cntor + : Bootstrap.virtualMachineManager().allConnectors()) { + if (cntor.name().equals(name)) { + return cntor; + } + } + return null; + } + + private Map mergeConnectorArgs(Connector connector, Map argumentName2Value) { + Map arguments = connector.defaultArguments(); + + for (Entry argumentEntry : argumentName2Value.entrySet()) { + String name = argumentEntry.getKey(); + String value = argumentEntry.getValue(); + Connector.Argument argument = arguments.get(name); + + if (argument == null) { + throw new IllegalArgumentException("Argument is not defined for connector:" + + name + " -- " + connector.name()); + } + + argument.setValue(value); + } + + return arguments; + } + + /** + * The JShell specific Connector args for the LaunchingConnector. + * + * @param portthe socket port for (non-JDI) commands + * @param remoteVMOptions any user requested VM options + * @return the argument map + */ + private Map launchArgs(int port, String remoteVMOptions) { + Map argumentName2Value = new HashMap<>(); + argumentName2Value.put("main", remoteAgent + " " + port); + argumentName2Value.put("options", remoteVMOptions); + return argumentName2Value; + } + + private void reportLaunchFail(Exception ex, String context) { + throw new InternalError("Failed remote " + context + ": " + connector + + " -- " + connectorArgs, ex); + } + + /** + * Log debugging information. Arguments as for {@code printf}. + * + * @param format a format string as described in Format string syntax + * @param args arguments referenced by the format specifiers in the format + * string. + */ + private void debug(String format, Object... args) { + // Reserved for future logging + } + + /** + * Log a serious unexpected internal exception. + * + * @param ex the exception + * @param where a description of the context of the exception + */ + private void debug(Throwable ex, String where) { + // Reserved for future logging + } + +} diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java Fri Nov 11 16:44:36 2016 +0100 @@ -41,7 +41,7 @@ * process). This agent loads code over a socket from the main JShell process, * executes the code, and other misc, Specialization of * {@link DirectExecutionControl} which adds stop support controlled by - * an external process. Designed to work with {@link JDIDefaultExecutionControl}. + * an external process. Designed to work with {@link JdiDefaultExecutionControl}. * * @author Jan Lahoda * @author Robert Field diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/Util.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/Util.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/Util.java Fri Nov 11 16:44:36 2016 +0100 @@ -239,9 +239,9 @@ * @param unbiddenExitHandler the handler, which will accept the exit * information */ - public static void detectJDIExitEvent(VirtualMachine vm, Consumer unbiddenExitHandler) { + public static void detectJdiExitEvent(VirtualMachine vm, Consumer unbiddenExitHandler) { if (vm.canBeModified()) { - new JDIEventHandler(vm, unbiddenExitHandler).start(); + new JdiEventHandler(vm, unbiddenExitHandler).start(); } } diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java Fri Nov 11 16:44:36 2016 +0100 @@ -44,12 +44,13 @@ * To install an {@code ExecutionControl}, its {@code Generator} is passed to * {@link jdk.jshell.JShell.Builder#executionEngine(ExecutionControl.Generator) }. */ -public interface ExecutionControl { +public interface ExecutionControl extends AutoCloseable { /** * Defines a functional interface for creating {@link ExecutionControl} * instances. */ + @FunctionalInterface public interface Generator { /** diff -r f71b844f33d1 -r 95af45781076 langtools/src/jdk.jshell/share/classes/module-info.java --- a/langtools/src/jdk.jshell/share/classes/module-info.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/src/jdk.jshell/share/classes/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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 @@ -30,14 +30,16 @@ */ module jdk.jshell { requires public java.compiler; - requires java.desktop; requires java.prefs; requires jdk.compiler; requires jdk.internal.le; + requires jdk.internal.ed; requires jdk.internal.opt; requires jdk.jdi; exports jdk.jshell; exports jdk.jshell.spi; exports jdk.jshell.execution; + + uses jdk.internal.editor.spi.BuildInEditorProvider; } diff -r f71b844f33d1 -r 95af45781076 langtools/test/Makefile --- a/langtools/test/Makefile Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/Makefile Fri Nov 11 16:44:36 2016 +0100 @@ -253,7 +253,7 @@ # Is the test JVM 32-bit? DATA_MODEL := \ - $(shell $(JT_JAVA)/bin/java -XshowSettings:properties -version 2>&1 | \ + $(shell $(TESTJAVA)/bin/java -XshowSettings:properties -version 2>&1 | \ grep 'sun\.arch\.data\.model' | \ awk '{print $$3}') ifeq ($(DATA_MODEL), 32) diff -r f71b844f33d1 -r 95af45781076 langtools/test/ProblemList.txt --- a/langtools/test/ProblemList.txt Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/ProblemList.txt Fri Nov 11 16:44:36 2016 +0100 @@ -55,6 +55,7 @@ tools/javac/annotations/typeAnnotations/referenceinfos/NestedTypes.java 8057687 generic-all emit correct byte code an attributes for type annotations tools/javac/warnings/suppress/TypeAnnotations.java 8057683 generic-all improve ordering of errors with type annotations tools/javac/modules/T8159439/NPEForModuleInfoWithNonZeroSuperClassTest.java 8160396 generic-all current version of jtreg needs a new promotion to include lastes version of ASM +tools/javac/T8132562/ClassPathWithDoubleQuotesTest.java 8169005 windows-all ########################################################################### # diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/internal/shellsupport/doc/JavadocFormatterTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/jdk/internal/shellsupport/doc/JavadocFormatterTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8131019 + * @summary Test JavadocFormatter + * @library /tools/lib + * @modules jdk.compiler/jdk.internal.shellsupport.doc + * @run testng JavadocFormatterTest + */ + +import java.util.Objects; + +import jdk.internal.shellsupport.doc.JavadocFormatter; +import org.testng.annotations.Test; + +@Test +public class JavadocFormatterTest { + + private static final String CODE_RESET = "\033[0m"; + private static final String CODE_HIGHLIGHT = "\033[1m"; + private static final String CODE_UNDERLINE = "\033[4m"; + + public void testReflow() { + String actual; + String expected; + + actual = new JavadocFormatter(25, true).formatJavadoc( + "test", + "1234 1234\n1234\n1234 12345 123456789012345678901234567890 1234 1234\n1234 {@code 1234} 1234 1234\n1234 1234 123456 123456\n123456\n123456 123456 {@link String string} 1"); + + expected = CODE_HIGHLIGHT + "test" + CODE_RESET + "\n" + + "1234 1234 1234 1234 12345\n" + + "123456789012345678901234567890\n" + + "1234 1234 1234 1234 1234\n" + + "1234 1234 1234 123456\n" + + "123456 123456 123456\n" + + "123456 string 1\n"; + + if (!Objects.equals(actual, expected)) { + throw new AssertionError("Incorrect output: " + actual); + } + + actual = new JavadocFormatter(66, true).formatJavadoc("test", + "@param 51234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "@param 61234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "@param shortName 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 " + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 \n" + + "@param aVeryLongName1234567890123456789012345678901234567890 " + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 " + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 " + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 \n"); + + expected = CODE_HIGHLIGHT + "test" + CODE_RESET + "\n" + + "\n" + + CODE_UNDERLINE + "Type Parameters:" + CODE_RESET + "\n" + + "T - 51234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "E - 61234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "\n" + + CODE_UNDERLINE + "Parameters:" + CODE_RESET + "\n" + + "shortName - 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234\n" + + "aVeryLongName1234567890123456789012345678901234567890 - \n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n"; + + if (!Objects.equals(actual, expected)) { + throw new AssertionError("Incorrect output: " + actual); + } + + actual = new JavadocFormatter(66, true).formatJavadoc("test", + "@throws ShortExcp 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 " + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 \n" + + "@throws aVeryLongException1234567890123456789012345678901234567890 " + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 " + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 " + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 \n"); + + expected = CODE_HIGHLIGHT + "test" + CODE_RESET + "\n" + + "\n" + + CODE_UNDERLINE + "Thrown Exceptions:" + CODE_RESET + "\n" + + "ShortExcp - 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234\n" + + "aVeryLongException1234567890123456789012345678901234567890 - \n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n"; + + if (!Objects.equals(actual, expected)) { + throw new AssertionError("Incorrect output: " + actual); + } + actual = new JavadocFormatter(66, true).formatJavadoc("test", + "@return 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 " + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 \n"); + + expected = CODE_HIGHLIGHT + "test" + CODE_RESET + "\n" + + "\n" + + CODE_UNDERLINE + "Returns:" + CODE_RESET + "\n" + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "1234 1234 1234 1234 1234 1234 1234 1234 1234\n"; + + if (!Objects.equals(actual, expected)) { + throw new AssertionError("Incorrect output: " + actual); + } + + //handling of

    ,

    :
    +        actual = new JavadocFormatter(66, true).formatJavadoc("test",
    +                "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 " +
    +                "1234 1234 1234 1234 1234 

    1234 1234

    1234 1234 1234 1234 1234 " + + "1234 1234 1234 1234 1234 1234 1234 1234

    1234 1234 1234 1234 " + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 \n" + + "

    \n" +
    +                "for (String data : content) {\n" +
    +                "    System.err.println(data);\n" +
    +                "}\n" +
    +                "
    \n"); + + expected = CODE_HIGHLIGHT + "test" + CODE_RESET + "\n" + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "1234 1234 1234 1234\n" + + "1234 1234\n" + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "1234 1234 1234\n" + + " for (String data : content) {\n" + + " System.err.println(data);\n" + + " }\n" + + " \n"; + + if (!Objects.equals(actual, expected)) { + throw new AssertionError("Incorrect output: " + actual); + } + + //list handling: + actual = new JavadocFormatter(66, true).formatJavadoc("test", + "
      " + + "
    • A 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234
    • " + + "
    • B 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + "
    • C 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234
        " + + "
      1. D 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234
      2. " + + "
      3. E 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234
          " + + "
        • F 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234
            " + + "
          1. G 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + "
          " + + "
        " + + "
      " + + "
    • H 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234

      1234 1234 1234 1234 1234 1234 1234

        " + + "
      • I 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + "
      " + + "
    followup" + + "
    " + + "
    Term1
    " + + "
    A 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234
    " + + "
    Term2" + + "
    B 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + "
    Term3" + + "
    C 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + "
    " + + "
    " + + "
    TermUnfinished" + + "
    followup"); + + expected = CODE_HIGHLIGHT + "test" + CODE_RESET + "\n" + + " * A 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234\n" + + " * B 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234\n" + + " * C 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234\n" + + " 1. D 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234\n" + + " 2. E 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234\n" + + " * F 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234\n" + + " 1. G 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " * H 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234\n" + + " * I 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234\n" + + "followup\n" + + CODE_HIGHLIGHT + "Term1" + CODE_RESET + "\n" + + " A 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234\n" + + CODE_HIGHLIGHT + "Term2" + CODE_RESET + "\n" + + " B 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234\n" + + CODE_HIGHLIGHT + "Term3" + CODE_RESET + "\n" + + " C 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234\n" + + CODE_HIGHLIGHT + "TermUnfinished" + CODE_RESET + "\n" + + "followup\n"; + + if (!Objects.equals(actual, expected)) { + throw new AssertionError("Incorrect output: " + actual); + } + + //sections: + actual = new JavadocFormatter(66, true).formatJavadoc("test", + "text 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 " + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 " + + "

    1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234

    " + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 " + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234"); + + expected = CODE_HIGHLIGHT + "test" + CODE_RESET + "\n" + + "text 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "\n" + + CODE_UNDERLINE + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "1234 1234 1234 1234 1234" + CODE_RESET + "\n" + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + "1234 1234 1234 1234 1234 1234 1234 1234\n"; + + if (!Objects.equals(actual, expected)) { + throw new AssertionError("Incorrect output: " + actual); + } + + //table: + actual = new JavadocFormatter(66, true).formatJavadoc("test", + "" + + "" + + "" + + "" + + "" + + "" + + "" + + " \n" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "
    A 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234B 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234C 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234
    A 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234B 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + "C 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + "
    A 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234B 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234C 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234
    1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 12341234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234
    "); + + expected = CODE_HIGHLIGHT + "test" + CODE_RESET + "\n" + + "----------------------------------------------------------------\n" + + "| " + CODE_HIGHLIGHT + "A 1234 1234 1234" + CODE_RESET + " | " + CODE_HIGHLIGHT + "B 1234 1234 1234" + CODE_RESET + " | " + CODE_HIGHLIGHT + "C 1234 1234 1234" + CODE_RESET + " |\n" + + "| " + CODE_HIGHLIGHT + "1234 1234 1234" + CODE_RESET + " | " + CODE_HIGHLIGHT + "1234 1234 1234" + CODE_RESET + " | " + CODE_HIGHLIGHT + "1234 1234 1234" + CODE_RESET + " |\n" + + "| " + CODE_HIGHLIGHT + "1234 1234 1234" + CODE_RESET + " | " + CODE_HIGHLIGHT + "1234 1234 1234" + CODE_RESET + " | " + CODE_HIGHLIGHT + "1234 1234 1234" + CODE_RESET + " |\n" + + "| " + CODE_HIGHLIGHT + "1234 1234 1234" + CODE_RESET + " | " + CODE_HIGHLIGHT + "1234 1234 1234" + CODE_RESET + " | " + CODE_HIGHLIGHT + "1234 1234 1234" + CODE_RESET + " |\n" + + "| " + CODE_HIGHLIGHT + "1234 1234 1234" + CODE_RESET + " | " + CODE_HIGHLIGHT + "1234 1234 1234" + CODE_RESET + " | " + CODE_HIGHLIGHT + "1234 1234 1234" + CODE_RESET + " |\n" + + "| " + CODE_HIGHLIGHT + "1234 1234" + CODE_RESET + " | " + CODE_HIGHLIGHT + "1234 1234" + CODE_RESET + " | " + CODE_HIGHLIGHT + "1234 1234" + CODE_RESET + " |\n" + + "----------------------------------------------------------------\n" + + "| A 1234 1234 1234 | B 1234 1234 1234 | C 1234 1234 1234 |\n" + + "| 1234 1234 1234 | 1234 1234 1234 | 1234 1234 1234 |\n" + + "| 1234 1234 1234 | 1234 1234 1234 | 1234 1234 1234 |\n" + + "| 1234 1234 1234 | 1234 1234 1234 | 1234 1234 1234 |\n" + + "| 1234 1234 1234 | 1234 1234 1234 | 1234 1234 1234 |\n" + + "| 1234 1234 | 1234 1234 | 1234 1234 |\n" + + "----------------------------------------------------------------\n" + + "| A 1234 1234 1234 | B 1234 1234 1234 | C 1234 1234 1234 |\n" + + "| 1234 1234 1234 | 1234 1234 1234 | 1234 1234 1234 |\n" + + "| 1234 1234 1234 | 1234 1234 1234 | 1234 1234 1234 |\n" + + "| 1234 1234 1234 | 1234 1234 1234 | 1234 1234 1234 |\n" + + "| 1234 1234 1234 | 1234 1234 1234 | 1234 1234 1234 |\n" + + "| 1234 1234 | 1234 1234 | 1234 1234 |\n" + + "----------------------------------------------------------------\n" + + "| 1234 1234 1234 | 1234 1234 1234 |\n" + + "| 1234 1234 1234 | 1234 1234 1234 |\n" + + "| 1234 1234 1234 | 1234 1234 1234 |\n" + + "| 1234 1234 1234 | 1234 1234 1234 |\n" + + "| 1234 1234 1234 | 1234 1234 1234 |\n" + + "| 1234 1234 | 1234 1234 |\n" + + "-------------------------------------------\n"; + + if (!Objects.equals(actual, expected)) { + throw new AssertionError("Incorrect output: " + actual); + } + + //no escape sequences: + actual = new JavadocFormatter(66, false).formatJavadoc("test", + "@param shortName 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 " + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 \n" + + "@param aVeryLongName1234567890123456789012345678901234567890 " + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 " + + "1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 " + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 \n"); + + expected = "test\n" + + "\n" + + "Parameters:\n" + + "shortName - 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234\n" + + "aVeryLongName1234567890123456789012345678901234567890 - \n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" + + " 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n"; + + if (!Objects.equals(actual, expected)) { + throw new AssertionError("Incorrect output: " + actual); + } + + //null javadoc: + actual = new JavadocFormatter(66, true).formatJavadoc("test", null); + + expected = CODE_HIGHLIGHT + "test" + CODE_RESET + "\n"; + + if (!Objects.equals(actual, expected)) { + throw new AssertionError("Incorrect output: " + actual); + } + + //stray tags: + for (String tag : new String[] {"li", "ol", "h3", "table", "tr", "td", "dl", "dt", "dd"}) { + for (boolean closing : new boolean[] {false, true}) { + actual = new JavadocFormatter(66, true).formatJavadoc("test", + "<" + (closing ? "/" : "") + tag + ">text"); + + if (!actual.contains("text")) { + throw new AssertionError("Incorrect output: " + actual); + } + } + } + + //entities: + actual = new JavadocFormatter(66, false).formatJavadoc("test", + "α < A B > &broken; � �\n"); + + expected = "test\n" + + "\u03b1 < A B > &broken; � �\n"; + + if (!Objects.equals(actual, expected)) { + throw new AssertionError("Incorrect output: " + actual); + } + + //img: + actual = new JavadocFormatter(66, true).formatJavadoc("test", + "1234 text 1234"); + + expected = CODE_HIGHLIGHT + "test" + CODE_RESET + "\n" + + "1234 text 1234\n"; + + if (!Objects.equals(actual, expected)) { + throw new AssertionError("Incorrect output: " + actual); + } + } + +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/internal/shellsupport/doc/JavadocHelperTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/jdk/internal/shellsupport/doc/JavadocHelperTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8131019 + * @summary Test JavadocHelper + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/jdk.internal.shellsupport.doc + * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask + * @run testng JavadocHelperTest + */ + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.function.Function; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; + +import javax.lang.model.element.Element; +import javax.lang.model.util.ElementFilter; +import javax.tools.Diagnostic.Kind; +import javax.tools.DiagnosticListener; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; + +import com.sun.source.util.JavacTask; +import jdk.internal.shellsupport.doc.JavadocHelper; +import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +@Test +public class JavadocHelperTest { + + public void testJavadoc() throws Exception { + doTestJavadoc("", + t -> t.getElements().getTypeElement("test.Super"), + "Top level. "); + doTestJavadoc("", + t -> getFirstMethod(t, "test.Super"), + " javadoc1A\n" + + "\n" + + " @param p1 param1A\n" + + " @param p2 param2A\n" + + " @param p3 param3A\n" + + " @throws IllegalStateException exc1A\n" + + " @throws IllegalArgumentException exc2A\n" + + " @throws IllegalAccessException exc3A\n" + + " @return valueA\n"); + } + + private Element getFirstMethod(JavacTask task, String typeName) { + return ElementFilter.methodsIn(task.getElements().getTypeElement(typeName).getEnclosedElements()).get(0); + } + + private Function getSubTest = t -> getFirstMethod(t, "test.Sub"); + + public void testInheritNoJavadoc() throws Exception { + doTestJavadoc("", + getSubTest, + " javadoc1A\n" + + "\n" + + " @param p1 param1A\n" + + " @param p2 param2A\n" + + " @param p3 param3A\n" + + " @throws IllegalStateException exc1A\n" + + " @throws IllegalArgumentException exc2A\n" + + " @throws IllegalAccessException exc3A\n" + + " @return valueA\n"); + } + + public void testInheritFull() throws Exception { + doTestJavadoc(" /**\n" + + " * Prefix {@inheritDoc} suffix.\n" + + " *\n" + + " * @param p1 prefix {@inheritDoc} suffix\n" + + " * @param p2 prefix {@inheritDoc} suffix\n" + + " * @param p3 prefix {@inheritDoc} suffix\n" + + " * @throws IllegalStateException prefix {@inheritDoc} suffix\n" + + " * @throws IllegalArgumentException prefix {@inheritDoc} suffix\n" + + " * @throws IllegalAccessException prefix {@inheritDoc} suffix\n" + + " * @return prefix {@inheritDoc} suffix\n" + + " */\n", + getSubTest, + " Prefix javadoc1 suffix.\n" + + "\n" + + " @param p1 prefix param1 suffix\n" + + " @param p2 prefix param2 suffix\n" + + " @param p3 prefix param3 suffix\n" + + " @throws IllegalStateException prefix exc1 suffix\n" + + " @throws IllegalArgumentException prefix exc2 suffix\n" + + " @throws IllegalAccessException prefix exc3 suffix\n" + + " @return prefix value suffix\n"); + } + + public void testInheritMissingParam() throws Exception { + doTestJavadoc(" /**\n" + + " * Prefix {@inheritDoc} suffix.\n" + + " *\n" + + " * @param p1 prefix {@inheritDoc} suffix\n" + + " * @param p3 prefix {@inheritDoc} suffix\n" + + " * @throws IllegalStateException prefix {@inheritDoc} suffix\n" + + " * @throws IllegalArgumentException prefix {@inheritDoc} suffix\n" + + " * @throws IllegalAccessException prefix {@inheritDoc} suffix\n" + + " * @return prefix {@inheritDoc} suffix\n" + + " */\n", + getSubTest, + " Prefix javadoc1 suffix.\n" + + "\n" + + " @param p1 prefix param1 suffix\n" + + "@param p2 param2\n" + + " @param p3 prefix param3 suffix\n" + + " @throws IllegalStateException prefix exc1 suffix\n" + + " @throws IllegalArgumentException prefix exc2 suffix\n" + + " @throws IllegalAccessException prefix exc3 suffix\n" + + " @return prefix value suffix\n"); + } + + public void testInheritMissingFirstParam() throws Exception { + doTestJavadoc(" /**\n" + + " * Prefix {@inheritDoc} suffix.\n" + + " *\n" + + " * @param p2 prefix {@inheritDoc} suffix\n" + + " * @param p3 prefix {@inheritDoc} suffix\n" + + " * @throws IllegalStateException prefix {@inheritDoc} suffix\n" + + " * @throws IllegalArgumentException prefix {@inheritDoc} suffix\n" + + " * @throws IllegalAccessException prefix {@inheritDoc} suffix\n" + + " * @return prefix {@inheritDoc} suffix\n" + + " */\n", + getSubTest, + " Prefix javadoc1 suffix.\n" + + "@param p1 param1\n" + + "\n" + + " @param p2 prefix param2 suffix\n" + + " @param p3 prefix param3 suffix\n" + + " @throws IllegalStateException prefix exc1 suffix\n" + + " @throws IllegalArgumentException prefix exc2 suffix\n" + + " @throws IllegalAccessException prefix exc3 suffix\n" + + " @return prefix value suffix\n"); + } + + public void testInheritMissingThrows() throws Exception { + doTestJavadoc(" /**\n" + + " * Prefix {@inheritDoc} suffix.\n" + + " *\n" + + " * @param p1 prefix {@inheritDoc} suffix\n" + + " * @param p2 prefix {@inheritDoc} suffix\n" + + " * @param p3 prefix {@inheritDoc} suffix\n" + + " * @throws IllegalStateException prefix {@inheritDoc} suffix\n" + + " * @throws IllegalAccessException prefix {@inheritDoc} suffix\n" + + " * @return prefix {@inheritDoc} suffix\n" + + " */\n", + getSubTest, + " Prefix javadoc1 suffix.\n" + + "\n" + + " @param p1 prefix param1 suffix\n" + + " @param p2 prefix param2 suffix\n" + + " @param p3 prefix param3 suffix\n" + + " @throws IllegalStateException prefix exc1 suffix\n" + + "@throws java.lang.IllegalArgumentException exc2\n" + + " @throws IllegalAccessException prefix exc3 suffix\n" + + " @return prefix value suffix\n"); + } + + public void testInheritMissingReturn() throws Exception { + doTestJavadoc(" /**\n" + + " * Prefix {@inheritDoc} suffix.\n" + + " *\n" + + " * @param p1 prefix {@inheritDoc} suffix\n" + + " * @param p2 prefix {@inheritDoc} suffix\n" + + " * @param p3 prefix {@inheritDoc} suffix\n" + + " * @throws IllegalStateException prefix {@inheritDoc} suffix\n" + + " * @throws IllegalArgumentException prefix {@inheritDoc} suffix\n" + + " * @throws IllegalAccessException prefix {@inheritDoc} suffix\n" + + " */\n", + getSubTest, + " Prefix javadoc1 suffix.\n" + + "\n" + + " @param p1 prefix param1 suffix\n" + + " @param p2 prefix param2 suffix\n" + + " @param p3 prefix param3 suffix\n" + + " @throws IllegalStateException prefix exc1 suffix\n" + + " @throws IllegalArgumentException prefix exc2 suffix\n" + + " @throws IllegalAccessException prefix exc3 suffix\n" + + "@return value\n"); + } + + + private void doTestJavadoc(String origJavadoc, Function getElement, String expectedJavadoc) throws Exception { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + String subClass = + "package test;\n" + + "public class Sub extends Super {\n" + + origJavadoc + + " public String test(int p1, int p2, int p3) throws IllegalStateException, IllegalArgumentException, IllegalAccessException { return null;} \n" + + "}\n"; + String superClass = + "package test;\n" + + "/**Top level." + + " */\n" + + "public class Super {\n" + + " /**\n" + + " * javadoc1A\n" + + " *\n" + + " * @param p1 param1A\n" + + " * @param p2 param2A\n" + + " * @param p3 param3A\n" + + " * @throws IllegalStateException exc1A\n" + + " * @throws IllegalArgumentException exc2A\n" + + " * @throws IllegalAccessException exc3A\n" + + " * @return valueA\n" + + " */\n" + + " public String test(int p1, int p2, int p3) throws IllegalStateException, IllegalArgumentException, IllegalAccessException { return null;} \n" + + "}\n"; + + Path srcZip = Paths.get("src.zip"); + + try (JarOutputStream out = new JarOutputStream(Files.newOutputStream(srcZip))) { + out.putNextEntry(new JarEntry("test/Sub.java")); + out.write(subClass.getBytes()); + out.putNextEntry(new JarEntry("test/Super.java")); + out.write(superClass.getBytes()); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + + DiagnosticListener noErrors = d -> { + if (d.getKind() == Kind.ERROR) { + throw new AssertionError(d.getMessage(null)); + } + }; + + assertTrue(compiler.getTask(null, null, noErrors, Arrays.asList("-d", "."), null, Arrays.asList(new JFOImpl("Super", superClass), new JFOImpl("Sub", subClass))).call()); + + try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) { + fm.setLocationFromPaths(StandardLocation.CLASS_PATH, Arrays.asList(Paths.get(".").toAbsolutePath())); + JavacTask task = (JavacTask) compiler.getTask(null, fm, noErrors, null, null, null); + + Element el = getElement.apply(task); + + try (JavadocHelper helper = JavadocHelper.create(task, Arrays.asList(srcZip))) { + String javadoc = helper.getResolvedDocComment(el); + + assertEquals(javadoc, expectedJavadoc); + } + } + } + + private static final class JFOImpl extends SimpleJavaFileObject { + + private final String code; + + public JFOImpl(String name, String code) throws URISyntaxException { + super(new URI("mem:///" + name + ".java"), Kind.SOURCE); + this.code = code; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return code; + } + + } +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/ClassMembersTest.java --- a/langtools/test/jdk/jshell/ClassMembersTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/jdk/jshell/ClassMembersTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -38,6 +38,9 @@ import jdk.jshell.SourceCodeAnalysis; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import jdk.jshell.TypeDeclSnippet; +import static jdk.jshell.Snippet.Status.OVERWRITTEN; +import static jdk.jshell.Snippet.Status.VALID; public class ClassMembersTest extends KullaTesting { @@ -141,29 +144,36 @@ new ExpectedDiagnostic("compiler.err.non-static.cant.be.ref", 0, 8, 1, -1, -1, Diagnostic.Kind.ERROR)); } - @Test(enabled = false) // TODO 8080354 - public void annotationTest() { + @Test(dataProvider = "retentionPolicyTestCase") + public void annotationTest(RetentionPolicy policy) { assertEval("import java.lang.annotation.*;"); + String annotationSource = + "@Retention(RetentionPolicy." + policy.toString() + ")\n" + + "@interface A {}"; + assertEval(annotationSource); + String classSource = + "@A class C {\n" + + " @A C() {}\n" + + " @A void f() {}\n" + + " @A int f;\n" + + " @A class Inner {}\n" + + "}"; + assertEval(classSource); + String isRuntimeVisible = policy == RetentionPolicy.RUNTIME ? "true" : "false"; + assertEval("C.class.getAnnotationsByType(A.class).length > 0;", isRuntimeVisible); + assertEval("C.class.getDeclaredConstructor().getAnnotationsByType(A.class).length > 0;", isRuntimeVisible); + assertEval("C.class.getDeclaredMethod(\"f\").getAnnotationsByType(A.class).length > 0;", isRuntimeVisible); + assertEval("C.class.getDeclaredField(\"f\").getAnnotationsByType(A.class).length > 0;", isRuntimeVisible); + assertEval("C.Inner.class.getAnnotationsByType(A.class).length > 0;", isRuntimeVisible); + } + + @DataProvider(name = "retentionPolicyTestCase") + public Object[][] retentionPolicyTestCaseGenerator() { + List list = new ArrayList<>(); for (RetentionPolicy policy : RetentionPolicy.values()) { - String annotationSource = - "@Retention(RetentionPolicy." + policy.toString() + ")\n" + - "@interface A {}"; - assertEval(annotationSource); - String classSource = - "@A class C {\n" + - " @A C() {}\n" + - " @A void f() {}\n" + - " @A int f;\n" + - " @A class Inner {}\n" + - "}"; - assertEval(classSource); - String isRuntimeVisible = policy == RetentionPolicy.RUNTIME ? "true" : "false"; - assertEval("C.class.getAnnotationsByType(A.class).length > 0;", isRuntimeVisible); - assertEval("C.class.getDeclaredConstructor().getAnnotationsByType(A.class).length > 0;", isRuntimeVisible); - assertEval("C.class.getDeclaredMethod(\"f\").getAnnotationsByType(A.class).length > 0;", isRuntimeVisible); - assertEval("C.class.getDeclaredField(\"f\").getAnnotationsByType(A.class).length > 0;", isRuntimeVisible); - assertEval("C.Inner.class.getAnnotationsByType(A.class).length > 0;", isRuntimeVisible); + list.add(new Object[]{policy}); } + return list.toArray(new Object[list.size()][]); } @DataProvider(name = "memberTestCase") diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/ClassesTest.java --- a/langtools/test/jdk/jshell/ClassesTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/jdk/jshell/ClassesTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -23,7 +23,7 @@ /* * @test - * @bug 8145239 + * @bug 8145239 8129559 8080354 * @summary Tests for EvaluationState.classes * @build KullaTesting TestingInputStream ExpectedDiagnostic * @run testng ClassesTest @@ -247,14 +247,30 @@ } public void classesIgnoredModifiers() { - assertDeclareWarn1("public interface A { }", - new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 6, 0, -1, -1, Diagnostic.Kind.WARNING)); + assertEval("public interface A { }"); assertDeclareWarn1("static class B implements A { }", new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 6, 0, -1, -1, Diagnostic.Kind.WARNING)); assertDeclareWarn1("final interface C extends A { }", new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 5, 0, -1, -1, Diagnostic.Kind.WARNING)); - assertDeclareWarn1("protected enum D implements C { }", + assertActiveKeys(); + } + + public void classesIgnoredModifiersAnnotation() { + assertEval("public @interface X { }"); + assertEval("@X public interface A { }"); + assertDeclareWarn1("@X static class B implements A { }", new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 9, 0, -1, -1, Diagnostic.Kind.WARNING)); + assertDeclareWarn1("@X final interface C extends A { }", + new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 8, 0, -1, -1, Diagnostic.Kind.WARNING)); + assertActiveKeys(); + } + + public void classesIgnoredModifiersOtherModifiers() { + assertEval("strictfp public interface A { }"); + assertDeclareWarn1("strictfp static class B implements A { }", + new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 15, 0, -1, -1, Diagnostic.Kind.WARNING)); + assertDeclareWarn1("strictfp final interface C extends A { }", + new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 14, 0, -1, -1, Diagnostic.Kind.WARNING)); assertActiveKeys(); } diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/CompletenessTest.java --- a/langtools/test/jdk/jshell/CompletenessTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/jdk/jshell/CompletenessTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -23,7 +23,7 @@ /* * @test - * @bug 8149524 8131024 8165211 8080071 8130454 8167343 + * @bug 8149524 8131024 8165211 8080071 8130454 8167343 8129559 * @summary Test SourceCodeAnalysis * @build KullaTesting TestingInputStream * @run testng CompletenessTest @@ -176,6 +176,7 @@ "@interface Anno", "void f()", "void f() throws E", + "@A(", }; static final String[] unknown = new String[] { diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/CompletionSuggestionTest.java --- a/langtools/test/jdk/jshell/CompletionSuggestionTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/jdk/jshell/CompletionSuggestionTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -23,12 +23,12 @@ /* * @test - * @bug 8131025 8141092 8153761 8145263 + * @bug 8131025 8141092 8153761 8145263 8131019 * @summary Test Completion and Documentation + * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main * jdk.jdeps/com.sun.tools.javap - * @library /tools/lib * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask * @build KullaTesting TestingInputStream Compiler * @run testng CompletionSuggestionTest @@ -305,26 +305,26 @@ public void testDocumentation() throws Exception { dontReadParameterNamesFromClassFile(); - assertDocumentation("System.getProperty(|", + assertSignature("System.getProperty(|", "String System.getProperty(String key)", "String System.getProperty(String key, String def)"); assertEval("char[] chars = null;"); - assertDocumentation("new String(chars, |", + assertSignature("new String(chars, |", "String(char[], int, int)"); - assertDocumentation("String.format(|", + assertSignature("String.format(|", "String String.format(String, Object...)", "String String.format(java.util.Locale, String, Object...)"); - assertDocumentation("\"\".getBytes(\"\"|", "void String.getBytes(int, int, byte[], int)", + assertSignature("\"\".getBytes(\"\"|", "void String.getBytes(int, int, byte[], int)", "byte[] String.getBytes(String) throws java.io.UnsupportedEncodingException", "byte[] String.getBytes(java.nio.charset.Charset)"); - assertDocumentation("\"\".getBytes(\"\" |", "void String.getBytes(int, int, byte[], int)", + assertSignature("\"\".getBytes(\"\" |", "void String.getBytes(int, int, byte[], int)", "byte[] String.getBytes(String) throws java.io.UnsupportedEncodingException", "byte[] String.getBytes(java.nio.charset.Charset)"); } public void testMethodsWithNoArguments() throws Exception { dontReadParameterNamesFromClassFile(); - assertDocumentation("System.out.println(|", + assertSignature("System.out.println(|", "void java.io.PrintStream.println()", "void java.io.PrintStream.println(boolean)", "void java.io.PrintStream.println(char)", @@ -339,6 +339,7 @@ public void testErroneous() { assertCompletion("Undefined.|"); + assertSignature("does.not.exist|"); } public void testClinit() { @@ -474,59 +475,63 @@ public void testDocumentationOfUserDefinedMethods() { assertEval("void f() {}"); - assertDocumentation("f(|", "void f()"); + assertSignature("f(|", "void f()"); assertEval("void f(int i) {}"); - assertDocumentation("f(|", "void f()", "void f(int i)"); + assertSignature("f(|", "void f()", "void f(int i)"); assertEval(" void f(T... ts) {}", DiagCheck.DIAG_WARNING, DiagCheck.DIAG_OK); - assertDocumentation("f(|", "void f()", "void f(int i)", "void f(T... ts)"); + assertSignature("f(|", "void f()", "void f(int i)", "void f(T... ts)"); assertEval("class A {}"); assertEval("void f(A a) {}"); - assertDocumentation("f(|", "void f()", "void f(int i)", "void f(T... ts)", "void f(A a)"); + assertSignature("f(|", "void f()", "void f(int i)", "void f(T... ts)", "void f(A a)"); + } + + public void testClass() { + assertSignature("String|", "java.lang.String"); } public void testDocumentationOfUserDefinedConstructors() { Snippet a = classKey(assertEval("class A {}")); - assertDocumentation("new A(|", "A()"); + assertSignature("new A(|", "A()"); Snippet a2 = classKey(assertEval("class A { A() {} A(int i) {}}", ste(MAIN_SNIPPET, VALID, VALID, true, null), ste(a, VALID, OVERWRITTEN, false, MAIN_SNIPPET))); - assertDocumentation("new A(|", "A()", "A(int i)"); + assertSignature("new A(|", "A()", "A(int i)"); assertEval("class A { A(T a) {} A(int i) {} A(T t, U u) {}}", ste(MAIN_SNIPPET, VALID, VALID, true, null), ste(a2, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); - assertDocumentation("new A(|", "A(T a)", "A(int i)", " A(T t, U u)"); + assertSignature("new A(|", "A(T a)", "A(int i)", " A(T t, U u)"); } public void testDocumentationOfOverriddenMethods() throws Exception { dontReadParameterNamesFromClassFile(); - assertDocumentation("\"\".wait(|", + assertSignature("\"\".wait(|", "void Object.wait(long) throws InterruptedException", "void Object.wait(long, int) throws InterruptedException", "void Object.wait() throws InterruptedException"); assertEval("class Base {void method() {}}"); Snippet e = classKey(assertEval("class Extend extends Base {}")); - assertDocumentation("new Extend().method(|", "void Base.method()"); + assertSignature("new Extend().method(|", "void Base.method()"); assertEval("class Extend extends Base {void method() {}}", ste(MAIN_SNIPPET, VALID, VALID, true, null), ste(e, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); - assertDocumentation("new Extend().method(|", "void Extend.method()"); + assertSignature("new Extend().method(|", "void Extend.method()"); } public void testDocumentationOfInvisibleMethods() { - assertDocumentation("Object.wait(|", ""); - assertDocumentation("\"\".indexOfSupplementary(|", ""); + assertSignature("Object.wait(|"); + assertSignature("\"\".indexOfSupplementary(|"); Snippet a = classKey(assertEval("class A {void method() {}}")); - assertDocumentation("A.method(|", ""); + assertSignature("A.method(|"); assertEval("class A {private void method() {}}", ste(MAIN_SNIPPET, VALID, VALID, true, null), ste(a, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); - assertDocumentation("new A().method(|", ""); + assertSignature("new A().method(|"); } public void testDocumentationOfInvisibleConstructors() { - assertDocumentation("new Compiler(|", ""); + assertSignature("new Compiler(|"); assertEval("class A { private A() {} }"); - assertDocumentation("new A(|", ""); + assertSignature("new A(|"); } public void testDocumentationWithBoxing() { @@ -535,13 +540,13 @@ assertEval("Object object = null;"); assertEval("void method(int n, Object o) { }"); assertEval("void method(Object n, int o) { }"); - assertDocumentation("method(primitive,|", + assertSignature("method(primitive,|", "void method(int n, Object o)", "void method(Object n, int o)"); - assertDocumentation("method(boxed,|", + assertSignature("method(boxed,|", "void method(int n, Object o)", "void method(Object n, int o)"); - assertDocumentation("method(object,|", + assertSignature("method(object,|", "void method(Object n, int o)"); } @@ -567,7 +572,7 @@ void assertDoc(String generics, String expectedGenerics) { assertEval(evalFormatter.apply(generics, count)); - assertDocumentation(codeFacotry.apply(count), docFormatter.apply(expectedGenerics, count)); + assertSignature(codeFacotry.apply(count), docFormatter.apply(expectedGenerics, count)); count++; } } diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/EditorPadTest.java --- a/langtools/test/jdk/jshell/EditorPadTest.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,246 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8139872 - * @summary Testing built-in editor. - * @modules java.desktop/java.awt - * jdk.jshell/jdk.internal.jshell.tool - * @build ReplToolTesting EditorTestBase - * @run testng EditorPadTest - */ - -import java.awt.AWTException; -import java.awt.Component; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.Frame; -import java.awt.GraphicsEnvironment; -import java.awt.Point; -import java.awt.Robot; -import java.awt.event.InputEvent; -import java.awt.event.WindowEvent; -import java.lang.reflect.InvocationTargetException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.function.Consumer; - -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.JViewport; -import javax.swing.SwingUtilities; - -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -public class EditorPadTest extends EditorTestBase { - - private static final int DELAY = 500; - - private static Robot robot; - private static JFrame frame = null; - private static JTextArea area = null; - private static JButton cancel = null; - private static JButton accept = null; - private static JButton exit = null; - - // Do not actually run if we are headless - @Override - public void testEditor(boolean defaultStartup, String[] args, ReplTest... tests) { - if (!GraphicsEnvironment.isHeadless()) { - test(defaultStartup, args, tests); - } - } - - @BeforeClass - public static void setUpEditorPadTest() { - if (!GraphicsEnvironment.isHeadless()) { - try { - robot = new Robot(); - robot.setAutoWaitForIdle(true); - robot.setAutoDelay(DELAY); - } catch (AWTException e) { - throw new ExceptionInInitializerError(e); - } - } - } - - @AfterClass - public static void shutdown() { - executorShutdown(); - } - - @Override - public void writeSource(String s) { - SwingUtilities.invokeLater(() -> area.setText(s)); - } - - @Override - public String getSource() { - try { - String[] s = new String[1]; - SwingUtilities.invokeAndWait(() -> s[0] = area.getText()); - return s[0]; - } catch (InvocationTargetException | InterruptedException e) { - throw new RuntimeException(e); - } - } - - @Override - public void accept() { - clickOn(accept); - } - - @Override - public void exit() { - clickOn(exit); - } - - @Override - public void cancel() { - clickOn(cancel); - } - - @Override - public void shutdownEditor() { - SwingUtilities.invokeLater(this::clearElements); - waitForIdle(); - } - - @Test - public void testShuttingDown() { - testEditor( - (a) -> assertEditOutput(a, "/ed", "", this::shutdownEditor) - ); - } - - private void waitForIdle() { - robot.waitForIdle(); - robot.delay(DELAY); - } - - private Future task; - @Override - public void assertEdit(boolean after, String cmd, - Consumer checkInput, Consumer checkOutput, Action action) { - if (!after) { - setCommandInput(cmd + "\n"); - task = getExecutor().submit(() -> { - try { - waitForIdle(); - SwingUtilities.invokeLater(this::seekElements); - waitForIdle(); - checkInput.accept(getSource()); - action.accept(); - } catch (Throwable e) { - shutdownEditor(); - if (e instanceof AssertionError) { - throw (AssertionError) e; - } - throw new RuntimeException(e); - } - }); - } else { - try { - task.get(); - waitForIdle(); - checkOutput.accept(getCommandOutput()); - } catch (ExecutionException e) { - if (e.getCause() instanceof AssertionError) { - throw (AssertionError) e.getCause(); - } - throw new RuntimeException(e); - } catch (Exception e) { - throw new RuntimeException(e); - } finally { - shutdownEditor(); - } - } - } - - private void seekElements() { - for (Frame f : Frame.getFrames()) { - if (f.getTitle().contains("Edit Pad")) { - frame = (JFrame) f; - // workaround - frame.setLocation(0, 0); - Container root = frame.getContentPane(); - for (Component c : root.getComponents()) { - if (c instanceof JScrollPane) { - JScrollPane scrollPane = (JScrollPane) c; - for (Component comp : scrollPane.getComponents()) { - if (comp instanceof JViewport) { - JViewport view = (JViewport) comp; - area = (JTextArea) view.getComponent(0); - } - } - } - if (c instanceof JPanel) { - JPanel p = (JPanel) c; - for (Component comp : p.getComponents()) { - if (comp instanceof JButton) { - JButton b = (JButton) comp; - switch (b.getText()) { - case "Cancel": - cancel = b; - break; - case "Exit": - exit = b; - break; - case "Accept": - accept = b; - break; - } - } - } - } - } - } - } - } - - private void clearElements() { - if (frame != null) { - frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING)); - frame = null; - } - area = null; - accept = null; - cancel = null; - exit = null; - } - - private void clickOn(JButton button) { - waitForIdle(); - Point p = button.getLocationOnScreen(); - Dimension d = button.getSize(); - robot.mouseMove(p.x + d.width / 2, p.y + d.height / 2); - robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); - robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); - } -} diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/ErrorTranslationTest.java --- a/langtools/test/jdk/jshell/ErrorTranslationTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/jdk/jshell/ErrorTranslationTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -63,11 +63,8 @@ List list = new ArrayList<>(); ExpectedDiagnostic[] diagnostics = new ExpectedDiagnostic[]{ newExpectedDiagnostic(0, 6, 0, -1, -1, Diagnostic.Kind.WARNING), - newExpectedDiagnostic(0, 9, 0, -1, -1, Diagnostic.Kind.WARNING), - newExpectedDiagnostic(0, 7, 0, -1, -1, Diagnostic.Kind.WARNING), - newExpectedDiagnostic(0, 6, 0, -1, -1, Diagnostic.Kind.WARNING), newExpectedDiagnostic(0, 5, 0, -1, -1, Diagnostic.Kind.WARNING)}; - String[] mods = {"public", "protected", "private", "static", "final"}; + String[] mods = {"static", "final"}; for (int i = 0; i < mods.length; ++i) { for (String code : new String[] {"class A {}", "void f() {}", "int a;"}) { final int finalI = i; diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/FailOverExecutionControlTest.java --- a/langtools/test/jdk/jshell/FailOverExecutionControlTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/jdk/jshell/FailOverExecutionControlTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -33,7 +33,7 @@ import org.testng.annotations.Test; import org.testng.annotations.BeforeMethod; -import jdk.jshell.execution.JDIDefaultExecutionControl; +import jdk.jshell.execution.JdiDefaultExecutionControl; import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionEnv; import static jdk.jshell.execution.Util.failOverExecutionControlGenerator; @@ -47,7 +47,7 @@ setUp(builder -> builder.executionEngine(failOverExecutionControlGenerator( new AlwaysFailingGenerator(), new AlwaysFailingGenerator(), - JDIDefaultExecutionControl.launch()))); + JdiDefaultExecutionControl.launch()))); } class AlwaysFailingGenerator implements ExecutionControl.Generator { diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/IgnoreTest.java --- a/langtools/test/jdk/jshell/IgnoreTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/jdk/jshell/IgnoreTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -22,7 +22,7 @@ */ /* - * @test + * @test 8129559 * @summary Test the ignoring of comments and certain modifiers * @build KullaTesting TestingInputStream * @run testng IgnoreTest @@ -58,38 +58,67 @@ } public void testVarModifier() { - VarSnippet x1 = (VarSnippet) assertDeclareWarn1("public int x1;", "jdk.eval.warn.illegal.modifiers"); - assertVariableDeclSnippet(x1, "x1", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 1); - VarSnippet x2 = (VarSnippet) assertDeclareWarn1("protected int x2;", "jdk.eval.warn.illegal.modifiers"); - assertVariableDeclSnippet(x2, "x2", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 1); - VarSnippet x3 = (VarSnippet) assertDeclareWarn1("private int x3;", "jdk.eval.warn.illegal.modifiers"); - assertVariableDeclSnippet(x3, "x3", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 1); + VarSnippet x1 = varKey(assertEval("public int x1;")); + assertVariableDeclSnippet(x1, "x1", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); + VarSnippet x2 = varKey(assertEval("protected int x2;")); + assertVariableDeclSnippet(x2, "x2", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); + VarSnippet x3 = varKey(assertEval("private int x3;")); + assertVariableDeclSnippet(x3, "x3", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); VarSnippet x4 = (VarSnippet) assertDeclareWarn1("static int x4;", "jdk.eval.warn.illegal.modifiers"); assertVariableDeclSnippet(x4, "x4", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 1); VarSnippet x5 = (VarSnippet) assertDeclareWarn1("final int x5;", "jdk.eval.warn.illegal.modifiers"); assertVariableDeclSnippet(x5, "x5", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 1); } + public void testVarModifierAnnotation() { + assertEval("@interface A { int value() default 0; }"); + VarSnippet x1 = varKey(assertEval("@A public int x1;")); + assertVariableDeclSnippet(x1, "x1", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); + VarSnippet x2 = varKey(assertEval("@A(14) protected int x2;")); + assertVariableDeclSnippet(x2, "x2", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); + VarSnippet x3 = varKey(assertEval("@A(value=111)private int x3;")); + assertVariableDeclSnippet(x3, "x3", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); + VarSnippet x4 = (VarSnippet) assertDeclareWarn1("@A static int x4;", "jdk.eval.warn.illegal.modifiers"); + assertVariableDeclSnippet(x4, "x4", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 1); + VarSnippet x5 = (VarSnippet) assertDeclareWarn1("@A(1111) final int x5;", "jdk.eval.warn.illegal.modifiers"); + assertVariableDeclSnippet(x5, "x5", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 1); + } + + public void testVarModifierOtherModifier() { + VarSnippet x1 = varKey(assertEval("volatile public int x1;")); + assertVariableDeclSnippet(x1, "x1", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); + VarSnippet x2 = varKey(assertEval("transient protected int x2;")); + assertVariableDeclSnippet(x2, "x2", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); + VarSnippet x3 = varKey(assertEval("transient private int x3;")); + assertVariableDeclSnippet(x3, "x3", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 0); + VarSnippet x4 = (VarSnippet) assertDeclareWarn1("volatile static int x4;", "jdk.eval.warn.illegal.modifiers"); + assertVariableDeclSnippet(x4, "x4", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 1); + VarSnippet x5 = (VarSnippet) assertDeclareWarn1("transient final int x5;", "jdk.eval.warn.illegal.modifiers"); + assertVariableDeclSnippet(x5, "x5", "int", VALID, VAR_DECLARATION_SUBKIND, 0, 1); + } + + public void testMisplacedIgnoredModifier() { + assertEvalFail("int public y;"); + assertEvalFail("String private x;"); + assertEvalFail("(protected 34);"); + } + public void testMethodModifier() { - MethodSnippet m1 = (MethodSnippet) assertDeclareWarn1("public void m1() {}", "jdk.eval.warn.illegal.modifiers"); - assertMethodDeclSnippet(m1, "m1", "()void", VALID, 0, 1); - MethodSnippet m2 = (MethodSnippet) assertDeclareWarn1("protected void m2() {}", "jdk.eval.warn.illegal.modifiers"); - assertMethodDeclSnippet(m2, "m2", "()void", VALID, 0, 1); - MethodSnippet m3 = (MethodSnippet) assertDeclareWarn1("private void m3() {}", "jdk.eval.warn.illegal.modifiers"); - assertMethodDeclSnippet(m3, "m3", "()void", VALID, 0, 1); MethodSnippet m4 = (MethodSnippet) assertDeclareWarn1("static void m4() {}", "jdk.eval.warn.illegal.modifiers"); assertMethodDeclSnippet(m4, "m4", "()void", VALID, 0, 1); MethodSnippet m5 = (MethodSnippet) assertDeclareWarn1("final void m5() {}", "jdk.eval.warn.illegal.modifiers"); assertMethodDeclSnippet(m5, "m5", "()void", VALID, 0, 1); } + public void testMethodModifierAnnotation() { + assertEval("@interface A { int value() default 0; }"); + MethodSnippet m4 = (MethodSnippet) assertDeclareWarn1("@A static void m4() {}", "jdk.eval.warn.illegal.modifiers"); + assertMethodDeclSnippet(m4, "m4", "()void", VALID, 0, 1); + MethodSnippet m5 = (MethodSnippet) assertDeclareWarn1("@A(value=66)final void m5() {}", "jdk.eval.warn.illegal.modifiers"); + assertMethodDeclSnippet(m5, "m5", "()void", VALID, 0, 1); + } + public void testClassModifier() { - TypeDeclSnippet c1 = (TypeDeclSnippet) assertDeclareWarn1("public class C1 {}", "jdk.eval.warn.illegal.modifiers"); - assertTypeDeclSnippet(c1, "C1", VALID, CLASS_SUBKIND, 0, 1); - TypeDeclSnippet c2 = (TypeDeclSnippet) assertDeclareWarn1("protected class C2 {}", "jdk.eval.warn.illegal.modifiers"); - assertTypeDeclSnippet(c2, "C2", VALID, CLASS_SUBKIND, 0, 1); - TypeDeclSnippet c3 = (TypeDeclSnippet) assertDeclareWarn1("private class C3 {}", "jdk.eval.warn.illegal.modifiers"); - assertTypeDeclSnippet(c3, "C3", VALID, CLASS_SUBKIND, 0, 1); TypeDeclSnippet c4 = (TypeDeclSnippet) assertDeclareWarn1("static class C4 {}", "jdk.eval.warn.illegal.modifiers"); assertTypeDeclSnippet(c4, "C4", VALID, CLASS_SUBKIND, 0, 1); TypeDeclSnippet c5 = (TypeDeclSnippet) assertDeclareWarn1("final class C5 {}", "jdk.eval.warn.illegal.modifiers"); diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/JDILaunchingExecutionControlTest.java --- a/langtools/test/jdk/jshell/JDILaunchingExecutionControlTest.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8164518 - * @summary Tests for standard JDI connector (without failover) -- launching - * @modules jdk.jshell/jdk.jshell.execution - * @build KullaTesting ExecutionControlTestBase - * @run testng JDILaunchingExecutionControlTest - */ - - -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; -import jdk.jshell.execution.JDIDefaultExecutionControl; - -@Test -public class JDILaunchingExecutionControlTest extends ExecutionControlTestBase { - - @BeforeMethod - @Override - public void setUp() { - setUp(builder -> builder.executionEngine(JDIDefaultExecutionControl.launch())); - } -} diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/JDIListeningExecutionControlTest.java --- a/langtools/test/jdk/jshell/JDIListeningExecutionControlTest.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8131029 8159935 8160127 8164518 - * @summary Tests for alternate JDI connector -- listening - * @modules jdk.jshell/jdk.jshell.execution - * @build KullaTesting ExecutionControlTestBase - * @run testng JDIListeningExecutionControlTest - */ - - -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; -import jdk.jshell.execution.JDIDefaultExecutionControl; - -@Test -public class JDIListeningExecutionControlTest extends ExecutionControlTestBase { - - @BeforeMethod - @Override - public void setUp() { - setUp(builder -> builder.executionEngine(JDIDefaultExecutionControl.listen(null))); - } -} diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/JDIListeningLocalhostExecutionControlTest.java --- a/langtools/test/jdk/jshell/JDIListeningLocalhostExecutionControlTest.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8164518 - * @summary Tests for alternate JDI connector -- listening to "localhost" - * @modules jdk.jshell/jdk.jshell.execution - * @build KullaTesting ExecutionControlTestBase - * @run testng JDIListeningLocalhostExecutionControlTest - */ - - -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; -import jdk.jshell.execution.JDIDefaultExecutionControl; - -@Test -public class JDIListeningLocalhostExecutionControlTest extends ExecutionControlTestBase { - - @BeforeMethod - @Override - public void setUp() { - setUp(builder -> builder.executionEngine(JDIDefaultExecutionControl.listen("localhost"))); - } -} diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/JavadocTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/jdk/jshell/JavadocTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8131019 + * @summary Test Javadoc + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.jshell + * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask + * @build KullaTesting TestingInputStream Compiler + * @run testng JavadocTest + */ + +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; + +import org.testng.annotations.Test; + +@Test +public class JavadocTest extends KullaTesting { + + private final Compiler compiler = new Compiler(); + + public void testJavadoc() { + prepareZip(); + assertJavadoc("test.Clazz|", "test.Clazz\n" + + "Top level. "); + assertEval("test.Clazz clz = null;"); + assertJavadoc("clz.test(|", "String test.Clazz.test(int p) throws IllegalStateException\n" + + " javadoc1A\n" + + "\n" + + " @param p param\n" + + " @throws IllegalStateException exc\n" + + " @return value\n"); + //undefined handling: + assertJavadoc("clz.undef|"); + } + + private void prepareZip() { + String clazz = + "package test;\n" + + "/**Top level." + + " */\n" + + "public class Clazz {\n" + + " /**\n" + + " * javadoc1A\n" + + " *\n" + + " * @param p param\n" + + " * @throws IllegalStateException exc\n" + + " * @return value\n" + + " */\n" + + " public String test(int p) throws IllegalStateException { return null;}\n" + + "}\n"; + + Path srcZip = Paths.get("src.zip"); + + try (JarOutputStream out = new JarOutputStream(Files.newOutputStream(srcZip))) { + out.putNextEntry(new JarEntry("test/Clazz.java")); + out.write(clazz.getBytes()); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + + compiler.compile(clazz); + + try { + Field availableSources = getAnalysis().getClass().getDeclaredField("availableSources"); + availableSources.setAccessible(true); + availableSources.set(getAnalysis(), Arrays.asList(srcZip)); + } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException ex) { + throw new IllegalStateException(ex); + } + addToClasspath(compiler.getClassDir()); + } + +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/JdiLaunchingExecutionControlTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/jdk/jshell/JdiLaunchingExecutionControlTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8164518 + * @summary Tests for standard JDI connector (without failover) -- launching + * @modules jdk.jshell/jdk.jshell.execution + * @build KullaTesting ExecutionControlTestBase + * @run testng JdiLaunchingExecutionControlTest + */ + + +import org.testng.annotations.Test; +import org.testng.annotations.BeforeMethod; +import jdk.jshell.execution.JdiDefaultExecutionControl; + +@Test +public class JdiLaunchingExecutionControlTest extends ExecutionControlTestBase { + + @BeforeMethod + @Override + public void setUp() { + setUp(builder -> builder.executionEngine(JdiDefaultExecutionControl.launch())); + } +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/JdiListeningExecutionControlTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/jdk/jshell/JdiListeningExecutionControlTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8131029 8159935 8160127 8164518 + * @summary Tests for alternate JDI connector -- listening + * @modules jdk.jshell/jdk.jshell.execution + * @build KullaTesting ExecutionControlTestBase + * @run testng JdiListeningExecutionControlTest + */ + + +import org.testng.annotations.Test; +import org.testng.annotations.BeforeMethod; +import jdk.jshell.execution.JdiDefaultExecutionControl; + +@Test +public class JdiListeningExecutionControlTest extends ExecutionControlTestBase { + + @BeforeMethod + @Override + public void setUp() { + setUp(builder -> builder.executionEngine(JdiDefaultExecutionControl.listen(null))); + } +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/JdiListeningLocalhostExecutionControlTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/jdk/jshell/JdiListeningLocalhostExecutionControlTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8164518 + * @summary Tests for alternate JDI connector -- listening to "localhost" + * @modules jdk.jshell/jdk.jshell.execution + * @build KullaTesting ExecutionControlTestBase + * @run testng JdiListeningLocalhostExecutionControlTest + */ + + +import org.testng.annotations.Test; +import org.testng.annotations.BeforeMethod; +import jdk.jshell.execution.JdiDefaultExecutionControl; + +@Test +public class JdiListeningLocalhostExecutionControlTest extends ExecutionControlTestBase { + + @BeforeMethod + @Override + public void setUp() { + setUp(builder -> builder.executionEngine(JdiDefaultExecutionControl.listen("localhost"))); + } +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/KullaTesting.java --- a/langtools/test/jdk/jshell/KullaTesting.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/jdk/jshell/KullaTesting.java Fri Nov 11 16:44:36 2016 +0100 @@ -72,11 +72,14 @@ import org.testng.annotations.BeforeMethod; import jdk.jshell.Diag; + import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; + import static jdk.jshell.Snippet.Status.*; import static org.testng.Assert.*; import static jdk.jshell.Snippet.SubKind.METHOD_SUBKIND; +import jdk.jshell.SourceCodeAnalysis.Documentation; public class KullaTesting { @@ -946,54 +949,56 @@ } } - public void assertDocumentation(String code, String... expected) { + public void assertSignature(String code, String... expected) { int cursor = code.indexOf('|'); code = code.replace("|", ""); assertTrue(cursor > -1, "'|' expected, but not found in: " + code); - String documentation = getAnalysis().documentation(code, cursor); - Set docSet = Stream.of(documentation.split("\r?\n")).collect(Collectors.toSet()); + List documentation = getAnalysis().documentation(code, cursor, false); + Set docSet = documentation.stream().map(doc -> doc.signature()).collect(Collectors.toSet()); + Set expectedSet = Stream.of(expected).collect(Collectors.toSet()); + assertEquals(docSet, expectedSet, "Input: " + code); + } + + public void assertJavadoc(String code, String... expected) { + int cursor = code.indexOf('|'); + code = code.replace("|", ""); + assertTrue(cursor > -1, "'|' expected, but not found in: " + code); + List documentation = getAnalysis().documentation(code, cursor, true); + Set docSet = documentation.stream() + .map(doc -> doc.signature() + "\n" + doc.javadoc()) + .collect(Collectors.toSet()); Set expectedSet = Stream.of(expected).collect(Collectors.toSet()); assertEquals(docSet, expectedSet, "Input: " + code); } public enum ClassType { - CLASS("CLASS_SUBKIND") { - @Override - public String toString() { - return "class"; - } - }, - ENUM("ENUM_SUBKIND") { - @Override - public String toString() { - return "enum"; - } - }, - INTERFACE("INTERFACE_SUBKIND") { - @Override - public String toString() { - return "interface"; - } - }, - ANNOTATION("ANNOTATION_TYPE_SUBKIND") { - @Override - public String toString() { - return "@interface"; - } - }; + CLASS("CLASS_SUBKIND", "class", "class"), + ENUM("ENUM_SUBKIND", "enum", "enum"), + INTERFACE("INTERFACE_SUBKIND", "interface", "interface"), + ANNOTATION("ANNOTATION_TYPE_SUBKIND", "@interface", "annotation interface"); private final String classType; + private final String name; + private final String displayed; - ClassType(String classType) { + ClassType(String classType, String name, String displayed) { this.classType = classType; + this.name = name; + this.displayed = displayed; } public String getClassType() { return classType; } + public String getDisplayed() { + return displayed; + } + @Override - public abstract String toString(); + public String toString() { + return name; + } } public static MemberInfo variable(String type, String name) { diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/MethodsTest.java --- a/langtools/test/jdk/jshell/MethodsTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/jdk/jshell/MethodsTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -23,7 +23,7 @@ /* * @test - * @bug 8080357 + * @bug 8080357 8167643 * @summary Tests for EvaluationState.methods * @build KullaTesting TestingInputStream ExpectedDiagnostic * @run testng MethodsTest @@ -230,31 +230,30 @@ assertActiveKeys(); } - public void methodsWarn() { - Snippet f = assertDeclareWarn1("public String f() {return null;}", - new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 6, 0, -1, -1, Diagnostic.Kind.WARNING), - added(VALID)); + + public void methodsAccessModifierIgnored() { + Snippet f = methodKey(assertEval("public String f() {return null;}", + added(VALID))); assertNumberOfActiveMethods(1); assertActiveKeys(); - f = assertDeclareWarn1("protected String f() {return null;}", - new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 9, 0, -1, -1, Diagnostic.Kind.WARNING), + f = methodKey(assertEval("protected String f() {return null;}", + ste(MAIN_SNIPPET, VALID, VALID, false, null), + ste(f, VALID, OVERWRITTEN, false, MAIN_SNIPPET))); + assertNumberOfActiveMethods(1); + assertActiveKeys(); + + assertEval("private String f() {return null;}", ste(MAIN_SNIPPET, VALID, VALID, false, null), ste(f, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); assertNumberOfActiveMethods(1); assertActiveKeys(); + } - f = assertDeclareWarn1("private String f() {return null;}", - new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 7, 0, -1, -1, Diagnostic.Kind.WARNING), - ste(MAIN_SNIPPET, VALID, VALID, false, null), - ste(f, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); - assertNumberOfActiveMethods(1); - assertActiveKeys(); - - f = assertDeclareWarn1("static String f() {return null;}", + public void methodsWarn() { + Snippet f = assertDeclareWarn1("static String f() {return null;}", new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 6, 0, -1, -1, Diagnostic.Kind.WARNING), - ste(MAIN_SNIPPET, VALID, VALID, false, null), - ste(f, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); + added(VALID)); assertNumberOfActiveMethods(1); assertActiveKeys(); diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/ModifiersTest.java --- a/langtools/test/jdk/jshell/ModifiersTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/jdk/jshell/ModifiersTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -22,7 +22,7 @@ */ /* - * @test + * @test 8167643 8129559 * @summary Tests for modifiers * @build KullaTesting TestingInputStream ExpectedDiagnostic * @run testng ModifiersTest @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; import javax.tools.Diagnostic; import org.testng.annotations.DataProvider; @@ -43,22 +44,55 @@ public Object[][] getTestCases() { List testCases = new ArrayList<>(); String[] ignoredModifiers = new String[] { - "public", "protected", "private", "static", "final" + "static", "final" + }; + String[] silentlyIgnoredModifiers = new String[] { + "public", "protected", "private" }; + String[] before = new String[] { + "strictfp", "abstract", "@X", "@X(value=9)" + }; + String context = "@interface X { int value() default 0; }"; + Consumer eval = this::assertEval; + Consumer evalWarn = s -> assertDeclareWarn1(s, "jdk.eval.warn.illegal.modifiers"); for (String ignoredModifier : ignoredModifiers) { for (ClassType classType : ClassType.values()) { - testCases.add(new Object[] { ignoredModifier, classType }); + testCases.add(new Object[] { ignoredModifier, classType, evalWarn, "", null }); + } + } + for (String ignoredModifier : ignoredModifiers) { + for (String preface : before) { + testCases.add(new Object[] { ignoredModifier, ClassType.CLASS, evalWarn, preface, context}); + } + } + for (String ignoredModifier : silentlyIgnoredModifiers) { + for (ClassType classType : ClassType.values()) { + testCases.add(new Object[] { ignoredModifier, classType, eval, "", null }); + } + } + for (String ignoredModifier : silentlyIgnoredModifiers) { + for (String preface : before) { + testCases.add(new Object[] { ignoredModifier, ClassType.CLASS, eval, preface, context}); } } return testCases.toArray(new Object[testCases.size()][]); } @Test(dataProvider = "ignoredModifiers") - public void ignoredModifiers(String modifier, ClassType classType) { - assertDeclareWarn1( - String.format("%s %s A {}", modifier, classType), "jdk.eval.warn.illegal.modifiers"); - assertNumberOfActiveClasses(1); - assertClasses(clazz(classType, "A")); + public void ignoredModifiers(String modifier, ClassType classType, + Consumer eval, String preface, String context) { + if (context != null) { + assertEval(context); + } + String decl = String.format("%s %s %s A {}", preface, modifier, classType); + eval.accept(decl); + if (context != null) { + assertNumberOfActiveClasses(2); + assertClasses(clazz(ClassType.ANNOTATION, "X"), clazz(classType, "A")); + } else { + assertNumberOfActiveClasses(1); + assertClasses(clazz(classType, "A")); + } assertActiveKeys(); } diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/ToolBasicTest.java --- a/langtools/test/jdk/jshell/ToolBasicTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/jdk/jshell/ToolBasicTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -23,7 +23,7 @@ /* * @test - * @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 8148316 8148317 8143955 8157953 8080347 8154714 + * @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 8148316 8148317 8143955 8157953 8080347 8154714 8166649 8167643 * @summary Tests for Basic tests for REPL tool * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main @@ -289,6 +289,21 @@ ); } + public void testModulePath() { + Compiler compiler = new Compiler(); + Path modsDir = Paths.get("mods"); + Path outDir = Paths.get("mods", "org.astro"); + compiler.compile(outDir, "package org.astro; public class World { public static String name() { return \"world\"; } }"); + compiler.compile(outDir, "module org.astro { exports org.astro; }"); + Path modsPath = compiler.getPath(modsDir); + test(new String[] { "--module-path", modsPath.toString(), "--add-modules", "org.astro" }, + (a) -> assertCommand(a, "import org.astro.World;", ""), + (a) -> evaluateExpression(a, "String", + "String.format(\"Greetings %s!\", World.name());", + "\"Greetings world!\"") + ); + } + public void testStartupFileOption() { try { Compiler compiler = new Compiler(); @@ -505,7 +520,7 @@ a -> assertCommand(a, "int a", ""), a -> assertCommand(a, "void f() {}", ""), a -> assertCommandCheckOutput(a, "aaaa", assertStartsWith("| Error:")), - a -> assertCommandCheckOutput(a, "public void f() {}", assertStartsWith("| Warning:")) + a -> assertCommandCheckOutput(a, "static void f() {}", assertStartsWith("| Warning:")) ); } } diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/ToolFormatTest.java --- a/langtools/test/jdk/jshell/ToolFormatTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/jdk/jshell/ToolFormatTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -23,7 +23,7 @@ /* * @test - * @bug 8148316 8148317 8151755 8152246 8153551 8154812 8157261 8163840 + * @bug 8148316 8148317 8151755 8152246 8153551 8154812 8157261 8163840 8166637 8161969 * @summary Tests for output customization * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -220,8 +220,8 @@ test( (a) -> assertCommandOutputStartsWith(a, "/set feedback normal", ""), (a) -> assertCommand(a, "String s = java.util.stream.IntStream.range(65, 74)"+ - ".mapToObj(i -> \"\"+(char)i).reduce((a,b) -> a + b + a).get()", - "s ==> \"ABACABADABACABAEABACABADABACABAFABACABADABACABAEABACABADABACABAGABACABADABA ..."), + ".mapToObj(i -> \"\"+(char)i).reduce((a,b) -> a + b + a).get() + \"XYZ\"", + "s ==> \"ABACABADABACABAEABACABADABACABAFABACABADABACABAE ... BACABAEABACABADABACABAXYZ\""), (a) -> assertCommandOutputStartsWith(a, "/set mode test -quiet", ""), (a) -> assertCommandOutputStartsWith(a, "/set feedback test", ""), (a) -> assertCommand(a, "/set format test display '{type}:{value}' primary", ""), @@ -234,8 +234,9 @@ "/set truncation test 10 varvalue"), (a) -> assertCommandOutputContains(a, "/set truncation test", "/set truncation test 10 varvalue"), - (a) -> assertCommand(a, "String r = s", "String:\"ABACABADABACABA ..."), - (a) -> assertCommand(a, "r", "String:\"ABACA ..."), + (a) -> assertCommand(a, "/var", "| String s = \"ABACABADA"), + (a) -> assertCommand(a, "String r = s", "String:\"ABACABAD ... BAXYZ\""), + (a) -> assertCommand(a, "r", "String:\"ABACABADA"), (a) -> assertCommand(a, "r=s", "String:\"AB") ); } finally { diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/ToolRetainTest.java --- a/langtools/test/jdk/jshell/ToolRetainTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/jdk/jshell/ToolRetainTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -23,13 +23,14 @@ /* * @test - * @bug 8157200 8163840 + * @bug 8157200 8163840 8154513 * @summary Tests of what information is retained across jshell tool runs * @modules jdk.jshell/jdk.internal.jshell.tool * @build ToolRetainTest ReplToolTesting * @run testng ToolRetainTest */ +import java.util.Locale; import org.testng.annotations.Test; @Test @@ -62,14 +63,14 @@ (a) -> assertCommand(a, "/set mode -retain trm1", ""), (a) -> assertCommand(a, "/exit", "") ); - test( + test(Locale.ROOT, true, new String[0], "", (a) -> assertCommand(a, "/set mode trm2 -quiet", ""), (a) -> assertCommand(a, "/set format trm2 display '{name}={value}'", ""), (a) -> assertCommand(a, "int x = 45", "x:45"), (a) -> assertCommand(a, "/set mode -retain trm2", ""), (a) -> assertCommand(a, "/exit", "") ); - test( + test(Locale.ROOT, true, new String[0], "", (a) -> assertCommandOutputContains(a, "/set mode trm1", "/set format trm1 display \"{name}:{value}\""), (a) -> assertCommand(a, "/set format trm2 display", diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/ToolSimpleTest.java --- a/langtools/test/jdk/jshell/ToolSimpleTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/jdk/jshell/ToolSimpleTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -23,7 +23,7 @@ /* * @test - * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 + * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 * @summary Simple jshell tool tests * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main @@ -35,6 +35,7 @@ import java.util.Arrays; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -465,14 +466,14 @@ } public void testOptionQ() { - test(new String[]{"-q", "--no-startup"}, + test(Locale.ROOT, false, new String[]{"-q", "--no-startup"}, "", (a) -> assertCommand(a, "1+1", "$1 ==> 2"), (a) -> assertCommand(a, "int x = 5", "") ); } public void testOptionS() { - test(new String[]{"-s", "--no-startup"}, + test(Locale.ROOT, false, new String[]{"-s", "--no-startup"}, "", (a) -> assertCommand(a, "1+1", "") ); } @@ -486,7 +487,7 @@ } public void testOptionFeedback() { - test(new String[]{"--feedback", "concise", "--no-startup"}, + test(Locale.ROOT, false, new String[]{"--feedback", "concise", "--no-startup"}, "", (a) -> assertCommand(a, "1+1", "$1 ==> 2"), (a) -> assertCommand(a, "int x = 5", "") ); @@ -498,17 +499,17 @@ .filter(l -> !l.isEmpty()) .count(), "Expected no lines: " + s); }; - test(new String[]{"-nq"}, + test(Locale.ROOT, false, new String[]{"-nq"}, "", (a) -> assertCommandCheckOutput(a, "/list -all", confirmNoStartup), (a) -> assertCommand(a, "1+1", "$1 ==> 2"), (a) -> assertCommand(a, "int x = 5", "") ); - test(new String[]{"-qn"}, + test(Locale.ROOT, false, new String[]{"-qn"}, "", (a) -> assertCommandCheckOutput(a, "/list -all", confirmNoStartup), (a) -> assertCommand(a, "1+1", "$1 ==> 2"), (a) -> assertCommand(a, "int x = 5", "") ); - test(new String[]{"-ns"}, + test(Locale.ROOT, false, new String[]{"-ns"}, "", (a) -> assertCommandCheckOutput(a, "/list -all", confirmNoStartup), (a) -> assertCommand(a, "1+1", "") ); diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/UserJDIUserRemoteTest.java --- a/langtools/test/jdk/jshell/UserJDIUserRemoteTest.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,286 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - /* - * @test - * @bug 8160128 8159935 - * @summary Tests for Aux channel, custom remote agents, custom JDI implementations. - * @build KullaTesting ExecutionControlTestBase - * @run testng UserJDIUserRemoteTest - */ -import java.io.ByteArrayOutputStream; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeMethod; -import jdk.jshell.Snippet; -import static jdk.jshell.Snippet.Status.OVERWRITTEN; -import static jdk.jshell.Snippet.Status.VALID; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; -import java.net.ServerSocket; -import java.util.ArrayList; -import java.util.List; -import com.sun.jdi.VMDisconnectedException; -import com.sun.jdi.VirtualMachine; -import jdk.jshell.VarSnippet; -import jdk.jshell.execution.DirectExecutionControl; -import jdk.jshell.execution.JDIExecutionControl; -import jdk.jshell.execution.JDIInitiator; -import jdk.jshell.execution.Util; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.net.Socket; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Consumer; -import jdk.jshell.spi.ExecutionControl; -import jdk.jshell.spi.ExecutionControl.ExecutionControlException; -import jdk.jshell.spi.ExecutionEnv; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; -import static jdk.jshell.execution.Util.forwardExecutionControlAndIO; -import static jdk.jshell.execution.Util.remoteInputOutput; - -@Test -public class UserJDIUserRemoteTest extends ExecutionControlTestBase { - - ExecutionControl currentEC; - ByteArrayOutputStream auxStream; - - @BeforeMethod - @Override - public void setUp() { - auxStream = new ByteArrayOutputStream(); - setUp(builder -> builder.executionEngine(MyExecutionControl.create(this))); - } - - public void testVarValue() { - VarSnippet dv = varKey(assertEval("double aDouble = 1.5;")); - String vd = getState().varValue(dv); - assertEquals(vd, "1.5"); - assertEquals(auxStream.toString(), "aDouble"); - } - - public void testExtension() throws ExecutionControlException { - assertEval("42;"); - Object res = currentEC.extensionCommand("FROG", "test"); - assertEquals(res, "ribbit"); - } - - public void testRedefine() { - Snippet vx = varKey(assertEval("int x;")); - Snippet mu = methodKey(assertEval("int mu() { return x * 4; }")); - Snippet c = classKey(assertEval("class C { String v() { return \"#\" + mu(); } }")); - assertEval("C c0 = new C();"); - assertEval("c0.v();", "\"#0\""); - assertEval("int x = 10;", "10", - ste(MAIN_SNIPPET, VALID, VALID, false, null), - ste(vx, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); - assertEval("c0.v();", "\"#40\""); - assertEval("C c = new C();"); - assertEval("c.v();", "\"#40\""); - assertEval("int mu() { return x * 3; }", - ste(MAIN_SNIPPET, VALID, VALID, false, null), - ste(mu, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); - assertEval("c.v();", "\"#30\""); - assertEval("class C { String v() { return \"@\" + mu(); } }", - ste(MAIN_SNIPPET, VALID, VALID, false, null), - ste(c, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); - assertEval("c0.v();", "\"@30\""); - assertEval("c = new C();"); - assertEval("c.v();", "\"@30\""); - assertActiveKeys(); - } -} - -class MyExecutionControl extends JDIExecutionControl { - - private static final String REMOTE_AGENT = MyRemoteExecutionControl.class.getName(); - - private VirtualMachine vm; - private Process process; - - /** - * Creates an ExecutionControl instance based on a JDI - * {@code LaunchingConnector}. - * - * @return the generator - */ - public static ExecutionControl.Generator create(UserJDIUserRemoteTest test) { - return env -> make(env, test); - } - - /** - * Creates an ExecutionControl instance based on a JDI - * {@code ListeningConnector} or {@code LaunchingConnector}. - * - * Initialize JDI and use it to launch the remote JVM. Set-up a socket for - * commands and results. This socket also transports the user - * input/output/error. - * - * @param env the context passed by - * {@link jdk.jshell.spi.ExecutionControl#start(jdk.jshell.spi.ExecutionEnv) } - * @return the channel - * @throws IOException if there are errors in set-up - */ - static ExecutionControl make(ExecutionEnv env, UserJDIUserRemoteTest test) throws IOException { - try (final ServerSocket listener = new ServerSocket(0)) { - // timeout after 60 seconds - listener.setSoTimeout(60000); - int port = listener.getLocalPort(); - - // Set-up the JDI connection - List opts = new ArrayList<>(env.extraRemoteVMOptions()); - opts.add("-classpath"); - opts.add(System.getProperty("java.class.path") - + System.getProperty("path.separator") - + System.getProperty("user.dir")); - JDIInitiator jdii = new JDIInitiator(port, - opts, REMOTE_AGENT, true, null); - VirtualMachine vm = jdii.vm(); - Process process = jdii.process(); - - List> deathListeners = new ArrayList<>(); - deathListeners.add(s -> env.closeDown()); - Util.detectJDIExitEvent(vm, s -> { - for (Consumer h : deathListeners) { - h.accept(s); - } - }); - - // Set-up the commands/reslts on the socket. Piggy-back snippet - // output. - Socket socket = listener.accept(); - // out before in -- match remote creation so we don't hang - OutputStream out = socket.getOutputStream(); - Map outputs = new HashMap<>(); - outputs.put("out", env.userOut()); - outputs.put("err", env.userErr()); - outputs.put("aux", test.auxStream); - Map input = new HashMap<>(); - input.put("in", env.userIn()); - ExecutionControl myec = remoteInputOutput(socket.getInputStream(), out, outputs, input, (objIn, objOut) -> new MyExecutionControl(objOut, objIn, vm, process, deathListeners)); - test.currentEC = myec; - return myec; - } - } - - /** - * Create an instance. - * - * @param out the output for commands - * @param in the input for responses - */ - private MyExecutionControl(ObjectOutput out, ObjectInput in, - VirtualMachine vm, Process process, - List> deathListeners) { - super(out, in); - this.vm = vm; - this.process = process; - deathListeners.add(s -> disposeVM()); - } - - @Override - public void close() { - super.close(); - disposeVM(); - } - - private synchronized void disposeVM() { - try { - if (vm != null) { - vm.dispose(); // This could NPE, so it is caught below - vm = null; - } - } catch (VMDisconnectedException ex) { - // Ignore if already closed - } catch (Throwable e) { - fail("disposeVM threw: " + e); - } finally { - if (process != null) { - process.destroy(); - process = null; - } - } - } - - @Override - protected synchronized VirtualMachine vm() throws EngineTerminationException { - if (vm == null) { - throw new EngineTerminationException("VM closed"); - } else { - return vm; - } - } - -} - -class MyRemoteExecutionControl extends DirectExecutionControl implements ExecutionControl { - - static PrintStream auxPrint; - - /** - * Launch the agent, connecting to the JShell-core over the socket specified - * in the command-line argument. - * - * @param args standard command-line arguments, expectation is the socket - * number is the only argument - * @throws Exception any unexpected exception - */ - public static void main(String[] args) throws Exception { - try { - String loopBack = null; - Socket socket = new Socket(loopBack, Integer.parseInt(args[0])); - InputStream inStream = socket.getInputStream(); - OutputStream outStream = socket.getOutputStream(); - Map> outputs = new HashMap<>(); - outputs.put("out", st -> System.setOut(new PrintStream(st, true))); - outputs.put("err", st -> System.setErr(new PrintStream(st, true))); - outputs.put("aux", st -> { auxPrint = new PrintStream(st, true); }); - Map> input = new HashMap<>(); - input.put("in", st -> System.setIn(st)); - forwardExecutionControlAndIO(new MyRemoteExecutionControl(), inStream, outStream, outputs, input); - } catch (Throwable ex) { - throw ex; - } - } - - @Override - public String varValue(String className, String varName) - throws RunException, EngineTerminationException, InternalException { - auxPrint.print(varName); - return super.varValue(className, varName); - } - - @Override - public Object extensionCommand(String className, Object arg) - throws RunException, EngineTerminationException, InternalException { - if (!arg.equals("test")) { - throw new InternalException("expected extensionCommand arg to be 'test' got: " + arg); - } - return "ribbit"; - } - -} diff -r f71b844f33d1 -r 95af45781076 langtools/test/jdk/jshell/UserJdiUserRemoteTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/jdk/jshell/UserJdiUserRemoteTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @bug 8160128 8159935 + * @summary Tests for Aux channel, custom remote agents, custom JDI implementations. + * @build KullaTesting ExecutionControlTestBase + * @run testng UserJdiUserRemoteTest + */ +import java.io.ByteArrayOutputStream; +import org.testng.annotations.Test; +import org.testng.annotations.BeforeMethod; +import jdk.jshell.Snippet; +import static jdk.jshell.Snippet.Status.OVERWRITTEN; +import static jdk.jshell.Snippet.Status.VALID; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.net.ServerSocket; +import java.util.ArrayList; +import java.util.List; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.VirtualMachine; +import jdk.jshell.VarSnippet; +import jdk.jshell.execution.DirectExecutionControl; +import jdk.jshell.execution.JdiExecutionControl; +import jdk.jshell.execution.JdiInitiator; +import jdk.jshell.execution.Util; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.net.Socket; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; +import jdk.jshell.spi.ExecutionControl; +import jdk.jshell.spi.ExecutionControl.ExecutionControlException; +import jdk.jshell.spi.ExecutionEnv; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; +import static jdk.jshell.execution.Util.forwardExecutionControlAndIO; +import static jdk.jshell.execution.Util.remoteInputOutput; + +@Test +public class UserJdiUserRemoteTest extends ExecutionControlTestBase { + + ExecutionControl currentEC; + ByteArrayOutputStream auxStream; + + @BeforeMethod + @Override + public void setUp() { + auxStream = new ByteArrayOutputStream(); + setUp(builder -> builder.executionEngine(MyExecutionControl.create(this))); + } + + public void testVarValue() { + VarSnippet dv = varKey(assertEval("double aDouble = 1.5;")); + String vd = getState().varValue(dv); + assertEquals(vd, "1.5"); + assertEquals(auxStream.toString(), "aDouble"); + } + + public void testExtension() throws ExecutionControlException { + assertEval("42;"); + Object res = currentEC.extensionCommand("FROG", "test"); + assertEquals(res, "ribbit"); + } + + public void testRedefine() { + Snippet vx = varKey(assertEval("int x;")); + Snippet mu = methodKey(assertEval("int mu() { return x * 4; }")); + Snippet c = classKey(assertEval("class C { String v() { return \"#\" + mu(); } }")); + assertEval("C c0 = new C();"); + assertEval("c0.v();", "\"#0\""); + assertEval("int x = 10;", "10", + ste(MAIN_SNIPPET, VALID, VALID, false, null), + ste(vx, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); + assertEval("c0.v();", "\"#40\""); + assertEval("C c = new C();"); + assertEval("c.v();", "\"#40\""); + assertEval("int mu() { return x * 3; }", + ste(MAIN_SNIPPET, VALID, VALID, false, null), + ste(mu, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); + assertEval("c.v();", "\"#30\""); + assertEval("class C { String v() { return \"@\" + mu(); } }", + ste(MAIN_SNIPPET, VALID, VALID, false, null), + ste(c, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); + assertEval("c0.v();", "\"@30\""); + assertEval("c = new C();"); + assertEval("c.v();", "\"@30\""); + assertActiveKeys(); + } +} + +class MyExecutionControl extends JdiExecutionControl { + + private static final String REMOTE_AGENT = MyRemoteExecutionControl.class.getName(); + + private VirtualMachine vm; + private Process process; + + /** + * Creates an ExecutionControl instance based on a JDI + * {@code LaunchingConnector}. + * + * @return the generator + */ + public static ExecutionControl.Generator create(UserJdiUserRemoteTest test) { + return env -> make(env, test); + } + + /** + * Creates an ExecutionControl instance based on a JDI + * {@code ListeningConnector} or {@code LaunchingConnector}. + * + * Initialize JDI and use it to launch the remote JVM. Set-up a socket for + * commands and results. This socket also transports the user + * input/output/error. + * + * @param env the context passed by + * {@link jdk.jshell.spi.ExecutionControl#start(jdk.jshell.spi.ExecutionEnv) } + * @return the channel + * @throws IOException if there are errors in set-up + */ + static ExecutionControl make(ExecutionEnv env, UserJdiUserRemoteTest test) throws IOException { + try (final ServerSocket listener = new ServerSocket(0)) { + // timeout after 60 seconds + listener.setSoTimeout(60000); + int port = listener.getLocalPort(); + + // Set-up the JDI connection + List opts = new ArrayList<>(env.extraRemoteVMOptions()); + opts.add("-classpath"); + opts.add(System.getProperty("java.class.path") + + System.getProperty("path.separator") + + System.getProperty("user.dir")); + JdiInitiator jdii = new JdiInitiator(port, + opts, REMOTE_AGENT, true, null); + VirtualMachine vm = jdii.vm(); + Process process = jdii.process(); + + List> deathListeners = new ArrayList<>(); + deathListeners.add(s -> env.closeDown()); + Util.detectJdiExitEvent(vm, s -> { + for (Consumer h : deathListeners) { + h.accept(s); + } + }); + + // Set-up the commands/reslts on the socket. Piggy-back snippet + // output. + Socket socket = listener.accept(); + // out before in -- match remote creation so we don't hang + OutputStream out = socket.getOutputStream(); + Map outputs = new HashMap<>(); + outputs.put("out", env.userOut()); + outputs.put("err", env.userErr()); + outputs.put("aux", test.auxStream); + Map input = new HashMap<>(); + input.put("in", env.userIn()); + ExecutionControl myec = remoteInputOutput(socket.getInputStream(), out, outputs, input, (objIn, objOut) -> new MyExecutionControl(objOut, objIn, vm, process, deathListeners)); + test.currentEC = myec; + return myec; + } + } + + /** + * Create an instance. + * + * @param out the output for commands + * @param in the input for responses + */ + private MyExecutionControl(ObjectOutput out, ObjectInput in, + VirtualMachine vm, Process process, + List> deathListeners) { + super(out, in); + this.vm = vm; + this.process = process; + deathListeners.add(s -> disposeVM()); + } + + @Override + public void close() { + super.close(); + disposeVM(); + } + + private synchronized void disposeVM() { + try { + if (vm != null) { + vm.dispose(); // This could NPE, so it is caught below + vm = null; + } + } catch (VMDisconnectedException ex) { + // Ignore if already closed + } catch (Throwable e) { + fail("disposeVM threw: " + e); + } finally { + if (process != null) { + process.destroy(); + process = null; + } + } + } + + @Override + protected synchronized VirtualMachine vm() throws EngineTerminationException { + if (vm == null) { + throw new EngineTerminationException("VM closed"); + } else { + return vm; + } + } + +} + +class MyRemoteExecutionControl extends DirectExecutionControl implements ExecutionControl { + + static PrintStream auxPrint; + + /** + * Launch the agent, connecting to the JShell-core over the socket specified + * in the command-line argument. + * + * @param args standard command-line arguments, expectation is the socket + * number is the only argument + * @throws Exception any unexpected exception + */ + public static void main(String[] args) throws Exception { + try { + String loopBack = null; + Socket socket = new Socket(loopBack, Integer.parseInt(args[0])); + InputStream inStream = socket.getInputStream(); + OutputStream outStream = socket.getOutputStream(); + Map> outputs = new HashMap<>(); + outputs.put("out", st -> System.setOut(new PrintStream(st, true))); + outputs.put("err", st -> System.setErr(new PrintStream(st, true))); + outputs.put("aux", st -> { auxPrint = new PrintStream(st, true); }); + Map> input = new HashMap<>(); + input.put("in", st -> System.setIn(st)); + forwardExecutionControlAndIO(new MyRemoteExecutionControl(), inStream, outStream, outputs, input); + } catch (Throwable ex) { + throw ex; + } + } + + @Override + public String varValue(String className, String varName) + throws RunException, EngineTerminationException, InternalException { + auxPrint.print(varName); + return super.varValue(className, varName); + } + + @Override + public Object extensionCommand(String className, Object arg) + throws RunException, EngineTerminationException, InternalException { + if (!arg.equals("test")) { + throw new InternalException("expected extensionCommand arg to be 'test' got: " + arg); + } + return "ribbit"; + } + +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/doclint/moduleTests/bad/module-info.java --- a/langtools/test/tools/doclint/moduleTests/bad/module-info.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/tools/doclint/moduleTests/bad/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -6,7 +6,7 @@ * @modules jdk.compiler/com.sun.tools.doclint * @build DocLintTester * @run main DocLintTester -ref module-info.out module-info.java - * @compile/fail/ref=module-info.javac.out -XDrawDiagnostics -Werror -Xdoclint:all module-info.java + * @compile/fail/ref=module-info.javac.out -XDrawDiagnostics -Werror -Xlint:-options -Xdoclint:all module-info.java */ // missing doc comment diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/doclint/moduleTests/good/module-info.java --- a/langtools/test/tools/doclint/moduleTests/good/module-info.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/tools/doclint/moduleTests/good/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -29,7 +29,7 @@ * @modules jdk.compiler/com.sun.tools.doclint * @build DocLintTester * @run main DocLintTester module-info.java - * @compile -Xdoclint:all -Werror module-info.java + * @compile -Xdoclint:all -Werror -Xlint:-options module-info.java */ /** good module */ diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/AnonymousClass/AnonymousCtorExceptionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/AnonymousClass/AnonymousCtorExceptionTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8166367 + * @summary Missing ExceptionTable attribute in anonymous class constructors + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.jdeps/com.sun.tools.javap + * @build toolbox.ToolBox toolbox.JavapTask + * @run compile -g AnonymousCtorExceptionTest.java + * @run main AnonymousCtorExceptionTest + */ + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +import toolbox.JavapTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class AnonymousCtorExceptionTest { + + AnonymousCtorExceptionTest() throws IOException { + } + + public static void main(String args[]) throws Exception { + + new AnonymousCtorExceptionTest() { + }; + + ToolBox tb = new ToolBox(); + Path classPath = Paths.get(ToolBox.testClasses, "AnonymousCtorExceptionTest$1.class"); + String javapOut = new JavapTask(tb) + .options("-v", "-p") + .classes(classPath.toString()) + .run() + .getOutput(Task.OutputKind.DIRECT); + if (!javapOut.contains("AnonymousCtorExceptionTest$1() throws java.io.IOException;")) + throw new AssertionError("Unexpected output " + javapOut); + if (!javapOut.contains("Exceptions:")) + throw new AssertionError("Unexpected output " + javapOut); + } +} \ No newline at end of file diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/PackageClassAmbiguity/util.out diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/T5003235/T5003235a.java diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/T5003235/T5003235a.out diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/T5003235/T5003235b.java diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/T5003235/T5003235b.out diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/T6403466.java --- a/langtools/test/tools/javac/T6403466.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/tools/javac/T6403466.java Fri Nov 11 16:44:36 2016 +0100 @@ -58,9 +58,7 @@ fm.getJavaFileObjectsFromFiles(Arrays.asList(new File(testSrcDir, self + ".java"))); Iterable options = Arrays.asList( - "--add-exports", - "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED," - + "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", + "--add-exports", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", "--processor-path", testClassDir, "-processor", self, "-s", ".", diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/T8132562/ClassPathWithDoubleQuotesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/T8132562/ClassPathWithDoubleQuotesTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8132562 + * @summary javac fails with CLASSPATH with double-quotes as an environment variable + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @run main ClassPathWithDoubleQuotesTest +*/ + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; + +import toolbox.TestRunner; +import toolbox.JarTask; +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class ClassPathWithDoubleQuotesTest extends TestRunner { + + ToolBox tb; + + private static final String ASrc = "public class A {}"; + private static final String JarSrc = "public class J {}"; + private static final String[] jarArgs = {"cf", "test/J.jar", "-C", "test", "J.java"}; + + public static void main(String... args) throws Exception { + new ClassPathWithDoubleQuotesTest().runTests(); + } + + ClassPathWithDoubleQuotesTest() { + super(System.err); + tb = new ToolBox(); + } + + public void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test + public void test(Path base) throws Exception { + Path current = base.resolve("."); + tb.writeJavaFiles(current, ASrc, JarSrc); + new JarTask(tb).run(jarArgs).writeAll(); + + executeTask(new JavacTask(tb, Task.Mode.EXEC) + .envVar("CLASSPATH", "\"test/J.jar" + File.pathSeparator + "test\"") + .files("test/A.java")); + + executeTask(new JavacTask(tb) + .classpath("\"test/J.jar" + File.pathSeparator + "test\"") + .files("test/A.java")); + } + + void executeTask(JavacTask task) { + boolean isWindows = System.getProperty("os.name").startsWith("Windows"); + Task.Expect whatToExpect = isWindows ? Task.Expect.FAIL : Task.Expect.SUCCESS; + try { + task.run(whatToExpect); + if (isWindows) { + throw new AssertionError("exception must be thrown"); + } + } catch (IllegalArgumentException iae) { + if (!isWindows) { + throw new AssertionError("exception unexpectedly thrown"); + } + } catch (Throwable t) { + throw new AssertionError("unexpected exception thrown"); + } + } +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/diags/Example.java diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/diags/RunExamples.java diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/diags/examples.not-yet.txt diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/diags/examples/BadNameForOption.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/diags/examples/BadNameForOption.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// key: compiler.warn.bad.name.for.option +// options: --add-exports Bad!Name/p=java.base + +class BadNameForOption { } + diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/diags/examples/CantFindModule/CantFindModule.java --- a/langtools/test/tools/javac/diags/examples/CantFindModule/CantFindModule.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// key: compiler.err.cant.find.module -// key: compiler.err.doesnt.exist - -// options: --add-exports undef/undef=ALL-UNNAMED - -import undef.Any; - -class Test {} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/diags/examples/ModuleForOptionNotFound.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/diags/examples/ModuleForOptionNotFound.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// key: compiler.warn.module.for.option.not.found +// key: compiler.err.doesnt.exist + +// options: --add-exports undefModule/undefPackage=ALL-UNNAMED + +import undefPackage.Any; + +class Test {} + diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/ServiceDefinitionInner.java --- a/langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/ServiceDefinitionInner.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// key: compiler.err.service.definition.is.inner -// key: compiler.err.encl.class.required diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/modulesourcepath/m/module-info.java --- a/langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/modulesourcepath/m/module-info.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -module m { - provides p1.C1.InnerDefinition with p2.C2; - exports p1; -} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/modulesourcepath/m/p1/C1.java --- a/langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/modulesourcepath/m/p1/C1.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package p1; - -public class C1 { - public class InnerDefinition {} -} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/modulesourcepath/m/p2/C2.java --- a/langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/modulesourcepath/m/p2/C2.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package p2; - -public class C2 extends p1.C1.InnerDefinition {} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/diags/examples/WrongNumberTypeArgsFragment.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/diags/examples/WrongNumberTypeArgsFragment.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// key: compiler.err.cant.apply.symbol +// key: compiler.misc.wrong.number.type.args + +import java.util.*; + +class WrongNumberTypeArgsFragment { + void test() { + Arrays.asList(""); + } +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/diags/examples/XaddexportsMalformedEntry.java --- a/langtools/test/tools/javac/diags/examples/XaddexportsMalformedEntry.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// key: compiler.err.xaddexports.malformed.entry -// options: --add-exports jdk.compiler/com.sun.tools.javac.util - -public class XaddexportsMalformedEntry { -} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/diags/examples/XaddexportsTooMany.java --- a/langtools/test/tools/javac/diags/examples/XaddexportsTooMany.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// key: compiler.err.xaddexports.too.many -// options: --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED - -public class XaddexportsTooMany { -} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/diags/examples/XaddreadsMalformedEntry.java --- a/langtools/test/tools/javac/diags/examples/XaddreadsMalformedEntry.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// key: compiler.err.xaddreads.malformed.entry -// options: --add-reads jdk.compiler - -public class XaddreadsMalformedEntry { -} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/diags/examples/XaddreadsTooMany.java --- a/langtools/test/tools/javac/diags/examples/XaddreadsTooMany.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// key: compiler.err.xaddreads.too.many -// options: --add-reads jdk.compiler=ALL-UNNAMED --add-reads jdk.compiler=ALL-UNNAMED - -public class XaddreadsTooMany { -} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/generics/inference/8168134/T8168134.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/generics/inference/8168134/T8168134.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8168134 + * @summary Inference: javac incorrectly propagating inner constraint with primitive target + * @compile T8168134.java + */ + +abstract class T8168134 { + interface W {} + abstract B f(W e); + abstract C g(C b, long i); + + void h(W i) { + g("", f(i)); + } +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/meth/BadPolySig.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/meth/BadPolySig.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,12 @@ +/* + * @test + * @bug 8168774 + * @summary Polymorhic signature method check crashes javac + * @compile -Xmodule:java.base BadPolySig.java + */ + +package java.lang.invoke; + +class MethodHandle { + native Object m(); +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/AddExportsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/modules/AddExportsTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test the --add-exports option + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase + * @run main AddExportsTest + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class AddExportsTest extends ModuleTestBase { + + public static void main(String... args) throws Exception { + new AddExportsTest().runTests(); + } + + @Test + public void testEmpty(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, "class Dummy { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + testEmpty(src, classes, "--add-exports", ""); + testEmpty(src, classes, "--add-exports="); + } + + private void testEmpty(Path src, Path classes, String... options) throws Exception { + String log = new JavacTask(tb, Task.Mode.CMDLINE) + .options(options) + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "javac: no value for --add-exports option"); + } + + @Test + public void testEmptyItem(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { }", + "package p1; public class C1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { }", + "package p2; class C2 { p1.C1 c1; }"); + Path src_m3 = src.resolve("m3"); + tb.writeJavaFiles(src_m3, + "module m3 { }", + "package p3; class C3 { p1.C1 c1; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + testEmptyItem(src, classes, "m1/p1=,m2,m3"); + testEmptyItem(src, classes, "m1/p1=m2,,m3"); + testEmptyItem(src, classes, "m1/p1=m2,m3,"); + } + + void testEmptyItem(Path src, Path classes, String option) throws Exception { + new JavacTask(tb) + .options("--module-source-path", src.toString(), + "--add-exports", option) + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + } + + @Test + public void testEmptyList(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + testEmptyList(src, classes, "m1/p1="); + testEmptyList(src, classes, "m1/p1=,"); + } + + void testEmptyList(Path src, Path classes, String option) throws Exception { + String log = new JavacTask(tb, Task.Mode.CMDLINE) + .options("--module-source-path", src.toString(), + "--add-exports", option) + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "javac: bad value for --add-exports option: '" + option + "'"); + } + + @Test + public void testMissingSourceParts(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { }", + "package p2; class C2 { p1.C1 c1; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + testMissingSourcePart(src, classes, "=m2"); + testMissingSourcePart(src, classes, "/=m2"); + testMissingSourcePart(src, classes, "m1/=m2"); + testMissingSourcePart(src, classes, "/p1=m2"); + testMissingSourcePart(src, classes, "m1p1=m2"); + } + + private void testMissingSourcePart(Path src, Path classes, String option) throws Exception { + String log = new JavacTask(tb, Task.Mode.CMDLINE) + .options("--module-source-path", src.toString(), + "--add-exports", option) + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "javac: bad value for --add-exports option: '" + option + "'"); + } + + @Test + public void testBadSourceParts(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { }", + "package p2; class C2 { p1.C1 c1; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + testBadSourcePart(src, classes, "m!/p1=m2", "m!"); + testBadSourcePart(src, classes, "m1/p!=m2", "p!"); + } + + private void testBadSourcePart(Path src, Path classes, String option, String badName) + throws Exception { + String log = new JavacTask(tb, Task.Mode.CMDLINE) + .options("-XDrawDiagnostics", + "--module-source-path", src.toString(), + "--add-exports", option) + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "- compiler.warn.bad.name.for.option: --add-exports, " + badName); + } + + @Test + public void testBadTarget(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + String log = new JavacTask(tb, Task.Mode.CMDLINE) + .options("-XDrawDiagnostics", + "--module-source-path", src.toString(), + "--add-exports", "m1/p1=m!") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "- compiler.warn.bad.name.for.option: --add-exports, m!"); + } + + @Test + public void testSourceNotFound(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + String log = new JavacTask(tb, Task.Mode.CMDLINE) + .options("-XDrawDiagnostics", + "--module-source-path", src.toString(), + "--add-exports", "DoesNotExist/p=m1") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "- compiler.warn.module.for.option.not.found: --add-exports, DoesNotExist"); + } + + @Test + public void testTargetNotFound(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { }", + "package p1; class C1 { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + String log = new JavacTask(tb, Task.Mode.CMDLINE) + .options("-XDrawDiagnostics", + "--module-source-path", src.toString(), + "--add-exports", "m1/p1=DoesNotExist") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "- compiler.warn.module.for.option.not.found: --add-exports, DoesNotExist"); + } + + @Test + public void testDuplicate(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { }", + "package p1; public class C1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { }", + "package p2; class C2 { p1.C1 c1; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + new JavacTask(tb) + .options("--module-source-path", src.toString(), + "--add-exports", "m1/p1=m2,m2") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + } + + @Test + public void testRepeated_SameTarget(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { }", + "package p1; public class C1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { }", + "package p2; class C2 { p1.C1 c1; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + new JavacTask(tb) + .options("--module-source-path", src.toString(), + "--add-exports", "m1/p1=m2", + "--add-exports", "m1/p1=m2") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + } + + @Test + public void testRepeated_DifferentTarget(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { }", + "package p1; public class C1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { }", + "package p2; class C2 { p1.C1 c1; }"); + Path src_m3 = src.resolve("m3"); + tb.writeJavaFiles(src_m3, + "module m3 { }", + "package p3; class C3 { p1.C1 c1; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + new JavacTask(tb) + .options("--module-source-path", src.toString(), + "--add-exports", "m1/p1=m2", + "--add-exports", "m1/p1=m3") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + } +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/AddLimitMods.java diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/AddModulesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/modules/AddModulesTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test the --add-modules option + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase + * @run main AddModulesTest + */ + + +import java.nio.file.Path; + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class AddModulesTest extends ModuleTestBase { + public static void main(String... args) throws Exception { + new AddModulesTest().runTests(); + } + + @Test + public void testEmpty(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, "class Dummy { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + testEmpty(src, classes, "--add-modules", ""); + testEmpty(src, classes, "--add-modules="); + } + + private void testEmpty(Path src, Path classes, String... options) throws Exception { + String log = new JavacTask(tb, Task.Mode.CMDLINE) + .options(options) + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "javac: no value for --add-modules option"); + } + + @Test + public void testEmptyItem(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + testEmptyItem(src, classes, ",m1"); + testEmptyItem(src, classes, "m1,,m2"); + testEmptyItem(src, classes, "m1,"); + } + + private void testEmptyItem(Path src, Path classes, String option) throws Exception { + new JavacTask(tb) + .options("--module-source-path", src.toString(), + "--add-modules", option) + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + } + + @Test + public void testEmptyList(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, "class Dummy { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + String log = new JavacTask(tb, Task.Mode.CMDLINE) + .options("--module-source-path", src.toString(), + "--add-modules", ",") + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "javac: bad value for --add-modules option"); + } + + @Test + public void testInvalidName(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, "class Dummy { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + String log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "--add-modules", "BadModule!") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "- compiler.warn.bad.name.for.option: --add-modules, BadModule!"); + } + + @Test + public void testUnknownName(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, "class Dummy { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + String log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "--add-modules", "DoesNotExist") + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "- compiler.err.module.not.found: DoesNotExist"); + } + + @Test + public void testDuplicate(Path base) throws Exception { + Path src = base.resolve("src"); + + // setup a utility module + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path modules = base.resolve("modules"); + tb.createDirectories(modules); + + new JavacTask(tb) + .options("--module-source-path", src.toString()) + .outdir(modules) + .files(findJavaFiles(src)) + .run() + .writeAll(); + + // now test access to the module + Path src2 = base.resolve("src2"); + tb.writeJavaFiles(src2, + "class Dummy { p1.C1 c1; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + new JavacTask(tb) + .options("--module-path", modules.toString(), + "--add-modules", "m1,m1") + .outdir(classes) + .files(findJavaFiles(src2)) + .run() + .writeAll(); + } + + @Test + public void testRepeatable(Path base) throws Exception { + Path src = base.resolve("src"); + + // setup some utility modules + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { exports p2; }", + "package p2; public class C2 { }"); + Path modules = base.resolve("modules"); + tb.createDirectories(modules); + + new JavacTask(tb) + .options("--module-source-path", src.toString()) + .outdir(modules) + .files(findJavaFiles(src)) + .run() + .writeAll(); + + // now test access to the modules + Path src2 = base.resolve("src2"); + tb.writeJavaFiles(src2, + "class Dummy { p1.C1 c1; p2.C2 c2; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + new JavacTask(tb) + .options("--module-path", modules.toString(), + "--add-modules", "m1", + "--add-modules", "m2") + .outdir(classes) + .files(findJavaFiles(src2)) + .run() + .writeAll(); + } +} + diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/AddReadsTest.java --- a/langtools/test/tools/javac/modules/AddReadsTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/tools/javac/modules/AddReadsTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -28,6 +28,7 @@ * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main * jdk.jdeps/com.sun.tools.javap + * java.desktop * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask toolbox.JavapTask ModuleTestBase * @run main AddReadsTest */ @@ -49,7 +50,6 @@ import toolbox.JavacTask; import toolbox.JavapTask; import toolbox.Task; -import toolbox.ToolBox; public class AddReadsTest extends ModuleTestBase { @@ -80,8 +80,8 @@ .writeAll() .getOutput(Task.OutputKind.DIRECT); - if (!log.contains("Test.java:1:44: compiler.err.not.def.access.package.cant.access: api.Api, api")) - throw new Exception("expected output not found"); + checkOutputContains(log, + "Test.java:1:44: compiler.err.not.def.access.package.cant.access: api.Api, api"); //test add dependencies: new JavacTask(tb) @@ -104,7 +104,8 @@ //cyclic dependencies OK when created through addReads: new JavacTask(tb) - .options("--add-reads", "m2=m1,m1=m2", + .options("--add-reads", "m2=m1", + "--add-reads", "m1=m2", "--module-source-path", src.toString()) .outdir(classes) .files(findJavaFiles(src)) @@ -233,7 +234,8 @@ "package impl; public class Impl { javax.swing.JButton b; }"); new JavacTask(tb) - .options("--add-reads", "java.base=java.desktop", + .options("--add-modules", "java.desktop", + "--add-reads", "java.base=java.desktop", "-Xmodule:java.base") .outdir(classes) .files(findJavaFiles(src)) @@ -308,4 +310,356 @@ .run() .writeAll(); } + + @Test + public void testAddSelf(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + new JavacTask(tb) + .options("--module-source-path", src.toString(), + "--add-reads", "m1=m1") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + } + + @Test + public void testEmpty(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, "class Dummy { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + testEmpty(src, classes, "--add-reads", ""); + testEmpty(src, classes, "--add-reads="); + } + + private void testEmpty(Path src, Path classes, String... options) throws Exception { + String log = new JavacTask(tb, Task.Mode.CMDLINE) + .options(options) + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "javac: no value for --add-reads option"); + } + + @Test + public void testEmptyItem(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { }", + "package p2; class C2 { }"); + Path src_m3 = src.resolve("m3"); + tb.writeJavaFiles(src_m3, + "module m3 { }", + "package p3; class C3 { p1.C1 c1; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + testEmptyItem(src, classes, "m3=,m1"); + testEmptyItem(src, classes, "m3=m1,,m2"); + testEmptyItem(src, classes, "m3=m1,"); + } + + private void testEmptyItem(Path src, Path classes, String option) throws Exception { + new JavacTask(tb) + .options("--module-source-path", src.toString(), + "--add-reads", option) + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + } + + @Test + public void testEmptyList(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { }", + "package p2; class C2 { }"); + Path src_m3 = src.resolve("m3"); + tb.writeJavaFiles(src_m3, + "module m3 { }", + "package p3; class C3 { p1.C1 c1; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + testEmptyList(src, classes, "m3="); + testEmptyList(src, classes, "m3=,"); + } + + private void testEmptyList(Path src, Path classes, String option) throws Exception { + String log = new JavacTask(tb, Task.Mode.CMDLINE) + .options("--module-source-path", src.toString(), + "--add-reads", option) + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "javac: bad value for --add-reads option: '" + option + "'"); + } + + @Test + public void testMultipleAddReads_DifferentModules(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { }", + "package p2; class C2 { p1.C1 c1; }"); + Path src_m3 = src.resolve("m3"); + tb.writeJavaFiles(src_m3, + "module m3 { }", + "package p3; class C3 { p1.C1 c1; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + new JavacTask(tb) + .options("--module-source-path", src.toString(), + "--add-reads", "m2=m1", + "--add-reads", "m3=m1") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + } + + @Test + public void testMultipleAddReads_SameModule(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { exports p2; }", + "package p2; public class C2 { }"); + Path src_m3 = src.resolve("m3"); + tb.writeJavaFiles(src_m3, + "module m3 { }", + "package p3; class C3 { p1.C1 c1; p2.C2 c2; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + new JavacTask(tb) + .options("--module-source-path", src.toString(), + "--add-reads", "m3=m1", + "--add-reads", "m3=m2") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + } + + @Test + public void testDuplicateAddReads_SameOption(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { exports p2; }", + "package p2; class C2 { p1.C1 c1; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + new JavacTask(tb) + .options("--module-source-path", src.toString(), + "--add-reads", "m2=m1,m1") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + } + + @Test + public void testDuplicateAddReads_MultipleOptions(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { }", + "package p2; class C2 { p1.C1 c1; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + new JavacTask(tb) + .options("--module-source-path", src.toString(), + "--add-reads", "m2=m1", + "--add-reads", "m2=m1") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + } + + @Test + public void testRepeatedAddReads(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { exports p2; }", + "package p2; public class C2 { }"); + Path src_m3 = src.resolve("m3"); + tb.writeJavaFiles(src_m3, + "module m3 { }", + "package p3; class C3 { p1.C1 c1; p2.C2 c2; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + new JavacTask(tb) + .options("--module-source-path", src.toString(), + "--add-reads", "m3=m1", + "--add-reads", "m3=m2") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + } + + @Test + public void testNoEquals(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, "class Dummy { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + String log = new JavacTask(tb, Task.Mode.CMDLINE) + .options("-XDrawDiagnostics", + "--add-reads", "m1:m2") + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "javac: bad value for --add-reads option: 'm1:m2'"); + } + + @Test + public void testBadSourceName(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, "class Dummy { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + String log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "--add-reads", "bad*Source=m2") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "- compiler.warn.bad.name.for.option: --add-reads, bad*Source"); + } + + @Test + public void testBadTargetName(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { }", + "package p1; class C1 { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + String log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "--add-reads", "m1=badTarget!") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "- compiler.warn.bad.name.for.option: --add-reads, badTarget!"); + } + + @Test + public void testSourceNameNotFound(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + String log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "--add-reads", "missingSource=m1") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "- compiler.warn.module.for.option.not.found: --add-reads, missingSource"); + } + + @Test + public void testTargetNameNotFound(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { exports p1; }", + "package p1; public class C1 { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + String log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "--add-reads", "m1=missingTarget") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + checkOutputContains(log, + "- compiler.warn.module.for.option.not.found: --add-reads, missingTarget"); + } } diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/AnnotationProcessorsInModulesTest.java --- a/langtools/test/tools/javac/modules/AnnotationProcessorsInModulesTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/tools/javac/modules/AnnotationProcessorsInModulesTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -230,8 +230,7 @@ .run(Task.Expect.FAIL) .writeAll() .getOutputLines(Task.OutputKind.DIRECT); - if (!log.equals(Arrays.asList("- compiler.err.processorpath.no.processormodulepath", - "1 error"))) { + if (!log.equals(Arrays.asList("- compiler.err.processorpath.no.processormodulepath"))) { throw new AssertionError("Unexpected output: " + log); } } diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/AutomaticModules.java diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/EdgeCases.java --- a/langtools/test/tools/javac/modules/EdgeCases.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/tools/javac/modules/EdgeCases.java Fri Nov 11 16:44:36 2016 +0100 @@ -71,21 +71,22 @@ @Test public void testAddExportUndefinedModule(Path base) throws Exception { Path src = base.resolve("src"); - tb.writeJavaFiles(src, "package test; import undef.Any; public class Test {}"); + tb.writeJavaFiles(src, "package test; import undefPackage.Any; public class Test {}"); Path classes = base.resolve("classes"); tb.createDirectories(classes); List log = new JavacTask(tb) - .options("--add-exports", "undef/undef=ALL-UNNAMED", "-XDrawDiagnostics") + .options("--add-exports", "undefModule/undefPackage=ALL-UNNAMED", + "-XDrawDiagnostics") .outdir(classes) .files(findJavaFiles(src)) .run(Task.Expect.FAIL) .writeAll() .getOutputLines(Task.OutputKind.DIRECT); - List expected = Arrays.asList("- compiler.err.cant.find.module: undef", - "Test.java:1:27: compiler.err.doesnt.exist: undef", - "2 errors"); + List expected = Arrays.asList("- compiler.warn.module.for.option.not.found: --add-exports, undefModule", + "Test.java:1:34: compiler.err.doesnt.exist: undefPackage", + "1 error", "1 warning"); if (!expected.equals(log)) throw new Exception("expected output not found: " + log); diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/GraphsTest.java diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/LimitModulesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/modules/LimitModulesTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test the --limit-modules option + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase + * @run main LimitModulesTest + */ + + +import java.nio.file.Path; + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class LimitModulesTest extends ModuleTestBase { + public static void main(String... args) throws Exception { + new LimitModulesTest().runTests(); + } + + @Test + public void testEmpty(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, "class Dummy { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + String log = new JavacTask(tb, Task.Mode.CMDLINE) + .options("--module-source-path", src.toString(), + "--limit-modules", "") + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + if (!log.contains("javac: no value for --limit-modules option")) + throw new Exception("expected output not found"); + + log = new JavacTask(tb, Task.Mode.CMDLINE) + .options("--module-source-path", src.toString(), + "--limit-modules=") + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + if (!log.contains("javac: no value for --limit-modules option")) + throw new Exception("expected output not found"); + } + + @Test + public void testEmptyItem(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + tb.writeJavaFiles(src_m1, + "module m1 { }"); + Path src_m2 = src.resolve("m2"); + tb.writeJavaFiles(src_m2, + "module m2 { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + new JavacTask(tb) + .options("--module-source-path", src.toString(), + "--limit-modules", ",m1") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + + new JavacTask(tb) + .options("--module-source-path", src.toString(), + "--limit-modules", "m1,,m2") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + + new JavacTask(tb) + .options("--module-source-path", src.toString(), + "--limit-modules", "m1,") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + } + + @Test + public void testEmptyList(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, "class Dummy { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + String log = new JavacTask(tb, Task.Mode.CMDLINE) + .options("--module-source-path", src.toString(), + "--limit-modules", ",") + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + if (!log.contains("javac: bad value for --limit-modules option")) + throw new Exception("expected output not found"); + } + + @Test + public void testInvalidName(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, "class Dummy { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + String log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "--limit-modules", "BadModule!") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + if (!log.contains("- compiler.warn.bad.name.for.option: --limit-modules, BadModule!")) + throw new Exception("expected output not found"); + } + + @Test + public void testLastOneWins(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + "package p; class C { com.sun.tools.javac.Main main; }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + System.err.println("case 1:"); + new JavacTask(tb) + .options("-XDrawDiagnostics", + "--limit-modules", "java.base", + "--limit-modules", "jdk.compiler") + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll(); + + System.err.println("case 2:"); + String log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "--limit-modules", "jdk.compiler", + "--limit-modules", "java.base") + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + + if (!log.contains("C.java:1:41: compiler.err.doesnt.exist: com.sun.tools.javac")) + throw new Exception("expected output not found"); + } +} + diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/ModuleTestBase.java --- a/langtools/test/tools/javac/modules/ModuleTestBase.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/tools/javac/modules/ModuleTestBase.java Fri Nov 11 16:44:36 2016 +0100 @@ -53,4 +53,12 @@ Path[] findJavaFiles(Path... paths) throws IOException { return tb.findJavaFiles(paths); } + + void checkOutputContains(String log, String... expect) throws Exception { + for (String e : expect) { + if (!log.contains(e)) { + throw new Exception("expected output not found: " + e); + } + } + } } diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/PackageMultipleModules.java diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/ProvidesTest.java --- a/langtools/test/tools/javac/modules/ProvidesTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/tools/javac/modules/ProvidesTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -24,6 +24,7 @@ /** * @test * @summary simple tests of module provides + * @bug 8168854 * @library /tools/lib * @modules * jdk.compiler/com.sun.tools.javac.api @@ -39,6 +40,7 @@ import toolbox.JavacTask; import toolbox.Task; +import toolbox.Task.Expect; import toolbox.ToolBox; public class ProvidesTest extends ModuleTestBase { @@ -415,24 +417,13 @@ tb.writeJavaFiles(src, "module m { provides p1.C1.InnerDefinition with p2.C2; }", "package p1; public class C1 { public class InnerDefinition { } }", - "package p2; public class C2 extends p1.C1.InnerDefinition { }"); + "package p2; public class C2 extends p1.C1.InnerDefinition { public C2() { new p1.C1().super(); } }"); - List output = new JavacTask(tb) + new JavacTask(tb) .options("-XDrawDiagnostics") .outdir(Files.createDirectories(base.resolve("classes"))) .files(findJavaFiles(src)) - .run(Task.Expect.FAIL) - .writeAll() - .getOutputLines(Task.OutputKind.DIRECT); - - List expected = Arrays.asList( - "module-info.java:1:26: compiler.err.service.definition.is.inner: p1.C1.InnerDefinition", - "module-info.java:1:12: compiler.warn.service.provided.but.not.exported.or.used: p1.C1.InnerDefinition", - "C2.java:1:20: compiler.err.encl.class.required: p1.C1.InnerDefinition", - "2 errors", - "1 warning"); - if (!output.containsAll(expected)) { - throw new Exception("Expected output not found"); - } + .run(Expect.SUCCESS) + .writeAll(); } } diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/RequiresPublicTest.java diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/ResolveTest.java diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/T8168854/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/modules/T8168854/module-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,10 @@ +/* + * @test + * @bug 8168854 + * @summary javac erroneously reject a a service interface inner class in a provides clause + * @compile module-info.java + */ +module mod { + exports pack1; + provides pack1.Outer.Inter with pack1.Outer1.Implem; +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/T8168854/pack1/Outer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/modules/T8168854/pack1/Outer.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pack1; + +public class Outer { + public class Inter { + } +} \ No newline at end of file diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/T8168854/pack1/Outer1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/modules/T8168854/pack1/Outer1.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pack1; + +public class Outer1 { + public static class Implem extends Outer.Inter { + public Implem () { + new Outer().super(); + } + } +} \ No newline at end of file diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/UsesTest.java diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/modules/XModuleTest.java --- a/langtools/test/tools/javac/modules/XModuleTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/tools/javac/modules/XModuleTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -223,8 +223,7 @@ .writeAll() .getOutputLines(Task.OutputKind.DIRECT); - List expected = Arrays.asList("- compiler.err.xmodule.no.module.sourcepath", - "1 error"); + List expected = Arrays.asList("- compiler.err.xmodule.no.module.sourcepath"); if (!expected.equals(log)) throw new Exception("expected output not found: " + log); diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/processing/model/nestedTypeVars/NestedTypeVars.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/processing/model/nestedTypeVars/NestedTypeVars.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @modules jdk.compiler + * @build NestedTypeVars + * @compile/process/ref=NestedTypeVars.out -processor NestedTypeVars Test$1L1$L2$1L3$L4$L5 Test$1L1$CCheck Test$1L1 Test$1CCheck Test$CCheck Test + */ + +import java.util.Set; +import java.util.stream.Collectors; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.TypeParameterElement; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; +import javax.lang.model.util.ElementFilter; + +@SupportedAnnotationTypes("*") +public class NestedTypeVars extends AbstractProcessor{ + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + for (TypeElement te : ElementFilter.typesIn(roundEnv.getRootElements())) { + System.out.print(processingEnv.getElementUtils().getBinaryName(te)); + System.out.print("<"); + String separator = ""; + for (TypeParameterElement tp : te.getTypeParameters()) { + System.out.print(separator); + separator = ", "; + System.out.print(tp.getSimpleName()); + System.out.print(" extends "); + System.out.print(tp.getBounds().stream().map(b -> toString(b)).collect(Collectors.joining("&"))); + } + System.out.println(">"); + for (ExecutableElement m : ElementFilter.methodsIn(te.getEnclosedElements())) { + System.out.print(" <"); + separator = ""; + for (TypeParameterElement tp : m.getTypeParameters()) { + System.out.print(separator); + separator = ", "; + System.out.print(tp.getSimpleName()); + System.out.print(" extends "); + System.out.print(tp.getBounds(). + stream(). + map(b -> toString(b)). + collect(Collectors.joining("&"))); + } + System.out.print(">"); + System.out.println(m.getSimpleName()); + } + } + + return false; + } + + String toString(TypeMirror bound) { + if (bound.getKind() == TypeKind.TYPEVAR) { + TypeVariable var = (TypeVariable) bound; + return toString(var.asElement()); + } + return bound.toString(); + } + + String toString(Element el) { + switch (el.getKind()) { + case METHOD: + return toString(el.getEnclosingElement()) + "." + el.getSimpleName(); + case CLASS: + return processingEnv.getElementUtils().getBinaryName((TypeElement) el).toString(); + case TYPE_PARAMETER: + return toString(((TypeParameterElement) el).getGenericElement()) + "." + el.getSimpleName(); + default: + throw new IllegalStateException("Unexpected element: " + el + "(" + el.getKind() + ")"); + } + } + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + +} + +class Test { + void m() { + class L1 { + class L2 { + void m() { + class L3 { + class L4 { + class L5 {} + } + } + } + } + class CCheck {} + void test() {} + } + class CCheck {} + } + class CCheck {} + void test() {} +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/javac/processing/model/nestedTypeVars/NestedTypeVars.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/processing/model/nestedTypeVars/NestedTypeVars.out Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,9 @@ +Test$1L1$L2$1L3$L4$L5 +Test$1L1$CCheck +Test$1L1 + test +Test$1CCheck +Test$CCheck +Test + m + test diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestLoad.java --- a/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestLoad.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestLoad.java Fri Nov 11 16:44:36 2016 +0100 @@ -23,6 +23,7 @@ /* * @test + * @bug 8145464 8164837 * @summary Test of jdeprscan tool loading and printing to aCSV file. * @modules jdk.jdeps/com.sun.tools.jdeprscan * @library ../../../cases diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java --- a/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java Fri Nov 11 16:44:36 2016 +0100 @@ -23,6 +23,7 @@ /* * @test + * @bug 8145464 8164837 8165646 * @summary Basic test of jdeprscan's scanning phase. * @modules jdk.jdeps/com.sun.tools.jdeprscan * @library ../../../cases @@ -89,6 +90,7 @@ new InputStreamReader( new ByteArrayInputStream(bytes), StandardCharsets.UTF_8)) .lines() + .filter(line -> !line.endsWith(":")) .map(line -> line.split(" +")) .map(array -> array[1]) .collect(Collectors.toSet()); diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/jdeps/lib/JdepsRunner.java --- a/langtools/test/tools/jdeps/lib/JdepsRunner.java Mon Nov 14 11:15:43 2016 +0100 +++ b/langtools/test/tools/jdeps/lib/JdepsRunner.java Fri Nov 11 16:44:36 2016 +0100 @@ -27,16 +27,19 @@ import java.io.StringWriter; import java.util.Arrays; import java.util.List; +import java.util.spi.ToolProvider; import java.util.stream.Collectors; /** * JdepsRunner class to invoke jdeps with the given command line argument */ public class JdepsRunner { + private static final ToolProvider JDEPS_TOOL = ToolProvider.findFirst("jdeps") + .orElseThrow(() -> new RuntimeException("jdeps tool not found")); + public static JdepsRunner run(String... args) { JdepsRunner jdeps = new JdepsRunner(args); - int rc = jdeps.run(); - jdeps.printStdout(System.err); + int rc = jdeps.run(true); if (rc != 0) throw new Error("jdeps failed: rc=" + rc); return jdeps; @@ -46,7 +49,7 @@ final StringWriter stderr = new StringWriter(); final String[] args; public JdepsRunner(String... args) { - System.err.println("jdeps " + Arrays.stream(args) + System.out.println("jdeps " + Arrays.stream(args) .collect(Collectors.joining(" "))); this.args = args; } @@ -60,10 +63,12 @@ } public int run(boolean showOutput) { - try (PrintWriter pw = new PrintWriter(stdout)) { - int rc = com.sun.tools.jdeps.Main.run(args, pw); + try (PrintWriter pwout = new PrintWriter(stdout); + PrintWriter pwerr = new PrintWriter(stderr)) { + int rc = JDEPS_TOOL.run(pwout, pwerr, args); if (showOutput) { - System.err.println(stdout.toString()); + printStdout(System.out); + printStderr(System.out); } return rc; } diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/jdeps/listdeps/ListModuleDeps.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/jdeps/listdeps/ListModuleDeps.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8167057 + * @summary Tests split packages + * @modules java.logging + * java.xml + * jdk.compiler + * jdk.jdeps + * jdk.unsupported + * @library ../lib + * @build CompilerUtils JdepsRunner + * @run testng ListModuleDeps + */ + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +public class ListModuleDeps { + private static final String TEST_SRC = System.getProperty("test.src"); + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path CLASSES_DIR = Paths.get("classes"); + private static final Path LIB_DIR = Paths.get("lib"); + + private static final Path FOO_CLASS = + CLASSES_DIR.resolve("z").resolve("Foo.class"); + private static final Path BAR_CLASS = + CLASSES_DIR.resolve("z").resolve("Bar.class"); + private static final Path UNSAFE_CLASS = + CLASSES_DIR.resolve("z").resolve("UseUnsafe.class"); + + /** + * Compiles classes used by the test + */ + @BeforeTest + public void compileAll() throws Exception { + // compile library + assertTrue(CompilerUtils.compile(Paths.get(TEST_SRC, "src", "lib"), LIB_DIR)); + + // compile classes in unnamed module + assertTrue(CompilerUtils.compile(Paths.get(TEST_SRC, "src", "z"), + CLASSES_DIR, + "-cp", LIB_DIR.toString(), + "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", + "--add-exports=java.base/sun.security.util=ALL-UNNAMED", + "--add-exports=java.xml/jdk.xml.internal=ALL-UNNAMED" + )); + } + + @Test(dataProvider = "listdeps") + public void testListDeps(Path classes, String[] expected) { + JdepsRunner jdeps = JdepsRunner.run( + "--class-path", LIB_DIR.toString(), + "--list-deps", classes.toString() + ); + String[] output = Arrays.stream(jdeps.output()) + .map(s -> s.trim()) + .toArray(String[]::new); + assertEquals(output, expected); + } + + @Test(dataProvider = "reduceddeps") + public void testListReducedDeps(Path classes, String[] expected) { + JdepsRunner jdeps = JdepsRunner.run( + "--class-path", LIB_DIR.toString(), + "--list-reduced-deps", classes.toString() + ); + String[] output = Arrays.stream(jdeps.output()) + .map(s -> s.trim()) + .toArray(String[]::new); + assertEquals(output, expected); + } + + + @DataProvider(name = "listdeps") + public Object[][] listdeps() { + return new Object[][] { + { CLASSES_DIR, new String[] { + "java.base/jdk.internal.misc", + "java.base/sun.security.util", + "java.logging", + "java.sql", + "java.xml/jdk.xml.internal", + "jdk.unsupported", + "unnamed module: lib" + } + }, + + { FOO_CLASS, new String[] { + "java.base", + "java.logging", + "java.sql", + "java.xml", + "unnamed module: lib" + } + }, + + { BAR_CLASS, new String[] { + "java.base/sun.security.util", + "java.xml/jdk.xml.internal", + } + }, + + { UNSAFE_CLASS, new String[] { + "java.base/jdk.internal.misc", + "jdk.unsupported", + } + }, + }; + } + + @DataProvider(name = "reduceddeps") + public Object[][] reduceddeps() { + Path barClass = CLASSES_DIR.resolve("z").resolve("Bar.class"); + + return new Object[][] { + { CLASSES_DIR, new String[] { + "java.base/jdk.internal.misc", + "java.base/sun.security.util", + "java.sql", + "java.xml/jdk.xml.internal", + "jdk.unsupported", + "unnamed module: lib" + } + }, + + + { FOO_CLASS, new String[] { + "java.base", + "java.sql", + "unnamed module: lib" + } + }, + + { BAR_CLASS, new String[] { + "java.base/sun.security.util", + "java.xml/jdk.xml.internal", + } + }, + + { UNSAFE_CLASS, new String[] { + "java.base/jdk.internal.misc", + "jdk.unsupported", + } + }, + }; + } + +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/jdeps/listdeps/src/lib/Lib.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/jdeps/listdeps/src/lib/Lib.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package lib; + +import javax.xml.stream.XMLInputFactory; + +public class Lib { + public static final String isCoalescing = XMLInputFactory.IS_COALESCING; + public static boolean check() { return true; } +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/jdeps/listdeps/src/z/Bar.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/jdeps/listdeps/src/z/Bar.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package z; + +import sun.security.util.HostnameChecker; +import jdk.xml.internal.JdkXmlUtils; + +public class Bar { + // internal API from java.xml + private static final String name = JdkXmlUtils.USE_CATALOG; + + public static void main(String[] argv) throws Exception { + HostnameChecker hc = HostnameChecker.getInstance(HostnameChecker.TYPE_LDAP); + } +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/jdeps/listdeps/src/z/Foo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/jdeps/listdeps/src/z/Foo.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package z; + +import java.sql.Driver; +import java.util.logging.Logger; +import javax.xml.stream.XMLInputFactory; +/* + * Dependences on java.sql and java.logging which can be reduced. + */ +public class Foo { + // dependence to java.logging + static Logger log = Logger.getLogger("foo"); + static final String isCoalescing = XMLInputFactory.IS_COALESCING; + + // dependence to java.sql + public Driver getDriver() { return null; } + + // dependence to same package + public Bar getBar() { return new Bar(); } + + // dependence to module m + public String isCoalescing() { return lib.Lib.isCoalescing; } + + +} diff -r f71b844f33d1 -r 95af45781076 langtools/test/tools/jdeps/listdeps/src/z/UseUnsafe.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/jdeps/listdeps/src/z/UseUnsafe.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package z; + +import sun.misc.Unsafe; +import jdk.internal.misc.VM; + +public class UseUnsafe { + private static Unsafe unsafe = Unsafe.getUnsafe(); + + private static boolean booted = VM.isBooted(); +} diff -r f71b844f33d1 -r 95af45781076 make/Bundles.gmk --- a/make/Bundles.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/make/Bundles.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -256,7 +256,7 @@ $(eval $(call SetupBundleFile, BUILD_DEMOS_BUNDLE, \ BUNDLE_NAME := $(DEMOS_BUNDLE_NAME), \ - FILES := $(call DoubleDollar, $(DEMOS_BUNDLE_FILES)), \ + FILES := $(DEMOS_BUNDLE_FILES), \ BASE_DIR := $(JDK_IMAGE_DIR), \ SUBDIR := $(JDK_BUNDLE_SUBDIR), \ )) @@ -271,7 +271,7 @@ $(eval $(call SetupBundleFile, BUILD_TEST_BUNDLE, \ BUNDLE_NAME := $(TEST_BUNDLE_NAME), \ - FILES := $(call DoubleDollar, $(TEST_BUNDLE_FILES)), \ + FILES := $(TEST_BUNDLE_FILES), \ BASE_DIR := $(TEST_IMAGE_DIR), \ )) diff -r f71b844f33d1 -r 95af45781076 make/CompileJavaModules.gmk --- a/make/CompileJavaModules.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/make/CompileJavaModules.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -95,7 +95,7 @@ ################################################################################ java.desktop_ADD_JAVAC_FLAGS := -Xdoclint:all/protected,-reference \ - '-Xdoclint/package:java.*,javax.*' -Xlint:-deprecation,-exports + '-Xdoclint/package:java.*,javax.*' -Xlint:-deprecation,exports java.desktop_COPY := .gif .png .wav .txt .xml .css .pf java.desktop_CLEAN := iio-plugin.properties cursors.properties @@ -348,7 +348,7 @@ ################################################################################ -jdk.compiler_ADD_JAVAC_FLAGS := -Xdoclint:all/protected '-Xdoclint/package:-com.sun.tools.*' \ +jdk.compiler_ADD_JAVAC_FLAGS := -Xdoclint:all/protected '-Xdoclint/package:-com.sun.tools.*,-jdk.internal.*' \ -XDstringConcat=inline jdk.compiler_CLEAN_FILES := $(wildcard \ $(patsubst %, $(JDK_TOPDIR)/src/jdk.compiler/share/classes/%/*.properties, \ @@ -365,6 +365,10 @@ ################################################################################ +jdk.editpad_COPY := .properties + +################################################################################ + jdk.internal.le_COPY := .properties ################################################################################ @@ -436,10 +440,6 @@ ################################################################################ -jdk.jsobject_ADD_JAVAC_FLAGS := -Xlint:-exports - -################################################################################ - jdk.dev_CLEAN_FILES := $(wildcard \ $(patsubst %, $(JDK_TOPDIR)/src/jdk.dev/share/classes/%/*.properties, \ com/sun/tools/script/shell)) @@ -477,6 +477,13 @@ jdk.localedata_EXCLUDE_FILES += sun/text/resources/ext/BreakIteratorRules_th.java ################################################################################ +# If this is an imported module that has prebuilt classes, only compile +# module-info.java. +ifneq ($(wildcard $(IMPORT_MODULES_CLASSES)/$(MODULE)), ) + $(MODULE)_INCLUDE_FILES := module-info.java +endif + +################################################################################ # Setup the compilation for the module # MODULE_SRC_DIRS := $(call FindModuleSrcDirs, $(MODULE)) diff -r f71b844f33d1 -r 95af45781076 make/CreateJmods.gmk --- a/make/CreateJmods.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/make/CreateJmods.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -36,6 +36,7 @@ ################################################################################ JMODS_DIR := $(IMAGES_OUTPUTDIR)/jmods +JMODS_TEMPDIR := $(SUPPORT_OUTPUTDIR)/jmods LIBS_DIR := $(firstword $(wildcard $(addsuffix /$(MODULE), \ $(SUPPORT_OUTPUTDIR)/modules_libs $(IMPORT_MODULES_LIBS)))) @@ -81,16 +82,19 @@ # Add dependencies on other jmod files. Only java.base needs access to other # jmods. ifeq ($(MODULE), java.base) - ALL_UPGRADEABLE_MODULES = $(call FindAllUpgradeableModules) # When creating a BUILDJDK, we don't need to add hashes to java.base ifneq ($(CREATING_BUILDJDK), true) - DEPS += $(patsubst %, $(JMODS_DIR)/%.jmod, \ - $(filter-out java.base $(ALL_UPGRADEABLE_MODULES), $(call FindAllModules))) + # When creating interim versions of jmods, skip hashes + ifneq ($(INTERIM_JMOD), true) + ALL_UPGRADEABLE_MODULES := $(call FindAllUpgradeableModules) + DEPS += $(patsubst %, $(JMODS_DIR)/%.jmod, \ + $(filter-out java.base $(ALL_UPGRADEABLE_MODULES), $(call FindAllModules))) - EXCLUDE_PATTERN := $(strip $(subst $(SPACE),|,$(strip $(ALL_UPGRADEABLE_MODULES)))) + EXCLUDE_PATTERN := $(strip $(subst $(SPACE),|,$(strip $(ALL_UPGRADEABLE_MODULES)))) - JMOD_FLAGS += --module-path $(JMODS_DIR) \ - --hash-modules '^(?!$(EXCLUDE_PATTERN))' + JMOD_FLAGS += --module-path $(JMODS_DIR) \ + --hash-modules '^(?!$(EXCLUDE_PATTERN))' + endif endif endif @@ -102,13 +106,19 @@ DEPS += $(call CacheFind, $(JDK_OUTPUTDIR)/modules/jdk.jlink/jdk/tools/jmod) endif +# If creating interim versions of jmods, certain files need to be filtered out +# to avoid false incremental rebuilds. +ifeq ($(INTERIM_JMOD), true) + DEPS := $(filter-out $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/classlist, $(DEPS)) +endif + # TODO: What about headers? # Create jmods in a temp dir and then move them into place to keep the # module path in $(IMAGES_OUTPUTDIR)/jmods valid at all times. $(JMODS_DIR)/$(MODULE).jmod: $(DEPS) $(call LogWarn, Creating $(patsubst $(OUTPUT_ROOT)/%, %, $@)) - $(call MakeDir, $(@D) $(SUPPORT_OUTPUTDIR)/jmods) - $(RM) $@ $(SUPPORT_OUTPUTDIR)/jmods/$(notdir $@) + $(call MakeDir, $(JMODS_DIR) $(JMODS_TEMPDIR)) + $(RM) $@ $(JMODS_TEMPDIR)/$(notdir $@) $(JMOD) create \ --module-version $(VERSION_SHORT) \ --os-name $(REQUIRED_OS_NAME) \ @@ -116,10 +126,10 @@ --os-version $(REQUIRED_OS_VERSION) \ --module-path $(JMODS_DIR) \ --exclude '**{_the.*,*.diz,*.debuginfo,*.dSYM/**,*.dSYM,*.pdb,*.map}' \ - $(JMOD_FLAGS) $(SUPPORT_OUTPUTDIR)/jmods/$(notdir $@) - $(MV) $(SUPPORT_OUTPUTDIR)/jmods/$(notdir $@) $@ + $(JMOD_FLAGS) $(JMODS_TEMPDIR)/$(notdir $@) + $(MV) $(JMODS_TEMPDIR)/$(notdir $@) $@ -TARGETS += $(IMAGES_OUTPUTDIR)/jmods/$(MODULE).jmod +TARGETS += $(JMODS_DIR)/$(MODULE).jmod ################################################################################ diff -r f71b844f33d1 -r 95af45781076 make/ExplodedImageOptimize.gmk --- a/make/ExplodedImageOptimize.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/make/ExplodedImageOptimize.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -39,6 +39,7 @@ $(PACKAGES_ATTRIBUTE_TARGET): $(ALL_MODULEINFO_CLASSES) $(BUILD_JIGSAW_CLASSES) $(call LogInfo, Optimizing the exploded image) $(TOOL_ADD_PACKAGES_ATTRIBUTE) $(JDK_OUTPUTDIR) + $(TOUCH) $@ TARGETS := $(PACKAGES_ATTRIBUTE_TARGET) diff -r f71b844f33d1 -r 95af45781076 make/GenerateLinkOptData.gmk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/GenerateLinkOptData.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,88 @@ +# +# Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +################################################################################ +# Generate classlist +################################################################################ + +default: all + +include $(SPEC) +include MakeBase.gmk +include JarArchive.gmk + +################################################################################ +# Create a jar with our generator class. Using a jar is intentional since it +# will load more classes + +$(eval $(call SetupJarArchive, CLASSLIST_JAR, \ + SRCS := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes, \ + INCLUDES := build/tools/classlist, \ + JAR := $(SUPPORT_OUTPUTDIR)/classlist.jar, \ +)) + +TARGETS += $(CLASSLIST_JAR) + +################################################################################ + +LINK_OPT_DIR := $(SUPPORT_OUTPUTDIR)/link_opt +CLASSLIST_FILE := $(LINK_OPT_DIR)/classlist +JLI_TRACE_FILE := $(LINK_OPT_DIR)/jli_trace.out + +# If an external buildjdk has been supplied, we don't build a separate interim +# image, so just use the external build jdk instead. +ifeq ($(EXTERNAL_BUILDJDK), true) + INTERIM_IMAGE_DIR := $(BUILD_JDK) +endif + +$(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXE_SUFFIX) $(CLASSLIST_JAR) + $(call MakeDir, $(LINK_OPT_DIR)) + $(call LogInfo, Generating $(patsubst $(OUTPUT_ROOT)/%, %, $@)) + $(call LogInfo, Generating $(patsubst $(OUTPUT_ROOT)/%, %, $(JLI_TRACE_FILE))) + $(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@ \ + -Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true \ + -cp $(SUPPORT_OUTPUTDIR)/classlist.jar \ + build.tools.classlist.HelloClasslist \ + $(LOG_DEBUG) 2>&1 > $(JLI_TRACE_FILE) + +# The jli trace is created by the same recipe as classlist. By declaring these +# dependencies, make will correctly rebuild both jli trace and classlist +# incrementally using the single recpie above. +$(CLASSLIST_FILE): $(JLI_TRACE_FILE) +$(JLI_TRACE_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXE_SUFFIX) $(CLASSLIST_JAR) + +TARGETS += $(CLASSLIST_FILE) $(JLI_TRACE_FILE) + +# Copy the classlist file into java.base libs +$(eval $(call SetupCopyFiles, COPY_CLASSLIST, \ + FILES := $(CLASSLIST_FILE), \ + DEST := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base, \ +)) + +TARGETS += $(COPY_CLASSLIST) + +################################################################################ + +all: $(TARGETS) diff -r f71b844f33d1 -r 95af45781076 make/Images.gmk --- a/make/Images.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/make/Images.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -113,8 +113,8 @@ JLINK_ORDER_RESOURCES := **module-info.class JLINK_JLI_CLASSES := ifeq ($(ENABLE_GENERATE_CLASSLIST), true) - JLINK_ORDER_RESOURCES += @$(SUPPORT_OUTPUTDIR)/classlist/classlist - JLINK_JLI_CLASSES := --generate-jli-classes=@$(SUPPORT_OUTPUTDIR)/classlist/jli_trace.out + JLINK_ORDER_RESOURCES += @$(SUPPORT_OUTPUTDIR)/link_opt/classlist + JLINK_JLI_CLASSES := --generate-jli-classes=@$(SUPPORT_OUTPUTDIR)/link_opt/jli_trace.out endif JLINK_ORDER_RESOURCES += \ /java.base/java/** \ @@ -142,7 +142,7 @@ $(ECHO) Creating jdk jimage $(RM) -r $(JDK_IMAGE_DIR) $(JLINK_TOOL) --add-modules $(JDK_MODULES_LIST) \ - $(JLINK_JDK_EXTRA_OPTS) \ + $(JLINK_JDK_EXTRA_OPTS) \ --output $(JDK_IMAGE_DIR) $(TOUCH) $@ @@ -152,7 +152,7 @@ $(RM) -r $(JRE_IMAGE_DIR) $(JLINK_TOOL) --add-modules $(JRE_MODULES_LIST) \ $(JLINK_JRE_EXTRA_OPTS) \ - --output $(JRE_IMAGE_DIR) + --output $(JRE_IMAGE_DIR) $(TOUCH) $@ JRE_COMPACT1_IMAGE_DIR := $(JRE_IMAGE_DIR)-compact1 @@ -360,34 +360,15 @@ JDK_TARGETS += $(JDK_IMAGE_DIR)/src.zip ################################################################################ -# classlist - -ifeq ($(ENABLE_GENERATE_CLASSLIST), true) - $(eval $(call SetupCopyFiles, JDK_COPY_CLASSLIST, \ - FILES := $(SUPPORT_OUTPUTDIR)/classlist/classlist, \ - DEST := $(JDK_IMAGE_DIR)/lib, \ - )) - - JDK_TARGETS += $(JDK_COPY_CLASSLIST) - - $(eval $(call SetupCopyFiles, JRE_COPY_CLASSLIST, \ - FILES := $(SUPPORT_OUTPUTDIR)/classlist/classlist, \ - DEST := $(JRE_IMAGE_DIR)/lib, \ - )) - - JRE_TARGETS += $(JRE_COPY_CLASSLIST) -endif - -################################################################################ # /demo dir # Avoid doing the expensive find unless called with "jdk" as target. ifneq ($(filter jdk, $(MAKECMDGOALS)), ) DEMO_FILES := \ $(if $(wildcard $(SUPPORT_OUTPUTDIR)/demos/image), \ - $(call DoubleDollar, $(call DoubleDollar, \ + $(call DoubleDollar, \ $(shell $(FIND) $(SUPPORT_OUTPUTDIR)/demos/image \ - -type f -a ! \( -name "_the*" -o -name "javac_state" \) ))) \ + -type f -a ! \( -name "_the*" -o -name "javac_state" \) )) \ ) ifeq ($(ZIP_EXTERNAL_DEBUG_SYMBOLS), true) diff -r f71b844f33d1 -r 95af45781076 make/InterimImage.gmk --- a/make/InterimImage.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/make/InterimImage.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -36,15 +36,15 @@ INTERIM_MODULES_LIST := $(call CommaList, $(INTERIM_IMAGE_MODULES)) -JMODS := $(patsubst %, $(IMAGES_OUTPUTDIR)/jmods/%.jmod, $(INTERIM_IMAGE_MODULES)) +JMODS := $(patsubst %, $(INTERIM_JMODS_DIR)/%.jmod, $(INTERIM_IMAGE_MODULES)) JLINK_TOOL := $(JLINK) \ - --module-path $(IMAGES_OUTPUTDIR)/jmods \ + --module-path $(INTERIM_JMODS_DIR) \ --endian $(OPENJDK_BUILD_CPU_ENDIAN) $(INTERIM_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(JMODS) \ $(call DependOnVariable, INTERIM_MODULES_LIST) - $(ECHO) Creating interim jimage + $(call LogWarn, Creating interim jimage) $(RM) -r $(INTERIM_IMAGE_DIR) $(JLINK_TOOL) \ --output $(INTERIM_IMAGE_DIR) \ diff -r f71b844f33d1 -r 95af45781076 make/Javadoc.gmk --- a/make/Javadoc.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/make/Javadoc.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -22,140 +22,16 @@ # questions. # +default: all + include $(SPEC) include MakeBase.gmk -################################################################# -# -# CORE_PKGS environment variable has been moved to the following file -# -include CORE_PKGS.gmk -# -# Load environment variables for API package names that are not part of -# the Java SE platform -# -include NON_CORE_PKGS.gmk - - -.SUFFIXES: # Delete the default suffixes -.SUFFIXES: .java - -# -# Definitions for directories -# - -DOCSDIR := $(DOCS_IMAGE_DIR) -DOCSTMPDIR = $(SUPPORT_OUTPUTDIR)/docs - -HOTSPOT_DOCS_IMPORT_PATH=$(HOTSPOT_OUTPUTDIR)/docs - -JAVADOC_CMD = $(JAVA) \ - -Djava.awt.headless=true \ - $(NEW_JAVADOC) - -JAVADOC_CMD_SMALL = $(JAVA_SMALL) \ - -Djava.awt.headless=true \ - $(NEW_JAVADOC) - -# Copyright year for beginning of Java and some of the apis -# (Needed when creating the javadocs) -FIRST_COPYRIGHT_YEAR = 1993 -DOMAPI_FIRST_COPYRIGHT_YEAR = 2005 -MIRROR_FIRST_COPYRIGHT_YEAR = 2004 -DOCLETAPI_FIRST_COPYRIGHT_YEAR = 1993 -TAGLETAPI_FIRST_COPYRIGHT_YEAR = 1993 -JDI_FIRST_COPYRIGHT_YEAR = 1999 -JAAS_FIRST_COPYRIGHT_YEAR = 1998 -JGSS_FIRST_COPYRIGHT_YEAR = 2000 -SMARTCARDIO_FIRST_COPYRIGHT_YEAR = 2005 -HTTPSERVER_FIRST_COPYRIGHT_YEAR = 2005 -MGMT_FIRST_COPYRIGHT_YEAR = 2003 -ATTACH_FIRST_COPYRIGHT_YEAR = 2005 -JCONSOLE_FIRST_COPYRIGHT_YEAR = 2006 -SCTPAPI_FIRST_COPYRIGHT_YEAR = 2009 -TRACING_FIRST_COPYRIGHT_YEAR = 2008 -JSHELLAPI_FIRST_COPYRIGHT_YEAR = 2015 -TREEAPI_FIRST_COPYRIGHT_YEAR = 2005 -NASHORNAPI_FIRST_COPYRIGHT_YEAR = 2014 -DYNALINKAPI_FIRST_COPYRIGHT_YEAR = 2015 -JNLP_FIRST_COPYRIGHT_YEAR = 1998 -PLUGIN2_FIRST_COPYRIGHT_YEAR = 2007 -JDKNET_FIRST_COPYRIGHT_YEAR = 2014 -JACCESSAPI_FIRST_COPYRIGHT_YEAR = 2002 -JSOBJECT_FIRST_COPYRIGHT_YEAR = 1993 - -# Oracle name -FULL_COMPANY_NAME = Oracle and/or its affiliates - -# Copyright address -COMPANY_ADDRESS = 500 Oracle Parkway
    Redwood Shores, CA 94065 USA. - -# The trademark symbol -TRADEMARK = ™ - -# Common copyright lines used -# The word "Copyright" might optionally be a link to the file cpyr.html. -# The first year of copyright may vary or not be available. -# The address to the company might be optional. -COMMA:= , -EMPTY:= -SPACE:=$(EMPTY) $(EMPTY) -COPYRIGHT_SYMBOL = &\#x00a9; -# Macro to construct the copyright line -# (The GNU make 3.78.1 "if" conditional is broken, fixed in GNU make 3.81) -define CopyrightLine # optionalurl optionalfirstyear optionaladdress -$(if $(strip $1),
    Copyright,Copyright) \ -$(COPYRIGHT_SYMBOL) $(if $2,$2${COMMA},) $(COPYRIGHT_YEAR),\ -$(FULL_COMPANY_NAME). $3 All rights reserved. -endef - -# Url to root of documents -DOCSDIR_URL = {@docroot}/$(GET2DOCSDIR) - -# Url to copyright html file -COPYRIGHT_URL = $(DOCSDIR_URL)/legal/cpyr.html - -# Url to bug filing site -BUG_SUBMIT_URL = http://bugreport.java.com/bugreport/ - -# Common line for how to submit a bug or rfe -BUG_SUBMIT_LINE = Submit a bug or feature - -# Url to devdocs page -DOCS_BASE_URL = http://docs.oracle.com/javase/$(VERSION_SPECIFICATION)/docs -DEV_DOCS_URL = $(DOCS_BASE_URL)/index.html - -# Common Java trademark line -JAVA_TRADEMARK_LINE = Java is a trademark or registered trademark of \ -$(FULL_COMPANY_NAME) in the US and other countries. - -################################################################# -# Macros: - +################################################################################ # List of all possible directories for javadoc to look for sources -# NOTE: Quotes are required around sourcepath argument only on Windows. -# Otherwise, you get "No packages or classes specified." due -# to $(PATH_SEP) being interpreted as an end of -# command (newline or shell ; character) -ALL_SOURCE_DIRS := $(wildcard \ - $(SUPPORT_OUTPUTDIR)/gensrc/j* \ - $(if $(IMPORT_MODULES_SRC), $(IMPORT_MODULES_SRC)/*) \ - $(JDK_TOPDIR)/src/*/$(OPENJDK_TARGET_OS)/classes \ - $(JDK_TOPDIR)/src/*/$(OPENJDK_TARGET_OS_TYPE)/classes \ - $(JDK_TOPDIR)/src/*/share/classes \ - $(HOTSPOT_TOPDIR)/src/*/share/classes \ - $(LANGTOOLS_TOPDIR)/src/*/share/classes \ - $(NASHORN_TOPDIR)/src/*/share/classes \ - $(CORBA_TOPDIR)/src/*/share/classes \ - $(JAXP_TOPDIR)/src/*/share/classes \ - $(JAXWS_TOPDIR)/src/*/share/classes \ - $(SUPPORT_OUTPUTDIR)/rmic/j* \ - $(JDK_TOPDIR)/src/*/share/doc/stub \ - ) \ - # - -ALL_MODULE_SOURCE_DIRS := \ +# Allow custom to overwrite. +JAVADOC_SOURCE_DIRS = \ $(SUPPORT_OUTPUTDIR)/gensrc/* \ $(if $(IMPORT_MODULES_SRC), $(IMPORT_MODULES_SRC)/*) \ $(JDK_TOPDIR)/src/*/$(OPENJDK_TARGET_OS)/classes \ @@ -171,181 +47,56 @@ $(JDK_TOPDIR)/src/*/share/doc/stub \ # - -# List with classpath separator between them -EMPTY:= -SPACE:= $(EMPTY) $(EMPTY) -RELEASEDOCS_SOURCEPATH = \ - $(subst $(SPACE),$(PATH_SEP),$(strip $(ALL_SOURCE_DIRS))) - -RELEASEDOCS_MODULESOURCEPATH = \ - $(subst $(SPACE),$(PATH_SEP),$(strip $(ALL_MODULE_SOURCE_DIRS))) - -define prep-target - $(MKDIR) -p $(@D) - $(RM) $@ -endef - -# Prep for javadoc creation, assumes $@ is an index.html file -define prep-javadoc - @if [ -f "$@" -a "$?" != "" ] ; then \ - $(ECHO) "# Dependencies have changed: $?"; \ - fi - $(RM) -r $(@D) - $(MKDIR) -p $(@D) -endef - -$(eval $(call FillCacheFind, $(ALL_SOURCE_DIRS))) -define PackageDependencies - $(call CacheFind, $(wildcard $(foreach p, $(subst .,/,$1), $(addsuffix /$p, $(ALL_SOURCE_DIRS))))) -endef - -# Given a list of packages, add packages that exist to $@, print summary -define PackageFilter # packages - @if [ "$1" != "" ] ; then \ - for p in $1 ; do \ - pd=`$(ECHO) $${p} | $(SED) -e 's@[.]@/@g'`; \ - found="false"; \ - for cp in $(ALL_SOURCE_DIRS) ; do \ - if [ -d $${cp}/$${pd} ] ; then \ - $(ECHO) "$${p}" >> $@; \ - found="true"; \ - break; \ - fi; \ - done; \ - if [ "$${found}" = "false" ] ; then \ - $(ECHO) "WARNING: Package not found: $${p}"; \ - fi; \ - done; \ - fi -endef - -# Print out a summary of the javadoc command about to be run -define JavadocSummary # optionsfile packagesfile - @$(ECHO) "# Running javadoc for $(patsubst $(OUTPUT_ROOT)/%,%,$@)" $(LOG_WARN) - @($(ECHO) "# Options (`$(BASENAME) $1`):"; $(SED) -e 's@^@# @' $1) $(LOG_DEBUG) - @($(ECHO) "# Packages (`$(BASENAME) $2`):";$(SED) -e 's@^@# @' $2) $(LOG_DEBUG) -endef - -# -# Different api directories created from root directory -# -COREAPI_DOCSDIR = $(DOCSDIR)/api -JDK_API_DOCSDIR = $(DOCSDIR)/jdk/api -JRE_API_DOCSDIR = $(DOCSDIR)/jre/api -PLATFORM_DOCSDIR = $(DOCSDIR)/platform - -JAVADOC_ARCHIVE_NAME := jdk-$(VERSION_STRING)-docs.zip -JAVADOC_ARCHIVE_ASSEMBLY_DIR := $(DOCSTMPDIR)/zip-docs -JAVADOC_ARCHIVE_DIR := $(OUTPUT_ROOT)/bundles -JAVADOC_ARCHIVE := $(JAVADOC_ARCHIVE_DIR)/$(JAVADOC_ARCHIVE_NAME) +# Should we use -Xdocrootparent? Allow custom to overwrite. +DOCROOTPARENT_FLAG = TRUE # The core api index file is the target for the core api javadocs rule # and needs to be defined early so that all other javadoc rules may # depend on it. -COREAPI_INDEX_FILE = $(COREAPI_DOCSDIR)/index.html - -# The non-core api javadocs need to be able to access the root of the core -# api directory, so for jdk/api or jre/api to get to the core api/ -# directory we would use this: -JDKJRE2COREAPI = ../../api - -# Common bottom argument -define CommonBottom # year -
    $(call CopyrightLine,,$1,)
    -endef - -# Common trademark bottom argument (Not sure why this is used sometimes) -define CommonTrademarkBottom # year -\ -$(BUG_SUBMIT_LINE)
    $(JAVA_TRADEMARK_LINE)
    \ -$(call CopyrightLine,,$1,$(COMPANY_ADDRESS))\ -
    -endef +CORE_INDEX_FILE := $(JAVADOC_OUTPUTDIR)/api/index.html -# Common echo of option -define OptionOnly # opt - if [ "$(strip $1)" != "" ] ; then \ - $(PRINTF) "%s\n" "$(strip $1)"; \ - fi -endef - -define OptionPair # opt arg - $(PRINTF) "%s '%s'\n" "$(strip $1)" '$(strip $2)' -endef +# Symbols +TRADEMARK := ™ +COPYRIGHT_SYMBOL := &$(HASH)x00a9; +COPYRIGHT_TEXT := Copyright +ALL_RIGHTS_RESERVED := All rights reserved. -define OptionTrip # opt arg arg - $(PRINTF) "%s '%s' '%s'\n" "$(strip $1)" '$(strip $2)' '$(strip $3)' -endef +# URLs +JAVADOC_BASE_URL := http://docs.oracle.com/javase/$(VERSION_SPECIFICATION)/docs +BUG_SUBMIT_URL := http://bugreport.java.com/bugreport/ -# Core api bottom argument (with special sauce) -COREAPI_BOTTOM = $(BUG_SUBMIT_LINE)\ -
    For further API reference and developer documentation, \ -see Java SE Documentation. \ -That documentation contains more detailed, developer-targeted descriptions, \ -with conceptual overviews, definitions of terms, workarounds, \ -and working code examples.
    \ -$(call CopyrightLine,$(COPYRIGHT_URL),$(FIRST_COPYRIGHT_YEAR),)\ -
    - -# Common javadoc options used by all bundles +################################################################################ +# Text snippets -# This flag may be overridden from a custom makefile -DOCROOTPARENT_FLAG = -Xdocrootparent $(DOCS_BASE_URL) +FULL_COMPANY_NAME := Oracle and/or its affiliates +COMPANY_ADDRESS := 500 Oracle Parkway
    Redwood Shores, CA 94065 USA. +BUG_SUBMIT_LINE := Submit a bug or feature +JAVA_TRADEMARK_LINE := Java is a trademark or registered trademark of \ + $(FULL_COMPANY_NAME) in the US and other countries. -define COMMON_JAVADOCFLAGS - $(call OptionOnly,-XDignore.symbol.file=true) ; \ - $(call OptionOnly,-quiet) ; \ - $(call OptionOnly,-use) ; \ - $(call OptionOnly,-keywords) ; \ - $(call OptionOnly,$(DOCROOTPARENT_FLAG)) -endef - -# Common javadoc tags used by all bundles - -# Java language specification cite -TAG_JLS = jls:a:See \ -The Java™ Language Specification: - -# Java virtual machine specification cite -TAG_JVMS = jvms:a:See \ -The Java™ Virtual Machine Specification: +COMMON_BOTTOM_ADDRESS := $(COMPANY_ADDRESS) +COMMON_BOTTOM_TEXT := $(BUG_SUBMIT_LINE)
    $(JAVA_TRADEMARK_LINE) -# In order to get a specific ordering it's necessary to specify the total -# ordering of tags as the tags are otherwise ordered in order of definition. -define COMMON_JAVADOCTAGS - $(call OptionPair,-tag,beaninfo:X) ; \ - $(call OptionPair,-tag,revised:X) ; \ - $(call OptionPair,-tag,since.unbundled:X) ; \ - $(call OptionPair,-tag,spec:X) ; \ - $(call OptionPair,-tag,specdefault:X) ; \ - $(call OptionPair,-tag,Note:X) ; \ - $(call OptionPair,-tag,ToDo:X) ; \ - $(call OptionPair,-tag,apiNote:a:API Note:) ; \ - $(call OptionPair,-tag,implSpec:a:Implementation Requirements:) ; \ - $(call OptionPair,-tag,implNote:a:Implementation Note:) ; \ - $(call OptionPair,-tag,param) ; \ - $(call OptionPair,-tag,return) ; \ - $(call OptionPair,-tag,throws) ; \ - $(call OptionPair,-tag,since) ; \ - $(call OptionPair,-tag,version) ; \ - $(call OptionPair,-tag,serialData) ; \ - $(call OptionPair,-tag,factory) ; \ - $(call OptionPair,-tag,see) ; \ - $(call OptionPair,-tag,$(TAG_JVMS)) ; \ - $(call OptionPair,-tag,$(TAG_JLS)) -endef +CORE_BOTTOM_COPYRIGHT_URL := {@docroot}/../legal/cpyr.html +CORE_BOTTOM_TEXT := $(BUG_SUBMIT_LINE)\ +
    For further API reference and developer documentation, \ +see Java SE \ +Documentation. That documentation contains more detailed, \ +developer-targeted descriptions, with conceptual overviews, definitions of \ +terms, workarounds, and working code examples. - - -# Assume we need a draft format when the version string is not a GA version. -ifeq ($(VERSION_IS_GA), false) +ifeq ($(VERSION_IS_GA), true) + DRAFT_HEADER := + DRAFT_BOTTOM := + DRAFT_WINTITLE := + CORE_TOP_EARLYACCESS := +else + # We need a draft format when not building the GA version. DRAFT_HEADER :=
    DRAFT $(VERSION_STRING) DRAFT_BOTTOM :=
    DRAFT $(VERSION_STRING) DRAFT_WINTITLE := $(VERSION_BUILD) - # Early access top text (not used in FCS releases) - COREAPI_TOP_EARLYACCESS := \ -
    \ + CORE_TOP_EARLYACCESS := \ +
    \
    > $@ +endef -################################################################# +# This function goes to great pains to exactly mimic the old behavior +# in all details, including whitespace. +# Note that COPYRIGHT_YEAR is the current year (from spec.gmk) +# Arguments: +# arg 1: first copyright year +# arg 2: copyright url (optional) +# arg 3: company address (optional) +# arg 4: free-form text snippet (optional) +define GenerateBottom + $(if $(strip $4), $(strip $4))
    $(if \ + $(strip $2),$(COPYRIGHT_TEXT),$(COPYRIGHT_TEXT)) \ + $(COPYRIGHT_SYMBOL) $(strip $1), $(COPYRIGHT_YEAR), \ + $(FULL_COMPANY_NAME). $(strip $3) \ + $(ALL_RIGHTS_RESERVED)$(if $(strip $4), )
    +endef -# -# Default target is same as docs target, create core api and all others it can +# Speed up finding by filling cache +$(eval $(call FillCacheFind, $(wildcard $(JAVADOC_SOURCE_DIRS)))) + +# Prevent # from expanding +EscapeHash = $(subst $(HASH),{hash},$(strip $1)) + +################################################################################ +# Setup make rules for running javadoc. # - -all: docs -docs: coredocs otherdocs - +# Parameter 1 is the name of the rule. This name is used as variable prefix, +# and the targets generated are listed in a variable by that name. Note that +# the index.html file will work as a "touch file" for all the magnitude of +# files that are generated by javadoc. # -# Optional target which bundles all generated javadocs into a zip archive. -# The dependency on docs is handled in Main.gmk. -# - -zip-docs: $(JAVADOC_ARCHIVE) - -############################################################# +# Remaining parameters are named arguments. These include: +# MODULES - Modules to include +# PACKAGES - Packages to include +# PACKAGE_FILTER - Filter for packages +# IS_CORE - Set to TRUE for the Core API package which needs special treatment +# API_ROOT - Where to base the documentation (jre or jdk) +# DEST_DIR - A directory relative to the API root +# OVERVIEW - Path to a html overview file +# TITLE - Default title to use for the more specific versions below +# WINDOW_TITLE - Title to use in -windowtitle. Computed from TITLE if empty. +# HEADER_TITLE - Title to use in -header. Computed from TITLE if empty. +# DOC_TITLE - Title to use in -doctitle. Computed from TITLE if empty. +# FIRST_COPYRIGHT_YEAR - First year this bundle was introduced +# DOCLINT - Doclint level. Defaults to "all". +# DOCLINT_PACKAGES - Optional -Xdoclint/package value +# ENCODING - Change character encoding (defaults to 'ascii') +# SPLIT_INDEX - Enable -splitIndex +# BREAKITERATOR - Enable -breakiterator +# NODEPRECATEDLIST - Enable nodeprecatedlist +# NOINDEX - Enable -noindex and -nonavbar +# BOTTOM_COPYRIGHT_URL - Copyright URL to use in -bottom +# BOTTOM_ADDRESS - Company address to use in -bottom +# BOTTOM_TEXT - Extra text to use in -bottom +# EXTRA_TOP - Additional -top data # -# coredocs -# -COREAPI_DOCTITLE = Java$(TRADEMARK) Platform, Standard Edition \ -$(VERSION_SPECIFICATION)
    API Specification -COREAPI_WINDOWTITLE = Java Platform SE $(VERSION_SPECIFICATION) -COREAPI_HEADER = \ -Java$(TRADEMARK) Platform
    Standard Ed. $(VERSION_SPECIFICATION)
    +SetupJavadocGeneration = $(NamedParamsMacroTemplate) +define SetupJavadocGenerationBody + ifeq ($$($1_IS_CORE), TRUE) + $1_JAVA := $$(JAVA) + $1_OUTPUT_DIRNAME := api + else + $1_JAVA := $$(JAVA_SMALL) + $1_OUTPUT_DIRNAME := $$($1_API_ROOT)/api/$$($1_DEST_DIR) + + ifeq ($$($1_RELATIVE_CORE_DIR),) + # Compute a relative path to core root. + # The non-core api javadocs need to be able to access the root of the core + # api directory, so for jdk/api or jre/api to get to the core api/ + # directory we would use this + # NOTE: Need to be able to override for broken old code in JShell + $1_RELATIVE_CORE_DIR := $$(strip $$(subst $$(call DirToDotDot, \ + $$(JAVADOC_OUTPUTDIR))/,, $$(call DirToDotDot, \ + $$(JAVADOC_OUTPUTDIR)/$$($1_OUTPUT_DIRNAME)))) + endif + + $1_DEPS += $(CORE_INDEX_FILE) + endif -# Overview file for core apis -COREAPI_OVERVIEW = $(JDK_TOPDIR)/src/java.base/share/classes/overview-core.html + ifneq ($$($1_OVERVIEW), ) + $1_DEPS += $$($1_OVERVIEW) + endif + + ifeq ($$($1_ENCODING), ) + $1_ENCODING := ascii + endif + + ifeq ($$($1_DOCLINT), ) + $1_DOCLINT := all + endif + + ifeq ($$($1_DOC_TITLE), ) + $1_DOC_TITLE := $$($1_TITLE) + endif + + ifeq ($$($1_WINDOW_TITLE), ) + $1_WINDOW_TITLE := $$(strip $$(subst $$(TRADEMARK),, $$($1_TITLE))) + endif + + ifeq ($$($1_HEADER_TITLE), ) + $1_HEADER_TITLE := $$(strip $$(subst $$(TRADEMARK),, $$($1_TITLE))) + endif + $1_HEADER := $$($1_HEADER_TITLE) -# The options and packages files -COREAPI_OPTIONS_FILE = $(DOCSTMPDIR)/coredocs.options -COREAPI_PACKAGES_FILE = $(DOCSTMPDIR)/coredocs.packages + $1_BOTTOM := $$(call GenerateBottom, $$($1_FIRST_COPYRIGHT_YEAR), \ + $$($1_BOTTOM_COPYRIGHT_URL), $$($1_BOTTOM_ADDRESS), $$($1_BOTTOM_TEXT)) -# The modules required to be documented -COREAPI_MODULES = java.se.ee + # The index.html, options, and packages files + $1_INDEX_FILE := $$(JAVADOC_OUTPUTDIR)/$$($1_OUTPUT_DIRNAME)/index.html + $1_OPTIONS_FILE := $$(SUPPORT_OUTPUTDIR)/docs/$1.options + $1_PACKAGES_FILE := $$(SUPPORT_OUTPUTDIR)/docs/$1.packages -coredocs: $(COREAPI_INDEX_FILE) + $1_PACKAGES_VARDEPS := $$($1_PACKAGES) $$($1_PACKAGES_SINGLE_CLASS) + $1_PACKAGES_VARDEPS_FILE := $$(call DependOnVariable, $1_PACKAGES_VARDEPS, \ + $$($1_PACKAGES_FILE).vardeps) -# Set relative location to core api document root -$(COREAPI_INDEX_FILE): GET2DOCSDIR=.. + # Rule for creating a file with the package names in it + $$($1_PACKAGES_FILE): $$($1_PACKAGES_VARDEPS_FILE) + $$(call LogInfo, Creating Javadoc package file for $1) + $$(call MakeDir, $$(@D)) + ifeq ($$($1_PACKAGES_SINGLE_CLASS), ) + $$(ECHO) $$($1_PACKAGES) | $$(TR) ' ' '\n' > $$@ + else + # NOTE: This is for backwards compatibility for taglet + $$(ECHO) $$($1_PACKAGES_SINGLE_CLASS) > $$@ + endif -# Run javadoc if the index file is out of date or missing -$(COREAPI_INDEX_FILE): $(COREAPI_OPTIONS_FILE) $(COREAPI_PACKAGES_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(COREAPI_OPTIONS_FILE),$(COREAPI_PACKAGES_FILE)) - $(JAVADOC_CMD) -d $(@D) \ - @$(COREAPI_OPTIONS_FILE) @$(COREAPI_PACKAGES_FILE) + # NOTE: Not including $$($1_EXTRA_TOP) due to $$(HASH) + $1_OPTIONS_VARDEPS := $$(call EscapeHash, \ + $$($DOCROOTPARENT_FLAG) $$(JAVADOC_BASE_URL) $$($1_NO_COMMON_TAGS) \ + $$($1_DOCLINT) $$($1_DOCLINT_PACKAGES) $$(JAVADOC_SOURCE_DIRS) \ + $$($1_MODULES) $$($1_ENCODING) $$($1_NODEPRECATEDLIST) \ + $$($1_BREAKITERATOR) $$($1_SPLIT_INDEX) $$($1_OVERVIEW) \ + $$($1_DOC_TITLE) $$($1_WINDOW_TITLE) $$(DRAFT_WINTITLE) \ + $$($1_HEADER) $$(DRAFT_HEADER) $$($1_NOINDEX) $$($1_EXTRA_TOP_2) \ + $$($1_BOTTOM) $$(DRAFT_BOTTOM)) $$($1_PACKAGE_FILTER) $$($1_RELATIVE_CORE_DIR) \ + $$(JAVADOC_OUTPUTDIR) \ + ) + $1_OPTIONS_VARDEPS_FILE := $$(call DependOnVariable, $1_OPTIONS_VARDEPS, \ + $$($1_OPTIONS_FILE).vardeps) -# Create file with javadoc options in it -$(COREAPI_OPTIONS_FILE): $(COREAPI_OVERVIEW) - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:reference) ; \ - $(call OptionOnly,-Xdoclint/package:-org.omg.*$(COMMA)jdk.internal.logging.*) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(COREAPI_MODULES)) ; \ - $(call OptionPair,-encoding,ISO-8859-1) ; \ - $(call OptionOnly,-splitIndex) ; \ - $(call OptionPair,-overview,$(COREAPI_OVERVIEW)) ; \ - $(call OptionPair,-doctitle,$(COREAPI_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(COREAPI_WINDOWTITLE) $(DRAFT_WINTITLE)) ; \ - $(call OptionPair,-header,$(COREAPI_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(COREAPI_BOTTOM)$(DRAFT_BOTTOM)) ; \ - ) >> $@ - ifdef COREAPI_TOP_EARLYACCESS - @$(call OptionPair,-top,$(COREAPI_TOP_EARLYACCESS)) >> $@ + # Rule for creating a file with javadoc options in it + $$($1_OPTIONS_FILE): $$($1_OPTIONS_VARDEPS_FILE) + $$(call LogInfo, Creating Javadoc options file for $1) + $$(call MakeDir, $$(@D)) + $$(RM) $$@ + $$(call AddOption, -XDignore.symbol.file=true) + ifneq ($$(LOG_LEVEL), trace) + $$(call AddOption, -quiet) + endif + $$(call AddOption, -use) + $$(call AddOption, -keywords) + ifneq ($$($DOCROOTPARENT_FLAG), ) + # NOTE: Argument to -Xdocrootparent is not quoted to keep backwards compatibility. + $$(call AddOption, -Xdocrootparent $(JAVADOC_BASE_URL)) + endif + ifneq ($$($1_NO_COMMON_TAGS), TRUE) + # In order to get a specific ordering it's necessary to specify the total + # ordering of tags as the tags are otherwise ordered in order of definition. + $$(call AddOption, -tag, beaninfo:X) + $$(call AddOption, -tag, revised:X) + $$(call AddOption, -tag, since.unbundled:X) + $$(call AddOption, -tag, spec:X) + $$(call AddOption, -tag, specdefault:X) + $$(call AddOption, -tag, Note:X) + $$(call AddOption, -tag, ToDo:X) + $$(call AddOption, -tag, apiNote:a:API Note:) + $$(call AddOption, -tag, implSpec:a:Implementation Requirements:) + $$(call AddOption, -tag, implNote:a:Implementation Note:) + $$(call AddOption, -tag, param) + $$(call AddOption, -tag, return) + $$(call AddOption, -tag, throws) + $$(call AddOption, -tag, since) + $$(call AddOption, -tag, version) + $$(call AddOption, -tag, serialData) + $$(call AddOption, -tag, factory) + $$(call AddOption, -tag, see) + $$(call AddOption, -tag, \ + jvms:a:See The Java™ Virtual Machine Specification:) + $$(call AddOption, -tag, \ + jls:a:See The Java™ Language Specification:) + endif + $$(call AddOption, -Xdoclint:$$($1_DOCLINT)) + ifneq ($$($1_DOCLINT_PACKAGES), ) + $$(call AddOption, -Xdoclint/package:$$(call CommaList, $$($1_DOCLINT_PACKAGES))) + endif + $$(call AddOption, --system, none) + $$(call AddOption, --module-source-path, $$(subst ",, $$(call PathList, $$(JAVADOC_SOURCE_DIRS)))) + $$(call AddOption, --add-modules, $$(call CommaList, $$($1_MODULES))) + $$(call AddOption, -encoding, $$($1_ENCODING)) + ifneq ($$($1_NODEPRECATEDLIST), ) + $$(call AddOption, -nodeprecatedlist) + endif + ifneq ($$($1_BREAKITERATOR), ) + $$(call AddOption, -breakiterator) + endif + ifneq ($$($1_SPLIT_INDEX), ) + $$(call AddOption, -splitIndex) + endif + ifneq ($$($1_OVERVIEW), ) + $$(call AddOption, -overview, $$($1_OVERVIEW)) + endif + $$(call AddOption, -doctitle, $$($1_DOC_TITLE)) + $$(call AddOption, -windowtitle, $$($1_WINDOW_TITLE) $$(DRAFT_WINTITLE)) + $$(call AddOption, -header, $$($1_HEADER)$$(DRAFT_HEADER)) + ifneq ($$($1_NOINDEX), ) + $$(call AddOption, -nonavbar) + $$(call AddOption, -noindex) + endif + ifneq ($$($1_EXTRA_TOP_2), ) + $$(call AddOption, -top,$$($1_EXTRA_TOP_2)) + endif + $$(call AddOption, -bottom, $$($1_BOTTOM)$$(DRAFT_BOTTOM)) + ifneq ($$($1_PACKAGE_FILTER), ) + $$(call AddOption, -group, Packages, $$($1_PACKAGE_FILTER)) + endif + ifneq ($$($1_RELATIVE_CORE_DIR), ) + $$(call AddOption, -linkoffline, $$($1_RELATIVE_CORE_DIR)/api, $$(JAVADOC_OUTPUTDIR)/api/) + endif + ifneq ($$($1_EXTRA_TOP), ) + $$(call AddOption, -top, $$($1_EXTRA_TOP)) endif -# Create a file with the package names in it -$(COREAPI_PACKAGES_FILE): $(call PackageDependencies,$(CORE_PKGS)) - $(prep-target) - $(call PackageFilter,$(CORE_PKGS)) - -############################################################# -# -# docletapidocs -# - -ALL_OTHER_TARGETS += docletapidocs - -DOCLETAPI_DOCDIR := $(JDK_API_DOCSDIR)/javadoc/doclet -DOCLETAPI2COREAPI := ../../$(JDKJRE2COREAPI) -DOCLETAPI_DOCTITLE := Doclet API -DOCLETAPI_WINDOWTITLE := Doclet API -DOCLETAPI_HEADER := Doclet API -DOCLETAPI_BOTTOM := $(call CommonTrademarkBottom,$(DOCLETAPI_FIRST_COPYRIGHT_YEAR)) -DOCLETAPI_GROUPNAME := Packages -DOCLETAPI_REGEXP := jdk.javadoc.doclet* -# DOCLETAPI_PKGS is located in NON_CORE_PKGS.gmk - -# The index.html, options, and packages files -DOCLETAPI_INDEX_FILE = $(DOCLETAPI_DOCDIR)/index.html -DOCLETAPI_OPTIONS_FILE = $(DOCSTMPDIR)/docletapi.options -DOCLETAPI_PACKAGES_FILE = $(DOCSTMPDIR)/docletapi.packages - -# The modules required to be documented -DOCLETAPI_MODULES = jdk.javadoc - -docletapidocs: $(DOCLETAPI_INDEX_FILE) - -# Set relative location to core api document root -$(DOCLETAPI_INDEX_FILE): GET2DOCSDIR=$(DOCLETAPI2COREAPI)/.. + $1_PACKAGE_DEPS := $$(call CacheFind, $$(wildcard $$(foreach p, \ + $$(subst .,/,$$(strip $$($1_PACKAGES))), \ + $$(addsuffix /$$p, $$(wildcard $$(JAVADOC_SOURCE_DIRS)))))) -# Run javadoc if the index file is out of date or missing -$(DOCLETAPI_INDEX_FILE): $(DOCLETAPI_OPTIONS_FILE) $(DOCLETAPI_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(DOCLETAPI_OPTIONS_FILE),$(DOCLETAPI_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(DOCLETAPI_OPTIONS_FILE) @$(DOCLETAPI_PACKAGES_FILE) + # Rule for actually running javadoc + $$($1_INDEX_FILE): $$($1_OPTIONS_FILE) $$($1_PACKAGES_FILE) \ + $$($1_PACKAGE_DEPS) $$($1_DEPS) + $$(call LogWarn, Generating Javadoc for $$($1_OUTPUT_DIRNAME)) + $$(call MakeDir, $$(@D)) + ifneq ($$(findstring $$(LOG_LEVEL), debug trace),) + $$(ECHO) "Contents of $$($1_OPTIONS_FILE):" `$$(CAT) $$($1_OPTIONS_FILE)` + $$(ECHO) "Contents of $$($1_PACKAGES_FILE):" `$$(CAT) $$($1_PACKAGES_FILE)` + endif + $$(call ExecuteWithLog, $$(SUPPORT_OUTPUTDIR)/docs/$1.javadoc, \ + $$($1_JAVA) -Djava.awt.headless=true $(NEW_JAVADOC) -d $$(@D) \ + @$$($1_OPTIONS_FILE) @$$($1_PACKAGES_FILE)) + $$(TOUCH) $$($1_INDEX_FILE) -# Create file with javadoc options in it -$(DOCLETAPI_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:all) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(DOCLETAPI_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionOnly,-breakiterator) ; \ - $(call OptionPair,-doctitle,$(DOCLETAPI_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(DOCLETAPI_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(DOCLETAPI_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(DOCLETAPI_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-group,$(DOCLETAPI_GROUPNAME),$(DOCLETAPI_REGEXP)); \ - $(call OptionTrip,-linkoffline,$(DOCLETAPI2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ + # The output returned will be the index.html file + $1 := $$($1_INDEX_FILE) +endef -# Create a file with the package names in it -$(DOCLETAPI_PACKAGES_FILE): $(call PackageDependencies,$(DOCLETAPI_PKGS)) - $(prep-target) - $(call PackageFilter,$(DOCLETAPI_PKGS)) - -############################################################# -# -# old docletapidocs -# - -ALL_OTHER_TARGETS += olddocletapidocs +################################################################################ -OLD_DOCLET_DIR := $(JDK_API_DOCSDIR)/javadoc/old -OLD_DOCLETAPI_DOCDIR := $(OLD_DOCLET_DIR)/doclet -OLD_DOCLETAPI2COREAPI := ../../../$(JDKJRE2COREAPI) -OLD_DOCLETAPI_DOCTITLE := Doclet API -OLD_DOCLETAPI_WINDOWTITLE := Doclet API -OLD_DOCLETAPI_HEADER := Doclet API -OLD_DOCLETAPI_BOTTOM := $(call CommonTrademarkBottom,$(DOCLETAPI_FIRST_COPYRIGHT_YEAR)) -OLD_DOCLETAPI_GROUPNAME := Packages -OLD_DOCLETAPI_REGEXP := com.sun.javadoc -# OLD_DOCLETAPI_PKGS is located in NON_CORE_PKGS.gmk - -# The index.html, options, and packages files -OLD_DOCLETAPI_INDEX_FILE = $(OLD_DOCLETAPI_DOCDIR)/index.html -OLD_DOCLETAPI_OPTIONS_FILE = $(DOCSTMPDIR)/old-docletapi.options -OLD_DOCLETAPI_PACKAGES_FILE = $(DOCSTMPDIR)/old-docletapi.packages - -# The modules required to be documented -OLD_DOCLETAPI_MODULES = jdk.javadoc - -olddocletapidocs: $(OLD_DOCLETAPI_INDEX_FILE) - -# Set relative location to core api document root -$(OLD_DOCLETAPI_INDEX_FILE): GET2DOCSDIR=$(OLD_DOCLETAPI2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(OLD_DOCLETAPI_INDEX_FILE): $(OLD_DOCLETAPI_OPTIONS_FILE) $(OLD_DOCLETAPI_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(OLD_DOCLETAPI_OPTIONS_FILE),$(OLD_DOCLETAPI_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(OLD_DOCLETAPI_OPTIONS_FILE) @$(OLD_DOCLETAPI_PACKAGES_FILE) +CORE_PACKAGES := \ + java.applet \ + java.awt \ + java.awt.color \ + java.awt.datatransfer \ + java.awt.desktop \ + java.awt.dnd \ + java.awt.event \ + java.awt.font \ + java.awt.geom \ + java.awt.im \ + java.awt.im.spi \ + java.awt.image \ + java.awt.image.renderable \ + java.awt.print \ + java.beans \ + java.beans.beancontext \ + java.io \ + java.lang \ + java.lang.annotation \ + java.lang.instrument \ + java.lang.invoke \ + java.lang.management \ + java.lang.module \ + java.lang.ref \ + java.lang.reflect \ + java.math \ + java.net \ + java.net.http \ + java.net.spi \ + java.nio \ + java.nio.channels \ + java.nio.channels.spi \ + java.nio.charset \ + java.nio.charset.spi \ + java.nio.file \ + java.nio.file.attribute \ + java.nio.file.spi \ + java.rmi \ + java.rmi.activation \ + java.rmi.dgc \ + java.rmi.registry \ + java.rmi.server \ + java.security \ + java.security.acl \ + java.security.cert \ + java.security.interfaces \ + java.security.spec \ + java.sql \ + java.text \ + java.text.spi \ + java.time \ + java.time.chrono \ + java.time.format \ + java.time.temporal \ + java.time.zone \ + java.util \ + java.util.concurrent \ + java.util.concurrent.atomic \ + java.util.concurrent.locks \ + java.util.function \ + java.util.jar \ + java.util.logging \ + java.util.prefs \ + java.util.regex \ + java.util.spi \ + java.util.stream \ + java.util.zip \ + javax.accessibility \ + javax.activation \ + javax.activity \ + javax.annotation \ + javax.annotation.processing \ + javax.crypto \ + javax.crypto.interfaces \ + javax.crypto.spec \ + javax.imageio \ + javax.imageio.event \ + javax.imageio.metadata \ + javax.imageio.plugins.jpeg \ + javax.imageio.plugins.bmp \ + javax.imageio.plugins.tiff \ + javax.imageio.spi \ + javax.imageio.stream \ + javax.jws \ + javax.jws.soap \ + javax.lang.model \ + javax.lang.model.element \ + javax.lang.model.type \ + javax.lang.model.util \ + javax.management \ + javax.management.loading \ + javax.management.monitor \ + javax.management.relation \ + javax.management.openmbean \ + javax.management.timer \ + javax.management.modelmbean \ + javax.management.remote \ + javax.management.remote.rmi \ + javax.naming \ + javax.naming.directory \ + javax.naming.event \ + javax.naming.ldap \ + javax.naming.spi \ + javax.net \ + javax.net.ssl \ + javax.print \ + javax.print.attribute \ + javax.print.attribute.standard \ + javax.print.event \ + javax.rmi \ + javax.rmi.CORBA \ + javax.rmi.ssl \ + javax.script \ + javax.security.auth \ + javax.security.auth.callback \ + javax.security.auth.kerberos \ + javax.security.auth.login \ + javax.security.auth.spi \ + javax.security.auth.x500 \ + javax.security.cert \ + javax.security.sasl \ + javax.sound.sampled \ + javax.sound.sampled.spi \ + javax.sound.midi \ + javax.sound.midi.spi \ + javax.sql \ + javax.sql.rowset \ + javax.sql.rowset.serial \ + javax.sql.rowset.spi \ + javax.swing \ + javax.swing.border \ + javax.swing.colorchooser \ + javax.swing.filechooser \ + javax.swing.event \ + javax.swing.table \ + javax.swing.text \ + javax.swing.text.html \ + javax.swing.text.html.parser \ + javax.swing.text.rtf \ + javax.swing.tree \ + javax.swing.undo \ + javax.swing.plaf \ + javax.swing.plaf.basic \ + javax.swing.plaf.metal \ + javax.swing.plaf.multi \ + javax.swing.plaf.nimbus \ + javax.swing.plaf.synth \ + javax.tools \ + javax.transaction \ + javax.transaction.xa \ + javax.xml.catalog \ + javax.xml.parsers \ + javax.xml.bind \ + javax.xml.bind.annotation \ + javax.xml.bind.annotation.adapters \ + javax.xml.bind.attachment \ + javax.xml.bind.helpers \ + javax.xml.bind.util \ + javax.xml.soap \ + javax.xml.ws \ + javax.xml.ws.handler \ + javax.xml.ws.handler.soap \ + javax.xml.ws.http \ + javax.xml.ws.soap \ + javax.xml.ws.spi \ + javax.xml.ws.spi.http \ + javax.xml.ws.wsaddressing \ + javax.xml.transform \ + javax.xml.transform.sax \ + javax.xml.transform.dom \ + javax.xml.transform.stax \ + javax.xml.transform.stream \ + javax.xml \ + javax.xml.crypto \ + javax.xml.crypto.dom \ + javax.xml.crypto.dsig \ + javax.xml.crypto.dsig.dom \ + javax.xml.crypto.dsig.keyinfo \ + javax.xml.crypto.dsig.spec \ + javax.xml.datatype \ + javax.xml.validation \ + javax.xml.namespace \ + javax.xml.xpath \ + javax.xml.stream \ + javax.xml.stream.events \ + javax.xml.stream.util \ + org.ietf.jgss \ + org.omg.CORBA \ + org.omg.CORBA.DynAnyPackage \ + org.omg.CORBA.ORBPackage \ + org.omg.CORBA.TypeCodePackage \ + org.omg.stub.java.rmi \ + org.omg.CORBA.portable \ + org.omg.CORBA_2_3 \ + org.omg.CORBA_2_3.portable \ + org.omg.CosNaming \ + org.omg.CosNaming.NamingContextExtPackage \ + org.omg.CosNaming.NamingContextPackage \ + org.omg.SendingContext \ + org.omg.PortableServer \ + org.omg.PortableServer.CurrentPackage \ + org.omg.PortableServer.POAPackage \ + org.omg.PortableServer.POAManagerPackage \ + org.omg.PortableServer.ServantLocatorPackage \ + org.omg.PortableServer.portable \ + org.omg.PortableInterceptor \ + org.omg.PortableInterceptor.ORBInitInfoPackage \ + org.omg.Messaging \ + org.omg.IOP \ + org.omg.IOP.CodecFactoryPackage \ + org.omg.IOP.CodecPackage \ + org.omg.Dynamic \ + org.omg.DynamicAny \ + org.omg.DynamicAny.DynAnyPackage \ + org.omg.DynamicAny.DynAnyFactoryPackage \ + org.w3c.dom \ + org.w3c.dom.events \ + org.w3c.dom.bootstrap \ + org.w3c.dom.ls \ + org.w3c.dom.ranges \ + org.w3c.dom.traversal \ + org.w3c.dom.views \ + org.xml.sax \ + org.xml.sax.ext \ + org.xml.sax.helpers -# Create file with javadoc options in it -$(OLD_DOCLETAPI_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:all) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(OLD_DOCLETAPI_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionOnly,-breakiterator) ; \ - $(call OptionPair,-doctitle,$(OLD_DOCLETAPI_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(OLD_DOCLETAPI_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(OLD_DOCLETAPI_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(OLD_DOCLETAPI_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-group,$(OLD_DOCLETAPI_GROUPNAME),$(OLD_DOCLETAPI_REGEXP)); \ - $(call OptionTrip,-linkoffline,$(OLD_DOCLETAPI2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ +$(eval $(call SetupJavadocGeneration, coredocs, \ + MODULES := java.se.ee, \ + PACKAGES := $(CORE_PACKAGES), \ + IS_CORE := TRUE, \ + OVERVIEW := $(JDK_TOPDIR)/src/java.base/share/classes/overview-core.html, \ + WINDOW_TITLE := Java Platform SE $(VERSION_SPECIFICATION), \ + HEADER_TITLE := Java$(TRADEMARK) Platform
    Standard Ed. $(VERSION_SPECIFICATION), \ + DOC_TITLE := Java$(TRADEMARK) Platform$(COMMA) Standard Edition \ + $(VERSION_SPECIFICATION)
    API Specification, \ + FIRST_COPYRIGHT_YEAR := 1993, \ + DOCLINT := reference, \ + DOCLINT_PACKAGES := -org.omg.* jdk.internal.logging.*, \ + ENCODING := ISO-8859-1, \ + SPLIT_INDEX := TRUE, \ + BOTTOM_COPYRIGHT_URL := $(CORE_BOTTOM_COPYRIGHT_URL), \ + BOTTOM_TEXT := $(CORE_BOTTOM_TEXT), \ + EXTRA_TOP := $(CORE_TOP_EARLYACCESS), \ +)) -# Create a file with the package names in it -$(OLD_DOCLETAPI_PACKAGES_FILE): $(call PackageDependencies,$(OLD_DOCLETAPI_PKGS)) - $(prep-target) - $(call PackageFilter,$(OLD_DOCLETAPI_PKGS)) +TARGETS += $(coredocs) + +################################################################################ + +$(eval $(call SetupJavadocGeneration, docletapi, \ + MODULES := jdk.javadoc, \ + PACKAGES := \ + jdk.javadoc.doclet \ + jdk.javadoc.doclet.taglet \ + jdk.javadoc.doclets, \ + PACKAGE_FILTER := jdk.javadoc.doclet*, \ + API_ROOT := jdk, \ + DEST_DIR := javadoc/doclet, \ + TITLE := Doclet API, \ + FIRST_COPYRIGHT_YEAR := 1993, \ + BREAKITERATOR := TRUE, \ + BOTTOM_ADDRESS := $(COMMON_BOTTOM_ADDRESS), \ + BOTTOM_TEXT := $(COMMON_BOTTOM_TEXT), \ +)) -############################################################# -# -# tagletapidocs -# +TARGETS += $(docletapi) + +################################################################################ -ALL_OTHER_TARGETS += tagletapidocs -TAGLETAPI_DOCDIR := $(OLD_DOCLET_DIR)/taglet -TAGLETAPI2COREAPI := ../../../$(JDKJRE2COREAPI) -TAGLETAPI_DOCTITLE := Taglet API -TAGLETAPI_WINDOWTITLE := Taglet API -TAGLETAPI_HEADER := Taglet API -TAGLETAPI_BOTTOM := $(call CommonTrademarkBottom,$(TAGLETAPI_FIRST_COPYRIGHT_YEAR)) -# TAGLETAPI_FILE is located in NON_CORE_PKGS.gmk +$(eval $(call SetupJavadocGeneration, old-docletapi, \ + MODULES := jdk.javadoc, \ + PACKAGES := com.sun.javadoc, \ + PACKAGE_FILTER := com.sun.javadoc, \ + API_ROOT := jdk, \ + DEST_DIR := javadoc/old/doclet, \ + TITLE := Doclet API, \ + FIRST_COPYRIGHT_YEAR := 1993, \ + BREAKITERATOR := TRUE, \ + BOTTOM_ADDRESS := $(COMMON_BOTTOM_ADDRESS), \ + BOTTOM_TEXT := $(COMMON_BOTTOM_TEXT), \ +)) + +TARGETS += $(old-docletapi) -# The index.html, options, and packages files -TAGLETAPI_INDEX_FILE = $(TAGLETAPI_DOCDIR)/index.html -TAGLETAPI_OPTIONS_FILE = $(DOCSTMPDIR)/tagletapi.options -TAGLETAPI_PACKAGES_FILE = $(DOCSTMPDIR)/tagletapi.packages +################################################################################ -# The modules required to be documented -TAGLETAPI_MODULES = jdk.javadoc +# Specify a single class instead of a package +TAGLET_PACKAGE_SINGLE_CLASS := com/sun/tools/doclets/Taglet.java +TAGLET_PACKAGE_DIR := $(LANGTOOLS_TOPDIR)/src/jdk.javadoc/share/classes -tagletapidocs: $(TAGLETAPI_INDEX_FILE) - -# Run javadoc if the index file is out of date or missing -$(TAGLETAPI_INDEX_FILE): $(TAGLETAPI_OPTIONS_FILE) $(TAGLETAPI_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(TAGLETAPI_OPTIONS_FILE),$(TAGLETAPI_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(TAGLETAPI_OPTIONS_FILE) @$(TAGLETAPI_PACKAGES_FILE) +$(eval $(call SetupJavadocGeneration, tagletapi, \ + MODULES := jdk.javadoc, \ + PACKAGES := com.sun.tools.doclets, \ + PACKAGES_SINGLE_CLASS := $(TAGLET_PACKAGE_DIR)/$(TAGLET_PACKAGE_SINGLE_CLASS), \ + API_ROOT := jdk, \ + DEST_DIR := javadoc/old/taglet, \ + TITLE := Taglet API, \ + FIRST_COPYRIGHT_YEAR := 1993, \ + BREAKITERATOR := TRUE, \ + NOINDEX := TRUE, \ + BOTTOM_ADDRESS := $(COMMON_BOTTOM_ADDRESS), \ + BOTTOM_TEXT := $(COMMON_BOTTOM_TEXT), \ +)) -# Create file with javadoc options in it -$(TAGLETAPI_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:all) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(TAGLETAPI_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionOnly,-breakiterator) ; \ - $(call OptionPair,-doctitle,$(TAGLETAPI_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(TAGLETAPI_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(TAGLETAPI_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionOnly,-nonavbar) ; \ - $(call OptionOnly,-noindex) ; \ - $(call OptionPair,-bottom,$(TAGLETAPI_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-linkoffline,$(TAGLETAPI2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ +TARGETS += $(tagletapi) + +################################################################################ + +$(eval $(call SetupJavadocGeneration, domapi, \ + MODULES := \ + java.xml \ + jdk.xml.dom, \ + PACKAGES := \ + org.w3c.dom \ + org.w3c.dom.bootstrap \ + org.w3c.dom.ls \ + org.w3c.dom.ranges \ + org.w3c.dom.traversal \ + org.w3c.dom.html \ + org.w3c.dom.stylesheets \ + org.w3c.dom.css \ + org.w3c.dom.events \ + org.w3c.dom.views, \ + PACKAGE_FILTER := org.w3c.dom*, \ + API_ROOT := jre, \ + DEST_DIR := plugin/dom, \ + TITLE := Common DOM API, \ + FIRST_COPYRIGHT_YEAR := 2005, \ + DOCLINT := none, \ + SPLIT_INDEX := TRUE, \ + BOTTOM_ADDRESS := $(COMMON_BOTTOM_ADDRESS), \ + BOTTOM_TEXT := $(COMMON_BOTTOM_TEXT), \ +)) + +TARGETS += $(domapi) + +################################################################################ -# Create a file with the package names in it -$(TAGLETAPI_PACKAGES_FILE): $(call PackageDependencies,$(TAGLETAPI_PKGS)) - $(prep-target) - @($(ECHO) "$(LANGTOOLS_TOPDIR)/src/jdk.javadoc/share/classes/$(TAGLETAPI_FILE)" ) > $@ +$(eval $(call SetupJavadocGeneration, jdi, \ + MODULES := jdk.jdi, \ + PACKAGES := \ + com.sun.jdi \ + com.sun.jdi.event \ + com.sun.jdi.request \ + com.sun.jdi.connect \ + com.sun.jdi.connect.spi, \ + API_ROOT := jdk, \ + DEST_DIR := jpda/jdi, \ + OVERVIEW := $(JDK_TOPDIR)/src/jdk.jdi/share/classes/jdi-overview.html, \ + TITLE := Java$(TRADEMARK) Debug Interface, \ + FIRST_COPYRIGHT_YEAR := 1999, \ + DOCLINT := none, \ +)) -############################################################# -# -# domapidocs -# +TARGETS += $(jdi) -ALL_OTHER_TARGETS += domapidocs +################################################################################ -DOMAPI_DOCDIR := $(JRE_API_DOCSDIR)/plugin/dom -DOMAPI2COREAPI := ../../$(JDKJRE2COREAPI) -DOMAPI_DOCTITLE := Common DOM API -DOMAPI_WINDOWTITLE := Common DOM API -DOMAPI_HEADER := Common DOM API -DOMAPI_BOTTOM := $(call CommonTrademarkBottom,$(DOMAPI_FIRST_COPYRIGHT_YEAR)) -DOMAPI_GROUPNAME := Packages -DOMAPI_REGEXP := org.w3c.dom* -# DOMAPI_PKGS is located in NON_CORE_PKGS.gmk +$(eval $(call SetupJavadocGeneration, jaas, \ + MODULES := jdk.security.auth, \ + PACKAGES := \ + com.sun.security.auth \ + com.sun.security.auth.callback \ + com.sun.security.auth.login \ + com.sun.security.auth.module, \ + API_ROOT := jre, \ + DEST_DIR := security/jaas/spec, \ + OVERVIEW := $(JDK_TOPDIR)/src/jdk.security.auth/share/classes/jaas-overview.html, \ + TITLE := Java$(TRADEMARK) Authentication and Authorization Service, \ + FIRST_COPYRIGHT_YEAR := 1998, \ + DOCLINT := none, \ +)) + +TARGETS += $(jaas) + +################################################################################ -# The index.html, options, and packages files -DOMAPI_INDEX_FILE = $(DOMAPI_DOCDIR)/index.html -DOMAPI_OPTIONS_FILE = $(DOCSTMPDIR)/domapi.options -DOMAPI_PACKAGES_FILE = $(DOCSTMPDIR)/domapi.packages +$(eval $(call SetupJavadocGeneration, jgss, \ + MODULES := jdk.security.jgss, \ + PACKAGES := com.sun.security.jgss, \ + API_ROOT := jre, \ + DEST_DIR := security/jgss/spec, \ + OVERVIEW := $(JDK_TOPDIR)/src/java.security.jgss/share/classes/jgss-overview.html, \ + TITLE := Java$(TRADEMARK) GSS-API Utilities, \ + FIRST_COPYRIGHT_YEAR := 2000, \ + DOCLINT := none, \ + NODEPRECATEDLIST := TRUE, \ +)) -# The modules required to be documented -DOMAPI_MODULES = java.xml,jdk.xml.dom +TARGETS += $(jgss) -domapidocs: $(DOMAPI_INDEX_FILE) +################################################################################ -# Set relative location to core api document root -$(DOMAPI_INDEX_FILE): GET2DOCSDIR=$(DOMAPI2COREAPI)/.. +$(eval $(call SetupJavadocGeneration, smartcardio, \ + MODULES := java.smartcardio, \ + PACKAGES := javax.smartcardio, \ + API_ROOT := jre, \ + DEST_DIR := security/smartcardio/spec, \ + TITLE := Java$(TRADEMARK) Smart Card I/O, \ + FIRST_COPYRIGHT_YEAR := 2005, \ + DOCLINT := none, \ + NODEPRECATEDLIST := TRUE, \ +)) + +TARGETS += $(smartcardio) + +################################################################################ -# Run javadoc if the index file is out of date or missing -$(DOMAPI_INDEX_FILE): $(DOMAPI_OPTIONS_FILE) $(DOMAPI_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(DOMAPI_OPTIONS_FILE),$(DOMAPI_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(DOMAPI_OPTIONS_FILE) @$(DOMAPI_PACKAGES_FILE) +$(eval $(call SetupJavadocGeneration, httpserver, \ + MODULES := jdk.httpserver, \ + PACKAGES := \ + com.sun.net.httpserver \ + com.sun.net.httpserver.spi, \ + API_ROOT := jre, \ + DEST_DIR := net/httpserver/spec, \ + TITLE := Java$(TRADEMARK) HTTP Server, \ + FIRST_COPYRIGHT_YEAR := 2005, \ + DOCLINT := none, \ + NODEPRECATEDLIST := TRUE, \ +)) + +TARGETS += $(httpserver) -# Create file with javadoc options in it -$(DOMAPI_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:none) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(DOMAPI_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionOnly,-splitIndex) ; \ - $(call OptionPair,-doctitle,$(DOMAPI_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(DOMAPI_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(DOMAPI_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(DOMAPI_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-group,$(DOMAPI_GROUPNAME),$(DOMAPI_REGEXP)); \ - $(call OptionTrip,-linkoffline,$(DOMAPI2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ +################################################################################ + +$(eval $(call SetupJavadocGeneration, jsobject, \ + MODULES := jdk.jsobject, \ + PACKAGES := netscape.javascript, \ + API_ROOT := jre, \ + DEST_DIR := plugin/jsobject, \ + FIRST_COPYRIGHT_YEAR := 1993, \ + TITLE := Java$(TRADEMARK) JSObject Doc, \ + DOCLINT := none, \ + NODEPRECATEDLIST := TRUE, \ +)) + +TARGETS += $(jsobject) + +################################################################################ -# Create a file with the package names in it -$(DOMAPI_PACKAGES_FILE): $(call PackageDependencies,$(DOMAPI_PKGS)) - $(prep-target) - $(call PackageFilter,$(DOMAPI_PKGS)) +$(eval $(call SetupJavadocGeneration, mgmt, \ + MODULES := jdk.management, \ + PACKAGES := com.sun.management, \ + API_ROOT := jre, \ + DEST_DIR := management/extension, \ + OVERVIEW := $(JDK_TOPDIR)/src/java.management/share/classes/mgmt-overview.html, \ + TITLE := Monitoring and Management Interface for the Java$(TRADEMARK) Platform, \ + FIRST_COPYRIGHT_YEAR := 2003, \ + DOCLINT := none, \ + NODEPRECATEDLIST := TRUE, \ +)) + +TARGETS += $(mgmt) + +################################################################################ + +$(eval $(call SetupJavadocGeneration, attach, \ + MODULES := jdk.attach, \ + PACKAGES := \ + com.sun.tools.attach \ + com.sun.tools.attach.spi, \ + API_ROOT := jdk, \ + DEST_DIR := attach/spec, \ + TITLE := Attach API, \ + FIRST_COPYRIGHT_YEAR := 2005, \ + DOCLINT := none, \ + NODEPRECATEDLIST := TRUE, \ +)) -############################################################# -# -# jpdadocs -# +TARGETS += $(attach) + +################################################################################ -ALL_OTHER_TARGETS += jpdadocs +$(eval $(call SetupJavadocGeneration, jconsole, \ + MODULES := jdk.jconsole, \ + PACKAGES := com.sun.tools.jconsole, \ + API_ROOT := jdk, \ + DEST_DIR := jconsole/spec, \ + TITLE := JConsole API, \ + FIRST_COPYRIGHT_YEAR := 2006, \ + DOCLINT := none, \ + NODEPRECATEDLIST := TRUE, \ +)) + +TARGETS += $(jconsole) -jpdadocs: jdidocs jdwpdocs jvmtidocs +################################################################################ -############################################################# -# -# jdidocs -# - -ALL_OTHER_TARGETS += jdidocs +# NOTE: Need to override RELATIVE_CORE_DIR to be bug compatible with old code. +$(eval $(call SetupJavadocGeneration, jshellapi, \ + MODULES := jdk.jshell, \ + PACKAGES := \ + jdk.jshell \ + jdk.jshell.spi \ + jdk.jshell.execution, \ + API_ROOT := jdk, \ + DEST_DIR := jshell, \ + RELATIVE_CORE_DIR := ../../../.., \ + OVERVIEW := $(LANGTOOLS_TOPDIR)/src/jdk.jshell/share/classes/jdk/jshell/overview.html, \ + TITLE := JShell API, \ + HEADER_TITLE := JSHELL API, \ + FIRST_COPYRIGHT_YEAR := 2015, \ +)) -JDI_DOCDIR := $(JDK_API_DOCSDIR)/jpda/jdi -JDI2COREAPI := ../../$(JDKJRE2COREAPI) -JDI_DOCTITLE := Java$(TRADEMARK) Debug Interface -JDI_WINDOWTITLE := Java Debug Interface -JDI_HEADER := Java Debug Interface -JDI_BOTTOM := $(call CommonBottom,$(JDI_FIRST_COPYRIGHT_YEAR)) -JDI_OVERVIEW := $(JDK_TOPDIR)/src/jdk.jdi/share/classes/jdi-overview.html -# JDI_PKGS is located in NON_CORE_PKGS.gmk +TARGETS += $(jshellapi) + +################################################################################ -# The index.html, options, and packages files -JDI_INDEX_FILE = $(JDI_DOCDIR)/index.html -JDI_OPTIONS_FILE = $(DOCSTMPDIR)/jdi.options -JDI_PACKAGES_FILE = $(DOCSTMPDIR)/jdi.packages +$(eval $(call SetupJavadocGeneration, treeapi, \ + MODULES := jdk.compiler, \ + PACKAGES := \ + com.sun.source.doctree \ + com.sun.source.tree \ + com.sun.source.util, \ + PACKAGE_FILTER := com.sun.source.*, \ + API_ROOT := jdk, \ + DEST_DIR := javac/tree, \ + TITLE := Compiler Tree API, \ + FIRST_COPYRIGHT_YEAR := 2005, \ +)) -# The modules required to be documented -JDI_MODULES = jdk.jdi +TARGETS += $(treeapi) -jdidocs: $(JDI_INDEX_FILE) +################################################################################ -# Set relative location to core api document root -$(JDI_INDEX_FILE): GET2DOCSDIR=$(JDI2COREAPI)/.. +$(eval $(call SetupJavadocGeneration, nashornapi, \ + MODULES := jdk.scripting.nashorn, \ + PACKAGES := \ + jdk.nashorn.api.scripting \ + jdk.nashorn.api.tree, \ + PACKAGE_FILTER := jdk.nashorn.api.*, \ + API_ROOT := jdk, \ + DEST_DIR := nashorn, \ + TITLE := Nashorn API, \ + FIRST_COPYRIGHT_YEAR := 2014, \ +)) -# Run javadoc if the index file is out of date or missing -$(JDI_INDEX_FILE): $(JDI_OPTIONS_FILE) $(JDI_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(JDI_OPTIONS_FILE),$(JDI_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(JDI_OPTIONS_FILE) @$(JDI_PACKAGES_FILE) +TARGETS += $(nashornapi) + +################################################################################ -# Create file with javadoc options in it -$(JDI_OPTIONS_FILE): $(JDI_OVERVIEW) - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:none) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(JDI_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionPair,-overview,$(JDI_OVERVIEW)) ; \ - $(call OptionPair,-doctitle,$(JDI_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(JDI_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(JDI_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(JDI_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-linkoffline,$(JDI2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ +$(eval $(call SetupJavadocGeneration, dynalinkapi, \ + MODULES := jdk.dynalink, \ + PACKAGES := \ + jdk.dynalink \ + jdk.dynalink.beans \ + jdk.dynalink.linker \ + jdk.dynalink.linker.support \ + jdk.dynalink.support, \ + API_ROOT := jdk, \ + DEST_DIR := dynalink, \ + TITLE := Dynalink API, \ + FIRST_COPYRIGHT_YEAR := 2015, \ +)) + +TARGETS += $(dynalinkapi) + +################################################################################ + +$(eval $(call SetupJavadocGeneration, sctp, \ + MODULES := jdk.sctp, \ + PACKAGES := com.sun.nio.sctp, \ + API_ROOT := jre, \ + DEST_DIR := nio/sctp/spec, \ + TITLE := SCTP API, \ + FIRST_COPYRIGHT_YEAR := 2009, \ + DOCLINT := none, \ + NODEPRECATEDLIST := TRUE, \ +)) + +TARGETS += $(sctp) + +################################################################################ + +$(eval $(call SetupJavadocGeneration, jaccess, \ + MODULES := jdk.accessibility, \ + PACKAGES := com.sun.java.accessibility.util, \ + API_ROOT := jre, \ + DEST_DIR := accessibility/jaccess/spec, \ + TITLE := JACCESS API, \ + FIRST_COPYRIGHT_YEAR := 2002, \ + NODEPRECATEDLIST := TRUE, \ +)) + +TARGETS += $(jaccess) -# Create a file with the package names in it -$(JDI_PACKAGES_FILE): $(call PackageDependencies,$(JDI_PKGS)) - $(prep-target) - $(call PackageFilter,$(JDI_PKGS)) +################################################################################ -############################################################# -# -# jdwpdocs -# +$(eval $(call SetupJavadocGeneration, jdknet, \ + MODULES := jdk.net, \ + PACKAGES := jdk.net, \ + API_ROOT := jre, \ + DEST_DIR := net/socketoptions/spec, \ + TITLE := jdk.net API, \ + FIRST_COPYRIGHT_YEAR := 2014, \ + DOCLINT := none, \ + NODEPRECATEDLIST := TRUE, \ +)) -ALL_OTHER_TARGETS += jdwpdocs +TARGETS += $(jdknet) + +################################################################################ -JDWP_DOCDIR = $(PLATFORM_DOCSDIR)/jpda/jdwp +# TODO: Need to decide when the plugin API is ready to publish as experimental API. +# This target is temporarily added for internal use for now. +$(eval $(call SetupJavadocGeneration, jlinkplugins, \ + MODULES := jdk.jlink, \ + PACKAGES := jdk.tools.jlink.plugin, \ + API_ROOT := jdk, \ + DEST_DIR := jlink, \ + TITLE := JLink Plugin API - EXPERIMENTAL, \ + FIRST_COPYRIGHT_YEAR := 2015, \ + DOCLINT := none, \ + NODEPRECATEDLIST := TRUE, \ +)) + +TARGETS += $(jlinkplugins) -jdwpdocs: $(JDWP_DOCDIR)/jdwp-protocol.html -$(JDWP_DOCDIR)/jdwp-protocol.html : $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/jdwp-protocol.html - $(MKDIR) -p $(@D) - $(RM) $@ - $(CP) $< $@ +################################################################################ +# Copy JDWP html file + +JDWP_HTML := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/jdwp-protocol.html -############################################################# -# -# jvmtidocs -# +$(eval $(call SetupCopyFiles, COPY_JDWP_HTML, \ + FILES := $(JDWP_HTML), \ + DEST := $(JAVADOC_OUTPUTDIR)/platform/jpda/jdwp, \ +)) -JVMTI_DOCDIR := $(PLATFORM_DOCSDIR)/jvmti +COPY_TARGETS += $(COPY_JDWP_HTML) + +################################################################################ +# Copy JVMTI html file + # Pick jvmti.html from any jvm variant, they are all the same. JVMTI_HTML := $(firstword \ $(wildcard $(HOTSPOT_OUTPUTDIR)/variant-*/gensrc/jvmtifiles/jvmti.html)) $(eval $(call SetupCopyFiles, COPY_JVMTI_HTML, \ FILES := $(JVMTI_HTML), \ - DEST := $(PLATFORM_DOCSDIR)/jvmti, \ + DEST := $(JAVADOC_OUTPUTDIR)/platform/jvmti, \ )) -jvmtidocs: $(COPY_JVMTI_HTML) - -############################################################# -# -# jaasdocs -# - -ALL_OTHER_TARGETS += jaasdocs - -JAAS_DOCDIR := $(JRE_API_DOCSDIR)/security/jaas/spec -JAAS2COREAPI := ../../../$(JDKJRE2COREAPI) -JAAS_DOCTITLE := Java$(TRADEMARK) Authentication and Authorization Service -JAAS_WINDOWTITLE := Java Authentication and Authorization Service -JAAS_HEADER := Java Authentication and Authorization Service -JAAS_BOTTOM := $(call CommonBottom,$(JAAS_FIRST_COPYRIGHT_YEAR)) -# JAAS_PKGS is located in NON_CORE_PKGS.gmk -JAAS_OVERVIEW := $(JDK_TOPDIR)/src/jdk.security.auth/share/classes/jaas-overview.html - -# The index.html, options, and packages files -JAAS_INDEX_FILE = $(JAAS_DOCDIR)/index.html -JAAS_OPTIONS_FILE = $(DOCSTMPDIR)/jaas.options -JAAS_PACKAGES_FILE = $(DOCSTMPDIR)/jaas.packages - -# The modules required to be documented -JAAS_MODULES = jdk.security.auth - -jaasdocs: $(JAAS_INDEX_FILE) - -# Set relative location to core api document root -$(JAAS_INDEX_FILE): GET2DOCSDIR=$(JAAS2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(JAAS_INDEX_FILE): $(JAAS_OPTIONS_FILE) $(JAAS_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(JAAS_OPTIONS_FILE),$(JAAS_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(JAAS_OPTIONS_FILE) @$(JAAS_PACKAGES_FILE) - -# Create file with javadoc options in it -$(JAAS_OPTIONS_FILE): $(JAAS_OVERVIEW) - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:none) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(JAAS_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionPair,-overview,$(JAAS_OVERVIEW)) ; \ - $(call OptionPair,-doctitle,$(JAAS_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(JAAS_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(JAAS_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(JAAS_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-linkoffline,$(JAAS2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(JAAS_PACKAGES_FILE): $(call PackageDependencies,$(JAAS_PKGS)) - $(prep-target) - $(call PackageFilter,$(JAAS_PKGS)) - -############################################################# -# -# jgssdocs -# - -ALL_OTHER_TARGETS += jgssdocs - -JGSS_DOCDIR := $(JRE_API_DOCSDIR)/security/jgss/spec -JGSS2COREAPI := ../../../$(JDKJRE2COREAPI) -JGSS_DOCTITLE := Java$(TRADEMARK) GSS-API Utilities -JGSS_WINDOWTITLE := Java GSS-API Utilities -JGSS_HEADER := Java GSS-API Utilities -JGSS_BOTTOM := $(call CommonBottom,$(JGSS_FIRST_COPYRIGHT_YEAR)) -JGSS_OVERVIEW := $(JDK_TOPDIR)/src/java.security.jgss/share/classes/jgss-overview.html -# JGSS_PKGS is located in NON_CORE_PKGS.gmk - -# The index.html, options, and packages files -JGSS_INDEX_FILE = $(JGSS_DOCDIR)/index.html -JGSS_OPTIONS_FILE = $(DOCSTMPDIR)/jgss.options -JGSS_PACKAGES_FILE = $(DOCSTMPDIR)/jgss.packages - -# The modules required to be documented -JGSS_MODULES = jdk.security.jgss - -jgssdocs: $(JGSS_INDEX_FILE) - -# Set relative location to core api document root -$(JGSS_INDEX_FILE): GET2DOCSDIR=$(JGSS2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(JGSS_INDEX_FILE): $(JGSS_OPTIONS_FILE) $(JGSS_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(JGSS_OPTIONS_FILE),$(JGSS_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(JGSS_OPTIONS_FILE) @$(JGSS_PACKAGES_FILE) - -# Create file with javadoc options in it -$(JGSS_OPTIONS_FILE): $(JGSS_OVERVIEW) - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:none) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(JGSS_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionOnly,-nodeprecatedlist) ; \ - $(call OptionPair,-overview,$(JGSS_OVERVIEW)) ; \ - $(call OptionPair,-doctitle,$(JGSS_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(JGSS_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(JGSS_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(JGSS_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-linkoffline,$(JGSS2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(JGSS_PACKAGES_FILE): $(call PackageDependencies,$(JGSS_PKGS)) - $(prep-target) - $(call PackageFilter,$(JGSS_PKGS)) - -############################################################# -# -# smartcardiodocs -# - -ALL_OTHER_TARGETS += smartcardiodocs - -SMARTCARDIO_DOCDIR := $(JRE_API_DOCSDIR)/security/smartcardio/spec -SMARTCARDIO2COREAPI := ../../../$(JDKJRE2COREAPI) -SMARTCARDIO_DOCTITLE := Java$(TRADEMARK) Smart Card I/O -SMARTCARDIO_WINDOWTITLE := Java Smart Card I/O -SMARTCARDIO_HEADER := Java Smart Card I/O -SMARTCARDIO_BOTTOM := $(call CommonBottom,$(SMARTCARDIO_FIRST_COPYRIGHT_YEAR)) -# SMARTCARDIO_PKGS is located in NON_CORE_PKGS.gmk - -# The index.html, options, and packages files -SMARTCARDIO_INDEX_FILE = $(SMARTCARDIO_DOCDIR)/index.html -SMARTCARDIO_OPTIONS_FILE = $(DOCSTMPDIR)/smartcardio.options -SMARTCARDIO_PACKAGES_FILE = $(DOCSTMPDIR)/smartcardio.packages - -# The modules required to be documented -SMARTCARDIO_MODULES = java.smartcardio - -smartcardiodocs: $(SMARTCARDIO_INDEX_FILE) - -# Set relative location to core api document root -$(SMARTCARDIO_INDEX_FILE): GET2DOCSDIR=$(SMARTCARDIO2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(SMARTCARDIO_INDEX_FILE): $(SMARTCARDIO_OPTIONS_FILE) $(SMARTCARDIO_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(SMARTCARDIO_OPTIONS_FILE),$(SMARTCARDIO_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(SMARTCARDIO_OPTIONS_FILE) @$(SMARTCARDIO_PACKAGES_FILE) - -# Create file with javadoc options in it -$(SMARTCARDIO_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:none) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(SMARTCARDIO_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionOnly,-nodeprecatedlist) ; \ - $(call OptionPair,-doctitle,$(SMARTCARDIO_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(SMARTCARDIO_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(SMARTCARDIO_HEADER)$(DRAFT_HEADER)); \ - $(call OptionPair,-bottom,$(SMARTCARDIO_BOTTOM)$(DRAFT_BOTTOM)); \ - $(call OptionTrip,-linkoffline,$(SMARTCARDIO2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(SMARTCARDIO_PACKAGES_FILE): $(call PackageDependencies,$(SMARTCARDIO_PKGS)) - $(prep-target) - $(call PackageFilter,$(SMARTCARDIO_PKGS)) - -############################################################# -# -# httpserverdocs -# - -ALL_OTHER_TARGETS += httpserverdocs - -HTTPSERVER_DOCDIR := $(JRE_API_DOCSDIR)/net/httpserver/spec -HTTPSERVER2COREAPI := ../../../$(JDKJRE2COREAPI) -HTTPSERVER_DOCTITLE := Java$(TRADEMARK) HTTP Server -HTTPSERVER_WINDOWTITLE := Java HTTP Server -HTTPSERVER_HEADER := Java HTTP Server -HTTPSERVER_BOTTOM := $(call CommonBottom,$(HTTPSERVER_FIRST_COPYRIGHT_YEAR)) -# HTTPSERVER_PKGS is located in NON_CORE_PKGS.gmk - -HTTPSERVER_INDEX_HTML = $(HTTPSERVER_DOCDIR)/index.html -HTTPSERVER_OPTIONS_FILE = $(DOCSTMPDIR)/httpserver.options -HTTPSERVER_PACKAGES_FILE = $(DOCSTMPDIR)/httpserver.packages - -# The modules required to be documented -HTTPSERVER_MODULES = jdk.httpserver - -httpserverdocs: $(HTTPSERVER_INDEX_HTML) - -# Set relative location to core api document root -$(HTTPSERVER_INDEX_HTML): GET2DOCSDIR=$(HTTPSERVER2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(HTTPSERVER_INDEX_HTML): $(HTTPSERVER_OPTIONS_FILE) $(HTTPSERVER_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(HTTPSERVER_OPTIONS_FILE),$(HTTPSERVER_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(HTTPSERVER_OPTIONS_FILE) @$(HTTPSERVER_PACKAGES_FILE) - -# Create file with javadoc options in it -$(HTTPSERVER_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:none) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(HTTPSERVER_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionOnly,-nodeprecatedlist) ; \ - $(call OptionPair,-doctitle,$(HTTPSERVER_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(HTTPSERVER_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(HTTPSERVER_HEADER)$(DRAFT_HEADER)); \ - $(call OptionPair,-bottom,$(HTTPSERVER_BOTTOM)$(DRAFT_BOTTOM)); \ - $(call OptionTrip,-linkoffline,$(HTTPSERVER2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(HTTPSERVER_PACKAGES_FILE): $(call PackageDependencies,$(HTTPSERVER_PKGS)) - $(prep-target) - $(call PackageFilter,$(HTTPSERVER_PKGS)) - -############################################################# -# -# jsobjectdocs -# - -ALL_OTHER_TARGETS += jsobjectdocs - -JSOBJECT_DOCDIR := $(JRE_API_DOCSDIR)/plugin/jsobject -JSOBJECT2COREAPI := ../../$(JDKJRE2COREAPI) -JSOBJECT_DOCTITLE := Java$(TRADEMARK) JSObject Doc -JSOBJECT_WINDOWTITLE := Java JSObject Doc -JSOBJECT_HEADER := Java JSObject Doc -JSOBJECT_BOTTOM := $(call CommonBottom,$(JSOBJECT_FIRST_COPYRIGHT_YEAR)) -# JSOBJECT_PKGS is located in NON_CORE_PKGS.gmk - -JSOBJECT_INDEX_HTML = $(JSOBJECT_DOCDIR)/index.html -JSOBJECT_OPTIONS_FILE = $(DOCSTMPDIR)/jsobject.options -JSOBJECT_PACKAGES_FILE = $(DOCSTMPDIR)/jsobject.packages - -# The modules required to be documented -JSOBJECT_MODULES = jdk.jsobject - -jsobjectdocs: $(JSOBJECT_INDEX_HTML) - -# Set relative location to core api document root -$(JSOBJECT_INDEX_HTML): GET2DOCSDIR=$(JSOBJECT2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(JSOBJECT_INDEX_HTML): $(JSOBJECT_OPTIONS_FILE) $(JSOBJECT_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(JSOBJECT_OPTIONS_FILE),$(JSOBJECT_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(JSOBJECT_OPTIONS_FILE) @$(JSOBJECT_PACKAGES_FILE) - -# Create file with javadoc options in it -$(JSOBJECT_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:none) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(JSOBJECT_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionOnly,-nodeprecatedlist) ; \ - $(call OptionPair,-doctitle,$(JSOBJECT_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(JSOBJECT_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(JSOBJECT_HEADER)$(DRAFT_HEADER)); \ - $(call OptionPair,-bottom,$(JSOBJECT_BOTTOM)$(DRAFT_BOTTOM)); \ - $(call OptionTrip,-linkoffline,$(JSOBJECT2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(JSOBJECT_PACKAGES_FILE): $(call PackageDependencies,$(JSOBJECT_PKGS)) - $(prep-target) - $(call PackageFilter,$(JSOBJECT_PKGS)) - - -############################################################# -# -# mgmtdocs -# - -ALL_OTHER_TARGETS += mgmtdocs - -MGMT_DOCDIR := $(JRE_API_DOCSDIR)/management/extension -MGMT2COREAPI := ../../$(JDKJRE2COREAPI) -MGMT_DOCTITLE := Monitoring and Management Interface for the Java$(TRADEMARK) Platform -MGMT_WINDOWTITLE := Monitoring and Management Interface for the Java Platform -MGMT_HEADER := Monitoring and Management Interface for the Java Platform -MGMT_BOTTOM := $(call CommonBottom,$(MGMT_FIRST_COPYRIGHT_YEAR)) -MGMT_OVERVIEW := $(JDK_TOPDIR)/src/java.management/share/classes/mgmt-overview.html -# MGMT_PKGS is located in NON_CORE_PKGS.gmk - -# The index.html, options, and packages files -MGMT_INDEX_FILE = $(MGMT_DOCDIR)/index.html -MGMT_OPTIONS_FILE = $(DOCSTMPDIR)/mgmt.options -MGMT_PACKAGES_FILE = $(DOCSTMPDIR)/mgmt.packages - -# The modules required to be documented -MGMT_MODULES = jdk.management - -mgmtdocs: $(MGMT_INDEX_FILE) - -# Set relative location to core api document root -$(MGMT_INDEX_FILE): GET2DOCSDIR=$(MGMT2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(MGMT_INDEX_FILE): $(MGMT_OPTIONS_FILE) $(MGMT_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(MGMT_OPTIONS_FILE),$(MGMT_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(MGMT_OPTIONS_FILE) @$(MGMT_PACKAGES_FILE) - -# Create file with javadoc options in it -$(MGMT_OPTIONS_FILE): $(MGMT_OVERVIEW) - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:none) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(MGMT_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionOnly,-nodeprecatedlist) ; \ - $(call OptionPair,-overview,$(MGMT_OVERVIEW)) ; \ - $(call OptionPair,-doctitle,$(MGMT_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(MGMT_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(MGMT_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(MGMT_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-linkoffline,$(MGMT2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(MGMT_PACKAGES_FILE): $(call PackageDependencies,$(MGMT_PKGS)) - $(prep-target) - $(call PackageFilter,$(MGMT_PKGS)) - -############################################################# -# -# attachdocs -# - -ALL_OTHER_TARGETS += attachdocs - -ATTACH_DOCDIR := $(JDK_API_DOCSDIR)/attach/spec -ATTACH2COREAPI := ../../$(JDKJRE2COREAPI) -ATTACH_DOCTITLE := Attach API -ATTACH_WINDOWTITLE := Attach API -ATTACH_HEADER := Attach API -ATTACH_BOTTOM := $(call CommonBottom,$(ATTACH_FIRST_COPYRIGHT_YEAR)) -# ATTACH_PKGS is located in NON_CORE_PKGS.gmk - -ATTACH_INDEX_HTML = $(ATTACH_DOCDIR)/index.html -ATTACH_OPTIONS_FILE = $(DOCSTMPDIR)/attach.options -ATTACH_PACKAGES_FILE = $(DOCSTMPDIR)/attach.packages - -# The modules required to be documented -ATTACH_MODULES = jdk.attach - -attachdocs: $(ATTACH_INDEX_HTML) - -# Set relative location to core api document root -$(ATTACH_INDEX_HTML): GET2DOCSDIR=$(ATTACH2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(ATTACH_INDEX_HTML): $(ATTACH_OPTIONS_FILE) $(ATTACH_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(ATTACH_OPTIONS_FILE),$(ATTACH_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(ATTACH_OPTIONS_FILE) @$(ATTACH_PACKAGES_FILE) - -# Create file with javadoc options in it -$(ATTACH_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:none) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(ATTACH_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionOnly,-nodeprecatedlist) ; \ - $(call OptionPair,-doctitle,$(ATTACH_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(ATTACH_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(ATTACH_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(ATTACH_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-linkoffline,$(ATTACH2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(ATTACH_PACKAGES_FILE): $(call PackageDependencies,$(ATTACH_PKGS)) - $(prep-target) - $(call PackageFilter,$(ATTACH_PKGS)) - -############################################################# -# -# jconsoledocs -# - -ALL_OTHER_TARGETS += jconsoledocs - -JCONSOLE_DOCDIR := $(JDK_API_DOCSDIR)/jconsole/spec -JCONSOLE2COREAPI := ../../$(JDKJRE2COREAPI) -JCONSOLE_DOCTITLE := JConsole API -JCONSOLE_WINDOWTITLE := JConsole API -JCONSOLE_HEADER := JConsole API -JCONSOLE_BOTTOM := $(call CommonBottom,$(JCONSOLE_FIRST_COPYRIGHT_YEAR)) -# JCONSOLE_PKGS is located in NON_CORE_PKGS.gmk - -JCONSOLE_INDEX_HTML = $(JCONSOLE_DOCDIR)/index.html -JCONSOLE_OPTIONS_FILE = $(DOCSTMPDIR)/jconsole.options -JCONSOLE_PACKAGES_FILE = $(DOCSTMPDIR)/jconsole.packages - -# The modules required to be documented -JCONSOLE_MODULES = jdk.jconsole - -jconsoledocs: $(JCONSOLE_INDEX_HTML) - -# Set relative location to core api document root -$(JCONSOLE_INDEX_HTML): GET2DOCSDIR=$(JCONSOLE2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(JCONSOLE_INDEX_HTML): $(JCONSOLE_OPTIONS_FILE) $(JCONSOLE_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(JCONSOLE_OPTIONS_FILE),$(JCONSOLE_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(JCONSOLE_OPTIONS_FILE) @$(JCONSOLE_PACKAGES_FILE) - -# Create file with javadoc options in it -$(JCONSOLE_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:none) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(JCONSOLE_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionOnly,-nodeprecatedlist) ; \ - $(call OptionPair,-doctitle,$(JCONSOLE_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(JCONSOLE_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(JCONSOLE_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(JCONSOLE_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-linkoffline,$(JCONSOLE2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(JCONSOLE_PACKAGES_FILE): $(call PackageDependencies,$(JCONSOLE_PKGS)) - $(prep-target) - $(call PackageFilter,$(JCONSOLE_PKGS)) +COPY_TARGETS += $(COPY_JVMTI_HTML) -############################################################# -# -# jshellapidocs -# - -ALL_OTHER_TARGETS += jshellapidocs - -JSHELLAPI_DOCDIR := $(JDK_API_DOCSDIR)/jshell -JSHELLAPI2COREAPI := ../../$(JDKJRE2COREAPI) -JSHELLAPI_DOCTITLE := JShell API -JSHELLAPI_WINDOWTITLE := JShell API -JSHELLAPI_HEADER := JSHELL API -JSHELLAPI_BOTTOM := $(call CommonBottom,$(JSHELLAPI_FIRST_COPYRIGHT_YEAR)) -JSHELLAPI_OVERVIEW := $(LANGTOOLS_TOPDIR)/src/jdk.jshell/share/classes/jdk/jshell/overview.html -# JSHELLAPI_PKGS is located in NON_CORE_PKGS.gmk - -JSHELLAPI_INDEX_HTML = $(JSHELLAPI_DOCDIR)/index.html -JSHELLAPI_OPTIONS_FILE = $(DOCSTMPDIR)/jshellapi.options -JSHELLAPI_PACKAGES_FILE = $(DOCSTMPDIR)/jshellapi.packages - -# The modules required to be documented -JSHELLAPI_MODULES = jdk.jshell - -jshellapidocs: $(JSHELLAPI_INDEX_HTML) - -# Set relative location to core api document root -$(JSHELLAPI_INDEX_HTML): GET2DOCSDIR=$(JSHELLAPI2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(JSHELLAPI_INDEX_HTML): $(JSHELLAPI_OPTIONS_FILE) $(JSHELLAPI_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(JSHELLAPI_OPTIONS_FILE),$(JSHELLAPI_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(JSHELLAPI_OPTIONS_FILE) @$(JSHELLAPI_PACKAGES_FILE) - -# Create file with javadoc options in it -$(JSHELLAPI_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:all) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(JSHELLAPI_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionPair,-overview,$(JSHELLAPI_OVERVIEW)) ; \ - $(call OptionPair,-doctitle,$(JSHELLAPI_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(JSHELLAPI_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(JSHELLAPI_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(JSHELLAPI_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-linkoffline,$(JSHELLAPI2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(JSHELLAPI_PACKAGES_FILE): $(call PackageDependencies,$(JSHELLAPI_PKGS)) - $(prep-target) - $(call PackageFilter,$(JSHELLAPI_PKGS)) - -############################################################# -# -# treeapidocs -# - -ALL_OTHER_TARGETS += treeapidocs - -TREEAPI_DOCDIR := $(JDK_API_DOCSDIR)/javac/tree -TREEAPI2COREAPI := ../../$(JDKJRE2COREAPI) -TREEAPI_DOCTITLE := Compiler Tree API -TREEAPI_WINDOWTITLE := Compiler Tree API -TREEAPI_HEADER := Compiler Tree API -TREEAPI_BOTTOM := $(call CommonBottom,$(TREEAPI_FIRST_COPYRIGHT_YEAR)) -TREEAPI_GROUPNAME := Packages -TREEAPI_REGEXP := com.sun.source.* -# TREEAPI_PKGS is located in NON_CORE_PKGS.gmk - -TREEAPI_INDEX_HTML = $(TREEAPI_DOCDIR)/index.html -TREEAPI_OPTIONS_FILE = $(DOCSTMPDIR)/treeapi.options -TREEAPI_PACKAGES_FILE = $(DOCSTMPDIR)/treeapi.packages - -# The modules required to be documented -TREEAPI_MODULES = jdk.compiler - -treeapidocs: $(TREEAPI_INDEX_HTML) - -# Set relative location to core api document root -$(TREEAPI_INDEX_HTML): GET2DOCSDIR=$(TREEAPI2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(TREEAPI_INDEX_HTML): $(TREEAPI_OPTIONS_FILE) $(TREEAPI_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(TREEAPI_OPTIONS_FILE),$(TREEAPI_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(TREEAPI_OPTIONS_FILE) @$(TREEAPI_PACKAGES_FILE) - -# Create file with javadoc options in it -$(TREEAPI_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:all) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(TREEAPI_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionPair,-doctitle,$(TREEAPI_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(TREEAPI_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(TREEAPI_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(TREEAPI_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-group,$(TREEAPI_GROUPNAME),$(TREEAPI_REGEXP)); \ - $(call OptionTrip,-linkoffline,$(TREEAPI2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(TREEAPI_PACKAGES_FILE): $(call PackageDependencies,$(TREEAPI_PKGS)) - $(prep-target) - $(call PackageFilter,$(TREEAPI_PKGS)) - -############################################################# -# -# nashornapidocs -# - -ALL_OTHER_TARGETS += nashornapidocs - -NASHORNAPI_DOCDIR := $(JDK_API_DOCSDIR)/nashorn -NASHORNAPI2COREAPI := ../$(JDKJRE2COREAPI) -NASHORNAPI_DOCTITLE := Nashorn API -NASHORNAPI_WINDOWTITLE := Nashorn API -NASHORNAPI_HEADER := Nashorn API -NASHORNAPI_BOTTOM := $(call CommonBottom,$(NASHORNAPI_FIRST_COPYRIGHT_YEAR)) -NASHORNAPI_GROUPNAME := Packages -NASHORNAPI_REGEXP := jdk.nashorn.api.* -# NASHORNAPI_PKGS is located in NON_CORE_PKGS.gmk - -NASHORNAPI_INDEX_HTML = $(NASHORNAPI_DOCDIR)/index.html -NASHORNAPI_OPTIONS_FILE = $(DOCSTMPDIR)/nashornapi.options -NASHORNAPI_PACKAGES_FILE = $(DOCSTMPDIR)/nashornapi.packages - -# The modules required to be documented -NASHORNAPI_MODULES = jdk.scripting.nashorn - -nashornapidocs: $(NASHORNAPI_INDEX_HTML) - -# Set relative location to core api document root -$(NASHORNAPI_INDEX_HTML): GET2DOCSDIR=$(NASHORNAPI2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(NASHORNAPI_INDEX_HTML): $(NASHORNAPI_OPTIONS_FILE) $(NASHORNAPI_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(NASHORNAPI_OPTIONS_FILE),$(NASHORNAPI_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(NASHORNAPI_OPTIONS_FILE) @$(NASHORNAPI_PACKAGES_FILE) - -# Create file with javadoc options in it -$(NASHORNAPI_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:all) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(NASHORNAPI_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionPair,-doctitle,$(NASHORNAPI_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(NASHORNAPI_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(NASHORNAPI_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(NASHORNAPI_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-group,$(NASHORNAPI_GROUPNAME),$(NASHORNAPI_REGEXP)); \ - $(call OptionTrip,-linkoffline,$(NASHORNAPI2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(NASHORNAPI_PACKAGES_FILE): $(call PackageDependencies,$(NASHORNAPI_PKGS)) - $(prep-target) - $(call PackageFilter,$(NASHORNAPI_PKGS)) - -############################################################# -# -# dynalinkapidocs -# - -ALL_OTHER_TARGETS += dynalinkapidocs - -DYNALINKAPI_DOCDIR := $(JDK_API_DOCSDIR)/dynalink -DYNALINKAPI2COREAPI := ../$(JDKJRE2COREAPI) -DYNALINKAPI_DOCTITLE := Dynalink API -DYNALINKAPI_WINDOWTITLE := Dynalink API -DYNALINKAPI_HEADER := Dynalink API -DYNALINKAPI_BOTTOM := $(call CommonBottom,$(DYNALINKAPI_FIRST_COPYRIGHT_YEAR)) -DYNALINKAPI_GROUPNAME := Packages -DYNALINKAPI_REGEXP := jdk.dynalink.* -# DYNALINKAPI_PKGS is located in NON_CORE_PKGS.gmk - -DYNALINKAPI_INDEX_HTML = $(DYNALINKAPI_DOCDIR)/index.html -DYNALINKAPI_OPTIONS_FILE = $(DOCSTMPDIR)/dynalinkapi.options -DYNALINKAPI_PACKAGES_FILE = $(DOCSTMPDIR)/dynalinkapi.packages - -# The modules required to be documented -DYNALINKAPI_MODULES = jdk.dynalink - -dynalinkapidocs: $(DYNALINKAPI_INDEX_HTML) - -# Set relative location to core api document root -$(DYNALINKAPI_INDEX_HTML): GET2DOCSDIR=$(DYNALINKAPI2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(DYNALINKAPI_INDEX_HTML): $(DYNALINKAPI_OPTIONS_FILE) $(DYNALINKAPI_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(DYNALINKAPI_OPTIONS_FILE),$(DYNALINKAPI_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(DYNALINKAPI_OPTIONS_FILE) @$(DYNALINKAPI_PACKAGES_FILE) - -# Create file with javadoc options in it -$(DYNALINKAPI_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:all) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(DYNALINKAPI_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionPair,-doctitle,$(DYNALINKAPI_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(DYNALINKAPI_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(DYNALINKAPI_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(DYNALINKAPI_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-linkoffline,$(DYNALINKAPI2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(DYNALINKAPI_PACKAGES_FILE): $(call PackageDependencies,$(DYNALINKAPI_PKGS)) - $(prep-target) - $(call PackageFilter,$(DYNALINKAPI_PKGS)) +################################################################################ +# Optional target which bundles all generated javadocs into a zip archive. +# The dependency on docs is handled in Main.gmk. -############################################################# -# -# sctpdocs -# - -ALL_OTHER_TARGETS += sctpdocs - -SCTPAPI_DOCDIR := $(JRE_API_DOCSDIR)/nio/sctp/spec -SCTPAPI2COREAPI := ../../../$(JDKJRE2COREAPI) -SCTPAPI_DOCTITLE := SCTP API -SCTPAPI_WINDOWTITLE := SCTP API -SCTPAPI_HEADER := SCTP API -SCTPAPI_BOTTOM := $(call CommonBottom,$(SCTPAPI_FIRST_COPYRIGHT_YEAR)) -# SCTPAPI_PKGS is located in NON_CORE_PKGS.gmk - -SCTPAPI_INDEX_HTML = $(SCTPAPI_DOCDIR)/index.html -SCTPAPI_OPTIONS_FILE = $(DOCSTMPDIR)/sctp.options -SCTPAPI_PACKAGES_FILE = $(DOCSTMPDIR)/sctp.packages - -# The modules required to be documented -SCTPAPI_MODULES = jdk.sctp - -sctpdocs: $(SCTPAPI_INDEX_HTML) - -# Set relative location to core api document root -$(SCTPAPI_INDEX_HTML): GET2DOCSDIR=$(SCTPAPI2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(SCTPAPI_INDEX_HTML): $(SCTPAPI_OPTIONS_FILE) $(SCTPAPI_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(SCTPAPI_OPTIONS_FILE),$(SCTPAPI_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(SCTPAPI_OPTIONS_FILE) @$(SCTPAPI_PACKAGES_FILE) - -# Create file with javadoc options in it -$(SCTPAPI_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:none) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(SCTPAPI_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionOnly,-nodeprecatedlist) ; \ - $(call OptionPair,-doctitle,$(SCTPAPI_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(SCTPAPI_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(SCTPAPI_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(SCTPAPI_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-linkoffline,$(SCTPAPI2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(SCTPAPI_PACKAGES_FILE): $(call PackageDependencies,$(SCTPAPI_PKGS)) - $(prep-target) - $(call PackageFilter,$(SCTPAPI_PKGS)) - -############################################################# -# -# jaccessdocs - Java Accessibility Utilities -# - -ALL_OTHER_TARGETS += jaccessdocs - -JACCESSAPI_DOCDIR := $(JRE_API_DOCSDIR)/accessibility/jaccess/spec -JACCESSAPI2COREAPI := ../../../$(JDKJRE2COREAPI) -JACCESSAPI_DOCTITLE := JACCESS API -JACCESSAPI_WINDOWTITLE := JACCESS API -JACCESSAPI_HEADER := JACCESS API -JACCESSAPI_BOTTOM := $(call CommonBottom,$(JACCESSAPI_FIRST_COPYRIGHT_YEAR)) -# JACCESSAPI_PKGS is located in NON_CORE_PKGS.gmk - -JACCESSAPI_INDEX_HTML = $(JACCESSAPI_DOCDIR)/index.html -JACCESSAPI_OPTIONS_FILE = $(DOCSTMPDIR)/jaccess.options -JACCESSAPI_PACKAGES_FILE = $(DOCSTMPDIR)/jaccess.packages - -# The modules required to be documented -JACCESSAPI_MODULES = jdk.accessibility - -jaccessdocs: $(JACCESSAPI_INDEX_HTML) - -# Set relative location to core api document root -$(JACCESSAPI_INDEX_HTML): GET2DOCSDIR=$(JACCESSAPI2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(JACCESSAPI_INDEX_HTML): $(JACCESSAPI_OPTIONS_FILE) $(JACCESSAPI_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(JACCESSAPI_OPTIONS_FILE),$(JACCESSAPI_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(JACCESSAPI_OPTIONS_FILE) @$(JACCESSAPI_PACKAGES_FILE) - -# Create file with javadoc options in it -$(JACCESSAPI_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:all) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(JACCESSAPI_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionOnly,-nodeprecatedlist) ; \ - $(call OptionPair,-doctitle,$(JACCESSAPI_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(JACCESSAPI_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(JACCESSAPI_HEADER)$(DRAFT_HEADER)) ; \ - $(call OptionPair,-bottom,$(JACCESSAPI_BOTTOM)$(DRAFT_BOTTOM)) ; \ - $(call OptionTrip,-linkoffline,$(JACCESSAPI2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(JACCESSAPI_PACKAGES_FILE): $(call PackageDependencies,$(JACCESSAPI_PKGS)) - $(prep-target) - $(call PackageFilter,$(JACCESSAPI_PKGS)) - -############################################################# -# -# jdk.net docs -# - -ALL_OTHER_TARGETS += jdknetdocs - -JDKNET_DOCDIR := $(JRE_API_DOCSDIR)/net/socketoptions/spec -JDKNET2COREAPI := ../../../$(JDKJRE2COREAPI) -JDKNET_DOCTITLE := jdk.net API -JDKNET_WINDOWTITLE := jdk.net API -JDKNET_HEADER := jdk.net API -JDKNET_BOTTOM := $(call CommonBottom,$(JDKNET_FIRST_COPYRIGHT_YEAR)) -JDKNET_PKGS := jdk.net - -JDKNET_INDEX_HTML = $(JDKNET_DOCDIR)/index.html -JDKNET_OPTIONS_FILE = $(DOCSTMPDIR)/jdknet.options -JDKNET_PACKAGES_FILE = $(DOCSTMPDIR)/jdknet.packages - -# The modules required to be documented -JDKNET_MODULES = jdk.net - -jdknetdocs: $(JDKNET_INDEX_HTML) - -# Set relative location to core api document root -$(JDKNET_INDEX_HTML): GET2DOCSDIR=$(JDKNET2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(JDKNET_INDEX_HTML): $(JDKNET_OPTIONS_FILE) $(JDKNET_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(JDKNET_OPTIONS_FILE),$(JDKNET_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(JDKNET_OPTIONS_FILE) @$(JDKNET_PACKAGES_FILE) - -# Create file with javadoc options in it -$(JDKNET_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:none) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(JDKNET_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionOnly,-nodeprecatedlist) ; \ - $(call OptionPair,-doctitle,$(JDKNET_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(JDKNET_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(JDKNET_HEADER)$(DRAFT_HEADER)); \ - $(call OptionPair,-bottom,$(JDKNET_BOTTOM)$(DRAFT_BOTTOM)); \ - $(call OptionTrip,-linkoffline,$(JDKNET2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(JDKNET_PACKAGES_FILE): $(call PackageDependencies,$(JDKNET_PKGS)) - $(prep-target) - $(call PackageFilter,$(JDKNET_PKGS)) - -############################################################# -# -# jlink plugin API docs -# -# TODO: Need to decide when the plugin API is ready to publish as experimental API. -# This target is temporarily added for internal use for now. -# - -ALL_OTHER_TARGETS += jlinkdocs - -JLINK_PLUGIN_FIRST_COPYRIGHT_YEAR = 2015 -JLINK_PLUGIN_DOCDIR := $(JDK_API_DOCSDIR)/jlink -JLINK_PLUGIN2COREAPI := ../$(JDKJRE2COREAPI) -JLINK_PLUGIN_DOCTITLE := JLink Plugin API - EXPERIMENTAL -JLINK_PLUGIN_WINDOWTITLE := JLink Plugin API - EXPERIMENTAL -JLINK_PLUGIN_HEADER := JLink Plugin API - EXPERIMENTAL -JLINK_PLUGIN_BOTTOM := $(call CommonBottom,$(JLINK_PLUGIN_FIRST_COPYRIGHT_YEAR)) -JLINK_PLUGIN_PKGS = jdk.tools.jlink.plugin - -JLINK_PLUGIN_INDEX_HTML = $(JLINK_PLUGIN_DOCDIR)/index.html -JLINK_PLUGIN_OPTIONS_FILE = $(DOCSTMPDIR)/jlinkplugins.options -JLINK_PLUGIN_PACKAGES_FILE = $(DOCSTMPDIR)/jlinkplugins.packages - -# The modules required to be documented -JLINK_PLUGIN_MODULES = jdk.jlink - -jlinkdocs: $(JLINK_PLUGIN_INDEX_HTML) - -# Set relative location to core api document root -$(JLINK_PLUGIN_INDEX_HTML): GET2DOCSDIR=$(JLINK_PLUGIN2COREAPI)/.. - -# Run javadoc if the index file is out of date or missing -$(JLINK_PLUGIN_INDEX_HTML): $(JLINK_PLUGIN_OPTIONS_FILE) $(JLINK_PLUGIN_PACKAGES_FILE) $(COREAPI_INDEX_FILE) - $(prep-javadoc) - $(call JavadocSummary,$(JLINK_PLUGIN_OPTIONS_FILE),$(JLINK_PLUGIN_PACKAGES_FILE)) - $(JAVADOC_CMD_SMALL) -d $(@D) \ - @$(JLINK_PLUGIN_OPTIONS_FILE) @$(JLINK_PLUGIN_PACKAGES_FILE) - -# Create file with javadoc options in it -$(JLINK_PLUGIN_OPTIONS_FILE): - $(prep-target) - @($(call COMMON_JAVADOCFLAGS) ; \ - $(call COMMON_JAVADOCTAGS) ; \ - $(call OptionOnly,-Xdoclint:none) ; \ - $(call OptionPair,--system,none) ; \ - $(call OptionPair,--module-source-path,$(RELEASEDOCS_MODULESOURCEPATH)) ; \ - $(call OptionPair,--add-modules,$(JLINK_PLUGIN_MODULES)) ; \ - $(call OptionPair,-encoding,ascii) ; \ - $(call OptionOnly,-nodeprecatedlist) ; \ - $(call OptionPair,-doctitle,$(JLINK_PLUGIN_DOCTITLE)) ; \ - $(call OptionPair,-windowtitle,$(JLINK_PLUGIN_WINDOWTITLE) $(DRAFT_WINTITLE)); \ - $(call OptionPair,-header,$(JLINK_PLUGIN_HEADER)$(DRAFT_HEADER)); \ - $(call OptionPair,-bottom,$(JLINK_PLUGIN_BOTTOM)$(DRAFT_BOTTOM)); \ - $(call OptionTrip,-linkoffline,$(JLINK_PLUGIN2COREAPI),$(COREAPI_DOCSDIR)/); \ - ) >> $@ - -# Create a file with the package names in it -$(JLINK_PLUGIN_PACKAGES_FILE): $(call PackageDependencies,$(JLINK_PLUGIN_PKGS)) - $(prep-target) - $(call PackageFilter,$(JLINK_PLUGIN_PKGS)) - - -otherdocs: $(ALL_OTHER_TARGETS) - -# # Add the core docs as prerequisite to the archive to trigger a rebuild # if the core docs were rebuilt. Ideally any doc rebuild should trigger # this, but the way prerequisites are currently setup in this file, that # is hard to achieve. -# -$(JAVADOC_ARCHIVE): $(COREAPI_INDEX_FILE) +JAVADOC_ARCHIVE_NAME := jdk-$(VERSION_STRING)-docs.zip +JAVADOC_ARCHIVE_ASSEMBLY_DIR := $(SUPPORT_OUTPUTDIR)/docs/zip-docs +JAVADOC_ARCHIVE_DIR := $(OUTPUT_ROOT)/bundles +JAVADOC_ARCHIVE := $(JAVADOC_ARCHIVE_DIR)/$(JAVADOC_ARCHIVE_NAME) + +$(JAVADOC_ARCHIVE): $(CORE_INDEX_FILE) $(call LogInfo, Compressing javadoc to single $(JAVADOC_ARCHIVE_NAME)) $(MKDIR) -p $(JAVADOC_ARCHIVE_DIR) $(RM) -r $(JAVADOC_ARCHIVE_ASSEMBLY_DIR) $(MKDIR) -p $(JAVADOC_ARCHIVE_ASSEMBLY_DIR) - all_roots=`$(FIND) $(DOCSDIR) | $(GREP) index.html | grep -v old/doclet`; \ + all_roots=`$(FIND) $(JAVADOC_OUTPUTDIR) | $(GREP) index.html | grep -v old/doclet`; \ pushd $(JAVADOC_ARCHIVE_ASSEMBLY_DIR); \ for index_file in $${all_roots} ; do \ target_dir=`dirname $${index_file}`; \ @@ -1742,10 +1041,21 @@ $(ZIP) -q -r $(JAVADOC_ARCHIVE) * ; \ popd ; -############################################################# -.PHONY: all docs coredocs otherdocs \ - $(ALL_OTHER_TARGETS) zip-docs +ZIP_TARGETS += $(JAVADOC_ARCHIVE) + +################################################################################ + +# Hook to include the corresponding custom file, if present. +$(eval $(call IncludeCustomExtension, , Javadoc.gmk)) ################################################################################ -$(eval $(call IncludeCustomExtension, , Javadoc-post.gmk)) +docs-javadoc: $(TARGETS) + +docs-copy: $(COPY_TARGETS) + +docs-zip: $(ZIP_TARGETS) + +all: docs-javadoc docs-copy docs-zip + +.PHONY: default all docs-javadoc docs-copy docs-zip diff -r f71b844f33d1 -r 95af45781076 make/Main.gmk --- a/make/Main.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/make/Main.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -341,15 +341,15 @@ # Docs targets docs-javadoc: - +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f Javadoc.gmk docs) + +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f Javadoc.gmk docs-javadoc) -docs-jvmtidoc: - +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f Javadoc.gmk jvmtidocs) +docs-copy: + +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f Javadoc.gmk docs-copy) -zip-docs: - +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f Javadoc.gmk zip-docs) +docs-zip: + +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f Javadoc.gmk docs-zip) -ALL_TARGETS += docs-javadoc docs-jvmtidoc zip-docs +ALL_TARGETS += docs-javadoc docs-copy docs-zip ################################################################################ # Cross compilation support @@ -376,15 +376,29 @@ # The interim-image is a small jlinked image that is used to generate artifacts # at build time for use when linking the real images. +INTERIM_JMOD_TARGETS := $(addsuffix -interim-jmod, $(INTERIM_IMAGE_MODULES)) + +define DeclareInterimJmodRecipe + $1-interim-jmod: + +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f CreateJmods.gmk \ + MODULE=$1 \ + JMODS_DIR=$(INTERIM_JMODS_DIR) \ + JMODS_TEMPDIR=$(INTERIM_JMODS_DIR)/temp \ + INTERIM_JMOD=true \ + ) +endef + +$(foreach m, $(INTERIM_IMAGE_MODULES), $(eval $(call DeclareInterimJmodRecipe,$m))) + interim-image: +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f InterimImage.gmk) ifeq ($(ENABLE_GENERATE_CLASSLIST), true) - generate-classlist: - +($(CD) $(JDK_TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f GenerateClasslist.gmk) + generate-link-opt-data: + +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f GenerateLinkOptData.gmk) endif -ALL_TARGETS += interim-image generate-classlist +ALL_TARGETS += $(INTERIM_JMOD_TARGETS) interim-image generate-link-opt-data ################################################################################ # Build tests @@ -607,13 +621,15 @@ # When creating a BUILDJDK, the java compilation has already been done by the # normal build and copied in. ifneq ($(CREATING_BUILDJDK), true) - $(foreach m, $(JAVA_MODULES), $(eval $m-jmod: $m-java)) + $(foreach m, $(JAVA_MODULES), $(eval $m_JMOD_DEPS += $m-java)) endif - $(foreach m, $(GENDATA_MODULES), $(eval $m-jmod: $m-gendata)) - $(foreach m, $(RMIC_MODULES), $(eval $m-jmod: $m-rmic)) - $(foreach m, $(LIBS_MODULES), $(eval $m-jmod: $m-libs)) - $(foreach m, $(LAUNCHER_MODULES), $(eval $m-jmod: $m-launchers)) - $(foreach m, $(COPY_MODULES), $(eval $m-jmod: $m-copy)) + $(foreach m, $(GENDATA_MODULES), $(eval $m_JMOD_DEPS += $m-gendata)) + $(foreach m, $(RMIC_MODULES), $(eval $m_JMOD_DEPS += $m-rmic)) + $(foreach m, $(LIBS_MODULES), $(eval $m_JMOD_DEPS += $m-libs)) + $(foreach m, $(LAUNCHER_MODULES), $(eval $m_JMOD_DEPS += $m-launchers)) + $(foreach m, $(COPY_MODULES), $(eval $m_JMOD_DEPS += $m-copy)) + $(foreach m, $(ALL_MODULES), $(eval $m-jmod: $($(m)_JMOD_DEPS))) + $(foreach m, $(INTERIM_IMAGE_MODULES), $(eval $m-interim-jmod: $($(m)_JMOD_DEPS))) # Jmods cannot be created until we have the jmod tool ready to run. During # a normal build we run it from the exploded image, but when cross compiling @@ -636,12 +652,13 @@ buildtools-modules: create-buildjdk else # While actually creating the buildjdk, the default deps applies. - $(JMOD_TARGETS): $(DEFAULT_JMOD_DEPS) + $(JMOD_TARGETS) $(INTERIM_JMOD_TARGETS): $(DEFAULT_JMOD_DEPS) endif else # The normal non cross compilation case uses the default deps. # To avoid races with the optimize target, that also needs to happen first. - $(JMOD_TARGETS): $(DEFAULT_JMOD_DEPS) exploded-image-optimize + $(JMOD_TARGETS) $(INTERIM_JMOD_TARGETS): $(DEFAULT_JMOD_DEPS) \ + exploded-image-optimize endif zip-security: java.base-java java.security.jgss-java java.security.jgss-libs \ @@ -654,16 +671,17 @@ ifeq ($(ENABLE_GENERATE_CLASSLIST), true) ifeq ($(CREATE_BUILDJDK), true) # If creating a buildjdk, the interim image needs to be based on that. - generate-classlist: create-buildjdk + generate-link-opt-data: create-buildjdk else ifeq ($(EXTERNAL_BUILDJDK), false) # If an external buildjdk has been provided, we skip generating an # interim-image and just use the external buildjdk for generating # classlist. - generate-classlist: interim-image + generate-link-opt-data: interim-image endif - generate-classlist: buildtools-jdk + generate-link-opt-data: buildtools-jdk - jdk-image jre-image: generate-classlist + # The generated classlist needs to go into java.base-jmod. + java.base-jmod jdk-image jre-image: generate-link-opt-data endif jdk-image: jmods zip-source source-tips demos samples jrtfs-jar @@ -683,9 +701,10 @@ docs-javadoc: $(GENSRC_TARGETS) rmic - docs-jvmtidoc: hotspot + # The gensrc step for jdk.jdi creates an html file that is used by docs-copy. + docs-copy: hotspot jdk.jdi-gensrc - zip-docs: docs-javadoc docs-jvmtidoc + docs-zip: docs-javadoc docs-copy test: jdk-image test-image @@ -694,7 +713,7 @@ create-buildjdk-interim-image: create-buildjdk-copy - interim-image: $(addsuffix -jmod, $(INTERIM_IMAGE_MODULES)) + interim-image: $(INTERIM_JMOD_TARGETS) test-make: clean-test-make @@ -812,7 +831,7 @@ endif # This target builds the documentation image -docs-image: docs-javadoc docs-jvmtidoc +docs-image: docs-javadoc docs-copy # This target builds the test image test-image: prepare-test-image test-image-hotspot-jtreg-native \ @@ -860,7 +879,7 @@ CLEAN_SUPPORT_DIR_TARGETS := $(addprefix clean-, $(CLEAN_SUPPORT_DIRS)) CLEAN_TESTS += hotspot-jtreg-native jdk-jtreg-native lib CLEAN_TEST_TARGETS += $(addprefix clean-test-, $(CLEAN_TESTS)) -CLEAN_PHASES := gensrc java native include docs +CLEAN_PHASES := gensrc java native include CLEAN_PHASE_TARGETS := $(addprefix clean-, $(CLEAN_PHASES)) CLEAN_MODULE_TARGETS := $(addprefix clean-, $(ALL_MODULES)) # Construct targets of the form clean-$module-$phase @@ -872,6 +891,9 @@ ($(CD) $(OUTPUT_ROOT) && $(RM) -r build*.log*) $(ECHO) Cleaned all build artifacts. +clean-docs: + $(call CleanDocs) + $(CLEAN_DIR_TARGETS): $(call CleanDir,$(patsubst clean-%, %, $@)) @@ -911,7 +933,7 @@ ) $(ECHO) Cleaned everything, you will have to re-run configure. -ALL_TARGETS += clean dist-clean $(CLEAN_DIR_TARGETS) $(CLEAN_SUPPORT_DIR_TARGETS) \ +ALL_TARGETS += clean clean-docs dist-clean $(CLEAN_DIR_TARGETS) $(CLEAN_SUPPORT_DIR_TARGETS) \ $(CLEAN_TEST_TARGETS) $(CLEAN_PHASE_TARGETS) $(CLEAN_MODULE_TARGETS) \ $(CLEAN_MODULE_PHASE_TARGETS) diff -r f71b844f33d1 -r 95af45781076 make/MainSupport.gmk --- a/make/MainSupport.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/make/MainSupport.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -41,6 +41,15 @@ JOBS=$(JOBS) $1) || true endef +define CleanDocs + @$(PRINTF) "Cleaning docs ..." + @$(PRINTF) "\n" $(LOG_DEBUG) + $(RM) -r $(SUPPORT_OUTPUTDIR)/docs + $(RM) -r $(SUPPORT_OUTPUTDIR)/javadoc + $(RM) -r $(IMAGES_OUTPUTDIR)/docs + @$(PRINTF) " done\n" +endef + # Cleans the dir given as $1 define CleanDir @$(PRINTF) "Cleaning $(strip $1) build artifacts ..." @@ -99,15 +108,6 @@ @$(PRINTF) " done\n" endef -define Clean-docs - @$(PRINTF) "Cleaning docs ..." - @$(PRINTF) "\n" $(LOG_DEBUG) - $(RM) -r $(SUPPORT_OUTPUTDIR)/docs - $(RM) -r $(IMAGES_OUTPUTDIR)/docs - $(RM) $(OUTPUT_ROOT)/bundles/jdk-*-docs.zip - @$(PRINTF) " done\n" -endef - define CleanModule $(call Clean-gensrc, $1) $(call Clean-java, $1) diff -r f71b844f33d1 -r 95af45781076 make/ZipSource.gmk --- a/make/ZipSource.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/make/ZipSource.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2016, Oracle and/or its affiliates. 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,61 +28,68 @@ include $(SPEC) include MakeBase.gmk include JavaCompilation.gmk +include Modules.gmk + +SRC_ZIP_WORK_DIR := $(SUPPORT_OUTPUTDIR)/src # Hook to include the corresponding custom file, if present. $(eval $(call IncludeCustomExtension, , ZipSource.gmk)) ################################################################################ +# Create the directory structure for src.zip using symlinks. +# //.java -# Use ?= to enable override in custom makefile -SRC_ZIP_INCLUDES ?= \ - com \ - java \ - javax \ - jdk \ - org \ - sun \ - # +# Find extra source dirs for a module that are not part of normal compilation +# but should be included in src.zip. +# $1: Module to find dirs for +ExtraSrcDirs = \ + $(wildcard $(SUPPORT_OUTPUTDIR)/rmic/$(strip $1)) -SRC_ZIP_EXCLUDES ?= +ALL_MODULES := $(FindAllModules) -SRC_ZIP_SRCS += $(wildcard \ - $(JDK_TOPDIR)/src/*/share/classes \ - $(JDK_TOPDIR)/src/*/$(OPENJDK_TARGET_OS)/classes \ - $(JDK_TOPDIR)/src/*/$(OPENJDK_TARGET_OS_API_DIR)/classes \ - $(LANGTOOLS_TOPDIR)/src/*/share/classes \ - $(CORBA_TOPDIR)/src/*/share/classes \ - $(JAXP_TOPDIR)/src/*/share/classes \ - $(JAXWS_TOPDIR)/src/*/share/classes \ - $(SUPPORT_OUTPUTDIR)/gensrc/j* \ - $(SUPPORT_OUTPUTDIR)/rmic/j* \ +# Generate the src dirs in the first make invocation and then call this makefile +# again to create src.zip. +$(foreach m, $(ALL_MODULES), \ + $(foreach d, $(call FindModuleSrcDirs, $m) $(call ExtraSrcDirs, $m), \ + $(eval $d_TARGET := $(SRC_ZIP_WORK_DIR)/$(patsubst $(TOPDIR)/%,%,$d)/$m) \ + $(if $(SRC_GENERATED), , \ + $(eval $$($d_TARGET): $d ; \ + $$(if $(filter $(TOPDIR)/%, $d), $$(link-file-relative), $$(link-file-absolute)) \ + ) \ ) \ - # + $(eval SRC_ZIP_SRCS += $$($d_TARGET)) \ + $(eval SRC_ZIP_SRCS_$m += $$($d_TARGET)) \ + ) \ +) + +TARGETS += $(SRC_ZIP_SRCS) -# Need to copy launcher src files into desired directory structure -# before zipping the sources. -$(eval $(call SetupCopyFiles,COPY_LAUNCHER_SRC, \ - SRC := $(JDK_TOPDIR)/src/java.base, \ - DEST := $(SUPPORT_OUTPUTDIR)/src/launcher, \ - FLATTEN := true, \ - FILES := $(wildcard \ - $(JDK_TOPDIR)/src/java.base/share/native/launcher/* \ - $(JDK_TOPDIR)/src/java.base/share/native/libjli/* \ - $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_API_DIR)/native/libjli/java_md*))) +################################################################################ +# Only evaluate the creation of src.zip in a sub make call when the symlinked +# src directory structure has been generated. +ifeq ($(SRC_GENERATED), true) + $(eval $(call SetupZipArchive, BUILD_SRC_ZIP, \ + SRC := $(dir $(SRC_ZIP_SRCS)), \ + INCLUDES := $(SRC_ZIP_INCLUDES), \ + INCLUDE_FILES := $(SRC_ZIP_INCLUDE_FILES), \ + EXCLUDES := $(SRC_ZIP_EXCLUDES), \ + EXCLUDE_FILES := $(SRC_ZIP_EXCLUDE_FILES), \ + SUFFIXES := .java, \ + ZIP := $(SUPPORT_OUTPUTDIR)/src.zip, \ + )) -# This dir needs to exist before macro is evaluated to avoid warning from find. -$(call MakeDir, $(SUPPORT_OUTPUTDIR)/src) -$(eval $(call SetupZipArchive,BUILD_SRC_ZIP, \ - SRC := $(SRC_ZIP_SRCS) $(SUPPORT_OUTPUTDIR)/src, \ - INCLUDES := $(SRC_ZIP_INCLUDES) launcher, \ - EXCLUDES := $(SRC_ZIP_EXCLUDES), \ - EXCLUDE_FILES := $(SRC_ZIP_EXCLUDE_FILES), \ - SUFFIXES := .java .c .h, \ - ZIP := $(SUPPORT_OUTPUTDIR)/src.zip, \ - EXTRA_DEPS := $(COPY_LAUNCHER_SRC))) + do-zip: $(BUILD_SRC_ZIP) + + .PHONY: do-zip +endif + +zip: $(SRC_ZIP_SRCS) + +$(MAKE) $(MAKE_ARGS) -f ZipSource.gmk do-zip SRC_GENERATED=true + +TARGETS += zip ################################################################################ -all: $(BUILD_SRC_ZIP) +all: $(TARGETS) -.PHONY: default all +.PHONY: default all zip diff -r f71b844f33d1 -r 95af45781076 make/common/MakeBase.gmk --- a/make/common/MakeBase.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/make/common/MakeBase.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -454,7 +454,7 @@ Too many named arguments to macro, please update MAX_PARAMS in MakeBase.gmk)) # Iterate over 2 3 4... and evaluate the named parameters with $1_ as prefix $(foreach i,$(PARAM_SEQUENCE), $(if $(strip $($i)),\ - $(strip $1)_$(strip $($i)))$(NEWLINE)) + $(strip $1)_$(strip $(call DoubleDollar, $($i))))$(NEWLINE)) # Debug print all named parameter names and values $(if $(findstring $(LOG_LEVEL),debug trace), \ $(info $0 $(strip $1) $(foreach i,$(PARAM_SEQUENCE), \ @@ -575,25 +575,21 @@ $($(strip $1)_dotdots)/$($(strip $1)_suffix) ################################################################################ -# link-file-* works similarly to install file but creates a symlink instead on -# platforms that support it. There are two versions, either creating a relative -# or an absolute link. -ifeq ($(OPENJDK_BUILD_OS), windows) - link-file-absolute = $(install-file) - link-file-relative = $(install-file) -else - define link-file-relative +# link-file-* works similarly to install-file but creates a symlink instead. +# There are two versions, either creating a relative or an absolute link. Be +# careful when using this on Windows since the symlink created is only valid in +# the unix emulation environment. +define link-file-relative $(call MakeDir, $(@D)) $(RM) $@ $(LN) -s $(call RelativePath, $<, $(@D)) $@ - endef +endef - define link-file-absolute +define link-file-absolute $(call MakeDir, $(@D)) $(RM) $@ $(LN) -s $< $@ - endef -endif +endef ################################################################################ # Filter out duplicate sub strings while preserving order. Keeps the first occurance. diff -r f71b844f33d1 -r 95af45781076 make/common/Modules.gmk --- a/make/common/Modules.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/make/common/Modules.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -108,6 +108,7 @@ jdk.charsets \ jdk.crypto.ec \ jdk.crypto.pkcs11 \ + jdk.desktop \ jdk.dynalink \ jdk.jsobject \ jdk.localedata \ @@ -177,6 +178,16 @@ $(patsubst %,%/$(strip $1)/$(sub)/module-info.java, $(TOP_SRC_DIRS))) \ $(patsubst %,%/$(strip $1)/module-info.java, $(IMPORT_MODULES_SRC))) +# Find module-info.java files in the specific source dir +# Param 1 - Src dir to find module-info.java files in +FindModuleInfosForSrcDir = \ + $(wildcard \ + $(foreach sub, $(SRC_SUBDIRS), \ + $(patsubst %,%/*/$(sub)/module-info.java, $(strip $1)) \ + ) \ + $(patsubst %,%/*/module-info.java, $(strip $1)) \ + ) + # Extract the module names from the paths of module-info.java files. The # position of the module directory differs depending on if this is an imported # src dir or not. @@ -192,6 +203,13 @@ $(sort $(filter-out $(MODULES_FILTER), \ $(call GetModuleNameFromModuleInfo, $(MODULE_INFOS)))) +# Find all modules in a specific src dir +# Param 1 - Src dir to find modules in +FindModulesForSrcDir = \ + $(sort $(filter-out $(MODULES_FILTER), \ + $(call GetModuleNameFromModuleInfo, $(call FindModuleInfosForSrcDir, $1)) \ + )) + FindImportedModules = \ $(filter-out $(MODULES_FILTER), \ $(if $(IMPORT_MODULES_CLASSES), $(notdir $(wildcard $(IMPORT_MODULES_CLASSES)/*)))) diff -r f71b844f33d1 -r 95af45781076 make/common/NativeCompilation.gmk --- a/make/common/NativeCompilation.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/make/common/NativeCompilation.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -746,9 +746,10 @@ # This is a rough heuristic and may not always print accurate information. $$($1_BUILD_INFO): $$($1_SRCS) $$($1_COMPILE_VARDEPS_FILE) ifeq ($$(wildcard $$($1_TARGET)),) - $(ECHO) 'Creating $$($1_BASENAME) from $$(words $$(filter-out %.vardeps, $$?)) file(s)' + $(ECHO) 'Creating $$(subst $$(BUILD_OUTPUT)/,,$$($1_TARGET)) from $$(words \ + $$(filter-out %.vardeps, $$?)) file(s)' else - $(ECHO) $$(strip 'Updating $$($1_BASENAME)' \ + $(ECHO) $$(strip 'Updating $$(subst $$(BUILD_OUTPUT)/,,$$($1_TARGET))' \ $$(if $$(filter-out %.vardeps, $$?), \ 'due to $$(words $$(filter-out %.vardeps, $$?)) file(s)', \ $$(if $$(filter %.vardeps, $$?), 'due to makefile changes'))) diff -r f71b844f33d1 -r 95af45781076 make/common/ZipArchive.gmk --- a/make/common/ZipArchive.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/make/common/ZipArchive.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -73,6 +73,11 @@ else $1_ZIP_INCLUDES := $$(addprefix -i$(SPACE)$(DQUOTE),$$(addsuffix /*$(DQUOTE),$$($1_INCLUDES))) endif + else + ifneq ($$($1_SUFFIXES),) + $1_ZIP_INCLUDES := $$(foreach s,$$($1_SUFFIXES), \ + $$(addprefix -i$(SPACE)$(DQUOTE),*$$s$(DQUOTE))) + endif endif ifneq ($$($1_INCLUDE_FILES),) $1_ZIP_INCLUDES += $$(addprefix -i$(SPACE),$$($1_INCLUDE_FILES)) diff -r f71b844f33d1 -r 95af45781076 nashorn/.hgtags --- a/nashorn/.hgtags Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/.hgtags Fri Nov 11 16:44:36 2016 +0100 @@ -375,3 +375,5 @@ e3b11296395b39bfeb3364f26c2ef77fa652e300 jdk-9+139 785843878cf78d50cc2959ea2c5a4202bbe885b4 jdk-9+140 a46b7d3867957a868a6cc8ee66c05079b883733a jdk-9+141 +d3f5d7311a1aec3152b17d75046d5d298245a0b4 jdk-9+142 +b4e57ead3fae4939b70dd345d1f6744a1dedfa21 jdk-9+143 diff -r f71b844f33d1 -r 95af45781076 nashorn/samples/dynalink/ArrayStreamLinkerExporter.java --- a/nashorn/samples/dynalink/ArrayStreamLinkerExporter.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/samples/dynalink/ArrayStreamLinkerExporter.java Fri Nov 11 16:44:36 2016 +0100 @@ -38,9 +38,10 @@ import java.util.stream.LongStream; import java.util.stream.Stream; import jdk.dynalink.CallSiteDescriptor; -import jdk.dynalink.CompositeOperation; import jdk.dynalink.NamedOperation; +import jdk.dynalink.NamespaceOperation; import jdk.dynalink.Operation; +import jdk.dynalink.StandardNamespace; import jdk.dynalink.StandardOperation; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.GuardingDynamicLinker; @@ -104,9 +105,9 @@ final CallSiteDescriptor desc = request.getCallSiteDescriptor(); final Operation op = desc.getOperation(); final Object name = NamedOperation.getName(op); - final boolean getProp = CompositeOperation.contains( + final boolean getProp = NamespaceOperation.contains( NamedOperation.getBaseOperation(op), - StandardOperation.GET_PROPERTY); + StandardOperation.GET, StandardNamespace.PROPERTY); if (getProp && "stream".equals(name)) { return new GuardedInvocation(ARRAY_TO_STREAM, Guards.isOfClass(self.getClass(), GUARD_TYPE)); diff -r f71b844f33d1 -r 95af45781076 nashorn/samples/dynalink/BufferIndexingLinkerExporter.java --- a/nashorn/samples/dynalink/BufferIndexingLinkerExporter.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/samples/dynalink/BufferIndexingLinkerExporter.java Fri Nov 11 16:44:36 2016 +0100 @@ -29,6 +29,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import static jdk.dynalink.StandardNamespace.ELEMENT; +import static jdk.dynalink.StandardNamespace.PROPERTY; +import static jdk.dynalink.StandardOperation.GET; +import static jdk.dynalink.StandardOperation.SET; + import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import java.nio.Buffer; @@ -42,10 +47,10 @@ import java.util.ArrayList; import java.util.List; import jdk.dynalink.CallSiteDescriptor; -import jdk.dynalink.CompositeOperation; import jdk.dynalink.NamedOperation; +import jdk.dynalink.NamespaceOperation; import jdk.dynalink.Operation; -import jdk.dynalink.StandardOperation; +import jdk.dynalink.StandardNamespace; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.GuardingDynamicLinker; import jdk.dynalink.linker.GuardingDynamicLinkerExporter; @@ -135,23 +140,6 @@ IS_DOUBLEBUFFER = Guards.isInstance(DoubleBuffer.class, GUARD_TYPE); } - // locate the first standard operation from the call descriptor - private static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) { - final Operation base = NamedOperation.getBaseOperation(desc.getOperation()); - if (base instanceof StandardOperation) { - return (StandardOperation)base; - } else if (base instanceof CompositeOperation) { - final CompositeOperation cop = (CompositeOperation)base; - for(int i = 0; i < cop.getOperationCount(); ++i) { - final Operation op = cop.getOperation(i); - if (op instanceof StandardOperation) { - return (StandardOperation)op; - } - } - } - return null; - } - @Override public List get() { final ArrayList linkers = new ArrayList<>(); @@ -170,22 +158,25 @@ } final CallSiteDescriptor desc = request.getCallSiteDescriptor(); - final StandardOperation op = getFirstStandardOperation(desc); - if (op == null) { + final Operation namedOp = desc.getOperation(); + final Operation namespaceOp = NamedOperation.getBaseOperation(namedOp); + final Operation op = NamespaceOperation.getBaseOperation(namespaceOp); + final StandardNamespace ns = StandardNamespace.findFirst(namespaceOp); + if (ns == null) { return null; } - switch (op) { - case GET_ELEMENT: + if (op == GET) { + if (ns == ELEMENT) { return linkGetElement(self); - case SET_ELEMENT: - return linkSetElement(self); - case GET_PROPERTY: { + } else if (ns == PROPERTY) { final Object name = NamedOperation.getName(desc.getOperation()); if ("length".equals(name)) { return linkLength(); } } + } else if (op == SET && ns == ELEMENT) { + return linkSetElement(self); } return null; diff -r f71b844f33d1 -r 95af45781076 nashorn/samples/dynalink/DOMLinkerExporter.java --- a/nashorn/samples/dynalink/DOMLinkerExporter.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/samples/dynalink/DOMLinkerExporter.java Fri Nov 11 16:44:36 2016 +0100 @@ -35,9 +35,10 @@ import java.util.ArrayList; import java.util.List; import jdk.dynalink.CallSiteDescriptor; -import jdk.dynalink.CompositeOperation; import jdk.dynalink.NamedOperation; +import jdk.dynalink.NamespaceOperation; import jdk.dynalink.Operation; +import jdk.dynalink.StandardNamespace; import jdk.dynalink.StandardOperation; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.GuardingDynamicLinker; @@ -132,9 +133,9 @@ final CallSiteDescriptor desc = request.getCallSiteDescriptor(); final Operation op = desc.getOperation(); final Object name = NamedOperation.getName(op); - final boolean getProp = CompositeOperation.contains( + final boolean getProp = NamespaceOperation.contains( NamedOperation.getBaseOperation(op), - StandardOperation.GET_PROPERTY); + StandardOperation.GET, StandardNamespace.PROPERTY); if (getProp && name instanceof String) { final String nameStr = (String)name; diff -r f71b844f33d1 -r 95af45781076 nashorn/samples/dynalink/MissingMethodLinkerExporter.java --- a/nashorn/samples/dynalink/MissingMethodLinkerExporter.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/samples/dynalink/MissingMethodLinkerExporter.java Fri Nov 11 16:44:36 2016 +0100 @@ -35,9 +35,10 @@ import java.util.ArrayList; import java.util.List; import jdk.dynalink.CallSiteDescriptor; -import jdk.dynalink.CompositeOperation; import jdk.dynalink.NamedOperation; +import jdk.dynalink.NamespaceOperation; import jdk.dynalink.Operation; +import jdk.dynalink.StandardNamespace; import jdk.dynalink.StandardOperation; import jdk.dynalink.beans.BeansLinker; import jdk.dynalink.linker.GuardedInvocation; @@ -99,23 +100,6 @@ "getName", MethodType.methodType(String.class)); } - // locate the first standard operation from the call descriptor - private static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) { - final Operation base = NamedOperation.getBaseOperation(desc.getOperation()); - if (base instanceof StandardOperation) { - return (StandardOperation)base; - } else if (base instanceof CompositeOperation) { - final CompositeOperation cop = (CompositeOperation)base; - for(int i = 0; i < cop.getOperationCount(); ++i) { - final Operation op = cop.getOperation(i); - if (op instanceof StandardOperation) { - return (StandardOperation)op; - } - } - } - return null; - } - @Override public List get() { final ArrayList linkers = new ArrayList<>(); @@ -140,8 +124,12 @@ // we return that method object. If not, we return a MissingMethod object. if (self instanceof MissingMethodHandler) { // Check if this is a named GET_METHOD first. - final boolean isGetMethod = getFirstStandardOperation(desc) == StandardOperation.GET_METHOD; - final Object name = NamedOperation.getName(desc.getOperation()); + final Operation namedOp = desc.getOperation(); + final Operation namespaceOp = NamedOperation.getBaseOperation(namedOp); + final Operation op = NamespaceOperation.getBaseOperation(namespaceOp); + + final boolean isGetMethod = op == StandardOperation.GET && StandardNamespace.findFirst(namespaceOp) == StandardNamespace.METHOD; + final Object name = NamedOperation.getName(namedOp); if (isGetMethod && name instanceof String) { final GuardingDynamicLinker javaLinker = beansLinker.getLinkerForClass(self.getClass()); GuardedInvocation inv; @@ -166,7 +154,7 @@ } else if (self instanceof MissingMethod) { // This is step (2). We call MissingMethodHandler.doesNotUnderstand here // Check if this is this a CALL first. - final boolean isCall = getFirstStandardOperation(desc) == StandardOperation.CALL; + final boolean isCall = NamedOperation.getBaseOperation(desc.getOperation()) == StandardOperation.CALL; if (isCall) { MethodHandle mh = DOES_NOT_UNDERSTAND; diff -r f71b844f33d1 -r 95af45781076 nashorn/samples/dynalink/UnderscoreNameLinkerExporter.java --- a/nashorn/samples/dynalink/UnderscoreNameLinkerExporter.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/samples/dynalink/UnderscoreNameLinkerExporter.java Fri Nov 11 16:44:36 2016 +0100 @@ -34,9 +34,10 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import jdk.dynalink.CallSiteDescriptor; -import jdk.dynalink.CompositeOperation; import jdk.dynalink.NamedOperation; +import jdk.dynalink.NamespaceOperation; import jdk.dynalink.Operation; +import jdk.dynalink.StandardNamespace; import jdk.dynalink.StandardOperation; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.GuardingDynamicLinker; @@ -68,23 +69,6 @@ return buf.toString(); } - // locate the first standard operation from the call descriptor - private static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) { - final Operation base = NamedOperation.getBaseOperation(desc.getOperation()); - if (base instanceof StandardOperation) { - return (StandardOperation)base; - } else if (base instanceof CompositeOperation) { - final CompositeOperation cop = (CompositeOperation)base; - for(int i = 0; i < cop.getOperationCount(); ++i) { - final Operation op = cop.getOperation(i); - if (op instanceof StandardOperation) { - return (StandardOperation)op; - } - } - } - return null; - } - @Override public List get() { final ArrayList linkers = new ArrayList<>(); @@ -92,12 +76,14 @@ @Override public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices) throws Exception { - final Object self = request.getReceiver(); final CallSiteDescriptor desc = request.getCallSiteDescriptor(); final Operation op = desc.getOperation(); final Object name = NamedOperation.getName(op); + final Operation namespaceOp = NamedOperation.getBaseOperation(op); // is this a named GET_METHOD? - final boolean isGetMethod = getFirstStandardOperation(desc) == StandardOperation.GET_METHOD; + final boolean isGetMethod = + NamespaceOperation.getBaseOperation(namespaceOp) == StandardOperation.GET + && StandardNamespace.findFirst(namespaceOp) == StandardNamespace.METHOD; if (isGetMethod && name instanceof String) { final String str = (String)name; if (str.indexOf('_') == -1) { @@ -106,13 +92,9 @@ final String nameStr = translateToCamelCase(str); // create a new call descriptor to use translated name - final CallSiteDescriptor newDesc = new CallSiteDescriptor( - desc.getLookup(), - new NamedOperation(NamedOperation.getBaseOperation(op), nameStr), - desc.getMethodType()); + final CallSiteDescriptor newDesc = desc.changeOperation(((NamedOperation)op).changeName(nameStr)); // create a new Link request to link the call site with translated name - final LinkRequest newRequest = new SimpleLinkRequest(newDesc, - request.isCallSiteUnstable(), request.getArguments()); + final LinkRequest newRequest = request.replaceArguments(newDesc, request.getArguments()); // return guarded invocation linking the translated request return linkerServices.getGuardedInvocation(newRequest); } diff -r f71b844f33d1 -r 95af45781076 nashorn/samples/dynalink/underscore_linker.js --- a/nashorn/samples/dynalink/underscore_linker.js Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/samples/dynalink/underscore_linker.js Fri Nov 11 16:44:36 2016 +0100 @@ -46,5 +46,6 @@ // but make sure classpath points to the pluggable linker jar! `jjs -cp underscore_linker.jar underscore.js` +print($ERR) print($OUT) diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java Fri Nov 11 16:44:36 2016 +0100 @@ -83,9 +83,11 @@ package jdk.dynalink; +import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; import java.util.Objects; +import java.util.function.Supplier; /** * Call site descriptors contain all the information necessary for linking a @@ -148,44 +150,82 @@ } /** - * Creates a new call site descriptor from this descriptor, which is - * identical to this, except it changes the method type. Invokes - * {@link #changeMethodTypeInternal(MethodType)} and checks that it returns - * a descriptor of the same class as this descriptor. + * Finds or creates a call site descriptor that only differs in its + * method type from this descriptor. + * Invokes {@link #changeMethodTypeInternal(MethodType)}. * * @param newMethodType the new method type - * @return a new call site descriptor, with the method type changed. - * @throws RuntimeException if {@link #changeMethodTypeInternal(MethodType)} - * returned a descriptor of different class than this object. - * @throws NullPointerException if {@link #changeMethodTypeInternal(MethodType)} - * returned null. + * @return a call site descriptor with changed method type. + * @throws NullPointerException if {@code newMethodType} is null. */ public final CallSiteDescriptor changeMethodType(final MethodType newMethodType) { - final CallSiteDescriptor changed = Objects.requireNonNull( - changeMethodTypeInternal(newMethodType), - "changeMethodTypeInternal() must not return null."); + final CallSiteDescriptor changed = changeMethodTypeInternal(newMethodType); - if (getClass() != changed.getClass()) { - throw new RuntimeException( - "changeMethodTypeInternal() must return an object of the same class it is invoked on."); + if (getClass() != CallSiteDescriptor.class) { + assertChangeInvariants(changed, "changeMethodTypeInternal"); + alwaysAssert(operation == changed.operation, () -> "changeMethodTypeInternal must not change the descriptor's operation"); + alwaysAssert(newMethodType == changed.methodType, () -> "changeMethodTypeInternal didn't set the correct new method type"); } - return changed; } /** - * Creates a new call site descriptor from this descriptor, which is - * identical to this, except it changes the method type. Subclasses must - * override this method to return an object of their exact class. + * Finds or creates a call site descriptor that only differs in its + * method type from this descriptor. Subclasses must override this method + * to return an object of their exact class. If an overridden method changes + * something other than the method type in the descriptor (its class, lookup, + * or operation), or returns null, an {@code AssertionError} will be thrown + * from {@link #changeMethodType(MethodType)}. * * @param newMethodType the new method type - * @return a new call site descriptor, with the method type changed. + * @return a call site descriptor with the changed method type. */ protected CallSiteDescriptor changeMethodTypeInternal(final MethodType newMethodType) { return new CallSiteDescriptor(getLookupPrivileged(), operation, newMethodType); } /** + * Finds or creates a call site descriptor that only differs in its + * operation from this descriptor. + * Invokes {@link #changeOperationInternal(Operation)}. + * + * @param newOperation the new operation + * @return a call site descriptor with the changed operation. + * @throws NullPointerException if {@code newOperation} is null. + * @throws SecurityException if the descriptor's lookup isn't the + * {@link MethodHandles#publicLookup()}, and a security manager is present, + * and a check for {@code RuntimePermission("dynalink.getLookup")} fails. + * This is necessary as changing the operation in the call site descriptor + * allows fabrication of descriptors for arbitrary operations with the lookup. + */ + public final CallSiteDescriptor changeOperation(final Operation newOperation) { + getLookup(); // force security check + final CallSiteDescriptor changed = changeOperationInternal(newOperation); + + if (getClass() != CallSiteDescriptor.class) { + assertChangeInvariants(changed, "changeOperationInternal"); + alwaysAssert(methodType == changed.methodType, () -> "changeOperationInternal must not change the descriptor's method type"); + alwaysAssert(newOperation == changed.operation, () -> "changeOperationInternal didn't set the correct new operation"); + } + return changed; + } + + /** + * Finds or creates a call site descriptor that only differs in its + * operation from this descriptor. Subclasses must override this method + * to return an object of their exact class. If an overridden method changes + * something other than the operation in the descriptor (its class, lookup, + * or method type), or returns null, an {@code AssertionError} will be thrown + * from {@link #changeOperation(Operation)}. + * + * @param newOperation the new operation + * @return a call site descriptor with the changed operation. + */ + protected CallSiteDescriptor changeOperationInternal(final Operation newOperation) { + return new CallSiteDescriptor(getLookupPrivileged(), newOperation, methodType); + } + + /** * Returns true if this call site descriptor is equal to the passed object. * It is considered equal if the other object is of the exact same class, * their operations and method types are equal, and their lookups have the @@ -255,4 +295,16 @@ final StringBuilder b = new StringBuilder(o.length() + mt.length() + 1 + l.length()); return b.append(o).append(mt).append('@').append(l).toString(); } + + private void assertChangeInvariants(final CallSiteDescriptor changed, final String caller) { + alwaysAssert(changed != null, () -> caller + " must not return null."); + alwaysAssert(getClass() == changed.getClass(), () -> caller + " must not change the descriptor's class"); + alwaysAssert(lookupsEqual(getLookupPrivileged(), changed.getLookupPrivileged()), () -> caller + " must not change the descriptor's lookup"); + } + + private static void alwaysAssert(final boolean cond, final Supplier errorMessage) { + if (!cond) { + throw new AssertionError(errorMessage.get()); + } + } } diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/CompositeOperation.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/CompositeOperation.java Mon Nov 14 11:15:43 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,297 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.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, and Oracle licenses the original version of this file under the BSD - * license: - */ -/* - Copyright 2015 Attila Szegedi - - Licensed under both the Apache License, Version 2.0 (the "Apache License") - and the BSD License (the "BSD License"), with licensee being free to - choose either of the two at their discretion. - - You may not use this file except in compliance with either the Apache - License or the BSD License. - - If you choose to use this file in compliance with the Apache License, the - following notice applies to you: - - You may obtain a copy of the Apache License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied. See the License for the specific language governing - permissions and limitations under the License. - - If you choose to use this file in compliance with the BSD License, the - following notice applies to you: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package jdk.dynalink; - -import java.util.Arrays; -import java.util.Objects; - -/** - * Describes an operation that is composed of at least two other operations. The - * component operations are treated as alternatives to each other in order of - * preference. The semantics of the composite operation is "first successful". - * That is, a composite of {@code GET_PROPERTY|GET_ELEMENT:color} should be - * interpreted as get the property named "color" on the object, but if the - * property does not exist, then get the collection element named "color" - * instead. - *

    - * Composite operations are helpful in implementation of languages that - * don't distinguish between one or more of the property, method, and element - * namespaces, or when expressing operations against objects that can be - * considered both ordinary objects and collections, e.g. Java - * {@link java.util.Map} objects. A composite operation - * {@code GET_PROPERTY|GET_ELEMENT:empty} against a Java map will always match - * the {@link java.util.Map#isEmpty()} property, but - * {@code GET_ELEMENT|GET_PROPERTY:empty} will actually match a map element with - * key {@code "empty"} if the map contains that key, and only fall back to the - * {@code isEmpty()} property getter if the map does not contain the key. If - * the source language mandates this semantics, it can be easily achieved using - * composite operations. - *

    - * Even if the language itself doesn't distinguish between some of the - * namespaces, it can be helpful to map different syntaxes to different - * compositions. E.g. the source expression {@code obj.color} could map to - * {@code GET_PROPERTY|GET_ELEMENT|GET_METHOD:color}, but a different source - * expression that looks like collection element access {@code obj[key]} could - * be expressed instead as {@code GET_ELEMENT|GET_PROPERTY|GET_METHOD}. - * Finally, if the retrieved value is subsequently called, then it makes sense - * to bring {@code GET_METHOD} to the front of the list: the getter part of the - * source expression {@code obj.color()} should be - * {@code GET_METHOD|GET_PROPERTY|GET_ELEMENT:color} and the one for - * {@code obj[key]()} should be {@code GET_METHOD|GET_ELEMENT|GET_PROPERTY}. - *

    - * The elements of a composite operation can not be composites or named - * operations, but rather simple operations such are elements of - * {@link StandardOperation}. A composite operation itself can serve as the base - * operation of a named operation, though; a typical way to construct e.g. the - * {@code GET_ELEMENT|GET_PROPERTY:empty} from above would be: - *

    - * Operation getElementOrPropertyEmpty = new NamedOperation(
    - *     new CompositeOperation(
    - *         StandardOperation.GET_ELEMENT,
    - *         StandardOperation.GET_PROPERTY),
    - *     "empty");
    - * 
    - *

    - * Not all compositions make sense. Typically, any combination in any order of - * standard getter operations {@code GET_PROPERTY}, {@code GET_ELEMENT}, and - * {@code GET_METHOD} make sense, as do combinations of {@code SET_PROPERTY} and - * {@code SET_ELEMENT}; other standard operations should not be combined. The - * constructor will allow any combination of operations, though. - */ -public final class CompositeOperation implements Operation { - private final Operation[] operations; - - /** - * Constructs a new composite operation. - * @param operations the components for this composite operation. The passed - * array will be cloned. - * @throws IllegalArgumentException if less than two components are - * specified, or any component is itself a {@link CompositeOperation} or a - * {@link NamedOperation}. - * @throws NullPointerException if either the operations array or any of its - * elements are {@code null}. - */ - public CompositeOperation(final Operation... operations) { - Objects.requireNonNull(operations, "operations array is null"); - if (operations.length < 2) { - throw new IllegalArgumentException("Must have at least two operations"); - } - final Operation[] clonedOps = operations.clone(); - for(int i = 0; i < clonedOps.length; ++i) { - final Operation op = clonedOps[i]; - if (op == null) { - throw new NullPointerException("operations[" + i + "] is null"); - } else if (op instanceof NamedOperation) { - throw new IllegalArgumentException("operations[" + i + "] is a NamedOperation"); - } else if (op instanceof CompositeOperation) { - throw new IllegalArgumentException("operations[" + i + "] is a CompositeOperation"); - } - } - this.operations = clonedOps; - } - - /** - * Returns the component operations in this composite operation. The - * returned array is a copy and changes to it don't have effect on this - * object. - * @return the component operations in this composite operation. - */ - public Operation[] getOperations() { - return operations.clone(); - } - - /** - * Returns the number of component operations in this composite operation. - * @return the number of component operations in this composite operation. - */ - public int getOperationCount() { - return operations.length; - } - - /** - * Returns the i-th component operation in this composite operation. - * @param i the operation index - * @return the i-th component operation in this composite operation. - * @throws IndexOutOfBoundsException if the index is out of range. - */ - public Operation getOperation(final int i) { - try { - return operations[i]; - } catch (final ArrayIndexOutOfBoundsException e) { - throw new IndexOutOfBoundsException(Integer.toString(i)); - } - } - - /** - * Returns true if this composite operation contains an operation equal to - * the specified operation. - * @param operation the operation being searched for. Must not be null. - * @return true if the if this composite operation contains an operation - * equal to the specified operation. - */ - public boolean contains(final Operation operation) { - Objects.requireNonNull(operation); - for(final Operation component: operations) { - if (component.equals(operation)) { - return true; - } - } - return false; - } - - /** - * Returns true if the other object is also a composite operation and their - * component operations are equal. - * @param obj the object to compare to - * @return true if this object is equal to the other one, false otherwise. - */ - @Override - public boolean equals(final Object obj) { - if (obj instanceof CompositeOperation) { - return Arrays.equals(operations, ((CompositeOperation)obj).operations); - } - return false; - } - - /** - * Returns the hash code of this composite operation. Defined to be equal - * to {@code java.util.Arrays.hashCode(operations)}. - */ - @Override - public int hashCode() { - return Arrays.hashCode(operations); - }; - - /** - * Returns the string representation of this composite operation. Defined to - * be the {@code toString} of its component operations, each separated by - * the vertical line character (e.g. {@code "GET_PROPERTY|GET_ELEMENT"}). - * @return the string representation of this composite operation. - */ - @Override - public String toString() { - final StringBuilder b = new StringBuilder(); - b.append(operations[0]); - for(int i = 1; i < operations.length; ++i) { - b.append('|').append(operations[i]); - } - return b.toString(); - } - - /** - * Returns the components of the passed operation if it is a composite - * operation, otherwise returns an array containing the operation itself. - * This allows for returning an array of component even if it is not known - * whether the operation is itself a composite (treating a non-composite - * operation as if it were a single-element composite of itself). - * @param op the operation whose components are retrieved. - * @return if the passed operation is a composite operation, returns its - * {@link #getOperations()}, otherwise returns the operation itself. - */ - public static Operation[] getOperations(final Operation op) { - return op instanceof CompositeOperation - ? ((CompositeOperation)op).operations.clone() - : new Operation[] { op }; - } - - /** - * Returns true if the specified potentially composite operation is a - * {@link CompositeOperation} and contains an operation equal to the - * specified operation. If {@code composite} is not a - * {@link CompositeOperation}, then the two operations are compared for - * equality. - * @param composite the potentially composite operation. Must not be null. - * @param operation the operation being searched for. Must not be null. - * @return true if the if the passed operation is a - * {@link CompositeOperation} and contains a component operation equal to - * the specified operation, or if it is not a {@link CompositeOperation} and - * is equal to {@code operation}. - */ - public static boolean contains(final Operation composite, final Operation operation) { - if (composite instanceof CompositeOperation) { - return ((CompositeOperation)composite).contains(operation); - } - return composite.equals(Objects.requireNonNull(operation)); - } -} diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java Fri Nov 11 16:44:36 2016 +0100 @@ -88,15 +88,47 @@ /** * Operation that associates a name with another operation. Typically used with * operations that normally take a name or an index to bind them to a fixed - * name. E.g. {@code new NamedOperation(StandardOperation.GET_PROPERTY, "color")} + * name. E.g. + *

    + *     new NamedOperation(
    + *         new NamespaceOperation(
    + *             StandardOperation.GET,
    + *             StandardNamespace.PROPERTY),
    + *         "color")
    + * 
    * will be a named operation for getting the property named "color" on the * object it is applied to, and - * {@code new NamedOperation(StandardOperation.GET_ELEMENT, 3)} will be a named - * operation for getting the element at index 3 from the collection it is - * applied to. In these cases, the expected signature of the call site for the + *
    + *     new NamedOperation(
    + *         new NamespaceOperation(
    + *             StandardOperation.GET,
    + *             StandardNamespace.ELEMENT),
    + *         3)
    + * 
    + * will be a named operation for getting the element at index 3 from the collection + * it is applied to ("name" in this context is akin to "address" and encompasses both + * textual names, numeric indices, or any other kinds of addressing that linkers can + * understand). In these cases, the expected signature of the call site for the * operation will change to no longer include the name parameter. Specifically, * the documentation for all {@link StandardOperation} members describes how * they are affected by being incorporated into a named operation. + *

    While {@code NamedOperation} can be constructed directly, it is often convenient + * to use the {@link Operation#named(Object)} factory method instead, e.g.: + *

    + *    StandardOperation.GET
    + *        .withNamespace(StandardNamespace.ELEMENT),
    + *        .named(3)
    + *     )
    + * 
    + *

    + * Even though {@code NamedOperation} is most often used with {@link NamespaceOperation} as + * its base, it can have other operations as its base too (except another named operation). + * Specifically, {@link StandardOperation#CALL} as well as {@link StandardOperation#NEW} can + * both be used with {@code NamedOperation} directly. The contract for these operations is such + * that when they are used as named operations, their name is only used for diagnostic messages, + * usually containing the textual representation of the source expression that retrieved the + * callee, e.g. {@code StandardOperation.CALL.named("window.open")}. + *

    */ public final class NamedOperation implements Operation { private final Operation baseOperation; @@ -116,7 +148,7 @@ */ public NamedOperation(final Operation baseOperation, final Object name) { if (baseOperation instanceof NamedOperation) { - throw new IllegalArgumentException("baseOperation is a named operation"); + throw new IllegalArgumentException("baseOperation is a NamedOperation"); } this.baseOperation = Objects.requireNonNull(baseOperation, "baseOperation is null"); this.name = Objects.requireNonNull(name, "name is null"); @@ -139,6 +171,16 @@ } /** + * Finds or creates a named operation that differs from this one only in the name. + * @param newName the new name to replace the old name with. + * @return a named operation with the changed name. + * @throws NullPointerException if the name is null. + */ + public final NamedOperation changeName(final String newName) { + return new NamedOperation(baseOperation, newName); + } + + /** * Compares this named operation to another object. Returns true if the * other object is also a named operation, and both their base operations * and name are equal. diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2016 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the names of + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package jdk.dynalink; + +/** + * An object that describes a namespace that is the target of a dynamic operation + * on an object. Every object can have one or more namespaces. Dynalink defines a + * set of standard namespaces with the {@link StandardNamespace} enum. Operations + * that need to specify a namespace they operate on can be expressed using + * {@link NamespaceOperation}. + */ +public interface Namespace { +} diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2016 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the names of + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package jdk.dynalink; + +import java.util.Arrays; +import java.util.Objects; + +/** + * Describes an operation that operates on at least one {@link Namespace} of + * an object. E.g. a property getter would be described as + *
    + * Operation propertyGetter = new NamespaceOperation(
    + *     StandardOperation.GET,
    + *     StandardNamespace.PROPERTY);
    + * 
    + * They are often combined with {@link NamedOperation}, e.g. to express a + * property getter for a property named "color", you would construct: + *
    + * Operation colorPropertyGetter = new NamedOperation(
    + *     new NamespaceOperation(
    + *         StandardOperation.GET,
    + *         StandardNamespace.PROPERTY),
    + *     "color");
    + * 
    + *

    While {@code NamespaceOperation} can be constructed directly, it is often convenient + * to use the {@link Operation#withNamespace(Namespace)} and {@link Operation#withNamespaces(Namespace...)} factory + * methods instead, e.g.: + *

    + * Operation getElementOrPropertyEmpty =
    + *     StandardOperation.GET
    + *         .withNamespace(StandardNamespace.PROPERTY)
    + *         .named("color");
    + * 
    + *

    Operations on multiple namespaces

    + * If multiple namespaces are specified, the namespaces are treated as + * alternatives to each other in order of preference. The semantics of + * such operation is "first applicable". + * That is, a composite of {@code GET:PROPERTY|ELEMENT:color} should be + * interpreted as get the property named "color" on the object, but if the + * property does not exist, then get the collection element named "color" + * instead. + *

    + * Operations with multiple namespaces are helpful in implementation of languages that + * don't distinguish between one or more of the namespaces, or when expressing operations + * against objects that can be considered both ordinary objects and collections, e.g. Java + * {@link java.util.Map} objects. A {@code GET:PROPERTY|ELEMENT:empty} operation + * against a Java map will always match + * the {@link java.util.Map#isEmpty()} property, but + * {@code GET:ELEMENT|PROPERTY:empty} will actually match a map element with + * key {@code "empty"} if the map contains that key, and only fall back to the + * {@code isEmpty()} property getter if the map does not contain the key. If + * the source language mandates this semantics, it can be easily achieved using + * operations on multiple namespaces. + *

    + * Even if the language itself doesn't distinguish between some of the + * namespaces, it can be helpful to map different syntaxes to different namespace orderings. + * E.g. the source expression {@code obj.color} could map to + * {@code GET:PROPERTY|ELEMENT|METHOD:color}, but a different source + * expression that looks like collection element access {@code obj[key]} could + * be expressed instead as {@code GET:ELEMENT|PROPERTY|METHOD} in order to favor the + * element semantics. Finally, if the retrieved value is subsequently called, then it makes sense + * to bring {@code METHOD} to the front of the namespace list: the getter part of the + * source expression {@code obj.color()} could be + * {@code GET:METHOD|PROPERTY|ELEMENT:color} and the one for + * {@code obj[key]()} could be {@code GET:METHOD|ELEMENT|PROPERTY}. + *

    + * The base operation of a namespace operation can not itself be a namespace or named + * operation, but rather one of simple operations such are elements of + * {@link StandardOperation}. A namespace operation itself can serve as the base + * operation of a named operation, though; a typical way to construct e.g. the + * {@code GET:ELEMENT|PROPERTY:empty} from above would be: + *

    + * Operation getElementOrPropertyEmpty = StandardOperation.GET
    + *     .withNamespaces(
    + *         StandardNamespace.ELEMENT,
    + *         StandardNamespace.PROPERTY)
    + *     .named("empty");
    + * 
    + */ +public final class NamespaceOperation implements Operation { + private final Operation baseOperation; + private final Namespace[] namespaces; + + /** + * Constructs a new namespace operation. + * @param baseOperation the base operation that operates on one or more namespaces. + * @param namespaces one or more namespaces this operation operates on. + * @throws IllegalArgumentException if less than one namespace is + * specified, or the base operation is itself a {@link NamespaceOperation} or a + * {@link NamedOperation}. + * @throws NullPointerException if either the {@code namespaces} array or any of its + * elements are {@code null}, or if {@code baseOperation} is {@code null}. + */ + public NamespaceOperation(final Operation baseOperation, final Namespace... namespaces) { + this.baseOperation = Objects.requireNonNull(baseOperation, "baseOperation is null"); + if (baseOperation instanceof NamedOperation) { + throw new IllegalArgumentException("baseOperation is a NamedOperation"); + } else if (baseOperation instanceof NamespaceOperation) { + throw new IllegalArgumentException("baseOperation is a NamespaceOperation"); + } + + this.namespaces = Objects.requireNonNull(namespaces, "namespaces array is null").clone(); + if (namespaces.length < 1) { + throw new IllegalArgumentException("Must specify at least one namespace"); + } + for(int i = 0; i < namespaces.length; ++i) { + final int fi = i; + Objects.requireNonNull(namespaces[i], () -> "operations[" + fi + "] is null"); + } + } + + /** + * Returns the base operation of this named operation. + * @return the base operation of this named operation. + */ + public Operation getBaseOperation() { + return baseOperation; + } + + /** + * Returns the namespaces in this namespace operation. The returned + * array is a copy and changes to it don't have effect on this + * object. + * @return the namespaces in this namespace operation. + */ + public Namespace[] getNamespaces() { + return namespaces.clone(); + } + + /** + * Returns the number of namespaces in this namespace operation. + * @return the number of namespaces in this namespace operation. + */ + public int getNamespaceCount() { + return namespaces.length; + } + + /** + * Returns the i-th namespace in this namespace operation. + * @param i the namespace index + * @return the i-th namespace in this namespace operation. + * @throws IndexOutOfBoundsException if the index is out of range. + */ + public Namespace getNamespace(final int i) { + try { + return namespaces[i]; + } catch (final ArrayIndexOutOfBoundsException e) { + throw new IndexOutOfBoundsException(Integer.toString(i)); + } + } + + /** + * Returns true if this namespace operation contains a namespace equal to + * the specified namespace. + * @param namespace the namespace being searched for. Must not be null. + * @return true if the if this namespace operation contains a namespace + * equal to the specified namespace. + */ + public boolean contains(final Namespace namespace) { + Objects.requireNonNull(namespace); + for(final Namespace component: namespaces) { + if (component.equals(namespace)) { + return true; + } + } + return false; + } + + /** + * Returns true if the other object is also a namespace operation and their + * base operation and namespaces are equal. + * @param obj the object to compare to + * @return true if this object is equal to the other one, false otherwise. + */ + @Override + public boolean equals(final Object obj) { + if (obj instanceof NamespaceOperation) { + final NamespaceOperation other = (NamespaceOperation)obj; + return baseOperation.equals(other.baseOperation) && Arrays.equals(namespaces, other.namespaces); + } + return false; + } + + /** + * Returns the hash code of this namespace operation. Defined to be equal + * to {@code baseOperation.hashCode() + 31 * Arrays.hashCode(namespaces)}. + */ + @Override + public int hashCode() { + return baseOperation.hashCode() + 31 * Arrays.hashCode(namespaces); + }; + + /** + * Returns the string representation of this namespace operation. Defined to + * be the {@code toString} of its base operation, followed by a colon character, + * followed with the list of its namespaces separated with the vertical line + * character (e.g. {@code "GET:PROPERTY|ELEMENT"}). + * @return the string representation of this namespace operation. + */ + @Override + public String toString() { + final StringBuilder b = new StringBuilder(); + b.append(baseOperation).append(':'); + b.append(namespaces[0]); + for(int i = 1; i < namespaces.length; ++i) { + b.append('|').append(namespaces[i]); + } + return b.toString(); + } + + /** + * If the passed operation is a namespace operation, returns its + * {@link #getBaseOperation()}, otherwise returns the operation as is. + * @param op the operation + * @return the base operation of the passed operation. + */ + public static Operation getBaseOperation(final Operation op) { + return op instanceof NamespaceOperation ? ((NamespaceOperation )op).getBaseOperation() : op; + } + + /** + * If the passed operation is a namespace operation, returns its + * {@link #getNamespaces()}, otherwise returns an empty array. + * @param op the operation + * @return the namespaces of the passed operation. + */ + public static Namespace[] getNamespaces(final Operation op) { + return op instanceof NamespaceOperation ? ((NamespaceOperation)op).getNamespaces() : new Namespace[0]; + } + + /** + * Returns true if the specified operation is a {@link NamespaceOperation} + * and its base operation is equal to the specified operation, and it + * contains the specified namespace. If it is not a {@link NamespaceOperation}, + * then it returns false. + * @param op the operation. Must not be null. + * @param baseOperation the base operation being searched for. Must not be null. + * @param namespace the namespace being searched for. Must not be null. + * @return true if the if the passed operation is a {@link NamespaceOperation}, + * its base operation equals the searched base operation, and contains a namespace + * equal to the searched namespace. + */ + public static boolean contains(final Operation op, final Operation baseOperation, final Namespace namespace) { + if (op instanceof NamespaceOperation) { + final NamespaceOperation no = (NamespaceOperation)op; + return no.baseOperation.equals(baseOperation) && no.contains(namespace); + } + return false; + } +} diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java Fri Nov 11 16:44:36 2016 +0100 @@ -86,14 +86,51 @@ /** * An object that describes a dynamic operation. Dynalink defines a set of * standard operations with the {@link StandardOperation} class, as well as a - * way to attach a fixed name to an operation using {@link NamedOperation} and - * to express a set of alternative operations using {@link CompositeOperation}. + * way to express the target {@link Namespace namespace(s)} of an operation + * on an object using {@link NamespaceOperation} and finally a way to attach + * a fixed target name to an operation using {@link NamedOperation}. * When presenting examples in this documentation, we will refer to standard - * operations using their name (e.g. {@code GET_PROPERTY}), to composite - * operations by separating their components with the vertical line character - * (e.g. {@code GET_PROPERTY|GET_ELEMENT}), and finally to named operations by - * separating the base operation and the name with the colon character (e.g. - * {@code GET_PROPERTY|GET_ELEMENT:color}). + * operations using their name (e.g. {@code GET}), to namespace operations + * by separating their base operation with a colon from their namespace + * (e.g. {@code GET:PROPERTY}), or in case of multiple namespaces we will + * further separate those with the vertical line character (e.g. + * {@code GET:PROPERTY|ELEMENT}), and finally we will refer to named operations + * by separating the base operation and the name with the colon character (e.g. + * {@code GET:PROPERTY|ELEMENT:color}). */ public interface Operation { + /** + * Returns a {@link NamespaceOperation} using this operation as its base. + * @param namespace the namespace that is the target of the namespace operation. + * @return a {@link NamespaceOperation} with this operation as its base and the specified + * namespace as its target. + * @throws IllegalArgumentException if this operation is already a namespace operation or a named operation. + * @throws NullPointerException if {@code namespace} is null. + */ + default NamespaceOperation withNamespace(final Namespace namespace) { + return withNamespaces(namespace); + } + + /** + * Returns a {@link NamespaceOperation} using this operation as its base. + * @param namespaces the namespaces that are the target of the namespace operation. + * @return a {@link NamespaceOperation} with this operation as its base and the specified + * namespaces as its targets. + * @throws IllegalArgumentException if this operation is already a namespace operation or a named operation. + * @throws NullPointerException if {@code namespace} or any of its elements is null. + */ + default NamespaceOperation withNamespaces(final Namespace... namespaces) { + return new NamespaceOperation(this, namespaces); + } + + /** + * Returns a {@link NamedOperation} using this operation as its base. + * @param name the name that is the target of the named operation. + * @return a {@link NamedOperation} with this operation as its base and the specified name. + * @throws IllegalArgumentException if this operation is already a named operation. + * @throws NullPointerException if {@code name} is null. + */ + default NamedOperation named(final Object name) { + return new NamedOperation(this, name); + } } diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2016 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the names of + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package jdk.dynalink; + +/** + * An enumeration of standard namespaces defined by Dynalink. + */ +public enum StandardNamespace implements Namespace { + /** + * Standard namespace for properties of an object. + */ + PROPERTY, + /** + * Standard namespace for elements of a collection object. + */ + ELEMENT, + /** + * Standard namespace for methods of an object. The method objects retrieved + * through a {@link StandardOperation#GET} on this namespace can be (and where + * object semantics allows they should be) unbound, that is: not bound to the + * object they were retrieved through. When they are used with + * {@link StandardOperation#CALL} an explicit "this" receiver argument is always + * passed to them. Of course bound methods can be returned if the object semantics + * requires them and such methods are free to ignore the receiver passed in the + * {@code CALL} operation or even raise an error when it is different from the one + * the method is bound to, or exhibit any other behavior their semantics requires + * in such case. + */ + METHOD; + + /** + * If the passed in operation is a {@link NamespaceOperation}, or a + * {@link NamedOperation} wrapping a {@link NamespaceOperation}, then it + * returns the first (if any) {@link StandardNamespace} in its namespace + * list. If the passed operation is not a namespace operation (optionally + * wrapped in a named operation), or if it doesn't have any standard + * namespaces in it, returns {@code null}. + * @param op the operation + * @return the first standard namespace in the operation's namespace list + */ + public static StandardNamespace findFirst(final Operation op) { + for(final Namespace ns: NamespaceOperation.getNamespaces(NamedOperation.getBaseOperation(op))) { + if (ns instanceof StandardNamespace) { + return (StandardNamespace)ns; + } + } + return null; + } +} diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java Fri Nov 11 16:44:36 2016 +0100 @@ -84,79 +84,40 @@ package jdk.dynalink; /** - * Defines the standard dynamic operations. Getter and setter operations defined - * in this enumeration can be composed into a {@link CompositeOperation}, and - * {@link NamedOperation} can be used to bind the name parameter of operations - * that take one, in which case it disappears from the type signature. + * Defines the standard dynamic operations. The operations {@link #GET} and {@link #SET} must + * be used as part of a {@link NamespaceOperation}. {@link NamedOperation} can then be further used on these + * {@link NamespaceOperation}s to bind the name parameter of {@link #GET} and {@link #SET} operations, in which case it + * disappears from their type signature. + * {@link NamedOperation} can also be used to decorate {@link #CALL} and {@link #NEW} operations with a + * diagnostic name, and as such it does not affect their type signature. */ public enum StandardOperation implements Operation { /** - * Get the value of a property defined on an object. Call sites with this + * Get the value from a namespace defined on an object. Call sites with this * operation should have a signature of - * (receiver, propertyName)→value or + * (receiver, name)→value or * (receiver)→value when used with {@link NamedOperation}, with * all parameters and return type being of any type (either primitive or - * reference). + * reference). This operation must always be used as part of a {@link NamespaceOperation}. */ - GET_PROPERTY, - /** - * Set the value of a property defined on an object. Call sites with this - * operation should have a signature of - * (receiver, propertyName, value)→void or - * (receiver, value)→void when used with {@link NamedOperation}, - * with all parameters and return type being of any type (either primitive - * or reference). - */ - SET_PROPERTY, + GET, /** - * Get the value of an element of a collection. Call sites with this + * Set the value in a namespace defined on an object. Call sites with this * operation should have a signature of - * (receiver, index)→value or - * (receiver)→value when used with {@link NamedOperation}, with - * all parameters and return type being of any type (either primitive or - * reference). - */ - GET_ELEMENT, - /** - * Set the value of an element of a collection. Call sites with this - * operation should have a signature of - * (receiver, index, value)→void or + * (receiver, name, value)→void or * (receiver, value)→void when used with {@link NamedOperation}, * with all parameters and return type being of any type (either primitive - * or reference). + * or reference). This operation must always be used as part of a {@link NamespaceOperation}. */ - SET_ELEMENT, - /** - * Get the length of an array or size of a collection. Call sites with - * this operation should have a signature of (receiver)→value, - * with all parameters and return type being of any type (either primitive - * or reference). - */ - GET_LENGTH, + SET, /** - * Gets an object representing a method defined on an object. Call sites - * with this operation should have a signature of - * (receiver, methodName)→value, or - * (receiver)→value when used with {@link NamedOperation} - * with all parameters and return type being of any type (either primitive - * or reference). - */ - GET_METHOD, - /** - * Calls a method defined on an object. Call sites with this - * operation should have a signature of - * (receiver, methodName, arguments...)→value or - * (receiver, arguments...)→value when used with {@link NamedOperation}, - * with all parameters and return type being of any type (either primitive - * or reference). - */ - CALL_METHOD, - /** - * Calls a callable object. Call sites with this operation should have a - * signature of (receiver, arguments...)→value, with all - * parameters and return type being of any type (either primitive or - * reference). Typically, if the callable is a method of an object, the - * first argument will act as the "this" value passed to the called method. + * Call a callable object. Call sites with this operation should have a + * signature of (callable, receiver, arguments...)→value, + * with all parameters and return type being of any type (either primitive or + * reference). Typically, the callables are presumed to be methods of an object, so + * an explicit receiver value is always passed to the callable before the arguments. + * If a callable has no concept of a receiver, it is free to ignore the value of the + * receiver argument. * The CALL operation is allowed to be used with a * {@link NamedOperation} even though it does not take a name. Using it with * a named operation won't affect its signature; the name is solely meant to @@ -164,8 +125,8 @@ */ CALL, /** - * Calls a constructor object. Call sites with this operation should have a - * signature of (receiver, arguments...)→value, with all + * Call a constructor object. Call sites with this operation should have a + * signature of (constructor, arguments...)→value, with all * parameters and return type being of any type (either primitive or * reference). The NEW operation is allowed to be used with a * {@link NamedOperation} even though it does not take a name. Using it with diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java Fri Nov 11 16:44:36 2016 +0100 @@ -99,9 +99,11 @@ import java.util.Map; import java.util.Set; import jdk.dynalink.CallSiteDescriptor; -import jdk.dynalink.CompositeOperation; import jdk.dynalink.NamedOperation; +import jdk.dynalink.Namespace; +import jdk.dynalink.NamespaceOperation; import jdk.dynalink.Operation; +import jdk.dynalink.StandardNamespace; import jdk.dynalink.StandardOperation; import jdk.dynalink.beans.GuardedInvocationComponent.ValidationType; import jdk.dynalink.internal.InternalTypeUtilities; @@ -360,22 +362,6 @@ directLinkerServices = linkerServices; } - // Handle NamedOperation(CALL_METHOD, name) separately - final Operation operation = callSiteDescriptor.getOperation(); - if (operation instanceof NamedOperation) { - final NamedOperation namedOperation = (NamedOperation)operation; - if (namedOperation.getBaseOperation() == StandardOperation.CALL_METHOD) { - final GuardedInvocation inv = - createGuardedDynamicMethodInvocation(callSiteDescriptor, - directLinkerServices, namedOperation.getName().toString(), methods); - if (inv == null) { - return createNoSuchMemberHandler(missingMemberHandlerFactory, - request, directLinkerServices).getGuardedInvocation(); - } - return inv; - } - } - final GuardedInvocationComponent gic = getGuardedInvocationComponent( new ComponentLinkRequest(request, directLinkerServices, missingMemberHandlerFactory)); @@ -386,7 +372,8 @@ final LinkRequest linkRequest; final LinkerServices linkerServices; final MissingMemberHandlerFactory missingMemberHandlerFactory; - final List operations; + final Operation baseOperation; + final List namespaces; final Object name; ComponentLinkRequest(final LinkRequest linkRequest, @@ -395,21 +382,22 @@ this.linkRequest = linkRequest; this.linkerServices = linkerServices; this.missingMemberHandlerFactory = missingMemberHandlerFactory; - final Operation operation = linkRequest.getCallSiteDescriptor().getOperation(); - this.operations = Arrays.asList( - CompositeOperation.getOperations( - NamedOperation.getBaseOperation(operation))); - this.name = NamedOperation.getName(operation); + final Operation namedOp = linkRequest.getCallSiteDescriptor().getOperation(); + this.name = NamedOperation.getName(namedOp); + final Operation namespaceOp = NamedOperation.getBaseOperation(namedOp); + this.baseOperation = NamespaceOperation.getBaseOperation(namespaceOp); + this.namespaces = Arrays.asList(NamespaceOperation.getNamespaces(namespaceOp)); } private ComponentLinkRequest(final LinkRequest linkRequest, final LinkerServices linkerServices, final MissingMemberHandlerFactory missingMemberHandlerFactory, - final List operations, final Object name) { + final Operation baseOperation, final List namespaces, final Object name) { this.linkRequest = linkRequest; this.linkerServices = linkerServices; this.missingMemberHandlerFactory = missingMemberHandlerFactory; - this.operations = operations; + this.baseOperation = baseOperation; + this.namespaces = namespaces; this.name = name; } @@ -417,29 +405,33 @@ return linkRequest.getCallSiteDescriptor(); } - ComponentLinkRequest popOperations() { + ComponentLinkRequest popNamespace() { return new ComponentLinkRequest(linkRequest, linkerServices, - missingMemberHandlerFactory, - operations.subList(1, operations.size()), name); + missingMemberHandlerFactory, baseOperation, + namespaces.subList(1, namespaces.size()), name); } } protected GuardedInvocationComponent getGuardedInvocationComponent(final ComponentLinkRequest req) throws Exception { - final Operation op = req.operations.get(0); - if (op instanceof StandardOperation) { - switch((StandardOperation)op) { - case GET_PROPERTY: return getPropertyGetter(req.popOperations()); - case SET_PROPERTY: return getPropertySetter(req.popOperations()); - case GET_METHOD: return getMethodGetter(req.popOperations()); - default: + if (!req.namespaces.isEmpty()) { + final Namespace ns = req.namespaces.get(0); + final Operation op = req.baseOperation; + if (op == StandardOperation.GET) { + if (ns == StandardNamespace.PROPERTY) { + return getPropertyGetter(req.popNamespace()); + } else if (ns == StandardNamespace.METHOD) { + return getMethodGetter(req.popNamespace()); + } + } else if (op == StandardOperation.SET && ns == StandardNamespace.PROPERTY) { + return getPropertySetter(req.popNamespace()); } } return null; } GuardedInvocationComponent getNextComponent(final ComponentLinkRequest req) throws Exception { - if (req.operations.isEmpty()) { + if (req.namespaces.isEmpty()) { return createNoSuchMemberHandler(req.missingMemberHandlerFactory, req.linkRequest, req.linkerServices); } @@ -447,7 +439,7 @@ if (gic != null) { return gic; } - return getNextComponent(req.popOperations()); + return getNextComponent(req.popNamespace()); } private GuardedInvocationComponent createNoSuchMemberHandler( @@ -626,8 +618,7 @@ if(gi != null) { return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS); } - // If we don't have a property setter with this name, always fall back to the next operation in the - // composite (if any) + // If we don't have a property setter with this name, always fall back to the next namespace (if any). return getNextComponent(req); } @@ -808,8 +799,8 @@ // We have no such method, always delegate to the next component return getNextComponent(req); } - // No delegation to the next component of the composite operation; if we have a method with that name, - // we'll always return it at this point. + // No delegation to the next namespace; if we have a method with that name, we'll always return it at + // this point. final MethodType type = getMethodGetterType(req); return getClassGuardedInvocationComponent(req.linkerServices.asType(MethodHandles.dropArguments( MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type); @@ -880,7 +871,7 @@ @SuppressWarnings("unused") // This method is marked to return Object instead of DynamicMethod as it's used as a linking component and we don't // want to make the DynamicMethod type observable externally (e.g. as the return type of a MethodHandle returned for - // GET_METHOD linking). + // GET:METHOD linking). private Object getDynamicMethod(final Object name) { return getDynamicMethod(String.valueOf(name), methods); } diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java Fri Nov 11 16:44:36 2016 +0100 @@ -92,7 +92,9 @@ import java.util.List; import java.util.Map; import jdk.dynalink.CallSiteDescriptor; +import jdk.dynalink.Namespace; import jdk.dynalink.Operation; +import jdk.dynalink.StandardNamespace; import jdk.dynalink.StandardOperation; import jdk.dynalink.beans.GuardedInvocationComponent.ValidationType; import jdk.dynalink.linker.GuardedInvocation; @@ -112,10 +114,11 @@ if(clazz.isArray()) { // Some languages won't have a notion of manipulating collections. Exposing "length" on arrays as an // explicit property is beneficial for them. - // REVISIT: is it maybe a code smell that StandardOperation.GET_LENGTH is not needed? setPropertyGetter("length", MethodHandles.arrayLength(clazz), ValidationType.EXACT_CLASS); - } else if(List.class.isAssignableFrom(clazz)) { + } else if(Collection.class.isAssignableFrom(clazz)) { setPropertyGetter("length", GET_COLLECTION_LENGTH, ValidationType.INSTANCE_OF); + } else if(Map.class.isAssignableFrom(clazz)) { + setPropertyGetter("length", GET_MAP_LENGTH, ValidationType.INSTANCE_OF); } } @@ -135,14 +138,14 @@ if(superGic != null) { return superGic; } - if (!req.operations.isEmpty()) { - final Operation op = req.operations.get(0); - if (op instanceof StandardOperation) { - switch ((StandardOperation)op) { - case GET_ELEMENT: return getElementGetter(req.popOperations()); - case SET_ELEMENT: return getElementSetter(req.popOperations()); - case GET_LENGTH: return getLengthGetter(req.getDescriptor()); - default: + if (!req.namespaces.isEmpty()) { + final Operation op = req.baseOperation; + final Namespace ns = req.namespaces.get(0); + if (ns == StandardNamespace.ELEMENT) { + if (op == StandardOperation.GET) { + return getElementGetter(req.popNamespace()); + } else if (op == StandardOperation.SET) { + return getElementSetter(req.popNamespace()); } } } @@ -524,38 +527,6 @@ private static final MethodHandle GET_MAP_LENGTH = Lookup.PUBLIC.findVirtual(Map.class, "size", MethodType.methodType(int.class)); - private static final MethodHandle COLLECTION_GUARD = Guards.getInstanceOfGuard(Collection.class); - - private GuardedInvocationComponent getLengthGetter(final CallSiteDescriptor callSiteDescriptor) { - assertParameterCount(callSiteDescriptor, 1); - final MethodType callSiteType = callSiteDescriptor.getMethodType(); - final Class declaredType = callSiteType.parameterType(0); - // If declared type of receiver at the call site is already an array, collection, or map, bind without guard. - // Thing is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance - // they're dealing with an array, collection, or map, but hey... - if(declaredType.isArray()) { - return new GuardedInvocationComponent(MethodHandles.arrayLength(declaredType).asType(callSiteType)); - } else if(Collection.class.isAssignableFrom(declaredType)) { - return new GuardedInvocationComponent(GET_COLLECTION_LENGTH.asType(callSiteType)); - } else if(Map.class.isAssignableFrom(declaredType)) { - return new GuardedInvocationComponent(GET_MAP_LENGTH.asType(callSiteType)); - } - - // Otherwise, create a binding based on the actual type of the argument with an appropriate guard. - if(clazz.isArray()) { - return new GuardedInvocationComponent(MethodHandles.arrayLength(clazz).asType(callSiteType), - Guards.isArray(0, callSiteType), ValidationType.EXACT_CLASS); - } if(Collection.class.isAssignableFrom(clazz)) { - return new GuardedInvocationComponent(GET_COLLECTION_LENGTH.asType(callSiteType), Guards.asType( - COLLECTION_GUARD, callSiteType), Collection.class, ValidationType.INSTANCE_OF); - } if(Map.class.isAssignableFrom(clazz)) { - return new GuardedInvocationComponent(GET_MAP_LENGTH.asType(callSiteType), Guards.asType(MAP_GUARD, - callSiteType), Map.class, ValidationType.INSTANCE_OF); - } - // Can't retrieve length for objects that are neither arrays, nor collections, nor maps. - return null; - } - private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) { if(descriptor.getMethodType().parameterCount() != paramCount) { throw new BootstrapMethodError(descriptor.getOperation() + " must have exactly " + paramCount + " parameters."); diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java Fri Nov 11 16:44:36 2016 +0100 @@ -87,6 +87,7 @@ import java.util.Collections; import java.util.Set; import jdk.dynalink.DynamicLinkerFactory; +import jdk.dynalink.StandardNamespace; import jdk.dynalink.StandardOperation; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.GuardingDynamicLinker; @@ -102,21 +103,18 @@ *
      *
    • expose all public methods of form {@code setXxx()}, {@code getXxx()}, * and {@code isXxx()} as property setters and getters for - * {@link StandardOperation#SET_PROPERTY} and {@link StandardOperation#GET_PROPERTY} - * operations;
    • - *
    • expose all public methods for invocation through - * {@link StandardOperation#CALL_METHOD} operation;
    • + * {@link StandardOperation#SET} and {@link StandardOperation#GET} operations in the + * {@link StandardNamespace#PROPERTY} namespace; *
    • expose all public methods for retrieval for - * {@link StandardOperation#GET_METHOD} operation; the methods thus retrieved - * can then be invoked using {@link StandardOperation#CALL}.
    • + * {@link StandardOperation#GET} operation in the {@link StandardNamespace#METHOD} namespace; + * the methods thus retrieved can then be invoked using {@link StandardOperation#CALL}. *
    • expose all public fields as properties, unless there are getters or * setters for the properties of the same name;
    • - *
    • expose {@link StandardOperation#GET_LENGTH}, - * {@link StandardOperation#GET_ELEMENT} and {@link StandardOperation#SET_ELEMENT} - * on native Java arrays, as well as {@link java.util.List} and - * {@link java.util.Map} objects; ({@link StandardOperation#GET_LENGTH} works on - * any {@link java.util.Collection});
    • - *
    • expose a virtual property named {@code length} on Java arrays;
    • + *
    • expose elements of native Java arrays, {@link java.util.List} and {@link java.util.Map} objects as + * {@link StandardOperation#GET} and {@link StandardOperation#SET} operations in the + * {@link StandardNamespace#ELEMENT} namespace;
    • + *
    • expose a virtual property named {@code length} on Java arrays, {@link java.util.Collection} and + * {@link java.util.Map} objects;
    • *
    • expose {@link StandardOperation#NEW} on instances of {@link StaticClass} * as calls to constructors, including those static class objects that represent * Java arrays (their constructors take a single {@code int} parameter @@ -130,10 +128,10 @@ *

      Overloaded method resolution is performed automatically * for property setters, methods, and constructors. Additionally, manual * overloaded method selection is supported by having a call site specify a name - * for a method that contains an explicit signature, i.e. - * {@code NamedMethod(GET_METHOD, "parseInt(String,int)")}. You can use - * non-qualified class names in such signatures regardless of those classes' - * packages, they will match any class with the same non-qualified name. You + * for a method that contains an explicit signature, e.g. + * {@code StandardOperation.GET.withNamespace(METHOD).named("parseInt(String,int)")} + * You can use non-qualified class names in such signatures regardless of those + * classes' packages, they will match any class with the same non-qualified name. You * only have to use a fully qualified class name in case non-qualified class * names would cause selection ambiguity (that is extremely rare). Overloaded * resolution for constructors is not automatic as there is no logical place to @@ -235,7 +233,7 @@ /** * Returns true if the object is a Java dynamic method (e.g., one - * obtained through a {@code GET_METHOD} operation on a Java object or + * obtained through a {@code GET:METHOD} operation on a Java object or * {@link StaticClass} or through * {@link #getConstructorMethod(Class, String)}. * diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java Fri Nov 11 16:44:36 2016 +0100 @@ -88,6 +88,7 @@ import jdk.dynalink.CallSiteDescriptor; import jdk.dynalink.NamedOperation; import jdk.dynalink.Operation; +import jdk.dynalink.StandardNamespace; import jdk.dynalink.StandardOperation; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.LinkRequest; @@ -98,7 +99,8 @@ /** * Simple linker that implements the {@link StandardOperation#CALL} operation * for {@link DynamicMethod} objects - the objects returned by - * {@link StandardOperation#GET_METHOD} through {@link AbstractJavaLinker}. + * {@link StandardOperation#GET} on {@link StandardNamespace#METHOD} namespace through + * {@link AbstractJavaLinker}. */ class DynamicMethodLinker implements TypeBasedGuardingDynamicLinker { @Override diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java Fri Nov 11 16:44:36 2016 +0100 @@ -87,7 +87,7 @@ import jdk.dynalink.linker.GuardedInvocation; /** - * Represents one component for a GuardedInvocation of a potentially composite operation of an + * Represents one component for a GuardedInvocation of a potentially multi-namespace operation of an * {@link AbstractJavaLinker}. In addition to holding a guarded invocation, it holds semantic information about its * guard. All guards produced in the AbstractJavaLinker are either "Class.isInstance()" or "getClass() == clazz" * expressions. This allows choosing the most restrictive guard as the guard for the composition of two components. diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java Fri Nov 11 16:44:36 2016 +0100 @@ -92,7 +92,7 @@ * methods, properties, and fields), as well as construction of instances using * {@link StandardOperation#NEW} operation. In Dynalink, {@link Class} objects * are not treated specially and act as ordinary Java objects; you can use e.g. - * {@code NamedOperation(GET_PROPERTY, "superclass")} as a property getter to + * {@code GET:PROPERTY:superclass} as a property getter to * invoke {@code clazz.getSuperclass()}. On the other hand, you can not use * {@code Class} objects to access static members of a class, nor to create new * instances of the class using {@code NEW}. This is consistent with how diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java Fri Nov 11 16:44:36 2016 +0100 @@ -91,7 +91,7 @@ import java.util.Set; import jdk.dynalink.CallSiteDescriptor; import jdk.dynalink.NamedOperation; -import jdk.dynalink.Operation; +import jdk.dynalink.StandardNamespace; import jdk.dynalink.StandardOperation; import jdk.dynalink.beans.GuardedInvocationComponent.ValidationType; import jdk.dynalink.linker.GuardedInvocation; @@ -168,17 +168,12 @@ if (superGic != null) { return superGic; } - if (!req.operations.isEmpty()) { - final Operation op = req.operations.get(0); - if (op instanceof StandardOperation) { - switch ((StandardOperation)op) { - case GET_ELEMENT: - case SET_ELEMENT: - // StaticClass doesn't behave as a collection - return getNextComponent(req.popOperations()); - default: - } - } + if (!req.namespaces.isEmpty() + && req.namespaces.get(0) == StandardNamespace.ELEMENT + && (req.baseOperation == StandardOperation.GET || req.baseOperation == StandardOperation.SET)) + { + // StaticClass doesn't behave as a collection + return getNextComponent(req.popNamespace()); } return null; } diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java Fri Nov 11 16:44:36 2016 +0100 @@ -129,7 +129,7 @@ * bytecode would look something like this: *

        * aload 2 // load "obj" on stack
      - * invokedynamic "GET_PROPERTY:color"(Object)Object // invoke property getter on object of unknown type
      + * invokedynamic "GET:PROPERTY:color"(Object)Object // invoke property getter on object of unknown type
        * astore 3 // store the return value into local variable "color"
        * 
      * In order to link the {@code invokedynamic} instruction, we need a bootstrap @@ -175,9 +175,9 @@ * dynamic operations. It does not prescribe how would you encode the operations * in your call site, though. That is why in the above example the * {@code parseOperation} function is left empty, and you would be expected to - * provide the code to parse the string {@code "GET_PROPERTY:color"} + * provide the code to parse the string {@code "GET:PROPERTY:color"} * in the call site's name into a named property getter operation object as - * {@code new NamedOperation(StandardOperation.GET_PROPERTY), "color")}. + * {@code StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")}. *
    *

    What can you already do with the above setup? {@code DynamicLinkerFactory} * by default creates a {@code DynamicLinker} that can link Java objects with the @@ -231,18 +231,20 @@ * Dynalink defines several standard operations in its * {@link jdk.dynalink.StandardOperation} class. The linker for Java * objects can link all of these operations, and you are encouraged to at - * minimum support and use these operations in your language too. To associate - * a fixed name with an operation, you can use - * {@link jdk.dynalink.NamedOperation} as in the above example where - * {@code StandardOperation.GET_PROPERTY} was combined with the name - * {@code "color"} in a {@code NamedOperation} to form a property getter for the - * property named "color". - *

    Composite operations

    + * minimum support and use these operations in your language too. The + * standard operations {@code GET} and {@code SET} need to be combined with + * at least one {@link jdk.dynalink.Namespace} to be useful, e.g. to express a + * property getter, you'd use {@code StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY)}. + * Dynalink defines three standard namespaces in the {@link jdk.dynalink.StandardNamespace} class. + * To associate a fixed name with an operation, you can use + * {@link jdk.dynalink.NamedOperation} as in the previous example: + * {@code StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")} + * expresses a getter for the property named "color". + *

    Operations on multiple namespaces

    * Some languages might not have separate namespaces on objects for * properties, elements, and methods, and a source language construct might - * address two or three of them. Dynalink supports specifying composite - * operations for this purpose using the - * {@link jdk.dynalink.CompositeOperation} class. + * address several of them at once. Dynalink supports specifying multiple + * {@link jdk.dynalink.Namespace} objects with {@link jdk.dynalink.NamespaceOperation}. *

    Language-specific linkers

    * Languages that define their own object model different than the JVM * class-based model and/or use their own type conversions will need to create diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Fri Nov 11 16:44:36 2016 +0100 @@ -343,7 +343,7 @@ symbol = null; } else if (symbol.isParam()) { // Duplicate parameter. Null return will force an error. - throw new AssertionError("duplicate parameter"); + throwParserException(ECMAErrors.getMessage("syntax.error.duplicate.parameter", name), origin); } } else if (isVar) { if (isBlockScope) { diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java Fri Nov 11 16:44:36 2016 +0100 @@ -45,6 +45,7 @@ import jdk.nashorn.internal.ir.CallNode; import jdk.nashorn.internal.ir.CaseNode; import jdk.nashorn.internal.ir.CatchNode; +import jdk.nashorn.internal.ir.ClassNode; import jdk.nashorn.internal.ir.ContinueNode; import jdk.nashorn.internal.ir.DebuggerNode; import jdk.nashorn.internal.ir.EmptyNode; @@ -60,9 +61,11 @@ import jdk.nashorn.internal.ir.LabelNode; import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LiteralNode; +import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; import jdk.nashorn.internal.ir.LiteralNode.PrimitiveLiteralNode; import jdk.nashorn.internal.ir.LoopNode; import jdk.nashorn.internal.ir.Node; +import jdk.nashorn.internal.ir.ObjectNode; import jdk.nashorn.internal.ir.ReturnNode; import jdk.nashorn.internal.ir.RuntimeNode; import jdk.nashorn.internal.ir.Statement; @@ -70,6 +73,7 @@ import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.ir.ThrowNode; import jdk.nashorn.internal.ir.TryNode; +import jdk.nashorn.internal.ir.UnaryNode; import jdk.nashorn.internal.ir.VarNode; import jdk.nashorn.internal.ir.WhileNode; import jdk.nashorn.internal.ir.WithNode; @@ -78,6 +82,8 @@ import jdk.nashorn.internal.parser.Token; import jdk.nashorn.internal.parser.TokenType; import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.ECMAErrors; +import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.logging.DebugLogger; @@ -98,6 +104,7 @@ private final DebugLogger log; private final boolean es6; + private final Source source; // Conservative pattern to test if element names consist of characters valid for identifiers. // This matches any non-zero length alphanumeric string including _ and $ and not starting with a digit. @@ -146,6 +153,7 @@ this.log = initLogger(compiler.getContext()); this.es6 = compiler.getScriptEnvironment()._es6; + this.source = compiler.getSource(); } @Override @@ -241,6 +249,10 @@ } } + if (es6 && expressionStatement.destructuringDeclarationType() != null) { + throwNotImplementedYet("es6.destructuring", expressionStatement); + } + return addStatement(node); } @@ -250,6 +262,14 @@ } @Override + public boolean enterForNode(final ForNode forNode) { + if (es6 && (forNode.getInit() instanceof ObjectNode || forNode.getInit() instanceof ArrayLiteralNode)) { + throwNotImplementedYet("es6.destructuring", forNode); + } + return super.enterForNode(forNode); + } + + @Override public Node leaveForNode(final ForNode forNode) { ForNode newForNode = forNode; @@ -270,6 +290,37 @@ } @Override + public boolean enterFunctionNode(final FunctionNode functionNode) { + if (es6) { + if (functionNode.getKind() == FunctionNode.Kind.MODULE) { + throwNotImplementedYet("es6.module", functionNode); + } + + if (functionNode.getKind() == FunctionNode.Kind.GENERATOR) { + throwNotImplementedYet("es6.generator", functionNode); + } + if (functionNode.usesSuper()) { + throwNotImplementedYet("es6.super", functionNode); + } + + final int numParams = functionNode.getNumOfParams(); + if (numParams > 0) { + final IdentNode lastParam = functionNode.getParameter(numParams - 1); + if (lastParam.isRestParameter()) { + throwNotImplementedYet("es6.rest.param", lastParam); + } + } + for (final IdentNode param : functionNode.getParameters()) { + if (param.isDestructuredParameter()) { + throwNotImplementedYet("es6.destructuring", functionNode); + } + } + } + + return super.enterFunctionNode(functionNode); + } + + @Override public Node leaveFunctionNode(final FunctionNode functionNode) { log.info("END FunctionNode: ", functionNode.getName()); return functionNode; @@ -578,6 +629,29 @@ } @Override + public boolean enterUnaryNode(final UnaryNode unaryNode) { + if (es6) { + if (unaryNode.isTokenType(TokenType.YIELD) || + unaryNode.isTokenType(TokenType.YIELD_STAR)) { + throwNotImplementedYet("es6.yield", unaryNode); + } else if (unaryNode.isTokenType(TokenType.SPREAD_ARGUMENT) || + unaryNode.isTokenType(TokenType.SPREAD_ARRAY)) { + throwNotImplementedYet("es6.spread", unaryNode); + } + } + + return super.enterUnaryNode(unaryNode); + } + + @Override + public boolean enterASSIGN(BinaryNode binaryNode) { + if (es6 && (binaryNode.lhs() instanceof ObjectNode || binaryNode.lhs() instanceof ArrayLiteralNode)) { + throwNotImplementedYet("es6.destructuring", binaryNode); + } + return super.enterASSIGN(binaryNode); + } + + @Override public Node leaveVarNode(final VarNode varNode) { addStatement(varNode); if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) @@ -608,6 +682,12 @@ return addStatement(withNode); } + @Override + public boolean enterClassNode(final ClassNode classNode) { + throwNotImplementedYet("es6.class", classNode); + return super.enterClassNode(classNode); + } + /** * Given a function node that is a callee in a CallNode, replace it with * the appropriate marker function. This is used by {@link CodeGenerator} @@ -766,4 +846,13 @@ } return false; } + + private void throwNotImplementedYet(final String msgId, final Node node) { + final long token = node.getToken(); + final int line = source.getLine(node.getStart()); + final int column = source.getColumn(node.getStart()); + final String message = ECMAErrors.getMessage("unimplemented." + msgId); + final String formatted = ErrorManager.format(message, source, line, column, token); + throw new RuntimeException(formatted); + } } diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Fri Nov 11 16:44:36 2016 +0100 @@ -45,7 +45,7 @@ } @Override - public final boolean enterUnaryNode(final UnaryNode unaryNode) { + public boolean enterUnaryNode(final UnaryNode unaryNode) { switch (unaryNode.tokenType()) { case ADD: return enterADD(unaryNode); diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Fri Nov 11 16:44:36 2016 +0100 @@ -48,7 +48,6 @@ import javax.script.ScriptContext; import javax.script.ScriptEngine; import jdk.dynalink.CallSiteDescriptor; -import jdk.dynalink.StandardOperation; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.LinkRequest; import jdk.nashorn.api.scripting.ClassFilter; @@ -2449,17 +2448,17 @@ } @Override - public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) { + public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) { final String name = NashornCallSiteDescriptor.getOperand(desc); final boolean isScope = NashornCallSiteDescriptor.isScope(desc); if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) { if (lexicalScope.hasOwnProperty(name)) { - return lexicalScope.findGetMethod(desc, request, operation); + return lexicalScope.findGetMethod(desc, request); } } - final GuardedInvocation invocation = super.findGetMethod(desc, request, operation); + final GuardedInvocation invocation = super.findGetMethod(desc, request); // We want to avoid adding our generic lexical scope switchpoint to global constant invocations, // because those are invalidated per-key in the addBoundProperties method above. @@ -3061,8 +3060,8 @@ } @Override - protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) { - return filterInvocation(super.findGetMethod(desc, request, operation)); + protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) { + return filterInvocation(super.findGetMethod(desc, request)); } @Override diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java Fri Nov 11 16:44:36 2016 +0100 @@ -37,7 +37,6 @@ import java.util.Iterator; import java.util.List; import jdk.dynalink.CallSiteDescriptor; -import jdk.dynalink.StandardOperation; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.LinkRequest; import jdk.nashorn.internal.lookup.Lookup; @@ -365,7 +364,7 @@ Object obj; if (func instanceof ScriptFunction) { - obj = ScriptRuntime.apply((ScriptFunction)func, adaptee); + obj = ScriptRuntime.apply((ScriptFunction)func, this); } else { obj = new NativeArray(0); } @@ -473,11 +472,11 @@ } @Override - protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) { + protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) { final String name = NashornCallSiteDescriptor.getOperand(desc); if (overrides && super.hasOwnProperty(name)) { try { - final GuardedInvocation inv = super.findGetMethod(desc, request, operation); + final GuardedInvocation inv = super.findGetMethod(desc, request); if (inv != null) { return inv; } @@ -486,11 +485,9 @@ } } - switch(operation) { - case GET_PROPERTY: - case GET_ELEMENT: + if (!NashornCallSiteDescriptor.isMethodFirstOperation(desc)) { return findHook(desc, __get__); - case GET_METHOD: + } else { final FindProperty find = adaptee.findProperty(__call__, true); if (find != null) { final Object value = find.getObjectValue(); @@ -505,11 +502,7 @@ } } throw typeError("no.such.function", name, ScriptRuntime.safeToString(this)); - default: - break; } - - throw new AssertionError("should not reach here"); } @Override @@ -544,7 +537,7 @@ private Object callAdaptee(final Object retValue, final String name, final Object... args) { final Object func = adaptee.get(name); if (func instanceof ScriptFunction) { - return ScriptRuntime.apply((ScriptFunction)func, adaptee, args); + return ScriptRuntime.apply((ScriptFunction)func, this, args); } return retValue; } diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java Fri Nov 11 16:44:36 2016 +0100 @@ -25,6 +25,10 @@ package jdk.nashorn.internal.objects; +import static jdk.dynalink.StandardNamespace.METHOD; +import static jdk.dynalink.StandardNamespace.PROPERTY; +import static jdk.dynalink.StandardOperation.GET; +import static jdk.dynalink.StandardOperation.SET; import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; @@ -40,9 +44,7 @@ import java.util.Set; import java.util.concurrent.Callable; import jdk.dynalink.CallSiteDescriptor; -import jdk.dynalink.NamedOperation; import jdk.dynalink.Operation; -import jdk.dynalink.StandardOperation; import jdk.dynalink.beans.BeansLinker; import jdk.dynalink.beans.StaticClass; import jdk.dynalink.linker.GuardedInvocation; @@ -97,6 +99,10 @@ }); } + private static final Operation GET_METHOD = GET.withNamespace(METHOD); + private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY); + private static final Operation SET_PROPERTY = SET.withNamespace(PROPERTY); + @SuppressWarnings("unused") private static ScriptObject get__proto__(final Object self) { // See ES6 draft spec: B.2.2.1.1 get Object.prototype.__proto__ @@ -782,7 +788,7 @@ for(final String methodName: methodNames) { final MethodHandle method; try { - method = getBeanOperation(linker, StandardOperation.GET_METHOD, methodName, getterType, source); + method = getBeanOperation(linker, GET_METHOD, methodName, getterType, source); } catch(final IllegalAccessError e) { // Presumably, this was a caller sensitive method. Ignore it and carry on. continue; @@ -794,7 +800,7 @@ MethodHandle getter; if(readablePropertyNames.contains(propertyName)) { try { - getter = getBeanOperation(linker, StandardOperation.GET_PROPERTY, propertyName, getterType, source); + getter = getBeanOperation(linker, GET_PROPERTY, propertyName, getterType, source); } catch(final IllegalAccessError e) { // Presumably, this was a caller sensitive method. Ignore it and carry on. getter = Lookup.EMPTY_GETTER; @@ -806,7 +812,7 @@ MethodHandle setter; if(isWritable) { try { - setter = getBeanOperation(linker, StandardOperation.SET_PROPERTY, propertyName, setterType, source); + setter = getBeanOperation(linker, SET_PROPERTY, propertyName, setterType, source); } catch(final IllegalAccessError e) { // Presumably, this was a caller sensitive method. Ignore it and carry on. setter = Lookup.EMPTY_SETTER; @@ -836,11 +842,11 @@ } } - private static MethodHandle getBeanOperation(final GuardingDynamicLinker linker, final StandardOperation operation, + private static MethodHandle getBeanOperation(final GuardingDynamicLinker linker, final Operation operation, final String name, final MethodType methodType, final Object source) { final GuardedInvocation inv; try { - inv = NashornBeansLinker.getGuardedInvocation(linker, createLinkRequest(new NamedOperation(operation, name), methodType, source), Bootstrap.getLinkerServices()); + inv = NashornBeansLinker.getGuardedInvocation(linker, createLinkRequest(operation.named(name), methodType, source), Bootstrap.getLinkerServices()); assert passesGuard(source, inv.getGuard()); } catch(RuntimeException|Error e) { throw e; diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Fri Nov 11 16:44:36 2016 +0100 @@ -42,7 +42,6 @@ import java.util.Locale; import java.util.Set; import jdk.dynalink.CallSiteDescriptor; -import jdk.dynalink.StandardOperation; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.LinkRequest; import jdk.nashorn.internal.lookup.MethodHandleFactory.LookupException; @@ -127,15 +126,15 @@ // This is to support length as method call as well. @Override - protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) { + protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) { final String name = NashornCallSiteDescriptor.getOperand(desc); // if str.length(), then let the bean linker handle it - if ("length".equals(name) && operation == StandardOperation.GET_METHOD) { + if ("length".equals(name) && NashornCallSiteDescriptor.isMethodFirstOperation(desc)) { return null; } - return super.findGetMethod(desc, request, operation); + return super.findGetMethod(desc, request); } // This is to provide array-like access to string characters without creating a NativeString wrapper. diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Fri Nov 11 16:44:36 2016 +0100 @@ -1962,6 +1962,18 @@ switch (type) { case SEMICOLON: // for (init; test; modify) + if (varDeclList != null) { + assert init == null; + init = varDeclList.init; + // late check for missing assignment, now we know it's a for (init; test; modify) loop + if (varDeclList.missingAssignment != null) { + if (varDeclList.missingAssignment instanceof IdentNode) { + throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)varDeclList.missingAssignment).getName())); + } else { + throw error(AbstractParser.message("missing.destructuring.assignment"), varDeclList.missingAssignment.getToken()); + } + } + } // for each (init; test; modify) is invalid if ((flags & ForNode.IS_FOR_EACH) != 0) { diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Fri Nov 11 16:44:36 2016 +0100 @@ -67,7 +67,6 @@ import java.util.concurrent.atomic.LongAdder; import jdk.dynalink.CallSiteDescriptor; import jdk.dynalink.NamedOperation; -import jdk.dynalink.StandardOperation; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.LinkRequest; import jdk.nashorn.internal.codegen.CompilerConstants.Call; @@ -1858,23 +1857,16 @@ * @return GuardedInvocation for the callsite */ public GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request) { - // NOTE: we support GET_ELEMENT and SET_ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself - // emits "GET_PROPERTY|GET_ELEMENT|GET_METHOD:identifier" for "." and "GET_ELEMENT|GET_PROPERTY|GET_METHOD" for "[]", but we are + // NOTE: we support GET:ELEMENT and SET:ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself + // emits "GET:PROPERTY|ELEMENT|METHOD:identifier" for "." and "GET:ELEMENT|PROPERTY|METHOD" for "[]", but we are // more flexible here and dispatch not on operation name (getProp vs. getElem), but rather on whether the // operation has an associated name or not. - final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc); - if (op == null) { - return null; - } - switch (op) { - case GET_PROPERTY: - case GET_ELEMENT: - case GET_METHOD: + switch (NashornCallSiteDescriptor.getStandardOperation(desc)) { + case GET: return desc.getOperation() instanceof NamedOperation - ? findGetMethod(desc, request, op) + ? findGetMethod(desc, request) : findGetIndexMethod(desc, request); - case SET_PROPERTY: - case SET_ELEMENT: + case SET: return desc.getOperation() instanceof NamedOperation ? findSetMethod(desc, request) : findSetIndexMethod(desc, request); @@ -1883,8 +1875,8 @@ case NEW: return findNewMethod(desc, request); default: + return null; } - return null; } /** @@ -1952,11 +1944,10 @@ * * @param desc the call site descriptor * @param request the link request - * @param operation operation for get: getProp, getMethod, getElem etc * * @return GuardedInvocation to be invoked at call site. */ - protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) { + protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) { final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request); String name = NashornCallSiteDescriptor.getOperand(desc); @@ -1967,21 +1958,17 @@ } if (request.isCallSiteUnstable() || hasWithScope()) { - return findMegaMorphicGetMethod(desc, name, operation == StandardOperation.GET_METHOD); + return findMegaMorphicGetMethod(desc, name, NashornCallSiteDescriptor.isMethodFirstOperation(desc)); } final FindProperty find = findProperty(name, true, NashornCallSiteDescriptor.isScope(desc), this); MethodHandle mh; if (find == null) { - switch (operation) { - case GET_ELEMENT: // getElem only gets here if element name is constant, so treat it like a property access - case GET_PROPERTY: + if (!NashornCallSiteDescriptor.isMethodFirstOperation(desc)) { return noSuchProperty(desc, request); - case GET_METHOD: + } else { return noSuchMethod(desc, request); - default: - throw new AssertionError(operation); // never invoked with any other operation } } diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java Fri Nov 11 16:44:36 2016 +0100 @@ -32,7 +32,6 @@ import java.lang.invoke.MethodHandles; import jdk.dynalink.CallSiteDescriptor; import jdk.dynalink.NamedOperation; -import jdk.dynalink.StandardOperation; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.support.Guards; import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; @@ -93,29 +92,22 @@ * @return GuardedInvocation to be invoked at call site. */ public static GuardedInvocation lookup(final CallSiteDescriptor desc) { - final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc); - if (op == null) { - return null; - } - switch (op) { + switch (NashornCallSiteDescriptor.getStandardOperation(desc)) { case CALL: case NEW: final String name = NashornCallSiteDescriptor.getOperand(desc); final String msg = name != null? "not.a.function" : "cant.call.undefined"; throw typeError(msg, name); - case GET_PROPERTY: - case GET_ELEMENT: - case GET_METHOD: - // NOTE: we support GET_ELEMENT and SET_ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself - // emits "GET_PROPERTY|GET_ELEMENT|GET_METHOD:identifier" for "." and "GET_ELEMENT|GET_PROPERTY|GET_METHOD" for "[]", but we are + case GET: + // NOTE: we support GET:ELEMENT and SET:ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself + // emits "GET:PROPERTY|ELEMENT|METHOD:identifier" for "." and "GET:ELEMENT|PROPERTY|METHOD" for "[]", but we are // more flexible here and dispatch not on operation name (getProp vs. getElem), but rather on whether the // operation has an associated name or not. if (!(desc.getOperation() instanceof NamedOperation)) { return findGetIndexMethod(desc); } return findGetMethod(desc); - case SET_PROPERTY: - case SET_ELEMENT: + case SET: if (!(desc.getOperation() instanceof NamedOperation)) { return findSetIndexMethod(desc); } diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java Fri Nov 11 16:44:36 2016 +0100 @@ -97,9 +97,6 @@ return super.lookup(desc, request); } - // With scopes can never be observed outside of Nashorn code, so all call sites that can address it will of - // necessity have a Nashorn descriptor - it is safe to cast. - final NashornCallSiteDescriptor ndesc = (NashornCallSiteDescriptor)desc; GuardedInvocation link = null; final Operation op = desc.getOperation(); @@ -111,7 +108,7 @@ if (find != null) { link = expression.lookup(desc, request); if (link != null) { - return fixExpressionCallSite(ndesc, link); + return fixExpressionCallSite(desc, link); } } @@ -126,39 +123,30 @@ // __noSuchProperty__ and __noSuchMethod__ in expression final String fallBack; - final StandardOperation firstOp = ndesc.getFirstOperation(); - switch (firstOp) { - case GET_METHOD: - fallBack = NO_SUCH_METHOD_NAME; - break; - case GET_PROPERTY: - case GET_ELEMENT: - fallBack = NO_SUCH_PROPERTY_NAME; - break; - default: + final Operation firstOp = NashornCallSiteDescriptor.getBaseOperation(desc); + if (firstOp == StandardOperation.GET) { + if (NashornCallSiteDescriptor.isMethodFirstOperation(desc)) { + fallBack = NO_SUCH_METHOD_NAME; + } else { + fallBack = NO_SUCH_PROPERTY_NAME; + } + } else { fallBack = null; - break; } if (fallBack != null) { find = expression.findProperty(fallBack, true); if (find != null) { - switch (firstOp) { - case GET_METHOD: + if (NO_SUCH_METHOD_NAME.equals(fallBack)) { link = expression.noSuchMethod(desc, request); - break; - case GET_PROPERTY: - case GET_ELEMENT: + } else if (NO_SUCH_PROPERTY_NAME.equals(fallBack)) { link = expression.noSuchProperty(desc, request); - break; - default: - break; } } } if (link != null) { - return fixExpressionCallSite(ndesc, link); + return fixExpressionCallSite(desc, link); } // still not found, may be scope can handle with it's own @@ -245,10 +233,10 @@ return link.asType(newInvType); } - private static GuardedInvocation fixExpressionCallSite(final NashornCallSiteDescriptor desc, final GuardedInvocation link) { + private static GuardedInvocation fixExpressionCallSite(final CallSiteDescriptor desc, final GuardedInvocation link) { // If it's not a getMethod, just add an expression filter that converts WithObject in "this" position to its // expression. - if (desc.getFirstOperation() != StandardOperation.GET_METHOD) { + if (NashornCallSiteDescriptor.getBaseOperation(desc) != StandardOperation.GET || !NashornCallSiteDescriptor.isMethodFirstOperation(desc)) { return fixReceiverType(link, WITHEXPRESSIONFILTER).filterArguments(0, WITHEXPRESSIONFILTER); } diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java Fri Nov 11 16:44:36 2016 +0100 @@ -35,7 +35,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import jdk.dynalink.CallSiteDescriptor; -import jdk.dynalink.StandardOperation; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.LinkRequest; import jdk.dynalink.linker.LinkerServices; @@ -91,24 +90,17 @@ inv = null; } - final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc); - if (op == null) { - return inv; - } final String name = NashornCallSiteDescriptor.getOperand(desc); - switch (op) { - case GET_PROPERTY: - case GET_ELEMENT: - case GET_METHOD: + switch (NashornCallSiteDescriptor.getStandardOperation(desc)) { + case GET: return name != null ? findGetMethod(name, inv) : findGetIndexMethod(inv); - case SET_PROPERTY: - case SET_ELEMENT: + case SET: return name != null ? findSetMethod(name, inv) : findSetIndexMethod(); case CALL: return findCallMethod(desc); default: + return null; } - return null; } private static GuardedInvocation findGetMethod(final String name, final GuardedInvocation inv) { diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Fri Nov 11 16:44:36 2016 +0100 @@ -33,6 +33,7 @@ import java.util.Map; import javax.script.Bindings; import jdk.dynalink.CallSiteDescriptor; +import jdk.dynalink.Operation; import jdk.dynalink.StandardOperation; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.LinkRequest; @@ -92,29 +93,31 @@ } private GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request, final LinkerServices linkerServices) throws Exception { - final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc); - if (op == null) { - return null; - } - final String name = NashornCallSiteDescriptor.getOperand(desc); - switch (op) { - case GET_PROPERTY: - case GET_ELEMENT: - case GET_METHOD: - if (name != null) { - return findGetMethod(name); + final Operation op = NashornCallSiteDescriptor.getBaseOperation(desc); + if (op instanceof StandardOperation) { + final String name = NashornCallSiteDescriptor.getOperand(desc); + switch ((StandardOperation)op) { + case GET: + if (NashornCallSiteDescriptor.hasStandardNamespace(desc)) { + if (name != null) { + return findGetMethod(name); + } + // For indexed get, we want get GuardedInvocation beans linker and pass it. + // JSObjectLinker.get uses this fallback getter for explicit signature method access. + return findGetIndexMethod(nashornBeansLinker.getGuardedInvocation(request, linkerServices)); + } + break; + case SET: + if (NashornCallSiteDescriptor.hasStandardNamespace(desc)) { + return name != null ? findSetMethod(name) : findSetIndexMethod(); + } + break; + case CALL: + return findCallMethod(desc); + case NEW: + return findNewMethod(desc); + default: } - // For indexed get, we want get GuardedInvocation beans linker and pass it. - // JSObjectLinker.get uses this fallback getter for explicit signature method access. - return findGetIndexMethod(nashornBeansLinker.getGuardedInvocation(request, linkerServices)); - case SET_PROPERTY: - case SET_ELEMENT: - return name != null ? findSetMethod(name) : findSetIndexMethod(); - case CALL: - return findCallMethod(desc); - case NEW: - return findNewMethod(desc); - default: } return null; } diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Fri Nov 11 16:44:36 2016 +0100 @@ -25,15 +25,15 @@ package jdk.nashorn.internal.runtime.linker; +import static jdk.dynalink.StandardNamespace.METHOD; +import static jdk.dynalink.StandardOperation.GET; import static jdk.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.SUPER_PREFIX; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import jdk.dynalink.CallSiteDescriptor; -import jdk.dynalink.NamedOperation; import jdk.dynalink.Operation; -import jdk.dynalink.StandardOperation; import jdk.dynalink.beans.BeansLinker; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.LinkRequest; @@ -61,6 +61,8 @@ IS_ADAPTER_OF_CLASS = lookup.findOwnStatic("isAdapterOfClass", boolean.class, Class.class, Object.class); } + private static final Operation GET_METHOD = GET.withNamespace(METHOD); + private final BeansLinker beansLinker; JavaSuperAdapterLinker(final BeansLinker beansLinker) { @@ -82,8 +84,8 @@ final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor(); - if(!NashornCallSiteDescriptor.contains(descriptor, StandardOperation.GET_METHOD)) { - // We only handle GET_METHOD + if(!NashornCallSiteDescriptor.contains(descriptor, GET, METHOD)) { + // We only handle GET:METHOD return null; } @@ -97,8 +99,7 @@ final MethodType type = descriptor.getMethodType(); final Class adapterClass = adapter.getClass(); final String name = NashornCallSiteDescriptor.getOperand(descriptor); - final Operation newOp = name == null ? StandardOperation.GET_METHOD : - new NamedOperation(StandardOperation.GET_METHOD, SUPER_PREFIX + name); + final Operation newOp = name == null ? GET_METHOD : GET_METHOD.named(SUPER_PREFIX + name); final CallSiteDescriptor newDescriptor = new CallSiteDescriptor( NashornCallSiteDescriptor.getLookupInternal(descriptor), newOp, diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Fri Nov 11 16:44:36 2016 +0100 @@ -35,7 +35,9 @@ import java.util.function.Supplier; import jdk.dynalink.CallSiteDescriptor; import jdk.dynalink.NamedOperation; +import jdk.dynalink.Operation; import jdk.dynalink.SecureLookupSupplier; +import jdk.dynalink.StandardNamespace; import jdk.dynalink.StandardOperation; import jdk.dynalink.beans.BeansLinker; import jdk.dynalink.linker.ConversionComparator.Comparison; @@ -46,6 +48,7 @@ import jdk.dynalink.linker.MethodHandleTransformer; import jdk.dynalink.linker.support.DefaultInternalObjectFilter; import jdk.dynalink.linker.support.Lookup; +import jdk.dynalink.linker.support.SimpleLinkRequest; import jdk.nashorn.api.scripting.ScriptUtils; import jdk.nashorn.internal.runtime.ConsString; import jdk.nashorn.internal.runtime.Context; @@ -68,6 +71,9 @@ // Object type arguments of Java method calls, field set and array set. private static final boolean MIRROR_ALWAYS = Options.getBooleanProperty("nashorn.mirror.always", true); + private static final Operation GET_METHOD = StandardOperation.GET.withNamespace(StandardNamespace.METHOD); + private static final MethodType GET_METHOD_TYPE = MethodType.methodType(Object.class, Object.class); + private static final MethodHandle EXPORT_ARGUMENT; private static final MethodHandle IMPORT_RESULT; private static final MethodHandle FILTER_CONSSTRING; @@ -114,20 +120,38 @@ // those are script functions. final String name = getFunctionalInterfaceMethodName(self.getClass()); if (name != null) { - final MethodType callType = desc.getMethodType(); - // drop callee (Undefined ScriptFunction) and change the request to be CALL_METHOD: - final CallSiteDescriptor newDesc = new CallSiteDescriptor( + // Obtain the method + final CallSiteDescriptor getMethodDesc = new CallSiteDescriptor( NashornCallSiteDescriptor.getLookupInternal(desc), - new NamedOperation(StandardOperation.CALL_METHOD, name), - desc.getMethodType().dropParameterTypes(1, 2)); - final GuardedInvocation gi = getGuardedInvocation(beansLinker, - linkRequest.replaceArguments(newDesc, linkRequest.getArguments()), + GET_METHOD.named(name), GET_METHOD_TYPE); + final GuardedInvocation getMethodInv = linkerServices.getGuardedInvocation( + new SimpleLinkRequest(getMethodDesc, false, self)); + final Object method; + try { + method = getMethodInv.getInvocation().invokeExact(self); + } catch (final Exception|Error e) { + throw e; + } catch (final Throwable t) { + throw new RuntimeException(t); + } + + final Object[] args = linkRequest.getArguments(); + args[1] = args[0]; // callee (the functional object) becomes this + args[0] = method; // the method becomes the callee + + final MethodType callType = desc.getMethodType(); + + final CallSiteDescriptor newDesc = desc.changeMethodType( + desc.getMethodType().changeParameterType(0, Object.class).changeParameterType(1, callType.parameterType(0))); + final GuardedInvocation gi = getGuardedInvocation(beansLinker, linkRequest.replaceArguments(newDesc, args), new NashornBeansLinkerServices(linkerServices)); - // drop 'thiz' passed from the script. - return gi.replaceMethods( - MH.dropArguments(linkerServices.filterInternalObjects(gi.getInvocation()), 1, callType.parameterType(1)), - gi.getGuard()); + // Bind to the method, drop the original "this" and use original "callee" as this: + final MethodHandle inv = linkerServices.filterInternalObjects(gi + .getInvocation() // (method, this, args...) + .bindTo(method)); // (this, args...) + final MethodHandle calleeToThis = MH.dropArguments(inv, 1, callType.parameterType(1)); // (callee->this, , args...) + return gi.replaceMethods(calleeToThis, gi.getGuard()); } } return getGuardedInvocation(beansLinker, linkRequest, linkerServices); diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Fri Nov 11 16:44:36 2016 +0100 @@ -38,7 +38,6 @@ import jdk.dynalink.CallSiteDescriptor; import jdk.dynalink.NamedOperation; import jdk.dynalink.Operation; -import jdk.dynalink.StandardOperation; import jdk.dynalink.beans.BeansLinker; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.GuardingDynamicLinker; @@ -98,7 +97,7 @@ private static GuardedInvocation linkBean(final LinkRequest linkRequest) throws Exception { final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor(); final Object self = linkRequest.getReceiver(); - switch (NashornCallSiteDescriptor.getFirstStandardOperation(desc)) { + switch (NashornCallSiteDescriptor.getStandardOperation(desc)) { case NEW: if(BeansLinker.isDynamicConstructor(self)) { throw typeError("no.constructor.matches.args", ScriptRuntime.safeToString(self)); @@ -124,35 +123,26 @@ static MethodHandle linkMissingBeanMember(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor(); - final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc); - if (op != null) { - final String operand = NashornCallSiteDescriptor.getOperand(desc); - switch (op) { - case GET_METHOD: - case GET_PROPERTY: - case GET_ELEMENT: { - if (NashornCallSiteDescriptor.isOptimistic(desc)) { - return adaptThrower(MethodHandles.insertArguments(THROW_OPTIMISTIC_UNDEFINED, 0, NashornCallSiteDescriptor.getProgramPoint(desc)), desc); - } - if (NashornCallSiteDescriptor.getOperand(desc) != null) { - return getInvocation(EMPTY_PROP_GETTER, linkerServices, desc); - } - return getInvocation(EMPTY_ELEM_GETTER, linkerServices, desc); + final String operand = NashornCallSiteDescriptor.getOperand(desc); + switch (NashornCallSiteDescriptor.getStandardOperation(desc)) { + case GET: + if (NashornCallSiteDescriptor.isOptimistic(desc)) { + return adaptThrower(MethodHandles.insertArguments(THROW_OPTIMISTIC_UNDEFINED, 0, NashornCallSiteDescriptor.getProgramPoint(desc)), desc); + } else if (operand != null) { + return getInvocation(EMPTY_PROP_GETTER, linkerServices, desc); } - case SET_PROPERTY: - case SET_ELEMENT: - final boolean strict = NashornCallSiteDescriptor.isStrict(desc); - if (strict) { - return adaptThrower(bindOperand(THROW_STRICT_PROPERTY_SETTER, operand), desc); - } - if (NashornCallSiteDescriptor.getOperand(desc) != null) { - return getInvocation(EMPTY_PROP_SETTER, linkerServices, desc); - } - return getInvocation(EMPTY_ELEM_SETTER, linkerServices, desc); - default: + return getInvocation(EMPTY_ELEM_GETTER, linkerServices, desc); + case SET: + final boolean strict = NashornCallSiteDescriptor.isStrict(desc); + if (strict) { + return adaptThrower(bindOperand(THROW_STRICT_PROPERTY_SETTER, operand), desc); + } else if (operand != null) { + return getInvocation(EMPTY_PROP_SETTER, linkerServices, desc); } + return getInvocation(EMPTY_ELEM_SETTER, linkerServices, desc); + default: + throw new AssertionError("unknown call type " + desc); } - throw new AssertionError("unknown call type " + desc); } private static MethodHandle bindOperand(final MethodHandle handle, final String operand) { @@ -217,17 +207,13 @@ private static GuardedInvocation linkNull(final LinkRequest linkRequest) { final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor(); - switch (NashornCallSiteDescriptor.getFirstStandardOperation(desc)) { + switch (NashornCallSiteDescriptor.getStandardOperation(desc)) { case NEW: case CALL: throw typeError("not.a.function", "null"); - case GET_METHOD: - throw typeError("no.such.function", getArgument(linkRequest), "null"); - case GET_PROPERTY: - case GET_ELEMENT: - throw typeError("cant.get.property", getArgument(linkRequest), "null"); - case SET_PROPERTY: - case SET_ELEMENT: + case GET: + throw typeError(NashornCallSiteDescriptor.isMethodFirstOperation(desc) ? "no.such.function" : "cant.get.property", getArgument(linkRequest), "null"); + case SET: throw typeError("cant.set.property", getArgument(linkRequest), "null"); default: throw new AssertionError("unknown call type " + desc); diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java Fri Nov 11 16:44:36 2016 +0100 @@ -25,6 +25,12 @@ package jdk.nashorn.internal.runtime.linker; +import static jdk.dynalink.StandardNamespace.ELEMENT; +import static jdk.dynalink.StandardNamespace.METHOD; +import static jdk.dynalink.StandardNamespace.PROPERTY; +import static jdk.dynalink.StandardOperation.GET; +import static jdk.dynalink.StandardOperation.SET; + import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; @@ -40,10 +46,11 @@ import java.util.concurrent.ConcurrentMap; import java.util.stream.Stream; import jdk.dynalink.CallSiteDescriptor; -import jdk.dynalink.CompositeOperation; import jdk.dynalink.NamedOperation; +import jdk.dynalink.NamespaceOperation; import jdk.dynalink.Operation; import jdk.dynalink.SecureLookupSupplier; +import jdk.dynalink.StandardNamespace; import jdk.dynalink.StandardOperation; import jdk.nashorn.internal.ir.debug.NashornTextifier; import jdk.nashorn.internal.runtime.AccessControlContextFactory; @@ -78,12 +85,12 @@ // Correspond to the operation indices above. private static final Operation[] OPERATIONS = new Operation[] { - new CompositeOperation(StandardOperation.GET_PROPERTY, StandardOperation.GET_ELEMENT, StandardOperation.GET_METHOD), - new CompositeOperation(StandardOperation.GET_ELEMENT, StandardOperation.GET_PROPERTY, StandardOperation.GET_METHOD), - new CompositeOperation(StandardOperation.GET_METHOD, StandardOperation.GET_PROPERTY, StandardOperation.GET_ELEMENT), - new CompositeOperation(StandardOperation.GET_METHOD, StandardOperation.GET_ELEMENT, StandardOperation.GET_PROPERTY), - new CompositeOperation(StandardOperation.SET_PROPERTY, StandardOperation.SET_ELEMENT), - new CompositeOperation(StandardOperation.SET_ELEMENT, StandardOperation.SET_PROPERTY), + GET.withNamespaces(PROPERTY, ELEMENT, METHOD), + GET.withNamespaces(ELEMENT, PROPERTY, METHOD), + GET.withNamespaces(METHOD, PROPERTY, ELEMENT), + GET.withNamespaces(METHOD, ELEMENT, PROPERTY), + SET.withNamespaces(PROPERTY, ELEMENT), + SET.withNamespaces(ELEMENT, PROPERTY), StandardOperation.CALL, StandardOperation.NEW }; @@ -248,7 +255,7 @@ return existing; } } - final NamedOperation newOp = new NamedOperation(baseOp, name); + final NamedOperation newOp = baseOp.named(name); namedOps.put(name, new WeakReference<>(newOp)); return newOp; } @@ -288,16 +295,6 @@ } /** - * Returns the named operand in this descriptor's operation. Equivalent to - * {@code ((NamedOperation)getOperation()).getName().toString()} for call - * sites with a named operand. For call sites without named operands returns null. - * @return the named operand in this descriptor's operation. - */ - public String getOperand() { - return getOperand(this); - } - - /** * Returns the named operand in the passed descriptor's operation. * Equivalent to * {@code ((NamedOperation)desc.getOperation()).getName().toString()} for @@ -311,70 +308,63 @@ return operation instanceof NamedOperation ? ((NamedOperation)operation).getName().toString() : null; } + private static StandardNamespace findFirstStandardNamespace(final CallSiteDescriptor desc) { + return StandardNamespace.findFirst(desc.getOperation()); + } + /** - * Returns the first operation in this call site descriptor's potentially - * composite operation. E.g. if this call site descriptor has a composite - * operation {@code GET_PROPERTY|GET_METHOD|GET_ELEM}, it will return - * {@code GET_PROPERTY}. Nashorn - being a ECMAScript engine - does not - * distinguish between property, element, and method namespace; ECMAScript - * objects just have one single property namespace for all these, therefore - * it is largely irrelevant what the composite operation is structured like; - * if the first operation can't be satisfied, neither can the others. The - * first operation is however sometimes used to slightly alter the - * semantics; for example, a distinction between {@code GET_PROPERTY} and - * {@code GET_METHOD} being the first operation can translate into whether - * {@code "__noSuchProperty__"} or {@code "__noSuchMethod__"} will be - * executed in case the property is not found. Note that if a call site - * descriptor comes from outside of Nashorn, its class will be different, - * and there is no guarantee about the way it composes its operations. For - * that reason, for potentially foreign call site descriptors you should use - * {@link #getFirstStandardOperation(CallSiteDescriptor)} instead. - * @return the first operation in this call site descriptor. Note this will - * always be a {@code StandardOperation} as Nashorn internally only uses - * standard operations. + * Returns true if the operation of the call descriptor is operating on the method namespace first. + * @param desc the call descriptor in question. + * @return true if the operation of the call descriptor is operating on the method namespace first. */ - public StandardOperation getFirstOperation() { - final Operation base = NamedOperation.getBaseOperation(getOperation()); - if (base instanceof CompositeOperation) { - return (StandardOperation)((CompositeOperation)base).getOperation(0); - } - return (StandardOperation)base; + public static boolean isMethodFirstOperation(final CallSiteDescriptor desc) { + return findFirstStandardNamespace(desc) == StandardNamespace.METHOD; + } + + /** + * Returns true if there's a namespace operation in the call descriptor and it is operating on at least + * one {@link StandardNamespace}. This method is only needed for exported linkers, since internal linkers + * always operate on Nashorn-generated call sites, and they always operate on standard namespaces only. + * @param desc the call descriptor in question. + * @return true if the operation of the call descriptor is operating on at least one standard namespace. + */ + public static boolean hasStandardNamespace(final CallSiteDescriptor desc) { + return findFirstStandardNamespace(desc) != null; } /** - * Returns the first standard operation in the (potentially composite) - * operation of the passed call site descriptor. + * Returns the base operation in this call site descriptor after unwrapping it from both a named operation + * and a namespace operation. * @param desc the call site descriptor. - * @return Returns the first standard operation in the (potentially - * composite) operation of the passed call site descriptor. Can return null - * if the call site contains no standard operations. + * @return the base operation in this call site descriptor. */ - public static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) { - final Operation base = NamedOperation.getBaseOperation(desc.getOperation()); - if (base instanceof StandardOperation) { - return (StandardOperation)base; - } else if (base instanceof CompositeOperation) { - final CompositeOperation cop = (CompositeOperation)base; - for(int i = 0; i < cop.getOperationCount(); ++i) { - final Operation op = cop.getOperation(i); - if (op instanceof StandardOperation) { - return (StandardOperation)op; - } - } - } - return null; + public static Operation getBaseOperation(final CallSiteDescriptor desc) { + return NamespaceOperation.getBaseOperation(NamedOperation.getBaseOperation(desc.getOperation())); } /** - * Returns true if the passed call site descriptor's operation contains (or - * is) the specified standard operation. + * Returns the standard operation that is the base operation in this call site descriptor. + * @param desc the call site descriptor. + * @return the standard operation that is the base operation in this call site descriptor. + * @throws ClassCastException if the base operation is not a standard operation. This method is only + * safe to use when the base operation is known to be a standard operation (e.g. all Nashorn call sites + * are such, so it's safe to use from internal linkers). + */ + public static StandardOperation getStandardOperation(final CallSiteDescriptor desc) { + return (StandardOperation)getBaseOperation(desc); + } + + /** + * Returns true if the passed call site descriptor contains the specified standard operation on the + * specified standard namespace. * @param desc the call site descriptor. * @param operation the operation whose presence is tested. - * @return Returns true if the call site descriptor's operation contains (or - * is) the specified standard operation. + * @param namespace the namespace on which the operation operates. + * @return Returns true if the call site descriptor contains the specified standard operation on the + * specified standard namespace. */ - public static boolean contains(final CallSiteDescriptor desc, final StandardOperation operation) { - return CompositeOperation.contains(NamedOperation.getBaseOperation(desc.getOperation()), operation); + public static boolean contains(final CallSiteDescriptor desc, final StandardOperation operation, final StandardNamespace namespace) { + return NamespaceOperation.contains(NamedOperation.getBaseOperation(desc.getOperation()), operation, namespace); } /** @@ -383,8 +373,8 @@ * @param obj object on which CALL or NEW is used * @return error message */ - public String getFunctionErrorMessage(final Object obj) { - final String funcDesc = getOperand(); + private String getFunctionErrorMessage(final Object obj) { + final String funcDesc = getOperand(this); return funcDesc != null? funcDesc : ScriptRuntime.safeToString(obj); } @@ -552,4 +542,9 @@ public CallSiteDescriptor changeMethodTypeInternal(final MethodType newMethodType) { return get(getLookupPrivileged(), getOperation(), newMethodType, flags); } + + @Override + protected CallSiteDescriptor changeOperationInternal(final Operation newOperation) { + return get(getLookupPrivileged(), newOperation, getMethodType(), flags); + } } diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Fri Nov 11 16:44:36 2016 +0100 @@ -99,10 +99,8 @@ final String name = NashornCallSiteDescriptor.getOperand(desc); final FindProperty find = name != null ? wrappedReceiver.findProperty(name, true) : null; - switch (NashornCallSiteDescriptor.getFirstStandardOperation(desc)) { - case GET_PROPERTY: - case GET_ELEMENT: - case GET_METHOD: + switch (NashornCallSiteDescriptor.getStandardOperation(desc)) { + case GET: //checks whether the property name is hard-coded in the call-site (i.e. a getProp vs a getElem, or setProp vs setElem) //if it is we can make assumptions on the property: that if it is not defined on primitive wrapper itself it never will be. //so in that case we can skip creation of primitive wrapper and start our search with the prototype. @@ -133,8 +131,7 @@ } } break; - case SET_PROPERTY: - case SET_ELEMENT: + case SET: return getPrimitiveSetter(name, guard, wrapFilter, NashornCallSiteDescriptor.isStrict(desc)); default: break; diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java Fri Nov 11 16:44:36 2016 +0100 @@ -30,6 +30,7 @@ import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; import jdk.dynalink.CallSiteDescriptor; +import jdk.dynalink.StandardNamespace; import jdk.dynalink.StandardOperation; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.LinkRequest; @@ -129,9 +130,9 @@ // allow 'static' access on Class objects representing public classes of non-restricted packages if ((self instanceof Class) && Modifier.isPublic(((Class)self).getModifiers())) { final CallSiteDescriptor desc = request.getCallSiteDescriptor(); - if ("static".equals(NashornCallSiteDescriptor.getOperand(desc)) && NashornCallSiteDescriptor.contains(desc, StandardOperation.GET_PROPERTY)) { + if ("static".equals(NashornCallSiteDescriptor.getOperand(desc)) && NashornCallSiteDescriptor.contains(desc, StandardOperation.GET, StandardNamespace.PROPERTY)) { if (Context.isAccessibleClass((Class)self) && !isReflectionClass((Class)self)) { - // If "GET_PROPERTY:static" passes access checks, allow access. + // If "GET:PROPERTY:static" passes access checks, allow access. return; } } diff -r f71b844f33d1 -r 95af45781076 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Fri Nov 11 16:44:36 2016 +0100 @@ -214,6 +214,7 @@ syntax.error.strict.cant.delete=cannot delete "{0}" in strict mode syntax.error.redeclare.variable=Variable "{0}" has already been declared syntax.error.unprotected.switch.declaration=Unsupported {0} declaration in unprotected switch statement +syntax.error.duplicate.parameter=Duplicate parameter name "{0}" io.error.cant.write=cannot write "{0}" @@ -222,3 +223,12 @@ uri.error.bad.uri=Bad URI "{0}" near offset {1} list.adapter.null.global=Attempted to create the adapter from outside a JavaScript execution context. + +unimplemented.es6.module=ES6 modules are not yet implemented +unimplemented.es6.rest.param=ES6 function rest parameter declaration is not yet implemented +unimplemented.es6.yield=ES6 yield and yield* are not yet implemented +unimplemented.es6.spread=ES6 spread operator is not yet implemented +unimplemented.es6.class=ES6 class declarations and expressions are not yet implemented +unimplemented.es6.destructuring=ES6 destructuring is not yet implemented +unimplemented.es6.generator=ES6 generator is not yet implemented +unimplemented.es6.super=ES6 super keyword is not yet implemented diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/es6/class.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/es6/class.js Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Class declaration is not implemented + * + * @test + * @run + * @option --language=es6 + */ + +try { + eval("class Foo {}"); +} catch (e) { + print(String(e).replace(/\\/g, "/")) +} diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/es6/class.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/es6/class.js.EXPECTED Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,3 @@ +java.lang.RuntimeException: test/script/basic/es6/class.js#33:3:1:0 ES6 class declarations and expressions are not yet implemented +class Foo {} +^ diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/es6/destructuring.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/es6/destructuring.js Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Destructuring is not implemented + * + * @test + * @run + * @option --language=es6 + */ + + +function check(code) { + try { + eval(code); + } catch (e) { + print(String(e).replace(/\\/g, "/")) + } +} + +check("var { x: y } = obj;"); +check("let { x: y } = obj;"); +check("const { x: y } = obj;"); +check("({ x: y }) = obj;"); +check("for (var { x: y } of obj) ;"); +check("for (let { x: y } of obj) ;"); +check("var { x, y } = obj;"); +check("let { x, y } = obj;"); +check("const { x, y } = obj;"); +check("({ x, y }) = obj;"); +check("for (var { x, y } of obj) ;"); +check("for (let { x, y } of obj) ;"); +check("var [a, b] = obj;"); +check("let [a, b] = obj;"); +check("const [a, b] = obj;"); +check("[a, b] = obj;"); +check("for ([a, b] of obj) ;"); +check("for (var [a, b] of obj) ;"); +check("for (let [a, b] of obj) ;"); +check("(function({ x: y }) { return x; })()"); +check("(function({ x }) { return x; })()"); +check("(function([x]) { return x; })()"); +check("for (var [[x, y, z] = [4, 5, 6]] = [7, 8, 9]; iterCount < 1; ) ;"); +check("for ([ arrow = () => {} ] of [[]]) ;"); + diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/es6/destructuring.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/es6/destructuring.js.EXPECTED Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,72 @@ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:4 ES6 destructuring is not yet implemented +var { x: y } = obj; + ^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:4 ES6 destructuring is not yet implemented +let { x: y } = obj; + ^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:6 ES6 destructuring is not yet implemented +const { x: y } = obj; + ^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:1 ES6 destructuring is not yet implemented +({ x: y }) = obj; + ^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:0 ES6 destructuring is not yet implemented +for (var { x: y } of obj) ; +^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:0 ES6 destructuring is not yet implemented +for (let { x: y } of obj) ; +^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:4 ES6 destructuring is not yet implemented +var { x, y } = obj; + ^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:4 ES6 destructuring is not yet implemented +let { x, y } = obj; + ^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:6 ES6 destructuring is not yet implemented +const { x, y } = obj; + ^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:1 ES6 destructuring is not yet implemented +({ x, y }) = obj; + ^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:0 ES6 destructuring is not yet implemented +for (var { x, y } of obj) ; +^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:0 ES6 destructuring is not yet implemented +for (let { x, y } of obj) ; +^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:4 ES6 destructuring is not yet implemented +var [a, b] = obj; + ^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:4 ES6 destructuring is not yet implemented +let [a, b] = obj; + ^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:6 ES6 destructuring is not yet implemented +const [a, b] = obj; + ^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:0 ES6 destructuring is not yet implemented +[a, b] = obj; +^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:0 ES6 destructuring is not yet implemented +for ([a, b] of obj) ; +^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:0 ES6 destructuring is not yet implemented +for (var [a, b] of obj) ; +^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:0 ES6 destructuring is not yet implemented +for (let [a, b] of obj) ; +^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:9 ES6 destructuring is not yet implemented +(function({ x: y }) { return x; })() + ^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:9 ES6 destructuring is not yet implemented +(function({ x }) { return x; })() + ^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:9 ES6 destructuring is not yet implemented +(function([x]) { return x; })() + ^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:9 ES6 destructuring is not yet implemented +for (var [[x, y, z] = [4, 5, 6]] = [7, 8, 9]; iterCount < 1; ) ; + ^ +java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6:1:0 ES6 destructuring is not yet implemented +for ([ arrow = () => {} ] of [[]]) ; +^ diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/es6/generator.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/es6/generator.js Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Generators are not implemented + * + * @test + * @run + * @option --language=es6 + */ + +function check(code) { + try { + eval(code); + } catch (e) { + print(String(e).replace(/\\/g, "/")) + } +} + +check("function* func() { yield 1; }"); +check("({ * generatorMethod() { yield 1; } })"); +check("var func = function*() { yield 1; }"); diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/es6/generator.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/es6/generator.js.EXPECTED Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,9 @@ +java.lang.RuntimeException: test/script/basic/es6/generator.js#34:6:1:17 ES6 generator is not yet implemented +function* func() { yield 1; } + ^ +java.lang.RuntimeException: test/script/basic/es6/generator.js#34:6:1:23 ES6 generator is not yet implemented +({ * generatorMethod() { yield 1; } }) + ^ +java.lang.RuntimeException: test/script/basic/es6/generator.js#34:6:1:23 ES6 generator is not yet implemented +var func = function*() { yield 1; } + ^ diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/es6/restparam.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/es6/restparam.js Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * ES6 rest params are not implemented + * + * @test + * @run + * @option --language=es6 + */ + + +function check(code) { + try { + eval(code); + } catch (e) { + print(String(e).replace(/\\/g, "/")) + } +} + +check("function func(...args) {}"); +check("function func(x, y, ...args) {}"); +check("({ meth(...args) {} })"); +check("({ meth(x, y, ...args) {} })"); +check("({ meth(x = 0, x) {} })"); + diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/es6/restparam.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/es6/restparam.js.EXPECTED Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,15 @@ +java.lang.RuntimeException: test/script/basic/es6/restparam.js#35:6:1:17 ES6 function rest parameter declaration is not yet implemented +function func(...args) {} + ^ +java.lang.RuntimeException: test/script/basic/es6/restparam.js#35:6:1:23 ES6 function rest parameter declaration is not yet implemented +function func(x, y, ...args) {} + ^ +java.lang.RuntimeException: test/script/basic/es6/restparam.js#35:6:1:11 ES6 function rest parameter declaration is not yet implemented +({ meth(...args) {} }) + ^ +java.lang.RuntimeException: test/script/basic/es6/restparam.js#35:6:1:17 ES6 function rest parameter declaration is not yet implemented +({ meth(x, y, ...args) {} }) + ^ +SyntaxError: test/script/basic/es6/restparam.js#35:6:1:15 Duplicate parameter name "x" +({ meth(x = 0, x) {} }) + ^ diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/es6/spread.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/es6/spread.js Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * ES6 spread operator is not implemented + * + * @test + * @run + * @option --language=es6 + */ + +function check(code) { + try { + eval(code); + } catch (e) { + print(String(e).replace(/\\/g, "/")) + } +} + +check("var x = [...args]"); +check("var x = [1, 2, ...args]"); +check("var x = [...args, 3, 5]"); +check("var r = func(...arr)"); diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/es6/spread.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/es6/spread.js.EXPECTED Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,12 @@ +java.lang.RuntimeException: test/script/basic/es6/spread.js#34:8:1:9 ES6 spread operator is not yet implemented +var x = [...args] + ^ +java.lang.RuntimeException: test/script/basic/es6/spread.js#34:8:1:15 ES6 spread operator is not yet implemented +var x = [1, 2, ...args] + ^ +java.lang.RuntimeException: test/script/basic/es6/spread.js#34:8:1:9 ES6 spread operator is not yet implemented +var x = [...args, 3, 5] + ^ +java.lang.RuntimeException: test/script/basic/es6/spread.js#34:8:1:13 ES6 spread operator is not yet implemented +var r = func(...arr) + ^ diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/es6/super.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/es6/super.js Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * ES6 super keyword is not implemented + * + * @test + * @run + * @option --language=es6 + */ + +function check(code) { + try { + eval(code); + } catch (e) { + print(String(e).replace(/\\/g, "/")) + } +} + +check("({ meth() { x = super.x } })"); +check("({ meth() { x = super.x() } })"); +check("({ meth() { x = super['x'] } })"); diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/es6/super.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/es6/super.js.EXPECTED Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,9 @@ +java.lang.RuntimeException: test/script/basic/es6/super.js#34:8:1:10 ES6 super keyword is not yet implemented +({ meth() { x = super.x } }) + ^ +java.lang.RuntimeException: test/script/basic/es6/super.js#34:8:1:10 ES6 super keyword is not yet implemented +({ meth() { x = super.x() } }) + ^ +java.lang.RuntimeException: test/script/basic/es6/super.js#34:8:1:10 ES6 super keyword is not yet implemented +({ meth() { x = super['x'] } }) + ^ diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/jsadapter-ids.js --- a/nashorn/test/script/basic/jsadapter-ids.js Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/test/script/basic/jsadapter-ids.js Fri Nov 11 16:44:36 2016 +0100 @@ -30,6 +30,7 @@ var obj = new JSAdapter() { __getIds__: function() { + Assert.assertTrue(this === obj); print("__getIds__ called"); return [ "foo", "bar" ]; } diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/jsadapter.js --- a/nashorn/test/script/basic/jsadapter.js Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/test/script/basic/jsadapter.js Fri Nov 11 16:44:36 2016 +0100 @@ -30,39 +30,81 @@ var obj = new JSAdapter() { __get__: function(name) { + Assert.assertTrue(this === obj); print("getter called for '" + name + "'"); return name; }, __put__: function(name, value) { + Assert.assertTrue(this === obj); print("setter called for '" + name + "' with " + value); }, __call__: function(name, arg1, arg2) { + Assert.assertTrue(this === obj); print("method '" + name + "' called with " + arg1 + ", " + arg2); }, __new__: function(arg1, arg2) { + Assert.assertTrue(this === obj); print("new with " + arg1 + ", " + arg2); }, __getKeys__: function() { + Assert.assertTrue(this === obj); print("__getKeys__ called"); return [ "foo", "bar" ]; }, __getValues__: function() { + Assert.assertTrue(this === obj); print("__getValues__ called"); return [ "fooval", "barval" ]; }, __has__: function(name) { + Assert.assertTrue(this === obj); print("__has__ called with '" + name + "'"); return name == "js"; }, __delete__: function(name) { + Assert.assertTrue(this === obj); print("__delete__ called with '" + name + "'"); return true; + }, + + __preventExtensions__ : function() { + Assert.assertTrue(this === obj); + print("__preventExtensions__ called"); + }, + + __freeze__ : function() { + Assert.assertTrue(this === obj); + print("__freeze__ called"); + + }, + + __isFrozen__ : function() { + Assert.assertTrue(this === obj); + print("__isFrozen__ called"); + return false; + }, + + __seal__ : function() { + Assert.assertTrue(this === obj); + print("__seal__ called"); + }, + + __isSealed__ : function() { + Assert.assertTrue(this === obj); + print("__isSealed__ called"); + return false; + }, + + __isExtensible__ : function() { + Assert.assertTrue(this === obj); + print("__isExtensible__ called"); + return true; } }; @@ -103,3 +145,13 @@ print(obj["js"]); obj["js"] = "javascript"; print(obj["javascript"]); + +// call __isExtensible__, __isSealed__, __isFrozen__ +print(Object.isExtensible(obj)); +print(Object.isSealed(obj)); +print(Object.isFrozen(obj)); + +// call __freeze__, __seal__, __preventExtensions__ +Object.freeze(obj); +Object.seal(obj); +Object.preventExtensions(obj); diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/jsadapter.js.EXPECTED --- a/nashorn/test/script/basic/jsadapter.js.EXPECTED Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/test/script/basic/jsadapter.js.EXPECTED Fri Nov 11 16:44:36 2016 +0100 @@ -20,3 +20,12 @@ setter called for 'js' with javascript getter called for 'javascript' javascript +__isExtensible__ called +true +__isSealed__ called +false +__isFrozen__ called +false +__freeze__ called +__seal__ called +__preventExtensions__ called diff -r f71b844f33d1 -r 95af45781076 nashorn/test/script/basic/jsadapterlink.js --- a/nashorn/test/script/basic/jsadapterlink.js Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/test/script/basic/jsadapterlink.js Fri Nov 11 16:44:36 2016 +0100 @@ -31,18 +31,21 @@ var js1 = new JSAdapter() { __get__: function(name) { + Assert.assertTrue(this === js1); return "js1->" + name; } }; var js2 = new JSAdapter() { __get__: function(name) { + Assert.assertTrue(this === js2); return "js2->" + name; } }; var js3 = new JSAdapter() { __get__: function(name) { + Assert.assertTrue(this === js3); return "js3->" + name; } }; diff -r f71b844f33d1 -r 95af45781076 nashorn/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter --- a/nashorn/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter Fri Nov 11 16:44:36 2016 +0100 @@ -1,2 +1,3 @@ jdk.dynalink.test.UntrustedGuardingDynamicLinkerExporter jdk.dynalink.test.TrustedGuardingDynamicLinkerExporter +jdk.dynalink.test.TrustedUnderscoreNameLinkerExporter diff -r f71b844f33d1 -r 95af45781076 nashorn/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java --- a/nashorn/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -24,14 +24,13 @@ */ package jdk.dynalink.beans.test; +import static jdk.dynalink.StandardNamespace.ELEMENT; +import static jdk.dynalink.StandardNamespace.METHOD; +import static jdk.dynalink.StandardNamespace.PROPERTY; import static jdk.dynalink.StandardOperation.CALL; -import static jdk.dynalink.StandardOperation.CALL_METHOD; -import static jdk.dynalink.StandardOperation.GET_ELEMENT; -import static jdk.dynalink.StandardOperation.GET_LENGTH; -import static jdk.dynalink.StandardOperation.GET_METHOD; -import static jdk.dynalink.StandardOperation.GET_PROPERTY; +import static jdk.dynalink.StandardOperation.GET; import static jdk.dynalink.StandardOperation.NEW; -import static jdk.dynalink.StandardOperation.SET_ELEMENT; +import static jdk.dynalink.StandardOperation.SET; import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandle; @@ -39,7 +38,6 @@ import java.lang.invoke.MethodType; import java.security.AccessControlException; import java.util.ArrayList; -import java.util.Collections; import java.util.Date; import java.util.List; import jdk.dynalink.CallSiteDescriptor; @@ -78,12 +76,21 @@ } private CallSite createCallSite(final boolean publicLookup, final Operation op, final Object name, final MethodType mt) { - return createCallSite(publicLookup, new NamedOperation(op, name), mt); + return createCallSite(publicLookup, op.named(name), mt); + } + + private CallSite createGetMethodCallSite(final boolean publicLookup, final String name) { + return createCallSite(publicLookup, GET_METHOD, name, MethodType.methodType(Object.class, Object.class)); } private static final MethodHandle throwArrayIndexOutOfBounds = findThrower("throwArrayIndexOutOfBounds"); private static final MethodHandle throwIndexOutOfBounds = findThrower("throwIndexOutOfBounds"); + private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY); + private static final Operation GET_ELEMENT = GET.withNamespace(ELEMENT); + private static final Operation GET_METHOD = GET.withNamespace(METHOD); + private static final Operation SET_ELEMENT = SET.withNamespace(ELEMENT); + private static final MethodHandle findThrower(final String name) { try { return MethodHandles.lookup().findStatic(BeanLinkerTest.class, name, @@ -209,26 +216,6 @@ } @Test(dataProvider = "flags") - public void getlengthTest(final boolean publicLookup) throws Throwable { - final MethodType mt = MethodType.methodType(int.class, Object.class); - final CallSite cs = createCallSite(publicLookup, GET_LENGTH, mt); - - final int[] arr = {23, 42}; - Assert.assertEquals((int) cs.getTarget().invoke((Object) arr), 2); - Assert.assertEquals((int) cs.getTarget().invoke(Collections.EMPTY_LIST), 0); - - final List list = new ArrayList<>(); - list.add("hello"); - list.add("world"); - list.add("dynalink"); - Assert.assertEquals((int) cs.getTarget().invoke(list), 3); - list.add("nashorn"); - Assert.assertEquals((int) cs.getTarget().invoke(list), 4); - list.clear(); - Assert.assertEquals((int) cs.getTarget().invoke(list), 0); - } - - @Test(dataProvider = "flags") public void getElementTest(final boolean publicLookup) throws Throwable { final MethodType mt = MethodType.methodType(int.class, Object.class, int.class); final CallSite cs = createCallSite(publicLookup, GET_ELEMENT, mt); @@ -364,8 +351,7 @@ @Test(dataProvider = "flags") public void instanceMethodCallTest(final boolean publicLookup) { - final MethodType mt = MethodType.methodType(Object.class, Object.class); - final CallSite cs = createCallSite(publicLookup, GET_METHOD, "getClass", mt); + final CallSite cs = createGetMethodCallSite(publicLookup, "getClass"); final MethodType mt2 = MethodType.methodType(Class.class, Object.class, Object.class); final CallSite cs2 = createCallSite(publicLookup, CALL, mt2); @@ -389,23 +375,8 @@ } @Test(dataProvider = "flags") - public void instanceMethodCallTest2(final boolean publicLookup) { - final MethodType mt = MethodType.methodType(Class.class, Object.class); - final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getClass", mt); - Class clz = null; - try { - clz = (Class) cs.getTarget().invoke(new Date()); - } catch (final Throwable th) { - throw new RuntimeException(th); - } - - Assert.assertEquals(clz, Date.class); - } - - @Test(dataProvider = "flags") public void staticMethodCallTest(final boolean publicLookup) { - final MethodType mt = MethodType.methodType(Object.class, StaticClass.class); - final CallSite cs = createCallSite(publicLookup, GET_METHOD, "getProperty", mt); + final CallSite cs = createGetMethodCallSite(publicLookup, "getProperty"); final MethodType mt2 = MethodType.methodType(String.class, Object.class, Object.class, String.class); final CallSite cs2 = createCallSite(publicLookup, CALL, mt2); @@ -428,28 +399,15 @@ Assert.assertEquals(str, System.getProperty("os.name")); } - @Test(dataProvider = "flags") - public void staticMethodCallTest2(final boolean publicLookup) { - final MethodType mt = MethodType.methodType(String.class, Object.class, String.class); - final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getProperty", mt); - - String str = null; - try { - str = (String) cs.getTarget().invoke(StaticClass.forClass(System.class), "os.name"); - } catch (final Throwable th) { - throw new RuntimeException(th); - } - Assert.assertEquals(str, System.getProperty("os.name")); - } - // try calling System.getenv and expect security exception @Test(dataProvider = "flags") public void systemGetenvTest(final boolean publicLookup) { - final MethodType mt = MethodType.methodType(Object.class, Object.class); - final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getenv", mt); + final CallSite cs1 = createGetMethodCallSite(publicLookup, "getenv"); + final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(Object.class, Object.class, Object.class)); try { - cs.getTarget().invoke(StaticClass.forClass(System.class)); + final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class)); + cs2.getTarget().invoke(method, StaticClass.forClass(System.class)); throw new RuntimeException("should not reach here in any case!"); } catch (final Throwable th) { Assert.assertTrue(th instanceof SecurityException); @@ -459,11 +417,12 @@ // try getting a specific sensitive System property and expect security exception @Test(dataProvider = "flags") public void systemGetPropertyTest(final boolean publicLookup) { - final MethodType mt = MethodType.methodType(String.class, Object.class, String.class); - final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getProperty", mt); + final CallSite cs1 = createGetMethodCallSite(publicLookup, "getProperty"); + final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(String.class, Object.class, Object.class, String.class)); try { - cs.getTarget().invoke(StaticClass.forClass(System.class), "java.home"); + final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class)); + cs2.getTarget().invoke(method, StaticClass.forClass(System.class), "java.home"); throw new RuntimeException("should not reach here in any case!"); } catch (final Throwable th) { Assert.assertTrue(th instanceof SecurityException); @@ -473,11 +432,12 @@ // check a @CallerSensitive API and expect appropriate access check exception @Test(dataProvider = "flags") public void systemLoadLibraryTest(final boolean publicLookup) { - final MethodType mt = MethodType.methodType(void.class, Object.class, String.class); - final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "loadLibrary", mt); + final CallSite cs1 = createGetMethodCallSite(publicLookup, "loadLibrary"); + final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(void.class, Object.class, Object.class, String.class)); try { - cs.getTarget().invoke(StaticClass.forClass(System.class), "foo"); + final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class)); + cs2.getTarget().invoke(method, StaticClass.forClass(System.class), "foo"); throw new RuntimeException("should not reach here in any case!"); } catch (final Throwable th) { if (publicLookup) { diff -r f71b844f33d1 -r 95af45781076 nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java --- a/nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -24,12 +24,12 @@ */ package jdk.dynalink.beans.test; +import static jdk.dynalink.StandardNamespace.ELEMENT; +import static jdk.dynalink.StandardNamespace.METHOD; +import static jdk.dynalink.StandardNamespace.PROPERTY; import static jdk.dynalink.StandardOperation.CALL; -import static jdk.dynalink.StandardOperation.GET_ELEMENT; -import static jdk.dynalink.StandardOperation.GET_METHOD; -import static jdk.dynalink.StandardOperation.GET_PROPERTY; -import static jdk.dynalink.StandardOperation.SET_ELEMENT; -import static jdk.dynalink.StandardOperation.SET_PROPERTY; +import static jdk.dynalink.StandardOperation.GET; +import static jdk.dynalink.StandardOperation.SET; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -42,12 +42,11 @@ import java.util.regex.Pattern; import java.util.stream.Stream; import jdk.dynalink.CallSiteDescriptor; -import jdk.dynalink.CompositeOperation; import jdk.dynalink.DynamicLinkerFactory; -import jdk.dynalink.NamedOperation; +import jdk.dynalink.Namespace; +import jdk.dynalink.NamespaceOperation; import jdk.dynalink.NoSuchDynamicMethodException; import jdk.dynalink.Operation; -import jdk.dynalink.StandardOperation; import jdk.dynalink.support.SimpleRelinkableCallSite; import org.testng.Assert; import org.testng.annotations.Test; @@ -67,32 +66,32 @@ @Test public static void testPublicFieldPropertyUnnamedGetter() { - testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals(42, call(op, new Bean1(), "answer"))); + testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals(42, call(op, new Bean1(), "answer"))); } @Test public static void testPublicFieldPropertyNamedGetter() { - testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals(42, call(named("answer", op), new Bean1()))); + testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals(42, call(op.named("answer"), new Bean1()))); } @Test public static void testGetterPropertyUnnamedGetter() { - testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals("bean1", call(op, new Bean1(), "name"))); + testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals("bean1", call(op, new Bean1(), "name"))); } @Test public static void testGetterPropertyNamedGetter() { - testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals("bean1", call(named("name", op), new Bean1()))); + testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals("bean1", call(op.named("name"), new Bean1()))); } @Test public static void testMethodUnnamedGetter() { - testGetterPermutations(GET_METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(op, new Bean1(), "someMethod"), new Bean1(), "bar"))); + testGetterPermutations(METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(op, new Bean1(), "someMethod"), new Bean1(), "bar"))); } @Test public static void testMethodNamedGetter() { - testGetterPermutations(GET_METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(named("someMethod", op), new Bean1()), new Bean1(), "bar"))); + testGetterPermutations(METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(op.named("someMethod"), new Bean1()), new Bean1(), "bar"))); } private static final Map MAP1 = new HashMap<>(); @@ -102,12 +101,12 @@ @Test public static void testElementUnnamedGetter() { - testGetterPermutations(GET_ELEMENT, (op) -> Assert.assertEquals("bar", call(op, MAP1, "foo"))); + testGetterPermutations(ELEMENT, (op) -> Assert.assertEquals("bar", call(op, MAP1, "foo"))); } @Test public static void testElementNamedGetter() { - testGetterPermutations(GET_ELEMENT, (op) -> Assert.assertEquals("bar", call(named("foo", op), MAP1))); + testGetterPermutations(ELEMENT, (op) -> Assert.assertEquals("bar", call(op.named("foo"), MAP1))); } public static class Bean2 { @@ -121,7 +120,7 @@ @Test public static void testUnnamedFieldSetter() { - testSetterPermutations(SET_PROPERTY, (op) -> { + testSetterPermutations(PROPERTY, (op) -> { final Bean2 bean2 = new Bean2(); call(op, bean2, "answer", 12); Assert.assertEquals(bean2.answer, 12); @@ -130,16 +129,16 @@ @Test public static void testNamedFieldSetter() { - testSetterPermutations(SET_PROPERTY, (op) -> { + testSetterPermutations(PROPERTY, (op) -> { final Bean2 bean2 = new Bean2(); - call(named("answer", op), bean2, 14); + call(op.named("answer"), bean2, 14); Assert.assertEquals(bean2.answer, 14); }); } @Test public static void testUnnamedPropertySetter() { - testSetterPermutations(SET_PROPERTY, (op) -> { + testSetterPermutations(PROPERTY, (op) -> { final Bean2 bean2 = new Bean2(); call(op, bean2, "name", "boo"); Assert.assertEquals(bean2.name, "boo"); @@ -148,14 +147,14 @@ @Test public static void testNamedPropertySetter() { - testSetterPermutations(SET_PROPERTY, (op) -> { + testSetterPermutations(PROPERTY, (op) -> { final Bean2 bean2 = new Bean2(); - call(named("name", op), bean2, "blah"); + call(op.named("name"), bean2, "blah"); Assert.assertEquals(bean2.name, "blah"); }); } - private static final Pattern GET_ELEMENT_THEN_PROPERTY_PATTERN = Pattern.compile(".*GET_ELEMENT.*GET_PROPERTY.*"); + private static final Pattern GET_ELEMENT_THEN_PROPERTY_PATTERN = Pattern.compile(".*ELEMENT.*PROPERTY.*"); @Test public static void testUnnamedElementAndPropertyGetter() { @@ -168,10 +167,10 @@ public static void testNamedElementAndPropertyGetter() { final Map map = new HashMap<>(); map.put("empty", true); - testGetterPermutations(GET_ELEMENT_THEN_PROPERTY_PATTERN, 4, (op) -> Assert.assertEquals(true, call(named("empty", op), map))); + testGetterPermutations(GET_ELEMENT_THEN_PROPERTY_PATTERN, 4, (op) -> Assert.assertEquals(true, call(op.named("empty"), map))); } - private static final Pattern GET_PROPERTY_THEN_ELEMENT_PATTERN = Pattern.compile(".*GET_PROPERTY.*GET_ELEMENT.*"); + private static final Pattern GET_PROPERTY_THEN_ELEMENT_PATTERN = Pattern.compile(".*PROPERTY.*ELEMENT.*"); @Test public static void testUnnamedPropertyAndElementGetter() { @@ -184,7 +183,7 @@ public static void testNamedPropertyAndElementGetter() { final Map map = new HashMap<>(); map.put("empty", true); - testGetterPermutations(GET_PROPERTY_THEN_ELEMENT_PATTERN, 4, (op) -> Assert.assertEquals(false, call(named("empty", op), map))); + testGetterPermutations(GET_PROPERTY_THEN_ELEMENT_PATTERN, 4, (op) -> Assert.assertEquals(false, call(op.named("empty"), map))); } public static class MapWithProperty extends HashMap { @@ -200,24 +199,24 @@ final MapWithProperty map = new MapWithProperty(); map.put("name", "element"); - call(ops(SET_PROPERTY, SET_ELEMENT), map, "name", "property"); + call(SET.withNamespaces(PROPERTY, ELEMENT), map, "name", "property"); Assert.assertEquals("property", map.name); Assert.assertEquals("element", map.get("name")); - call(ops(SET_ELEMENT, SET_PROPERTY), map, "name", "element2"); + call(SET.withNamespaces(ELEMENT, PROPERTY), map, "name", "element2"); Assert.assertEquals("property", map.name); Assert.assertEquals("element2", map.get("name")); } @Test public static void testMissingMembersAtLinkTime() { - testPermutations(GETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(named("foo", op), new Object()))); - testPermutations(SETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(named("foo", op), new Object(), "newValue"))); + testPermutations(GETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(op.named("foo"), new Object()))); + testPermutations(SETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(op.named("foo"), new Object(), "newValue"))); } @Test public static void testMissingMembersAtRunTime() { - call(GET_ELEMENT, new ArrayList<>(), "foo"); + call(GET.withNamespace(ELEMENT), new ArrayList<>(), "foo"); Stream.of(new HashMap(), new ArrayList(), new Object[0]).forEach((receiver) -> { testPermutations(GETTER_PERMUTATIONS, (op) -> { System.err.println(op + " " + receiver.getClass().getName()); Assert.assertNull(call(op, receiver, "foo"));}); // No assertion for the setter; we just expect it to silently succeed @@ -233,59 +232,59 @@ } } - private static Operation[] GETTER_PERMUTATIONS = new Operation[] { - GET_PROPERTY, - GET_METHOD, - GET_ELEMENT, - ops(GET_PROPERTY, GET_ELEMENT), - ops(GET_PROPERTY, GET_METHOD), - ops(GET_ELEMENT, GET_PROPERTY), - ops(GET_ELEMENT, GET_METHOD), - ops(GET_METHOD, GET_PROPERTY), - ops(GET_METHOD, GET_ELEMENT), - ops(GET_PROPERTY, GET_ELEMENT, GET_METHOD), - ops(GET_PROPERTY, GET_METHOD, GET_ELEMENT), - ops(GET_ELEMENT, GET_PROPERTY, GET_METHOD), - ops(GET_ELEMENT, GET_METHOD, GET_PROPERTY), - ops(GET_METHOD, GET_PROPERTY, GET_ELEMENT), - ops(GET_METHOD, GET_ELEMENT, GET_PROPERTY), + private static NamespaceOperation[] GETTER_PERMUTATIONS = new NamespaceOperation[] { + GET.withNamespaces(PROPERTY), + GET.withNamespaces(METHOD), + GET.withNamespaces(ELEMENT), + GET.withNamespaces(PROPERTY, ELEMENT), + GET.withNamespaces(PROPERTY, METHOD), + GET.withNamespaces(ELEMENT, PROPERTY), + GET.withNamespaces(ELEMENT, METHOD), + GET.withNamespaces(METHOD, PROPERTY), + GET.withNamespaces(METHOD, ELEMENT), + GET.withNamespaces(PROPERTY, ELEMENT, METHOD), + GET.withNamespaces(PROPERTY, METHOD, ELEMENT), + GET.withNamespaces(ELEMENT, PROPERTY, METHOD), + GET.withNamespaces(ELEMENT, METHOD, PROPERTY), + GET.withNamespaces(METHOD, PROPERTY, ELEMENT), + GET.withNamespaces(METHOD, ELEMENT, PROPERTY) }; - private static Operation[] SETTER_PERMUTATIONS = new Operation[] { - SET_PROPERTY, - SET_ELEMENT, - ops(SET_PROPERTY, SET_ELEMENT), - ops(SET_ELEMENT, SET_PROPERTY) + private static NamespaceOperation[] SETTER_PERMUTATIONS = new NamespaceOperation[] { + SET.withNamespaces(PROPERTY), + SET.withNamespaces(ELEMENT), + SET.withNamespaces(PROPERTY, ELEMENT), + SET.withNamespaces(ELEMENT, PROPERTY) }; - private static void testPermutations(final Operation[] ops, final StandardOperation requiredOp, final int expectedCount, final Consumer test) { - testPermutationsWithFilter(ops, (op)->CompositeOperation.contains(op, requiredOp), expectedCount, test); + private static void testPermutations(final NamespaceOperation[] ops, final Operation requiredOp, final Namespace requiredNamespace, final int expectedCount, final Consumer test) { + testPermutationsWithFilter(ops, (op)->NamespaceOperation.contains(op, requiredOp, requiredNamespace), expectedCount, test); } - private static void testPermutations(final Operation[] ops, final Pattern regex, final int expectedCount, final Consumer test) { + private static void testPermutations(final NamespaceOperation[] ops, final Pattern regex, final int expectedCount, final Consumer test) { testPermutationsWithFilter(ops, (op)->regex.matcher(op.toString()).matches(), expectedCount, test); } - private static void testPermutations(final Operation[] ops, final Consumer test) { + private static void testPermutations(final NamespaceOperation[] ops, final Consumer test) { testPermutationsWithFilter(ops, (op)->true, ops.length, test); } - private static void testPermutationsWithFilter(final Operation[] ops, final Predicate filter, final int expectedCount, final Consumer test) { + private static void testPermutationsWithFilter(final NamespaceOperation[] ops, final Predicate filter, final int expectedCount, final Consumer test) { final int[] counter = new int[1]; Stream.of(ops).filter(filter).forEach((op)-> { counter[0]++; test.accept(op); }); Assert.assertEquals(counter[0], expectedCount); } - private static void testGetterPermutations(final StandardOperation requiredOp, final Consumer test) { - testPermutations(GETTER_PERMUTATIONS, requiredOp, 11, test); + private static void testGetterPermutations(final Namespace requiredNamespace, final Consumer test) { + testPermutations(GETTER_PERMUTATIONS, GET, requiredNamespace, 11, test); } - private static void testGetterPermutations(final Pattern regex, final int expectedCount, final Consumer test) { + private static void testGetterPermutations(final Pattern regex, final int expectedCount, final Consumer test) { testPermutations(GETTER_PERMUTATIONS, regex, expectedCount, test); } - private static void testSetterPermutations(final StandardOperation requiredOp, final Consumer test) { - testPermutations(SETTER_PERMUTATIONS, requiredOp, 3, test); + private static void testSetterPermutations(final Namespace requiredNamespace, final Consumer test) { + testPermutations(SETTER_PERMUTATIONS, SET, requiredNamespace, 3, test); } private static Object call(final Operation op, final Object... args) { @@ -305,14 +304,6 @@ return call(CALL, args); } - private static Operation named(final Object name, final Operation... ops) { - return new NamedOperation(ops(ops), name); - } - - private static Operation ops(final Operation... ops) { - return ops.length == 1 ? ops[0] : new CompositeOperation(ops); - } - private static MethodType t(final int argCount) { return MethodType.methodType(Object.class, Collections.nCopies(argCount, Object.class)); } diff -r f71b844f33d1 -r 95af45781076 nashorn/test/src/jdk/dynalink/support/test/CallSiteTest.java --- a/nashorn/test/src/jdk/dynalink/support/test/CallSiteTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/test/src/jdk/dynalink/support/test/CallSiteTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -25,6 +25,9 @@ package jdk.dynalink.support.test; +import static jdk.dynalink.StandardNamespace.PROPERTY; +import static jdk.dynalink.StandardOperation.GET; + import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -33,14 +36,15 @@ import jdk.dynalink.CallSiteDescriptor; import jdk.dynalink.DynamicLinker; import jdk.dynalink.DynamicLinkerFactory; -import jdk.dynalink.NamedOperation; -import jdk.dynalink.StandardOperation; +import jdk.dynalink.Operation; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.support.SimpleRelinkableCallSite; import org.testng.Assert; import org.testng.annotations.Test; public class CallSiteTest { + private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY); + @Test public void testInitialize() { final DynamicLinkerFactory factory = new DynamicLinkerFactory(); @@ -48,7 +52,7 @@ final MethodType mt = MethodType.methodType(Object.class, Object.class); final boolean[] initializeCalled = { Boolean.FALSE }; linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor( - MethodHandles.publicLookup(), new NamedOperation(StandardOperation.GET_PROPERTY, "DO_NOT_CARE"), mt)) { + MethodHandles.publicLookup(), GET_PROPERTY.named("DO_NOT_CARE"), mt)) { @Override public void initialize(final MethodHandle relinkAndInvoke) { initializeCalled[0] = Boolean.TRUE; @@ -66,7 +70,7 @@ final MethodType mt = MethodType.methodType(Object.class, Object.class); final boolean[] relinkCalled = { Boolean.FALSE }; final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor( - MethodHandles.publicLookup(), new NamedOperation(StandardOperation.GET_PROPERTY, "class"), mt)) { + MethodHandles.publicLookup(), GET_PROPERTY.named("class"), mt)) { @Override public void relink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) { relinkCalled[0] = Boolean.TRUE; @@ -90,7 +94,7 @@ final MethodType mt = MethodType.methodType(Object.class, Object.class); final boolean[] resetAndRelinkCalled = { Boolean.FALSE }; final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor( - MethodHandles.publicLookup(), new NamedOperation(StandardOperation.GET_PROPERTY, "length"), mt)) { + MethodHandles.publicLookup(), GET_PROPERTY.named("length"), mt)) { @Override public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) { resetAndRelinkCalled[0] = Boolean.TRUE; diff -r f71b844f33d1 -r 95af45781076 nashorn/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java --- a/nashorn/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -24,6 +24,9 @@ */ package jdk.dynalink.test; +import static jdk.dynalink.StandardNamespace.PROPERTY; +import static jdk.dynalink.StandardOperation.GET; + import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -35,9 +38,9 @@ import jdk.dynalink.CallSiteDescriptor; import jdk.dynalink.DynamicLinker; import jdk.dynalink.DynamicLinkerFactory; -import jdk.dynalink.NamedOperation; import jdk.dynalink.NoSuchDynamicMethodException; import jdk.dynalink.Operation; +import jdk.dynalink.StandardNamespace; import jdk.dynalink.StandardOperation; import jdk.dynalink.beans.StaticClass; import jdk.dynalink.linker.GuardedInvocation; @@ -52,6 +55,8 @@ @SuppressWarnings("javadoc") public class DynamicLinkerFactoryTest { + private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY); + private static DynamicLinkerFactory newDynamicLinkerFactory(final boolean resetClassLoader) { final DynamicLinkerFactory factory = new DynamicLinkerFactory(); if (resetClassLoader) { @@ -190,7 +195,7 @@ final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class); final DynamicLinker linker = factory.createLinker(); final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor( - MethodHandles.publicLookup(), StandardOperation.GET_PROPERTY, mt))); + MethodHandles.publicLookup(), GET_PROPERTY, mt))); Assert.assertFalse(reachedPrelinkTransformer[0]); Assert.assertEquals(cs.getTarget().invoke(new Object(), "class"), Object.class); Assert.assertTrue(reachedPrelinkTransformer[0]); @@ -209,7 +214,7 @@ final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class); final DynamicLinker linker = factory.createLinker(); final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor( - MethodHandles.publicLookup(), StandardOperation.GET_PROPERTY, mt))); + MethodHandles.publicLookup(), GET_PROPERTY, mt))); Assert.assertFalse(reachedInternalObjectsFilter[0]); Assert.assertEquals(cs.getTarget().invoke(new Object(), "class"), Object.class); Assert.assertTrue(reachedInternalObjectsFilter[0]); @@ -252,7 +257,7 @@ final MethodType mt = MethodType.methodType(Object.class, Object.class); final CallSiteDescriptor testDescriptor = new CallSiteDescriptor(MethodHandles.publicLookup(), - new NamedOperation(StandardOperation.GET_METHOD, methodName), mt); + GET.withNamespace(StandardNamespace.METHOD).named(methodName), mt); final CallSite cs = linker.link(new SimpleRelinkableCallSite(testDescriptor)); TrustedGuardingDynamicLinkerExporter.enable(); @@ -274,7 +279,7 @@ final DynamicLinker linker = factory.createLinker(); final MethodType mt = MethodType.methodType(Object.class, Object.class); - final NamedOperation op = new NamedOperation(StandardOperation.GET_PROPERTY, "foo"); + final Operation op = GET_PROPERTY.named("foo"); final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor( MethodHandles.publicLookup(), op, mt))); final boolean[] reachedGetMember = new boolean[1]; @@ -306,7 +311,7 @@ // check that the nashorn exported linker can be used for ScriptObjectMirror final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); final MethodType mt = MethodType.methodType(Object.class, Object.class); - final NamedOperation op = new NamedOperation(StandardOperation.GET_PROPERTY, "foo"); + final Operation op = GET_PROPERTY.named("foo"); final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor( MethodHandles.publicLookup(), op, mt))); Object value = null; diff -r f71b844f33d1 -r 95af45781076 nashorn/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java --- a/nashorn/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -24,20 +24,21 @@ */ package jdk.dynalink.test; -import static jdk.dynalink.StandardOperation.CALL_METHOD; - import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import jdk.dynalink.CallSiteDescriptor; import jdk.dynalink.DynamicLinker; import jdk.dynalink.DynamicLinkerFactory; -import jdk.dynalink.NamedOperation; +import jdk.dynalink.Operation; +import jdk.dynalink.StandardNamespace; +import jdk.dynalink.StandardOperation; import jdk.dynalink.linker.GuardingDynamicLinker; import jdk.dynalink.support.SimpleRelinkableCallSite; import org.testng.Assert; import org.testng.annotations.Test; public class LinkedCallSiteLocationTest { + private static final Operation GET_METHOD = StandardOperation.GET.withNamespace(StandardNamespace.METHOD); @Test public void testLinkedCallSiteLocation() throws Throwable { final StackTraceElement[] lastLinked = new StackTraceElement[1]; @@ -51,7 +52,7 @@ final SimpleRelinkableCallSite callSite = new SimpleRelinkableCallSite( new CallSiteDescriptor( MethodHandles.lookup(), - new NamedOperation(CALL_METHOD, "foo"), + GET_METHOD.named("foo"), MethodType.methodType(void.class, Object.class))); linker.link(callSite); diff -r f71b844f33d1 -r 95af45781076 nashorn/test/src/jdk/dynalink/test/TrustedUnderscoreNameLinkerExporter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/src/jdk/dynalink/test/TrustedUnderscoreNameLinkerExporter.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.dynalink.test; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import jdk.dynalink.CallSiteDescriptor; +import jdk.dynalink.NamedOperation; +import jdk.dynalink.NamespaceOperation; +import jdk.dynalink.Operation; +import jdk.dynalink.StandardNamespace; +import jdk.dynalink.StandardOperation; +import jdk.dynalink.linker.GuardedInvocation; +import jdk.dynalink.linker.GuardingDynamicLinker; +import jdk.dynalink.linker.GuardingDynamicLinkerExporter; +import jdk.dynalink.linker.LinkRequest; +import jdk.dynalink.linker.LinkerServices; +import jdk.dynalink.linker.support.SimpleLinkRequest; + +/** + * This is a dynalink pluggable linker (see http://openjdk.java.net/jeps/276). + * This linker translater underscore_separated method names to CamelCase names + * used in Java APIs. + */ +public final class TrustedUnderscoreNameLinkerExporter extends GuardingDynamicLinkerExporter { + private static final Pattern UNDERSCORE_NAME = Pattern.compile("_(.)"); + + // translate underscore_separated name as a CamelCase name + private static String translateToCamelCase(final String name) { + final Matcher m = UNDERSCORE_NAME.matcher(name); + final StringBuilder buf = new StringBuilder(); + while (m.find()) { + m.appendReplacement(buf, m.group(1).toUpperCase()); + } + m.appendTail(buf); + return buf.toString(); + } + + @Override + public List get() { + final ArrayList linkers = new ArrayList<>(); + linkers.add(new GuardingDynamicLinker() { + @Override + public GuardedInvocation getGuardedInvocation(final LinkRequest request, + final LinkerServices linkerServices) throws Exception { + final CallSiteDescriptor desc = request.getCallSiteDescriptor(); + final Operation op = desc.getOperation(); + final Object name = NamedOperation.getName(op); + final Operation namespaceOp = NamedOperation.getBaseOperation(op); + // is this a named GET_METHOD? + final boolean isGetMethod = + NamespaceOperation.getBaseOperation(namespaceOp) == StandardOperation.GET + && StandardNamespace.findFirst(namespaceOp) == StandardNamespace.METHOD; + if (isGetMethod && name instanceof String) { + final String str = (String)name; + if (str.indexOf('_') == -1) { + return null; + } + + final String nameStr = translateToCamelCase(str); + // create a new call descriptor to use translated name + final CallSiteDescriptor newDesc = AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public CallSiteDescriptor run() { + return desc.changeOperation(((NamedOperation)op).changeName(nameStr)); + } + }); + // create a new Link request to link the call site with translated name + final LinkRequest newRequest = request.replaceArguments(newDesc, request.getArguments()); + // return guarded invocation linking the translated request + return linkerServices.getGuardedInvocation(newRequest); + } + + return null; + } + }); + return linkers; + } +} diff -r f71b844f33d1 -r 95af45781076 nashorn/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java --- a/nashorn/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java Mon Nov 14 11:15:43 2016 +0100 +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java Fri Nov 11 16:44:36 2016 +0100 @@ -104,11 +104,11 @@ @Test public void testVarArgs() throws ScriptException { // Sole NativeArray in vararg position becomes vararg array itself - runTest("assertVarArg_42_17", "[42, 17]"); + runTest("assertVarArgWith42And17", "[42, 17]"); // NativeArray in vararg position becomes an argument if there are more arguments - runTest("assertVarArg_array_17", "[42], 18"); + runTest("assertVarArgArray7", "[42], 18"); // Only NativeArray is converted to vararg array, other objects (e.g. a function) aren't - runTest("assertVarArg_function", "function() { return 'Hello' }"); + runTest("assertVarArgFunction", "function() { return 'Hello' }"); } private static void runTest(final String testMethodName, final String argument) throws ScriptException { @@ -209,20 +209,20 @@ assertEquals(Arrays.asList("apple", "orange"), array[1]); } - public static void assertVarArg_42_17(final Object... args) { + public static void assertVarArgWith42And17(final Object... args) { assertEquals(2, args.length); assertEquals(42, ((Number)args[0]).intValue()); assertEquals(17, ((Number)args[1]).intValue()); } - public static void assertVarArg_array_17(final Object... args) throws ScriptException { + public static void assertVarArgArray7(final Object... args) throws ScriptException { assertEquals(2, args.length); e.getBindings(ScriptContext.ENGINE_SCOPE).put("arr", args[0]); assertTrue((Boolean)e.eval("arr instanceof Array && arr.length == 1 && arr[0] == 42")); assertEquals(18, ((Number)args[1]).intValue()); } - public static void assertVarArg_function(final Object... args) throws ScriptException { + public static void assertVarArgFunction(final Object... args) throws ScriptException { assertEquals(1, args.length); e.getBindings(ScriptContext.ENGINE_SCOPE).put("fn", args[0]); assertEquals("Hello", e.eval("fn()")); diff -r f71b844f33d1 -r 95af45781076 nashorn/test/src/jdk/nashorn/api/scripting/test/JDK_8169050_Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/src/jdk/nashorn/api/scripting/test/JDK_8169050_Test.java Fri Nov 11 16:44:36 2016 +0100 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.nashorn.api.scripting.test; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * @bug 8169050 + * @summary underscore_linker.js sample fails after dynalink changes for JDK-8168005 + */ +public class JDK_8169050_Test { + private ScriptEngine engine; + + @BeforeClass + public void setupTest() { + engine = new ScriptEngineManager().getEngineByName("js"); + } + + @Test + public void testUndersoreName() throws ScriptException { + engine.eval("var S = java.util.stream.Stream, v = 0;"); + // The underscore name 'for_each' exercises pluggable dynalink linker + engine.eval("S.of(4, 5, 9).for_each(function(x) { v += x })"); + assertEquals(18, ((Number)engine.get("v")).intValue()); + } +} diff -r f71b844f33d1 -r 95af45781076 test/Makefile --- a/test/Makefile Mon Nov 14 11:15:43 2016 +0100 +++ b/test/Makefile Fri Nov 11 16:44:36 2016 +0100 @@ -74,13 +74,14 @@ jaxp_%: @$(NO_STOPPING)$(call SUBDIR_TEST, $(JAXP_DIR), CONCURRENCY=$(JDK_TEST_JOBS) TEST="$@" $@) -ifeq ($(TEST_JOBS), 0) - HOTSPOT_TEST_JOBS=1 -else - HOTSPOT_TEST_JOBS=$(TEST_JOBS) +SUB_MAKE_ARGS := +ifneq ($(TEST_JOBS), 0) + ifneq ($(TEST_JOBS), ) + SUB_MAKE_ARGS += CONCURRENCY=$(TEST_JOBS) + endif endif hotspot_%: - @$(NO_STOPPING)$(call SUBDIR_TEST, $(HOTSPOT_DIR), CONCURRENCY=$(HOTSPOT_TEST_JOBS) TEST="$@" $@) + @$(NO_STOPPING)$(call SUBDIR_TEST, $(HOTSPOT_DIR), $(SUB_MAKE_ARGS) TEST="$@" $@) # # jtreg_tests diff -r f71b844f33d1 -r 95af45781076 test/make/TestJavaCompilation.gmk --- a/test/make/TestJavaCompilation.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/test/make/TestJavaCompilation.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -202,9 +202,9 @@ DEPENDENCIES := $(OUTPUT_DIR)/_jar3_created, \ SRCS := $(JAR3_SRC_ROOT1) $(JAR3_SRC_ROOT2), \ EXTRA_FILES := extra-file \ - dir2/file$$$$foo.dollar \ + dir2/file$$foo.dollar \ $(JAR3_SRC_ROOT2)/extra-file-abs, \ - EXCLUDE_FILES := dir1/file1$$$$foo.class, \ + EXCLUDE_FILES := dir1/file1$$foo.class, \ JAR := $(JAR3_FILE), \ )) diff -r f71b844f33d1 -r 95af45781076 test/make/TestMakeBase.gmk --- a/test/make/TestMakeBase.gmk Mon Nov 14 11:15:43 2016 +0100 +++ b/test/make/TestMakeBase.gmk Fri Nov 11 16:44:36 2016 +0100 @@ -209,9 +209,9 @@ test ! -e $(VARDEP_FLAG_FILE) # # Test including some problematic characters - $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR='value4 \$$$$ORIGIN' $(VARDEP_TARGET_FILE) + $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR='value4 \$$ORIGIN' $(VARDEP_TARGET_FILE) $(RM) $(VARDEP_FLAG_FILE) - $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR='value4 \$$$$ORIGIN' $(VARDEP_TARGET_FILE) + $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR='value4 \$$ORIGIN' $(VARDEP_TARGET_FILE) test ! -e $(VARDEP_FLAG_FILE) # Test specifying a specific value file to store variable in