diff --git a/.hgtags b/.hgtags index 1ee273ac14c..f54925473b1 100644 --- a/.hgtags +++ b/.hgtags @@ -384,3 +384,5 @@ d273dfe9a126d3bffe92072547fef2cd1361b0eb jdk-9+138 65477538bec32963dc41153d89c4417eb46c45fc jdk-9+139 0875007901f7d364a08220b052f0c81003e9c8c5 jdk-9+140 9aadd2163b568d76f8969ad2fb404a63733da359 jdk-9+141 +df0e03e3ca0ed1307793017dfc1a054c8726131c jdk-9+142 +d62173b931bf5b6bffc6e80a9060bb2e8b8efc75 jdk-9+143 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index c325445921e..846b6a11335 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -384,3 +384,5 @@ d7f519b004254b19e384131d9f0d0e40e31a0fd3 jdk-9+137 7dcf453eacae79ee86a6bcc75fd0b546fc99b48a jdk-9+139 a5815c6098a241d3a1df64d22b84b3524e4a77df jdk-9+140 f64afae7f1a5608e438585bbf0bc23785e69cba0 jdk-9+141 +2b3e5caafe3594ea507c37675c4d3086f415dc64 jdk-9+142 +1fc62b1c629fb80fdaa639d3b59452a184f0d705 jdk-9+143 diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 index d6a4ef04152..eb912119e70 100644 --- a/common/autoconf/flags.m4 +++ b/common/autoconf/flags.m4 @@ -280,7 +280,7 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS], 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 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS], # 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 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS], 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 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER], # 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 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER], # 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 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER], # 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 --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 49acd1801d7..131556f50ad 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -5093,7 +5093,7 @@ VS_SDK_PLATFORM_NAME_2013= #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 @@ $as_echo "$ac_cv_c_bigendian" >&6; } 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 @@ $as_echo "$ac_cv_c_bigendian" >&6; } # 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 @@ $as_echo "$ac_cv_c_bigendian" >&6; } 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 @@ $as_echo "$supports" >&6; } # 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 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA # 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 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA # 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 @@ $as_echo "$supports" >&6; } # 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 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA # 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 @@ $as_echo "$as_me: GCC >= 6 detected; adding ${NO_DELETE_NULL_POINTER_CHECKS_CFLA # 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 --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 7725e6fe84c..e2d7be936f6 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -265,6 +265,10 @@ IMAGES_OUTPUTDIR=$(BUILD_OUTPUT)/images 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_SUBDIR:=symbols 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 --git a/corba/.hgtags b/corba/.hgtags index 49efbd70a16..c96fdd40202 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -384,3 +384,5 @@ aa053a3faf266c12b4fd5272da431a3e08e4a3e3 jdk-9+136 8c9da7fc5b07c606afd571c7012441b77dda83b2 jdk-9+139 9f3fc931bc230f44f2a58d75f7f6360af98bb113 jdk-9+140 b32f998da32b488ec7c4e9dbb3c750841b48e74d jdk-9+141 +408c9c621938ca028e20bced0459f815de47eba8 jdk-9+142 +6211236ef15ec796806357608b1dd1b70c258ece jdk-9+143 diff --git a/hotspot/.hgtags b/hotspot/.hgtags index c8f06620fdc..4ff5566b655 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -544,3 +544,5 @@ fc0956308c7a586267c5dd35dff74f773aa9c3eb jdk-9+138 08492e67bf3226784dab3bf9ae967382ddbc1af5 jdk-9+139 fec31089c2ef5a12dd64f401b0bf2e00f56ee0d0 jdk-9+140 160a00bc6ed0af1fdf8418fc65e6bddbbc0c536d jdk-9+141 +7b48d63dfd6b8e2657288de3d7b1f153dee02d7e jdk-9+142 +d87d5d430c42342f0320ca7f5cbe0cbd1f9d62ba jdk-9+143 diff --git a/hotspot/make/gensrc/GensrcJvmti.gmk b/hotspot/make/gensrc/GensrcJvmti.gmk index 323c7e93da8..b834eae5673 100644 --- a/hotspot/make/gensrc/GensrcJvmti.gmk +++ b/hotspot/make/gensrc/GensrcJvmti.gmk @@ -135,14 +135,14 @@ TARGETS += $(JVMTI_OUTPUTDIR)/jvmtiEnvRecommended.cpp # 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 --git a/hotspot/make/symbols/symbols-unix b/hotspot/make/symbols/symbols-unix index 04dd4aeff53..cee0c5f71a8 100644 --- a/hotspot/make/symbols/symbols-unix +++ b/hotspot/make/symbols/symbols-unix @@ -125,7 +125,6 @@ JVM_GetPrimitiveArrayElement JVM_GetProtectionDomain JVM_GetSimpleBinaryName JVM_GetStackAccessControlContext -JVM_GetStackTraceElements JVM_GetSystemPackage JVM_GetSystemPackages JVM_GetTemporaryDirectory @@ -135,6 +134,8 @@ JVM_HasReferencePendingList JVM_HoldsLock JVM_IHashCode JVM_InitProperties +JVM_InitStackTraceElement +JVM_InitStackTraceElementArray JVM_InternString JVM_Interrupt JVM_InvokeMethod @@ -178,7 +179,6 @@ JVM_StartThread JVM_StopThread JVM_SupportsCX8 JVM_SuspendThread -JVM_ToStackTraceElement JVM_TotalMemory JVM_UnloadLibrary JVM_WaitForReferencePendingList diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index df8cfd821de..3da3b09f96d 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -2175,6 +2175,14 @@ void java_lang_StackTraceElement::fill_in(Handle element, 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 @@ oop java_security_AccessControlContext::create(objArrayHandle context, bool isPr 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 @@ void java_lang_ClassLoader::compute_offsets() { 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 @@ oop java_lang_ClassLoader::parent(oop loader) { 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_in_offset; 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 @@ void java_lang_StackTraceElement::set_moduleVersion(oop element, oop value) { 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 @@ void JavaClasses::compute_hard_coded_offsets() { 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 @@ void JavaClasses::check_offsets() { // 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 --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 448bb4d5bd8..d4cba683a9a 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -1225,6 +1225,7 @@ class java_lang_ClassLoader : AllStatic { 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 @@ class java_lang_ClassLoader : AllStatic { 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_System : AllStatic { 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 @@ class java_lang_StackTraceElement: AllStatic { 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 --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index f4816e63230..51bc575cf99 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -503,16 +503,27 @@ JVM_ENTRY(void, JVM_FillInStackTrace(JNIEnv *env, jobject receiver)) 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 @@ JVM_ENTRY(jint, JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, 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 --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index 5c7aefb7c0a..47bf5a0d023 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -189,8 +189,14 @@ JVM_GetVmArguments(JNIEnv *env); 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 @@ JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jlong anchor, jint frame_count, jint start_index, jobjectArray frames); -JNIEXPORT void JNICALL -JVM_ToStackTraceElement(JNIEnv* env, jobject frame, jobject stackElement); - /* * java.lang.Thread */ diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 2f1dbc70599..addee1762c9 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -384,3 +384,5 @@ a8d5fe567ae72b4931040e59dd4478363f9004f5 jdk-9+137 8991d71c5316bde259e6a417c1199b008ca3cdf0 jdk-9+139 8d100cb9b04819b5bd09f33c7fd5b8628d1a456f jdk-9+140 037c095ba0c345edbeaaab52fda913a76c3930c0 jdk-9+141 +bdafa0cc34a97a2f8db4847a4efd34b407943591 jdk-9+142 +ce81d03ad7320dca3d673374c1a33bc0efd9136a jdk-9+143 diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java index 8dde37676bc..7189b1ba7a9 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java @@ -746,42 +746,18 @@ public class XMLDocumentScannerImpl // 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 ; - } - // standard XML declaration - else { + if (fEntityScanner.peekChar() == ' ') { + fMarkupDepth++; scanXMLDeclOrTextDecl(false); - //REVISIT:where else we can set this value to 'true' - fEntityManager.fCurrentEntity.mayReadChunks = true; - return XMLEvent.START_DOCUMENT; + } else { + // PI, reset position + fEntityManager.fCurrentEntity.position = 0; } - } 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 --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java index 3788fad0227..30050ba2377 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java @@ -46,7 +46,10 @@ import java.util.Iterator; */ 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 @@ public interface XMLEventReader extends Iterator { * 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 @@ public interface XMLEventReader extends Iterator { * 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 @@ public interface XMLEventReader extends Iterator { * 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 --git a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java index e92e979ed08..102228bc716 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java @@ -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 @@ import javax.xml.namespace.QName; * 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 @@ import javax.xml.namespace.QName; * 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 interface XMLStreamReader extends XMLStreamConstants { // 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 @@ public interface XMLStreamReader extends XMLStreamConstants { /** * 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 @@ public interface XMLStreamReader extends XMLStreamConstants { /** * 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 interface XMLStreamReader extends XMLStreamConstants { 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 @@ public interface XMLStreamReader extends XMLStreamConstants { * 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 interface XMLStreamReader extends XMLStreamConstants { 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 --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/parsers/ptests/SAXParserTest.java b/jaxp/test/javax/xml/jaxp/functional/javax/xml/parsers/ptests/SAXParserTest.java index ed702b24ec9..7a18ddba527 100644 --- a/jaxp/test/javax/xml/jaxp/functional/javax/xml/parsers/ptests/SAXParserTest.java +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/parsers/ptests/SAXParserTest.java @@ -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 @@ public class SAXParserTest { */ @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 --git a/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogInvalidPathTest.java b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogInvalidPathTest.java new file mode 100644 index 00000000000..e8da1d0c3f4 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogInvalidPathTest.java @@ -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 --git a/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java index 4b9ea77826d..478dda72b79 100644 --- a/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java @@ -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.transform.stream.StreamSource; 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 @@ import org.xml.sax.ext.DefaultHandler2; /* * @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 @@ public class CatalogTest extends CatalogSupportBase { 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 @@ public class CatalogTest extends CatalogSupportBase { }; } - /* - 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 --git a/jaxp/test/javax/xml/jaxp/unittest/stream/XMLStreamReaderTest/BugTest.java b/jaxp/test/javax/xml/jaxp/unittest/stream/XMLStreamReaderTest/BugTest.java index ca30f426d68..508b52e41dd 100644 --- a/jaxp/test/javax/xml/jaxp/unittest/stream/XMLStreamReaderTest/BugTest.java +++ b/jaxp/test/javax/xml/jaxp/unittest/stream/XMLStreamReaderTest/BugTest.java @@ -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 @@ import org.testng.annotations.Test; @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 --git a/jaxws/.hgtags b/jaxws/.hgtags index e0585de8154..790219ed5e4 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -387,3 +387,5 @@ ab1d78d395d4cb8be426ff181211da1a4085cf01 jdk-9+134 7a7aadf3c4500cc273c889aa1172d4fe3844bb6b jdk-9+139 9004617323fe99cbe4fad48f373cb2ed4fc50aa6 jdk-9+140 b2c18f755228d1d19a86cd7d5fa1abb6b1495dfb jdk-9+141 +59101416d90160cfcb4f45dfbccaec15e2c27a29 jdk-9+142 +1c988e708a06257119d54d8a57e99e3b0f37ff18 jdk-9+143 diff --git a/jdk/.hgtags b/jdk/.hgtags index b1bdee32f0f..508a3a48852 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -384,3 +384,5 @@ e72df94364e3686e7d62059ce0d6b187b82da713 jdk-9+137 5518ac2f2ead5e594bd983f2047178136aafdfd0 jdk-9+139 e93b7ea559759f036c9f69fd2ddaf47bb4e98385 jdk-9+140 8d752af5f61d41f226adf2cda72a20faa9ad620a jdk-9+141 +6ce43dd8e954b452f330dd7a412df5107f7e1923 jdk-9+142 +8dbc8594f9d5149bf1c22221272284609408227a jdk-9+143 diff --git a/jdk/make/copy/Copy-java.base.gmk b/jdk/make/copy/Copy-java.base.gmk index c023e8cfbed..f736866e208 100644 --- a/jdk/make/copy/Copy-java.base.gmk +++ b/jdk/make/copy/Copy-java.base.gmk @@ -33,7 +33,6 @@ $(eval $(call IncludeCustomExtension, jdk, copy/Copy-java.base.gmk)) # 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 --git a/jdk/make/data/tzdata/VERSION b/jdk/make/data/tzdata/VERSION index f587cb7fca7..7009f248679 100644 --- a/jdk/make/data/tzdata/VERSION +++ b/jdk/make/data/tzdata/VERSION @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2016g +tzdata2016h diff --git a/jdk/make/data/tzdata/asia b/jdk/make/data/tzdata/asia index 65e5f944b0e..71711a946d1 100644 --- a/jdk/make/data/tzdata/asia +++ b/jdk/make/data/tzdata/asia @@ -2567,11 +2567,6 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # 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 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # # 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 2011 only - Sep 30 0:00 0 - 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 @@ Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1 # 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. +# 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. # -# 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. -# -# 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 --git a/jdk/make/data/tzdata/australasia b/jdk/make/data/tzdata/australasia index 20a40206431..23153b171fa 100644 --- a/jdk/make/data/tzdata/australasia +++ b/jdk/make/data/tzdata/australasia @@ -373,7 +373,13 @@ Zone Indian/Cocos 6:27:40 - LMT 1900 # 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 --git a/jdk/make/data/tzdata/europe b/jdk/make/data/tzdata/europe index aededb1d253..d182dbb6ba8 100644 --- a/jdk/make/data/tzdata/europe +++ b/jdk/make/data/tzdata/europe @@ -1931,7 +1931,7 @@ Zone Europe/Monaco 0:29:32 - LMT 1891 Mar 15 # 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 @@ Zone Europe/Zurich 0:34:08 - LMT 1853 Jul 16 # See above comment. # 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 - Jul 31 0:00 1:00 S 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 --git a/jdk/make/data/tzdata/northamerica b/jdk/make/data/tzdata/northamerica index 8ab635d089c..56b089c8fc5 100644 --- a/jdk/make/data/tzdata/northamerica +++ b/jdk/make/data/tzdata/northamerica @@ -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 --git a/jdk/make/gendata/GendataBreakIterator.gmk b/jdk/make/gendata/GendataBreakIterator.gmk index 828e6314790..39a5dfb5efc 100644 --- a/jdk/make/gendata/GendataBreakIterator.gmk +++ b/jdk/make/gendata/GendataBreakIterator.gmk @@ -55,7 +55,6 @@ $(eval $(call SetupJavaCompilation,BUILD_BREAKITERATOR_BASE, \ $(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 --git a/jdk/make/mapfiles/libjava/mapfile-vers b/jdk/make/mapfiles/libjava/mapfile-vers index 20ea7c916b8..f0e3f2bb076 100644 --- a/jdk/make/mapfiles/libjava/mapfile-vers +++ b/jdk/make/mapfiles/libjava/mapfile-vers @@ -140,7 +140,6 @@ SUNWprivate_1.1 { 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 @@ SUNWprivate_1.1 { 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 @@ SUNWprivate_1.1 { 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 --git a/jdk/make/mapfiles/libjava/reorder-sparc b/jdk/make/mapfiles/libjava/reorder-sparc index 6544e40393c..6743ccedfaa 100644 --- a/jdk/make/mapfiles/libjava/reorder-sparc +++ b/jdk/make/mapfiles/libjava/reorder-sparc @@ -78,7 +78,7 @@ text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_Pri 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 --git a/jdk/make/mapfiles/libjava/reorder-sparcv9 b/jdk/make/mapfiles/libjava/reorder-sparcv9 index 71e44cf938c..877d2d79b5e 100644 --- a/jdk/make/mapfiles/libjava/reorder-sparcv9 +++ b/jdk/make/mapfiles/libjava/reorder-sparcv9 @@ -74,7 +74,7 @@ text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_Pri 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 --git a/jdk/make/mapfiles/libjava/reorder-x86 b/jdk/make/mapfiles/libjava/reorder-x86 index 5031cd133af..d0407001e62 100644 --- a/jdk/make/mapfiles/libjava/reorder-x86 +++ b/jdk/make/mapfiles/libjava/reorder-x86 @@ -78,7 +78,7 @@ text: .text%Java_java_io_UnixFileSystem_checkAccess; 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 --git a/jdk/make/mapfiles/libsplashscreen/mapfile-vers b/jdk/make/mapfiles/libsplashscreen/mapfile-vers index b948ef474a6..088cb4d2896 100644 --- a/jdk/make/mapfiles/libsplashscreen/mapfile-vers +++ b/jdk/make/mapfiles/libsplashscreen/mapfile-vers @@ -44,6 +44,7 @@ SUNWprivate_1.1 { SplashSetFileJarName; SplashSetScaleFactor; SplashGetScaledImageName; + SplashGetScaledImgNameMaxPstfixLen; local: *; }; diff --git a/jdk/make/rmic/Rmic-java.rmi.gmk b/jdk/make/rmic/Rmic-java.rmi.gmk index 44eb8f3de74..c9b024e4f30 100644 --- a/jdk/make/rmic/Rmic-java.rmi.gmk +++ b/jdk/make/rmic/Rmic-java.rmi.gmk @@ -33,7 +33,7 @@ include RmicCommon.gmk # $(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 --git a/jdk/src/java.base/share/classes/java/io/File.java b/jdk/src/java.base/share/classes/java/io/File.java index 41eff3eb92d..0e966659ee0 100644 --- a/jdk/src/java.base/share/classes/java/io/File.java +++ b/jdk/src/java.base/share/classes/java/io/File.java @@ -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 @@ public class File 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 --git a/jdk/src/java.base/share/classes/java/io/FileInputStream.java b/jdk/src/java.base/share/classes/java/io/FileInputStream.java index cc77e5bd7c4..713b2ad0e95 100644 --- a/jdk/src/java.base/share/classes/java/io/FileInputStream.java +++ b/jdk/src/java.base/share/classes/java/io/FileInputStream.java @@ -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 @@ class FileInputStream extends InputStream 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 @@ class FileInputStream extends InputStream * @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 @@ class FileInputStream extends InputStream 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 --git a/jdk/src/java.base/share/classes/java/io/FileOutputStream.java b/jdk/src/java.base/share/classes/java/io/FileOutputStream.java index 52d1596b3c4..f6bdb1f3b5f 100644 --- a/jdk/src/java.base/share/classes/java/io/FileOutputStream.java +++ b/jdk/src/java.base/share/classes/java/io/FileOutputStream.java @@ -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 @@ class FileOutputStream extends OutputStream */ 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 @@ class FileOutputStream extends OutputStream * @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 @@ class FileOutputStream extends OutputStream 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 --git a/jdk/src/java.base/share/classes/java/io/FilePermission.java b/jdk/src/java.base/share/classes/java/io/FilePermission.java index f81018f3a79..0c5c0ac2e8b 100644 --- a/jdk/src/java.base/share/classes/java/io/FilePermission.java +++ b/jdk/src/java.base/share/classes/java/io/FilePermission.java @@ -173,6 +173,7 @@ public final class FilePermission extends Permission implements Serializable { 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 @@ public final class FilePermission extends Permission implements Serializable { * 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 @@ public final class FilePermission extends Permission implements Serializable { 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 @@ public final class FilePermission extends Permission implements Serializable { 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 @@ public final class FilePermission extends Permission implements Serializable { // 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 @@ public final class FilePermission extends Permission implements Serializable { */ 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 @@ public final class FilePermission extends Permission implements Serializable { 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 @@ public final class FilePermission extends Permission implements Serializable { @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 --git a/jdk/src/java.base/share/classes/java/lang/Class.java b/jdk/src/java.base/share/classes/java/lang/Class.java index 3e4d7492ffb..725d237aff6 100644 --- a/jdk/src/java.base/share/classes/java/lang/Class.java +++ b/jdk/src/java.base/share/classes/java/lang/Class.java @@ -485,7 +485,7 @@ public final class Class implements java.io.Serializable, * can be replaced by * *

{@code
-     * clazz.getConstructor().newInstance()
+     * clazz.getDeclaredConstructor().newInstance()
      * }
* * The latter sequence of calls is inferred to be able to throw diff --git a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java index a7c093c7034..73fe154586d 100644 --- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java @@ -104,9 +104,9 @@ import sun.security.util.SecurityConstants; * 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 @@ public abstract class ClassLoader { // 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 @@ public abstract class ClassLoader { } 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 @@ public abstract class ClassLoader { 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() @@ -355,6 +367,27 @@ public abstract class ClassLoader { } } + /** + * 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 @@ public abstract class ClassLoader { * @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 @@ public abstract class ClassLoader { * 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 @@ public abstract class ClassLoader { } /** - * 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 @@ public abstract class ClassLoader { *

    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 */ @@ -1460,6 +1520,22 @@ public abstract class ClassLoader { return ParallelLoaders.register(callerClass); } + /** + * 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 @@ -1610,6 +1686,9 @@ public abstract class ClassLoader { * 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 @@ public abstract class ClassLoader { * 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 --git a/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java b/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java index e731685dbb8..4f3cc1e980c 100644 --- a/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java +++ b/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java @@ -112,11 +112,6 @@ class StackFrameInfo implements StackFrame { 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 @@ class StackFrameInfo implements StackFrame { synchronized (this) { s = ste; if (s == null) { - s = new StackTraceElement(); - toStackTraceElement0(s); - ste = s; + ste = s = StackTraceElement.of(this); } } } diff --git a/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java b/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java index 3710678e4eb..04ba817a553 100644 --- a/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java +++ b/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java @@ -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 @@ import java.util.Objects; * @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 final class StackTraceElement implements java.io.Serializable { */ 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 @@ public final class StackTraceElement implements java.io.Serializable { * 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 @@ -177,6 +203,21 @@ public final class StackTraceElement implements java.io.Serializable { return moduleVersion; } + /** + * 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 @@ public final class StackTraceElement implements java.io.Serializable { * 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 @@ public final class StackTraceElement implements java.io.Serializable { * 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 @@ public final class StackTraceElement implements java.io.Serializable { 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 final class StackTraceElement implements java.io.Serializable { */ 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 @@ public final class StackTraceElement implements java.io.Serializable { 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 --git a/jdk/src/java.base/share/classes/java/lang/Throwable.java b/jdk/src/java.base/share/classes/java/lang/Throwable.java index a609719c9cd..1a56b7cdc0b 100644 --- a/jdk/src/java.base/share/classes/java/lang/Throwable.java +++ b/jdk/src/java.base/share/classes/java/lang/Throwable.java @@ -24,7 +24,6 @@ */ package java.lang; -import jdk.internal.misc.VM; import java.io.*; import java.util.*; @@ -826,11 +825,7 @@ public class Throwable implements Serializable { // 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; } @@ -881,13 +876,6 @@ public class Throwable implements Serializable { } } - /** - * 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 diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 104aa220932..e1fad4d7dbb 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -5347,7 +5347,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * {@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 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * 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 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); 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 --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java index e76c2f59200..60aeea6d85d 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java @@ -31,6 +31,7 @@ import java.io.PrintStream; 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 class ModuleDescriptor 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 --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java index 9dd5b54c8cc..4e72a52cf22 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java @@ -228,7 +228,7 @@ public interface ModuleFinder { * *

  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 @@ public interface ModuleFinder { *
  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 @@ public interface ModuleFinder { * {@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 @@ public interface ModuleFinder { * *

    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 @@ public interface ModuleFinder { * @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 --git a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java index cad2812ab64..fa40f3b7958 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java @@ -33,10 +33,12 @@ import java.io.InputStream; 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.jar.Manifest; 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 @@ class ModulePath implements ConfigurableModuleFinder { 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 @@ class ModulePath implements ConfigurableModuleFinder { } + /** + * 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 @@ class ModulePath implements ConfigurableModuleFinder { .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 @@ class ModulePath implements ConfigurableModuleFinder { 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 @@ class ModulePath implements ConfigurableModuleFinder { 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 @@ class ModulePath implements ConfigurableModuleFinder { 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 @@ class ModulePath implements ConfigurableModuleFinder { 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 @@ class ModulePath implements ConfigurableModuleFinder { 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 @@ class ModulePath implements ConfigurableModuleFinder { 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 @@ class ModulePath implements ConfigurableModuleFinder { 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("/"); - // + 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(); + } - // 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('/', '.'); + 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 --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java index 4d3d2bf15a0..d79d210edd0 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java @@ -32,6 +32,7 @@ import java.net.URI; import java.nio.ByteBuffer; import java.util.Objects; import java.util.Optional; +import java.util.stream.Stream; /** @@ -44,6 +45,11 @@ import java.util.Optional; * 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 @@ import java.util.Optional; * *

    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 @@ public interface ModuleReader extends Closeable { * 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 @@ -171,18 +180,38 @@ public interface ModuleReader extends Closeable { Objects.requireNonNull(bb); } + /** + * 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 --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java index de245656364..8393bd0f223 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java @@ -35,6 +35,7 @@ import java.nio.ByteBuffer; 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.concurrent.locks.ReentrantReadWriteLock; 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; @@ -139,6 +143,13 @@ class ModuleReferences { */ 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 @@ class ModuleReferences { } @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) { @@ -240,6 +265,16 @@ class ModuleReferences { } } + @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 @@ class ModuleReferences { * 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 @@ class ModuleReferences { @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(); } } @@ -377,6 +423,17 @@ class ModuleReferences { } } + @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 --git a/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java b/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java index 3e49c93f132..9fae75cb382 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java +++ b/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java @@ -32,14 +32,21 @@ import java.io.UncheckedIOException; 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 @@ import jdk.internal.perf.PerfCounter; 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 @@ class SystemModuleFinder implements ModuleFinder { // 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 @@ class SystemModuleFinder implements ModuleFinder { 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 @@ -331,6 +337,15 @@ class SystemModuleFinder implements ModuleFinder { ImageReader.releaseByteBuffer(bb); } + @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 @@ -338,4 +353,86 @@ class SystemModuleFinder implements ModuleFinder { } } + /** + * 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 --git a/jdk/src/java.base/share/classes/java/net/InetAddress.java b/jdk/src/java.base/share/classes/java/net/InetAddress.java index b008b35260a..84457f30066 100644 --- a/jdk/src/java.base/share/classes/java/net/InetAddress.java +++ b/jdk/src/java.base/share/classes/java/net/InetAddress.java @@ -201,13 +201,13 @@ class InetAddress implements java.io.Serializable { * 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 --git a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java index ebae81ceeb0..ef166dcdc23 100644 --- a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java +++ b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java @@ -110,19 +110,19 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { 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 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { if (security != null) { security.checkCreateClassLoader(); } - ucp = new URLClassPath(urls); + this.ucp = new URLClassPath(urls); this.acc = AccessController.getContext(); } @@ -165,7 +165,7 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { if (security != null) { security.checkCreateClassLoader(); } - ucp = new URLClassPath(urls); + this.ucp = new URLClassPath(urls); this.acc = acc; } @@ -198,8 +198,76 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { 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 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { 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 @@ final class FactoryURLClassLoader extends URLClassLoader { 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 --git a/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java b/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java index 03d431d80e1..2b46c5ccbbd 100644 --- a/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java +++ b/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java @@ -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 @@ class TempFileHelper { 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 --git a/jdk/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java b/jdk/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java index 1d3c24b7361..5b3c1237b06 100644 --- a/jdk/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java +++ b/jdk/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java @@ -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 @@ public class AlgorithmParameterGenerator { * 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 @@ public class AlgorithmParameterGenerator { * * @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 @@ public class AlgorithmParameterGenerator { 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 @@ public class AlgorithmParameterGenerator { * 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 * - * @exception NoSuchAlgorithmException if an AlgorithmParameterGeneratorSpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws IllegalArgumentException if the specified provider is + * {@code null} * - * @exception IllegalArgumentException if the specified provider is null. + * @throws NoSuchAlgorithmException if an + * {@code AlgorithmParameterGeneratorSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -259,6 +271,7 @@ public class AlgorithmParameterGenerator { Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(algorithm, "null algorithm name"); if (provider == null) throw new IllegalArgumentException("missing provider"); Object[] objs = Security.getImpl(algorithm, diff --git a/jdk/src/java.base/share/classes/java/security/AlgorithmParameters.java b/jdk/src/java.base/share/classes/java/security/AlgorithmParameters.java index be8a2c91abf..e03361233a5 100644 --- a/jdk/src/java.base/share/classes/java/security/AlgorithmParameters.java +++ b/jdk/src/java.base/share/classes/java/security/AlgorithmParameters.java @@ -28,6 +28,7 @@ package java.security; 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 @@ public class AlgorithmParameters { * 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 @@ public class AlgorithmParameters { * * @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 @@ public class AlgorithmParameters { 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 @@ public class AlgorithmParameters { * * @param provider the name of the provider. * - * @return the new parameter object. + * @return the new parameter object * - * @exception NoSuchAlgorithmException if an AlgorithmParameterGeneratorSpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws IllegalArgumentException if the provider is {@code null} * - * @exception IllegalArgumentException if the provider is null. + * @throws NoSuchAlgorithmException if an + * {@code AlgorithmParameterGeneratorSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -247,6 +257,7 @@ public class AlgorithmParameters { 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 --git a/jdk/src/java.base/share/classes/java/security/KeyFactory.java b/jdk/src/java.base/share/classes/java/security/KeyFactory.java index 5bbce1a3b74..4d297157ebc 100644 --- a/jdk/src/java.base/share/classes/java/security/KeyFactory.java +++ b/jdk/src/java.base/share/classes/java/security/KeyFactory.java @@ -167,16 +167,19 @@ public class KeyFactory { * 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 @@ public class KeyFactory { * * @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 @@ public class KeyFactory { * * @param provider 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 object. + * @throws IllegalArgumentException if the specified provider is + * {@code null} * - * @exception IllegalArgumentException if the specified provider is null. + * @throws NoSuchAlgorithmException if a {@code KeyFactorySpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -253,6 +262,7 @@ public class KeyFactory { */ 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 --git a/jdk/src/java.base/share/classes/java/security/KeyPairGenerator.java b/jdk/src/java.base/share/classes/java/security/KeyPairGenerator.java index 3a241787329..10d2f067f83 100644 --- a/jdk/src/java.base/share/classes/java/security/KeyPairGenerator.java +++ b/jdk/src/java.base/share/classes/java/security/KeyPairGenerator.java @@ -209,16 +209,19 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi { * 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 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi { * * @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 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi { * * @param provider 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 object. + * @throws IllegalArgumentException if the specified provider is + * {@code null} * - * @exception IllegalArgumentException if the specified provider is null. + * @throws NoSuchAlgorithmException if a {@code KeyPairGeneratorSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -320,6 +329,7 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi { */ 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 --git a/jdk/src/java.base/share/classes/java/security/KeyStore.java b/jdk/src/java.base/share/classes/java/security/KeyStore.java index 14da8cb9d4c..811422f73e5 100644 --- a/jdk/src/java.base/share/classes/java/security/KeyStore.java +++ b/jdk/src/java.base/share/classes/java/security/KeyStore.java @@ -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 @@ public class KeyStore { * 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 @@ public class KeyStore { * * @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 @@ public class KeyStore { * * @param provider the provider. * - * @return a keystore object of the specified type. + * @return a keystore object of the specified type * - * @exception KeyStoreException if KeyStoreSpi - * implementation for the specified type is not available - * from the specified Provider object. + * @throws IllegalArgumentException if the specified provider is + * {@code null} * - * @exception IllegalArgumentException if the specified provider is null. + * @throws KeyStoreException if {@code KeyStoreSpi} + * implementation for the specified type is not available + * from the specified {@code Provider} object + * + * @throws NullPointerException if {@code type} is {@code null} * * @see Provider * @@ -953,6 +961,7 @@ public class KeyStore { 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 --git a/jdk/src/java.base/share/classes/java/security/MessageDigest.java b/jdk/src/java.base/share/classes/java/security/MessageDigest.java index b6959f5db4f..dac789f1ab1 100644 --- a/jdk/src/java.base/share/classes/java/security/MessageDigest.java +++ b/jdk/src/java.base/share/classes/java/security/MessageDigest.java @@ -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 @@ public abstract class MessageDigest extends MessageDigestSpi { * 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 @@ public abstract class MessageDigest extends MessageDigestSpi { * * @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 @@ public abstract class MessageDigest extends MessageDigestSpi { * * @param provider 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 object. + * @throws IllegalArgumentException if the specified provider is + * {@code null} * - * @exception IllegalArgumentException if the specified provider is null. + * @throws NoSuchAlgorithmException if a {@code MessageDigestSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -281,6 +288,7 @@ public abstract class MessageDigest extends MessageDigestSpi { 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 --git a/jdk/src/java.base/share/classes/java/security/Policy.java b/jdk/src/java.base/share/classes/java/security/Policy.java index 33f766f3082..a0f22382a1c 100644 --- a/jdk/src/java.base/share/classes/java/security/Policy.java +++ b/jdk/src/java.base/share/classes/java/security/Policy.java @@ -29,6 +29,7 @@ package java.security; 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 @@ public abstract class Policy { * * @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. + * @throws IllegalArgumentException if the specified parameters + * are not understood by the {@code PolicySpi} implementation + * from the selected {@code Provider} * - * @exception NullPointerException if the specified type is null. + * @throws NoSuchAlgorithmException if no {@code Provider} supports + * a {@code PolicySpi} implementation for the specified type * - * @exception IllegalArgumentException if the specified parameters - * are not understood by the PolicySpi implementation - * from the selected Provider. + * @throws NullPointerException if {@code type} is {@code null} * - * @exception NoSuchAlgorithmException if no Provider supports a PolicySpi - * implementation for the specified type. + * @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 @@ public abstract class Policy { * * @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. + * @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 NullPointerException if the specified type is null. + * @throws NoSuchAlgorithmException if the specified provider does not + * support a {@code PolicySpi} implementation for the specified + * type * - * @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 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 NullPointerException if {@code type} is {@code null} * - * @exception NoSuchAlgorithmException if the specified provider does not - * support a PolicySpi implementation for the specified type. + * @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 @@ public abstract class Policy { 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 @@ public abstract class Policy { * * @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. + * @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 NullPointerException if the specified type is null. + * @throws NoSuchAlgorithmException if the specified {@code Provider} + * does not support a {@code PolicySpi} implementation for + * the specified type * - * @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 NullPointerException if {@code type} is {@code null} * - * @exception NoSuchAlgorithmException if the specified Provider does not - * support a PolicySpi implementation for the specified type. + * @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 @@ public abstract class Policy { Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(type, "null type name"); if (provider == null) { throw new IllegalArgumentException("missing provider"); } diff --git a/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java b/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java index 21b071f4061..8f84e10324e 100644 --- a/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java +++ b/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java @@ -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; @@ -113,6 +111,30 @@ public class SecureClassLoader extends ClassLoader { initialized = true; } + /** + * 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 diff --git a/jdk/src/java.base/share/classes/java/security/SecureRandom.java b/jdk/src/java.base/share/classes/java/security/SecureRandom.java index f8832f049ce..8449613ba66 100644 --- a/jdk/src/java.base/share/classes/java/security/SecureRandom.java +++ b/jdk/src/java.base/share/classes/java/security/SecureRandom.java @@ -303,11 +303,13 @@ public class SecureRandom extends java.util.Random { * 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 class SecureRandom extends java.util.Random { */ 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 @@ public class SecureRandom extends java.util.Random { * * @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 class SecureRandom extends java.util.Random { */ 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 @@ public class SecureRandom extends java.util.Random { * * @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 class SecureRandom extends java.util.Random { */ 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 @@ public class SecureRandom extends java.util.Random { * @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 class SecureRandom extends java.util.Random { 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 @@ public class SecureRandom extends java.util.Random { * * @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 class SecureRandom extends java.util.Random { 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 @@ public class SecureRandom extends java.util.Random { * * @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 class SecureRandom extends java.util.Random { 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 --git a/jdk/src/java.base/share/classes/java/security/Signature.java b/jdk/src/java.base/share/classes/java/security/Signature.java index 9bfe4667df6..df326f4a280 100644 --- a/jdk/src/java.base/share/classes/java/security/Signature.java +++ b/jdk/src/java.base/share/classes/java/security/Signature.java @@ -213,16 +213,19 @@ public abstract class Signature extends SignatureSpi { * 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 @@ public abstract class Signature extends SignatureSpi { * * @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 @@ public abstract class Signature extends SignatureSpi { * * @param provider 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 object. + * @throws IllegalArgumentException if the provider is {@code null} * - * @exception IllegalArgumentException if the provider is null. + * @throws NoSuchAlgorithmException if a {@code SignatureSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object + * + * @throws NullPointerException if {@code algorithm} is {@code null} * * @see Provider * @@ -399,6 +407,7 @@ public abstract class Signature extends SignatureSpi { */ 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 --git a/jdk/src/java.base/share/classes/java/security/cert/CertPathBuilder.java b/jdk/src/java.base/share/classes/java/security/cert/CertPathBuilder.java index b9100826c09..12f608816be 100644 --- a/jdk/src/java.base/share/classes/java/security/cert/CertPathBuilder.java +++ b/jdk/src/java.base/share/classes/java/security/cert/CertPathBuilder.java @@ -32,7 +32,7 @@ import java.security.NoSuchProviderException; 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 @@ public class CertPathBuilder { * 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 @@ public class CertPathBuilder { * @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 @@ public class CertPathBuilder { * @param provider the provider. * * @return a {@code CertPathBuilder} object that implements the - * specified algorithm. + * specified algorithm * - * @exception NoSuchAlgorithmException if a CertPathBuilderSpi - * implementation for the specified algorithm is not available - * from the specified Provider object. + * @throws IllegalArgumentException if the {@code provider} is + * {@code null} * - * @exception IllegalArgumentException if the {@code provider} is - * null. + * @throws NoSuchAlgorithmException if a {@code CertPathBuilderSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object + * + * @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 --git a/jdk/src/java.base/share/classes/java/security/cert/CertPathValidator.java b/jdk/src/java.base/share/classes/java/security/cert/CertPathValidator.java index be5bd77fd96..298923d84a2 100644 --- a/jdk/src/java.base/share/classes/java/security/cert/CertPathValidator.java +++ b/jdk/src/java.base/share/classes/java/security/cert/CertPathValidator.java @@ -32,7 +32,7 @@ import java.security.NoSuchProviderException; 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 @@ public class CertPathValidator { * 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 @@ public class CertPathValidator { * @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 @@ public class CertPathValidator { * @param provider 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 object. + * @throws IllegalArgumentException if the {@code provider} is + * {@code null} * - * @exception IllegalArgumentException if the {@code provider} is - * null. + * @throws NoSuchAlgorithmException if a {@code CertPathValidatorSpi} + * implementation for the specified algorithm is not available + * from the specified Provider object + * + * @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 --git a/jdk/src/java.base/share/classes/java/security/cert/CertStore.java b/jdk/src/java.base/share/classes/java/security/cert/CertStore.java index dcf7b922471..e62d39f27b0 100644 --- a/jdk/src/java.base/share/classes/java/security/cert/CertStore.java +++ b/jdk/src/java.base/share/classes/java/security/cert/CertStore.java @@ -33,6 +33,7 @@ import java.security.PrivilegedAction; 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 @@ public class CertStore { * @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 @@ public class CertStore { } 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 @@ public class CertStore { * @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 @@ public class CertStore { 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 @@ public class CertStore { * @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 --git a/jdk/src/java.base/share/classes/java/security/cert/CertificateFactory.java b/jdk/src/java.base/share/classes/java/security/cert/CertificateFactory.java index e2680e90c30..e63c3b403d4 100644 --- a/jdk/src/java.base/share/classes/java/security/cert/CertificateFactory.java +++ b/jdk/src/java.base/share/classes/java/security/cert/CertificateFactory.java @@ -29,10 +29,9 @@ import java.io.InputStream; 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 @@ public class CertificateFactory { * 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 @@ public class CertificateFactory { * * @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 @@ public class CertificateFactory { * 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 class CertificateFactory { */ 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 --git a/jdk/src/java.base/share/classes/java/util/ImmutableCollections.java b/jdk/src/java.base/share/classes/java/util/ImmutableCollections.java index 494dce83a89..26a03e0dae6 100644 --- a/jdk/src/java.base/share/classes/java/util/ImmutableCollections.java +++ b/jdk/src/java.base/share/classes/java/util/ImmutableCollections.java @@ -53,7 +53,8 @@ class ImmutableCollections { */ static final int SALT; static { - SALT = new Random().nextInt(); + long nt = System.nanoTime(); + SALT = (int)((nt >>> 32) ^ nt); } /** No instances. */ @@ -63,7 +64,7 @@ class ImmutableCollections { * 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 @@ class ImmutableCollections { } 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 @@ class ImmutableCollections { } 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 @@ class ImmutableCollections { 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 @@ class ImmutableCollections { } 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 @@ class ImmutableCollections { } 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 @@ final class CollSer implements Serializable { 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 --git a/jdk/src/java.base/share/classes/java/util/List.java b/jdk/src/java.base/share/classes/java/util/List.java index 8e97c2ea259..0f14c298805 100644 --- a/jdk/src/java.base/share/classes/java/util/List.java +++ b/jdk/src/java.base/share/classes/java/util/List.java @@ -786,7 +786,7 @@ public interface List extends Collection { * @since 9 */ static List of() { - return new ImmutableCollections.List0<>(); + return ImmutableCollections.List0.instance(); } /** @@ -1030,7 +1030,7 @@ public interface List extends Collection { 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 --git a/jdk/src/java.base/share/classes/java/util/Map.java b/jdk/src/java.base/share/classes/java/util/Map.java index d4ea203edee..b41e90dc866 100644 --- a/jdk/src/java.base/share/classes/java/util/Map.java +++ b/jdk/src/java.base/share/classes/java/util/Map.java @@ -1286,7 +1286,7 @@ public interface Map { * @since 9 */ static Map of() { - return new ImmutableCollections.Map0<>(); + return ImmutableCollections.Map0.instance(); } /** @@ -1604,7 +1604,7 @@ public interface Map { 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 --git a/jdk/src/java.base/share/classes/java/util/Scanner.java b/jdk/src/java.base/share/classes/java/util/Scanner.java index a6b3d8cb56f..df075844364 100644 --- a/jdk/src/java.base/share/classes/java/util/Scanner.java +++ b/jdk/src/java.base/share/classes/java/util/Scanner.java @@ -1267,6 +1267,9 @@ public final class Scanner implements Iterator, Closeable { // 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 @@ public final class Scanner implements Iterator, Closeable { * 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 @@ public final class Scanner implements Iterator, Closeable { * {@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 @@ public final class Scanner implements Iterator, Closeable { * 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 @@ public final class Scanner implements Iterator, Closeable { * 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 @@ public final class Scanner implements Iterator, Closeable { * {@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 @@ public final class Scanner implements Iterator, Closeable { * 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 @@ public final class Scanner implements Iterator, Closeable { * 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 @@ public final class Scanner implements Iterator, Closeable { * {@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 @@ public final class Scanner implements Iterator, Closeable { * 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 @@ public final class Scanner implements Iterator, Closeable { * 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 @@ public final class Scanner implements Iterator, Closeable { * {@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 @@ public final class Scanner implements Iterator, Closeable { * 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 @@ public final class Scanner implements Iterator, Closeable { * 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 @@ public final class Scanner implements Iterator, Closeable { * 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 @@ public final class Scanner implements Iterator, Closeable { * 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 --git a/jdk/src/java.base/share/classes/java/util/Set.java b/jdk/src/java.base/share/classes/java/util/Set.java index a1911c13e1b..08ef3297161 100644 --- a/jdk/src/java.base/share/classes/java/util/Set.java +++ b/jdk/src/java.base/share/classes/java/util/Set.java @@ -448,7 +448,7 @@ public interface Set extends Collection { * @since 9 */ static Set of() { - return new ImmutableCollections.Set0<>(); + return ImmutableCollections.Set0.instance(); } /** @@ -692,7 +692,7 @@ public interface Set extends Collection { 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 --git a/jdk/src/java.base/share/classes/java/util/stream/Collectors.java b/jdk/src/java.base/share/classes/java/util/stream/Collectors.java index fd7b0a477fa..aaa8c465966 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/Collectors.java +++ b/jdk/src/java.base/share/classes/java/util/stream/Collectors.java @@ -508,7 +508,7 @@ public final class Collectors { * 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 --git a/jdk/src/java.base/share/classes/javax/crypto/Cipher.java b/jdk/src/java.base/share/classes/javax/crypto/Cipher.java index 497069cd7fc..4c3ba78f676 100644 --- a/jdk/src/java.base/share/classes/javax/crypto/Cipher.java +++ b/jdk/src/java.base/share/classes/javax/crypto/Cipher.java @@ -493,21 +493,24 @@ public class Cipher { * 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 @@ public class Cipher { * * @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 @@ public class Cipher { 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 @@ public class Cipher { * * @param provider 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 object. + * @throws IllegalArgumentException if the {@code provider} + * is {@code null} * - * @exception NoSuchPaddingException if {@code transformation} - * contains a padding scheme that is not available. + * @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 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 @@ public class Cipher { 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 --git a/jdk/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java b/jdk/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java index 45d14027200..cf19807f2dc 100644 --- a/jdk/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java +++ b/jdk/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java @@ -34,6 +34,7 @@ import java.security.NoSuchProviderException; 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 @@ public class ExemptionMechanism { * 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 @@ public class ExemptionMechanism { * * @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 @@ public class ExemptionMechanism { * * @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 --git a/jdk/src/java.base/share/classes/javax/crypto/KeyAgreement.java b/jdk/src/java.base/share/classes/javax/crypto/KeyAgreement.java index dd8057ab485..be333ff1eb7 100644 --- a/jdk/src/java.base/share/classes/javax/crypto/KeyAgreement.java +++ b/jdk/src/java.base/share/classes/javax/crypto/KeyAgreement.java @@ -165,19 +165,19 @@ public class KeyAgreement { * 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 @@ public class KeyAgreement { * * @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 @@ public class KeyAgreement { * * @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 --git a/jdk/src/java.base/share/classes/javax/crypto/KeyGenerator.java b/jdk/src/java.base/share/classes/javax/crypto/KeyGenerator.java index 0719699d6f8..a5277d8bb6f 100644 --- a/jdk/src/java.base/share/classes/javax/crypto/KeyGenerator.java +++ b/jdk/src/java.base/share/classes/javax/crypto/KeyGenerator.java @@ -216,18 +216,19 @@ public class KeyGenerator { * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard algorithm names. * - * @return the new {@code KeyGenerator} object. + * @return the new {@code KeyGenerator} object * - * @exception NullPointerException if the specified algorithm is null. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code KeyGeneratorSpi} implementation for the + * specified algorithm * - * @exception NoSuchAlgorithmException if no Provider supports a - * 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 @@ public class KeyGenerator { * * @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 @@ public class KeyGenerator { * * @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 --git a/jdk/src/java.base/share/classes/javax/crypto/Mac.java b/jdk/src/java.base/share/classes/javax/crypto/Mac.java index 2d793ca45d7..97cd19a197a 100644 --- a/jdk/src/java.base/share/classes/javax/crypto/Mac.java +++ b/jdk/src/java.base/share/classes/javax/crypto/Mac.java @@ -166,16 +166,18 @@ public class Mac implements Cloneable { * 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 @@ public class Mac implements Cloneable { * * @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 @@ public class Mac implements Cloneable { * * @param provider 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 object. + * @throws IllegalArgumentException if the {@code provider} is + * {@code null} * - * @exception IllegalArgumentException if the {@code provider} - * is null. + * @throws NoSuchAlgorithmException if a {@code MacSpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object + * + * @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 --git a/jdk/src/java.base/share/classes/javax/crypto/SecretKeyFactory.java b/jdk/src/java.base/share/classes/javax/crypto/SecretKeyFactory.java index 091e08ac025..cadf2302d20 100644 --- a/jdk/src/java.base/share/classes/javax/crypto/SecretKeyFactory.java +++ b/jdk/src/java.base/share/classes/javax/crypto/SecretKeyFactory.java @@ -152,19 +152,19 @@ public class SecretKeyFactory { * 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 @@ public class SecretKeyFactory { * * @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 @@ public class SecretKeyFactory { * * @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 --git a/jdk/src/java.base/share/classes/javax/net/ssl/KeyManagerFactory.java b/jdk/src/java.base/share/classes/javax/net/ssl/KeyManagerFactory.java index 271974f90d9..443e704dde3 100644 --- a/jdk/src/java.base/share/classes/javax/net/ssl/KeyManagerFactory.java +++ b/jdk/src/java.base/share/classes/javax/net/ssl/KeyManagerFactory.java @@ -27,6 +27,7 @@ package javax.net.ssl; import java.security.Security; import java.security.*; +import java.util.Objects; import sun.security.jca.GetInstance; @@ -130,17 +131,19 @@ public class KeyManagerFactory { * 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 @@ public class KeyManagerFactory { * * @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 @@ public class KeyManagerFactory { * * @param provider an instance 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 object. + * @throws IllegalArgumentException if provider is {@code null} * - * @throws IllegalArgumentException if provider is null. - * @throws NullPointerException if algorithm is null. + * @throws NoSuchAlgorithmException if a {@code @KeyManagerFactorySpi} + * implementation for the specified algorithm is not available + * from the specified Provider object + * + * @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 --git a/jdk/src/java.base/share/classes/javax/net/ssl/SSLContext.java b/jdk/src/java.base/share/classes/javax/net/ssl/SSLContext.java index 598696b3427..2f2a0928a15 100644 --- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLContext.java +++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLContext.java @@ -26,6 +26,7 @@ package javax.net.ssl; import java.security.*; +import java.util.Objects; import sun.security.jca.GetInstance; @@ -151,17 +152,19 @@ public class SSLContext { * 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 @@ public class SSLContext { * * @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 @@ public class SSLContext { * * @param provider an instance 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 object. + * @throws IllegalArgumentException if the provider is {@code null} * - * @throws IllegalArgumentException if the provider is null. - * @throws NullPointerException if protocol is null. + * @throws NoSuchAlgorithmException if a {@code SSLContextSpi} + * implementation for the specified protocol is not available + * from the specified {@code Provider} object + * + * @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 --git a/jdk/src/java.base/share/classes/javax/net/ssl/TrustManagerFactory.java b/jdk/src/java.base/share/classes/javax/net/ssl/TrustManagerFactory.java index dd5ce10d5bd..0f999e8d0aa 100644 --- a/jdk/src/java.base/share/classes/javax/net/ssl/TrustManagerFactory.java +++ b/jdk/src/java.base/share/classes/javax/net/ssl/TrustManagerFactory.java @@ -27,6 +27,7 @@ package javax.net.ssl; import java.security.Security; import java.security.*; +import java.util.Objects; import sun.security.jca.GetInstance; @@ -144,17 +145,19 @@ public class TrustManagerFactory { * 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 @@ public class TrustManagerFactory { * * @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 @@ public class TrustManagerFactory { * * @param provider an instance 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 object. + * @throws IllegalArgumentException if the provider is {@code null} * - * @throws IllegalArgumentException if the provider is null. - * @throws NullPointerException if algorithm is null. + * @throws NoSuchAlgorithmException if a {@code TrustManagerFactorySpi} + * implementation for the specified algorithm is not available + * from the specified {@code Provider} object + * + * @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 --git a/jdk/src/java.base/share/classes/javax/security/auth/login/Configuration.java b/jdk/src/java.base/share/classes/javax/security/auth/login/Configuration.java index c1844d523eb..29d42df6855 100644 --- a/jdk/src/java.base/share/classes/javax/security/auth/login/Configuration.java +++ b/jdk/src/java.base/share/classes/javax/security/auth/login/Configuration.java @@ -329,27 +329,29 @@ public abstract class Configuration { * * @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. + * @throws IllegalArgumentException if the specified parameters + * are not understood by the {@code ConfigurationSpi} + * implementation from the selected {@code Provider} * - * @exception NullPointerException if the specified type is null. + * @throws NoSuchAlgorithmException if no {@code Provider} supports a + * {@code ConfigurationSpi} implementation for the specified type * - * @exception IllegalArgumentException if the specified parameters - * are not understood by the ConfigurationSpi implementation - * from the selected Provider. + * @throws NullPointerException if {@code type} is {@code null} * - * @exception NoSuchAlgorithmException if no Provider supports a - * ConfigurationSpi implementation for the specified type. + * @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 @@ public abstract class Configuration { * * @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. + * @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 NullPointerException if the specified type is null. + * @throws NoSuchProviderException if the specified provider is not + * registered in the security provider list * - * @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 NoSuchAlgorithmException if the specified provider does not + * support a {@code ConfigurationSpi} implementation for the + * specified type * - * @exception NoSuchProviderException if the specified provider is not - * registered in the security provider list. + * @throws NullPointerException if {@code type} is {@code null} * - * @exception NoSuchAlgorithmException if the specified provider does not - * support a ConfigurationSpi implementation for the specified - * type. + * @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 @@ public abstract class Configuration { 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 @@ public abstract class Configuration { * * @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. + * @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 NullPointerException if the specified type is null. + * @throws NoSuchAlgorithmException if the specified {@code Provider} + * does not support a {@code ConfigurationSpi} implementation + * for the specified type * - * @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 NullPointerException if {@code type} is {@code null} * - * @exception NoSuchAlgorithmException if the specified Provider does not - * support a ConfigurationSpi implementation for the specified - * type. + * @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 @@ public abstract class Configuration { Provider provider) throws NoSuchAlgorithmException { + Objects.requireNonNull(type, "null type name"); if (provider == null) { throw new IllegalArgumentException("missing provider"); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java index f64ccf2aa4a..df6724bec7b 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java @@ -175,6 +175,16 @@ public class JmodFile implements AutoCloseable { this.zipfile = new ZipFile(file.toFile()); } + /** + * 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 class JmodFile implements AutoCloseable { public InputStream getInputStream(Section section, String name) throws IOException { - String entry = section.jmodDir() + "/" + name; ZipEntry e = zipfile.getEntry(entry); if (e == null) { @@ -194,6 +203,15 @@ public class JmodFile implements AutoCloseable { return zipfile.getInputStream(e); } + /** + * 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. */ diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java index b6e58fb932b..e07559803fa 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java @@ -53,6 +53,7 @@ import java.util.Optional; 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 @@ public class BuiltinClassLoader /** * 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 @@ public class BuiltinClassLoader return Optional.empty(); } @Override + public Stream list() { + return Stream.empty(); + } + @Override public void close() { throw new InternalError("Should not get here"); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java b/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java index deaf34c41c2..7ed01991bb1 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java @@ -69,16 +69,17 @@ public class ClassLoaders { 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 @@ public class ClassLoaders { */ private static class BootClassLoader extends BuiltinClassLoader { BootClassLoader(URLClassPath bcp) { - super(null, bcp); + super(null, null, bcp); } @Override @@ -137,7 +138,7 @@ public class ClassLoaders { } PlatformClassLoader(BootClassLoader parent) { - super(parent, null); + super("platform", parent, null); } /** @@ -164,7 +165,7 @@ public class ClassLoaders { final URLClassPath ucp; AppClassLoader(PlatformClassLoader parent, URLClassPath ucp) { - super(parent, ucp); + super("app", parent, ucp); this.ucp = ucp; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java b/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java index 21900b5731e..8b2e257d7b8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java @@ -53,6 +53,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; /** @@ -534,6 +535,10 @@ public final class Loader extends SecureClassLoader { return Optional.empty(); } @Override + public Stream list() { + return Stream.empty(); + } + @Override public void close() { throw new InternalError("Should not get here"); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java b/jdk/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java index e24fcad2bd4..397ddba5432 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java +++ b/jdk/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java @@ -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 class DefaultLoggerFinder extends LoggerFinder { } 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 --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java index cf0e8f797d9..d19579212dd 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java @@ -39,6 +39,7 @@ import java.util.Collection; 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; @@ -102,6 +103,11 @@ public interface JavaLangModuleAccess { Set packages, 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 @@ -120,8 +126,10 @@ public interface JavaLangModuleAccess { 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 --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java index c86416e1dab..a8dda9b8d57 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java @@ -57,7 +57,15 @@ public final class ModuleInfoWriter { 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 --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java index ebc7d85a5e8..afee8bf3c36 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java @@ -50,6 +50,7 @@ import java.util.Optional; 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 @@ public final class ModulePatcher { // 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); } @@ -380,6 +379,15 @@ public final class ModulePatcher { } } + @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); @@ -393,6 +401,7 @@ public final class ModulePatcher { */ private static interface ResourceFinder extends Closeable { Resource find(String name) throws IOException; + Stream list() throws IOException; } @@ -453,6 +462,13 @@ public final class ModulePatcher { } }; } + + @Override + public Stream list() throws IOException { + return jf.stream() + .filter(e -> !e.isDirectory()) + .map(JarEntry::getName); + } } @@ -527,6 +543,15 @@ public final class ModulePatcher { } }; } + + @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 @@ public final class ModulePatcher { 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 @@ public final class ModulePatcher { 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 --git a/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java index 4b98f4c91bf..c6777c37827 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java @@ -364,6 +364,16 @@ public class ReflectionFactory { } } + 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 @@ public class ReflectionFactory { } catch (NoSuchMethodException ex) { return null; } + return generateConstructor(cl, constructorToCall); + } + + private final Constructor generateConstructor(Class cl, + Constructor constructorToCall) { + ConstructorAccessor acc = new MethodAccessorGenerator(). generateSerializationConstructor(cl, diff --git a/jdk/src/java.base/share/classes/module-info.java b/jdk/src/java.base/share/classes/module-info.java index 7b76d703cc4..0e4c0354ee2 100644 --- a/jdk/src/java.base/share/classes/module-info.java +++ b/jdk/src/java.base/share/classes/module-info.java @@ -196,7 +196,8 @@ module java.base { 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 --git a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties index b68e6a6a448..3801d542fcc 100644 --- a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties +++ b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties @@ -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 @@ java.launcher.opt.header = Usage: {0} [options] class [args...]\n\ \ (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 @@ java.launcher.opt.footer =\ -cp \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 --git a/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java b/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java index d3a58fe1b8a..05aa83ee3fd 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java +++ b/jdk/src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java @@ -253,20 +253,20 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { } 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 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { 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 --git a/jdk/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java index 9b77ebb1aca..fa680715874 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java @@ -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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { @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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // 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); + } - HandshakeFragment hsFrag = parseHandshakeMessage( - contentType, majorVersion, minorVersion, - recordEnS, recordEpoch, recordSeq, plaintextFragment); + 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); + + if (hsFrag == null) { + // invalid, discard this record + if (debug != null && Debug.isOn("verbose")) { + Debug.log("Invalid handshake message, discard it."); + } + + return null; + } + + 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."); + } - if (hsFrag == null) { - // invalid, discard this record 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { } } - 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { (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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { @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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { } } + 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { boolean flightIsReady = false; boolean needToCheckFlight = false; - // Is it a session-resuming abbreviated handshake.? - boolean isAbbreviatedHandshake = false; + DTLSReassembler(int handshakeEpoch) { + this.handshakeEpoch = handshakeEpoch; + this.nextRecordEpoch = handshakeEpoch; - // The handshke fragment with the biggest record sequence number - // in a flight, not counting the Finished message. - HandshakeFragment lastHandshakeFragment = null; - - // 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; } + // Clean up the retransmission messages if necessary. + cleanUpRetransmit(hsf); + // Is it the first message of next flight? - if ((flightTopMessageSeq == hsf.messageSeq) && - (hsf.fragmentOffset == 0) && (flightTopRecordSeq == -1)) { + // + // 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; + } - flightType = hsf.handshakeType; - flightTopEpoch = hsf.recordEpoch; - flightTopRecordSeq = hsf.recordSeq; + 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 (!isAbbreviatedHandshake) { - prevSessionID = getSessionID(hsf.fragment); - } + 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; } + + 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { (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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { } } - // 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; + } } - boolean isEmpty() { + 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; + } + + // 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { RecordFragment rFrag = bufferedFragments.first(); if (rFrag.contentType == Record.ct_change_cipher_spec) { this.nextRecordEpoch = rFrag.recordEpoch + 1; - this.nextRecordSeq = 0; - // no change on next handshake message sequence number - bufferedFragments.remove(rFrag); // popup the fragment + // 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; + + // 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { handshakeHashing(hsFrag, plaintext); this.nextRecordSeq = maxRecodeSN + 1; - this.nextMessageSeq = msgSeq + 1; return plaintext; } @@ -966,15 +1285,26 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { 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); + } + + return isReady; + } + + if (debug != null && Debug.isOn("verbose")) { + Debug.log("No flight is received yet."); + } - if (flightType == (byte)0xFF) { return false; } @@ -983,7 +1313,12 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { (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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { (flightType == HandshakeMessage.ht_client_key_exchange)) { // Firstly, check the first flight handshake message. - if (!hasCompleted(holesMap.get(flightType))) { + if (!hasCompleted(flightType)) { + if (debug != null && Debug.isOn("verbose")) { + Debug.log( + "The ClientKeyExchange or client Certificate " + + "message is not completed yet."); + } + return false; } - if (!hasFinisedMessage(bufferedFragments)) { - // not yet got the ChangeCipherSpec/Finished messages - return false; + // 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; + } } - if (flightType == HandshakeMessage.ht_client_key_exchange) { - // single handshake message flight - return true; - } + 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"); + } - // - // 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. 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { 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 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { 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 --git a/jdk/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java index 0381a0dc504..88ffa1611aa 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java @@ -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 @@ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord { 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 --git a/jdk/src/java.base/share/classes/sun/security/ssl/DTLSRecord.java b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSRecord.java index 30598e0148c..f8bbb3183be 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/DTLSRecord.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSRecord.java @@ -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 @@ interface DTLSRecord extends Record { + 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 --git a/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java b/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java index 4748330e4d6..48f6bb72bb5 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java @@ -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 @@ -144,6 +144,13 @@ public class Debug { System.err.println(prefix + ": "+message); } + /** + * 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 @@ public class Debug { /** * 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 --git a/jdk/src/java.base/share/classes/sun/security/ssl/OutputRecord.java b/jdk/src/java.base/share/classes/sun/security/ssl/OutputRecord.java index 7980ea77017..bffb1116337 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/OutputRecord.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/OutputRecord.java @@ -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 @@ abstract class OutputRecord extends ByteArrayOutputStream // blank } + // apply to DTLS SSLEngine + void launchRetransmission() { + // blank + } + @Override public synchronized void close() throws IOException { if (!isClosed) { @@ -224,6 +229,9 @@ abstract class OutputRecord extends ByteArrayOutputStream 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 @@ abstract class OutputRecord extends ByteArrayOutputStream // 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 @@ abstract class OutputRecord extends ByteArrayOutputStream // 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 @@ abstract class OutputRecord extends ByteArrayOutputStream 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 --git a/jdk/src/java.base/share/classes/sun/security/ssl/Plaintext.java b/jdk/src/java.base/share/classes/sun/security/ssl/Plaintext.java index ab80abe8738..24918a453f3 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/Plaintext.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/Plaintext.java @@ -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 @@ final class Plaintext { 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 --git a/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java index e7cd2acf126..6aaaf893d80 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java @@ -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 @@ public final class SSLEngineImpl extends SSLEngine { // 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 @@ public final class SSLEngineImpl extends SSLEngine { } if (plainText == null) { - plainText = new Plaintext(); + plainText = Plaintext.PLAINTEXT_NULL; } plainText.handshakeStatus = hsStatus; @@ -1378,7 +1393,8 @@ public final class SSLEngineImpl extends SSLEngine { // 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 @@ public final class SSLEngineImpl extends SSLEngine { 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()) { - hsStatus = finishHandshake(); - connectionState = cs_DATA; + if (handshaker == null) { + hsStatus = HandshakeStatus.FINISHED; + } else if (handshaker.isDone()) { + 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 @@ public final class SSLEngineImpl extends SSLEngine { 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 @@ public final class SSLEngineImpl extends SSLEngine { * 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 @@ public final class SSLEngineImpl extends SSLEngine { } /* - * 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 @@ public final class SSLEngineImpl extends SSLEngine { 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 @@ public final class SSLEngineImpl extends SSLEngine { } 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 @@ public final class SSLEngineImpl extends SSLEngine { } 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 --git a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java index a8870960ca6..17777825f3f 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java @@ -558,73 +558,6 @@ final class ServerHandshaker extends Handshaker { 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 @@ final class ServerHandshaker extends Handshaker { } } // 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 --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakDictionary.java b/jdk/src/java.base/share/classes/sun/text/BreakDictionary.java similarity index 70% rename from jdk/src/java.base/share/classes/sun/util/locale/provider/BreakDictionary.java rename to jdk/src/java.base/share/classes/sun/text/BreakDictionary.java index 4be1363b58f..ae2aba1e7c2 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakDictionary.java +++ b/jdk/src/java.base/share/classes/sun/text/BreakDictionary.java @@ -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 @@ -37,15 +37,10 @@ * This notice and attribution to Taligent may not be removed. * Taligent is a registered trademark of Taligent, Inc. */ -package sun.util.locale.provider; +package sun.text; -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.nio.BufferUnderflowException; +import java.nio.ByteBuffer; import java.util.MissingResourceException; import sun.text.CompactByteArray; import sun.text.SupplementaryCharacterData; @@ -137,131 +132,90 @@ class BreakDictionary { // deserialization //========================================================================= - BreakDictionary(Module module, String dictionaryName) - throws IOException, MissingResourceException { - - readDictionaryFile(module, dictionaryName); + 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 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, ""); - } + private void setupDictionary(String dictionaryName, byte[] dictionaryData) { + ByteBuffer bb = ByteBuffer.wrap(dictionaryData); // check version - int version = RuleBasedBreakIterator.getInt(buf, 0); + int version = bb.getInt(); 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; + // 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) - 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]; + 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 = RuleBasedBreakIterator.getInt(buf, offset); - offset += 4; - numColGroups = RuleBasedBreakIterator.getInt(buf, offset); - offset += 4; + numCols = bb.getInt(); + numColGroups = bb.getInt(); // 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); + 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 - 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); + len = bb.getInt(); + rowIndexFlagsIndex = new short[len]; + for (int i = 0; i < len; i++) { + rowIndexFlagsIndex[i] = bb.getShort(); } - 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); + len = bb.getInt(); + rowIndexFlags = new int[len]; + for (int i = 0; i < len; i++) { + rowIndexFlags[i] = bb.getInt(); } // 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]; - } + len = bb.getInt(); + rowIndexShifts = new byte[len]; + bb.get(rowIndexShifts); // 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); + 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 - 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); + 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); } diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/DictionaryBasedBreakIterator.java b/jdk/src/java.base/share/classes/sun/text/DictionaryBasedBreakIterator.java similarity index 96% rename from jdk/src/java.base/share/classes/sun/util/locale/provider/DictionaryBasedBreakIterator.java rename to jdk/src/java.base/share/classes/sun/text/DictionaryBasedBreakIterator.java index f7eff4e80cf..bd47872bec1 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/DictionaryBasedBreakIterator.java +++ b/jdk/src/java.base/share/classes/sun/text/DictionaryBasedBreakIterator.java @@ -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 @@ -38,10 +38,8 @@ * Taligent is a registered trademark of Taligent, Inc. */ -package sun.util.locale.provider; +package sun.text; -import java.io.IOException; -import java.lang.reflect.Module; import java.text.CharacterIterator; import java.util.ArrayList; import java.util.List; @@ -72,7 +70,7 @@ import java.util.Stack; * slow) BuildDictionaryFile utility for creating dictionary files, but aren't * currently making it public. Contact us for help. */ -class DictionaryBasedBreakIterator extends RuleBasedBreakIterator { +public class DictionaryBasedBreakIterator extends RuleBasedBreakIterator { /** * a list of known words that is used to divide up contiguous ranges of letters, @@ -109,18 +107,22 @@ class DictionaryBasedBreakIterator extends RuleBasedBreakIterator { /** * Constructs a DictionaryBasedBreakIterator. - * @param module The module where the dictionary file resides - * @param dictionaryFilename The filename of the dictionary file to use + * + * @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 */ - DictionaryBasedBreakIterator(Module module, String dataFile, String dictionaryFile) - throws IOException { - super(module, dataFile); + 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(module, dictionaryFile); + dictionary = new BreakDictionary(dictionaryFile, dictionaryData); } private void prepareCategoryFlags(byte[] data) { diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java b/jdk/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java similarity index 88% rename from jdk/src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java rename to jdk/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java index ebf6ba1956e..b3abf812f29 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java +++ b/jdk/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java @@ -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 @@ -38,15 +38,10 @@ * Taligent is a registered trademark of Taligent, Inc. */ -package sun.util.locale.provider; +package sun.text; -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.nio.BufferUnderflowException; +import java.nio.ByteBuffer; import java.text.BreakIterator; import java.text.CharacterIterator; import java.text.StringCharacterIterator; @@ -218,7 +213,7 @@ import sun.text.SupplementaryCharacterData; * * @author Richard Gillam */ -class RuleBasedBreakIterator extends BreakIterator { +public class RuleBasedBreakIterator extends BreakIterator { /** * A token used as a character-category value to identify ignore characters @@ -249,11 +244,6 @@ class RuleBasedBreakIterator extends BreakIterator { */ 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 */ @@ -315,16 +305,26 @@ class RuleBasedBreakIterator extends BreakIterator { //======================================================================= /** - * Constructs a RuleBasedBreakIterator according to the module and the datafile - * provided. + * Constructs a RuleBasedBreakIterator using the given rule data. + * + * @throws MissingResourceException if the rule data is invalid or corrupted */ - RuleBasedBreakIterator(Module module, String datafile) - throws IOException, MissingResourceException { - readTables(module, datafile); + 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; + } } /** - * Read datafile. The datafile's format is as follows: + * Initializes the fields with the given rule data. + * The data format is as follows: *
          *   BreakIteratorData {
          *       u1           magic[7];
    @@ -370,133 +370,101 @@ class RuleBasedBreakIterator extends BreakIterator {
          *       u1           additionalData[additionalDataLength];
          *   }
          * 
    + * + * @throws BufferUnderflowException if the end-of-data is reached before + * setting up all the tables */ - protected final void readTables(Module module, String datafile) - throws IOException, MissingResourceException { - - byte[] buffer = readFile(module, datafile); - + private void setupTables(String ruleFile, ByteBuffer bb) { /* 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); + 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]; - int offset = HEADER_LENGTH; - for (int i = 0; i < stateTableLength; i++, offset+=2) { - stateTable[i] = getShort(buffer, offset); + 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++, offset+=2) { - backwardsStateTable[i] = getShort(buffer, offset); + 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++, offset++) { - endStates[i] = buffer[offset] == 1; + 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++, offset++) { - lookaheadStates[i] = buffer[offset] == 1; + 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++, offset+=2) { - temp1[i] = getShort(buffer, offset); + for (int i = 0; i < BMP_INDICES_LENGTH; i++) { + temp1[i] = bb.getShort(); } byte[] temp2 = new byte[BMPdataLength]; // BMPdata - System.arraycopy(buffer, offset, temp2, 0, BMPdataLength); - offset += BMPdataLength; + 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++, offset+=4) { - temp3[i] = getInt(buffer, offset); + 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]; - System.arraycopy(buffer, offset, additionalData, 0, additionalDataLength); + bb.get(additionalData); } + assert bb.position() == bb.limit(); /* 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]) { + /** + * 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", - datafile, ""); + ruleFile, ""); } } - /* Validate the version number. */ - if (buf[offset] != supportedVersion) { - throw new MissingResourceException("Unsupported version(" + buf[offset] + ")", - datafile, ""); + /* Verify the version number. */ + byte version = bb.get(); + if (version != supportedVersion) { + throw new MissingResourceException("Unsupported version(" + version + ")", + ruleFile, ""); } - /* Read data: totalDataSize + 8(for checksum) */ - len = getInt(buf, ++offset); - buf = new byte[len]; - if (is.read(buf) != len) { + // Check the length of the rest of data + int len = bb.getInt(); + if (bb.position() + len != bb.limit()) { throw new MissingResourceException("Wrong data length", - datafile, ""); + ruleFile, ""); } - - is.close(); - - return buf; } byte[] getAdditionalData() { @@ -1061,28 +1029,6 @@ class RuleBasedBreakIterator extends BreakIterator { 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). diff --git a/jdk/src/java.base/share/classes/sun/text/resources/BreakIteratorResources.java b/jdk/src/java.base/share/classes/sun/text/resources/BreakIteratorResources.java new file mode 100644 index 00000000000..848117e126e --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/text/resources/BreakIteratorResources.java @@ -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 --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java index 2de50a98962..1343dadb3b9 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java @@ -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.Locale; 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 @@ public class BreakIteratorProviderImpl extends BreakIteratorProvider } 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 --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java index 2269d608eb5..a6f3bc53bb0 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java @@ -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 @@ package sun.util.locale.provider; 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 @@ public class LocaleResources { 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 --git a/jdk/src/java.base/share/classes/sun/util/resources/BreakIteratorResourceBundle.java b/jdk/src/java.base/share/classes/sun/util/resources/BreakIteratorResourceBundle.java new file mode 100644 index 00000000000..d859e2a3ace --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/util/resources/BreakIteratorResourceBundle.java @@ -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 --git a/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java b/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java index 5510b6cc250..497742667e7 100644 --- a/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java +++ b/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java @@ -122,6 +122,14 @@ public class LocaleData { return getBundle(type.getTextResourcesPackage() + ".BreakIteratorInfo", locale); } + /** + * 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 --git a/jdk/src/java.base/share/conf/security/java.security b/jdk/src/java.base/share/conf/security/java.security index 966f9ba027e..a521dde7ebb 100644 --- a/jdk/src/java.base/share/conf/security/java.security +++ b/jdk/src/java.base/share/conf/security/java.security @@ -645,6 +645,9 @@ krb5.kdc.bad.policy = tryLast # 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 @@ jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \ # 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 --git a/jdk/src/java.base/share/lib/security/default.policy b/jdk/src/java.base/share/lib/security/default.policy index 17e1c80e627..966898459a7 100644 --- a/jdk/src/java.base/share/lib/security/default.policy +++ b/jdk/src/java.base/share/lib/security/default.policy @@ -32,8 +32,22 @@ grant codeBase "jrt:/java.smartcardio" { 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 --git a/jdk/src/java.base/share/native/include/jvm.h b/jdk/src/java.base/share/native/include/jvm.h index 1d6576a6381..3d7fd391c25 100644 --- a/jdk/src/java.base/share/native/include/jvm.h +++ b/jdk/src/java.base/share/native/include/jvm.h @@ -165,14 +165,24 @@ JVM_FindLibraryEntry(void *handle, const char *name); 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 @@ JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jlong anchor, 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 --git a/jdk/src/java.base/share/native/include/jvmti.h b/jdk/src/java.base/share/native/include/jvmti.h deleted file mode 100644 index 0009a88ae29..00000000000 --- a/jdk/src/java.base/share/native/include/jvmti.h +++ /dev/null @@ -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 --git a/jdk/src/java.base/share/native/launcher/defines.h b/jdk/src/java.base/share/native/launcher/defines.h index 3b63e038f9d..1dd0cbe5b32 100644 --- a/jdk/src/java.base/share/native/launcher/defines.h +++ b/jdk/src/java.base/share/native/launcher/defines.h @@ -51,16 +51,6 @@ static const char* const_progname = PROGNAME; 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 --git a/jdk/src/java.base/share/native/launcher/main.c b/jdk/src/java.base/share/native/launcher/main.c index 9c24c2ebf68..22298385114 100644 --- a/jdk/src/java.base/share/native/launcher/main.c +++ b/jdk/src/java.base/share/native/launcher/main.c @@ -83,7 +83,7 @@ char **__initenv; 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 @@ WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow) 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 @@ main(int argc, char **argv) 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 --git a/jdk/src/java.base/share/native/libjava/StackFrameInfo.c b/jdk/src/java.base/share/native/libjava/StackTraceElement.c similarity index 69% rename from jdk/src/java.base/share/native/libjava/StackFrameInfo.c rename to jdk/src/java.base/share/native/libjava/StackTraceElement.c index 41c021a2027..e55f4c0fb53 100644 --- a/jdk/src/java.base/share/native/libjava/StackFrameInfo.c +++ b/jdk/src/java.base/share/native/libjava/StackTraceElement.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 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 @@ -23,25 +23,21 @@ * questions. */ -/* - * Implementation of class StackFrameInfo - */ - #include #include #include "jni.h" #include "jvm.h" -#include "java_lang_StackFrameInfo.h" +#include "java_lang_StackTraceElement.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); +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 --git a/jdk/src/java.base/share/native/libjava/Throwable.c b/jdk/src/java.base/share/native/libjava/Throwable.c index 9944d48af19..e8b6587b361 100644 --- a/jdk/src/java.base/share/native/libjava/Throwable.c +++ b/jdk/src/java.base/share/native/libjava/Throwable.c @@ -49,10 +49,3 @@ Java_java_lang_Throwable_fillInStackTrace(JNIEnv *env, jobject throwable, jint d 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 --git a/jdk/src/java.base/share/native/libjli/java.c b/jdk/src/java.base/share/native/libjli/java.c index 6dc9674a6ed..70a7bf7a6d9 100644 --- a/jdk/src/java.base/share/native/libjli/java.c +++ b/jdk/src/java.base/share/native/libjli/java.c @@ -1664,19 +1664,21 @@ AddApplicationOptions(int cpathc, const char **cpathv) 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 --git a/jdk/src/java.base/share/native/libnet/net_util.c b/jdk/src/java.base/share/native/libnet/net_util.c index c2d4b002b04..02bf588ddc9 100644 --- a/jdk/src/java.base/share/native/libnet/net_util.c +++ b/jdk/src/java.base/share/native/libnet/net_util.c @@ -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 @@ jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj) { 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 @@ NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { 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 @@ NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) { 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 @@ NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj) { 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 @@ NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj) 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 --git a/jdk/src/java.base/share/native/libnet/net_util.h b/jdk/src/java.base/share/native/libnet/net_util.h index 159079cd8f7..c625d60c27f 100644 --- a/jdk/src/java.base/share/native/libnet/net_util.h +++ b/jdk/src/java.base/share/native/libnet/net_util.h @@ -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_Inet6Address_init(JNIEnv *env, jclass cls); 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 @@ NET_MapSocketOptionV6(jint cmd, int *level, int *optname); 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 --git a/jdk/src/java.base/unix/conf/s390x/jvm.cfg b/jdk/src/java.base/unix/conf/s390x/jvm.cfg new file mode 100644 index 00000000000..2c147c9b97d --- /dev/null +++ b/jdk/src/java.base/unix/conf/s390x/jvm.cfg @@ -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 --git a/jdk/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/jdk/src/java.base/unix/native/libnet/Inet4AddressImpl.c index d8786309105..e2e0f10fad9 100644 --- a/jdk/src/java.base/unix/native/libnet/Inet4AddressImpl.c +++ b/jdk/src/java.base/unix/native/libnet/Inet4AddressImpl.c @@ -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 @@ Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this, 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 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, 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 @@ Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this, 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 --git a/jdk/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/jdk/src/java.base/unix/native/libnet/Inet6AddressImpl.c index c297c3b3a64..f4b961d943b 100644 --- a/jdk/src/java.base/unix/native/libnet/Inet6AddressImpl.c +++ b/jdk/src/java.base/unix/native/libnet/Inet6AddressImpl.c @@ -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 @@ Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) { 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 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, 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 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, 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 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, } freeaddrinfo(res); -#endif /* AF_INET6 */ return ret; } @@ -483,7 +471,6 @@ Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this, jstring ret = NULL; -#ifdef AF_INET6 char host[NI_MAXHOST+1]; int error = 0; int len = 0; @@ -504,30 +491,28 @@ Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this, 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 @@ Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this, 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 @@ ping6(JNIEnv *env, jint fd, struct sockaddr_in6* him, jint timeout, close(fd); return JNI_FALSE; } -#endif /* AF_INET6 */ /* * Class: java_net_Inet6AddressImpl @@ -663,7 +646,6 @@ Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this, 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 @@ Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this, close(fd); return JNI_FALSE; } -#else /* AF_INET6 */ - return JNI_FALSE; -#endif /* AF_INET6 */ } diff --git a/jdk/src/java.base/unix/native/libnet/InetAddressImplFactory.c b/jdk/src/java.base/unix/native/libnet/InetAddressImplFactory.c index feae9501590..2c799feb105 100644 --- a/jdk/src/java.base/unix/native/libnet/InetAddressImplFactory.c +++ b/jdk/src/java.base/unix/native/libnet/InetAddressImplFactory.c @@ -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 --git a/jdk/src/java.base/unix/native/libnet/NetworkInterface.c b/jdk/src/java.base/unix/native/libnet/NetworkInterface.c index d5b1824b314..d03e150a4f8 100644 --- a/jdk/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/jdk/src/java.base/unix/native/libnet/NetworkInterface.c @@ -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__) -#include -#include -#include -#include -#include -#endif #endif -#include "jvm.h" -#include "jni_util.h" +#if defined(_ALLBSD_SOURCE) +#include +#include +#include +#endif + #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 int getFlags0(JNIEnv *env, jstring ifname); 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 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0 (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 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0 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 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0 break; } } -#endif } if (match) { @@ -725,7 +697,6 @@ static jobject createNetworkInterface(JNIEnv *env, netif *ifs) { 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 @@ static jobject createNetworkInterface(JNIEnv *env, netif *ifs) { return NULL; } } -#endif (*env)->SetObjectArrayElement(env, addrArr, addr_index++, iaObj); addrP = addrP->next; @@ -815,25 +785,23 @@ static netif *enumInterfaces(JNIEnv *env) { } // 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; - } - - ifs = enumIPv6Interfaces(env, sock, ifs); - close(sock); - - if ((*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; } -#endif + + ifs = enumIPv6Interfaces(env, sock, ifs); + close(sock); + + if ((*env)->ExceptionOccurred(env)) { + freeif(ifs); + return NULL; + } + } return ifs; } @@ -889,12 +857,8 @@ static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs, // 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 @@ static int openSocket(JNIEnv *env, int proto) { /** 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 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { // 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 @@ static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { return ifs; } -#if defined(AF_INET6) - /* * Enumerates and returns all IPv6 interfaces on Linux. */ @@ -1240,8 +1196,6 @@ static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) { return ifs; } -#endif /* AF_INET6 */ - /* * Try to get the interface index. */ @@ -1330,7 +1284,6 @@ static int getFlags(int sock, const char *ifname, int *flags) { /** 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 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { 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 @@ static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { return ifs; } -#if defined(AF_INET6) - /* * Enumerates and returns all IPv6 interfaces on AIX. */ @@ -1518,8 +1464,6 @@ static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) { return ifs; } -#endif /* AF_INET6 */ - /* * Try to get the interface index. */ @@ -1614,7 +1558,6 @@ static int getFlags(int sock, const char *ifname, int *flags) { /** 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 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { 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 @@ static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { return ifs; } -#if defined(AF_INET6) - /* * Enumerates and returns all IPv6 interfaces on Solaris. */ @@ -1803,8 +1739,6 @@ static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) { return ifs; } -#endif /* AF_INET6 */ - /* * Try to get the interface index. * (Not supported on Solaris 2.6 or 7) @@ -1976,7 +1910,6 @@ static int getFlags(int sock, const char *ifname, int *flags) { /** 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 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { 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 @@ static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { return ifs; } -#if defined(AF_INET6) - /* * Enumerates and returns all IPv6 interfaces on BSD. */ @@ -2092,8 +2018,6 @@ static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) { return ifs; } -#endif /* AF_INET6 */ - /* * Try to get the interface index. */ diff --git a/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c b/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c index a716db9d7cb..a7fddecedd5 100644 --- a/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c +++ b/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c @@ -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 + +#include "net_util.h" + +#include "java_net_PlainDatagramSocketImpl.h" +#include "java_net_InetAddress.h" +#include "java_net_NetworkInterface.h" +#include "java_net_SocketOptions.h" -#ifndef BSD_COMP -#define BSD_COMP -#endif -#endif #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 @@ static int getFD(JNIEnv *env, jobject this) { 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 @@ Java_java_net_PlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jin #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 @@ Java_java_net_PlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject this, jin 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 @@ Java_java_net_PlainDatagramSocketImpl_send(JNIEnv *env, jobject this, (*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 @@ Java_java_net_PlainDatagramSocketImpl_peek(JNIEnv *env, jobject this, } 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 @@ Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env, 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 @@ Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env, return; } -#ifdef AF_INET6 /* Disable IPV6_V6ONLY to ensure dual-socket support */ if (domain == AF_INET6) { arg = 0; @@ -947,7 +919,6 @@ Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env, return; } } -#endif /* AF_INET6 */ #ifdef __APPLE__ arg = 65507; @@ -987,7 +958,7 @@ Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env, } #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 @@ static void mcast_set_if_by_if_v4(JNIEnv *env, jobject this, int fd, jobject val */ 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 @@ static void mcast_set_if_by_if_v4(JNIEnv *env, jobject this, int fd, jobject val * 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 @@ static void mcast_set_if_by_if_v6(JNIEnv *env, jobject this, int fd, jobject val } return; } - } -#endif /* AF_INET6 */ /* * Set outgoing multicast interface designated by an InetAddress. @@ -1137,7 +1105,6 @@ static void mcast_set_if_by_addr_v4(JNIEnv *env, jobject this, int fd, jobject v * 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 @@ static void mcast_set_if_by_addr_v6(JNIEnv *env, jobject this, int fd, jobject v mcast_set_if_by_if_v6(env, this, fd, value); } -#endif /* * Sets the multicast interface. @@ -1191,7 +1157,6 @@ static void setMulticastInterface(JNIEnv *env, jobject this, int fd, /* * 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 @@ static void setMulticastInterface(JNIEnv *env, jobject this, int fd, 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 @@ static void setMulticastInterface(JNIEnv *env, jobject this, int fd, 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 @@ static void mcast_set_loop_v4(JNIEnv *env, jobject this, int fd, jobject value) /* * 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 @@ static void mcast_set_loop_v6(JNIEnv *env, jobject this, int fd, jobject value) } } -#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 @@ static void setMulticastLoopbackMode(JNIEnv *env, jobject this, int fd, 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 @@ Java_java_net_PlainDatagramSocketImpl_socketSetOption0 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 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, jint opt) { } -#ifdef AF_INET6 /* * IPv6 implementation */ @@ -1677,7 +1626,6 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, jint opt) { } return ni; } -#endif return NULL; } @@ -1815,7 +1763,6 @@ static void setTTL(JNIEnv *env, int fd, jint ttl) { /* * 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 @@ static void setHopLimit(JNIEnv *env, int fd, jint ttl) { (env, JNU_JAVANETPKG "SocketException", "Error setting socket option"); } } -#endif /* * Class: java_net_PlainDatagramSocketImpl @@ -1847,7 +1793,6 @@ Java_java_net_PlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this, 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 @@ Java_java_net_PlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this, setTTL(env, fd, ttl); } #endif /* __linux__ */ -#else - setTTL(env, fd, ttl); -#endif /* AF_INET6 */ } /* @@ -1896,7 +1838,6 @@ Java_java_net_PlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) { 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 @@ Java_java_net_PlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) { 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 @@ static void mcast_join_leave(JNIEnv *env, jobject this, /* * 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 @@ static void mcast_join_leave(JNIEnv *env, jobject this, * NetworkInterface */ if (niObj != NULL) { -#if defined(__linux__) && defined(AF_INET6) +#if defined(__linux__) if (ipv6_available()) { static jfieldID ni_indexID; @@ -2062,7 +1993,7 @@ static void mcast_join_leave(JNIEnv *env, jobject this, if (niObj == NULL) { -#if defined(__linux__) && defined(AF_INET6) +#if defined(__linux__) if (ipv6_available()) { int index; @@ -2118,7 +2049,7 @@ static void mcast_join_leave(JNIEnv *env, jobject this, * 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 @@ static void mcast_join_leave(JNIEnv *env, jobject this, * 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 @@ static void mcast_join_leave(JNIEnv *env, jobject this, } } } -#endif } /* diff --git a/jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c b/jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c index c605edb700d..b5af3466ada 100644 --- a/jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c +++ b/jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c @@ -22,32 +22,8 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - #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 @@ Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this, 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 @@ Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this, return; } -#ifdef AF_INET6 /* Disable IPV6_V6ONLY to ensure dual-socket support */ if (domain == AF_INET6) { int arg = 0; @@ -225,7 +196,6 @@ Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this, return; } } -#endif /* AF_INET6 */ /* * If this is a server socket then enable SO_REUSEADDR @@ -295,11 +265,10 @@ Java_java_net_PlainSocketImpl_socketConnect(JNIEnv *env, jobject this, } 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 --git a/jdk/src/java.base/unix/native/libnet/SdpSupport.c b/jdk/src/java.base/unix/native/libnet/SdpSupport.c index 1fe5353fcd6..d9dde8db7ab 100644 --- a/jdk/src/java.base/unix/native/libnet/SdpSupport.c +++ b/jdk/src/java.base/unix/native/libnet/SdpSupport.c @@ -56,11 +56,7 @@ static int create(JNIEnv* env) 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 --git a/jdk/src/java.base/unix/native/libnet/SocketInputStream.c b/jdk/src/java.base/unix/native/libnet/SocketInputStream.c index a27902b1f83..961f53c7baf 100644 --- a/jdk/src/java.base/unix/native/libnet/SocketInputStream.c +++ b/jdk/src/java.base/unix/native/libnet/SocketInputStream.c @@ -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 --git a/jdk/src/java.base/unix/native/libnet/SocketOutputStream.c b/jdk/src/java.base/unix/native/libnet/SocketOutputStream.c index f5a685a741c..17afe8b8d46 100644 --- a/jdk/src/java.base/unix/native/libnet/SocketOutputStream.c +++ b/jdk/src/java.base/unix/native/libnet/SocketOutputStream.c @@ -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 --git a/jdk/src/java.base/unix/native/libnet/net_util_md.c b/jdk/src/java.base/unix/native/libnet/net_util_md.c index 13b97dcbc9a..e6d19d0a19a 100644 --- a/jdk/src/java.base/unix/native/libnet/net_util_md.c +++ b/jdk/src/java.base/unix/native/libnet/net_util_md.c @@ -22,59 +22,41 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - -#include -#include -#include -#include -#include /* Defines TCP_NODELAY, needed for 2.6 */ -#include -#include -#include -#include #include +#include +#include +#include // defines TCP_NODELAY +#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 - -#ifndef IPV6_FLOWINFO_SEND -#define IPV6_FLOWINFO_SEND 33 #endif +#if defined(__solaris__) +#include +#include +#include +#include +#include #endif -#ifdef _AIX -#include -#endif - -#include "jni_util.h" -#include "jvm.h" #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 + +#if defined(__solaris__) && !defined(MAXINT) +#define MAXINT INT_MAX +#endif /* * EXCLBIND socket options only on Solaris @@ -324,11 +306,6 @@ jint IPv6_supported() jint IPv6_supported() { -#ifndef AF_INET6 - return JNI_FALSE; -#endif - -#ifdef AF_INET6 int fd; void *ipv6_fn; SOCKETADDRESS sa; @@ -433,7 +410,6 @@ jint IPv6_supported() } else { return JNI_TRUE; } -#endif /* AF_INET6 */ } #endif /* DONT_ENABLE_IPV6 */ @@ -484,7 +460,7 @@ void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, } } -#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 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr 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 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr 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 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr * 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 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr #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 @@ NET_MapSocketOption(jint cmd, int *level, int *optname) { int i; -#ifdef AF_INET6 if (ipv6_available()) { switch (cmd) { // Different multicast options if IPv6 is enabled @@ -1047,7 +1014,6 @@ NET_MapSocketOption(jint cmd, int *level, int *optname) { #endif } } -#endif /* * Map the Java level option to the native level @@ -1079,7 +1045,7 @@ NET_MapSocketOption(jint cmd, int *level, int *optname) { * 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 @@ NET_SetSockOpt(int fd, int level, int opt, const void *arg, 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 @@ NET_SetSockOpt(int fd, int level, int opt, const void *arg, 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 @@ NET_Bind(int fd, struct sockaddr *him, int len) 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 --git a/jdk/src/java.base/unix/native/libnet/net_util_md.h b/jdk/src/java.base/unix/native/libnet/net_util_md.h index d7f526d8e7c..48503d2efbe 100644 --- a/jdk/src/java.base/unix/native/libnet/net_util_md.h +++ b/jdk/src/java.base/unix/native/libnet/net_util_md.h @@ -26,13 +26,9 @@ #ifndef NET_UTILS_MD_H #define NET_UTILS_MD_H -#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 @@ void NET_ThrowByNameWithLastError(JNIEnv *env, const char *name, #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 @@ typedef union { #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 --git a/jdk/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c b/jdk/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c index 3ea2333fa08..d834ef9bf11 100644 --- a/jdk/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c +++ b/jdk/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c @@ -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 --git a/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c b/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c index 0fa6d79be6a..39178408823 100644 --- a/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c +++ b/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c @@ -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 --git a/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c b/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c index 3a9e650a5f8..f7dc5c2ebe0 100644 --- a/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c +++ b/jdk/src/java.base/windows/native/libnet/Inet4AddressImpl.c @@ -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 "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 --git a/jdk/src/java.base/windows/native/libnet/Inet6AddressImpl.c b/jdk/src/java.base/windows/native/libnet/Inet6AddressImpl.c index b62a887a030..e07f8a3e46b 100644 --- a/jdk/src/java.base/windows/native/libnet/Inet6AddressImpl.c +++ b/jdk/src/java.base/windows/native/libnet/Inet6AddressImpl.c @@ -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 "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 @@ Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this, 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 @@ Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this, return ret; } -#ifdef AF_INET6 - /** * ping implementation using tcp port 7 (echo) */ @@ -493,7 +466,6 @@ ping6(JNIEnv *env, return JNI_FALSE; } } -#endif /* AF_INET6 */ /* * Class: java_net_Inet6AddressImpl @@ -507,7 +479,6 @@ Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this, 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 @@ Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this, return ping6(env, netif, &him6, timeout, hIcmpFile); } -#endif /* AF_INET6 */ return JNI_FALSE; } diff --git a/jdk/src/java.base/windows/native/libnet/NetworkInterface.c b/jdk/src/java.base/windows/native/libnet/NetworkInterface.c index ec2fd4c0a1d..4d07b399af7 100644 --- a/jdk/src/java.base/windows/native/libnet/NetworkInterface.c +++ b/jdk/src/java.base/windows/native/libnet/NetworkInterface.c @@ -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 --git a/jdk/src/java.base/windows/native/libnet/NetworkInterface.h b/jdk/src/java.base/windows/native/libnet/NetworkInterface.h index 3bf4ed06aec..9a95d77cecd 100644 --- a/jdk/src/java.base/windows/native/libnet/NetworkInterface.h +++ b/jdk/src/java.base/windows/native/libnet/NetworkInterface.h @@ -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 --git a/jdk/src/java.base/windows/native/libnet/NetworkInterface_winXP.c b/jdk/src/java.base/windows/native/libnet/NetworkInterface_winXP.c index 0f0fbe19712..ed191648e70 100644 --- a/jdk/src/java.base/windows/native/libnet/NetworkInterface_winXP.c +++ b/jdk/src/java.base/windows/native/libnet/NetworkInterface_winXP.c @@ -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 --git a/jdk/src/java.base/windows/native/libnet/SocketInputStream.c b/jdk/src/java.base/windows/native/libnet/SocketInputStream.c index 3e9da6e7176..b4022fb5d60 100644 --- a/jdk/src/java.base/windows/native/libnet/SocketInputStream.c +++ b/jdk/src/java.base/windows/native/libnet/SocketInputStream.c @@ -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 "java_net_SocketInputStream.h" #include "net_util.h" -#include "jni_util.h" + +#include "java_net_SocketInputStream.h" /************************************************************************* * SocketInputStream */ - static jfieldID IO_fd_fdID; /* diff --git a/jdk/src/java.base/windows/native/libnet/SocketOutputStream.c b/jdk/src/java.base/windows/native/libnet/SocketOutputStream.c index 4bcfbc32434..9894cb0e596 100644 --- a/jdk/src/java.base/windows/native/libnet/SocketOutputStream.c +++ b/jdk/src/java.base/windows/native/libnet/SocketOutputStream.c @@ -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,19 +22,11 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - -#include -#include -#include -#include -#include #include -#include - -#include "java_net_SocketOutputStream.h" #include "net_util.h" -#include "jni_util.h" + +#include "java_net_SocketOutputStream.h" /************************************************************************ * SocketOutputStream diff --git a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c index a01c46b36fd..d382267742c 100644 --- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c +++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c @@ -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 "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 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this, 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 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_connect0(JNIEnv *env, jobject thi 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 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_disconnect0(JNIEnv *env, jobject 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 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_send(JNIEnv *env, jobject this, } 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 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_peek(JNIEnv *env, jobject this, 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 @@ static int getInet4AddrFromIf (JNIEnv *env, jobject nif, struct in_addr *iaddr) { 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 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_socketLocalAddress 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 --git a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c index 51e33a5b464..f8f1063c904 100644 --- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c +++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c @@ -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 @@ Java_java_net_TwoStacksPlainSocketImpl_socketBind(JNIEnv *env, jobject this, 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 @@ Java_java_net_TwoStacksPlainSocketImpl_socketAccept(JNIEnv *env, jobject this, 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 @@ Java_java_net_TwoStacksPlainSocketImpl_socketAccept(JNIEnv *env, jobject this, } 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 @@ Java_java_net_TwoStacksPlainSocketImpl_socketAccept(JNIEnv *env, jobject this, 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 --git a/jdk/src/java.base/windows/native/libnet/icmp.h b/jdk/src/java.base/windows/native/libnet/icmp.h deleted file mode 100644 index 50362555acb..00000000000 --- a/jdk/src/java.base/windows/native/libnet/icmp.h +++ /dev/null @@ -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 --git a/jdk/src/java.base/windows/native/libnet/net_util_md.c b/jdk/src/java.base/windows/native/libnet/net_util_md.c index 0afbe08b881..e0bd5681e33 100644 --- a/jdk/src/java.base/windows/native/libnet/net_util_md.c +++ b/jdk/src/java.base/windows/native/libnet/net_util_md.c @@ -22,12 +22,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - -#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 @@ NET_Timeout2(int fd, int fd1, long timeout, int *fdret) { 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 @@ NET_BindV6(struct ipv6bind *b, jboolean exclBind) { * 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 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr 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 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr 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 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr (*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 @@ NET_IsEqual(jbyte* caddr1, jbyte* caddr2) { } 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 --git a/jdk/src/java.base/windows/native/libnet/net_util_md.h b/jdk/src/java.base/windows/native/libnet/net_util_md.h index af598564482..96c122b33c5 100644 --- a/jdk/src/java.base/windows/native/libnet/net_util_md.h +++ b/jdk/src/java.base/windows/native/libnet/net_util_md.h @@ -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 @@ int #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 @@ int NET_GetDefaultTOS(void); typedef union { struct sockaddr sa; struct sockaddr_in sa4; - struct SOCKADDR_IN6 sa6; + struct sockaddr_in6 sa6; } SOCKETADDRESS; /* @@ -264,7 +75,7 @@ struct ipv6bind { #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 --git a/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXSurfaceData.java b/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXSurfaceData.java index a0fd6486cb5..e59e932a8fe 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXSurfaceData.java +++ b/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXSurfaceData.java @@ -74,8 +74,13 @@ public abstract class OSXSurfaceData extends BufImgSurfaceData { 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 @@ public abstract class OSXSurfaceData extends BufImgSurfaceData { @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 @@ public abstract class OSXSurfaceData extends BufImgSurfaceData { @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 @@ public abstract class OSXSurfaceData extends BufImgSurfaceData { @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 @@ public abstract class OSXSurfaceData extends BufImgSurfaceData { 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 @@ public abstract class OSXSurfaceData extends BufImgSurfaceData { } 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 @@ public abstract class OSXSurfaceData extends BufImgSurfaceData { 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 --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java index e8bfd053bfc..ea3bf9d010d 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java @@ -29,11 +29,9 @@ import sun.lwawt.LWWindowPeer; 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 @@ class CAccessibility implements PropertyChangeListener { } 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 @@ class CAccessibility implements PropertyChangeListener { 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 --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java index d3d3dca9538..06d481111e8 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java @@ -39,7 +39,10 @@ import javax.swing.event.ChangeListener; 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 @@ class CAccessible extends CFRetainedResource implements Accessible { 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 @@ class CAccessible extends CFRetainedResource implements Accessible { 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 --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java index 0fbdf00246c..c0280fe4caf 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java @@ -97,7 +97,7 @@ public class CEmbeddedFrame extends EmbeddedFrame { 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 --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java index 0283b05e5d8..de99473a176 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java @@ -44,6 +44,8 @@ final class CPlatformResponder { 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 @@ final class CPlatformResponder { */ 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 @@ final class CPlatformResponder { 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 --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformView.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformView.java index ee88f8f75ce..5dcf376646a 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformView.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformView.java @@ -194,7 +194,8 @@ public class CPlatformView extends CFRetainedResource { 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 --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java index a22f0c3d15e..2d54d62b799 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java @@ -178,12 +178,6 @@ public final class CPrinterJob extends RasterPrinterJob { 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 @@ public final class CPrinterJob extends RasterPrinterJob { @Override protected void finalize() { - if (fNSPrintInfo != -1) { - dispose(fNSPrintInfo); + synchronized (fNSPrintInfoLock) { + if (fNSPrintInfo != -1) { + dispose(fNSPrintInfo); + } + fNSPrintInfo = -1; } } diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSEvent.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSEvent.java index d39f559be22..5710988643d 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSEvent.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSEvent.java @@ -32,6 +32,13 @@ import java.awt.event.*; * 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 @@ final class NSEvent { private int y; private double scrollDeltaY; private double scrollDeltaX; + private int scrollPhase; private int absX; private int absY; @@ -62,7 +70,7 @@ final class NSEvent { // 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 @@ final class NSEvent { this.absY = absY; this.scrollDeltaY = scrollDeltaY; this.scrollDeltaX = scrollDeltaX; + this.scrollPhase = scrollPhase; } int getType() { @@ -107,6 +116,10 @@ final class NSEvent { return scrollDeltaX; } + int getScrollPhase() { + return scrollPhase; + } + int getAbsX() { return absX; } diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m index dfe3906bf90..208d22d69ff 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m @@ -383,7 +383,7 @@ static BOOL shouldUsePressAndHold() { } 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 @@ static BOOL shouldUsePressAndHold() { (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 --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m index 211be30d895..8b76294c32d 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m @@ -317,7 +317,7 @@ AWT_ASSERT_APPKIT_THREAD; [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 @@ AWT_ASSERT_APPKIT_THREAD; // 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 @@ AWT_ASSERT_APPKIT_THREAD; // 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 @@ AWT_ASSERT_APPKIT_THREAD; - (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 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowSt 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 @@ JNF_COCOA_ENTER(env); } else { [JNFException raise:env as:kIllegalArgumentException reason:"unknown event type"]; } - + JNF_COCOA_EXIT(env); } @@ -1476,7 +1478,7 @@ JNF_COCOA_ENTER(env); 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 --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobotKeyCode.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobotKeyCode.m index e75648d18b8..799887f187e 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobotKeyCode.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobotKeyCode.m @@ -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 --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m index 36d13667f55..0cc9e84eb0d 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m @@ -139,9 +139,9 @@ static NSSize ScaledImageSizeForStatusBar(NSSize imageSize, BOOL autosize) { 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 @@ static NSSize ScaledImageSizeForStatusBar(NSSize imageSize, BOOL autosize) { (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 --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m index ad2fce0e55b..5a91adf70b5 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m @@ -66,7 +66,6 @@ static JNF_CLASS_CACHE(sjc_CAccessible, "sun/lwawt/macosx/CAccessible"); 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 @@ static NSObject *sAttributeNamesLOCK = nil; 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 @@ static NSObject *sAttributeNamesLOCK = nil; + (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 @@ static NSObject *sAttributeNamesLOCK = nil; // 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 @@ static NSObject *sAttributeNamesLOCK = nil; 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 @@ static NSObject *sAttributeNamesLOCK = nil; return value; } + - (BOOL)accessibilityIsChildrenAttributeSettable { return NO; @@ -939,6 +973,13 @@ static NSObject *sAttributeNamesLOCK = nil; 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 @@ static NSObject *sAttributeNamesLOCK = nil; } return fNSRole; } + - (BOOL)accessibilityIsRoleAttributeSettable { return NO; @@ -1046,8 +1088,7 @@ static NSObject *sAttributeNamesLOCK = nil; - (NSString *)accessibilitySubroleAttribute { NSString *value = nil; - if ([[self javaRole] isEqualToString:@"passwordtext"]) - { + if ([[self javaRole] isEqualToString:@"passwordtext"]) { value = NSAccessibilitySecureTextFieldSubrole; } /* @@ -1123,6 +1164,45 @@ static NSObject *sAttributeNamesLOCK = nil; 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 @@ -1343,6 +1423,54 @@ JNF_COCOA_ENTER(env); JNF_COCOA_EXIT(env); } +/* + * 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 diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.h b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.h index 7c07c9d9689..c581cb45be1 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.h +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.h @@ -41,6 +41,7 @@ extern jint* gButtonDownMasks; @interface AWTToolkit : NSObject { } + (long) getEventCount; + (void) eventCountPlusPlus; ++ (jint) scrollStateWithEvent: (NSEvent*) event; @end /* diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m index 54253484173..41e966894ce 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m @@ -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 @@ static long eventCount; 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 --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h index a1899aff8d5..8d4a8a246b0 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h @@ -44,6 +44,8 @@ enum SDRenderType SD_Fill, SD_EOFill, SD_Shade, + SD_LinearGradient, + SD_RadialGradient, SD_Pattern, SD_Image, SD_Text, @@ -65,6 +67,17 @@ struct _stateShadingInfo }; 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 @@ struct _QuartzSDOps // 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 --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.m index 81441f4a327..01f24de6ec7 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.m @@ -268,9 +268,105 @@ PRINT(" gradientPaintReleaseFunction") 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 @@ PRINT(" SetUpCGContext") 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 @@ SDRenderType SetUpPaint(JNIEnv *env, QuartzSDOps *qsdo, SDRenderType renderType) 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 @@ PRINT(" CompleteCGContext") } 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 @@ PRINT(" CompleteCGContext") gradientPaintReleaseFunction(qsdo->shadingInfo); qsdo->shadingInfo = NULL; } + if (qsdo->gradientInfo != NULL) { + gradientPaintReleaseFunction(qsdo->gradientInfo); + qsdo->gradientInfo = NULL; + } } diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m index 548fd5015d6..d374e5a1241 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m @@ -193,6 +193,44 @@ GetFamilyNameForFontName(NSString* fontname) 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 @@ GetFilteredFonts() } } + /* + * 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 --git a/jdk/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m b/jdk/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m index 82619b70244..1eda7334665 100644 --- a/jdk/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m +++ b/jdk/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m @@ -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 @@ BOOL isSWTRunning() { } 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 @@ jboolean SplashGetScaledImageName(const char* jar, const char* file, 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 @@ SplashReconfigure(Splash * splash) { 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 --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java index 61b00538596..067b275ab25 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java @@ -1314,7 +1314,7 @@ class GIFImageWriteParam extends ImageWriteParam { super(locale); this.canWriteCompressed = true; this.canWriteProgressive = true; - this.compressionTypes = new String[] {"LZW", "lzw"}; + this.compressionTypes = new String[] {"LZW"}; this.compressionType = compressionTypes[0]; } diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java index 7e5c4701e11..82bfd92f92c 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java @@ -298,31 +298,24 @@ public class MotifComboBoxUI extends BasicComboBoxUI implements Serializable { public void paintIcon(Component c, Graphics g, int xo, int yo) { int w = getIconWidth(); int h = getIconHeight(); + int x1 = xo + w - 1; + int y1 = yo; + int x2 = xo + w / 2; + int y2 = yo + h - 1; + g.setColor(fill); + g.fillPolygon(new int[]{xo, x1, x2}, new int[]{yo, y1, y2}, 3); 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); - - 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.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 --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java index 4c8e33fcf87..99efe02a03d 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java @@ -249,17 +249,11 @@ public class MotifIconFactory implements Serializable 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 @@ public class MotifIconFactory implements Serializable 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 --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java index 680a658a6c6..cb586512c82 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java @@ -117,95 +117,57 @@ public class MotifScrollBarButton extends BasicArrowButton 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 --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AlawCodec.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AlawCodec.java index 30dd2e8d726..a585a2b93ce 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AlawCodec.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AlawCodec.java @@ -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.Objects; 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 @@ public final class AlawCodec extends SunCodec { } } + @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 --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java index d28729fd7c5..6dbbb338450 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java @@ -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 @@ public final class AudioFloatFormatConverter extends FormatConversionProvider { @Override public Encoding[] getTargetEncodings() { - return new Encoding[] { Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED, - Encoding.PCM_FLOAT }; + return getSourceEncodings(); } @Override diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java index f65351e31c8..27c7e1bc7f6 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java @@ -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 @@ final class DirectAudioDevice extends AbstractMixer { // $$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 --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/PCMtoPCMCodec.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/PCMtoPCMCodec.java index edb26d5c9a5..f623d7db60e 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/PCMtoPCMCodec.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/PCMtoPCMCodec.java @@ -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.Objects; 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 { +public final class PCMtoPCMCodec extends FormatConversionProvider { - private static final AudioFormat.Encoding[] inputEncodings = { - AudioFormat.Encoding.PCM_SIGNED, - AudioFormat.Encoding.PCM_UNSIGNED, - }; + @Override + public AudioFormat.Encoding[] getSourceEncodings() { + return new Encoding[]{Encoding.PCM_SIGNED, Encoding.PCM_UNSIGNED}; + } - private static final AudioFormat.Encoding[] outputEncodings = { - AudioFormat.Encoding.PCM_SIGNED, - AudioFormat.Encoding.PCM_UNSIGNED, - }; - - /** - * Constructs a new PCMtoPCM codec object. - */ - public PCMtoPCMCodec() { - - super( inputEncodings, outputEncodings); + @Override + public AudioFormat.Encoding[] getTargetEncodings() { + return getSourceEncodings(); } @Override diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftMixingClip.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftMixingClip.java index af3577493fe..020d32ed6c4 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftMixingClip.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftMixingClip.java @@ -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 @@ public final class SoftMixingClip extends SoftMixingDataLine implements Clip { 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 --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SunCodec.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SunCodec.java deleted file mode 100644 index a878d123e15..00000000000 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SunCodec.java +++ /dev/null @@ -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 --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/Toolkit.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/Toolkit.java index cc1d0a91c49..1b903a3bcf1 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/Toolkit.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/Toolkit.java @@ -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 @@ public final class Toolkit { 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 --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/UlawCodec.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/UlawCodec.java index 3d39395da9c..77564e86c27 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/UlawCodec.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/UlawCodec.java @@ -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.Objects; 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 @@ public final class UlawCodec extends SunCodec { } } - /** - * 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 --git a/jdk/src/java.desktop/share/classes/java/awt/Component.java b/jdk/src/java.desktop/share/classes/java/awt/Component.java index 228e14c93d2..05fbfabe80f 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/Component.java +++ b/jdk/src/java.desktop/share/classes/java/awt/Component.java @@ -851,8 +851,8 @@ public abstract class Component implements ImageObserver, MenuContainer, { 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 @@ public abstract class Component implements ImageObserver, MenuContainer, 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 @@ public abstract class Component implements ImageObserver, MenuContainer, 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 @@ public abstract class Component implements ImageObserver, MenuContainer, 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 --git a/jdk/src/java.desktop/share/classes/java/awt/DisplayMode.java b/jdk/src/java.desktop/share/classes/java/awt/DisplayMode.java index 3dafedb2be8..fd0d6f95be7 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/DisplayMode.java +++ b/jdk/src/java.desktop/share/classes/java/awt/DisplayMode.java @@ -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 @@ public final class DisplayMode { /** * {@inheritDoc} */ + @Override public boolean equals(Object dm) { if (dm instanceof DisplayMode) { return equals((DisplayMode)dm); @@ -153,9 +154,20 @@ public final class DisplayMode { /** * {@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 --git a/jdk/src/java.desktop/share/classes/java/awt/Font.java b/jdk/src/java.desktop/share/classes/java/awt/Font.java index 3e63e9af52f..18046fd9ea3 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/Font.java +++ b/jdk/src/java.desktop/share/classes/java/awt/Font.java @@ -154,6 +154,10 @@ import static sun.font.EAttribute.*; * 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 --git a/jdk/src/java.desktop/share/classes/java/awt/SplashScreen.java b/jdk/src/java.desktop/share/classes/java/awt/SplashScreen.java index 952a6dc5bf2..3992172adcc 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/SplashScreen.java +++ b/jdk/src/java.desktop/share/classes/java/awt/SplashScreen.java @@ -65,6 +65,16 @@ import sun.awt.image.SunWritableRaster; *

      * 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 --git a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataNode.java b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataNode.java index dd054ea90dc..f957d997b7d 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataNode.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataNode.java @@ -122,7 +122,7 @@ class IIONodeList implements NodeList { } 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 @@ public class IIOMetadataNode implements Element, NodeList { } private void getElementsByTagName(String name, List l) { - if (nodeName.equals(name)) { + if (nodeName.equals(name) || "*".equals(name)) { l.add(this); } diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/package.html b/jdk/src/java.desktop/share/classes/javax/imageio/package.html index f8254b11284..63d6dcfeb26 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/package.html +++ b/jdk/src/java.desktop/share/classes/javax/imageio/package.html @@ -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 @@ image format plug-ins: PNG metadata format - + - BMP + TIFF yes yes - none - - BMP metadata format + + TIFF plug-in notes + + TIFF metadata format @@ -94,16 +114,6 @@ image format plug-ins: WBMP metadata format - - - GIF - yes - yes - - GIF plug-in notes - - GIF metadata format -
    diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifGPSTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifGPSTagSet.java index 174eb7ae028..9b67e609fc3 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifGPSTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifGPSTagSet.java @@ -55,9 +55,7 @@ public final class ExifGPSTagSet extends TIFFTagSet { * * @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 --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java index 09871751388..3b274b8d978 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java @@ -71,9 +71,7 @@ public final class ExifTIFFTagSet extends TIFFTagSet { * * @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 @@ public final class ExifTIFFTagSet extends TIFFTagSet { * * @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 --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java index da9ade0d8f7..8ac2316d277 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java @@ -261,7 +261,7 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * @see TIFFDirectory * @see TIFFTag */ -public class TIFFField implements Cloneable { +public final class TIFFField implements Cloneable { private static final String[] typeNames = { null, diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java index 9c120d094ef..1b8821aef1c 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java @@ -48,7 +48,7 @@ import javax.imageio.ImageReadParam; * * @since 9 */ -public class TIFFImageReadParam extends ImageReadParam { +public final class TIFFImageReadParam extends ImageReadParam { private List allowedTagSets = new ArrayList(4); diff --git a/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/FormatConversionProvider.java b/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/FormatConversionProvider.java index 565db2d4a66..9860ad3d476 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/FormatConversionProvider.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/FormatConversionProvider.java @@ -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 @@ public abstract class FormatConversionProvider { * {@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 @@ public class JRootPane extends JComponent implements Accessible { } } - @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 --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java index 3ce2e8925f9..66d215b92b2 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java @@ -46,7 +46,11 @@ public abstract class TextUI extends ComponentUI * @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 @@ public abstract class TextUI extends ComponentUI * @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 @@ public abstract class TextUI extends ComponentUI * 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 @@ public abstract class TextUI extends ComponentUI * * @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 @@ public abstract class TextUI extends ComponentUI * @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 --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java index 64894fbb2b1..70020a002db 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java @@ -28,6 +28,8 @@ import java.util.*; 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 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { * @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 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { * @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 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { 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 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { * @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 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { * @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 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { 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 --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalBorders.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalBorders.java index edbd02bbbad..5461d7485b1 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalBorders.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalBorders.java @@ -739,7 +739,7 @@ public class MetalBorders { /** * 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 --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java index d1b3c1e2166..91132582193 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java @@ -923,7 +923,7 @@ public class MetalFileChooserUI extends BasicFileChooserUI { * @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 --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalScrollBarUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalScrollBarUI.java index cb4fbd72590..bb066e8aade 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalScrollBarUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalScrollBarUI.java @@ -62,7 +62,7 @@ public class MetalScrollBarUI extends BasicScrollBarUI /** * The metal bumps. */ - protected MetalBumps bumps; + private MetalBumps bumps; /** * The increase button. diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/multi/MultiTextUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/multi/MultiTextUI.java index f68984260a4..df57f0bbecc 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/multi/MultiTextUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/multi/MultiTextUI.java @@ -38,6 +38,8 @@ import javax.swing.plaf.ComponentUI; 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 @@ public class MultiTextUI extends TextUI { * * @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 @@ public class MultiTextUI extends TextUI { * * @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 @@ public class MultiTextUI extends TextUI { 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 @@ public class MultiTextUI extends TextUI { * @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 @@ public class MultiTextUI extends TextUI { 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 --git a/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter1.java b/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter1.java index c68aa094938..f1326cda127 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter1.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter1.java @@ -98,26 +98,27 @@ class GlyphPainter1 extends GlyphView.GlyphPainter { 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 @@ class GlyphPainter1 extends GlyphView.GlyphPainter { 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 --git a/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter2.java b/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter2.java index 17606d052e4..74e5b3eef1b 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter2.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter2.java @@ -145,8 +145,9 @@ class GlyphPainter2 extends GlyphView.GlyphPainter { // 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 --git a/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java b/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java index ff28193c3e8..4e06e866dcf 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java @@ -49,6 +49,8 @@ import java.awt.im.InputContext; 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,11 +1372,37 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * @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. @@ -1388,11 +1416,35 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * 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 diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/ParagraphView.java b/jdk/src/java.desktop/share/classes/javax/swing/text/ParagraphView.java index fc96021ccc3..5af2ebd3a3f 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/ParagraphView.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/ParagraphView.java @@ -27,6 +27,7 @@ package javax.swing.text; 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 @@ public class ParagraphView extends FlowView implements TabExpander { 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 --git a/jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java b/jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java index c5a4fed9146..dc65285e75c 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java @@ -26,7 +26,11 @@ package javax.swing.text; 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 @@ public class PasswordView extends FieldView { * @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 @@ public class PasswordView extends FieldView { } 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 @@ public class PasswordView extends FieldView { * @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 @@ public class PasswordView extends FieldView { * @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 @@ public class PasswordView extends FieldView { * 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 @@ public class PasswordView extends FieldView { } 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 --git a/jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java b/jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java index a4efd018508..8675436f610 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java @@ -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 @@ -60,17 +63,6 @@ public class PlainView extends View implements TabExpander { return size; } - /** - * 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 @@ -84,8 +76,16 @@ public class PlainView extends View implements TabExpander { * @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 @@ public class PlainView extends View implements TabExpander { * {@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 @@ public class PlainView extends View implements TabExpander { } 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 @@ public class PlainView extends View implements TabExpander { * @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 @@ public class PlainView extends View implements TabExpander { * 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 @@ public class PlainView extends View implements TabExpander { * @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 @@ public class PlainView extends View implements TabExpander { * @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 @@ public class PlainView extends View implements TabExpander { * 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 @@ public class PlainView extends View implements TabExpander { * @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 @@ public class PlainView extends View implements TabExpander { // 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 @@ public class PlainView extends View implements TabExpander { 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 @@ public class PlainView extends View implements TabExpander { 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 @@ public class PlainView extends View implements TabExpander { * 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 @@ public class PlainView extends View implements TabExpander { 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 @@ public class PlainView extends View implements TabExpander { 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 @@ public class PlainView extends View implements TabExpander { 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 @@ public class PlainView extends View implements TabExpander { 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 @@ public class PlainView extends View implements TabExpander { Font font; Segment lineBuffer; - int tabSize; + float tabSize; int tabBase; int sel0; @@ -796,4 +876,46 @@ public class PlainView extends View implements TabExpander { */ 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 --git a/jdk/src/java.desktop/share/classes/javax/swing/text/Utilities.java b/jdk/src/java.desktop/share/classes/javax/swing/text/Utilities.java index bf26227ed87..940abb47c2c 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/Utilities.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/Utilities.java @@ -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 @@ public class Utilities { * 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 @@ public class Utilities { * 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 @@ public class Utilities { 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 @@ public class Utilities { && 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 @@ public class Utilities { 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 @@ public class Utilities { } } 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 @@ public class Utilities { * 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 @@ public class Utilities { * 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 @@ public class Utilities { // 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) { - int nextX = x; + 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) + { + 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 @@ public class Utilities { 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 @@ public class Utilities { } 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 @@ public class Utilities { * 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 @@ public class Utilities { int startOffset, int[] justificationData) { return getTabbedTextOffset(view, s, metrics, x0, x, e, startOffset, true, - justificationData); + justificationData, false); } /** @@ -365,13 +414,19 @@ public class Utilities { * @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 @@ public class Utilities { * @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 @@ public class Utilities { 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 @@ public class Utilities { 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 @@ public class Utilities { )){ 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 @@ public class Utilities { 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 @@ public class Utilities { } 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 @@ public class Utilities { * 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 @@ public class Utilities { * 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 @@ public class Utilities { * @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 @@ public class Utilities { * @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 @@ public class Utilities { * @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 @@ public class Utilities { * @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 @@ public class Utilities { * @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 @@ public class Utilities { */ 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 @@ public class Utilities { 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 --git a/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java b/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java index dbcc5fdd207..5549317d95c 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java @@ -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) @@ -86,17 +90,6 @@ public class WrappedPlainView extends BoxView implements TabExpander { return size; } - /** - * 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 @@ -111,8 +104,17 @@ public class WrappedPlainView extends BoxView implements TabExpander { * @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 @@ public class WrappedPlainView extends BoxView implements TabExpander { * 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 @@ public class WrappedPlainView extends BoxView implements TabExpander { * @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 @@ public class WrappedPlainView extends BoxView implements TabExpander { } 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 @@ public class WrappedPlainView extends BoxView implements TabExpander { * @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 @@ public class WrappedPlainView extends BoxView implements TabExpander { * 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 @@ public class WrappedPlainView extends BoxView implements TabExpander { * @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 @@ public class WrappedPlainView extends BoxView implements TabExpander { * @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 @@ public class WrappedPlainView extends BoxView implements TabExpander { * 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 @@ public class WrappedPlainView extends BoxView implements TabExpander { * @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 @@ public class WrappedPlainView extends BoxView implements TabExpander { 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 class WrappedPlainView extends BoxView implements TabExpander { 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 @@ public class WrappedPlainView extends BoxView implements TabExpander { Segment lineBuffer; boolean widthChanging; int tabBase; - int tabSize; + float tabSize; boolean wordWrap; int sel0; @@ -668,6 +718,7 @@ public class WrappedPlainView extends BoxView implements TabExpander { 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 @@ public class WrappedPlainView extends BoxView implements TabExpander { : 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 @@ public class WrappedPlainView extends BoxView implements TabExpander { 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 --git a/jdk/src/java.desktop/share/classes/module-info.java b/jdk/src/java.desktop/share/classes/module-info.java index 93ab9a46aa2..0a49c8b981c 100644 --- a/jdk/src/java.desktop/share/classes/module-info.java +++ b/jdk/src/java.desktop/share/classes/module-info.java @@ -88,6 +88,9 @@ module java.desktop { 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 --git a/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java b/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java index f59f064c111..b20d8d62367 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java @@ -107,7 +107,7 @@ public final class AWTAccessor { /* * 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 @@ public final class AWTAccessor { AWTAccessor.dropTargetContextAccessor = accessor; } -} \ No newline at end of file +} diff --git a/jdk/src/java.desktop/share/classes/sun/awt/IconInfo.java b/jdk/src/java.desktop/share/classes/sun/awt/IconInfo.java index 4d3e04425f6..604780ff768 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/IconInfo.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/IconInfo.java @@ -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 @@ public class IconInfo { } this.scaledWidth = width; this.scaledHeight = height; - this.rawLength = getScaledRawLength(); + this.rawLength = getScaledRawLength(width, height); } /* @@ -112,14 +112,14 @@ public class IconInfo { 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 --git a/jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java b/jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java index b82f1833177..86b957398f7 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java @@ -142,8 +142,8 @@ public abstract class KeyboardFocusManagerPeerImpl implements KeyboardFocusManag } // 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 --git a/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java b/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java index 054c3edf825..f2a99711ff7 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java @@ -1512,9 +1512,9 @@ public abstract class SunToolkit extends Toolkit */ 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 @@ public abstract class SunToolkit extends Toolkit @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 --git a/jdk/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java b/jdk/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java index 90bf4d02389..2b48a58de01 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java @@ -30,6 +30,9 @@ import java.awt.Image; 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 @@ public abstract class ShellFolder extends File { 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 --git a/jdk/src/java.desktop/share/classes/sun/font/NullFontScaler.java b/jdk/src/java.desktop/share/classes/sun/font/NullFontScaler.java index 3e0ecb3a55d..c0f4197b829 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/NullFontScaler.java +++ b/jdk/src/java.desktop/share/classes/sun/font/NullFontScaler.java @@ -36,8 +36,8 @@ class NullFontScaler extends FontScaler { 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 @@ class NullFontScaler extends FontScaler { return getNullScalerContext(); } - void invalidateScalerContext(long ppScalerContext) { + void invalidateScalerContext(long pScalerContext) { //nothing to do } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java index 57b40d769d8..2fe223647f1 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java @@ -1902,11 +1902,7 @@ public final class SunGraphics2D 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 --git a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/Region.java b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/Region.java index e78d5f7a482..89c8418769d 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/Region.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/Region.java @@ -28,10 +28,13 @@ package sun.java2d.pipe; 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. @@ -117,6 +120,34 @@ public final class Region { return newv; } + /** + * 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 @@ -557,6 +588,33 @@ public final class Region { return getIntersectionXYXY(x, y, dimAdd(x, w), dimAdd(y, h)); } + /** + * 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 diff --git a/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java b/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java index ab67aae0154..74085dd91c3 100644 --- a/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java +++ b/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java @@ -30,6 +30,7 @@ import java.awt.*; 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 @@ public class SwingUtilities2 { 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 @@ public class SwingUtilities2 { 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 @@ public class SwingUtilities2 { } } - 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 @@ public class SwingUtilities2 { } } 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 @@ public class SwingUtilities2 { 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 --git a/jdk/src/java.desktop/share/classes/sun/swing/plaf/GTKKeybindings.java b/jdk/src/java.desktop/share/classes/sun/swing/plaf/GTKKeybindings.java index 9bfc09161fb..9c82a4fda90 100644 --- a/jdk/src/java.desktop/share/classes/sun/swing/plaf/GTKKeybindings.java +++ b/jdk/src/java.desktop/share/classes/sun/swing/plaf/GTKKeybindings.java @@ -219,6 +219,38 @@ public class GTKKeybindings { "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 --git a/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.c b/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.c index 77a00c0b675..fd7f1618734 100644 --- a/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.c +++ b/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.c @@ -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 @@ int SplashStreamInitMemory(SplashStream * pStream, void* pData, int size) { 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 --git a/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.h b/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.h index 1f2d2aed4b0..2ae624b3d1b 100644 --- a/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.h +++ b/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.h @@ -150,7 +150,9 @@ void SplashUpdateScreenData(Splash * splash); 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 --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java index 1a8fb48c24a..b708fa56753 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java @@ -301,7 +301,10 @@ abstract class XDecoratedPeer extends XWindowPeer { } 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 @@ abstract class XDecoratedPeer extends XWindowPeer { // 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 @@ abstract class XDecoratedPeer extends XWindowPeer { 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 @@ abstract class XDecoratedPeer extends XWindowPeer { winAttr.functions = fs; XWM.setShellResizable(this); } else if (isResizable() && !resizable) { - currentInsets = new Insets(0, 0, 0, 0); resetWMSetInsets(); if (!isEmbedded()) { setReparented(false); diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/Xrandr.h b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/Xrandr.h index aed7c54f9e7..d9d91c5862f 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/Xrandr.h +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/Xrandr.h @@ -118,6 +118,19 @@ typedef struct { 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 @@ XRROutputInfo * XRRGetOutputInfo (Display *dpy, XRRScreenResources *resources, 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 --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c index 7124f6127af..8d6b0642a1c 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c @@ -1667,6 +1667,11 @@ typedef XRROutputInfo * (*XRRGetOutputInfoType)(Display *dpy, 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 XRRGetScreenResourcesType awt_XRRGetScreenResources; 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 @@ X11GD_InitXrandrFuncs(JNIEnv *env) 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 @@ Java_sun_awt_X11GraphicsDevice_getCurrentDisplayMode 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 @@ Java_sun_awt_X11GraphicsDevice_enumDisplayModes 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 --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c index 7ce7fae60d5..66fba97d19a 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c @@ -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 --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h index b405e070f43..18e53496899 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h @@ -351,9 +351,6 @@ struct _GtkProgressBar 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 GList* (*fp_g_list_append) (GList *list, gpointer data); 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 --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c index df501fb338b..d0d09314063 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c @@ -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 @@ static void* dl_symbol(const char* name) 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 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name) 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 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name) 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 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name) dlclose(gtk3_libhandle); gtk3_libhandle = NULL; + dlclose(gthread_libhandle); + gthread_libhandle = NULL; + return NULL; } @@ -651,6 +671,7 @@ static int gtk3_unload() dlerror(); dlclose(gtk3_libhandle); + dlclose(gthread_libhandle); if ((gtk3_error = dlerror()) != NULL) { return FALSE; diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h index e39e172f7e5..a2021ff02b7 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h @@ -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 @@ typedef struct GtkApi { 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 --git a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XWindow.c b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XWindow.c index 9ac7ee12d67..797e56fe3f2 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XWindow.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XWindow.c @@ -818,6 +818,32 @@ isXKBenabled(Display *display) { } 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 @@ isKPevent(XEvent *event) */ 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 @@ handleKeyEventWithNumLockMask_New(XEvent *event, KeySym *keysym) } 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 @@ handleKeyEventWithNumLockMask(XEvent *event, KeySym *keysym) 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 @@ handleKeyEventWithNumLockMask(XEvent *event, KeySym *keysym) } } - /* 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 --git a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XlibWrapper.c b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XlibWrapper.c index c40200e5c6c..7fcb7771cbf 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XlibWrapper.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XlibWrapper.c @@ -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 @@ JNIEXPORT jboolean JNICALL Java_sun_awt_X11_XlibWrapper_IsXsunKPBehavior // 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 @@ JNIEXPORT void JNICALL Java_sun_awt_X11_XlibWrapper_XQueryKeymap 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 --git a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Taskbar.c b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Taskbar.c index 210f2de4da4..9b415476f83 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Taskbar.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/awt_Taskbar.c @@ -97,10 +97,7 @@ static gboolean unity_load() { 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 @@ JNIEXPORT void JNICALL Java_sun_awt_X11_XTaskbarPeer_setNativeMenu 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 --git a/jdk/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c b/jdk/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c index 30739f03a4e..c439e8f2240 100644 --- a/jdk/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c +++ b/jdk/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c @@ -753,6 +753,9 @@ SplashScreenThread(void *param) { 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 @@ SplashGetScaledImageName(const char* jarName, const char* fileName, 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 --git a/jdk/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c b/jdk/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c index 89ee3f476fb..bf516068f8d 100644 --- a/jdk/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c +++ b/jdk/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c @@ -535,6 +535,9 @@ SplashScreenThread(LPVOID param) 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 @@ SplashGetScaledImageName(const char* jarName, const char* fileName, *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 --git a/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java b/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java index e8f96449fae..7e8ec41d84f 100644 --- a/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java +++ b/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java @@ -1449,6 +1449,11 @@ public class LogManager { 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 --git a/jdk/src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java b/jdk/src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java index 5f8b1bde338..42b52f3ab3a 100644 --- a/jdk/src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java +++ b/jdk/src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java @@ -58,7 +58,8 @@ public class StackTraceElementCompositeData extends LazyCompositeData { 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 @@ public class StackTraceElementCompositeData extends LazyCompositeData { // 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 @@ public class StackTraceElementCompositeData extends LazyCompositeData { } // 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 --git a/jdk/src/java.rmi/share/classes/sun/rmi/server/Activation.java b/jdk/src/java.rmi/share/classes/sun/rmi/server/Activation.java index d1f73305a2d..a6ebbca80c0 100644 --- a/jdk/src/java.rmi/share/classes/sun/rmi/server/Activation.java +++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/Activation.java @@ -1970,6 +1970,11 @@ public class Activation implements Serializable { 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 --git a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java index 764abefb551..0fef27e34c6 100644 --- a/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java +++ b/jdk/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java @@ -102,6 +102,11 @@ public class TCPTransport extends Transport { 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 @@ public class TCPTransport extends Transport { 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 --git a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java index 6dc93773d7a..4a28198d309 100644 --- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java @@ -301,12 +301,13 @@ public class KrbApReq { 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 @@ public class KrbApReq { apReqMessg.ticket.sname.toString(), authenticator.ctime.getSeconds(), authenticator.cusec, + alg, new String(h)); rcache.checkAndStore(KerberosTime.now(), time); diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthTime.java b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthTime.java index 7183d7d5c05..695268735a9 100644 --- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthTime.java +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthTime.java @@ -116,14 +116,14 @@ public class AuthTime { 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 --git a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthTimeWithHash.java b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthTimeWithHash.java index 52bc8a8260b..a67daeb11fc 100644 --- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthTimeWithHash.java +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthTimeWithHash.java @@ -25,6 +25,8 @@ package sun.security.krb5.internal.rcache; +import sun.security.action.GetPropertyAction; + import java.util.Objects; /** @@ -34,14 +36,39 @@ import java.util.Objects; 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 @@ public class AuthTimeWithHash extends AuthTime 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 @@ -88,6 +116,19 @@ public class AuthTimeWithHash extends AuthTime return cmp; } + /** + * 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. @@ -112,7 +153,7 @@ public class AuthTimeWithHash extends AuthTime 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 --git a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java index 54fa34add04..2398c180133 100644 --- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java @@ -96,6 +96,8 @@ import sun.security.krb5.internal.ReplayCache; * 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 @@ public class DflCache extends ReplayCache { 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 --git a/jdk/src/java.sql/share/classes/java/sql/CallableStatement.java b/jdk/src/java.sql/share/classes/java/sql/CallableStatement.java index 5ba89c7a2ea..c54b63bdc3e 100644 --- a/jdk/src/java.sql/share/classes/java/sql/CallableStatement.java +++ b/jdk/src/java.sql/share/classes/java/sql/CallableStatement.java @@ -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 @@ public interface CallableStatement extends PreparedStatement { * or getBigDecimal(String parameterName) * @see #setBigDecimal */ - @Deprecated + @Deprecated(since="1.2") BigDecimal getBigDecimal(int parameterIndex, int scale) throws SQLException; diff --git a/jdk/src/java.sql/share/classes/java/sql/Date.java b/jdk/src/java.sql/share/classes/java/sql/Date.java index c74bffc4eb6..f784e72e1e3 100644 --- a/jdk/src/java.sql/share/classes/java/sql/Date.java +++ b/jdk/src/java.sql/share/classes/java/sql/Date.java @@ -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 @@ public class Date extends java.util.Date { * @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 @@ public class Date extends java.util.Date { * @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 @@ public class Date extends java.util.Date { * @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 @@ public class Date extends java.util.Date { * @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 @@ public class Date extends java.util.Date { * @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 @@ public class Date extends java.util.Date { * @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 @@ public class Date extends java.util.Date { * @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 --git a/jdk/src/java.sql/share/classes/java/sql/DriverManager.java b/jdk/src/java.sql/share/classes/java/sql/DriverManager.java index 5530fda159d..a32cf8f564d 100644 --- a/jdk/src/java.sql/share/classes/java/sql/DriverManager.java +++ b/jdk/src/java.sql/share/classes/java/sql/DriverManager.java @@ -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 @@ public class DriverManager { * @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 @@ public class DriverManager { * @deprecated Use {@code getLogWriter} * @see #setLogStream */ - @Deprecated + @Deprecated(since="1.2") public static java.io.PrintStream getLogStream() { return logStream; } diff --git a/jdk/src/java.sql/share/classes/java/sql/PreparedStatement.java b/jdk/src/java.sql/share/classes/java/sql/PreparedStatement.java index 10da0267563..efeb136dde3 100644 --- a/jdk/src/java.sql/share/classes/java/sql/PreparedStatement.java +++ b/jdk/src/java.sql/share/classes/java/sql/PreparedStatement.java @@ -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 @@ public interface PreparedStatement extends Statement { * this method * @deprecated Use {@code setCharacterStream} */ - @Deprecated + @Deprecated(since="1.2") void setUnicodeStream(int parameterIndex, java.io.InputStream x, int length) throws SQLException; diff --git a/jdk/src/java.sql/share/classes/java/sql/ResultSet.java b/jdk/src/java.sql/share/classes/java/sql/ResultSet.java index 656fa535528..4170b89de2d 100644 --- a/jdk/src/java.sql/share/classes/java/sql/ResultSet.java +++ b/jdk/src/java.sql/share/classes/java/sql/ResultSet.java @@ -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 @@ public interface ResultSet extends Wrapper, AutoCloseable { * @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 @@ public interface ResultSet extends Wrapper, AutoCloseable { * @deprecated use getCharacterStream in place of * getUnicodeStream */ - @Deprecated + @Deprecated(since="1.2") java.io.InputStream getUnicodeStream(int columnIndex) throws SQLException; /** @@ -646,7 +646,7 @@ public interface ResultSet extends Wrapper, AutoCloseable { * @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 @@ public interface ResultSet extends Wrapper, AutoCloseable { * this method * @deprecated use getCharacterStream instead */ - @Deprecated + @Deprecated(since="1.2") java.io.InputStream getUnicodeStream(String columnLabel) throws SQLException; /** diff --git a/jdk/src/java.sql/share/classes/java/sql/Time.java b/jdk/src/java.sql/share/classes/java/sql/Time.java index b5d9b5cbbde..f764e0a685c 100644 --- a/jdk/src/java.sql/share/classes/java/sql/Time.java +++ b/jdk/src/java.sql/share/classes/java/sql/Time.java @@ -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 @@ public class Time extends java.util.Date { * @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 @@ public class Time extends java.util.Date { * method is invoked * @see #setYear */ - @Deprecated + @Deprecated(since="1.2") public int getYear() { throw new java.lang.IllegalArgumentException(); } @@ -160,7 +160,7 @@ public class Time extends java.util.Date { * method is invoked * @see #setMonth */ - @Deprecated + @Deprecated(since="1.2") public int getMonth() { throw new java.lang.IllegalArgumentException(); } @@ -173,7 +173,7 @@ public class Time extends java.util.Date { * @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 @@ public class Time extends java.util.Date { * method is invoked * @see #setDate */ - @Deprecated + @Deprecated(since="1.2") public int getDate() { throw new java.lang.IllegalArgumentException(); } @@ -201,7 +201,7 @@ public class Time extends java.util.Date { * method is invoked * @see #getYear */ - @Deprecated + @Deprecated(since="1.2") public void setYear(int i) { throw new java.lang.IllegalArgumentException(); } @@ -215,7 +215,7 @@ public class Time extends java.util.Date { * method is invoked * @see #getMonth */ - @Deprecated + @Deprecated(since="1.2") public void setMonth(int i) { throw new java.lang.IllegalArgumentException(); } @@ -229,7 +229,7 @@ public class Time extends java.util.Date { * method is invoked * @see #getDate */ - @Deprecated + @Deprecated(since="1.2") public void setDate(int i) { throw new java.lang.IllegalArgumentException(); } diff --git a/jdk/src/java.sql/share/classes/java/sql/Timestamp.java b/jdk/src/java.sql/share/classes/java/sql/Timestamp.java index c1d36e39e82..9192ed7df1b 100644 --- a/jdk/src/java.sql/share/classes/java/sql/Timestamp.java +++ b/jdk/src/java.sql/share/classes/java/sql/Timestamp.java @@ -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 @@ public class Timestamp extends java.util.Date { * @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 --git a/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java b/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java index acd7323cd1b..34a3e2957e7 100644 --- a/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java +++ b/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java @@ -41,13 +41,13 @@ import javax.swing.plaf.TreeUI; 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 @@ final public class AccessBridge { 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 --git a/jdk/src/jdk.desktop/share/classes/jdk/awt/AWTUtils.java b/jdk/src/jdk.desktop/share/classes/jdk/awt/AWTUtils.java new file mode 100644 index 00000000000..93b493e6ccd --- /dev/null +++ b/jdk/src/jdk.desktop/share/classes/jdk/awt/AWTUtils.java @@ -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 --git a/langtools/test/tools/javac/diags/examples/XaddexportsTooMany.java b/jdk/src/jdk.desktop/share/classes/module-info.java similarity index 75% rename from langtools/test/tools/javac/diags/examples/XaddexportsTooMany.java rename to jdk/src/jdk.desktop/share/classes/module-info.java index 6fac72572e3..d02b6b4626c 100644 --- a/langtools/test/tools/javac/diags/examples/XaddexportsTooMany.java +++ b/jdk/src/jdk.desktop/share/classes/module-info.java @@ -4,7 +4,9 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * 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 @@ -21,8 +23,12 @@ * 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 +/* + * Provides non-SE desktop APIs. + */ -public class XaddexportsTooMany { +module jdk.desktop { + requires public java.desktop; + + exports jdk.awt; } diff --git a/jdk/src/jdk.editpad/share/classes/jdk/editpad/EditPad.java b/jdk/src/jdk.editpad/share/classes/jdk/editpad/EditPad.java new file mode 100644 index 00000000000..ee68f035dcf --- /dev/null +++ b/jdk/src/jdk.editpad/share/classes/jdk/editpad/EditPad.java @@ -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 --git a/jdk/src/jdk.editpad/share/classes/jdk/editpad/EditPadProvider.java b/jdk/src/jdk.editpad/share/classes/jdk/editpad/EditPadProvider.java new file mode 100644 index 00000000000..7956012f35f --- /dev/null +++ b/jdk/src/jdk.editpad/share/classes/jdk/editpad/EditPadProvider.java @@ -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 --git a/jdk/src/jdk.editpad/share/classes/jdk/editpad/resources/l10n.properties b/jdk/src/jdk.editpad/share/classes/jdk/editpad/resources/l10n.properties new file mode 100644 index 00000000000..ceff3a1543b --- /dev/null +++ b/jdk/src/jdk.editpad/share/classes/jdk/editpad/resources/l10n.properties @@ -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 --git a/jdk/src/jdk.editpad/share/classes/module-info.java b/jdk/src/jdk.editpad/share/classes/module-info.java new file mode 100644 index 00000000000..ddf4bee6212 --- /dev/null +++ b/jdk/src/jdk.editpad/share/classes/module-info.java @@ -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 --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ExternalEditor.java b/jdk/src/jdk.internal.ed/share/classes/jdk/internal/editor/external/ExternalEditor.java similarity index 72% rename from langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ExternalEditor.java rename to jdk/src/jdk.internal.ed/share/classes/jdk/internal/editor/external/ExternalEditor.java index 241972afff7..9e203e3a9ff 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ExternalEditor.java +++ b/jdk/src/jdk.internal.ed/share/classes/jdk/internal/editor/external/ExternalEditor.java @@ -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 @@ -23,7 +23,7 @@ * questions. */ -package jdk.internal.jshell.tool; +package jdk.internal.editor.external; import java.io.IOException; import java.nio.charset.Charset; @@ -47,22 +47,55 @@ import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; public class ExternalEditor { private final Consumer errorHandler; private final Consumer saveHandler; - private final Consumer printHandler; - private final IOContext input; 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; - ExternalEditor(Consumer errorHandler, Consumer saveHandler, - IOContext input, boolean wait, Consumer printHandler) { + /** + * 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.printHandler = printHandler; - this.input = input; this.wait = wait; + this.suspendInteractiveInput = suspendInteractiveInput; + this.resumeInteractiveInput = resumeInteractiveInput; + this.promptForNewLineToEndWait = promptForNewLineToEndWait; } private void edit(String[] cmd, String initialText) { @@ -79,7 +112,7 @@ public class ExternalEditor { */ private void setupWatch(String initialText) throws IOException { this.watcher = FileSystems.getDefault().newWatchService(); - this.dir = Files.createTempDirectory("jshelltemp"); + this.dir = Files.createTempDirectory("extedit"); this.tmpfile = Files.createTempFile(dir, null, ".java"); Files.write(tmpfile, initialText.getBytes(Charset.forName("UTF-8"))); dir.register(watcher, @@ -100,12 +133,7 @@ public class ExternalEditor { } 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(); - } + saveFile(); } boolean valid = key.reset(); @@ -125,13 +153,13 @@ public class ExternalEditor { pb = pb.inheritIO(); try { - input.suspend(); + 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); - printHandler.accept("jshell.msg.press.return.to.leave.edit.mode"); + promptForNewLineToEndWait.run(); scanner.nextLine(); } else { // wait for process to exit @@ -149,7 +177,7 @@ public class ExternalEditor { } catch (InterruptedException ex) { errorHandler.accept("process interrupt: " + ex.getMessage()); } finally { - input.resume(); + resumeInteractiveInput.run(); } } } @@ -161,10 +189,4 @@ public class ExternalEditor { 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 --git a/jdk/src/jdk.internal.ed/share/classes/jdk/internal/editor/spi/BuildInEditorProvider.java b/jdk/src/jdk.internal.ed/share/classes/jdk/internal/editor/spi/BuildInEditorProvider.java new file mode 100644 index 00000000000..1a4740f103e --- /dev/null +++ b/jdk/src/jdk.internal.ed/share/classes/jdk/internal/editor/spi/BuildInEditorProvider.java @@ -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 --git a/jdk/src/jdk.internal.ed/share/classes/module-info.java b/jdk/src/jdk.internal.ed/share/classes/module-info.java new file mode 100644 index 00000000000..f6beda70a0b --- /dev/null +++ b/jdk/src/jdk.internal.ed/share/classes/module-info.java @@ -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 --git a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java index 6aa65550140..28e0752fe0a 100644 --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java @@ -80,6 +80,7 @@ class Main { String fname, mname, ename; String zname = ""; String rootjar = null; + Set concealedPackages = new HashSet<>(); private static final int BASE_VERSION = 0; @@ -821,22 +822,21 @@ class Main { 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 @@ class Main { 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 @@ class Main { } jarEntries.add(name); - if (name.endsWith(".class") && !(name.startsWith(VERSIONS_DIR))) + if (name.endsWith(".class")) packages.add(toPackageName(name)); } } @@ -1761,6 +1761,13 @@ class Main { err.println(s); } + /** + * Print a warning message + */ + void warn(String s) { + err.println(s); + } + /** * Main routine to start program. */ @@ -1975,24 +1982,30 @@ class Main { 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 --git a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java index bf4fa8bf702..c3307e05613 100644 --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java @@ -152,9 +152,13 @@ final class Validator implements Consumer { 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 @@ final class Validator implements Consumer { // 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 @@ final class Validator implements Consumer { } 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 @@ final class Validator implements Consumer { 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 --git a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties index 78c81048b96..d43231e21d2 100644 --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties @@ -99,16 +99,19 @@ error.validator.isolated.nested.class=\ 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 --git a/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java b/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java index 629fdb86a45..fa93b015cfa 100644 --- a/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java +++ b/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java @@ -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 @@ public interface ObjectReference extends Value { * @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 --git a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java index f127f0c5e5d..1949a358214 100644 --- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java +++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java @@ -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 @@ public class ObjectReferenceImpl extends ValueImpl 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 --git a/jdk/src/jdk.jdi/share/classes/module-info.java b/jdk/src/jdk.jdi/share/classes/module-info.java index 14e621c108b..a7bd83d6fc2 100644 --- a/jdk/src/jdk.jdi/share/classes/module-info.java +++ b/jdk/src/jdk.jdi/share/classes/module-info.java @@ -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 @@ module jdk.jdi { 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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java index 5b19b2e3e2b..06d86a7653a 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java @@ -359,9 +359,9 @@ class JImageTask { 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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java index 0e2eb4b5342..0ff88bf1f3e 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java @@ -30,9 +30,11 @@ import java.io.InputStream; 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 @@ public abstract class JarArchive implements Archive { 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 @@ public abstract class JarArchive implements Archive { @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 @@ public abstract class JarArchive implements Archive { @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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java index 90ca7fb397a..bf7e9e03e55 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java @@ -33,7 +33,6 @@ import java.lang.module.ModuleFinder; 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.Path; 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.internal.ImagePluginStack.ImageProvider; 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 @@ import jdk.tools.jlink.plugin.Plugin; 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 @@ public class JlinkTask { }, "--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 @@ public class JlinkTask { /** * 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 @@ public class JlinkTask { 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 @@ public class JlinkTask { 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 @@ public class JlinkTask { 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 @@ public class JlinkTask { 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 @@ public class JlinkTask { } 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 @@ public class JlinkTask { 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 @@ public class JlinkTask { Set addMods, Set limitMods, ByteOrder order, - Path retainModulesPath) + Path retainModulesPath, + boolean ignoreSigning) throws IOException { if (addMods.isEmpty()) { @@ -373,10 +380,10 @@ public class JlinkTask { 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 @@ public class JlinkTask { } 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() - .map(e -> newArchive(e.getKey(), e.getValue())) - .collect(Collectors.toSet()); + 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()); } 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 @@ public class JlinkTask { } 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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java index 909fb141d1a..c4d78cc412c 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java @@ -54,13 +54,9 @@ public class ModularJarArchive extends JarArchive { @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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java index d8bad6bf4af..f5f74001d9c 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java @@ -47,8 +47,6 @@ import java.util.MissingResourceException; 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.Jlink.PluginsConfiguration; 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 @@ public final class TaskHelper { 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 @@ public final class TaskHelper { 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); } @@ -198,10 +199,20 @@ public final class TaskHelper { // to have the options parsed. }, "--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 @@ public final class TaskHelper { 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 @@ public final class TaskHelper { 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 @@ public final class TaskHelper { 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 @@ public final class TaskHelper { } 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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java index 115020953f3..00a90f2f13a 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java @@ -159,13 +159,6 @@ public final class GenerateJLIClassesPlugin implements Plugin { 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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties index 832304b48bb..556e0b20c66 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties @@ -62,6 +62,9 @@ main.opt.endian=\ 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.modulepath.must.be.specified:--module-path must be specified 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.option.unsupported={0} not supported: {1} 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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties index b990e2a6069..3fcda64dcda 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties @@ -74,12 +74,11 @@ where is \"man\" or \"headers". 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.resources-last-sorter=\ 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.no.value=\ 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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java index d5db2a00991..e0d071d634a 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java @@ -47,6 +47,7 @@ import java.lang.module.ResolutionException; 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.OptionSpec; 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 @@ public class JmodTask { 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 @@ public class JmodTask { 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 --git a/jdk/src/jdk.jsobject/share/classes/netscape/javascript/JSObject.java b/jdk/src/jdk.jsobject/share/classes/netscape/javascript/JSObject.java index c7a11bc5096..bdf551f310f 100644 --- a/jdk/src/jdk.jsobject/share/classes/netscape/javascript/JSObject.java +++ b/jdk/src/jdk.jsobject/share/classes/netscape/javascript/JSObject.java @@ -156,6 +156,7 @@ public abstract class JSObject { */ @Deprecated(since = "9") + @SuppressWarnings("exports") public static JSObject getWindow(Applet applet) throws JSException { return ProviderLoader.callGetWindow(applet); } diff --git a/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/BreakIteratorResources_th.java b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/BreakIteratorResources_th.java new file mode 100644 index 00000000000..ea1012df911 --- /dev/null +++ b/jdk/src/jdk.localedata/share/classes/sun/text/resources/ext/BreakIteratorResources_th.java @@ -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 --git a/jdk/src/jdk.unsupported/share/classes/sun/reflect/ReflectionFactory.java b/jdk/src/jdk.unsupported/share/classes/sun/reflect/ReflectionFactory.java index 7e3fa5c337b..6ac09603a12 100644 --- a/jdk/src/jdk.unsupported/share/classes/sun/reflect/ReflectionFactory.java +++ b/jdk/src/jdk.unsupported/share/classes/sun/reflect/ReflectionFactory.java @@ -84,6 +84,21 @@ public class ReflectionFactory { return soleInstance; } + /** + * 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 --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index d9cf01912cb..df850721454 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -134,8 +134,6 @@ java/lang/instrument/RetransformBigClass.sh 8065756 generic- 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/Basic.java 7158947 solaris- 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 @@ sun/security/ssl/SSLSocketImpl/AsyncSSLSocketClose.java 8161232 macosx-a ############################################################################ # 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 --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups index d24280a517b..def84c827b3 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -158,6 +158,7 @@ jdk_nio = \ jdk_net = \ java/net \ + -java/net/httpclient \ com/sun/net/httpserver \ sun/net \ jdk/net diff --git a/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java b/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java index acfda6042b7..6aebc550cf0 100644 --- a/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java +++ b/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java @@ -42,13 +42,8 @@ import java.util.HashMap; 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.ORB; 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 @@ import org.testng.TestNG; * @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 @@ public class ObjectStreamTest { 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 @@ public class ObjectStreamTest { * @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 @@ public class ObjectStreamTest { 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 @@ public class ObjectStreamTest { * 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 @@ public class ObjectStreamTest { /** * 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 @@ public class ObjectStreamTest { */ 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 @@ public class ObjectStreamTest { * @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 @@ public class ObjectStreamTest { * @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 @@ public class ObjectStreamTest { } /** - * 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 @@ public class ObjectStreamTest { 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 class ObjectStreamTest { 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 --git a/jdk/test/com/sun/jdi/InterfaceMethodsTest.java b/jdk/test/com/sun/jdi/InterfaceMethodsTest.java index 73a05dbf98e..953893b0d8a 100644 --- a/jdk/test/com/sun/jdi/InterfaceMethodsTest.java +++ b/jdk/test/com/sun/jdi/InterfaceMethodsTest.java @@ -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 @@ public class InterfaceMethodsTest extends TestScaffold { 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 @@ public class InterfaceMethodsTest extends TestScaffold { 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 @@ public class InterfaceMethodsTest extends TestScaffold { @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 @@ public class InterfaceMethodsTest extends TestScaffold { } private void testInterfaceA(ObjectReference ref) { - // Test non-virtual calls on InterfaceA 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 + /* Default method calls */ // invoke the InterfaceA's "defaultMethodA" @@ -185,39 +202,48 @@ public class InterfaceMethodsTest extends TestScaffold { // "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 @@ public class InterfaceMethodsTest extends TestScaffold { 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 @@ public class InterfaceMethodsTest extends TestScaffold { "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 @@ public class InterfaceMethodsTest extends TestScaffold { } } + // 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 @@ public class InterfaceMethodsTest extends TestScaffold { } 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 @@ public class InterfaceMethodsTest extends TestScaffold { if (virtual) { returnValue = invokeVirtual(ref, method); } else { - returnValue = invokeInstance(ref, method); + returnValue = invokeNonVirtual(ref, method); } } else { returnValue = invokeStatic(targetClass, method); @@ -387,7 +445,7 @@ public class InterfaceMethodsTest extends TestScaffold { } } - 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 @@ public class InterfaceMethodsTest extends TestScaffold { 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 --git a/jdk/test/com/sun/jndi/dns/Parser.java b/jdk/test/com/sun/jndi/dns/Parser.java index 4532ede3957..04846173875 100644 --- a/jdk/test/com/sun/jndi/dns/Parser.java +++ b/jdk/test/com/sun/jndi/dns/Parser.java @@ -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 --git a/jdk/test/com/sun/jndi/rmi/registry/RegistryContext/ContextWithNullProperties.java b/jdk/test/com/sun/jndi/rmi/registry/RegistryContext/ContextWithNullProperties.java index b980bb644c9..d8590f0682d 100644 --- a/jdk/test/com/sun/jndi/rmi/registry/RegistryContext/ContextWithNullProperties.java +++ b/jdk/test/com/sun/jndi/rmi/registry/RegistryContext/ContextWithNullProperties.java @@ -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 --git a/jdk/test/java/awt/FileDialog/8017487/bug8017487.java b/jdk/test/java/awt/FileDialog/8017487/bug8017487.java index f3c3fbcc025..78056762187 100644 --- a/jdk/test/java/awt/FileDialog/8017487/bug8017487.java +++ b/jdk/test/java/awt/FileDialog/8017487/bug8017487.java @@ -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 --git a/jdk/test/java/awt/Focus/RequestFocusByCause/RequestFocusByCauseTest.java b/jdk/test/java/awt/Focus/RequestFocusByCause/RequestFocusByCauseTest.java new file mode 100644 index 00000000000..4d17f46aa0a --- /dev/null +++ b/jdk/test/java/awt/Focus/RequestFocusByCause/RequestFocusByCauseTest.java @@ -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 --git a/jdk/test/java/awt/Frame/SetIconImagesCrashTest/SetIconImagesCrashTest.java b/jdk/test/java/awt/Frame/SetIconImagesCrashTest/SetIconImagesCrashTest.java new file mode 100644 index 00000000000..5140bf15a93 --- /dev/null +++ b/jdk/test/java/awt/Frame/SetIconImagesCrashTest/SetIconImagesCrashTest.java @@ -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 --git a/jdk/test/java/awt/FullScreen/CurrentDisplayModeTest/CurrentDisplayModeTest.java b/jdk/test/java/awt/FullScreen/CurrentDisplayModeTest/CurrentDisplayModeTest.java new file mode 100644 index 00000000000..6929372ba85 --- /dev/null +++ b/jdk/test/java/awt/FullScreen/CurrentDisplayModeTest/CurrentDisplayModeTest.java @@ -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 --git a/jdk/test/java/awt/Graphics/IncorrectFractionalClip/IncorrectFractionalClip.java b/jdk/test/java/awt/Graphics/IncorrectFractionalClip/IncorrectFractionalClip.java new file mode 100644 index 00000000000..b98b279e5ed --- /dev/null +++ b/jdk/test/java/awt/Graphics/IncorrectFractionalClip/IncorrectFractionalClip.java @@ -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 --git a/jdk/test/java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java b/jdk/test/java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java index b30d468f2ac..4fb0a2f583c 100644 --- a/jdk/test/java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java +++ b/jdk/test/java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java @@ -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 class SubMenuShowTest extends Applet { 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 @@ public class SubMenuShowTest extends Applet { }); 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 --git a/jdk/test/java/awt/List/ActionEventTest/ActionEventTest.java b/jdk/test/java/awt/List/ActionEventTest/ActionEventTest.java index a587e7be5d1..758f9ff479f 100644 --- a/jdk/test/java/awt/List/ActionEventTest/ActionEventTest.java +++ b/jdk/test/java/awt/List/ActionEventTest/ActionEventTest.java @@ -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 class ActionEventTest extends Frame { public ActionEventTest() { try { robot = new Robot(); + robot.setAutoDelay(100); + robot.setAutoWaitForIdle(true); } catch(AWTException e) { throw new RuntimeException(e.getMessage()); } @@ -56,7 +58,6 @@ public class ActionEventTest extends Frame { setLayout(new FlowLayout()); pack(); setVisible(true); - robot.waitForIdle(); } void performTest() { @@ -86,11 +87,9 @@ public class ActionEventTest extends Frame { // 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 --git a/jdk/test/java/awt/Modal/InvisibleParentTest/InvisibleParentTest.html b/jdk/test/java/awt/Modal/InvisibleParentTest/InvisibleParentTest.html deleted file mode 100644 index 4ef42910f55..00000000000 --- a/jdk/test/java/awt/Modal/InvisibleParentTest/InvisibleParentTest.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - InvisibleParentTest - - - -

    InvisibleParentTest
    Bug ID: 6401700, 6412803

    - -

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

    - - - - diff --git a/jdk/test/java/awt/Modal/InvisibleParentTest/InvisibleParentTest.java b/jdk/test/java/awt/Modal/InvisibleParentTest/InvisibleParentTest.java index 494369cd91a..d4d8ae3431f 100644 --- a/jdk/test/java/awt/Modal/InvisibleParentTest/InvisibleParentTest.java +++ b/jdk/test/java/awt/Modal/InvisibleParentTest/InvisibleParentTest.java @@ -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 extends Applet -{ - public void init() - { - setLayout(new BorderLayout()); +public class InvisibleParentTest { - 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 ); + 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); + + 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 { - setSize (200,200); - setVisible(true); - validate(); + mainFrame = new JFrame("InvisibleParentTest"); + mainFrame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE); - Component c = this; - while ((c != null) && !(c instanceof Window)) - { - c = c.getParent(); - } - if (c != null) - { - ((Window)c).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"; + + 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(); + + }); + + 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 --git a/jdk/test/java/awt/Robot/WaitForIdleSyncroizedOnString/WaitForIdleSyncroizedOnString.java b/jdk/test/java/awt/Robot/WaitForIdleSyncroizedOnString/WaitForIdleSyncroizedOnString.java new file mode 100644 index 00000000000..96cc7d62c4b --- /dev/null +++ b/jdk/test/java/awt/Robot/WaitForIdleSyncroizedOnString/WaitForIdleSyncroizedOnString.java @@ -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 --git a/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java b/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java index 31e496dc466..226bf78bf72 100644 --- a/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java +++ b/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java @@ -43,7 +43,7 @@ import sun.java2d.SunGraphics2D; /** * @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 @@ public class MultiResolutionSplashTest { 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 @@ public class MultiResolutionSplashTest { 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 @@ public class MultiResolutionSplashTest { 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 @@ public class MultiResolutionSplashTest { static void testFocus() throws Exception { - System.out.println("Focus Test!"); Robot robot = new Robot(); robot.setAutoDelay(50); @@ -150,18 +139,18 @@ public class MultiResolutionSplashTest { 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 class MultiResolutionSplashTest { 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 @@ public class MultiResolutionSplashTest { 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 class MultiResolutionSplashTest { 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 --git a/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java b/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java index bf836973223..26c4f728599 100644 --- a/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java +++ b/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java @@ -44,7 +44,7 @@ import java.util.Map; 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 @@ public class UnixMultiResolutionSplashTest { 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 @@ public class UnixMultiResolutionSplashTest { 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 --git a/jdk/test/java/awt/TrayIcon/DragEventSource/DragEventSource.java b/jdk/test/java/awt/TrayIcon/DragEventSource/DragEventSource.java index 8a669c82e70..4f315f5e590 100644 --- a/jdk/test/java/awt/TrayIcon/DragEventSource/DragEventSource.java +++ b/jdk/test/java/awt/TrayIcon/DragEventSource/DragEventSource.java @@ -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 @@ public class DragEventSource 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 --git a/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java b/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java index 585097abddc..453b4677145 100644 --- a/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java +++ b/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java @@ -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 @@ import java.awt.image.BufferedImage; /* * @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 @@ public class TrayIconEventModifiersTest { mousePressed = false; robot.keyPress(keyTypes[j]); + robot.waitForIdle(); robot.mousePress(buttonTypes[i]); if (! mousePressed) { diff --git a/jdk/test/java/awt/Window/ChangeWindowResizabilty/ChangeWindowResizabiltyTest.java b/jdk/test/java/awt/Window/ChangeWindowResizabilty/ChangeWindowResizabiltyTest.java new file mode 100644 index 00000000000..f2e0e95273e --- /dev/null +++ b/jdk/test/java/awt/Window/ChangeWindowResizabilty/ChangeWindowResizabiltyTest.java @@ -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 --git a/jdk/test/java/awt/event/KeyEvent/RobotCrash/RobotCrash.java b/jdk/test/java/awt/event/KeyEvent/RobotCrash/RobotCrash.java new file mode 100644 index 00000000000..c8556041acf --- /dev/null +++ b/jdk/test/java/awt/event/KeyEvent/RobotCrash/RobotCrash.java @@ -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 --git a/jdk/test/java/awt/jdk/TestJDKAWTUtils.java b/jdk/test/java/awt/jdk/TestJDKAWTUtils.java new file mode 100644 index 00000000000..6f0439cc11a --- /dev/null +++ b/jdk/test/java/awt/jdk/TestJDKAWTUtils.java @@ -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 --git a/jdk/test/java/awt/print/PrinterJob/LinearGradientPrintingTest.java b/jdk/test/java/awt/print/PrinterJob/LinearGradientPrintingTest.java new file mode 100644 index 00000000000..ab1ab17aa7f --- /dev/null +++ b/jdk/test/java/awt/print/PrinterJob/LinearGradientPrintingTest.java @@ -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 --git a/jdk/test/java/awt/print/PrinterJob/RadialGradientPrintingTest.java b/jdk/test/java/awt/print/PrinterJob/RadialGradientPrintingTest.java new file mode 100644 index 00000000000..61c9faeda24 --- /dev/null +++ b/jdk/test/java/awt/print/PrinterJob/RadialGradientPrintingTest.java @@ -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 --git a/jdk/test/java/awt/security/WarningWindowDisposeTest/WarningWindowDisposeTest.java b/jdk/test/java/awt/security/WarningWindowDisposeTest/WarningWindowDisposeTest.java index 3f525e967d9..7eaa578df29 100644 --- a/jdk/test/java/awt/security/WarningWindowDisposeTest/WarningWindowDisposeTest.java +++ b/jdk/test/java/awt/security/WarningWindowDisposeTest/WarningWindowDisposeTest.java @@ -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 class WarningWindowDisposeTest { 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 --git a/jdk/test/java/io/FilePermission/FilePermissionCollectionMerge.java b/jdk/test/java/io/FilePermission/FilePermissionCollectionMerge.java new file mode 100644 index 00000000000..c85be3d6fde --- /dev/null +++ b/jdk/test/java/io/FilePermission/FilePermissionCollectionMerge.java @@ -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 --git a/jdk/test/java/io/FilePermission/Invalid.java b/jdk/test/java/io/FilePermission/Invalid.java new file mode 100644 index 00000000000..38c6a98b46c --- /dev/null +++ b/jdk/test/java/io/FilePermission/Invalid.java @@ -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 --git a/jdk/test/java/io/Serializable/serialFilter/SerialFilterTest.java b/jdk/test/java/io/Serializable/serialFilter/SerialFilterTest.java index f3e2cebabb5..9a3bc88d586 100644 --- a/jdk/test/java/io/Serializable/serialFilter/SerialFilterTest.java +++ b/jdk/test/java/io/Serializable/serialFilter/SerialFilterTest.java @@ -40,7 +40,7 @@ import java.util.Hashtable; 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 @@ public class SerialFilterTest implements Serializable { 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 @@ public class SerialFilterTest implements Serializable { 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 --git a/jdk/test/java/lang/ClassLoader/IsParallelCapable.java b/jdk/test/java/lang/ClassLoader/IsParallelCapable.java new file mode 100644 index 00000000000..14432488b20 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/IsParallelCapable.java @@ -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 --git a/jdk/test/java/lang/ClassLoader/platformClassLoader/DefinePlatformClass.java b/jdk/test/java/lang/ClassLoader/platformClassLoader/DefinePlatformClass.java index d02c483ce38..826b381f138 100644 --- a/jdk/test/java/lang/ClassLoader/platformClassLoader/DefinePlatformClass.java +++ b/jdk/test/java/lang/ClassLoader/platformClassLoader/DefinePlatformClass.java @@ -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 --git a/jdk/test/java/lang/ProcessBuilder/Basic.java b/jdk/test/java/lang/ProcessBuilder/Basic.java index e17e28865e4..c04e085ef43 100644 --- a/jdk/test/java/lang/ProcessBuilder/Basic.java +++ b/jdk/test/java/lang/ProcessBuilder/Basic.java @@ -2404,16 +2404,6 @@ public class Basic { 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 --git a/jdk/test/java/lang/StackTraceElement/PublicConstructor.java b/jdk/test/java/lang/StackTraceElement/PublicConstructor.java index b4ec9a4d47c..254be7825f7 100644 --- a/jdk/test/java/lang/StackTraceElement/PublicConstructor.java +++ b/jdk/test/java/lang/StackTraceElement/PublicConstructor.java @@ -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 --git a/jdk/test/java/lang/StackTraceElement/SerialTest.java b/jdk/test/java/lang/StackTraceElement/SerialTest.java new file mode 100644 index 00000000000..2cd409d58b8 --- /dev/null +++ b/jdk/test/java/lang/StackTraceElement/SerialTest.java @@ -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 --git a/jdk/test/java/lang/StackTraceElement/WithClassLoaderName.java b/jdk/test/java/lang/StackTraceElement/WithClassLoaderName.java new file mode 100644 index 00000000000..85f21555b4d --- /dev/null +++ b/jdk/test/java/lang/StackTraceElement/WithClassLoaderName.java @@ -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 --git a/jdk/test/java/lang/StackTraceElement/lib/m1/com/app/Main.java b/jdk/test/java/lang/StackTraceElement/lib/m1/com/app/Main.java new file mode 100644 index 00000000000..4ae77d6404f --- /dev/null +++ b/jdk/test/java/lang/StackTraceElement/lib/m1/com/app/Main.java @@ -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 --git a/jdk/test/java/lang/StackTraceElement/lib/m1/com/app/Utils.java b/jdk/test/java/lang/StackTraceElement/lib/m1/com/app/Utils.java new file mode 100644 index 00000000000..4c571af6833 --- /dev/null +++ b/jdk/test/java/lang/StackTraceElement/lib/m1/com/app/Utils.java @@ -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 --git a/langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/modulesourcepath/m/p1/C1.java b/jdk/test/java/lang/StackTraceElement/lib/m1/module-info.java similarity index 94% rename from langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/modulesourcepath/m/p1/C1.java rename to jdk/test/java/lang/StackTraceElement/lib/m1/module-info.java index ac25babd764..15d878b13cc 100644 --- a/langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/modulesourcepath/m/p1/C1.java +++ b/jdk/test/java/lang/StackTraceElement/lib/m1/module-info.java @@ -21,8 +21,6 @@ * questions. */ -package p1; - -public class C1 { - public class InnerDefinition {} +module m1 { + exports com.app; } diff --git a/langtools/test/tools/javac/diags/examples/XaddreadsTooMany.java b/jdk/test/java/lang/StackTraceElement/src/p/ThrowException.java similarity index 86% rename from langtools/test/tools/javac/diags/examples/XaddreadsTooMany.java rename to jdk/test/java/lang/StackTraceElement/src/p/ThrowException.java index 11560450da0..19e32f79e94 100644 --- a/langtools/test/tools/javac/diags/examples/XaddreadsTooMany.java +++ b/jdk/test/java/lang/StackTraceElement/src/p/ThrowException.java @@ -21,8 +21,12 @@ * questions. */ -// key: compiler.err.xaddreads.too.many -// options: --add-reads jdk.compiler=ALL-UNNAMED --add-reads jdk.compiler=ALL-UNNAMED +package p; -public class XaddreadsTooMany { +import java.lang.StackWalker.StackFrame; + +public class ThrowException { + public static void throwError() { + throw new Error("testing"); + } } diff --git a/jdk/test/java/lang/StackWalker/VerifyStackTrace.java b/jdk/test/java/lang/StackWalker/VerifyStackTrace.java index 704a807bc57..679bf4b86d6 100644 --- a/jdk/test/java/lang/StackWalker/VerifyStackTrace.java +++ b/jdk/test/java/lang/StackWalker/VerifyStackTrace.java @@ -71,7 +71,7 @@ public class VerifyStackTrace { "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 @@ public class VerifyStackTrace { "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 @@ public class VerifyStackTrace { "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 @@ public class VerifyStackTrace { // 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 --git a/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java b/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java new file mode 100644 index 00000000000..28bca5cf39c --- /dev/null +++ b/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java @@ -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 --git a/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/systempkg/log/SystemLoggerAccessor.java b/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/systempkg/log/SystemLoggerAccessor.java new file mode 100644 index 00000000000..8defec1a205 --- /dev/null +++ b/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/systempkg/log/SystemLoggerAccessor.java @@ -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 --git a/jdk/test/java/lang/annotation/AnnotationToStringTest.java b/jdk/test/java/lang/annotation/AnnotationToStringTest.java index ffcbcb4229d..e4eccacf5ce 100644 --- a/jdk/test/java/lang/annotation/AnnotationToStringTest.java +++ b/jdk/test/java/lang/annotation/AnnotationToStringTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8162817 + * @bug 8162817 8168921 * @summary Test of toString on normal annotations */ @@ -70,6 +70,8 @@ public class AnnotationToStringTest { "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 @@ public class AnnotationToStringTest { 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 class AnnotationToStringTest { 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 @@ class Obj {} double d1(); long l0(); long l1(); + long l2(); + long l3(); String s0(); String s1(); Class class0(); diff --git a/jdk/test/java/lang/instrument/DaemonThread/TestDaemonThreadLauncher.java b/jdk/test/java/lang/instrument/DaemonThread/TestDaemonThreadLauncher.java index 579db8d6e75..2bf3e6fd687 100644 --- a/jdk/test/java/lang/instrument/DaemonThread/TestDaemonThreadLauncher.java +++ b/jdk/test/java/lang/instrument/DaemonThread/TestDaemonThreadLauncher.java @@ -29,7 +29,7 @@ import jdk.testlibrary.ProcessTools; 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 --git a/jdk/test/java/lang/invoke/LoopCombinatorTest.java b/jdk/test/java/lang/invoke/LoopCombinatorTest.java index 1e8b8a8f9a7..fa11affa45c 100644 --- a/jdk/test/java/lang/invoke/LoopCombinatorTest.java +++ b/jdk/test/java/lang/invoke/LoopCombinatorTest.java @@ -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 @@ public class LoopCombinatorTest { {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 --git a/jdk/test/java/lang/management/CompositeData/ThreadInfoCompositeData.java b/jdk/test/java/lang/management/CompositeData/ThreadInfoCompositeData.java index 80ca1c41540..1a84226360e 100644 --- a/jdk/test/java/lang/management/CompositeData/ThreadInfoCompositeData.java +++ b/jdk/test/java/lang/management/CompositeData/ThreadInfoCompositeData.java @@ -337,9 +337,10 @@ public class ThreadInfoCompositeData { }; private static final String[] steItemNames = { - "className", + "classLoaderName", "moduleName", "moduleVersion", + "className", "methodName", "fileName", "lineNumber", @@ -362,9 +363,10 @@ public class ThreadInfoCompositeData { 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 --git a/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest.java b/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest.java index 8e3c2e55a3f..6d4fae0b632 100644 --- a/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest.java +++ b/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest.java @@ -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 --git a/jdk/test/java/lang/module/AutomaticModulesTest.java b/jdk/test/java/lang/module/AutomaticModulesTest.java index 680a727127e..3ad04a2a943 100644 --- a/jdk/test/java/lang/module/AutomaticModulesTest.java +++ b/jdk/test/java/lang/module/AutomaticModulesTest.java @@ -158,39 +158,84 @@ public class AutomaticModulesTest { */ 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"); - - Set exports - = m1.exports().stream().map(Exports::source).collect(Collectors.toSet()); + assertTrue(descriptor.packages().size() == 2); + assertTrue(descriptor.packages().contains("p")); + assertTrue(descriptor.packages().contains("q")); + 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 file in JAR file where the entry does not correspond to a + * Test class files in JAR file where the entry does not correspond to a * legal package name. */ - @Test(expectedExceptions = FindException.class) public void testBadPackage() throws IOException { Path dir = Files.createTempDirectory(USER_DIR, "mods"); - createDummyJarFile(dir.resolve("m1.jar"), "p-/T.class"); + createDummyJarFile(dir.resolve("m.jar"), "p/C1.class", "p-/C2.class"); - // should throw FindException - ModuleFinder.of(dir).findAll(); + 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 unnamed package (top-level directory) + */ + @Test(expectedExceptions = FindException.class) + public void testClassInUnnamedPackage() throws IOException { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + 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 @@ public class AutomaticModulesTest { 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 @@ public class AutomaticModulesTest { } - // 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 @@ public class AutomaticModulesTest { * 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 @@ public class AutomaticModulesTest { 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 --git a/jdk/test/java/lang/module/ModuleFinderTest.java b/jdk/test/java/lang/module/ModuleFinderTest.java index 58c2ae56334..9a79a5757de 100644 --- a/jdk/test/java/lang/module/ModuleFinderTest.java +++ b/jdk/test/java/lang/module/ModuleFinderTest.java @@ -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.lang.module.ModuleReference; 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; @@ -316,6 +318,111 @@ public class ModuleFinderTest { } + /** + * 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. */ @@ -641,7 +748,7 @@ public class ModuleFinderTest { 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 @@ public class ModuleFinderTest { * 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 --git a/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java b/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java index 139a56871b9..63c4c7404e0 100644 --- a/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java +++ b/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java @@ -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.Files; 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 @@ public class ModuleReaderTest { /** * 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 @@ public class ModuleReaderTest { testFind(reader, name, expectedBytes); testOpen(reader, name, expectedBytes); testRead(reader, name, expectedBytes); + testList(reader, name); } @@ -168,7 +171,7 @@ public class ModuleReaderTest { /** * Test ModuleReader to exploded module */ - public void testExplodedModule() throws Exception { + public void testExplodedModule() throws IOException { test(MODS_DIR); } @@ -176,7 +179,7 @@ public class ModuleReaderTest { /** * 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 @@ public class ModuleReaderTest { /** * 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 @@ public class ModuleReaderTest { * 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 @@ public class ModuleReaderTest { testFind(reader, name, expectedBytes); testOpen(reader, name, expectedBytes); testRead(reader, name, expectedBytes); + testList(reader, name); } // test "not found" @@ -275,13 +276,18 @@ public class ModuleReaderTest { 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 @@ public class ModuleReaderTest { * 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 @@ public class ModuleReaderTest { * 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 @@ public class ModuleReaderTest { } } + /** + * 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 --git a/jdk/test/java/lang/module/ModuleReader/MultiReleaseJarTest.java b/jdk/test/java/lang/module/ModuleReader/MultiReleaseJarTest.java deleted file mode 100644 index 4bb6ceaf34f..00000000000 --- a/jdk/test/java/lang/module/ModuleReader/MultiReleaseJarTest.java +++ /dev/null @@ -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 --git a/jdk/test/java/lang/module/MultiReleaseJarTest.java b/jdk/test/java/lang/module/MultiReleaseJarTest.java new file mode 100644 index 00000000000..ad982650334 --- /dev/null +++ b/jdk/test/java/lang/module/MultiReleaseJarTest.java @@ -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 --git a/jdk/test/java/net/URLClassLoader/NullURLTest.java b/jdk/test/java/net/URLClassLoader/NullURLTest.java index 4171a4f6735..2666bb0ae9c 100644 --- a/jdk/test/java/net/URLClassLoader/NullURLTest.java +++ b/jdk/test/java/net/URLClassLoader/NullURLTest.java @@ -109,7 +109,7 @@ public class NullURLTest { 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 --git a/jdk/test/java/net/URLPermission/nstest/LookupTest.java b/jdk/test/java/net/URLPermission/nstest/LookupTest.java index eebcff5249f..af36132672c 100644 --- a/jdk/test/java/net/URLPermission/nstest/LookupTest.java +++ b/jdk/test/java/net/URLPermission/nstest/LookupTest.java @@ -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 ioe) { + } catch (IOException e) { if (!throwsIOException) { - throw new RuntimeException ("(2) was not expecting ", ioe); + System.err.println("Unexpected IOException:" + e.getMessage()); + throw new RuntimeException(e); } return; + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + System.err.println("Unexpected IOException:" + e.getMessage()); + throw new RuntimeException(e); + } + } } + 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; + + 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(); } - } - } + } - static void startServer() { - try { - serverSocket = new ServerSocket(port); - server = new Server(); - server.start(); - } catch (Exception e) { - throw new RuntimeException ("Test failed to initialize", e); + void terminate() { + done = true; + try { serverSocket.close(); } + catch (IOException unexpected) { unexpected.printStackTrace(); } + } + + static final byte[] requestEnd = new byte[] {'\r', '\n', '\r', '\n' }; + + // 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 --git a/jdk/test/java/net/URLPermission/nstest/lookup.sh b/jdk/test/java/net/URLPermission/nstest/lookup.sh deleted file mode 100644 index a6b495c9f35..00000000000 --- a/jdk/test/java/net/URLPermission/nstest/lookup.sh +++ /dev/null @@ -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 --git a/jdk/test/java/net/httpclient/APIErrors.java b/jdk/test/java/net/httpclient/APIErrors.java index 6ac31c50978..fdda70fafb4 100644 --- a/jdk/test/java/net/httpclient/APIErrors.java +++ b/jdk/test/java/net/httpclient/APIErrors.java @@ -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 --git a/jdk/test/java/net/httpclient/ManyRequests.java b/jdk/test/java/net/httpclient/ManyRequests.java index 60d641e8f37..9584fa50e58 100644 --- a/jdk/test/java/net/httpclient/ManyRequests.java +++ b/jdk/test/java/net/httpclient/ManyRequests.java @@ -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.Arrays; 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 --git a/jdk/test/java/net/httpclient/RequestBodyTest.java b/jdk/test/java/net/httpclient/RequestBodyTest.java index 9347ef65619..72d60395c38 100644 --- a/jdk/test/java/net/httpclient/RequestBodyTest.java +++ b/jdk/test/java/net/httpclient/RequestBodyTest.java @@ -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 --git a/jdk/test/java/net/httpclient/SmokeTest.java b/jdk/test/java/net/httpclient/SmokeTest.java index 93a864d8fad..26348344b87 100644 --- a/jdk/test/java/net/httpclient/SmokeTest.java +++ b/jdk/test/java/net/httpclient/SmokeTest.java @@ -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 --git a/jdk/test/java/net/httpclient/security/Driver.java b/jdk/test/java/net/httpclient/security/Driver.java index 802826ed89e..dedcf3542e4 100644 --- a/jdk/test/java/net/httpclient/security/Driver.java +++ b/jdk/test/java/net/httpclient/security/Driver.java @@ -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 --git a/jdk/test/java/net/httpclient/security/Security.java b/jdk/test/java/net/httpclient/security/Security.java index 5c282be9a36..e7696f3c42a 100644 --- a/jdk/test/java/net/httpclient/security/Security.java +++ b/jdk/test/java/net/httpclient/security/Security.java @@ -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.Paths; 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 --git a/jdk/test/java/net/ipv6tests/Tests.java b/jdk/test/java/net/ipv6tests/Tests.java index a0d78fa9c56..95a20245562 100644 --- a/jdk/test/java/net/ipv6tests/Tests.java +++ b/jdk/test/java/net/ipv6tests/Tests.java @@ -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 @@ public class Tests { /* 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 --git a/jdk/test/java/net/ipv6tests/UdpTest.java b/jdk/test/java/net/ipv6tests/UdpTest.java index c5272157c85..4b3f9b02700 100644 --- a/jdk/test/java/net/ipv6tests/UdpTest.java +++ b/jdk/test/java/net/ipv6tests/UdpTest.java @@ -24,7 +24,6 @@ /* * @test * @bug 4868820 - * @key intermittent * @summary IPv6 support for Windows XP and 2003 server */ @@ -159,7 +158,7 @@ public class UdpTest extends Tests { }); 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 --git a/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java b/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java index 32e07a4b796..85e22e4bea0 100644 --- a/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java +++ b/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java @@ -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 @@ public class CheckActivateRef // start an rmid. RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff --git a/jdk/test/java/rmi/activation/Activatable/checkActivateRef/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/checkActivateRef/rmid.security.policy index d6b78e552ef..cdf9ca15fae 100644 --- a/jdk/test/java/rmi/activation/Activatable/checkActivateRef/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/checkActivateRef/rmid.security.policy @@ -2,4 +2,6 @@ grant { 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 --git a/jdk/test/java/rmi/activation/Activatable/checkActivateRef/security.policy b/jdk/test/java/rmi/activation/Activatable/checkActivateRef/security.policy index d847e377e90..e36b0a0a19e 100644 --- a/jdk/test/java/rmi/activation/Activatable/checkActivateRef/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/checkActivateRef/security.policy @@ -38,4 +38,6 @@ grant { 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 --git a/jdk/test/java/rmi/activation/Activatable/checkAnnotations/CheckAnnotations.java b/jdk/test/java/rmi/activation/Activatable/checkAnnotations/CheckAnnotations.java index e99f62faba9..a5a69a5c88c 100644 --- a/jdk/test/java/rmi/activation/Activatable/checkAnnotations/CheckAnnotations.java +++ b/jdk/test/java/rmi/activation/Activatable/checkAnnotations/CheckAnnotations.java @@ -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 @@ public class CheckAnnotations // 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 @@ public class CheckAnnotations 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 --git a/jdk/test/java/rmi/activation/Activatable/checkAnnotations/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/checkAnnotations/rmid.security.policy index 0e43c5d37ab..ca4b8e244d9 100644 --- a/jdk/test/java/rmi/activation/Activatable/checkAnnotations/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/checkAnnotations/rmid.security.policy @@ -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 --git a/jdk/test/java/rmi/activation/Activatable/checkAnnotations/security.policy b/jdk/test/java/rmi/activation/Activatable/checkAnnotations/security.policy index 572e29ce309..ef36478e900 100644 --- a/jdk/test/java/rmi/activation/Activatable/checkAnnotations/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/checkAnnotations/security.policy @@ -28,4 +28,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/CheckImplClassLoader.java b/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/CheckImplClassLoader.java index 46cadd1fd45..f01bcad60b1 100644 --- a/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/CheckImplClassLoader.java +++ b/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/CheckImplClassLoader.java @@ -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 @@ public class CheckImplClassLoader { TestParams.defaultSecurityManager); RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); System.err.println("Create activation group in this VM"); diff --git a/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/rmid.security.policy index 0e43c5d37ab..ca4b8e244d9 100644 --- a/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/rmid.security.policy @@ -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 --git a/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/security.policy b/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/security.policy index 300b2fc4f71..82bea323573 100644 --- a/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/checkImplClassLoader/security.policy @@ -39,4 +39,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/CheckRegisterInLog.java b/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/CheckRegisterInLog.java index 8939f6764e8..6053eddec6f 100644 --- a/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/CheckRegisterInLog.java +++ b/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/CheckRegisterInLog.java @@ -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 @@ public class CheckRegisterInLog * 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 --git a/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/rmid.security.policy index 0e43c5d37ab..ca4b8e244d9 100644 --- a/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/rmid.security.policy @@ -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 --git a/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/security.policy b/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/security.policy index 0c257a26879..c8a24a64de1 100644 --- a/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/checkRegisterInLog/security.policy @@ -31,4 +31,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/CreatePrivateActivatable.java b/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/CreatePrivateActivatable.java index 8ac5c1ecaa6..29a662176d4 100644 --- a/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/CreatePrivateActivatable.java +++ b/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/CreatePrivateActivatable.java @@ -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 @@ public class CreatePrivateActivatable // start an rmid. RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff --git a/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/rmid.security.policy index 0e43c5d37ab..ca4b8e244d9 100644 --- a/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/rmid.security.policy @@ -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 --git a/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/security.policy b/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/security.policy index 0c257a26879..c8a24a64de1 100644 --- a/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/createPrivateActivable/security.policy @@ -31,4 +31,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/DownloadParameterClass.java b/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/DownloadParameterClass.java index 7e63afba1ae..b3bafdb1c32 100644 --- a/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/DownloadParameterClass.java +++ b/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/DownloadParameterClass.java @@ -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 @@ public class DownloadParameterClass { try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff --git a/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/manual.security.policy b/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/manual.security.policy index d30ea1f3ea2..79d8bb32ce1 100644 --- a/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/manual.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/manual.security.policy @@ -34,4 +34,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/rmid.security.policy index 0e43c5d37ab..ca4b8e244d9 100644 --- a/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/rmid.security.policy @@ -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 --git a/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/security.policy b/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/security.policy index de2a5cf74e8..f37bf9525a5 100644 --- a/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/downloadParameterClass/security.policy @@ -35,4 +35,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/ElucidateNoSuchMethod.java b/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/ElucidateNoSuchMethod.java index ff741b0bd0e..89f3c90b24c 100644 --- a/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/ElucidateNoSuchMethod.java +++ b/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/ElucidateNoSuchMethod.java @@ -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 @@ public class ElucidateNoSuchMethod try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff --git a/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/rmid.security.policy index 0e43c5d37ab..53ed1f0bd93 100644 --- a/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/rmid.security.policy @@ -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 --git a/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/security.policy b/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/security.policy index 2348c442bb5..fd3dd828d23 100644 --- a/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/elucidateNoSuchMethod/security.policy @@ -37,4 +37,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ExtLoadedImplTest.java b/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ExtLoadedImplTest.java index c46baeaf5e7..96b2f7d9421 100644 --- a/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ExtLoadedImplTest.java +++ b/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ExtLoadedImplTest.java @@ -37,7 +37,7 @@ public class ExtLoadedImplTest { try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); Properties p = new Properties(); p.put("java.security.policy", diff --git a/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh b/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh index 546d693b962..224133930f1 100644 --- a/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh +++ b/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh @@ -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 --git a/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/ForceLogSnapshot.java b/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/ForceLogSnapshot.java index 53710ceb971..2b97650a599 100644 --- a/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/ForceLogSnapshot.java +++ b/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/ForceLogSnapshot.java @@ -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 @@ public class ForceLogSnapshot SNAPSHOT_INTERVAL; RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.addOptions(new String[] {option, "-Djava.compiler="}); rmid.start(); diff --git a/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/rmid.security.policy index 0e43c5d37ab..ca4b8e244d9 100644 --- a/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/rmid.security.policy @@ -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 --git a/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/security.policy b/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/security.policy index 0c257a26879..c8a24a64de1 100644 --- a/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/forceLogSnapshot/security.policy @@ -31,4 +31,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/Activatable/inactiveGroup/InactiveGroup.java b/jdk/test/java/rmi/activation/Activatable/inactiveGroup/InactiveGroup.java index fdce05cbc39..bf5d45d69e9 100644 --- a/jdk/test/java/rmi/activation/Activatable/inactiveGroup/InactiveGroup.java +++ b/jdk/test/java/rmi/activation/Activatable/inactiveGroup/InactiveGroup.java @@ -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 @@ public class InactiveGroup try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff --git a/jdk/test/java/rmi/activation/Activatable/inactiveGroup/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/inactiveGroup/rmid.security.policy index 0e43c5d37ab..ca4b8e244d9 100644 --- a/jdk/test/java/rmi/activation/Activatable/inactiveGroup/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/inactiveGroup/rmid.security.policy @@ -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 --git a/jdk/test/java/rmi/activation/Activatable/inactiveGroup/security.policy b/jdk/test/java/rmi/activation/Activatable/inactiveGroup/security.policy index 0c257a26879..c8a24a64de1 100644 --- a/jdk/test/java/rmi/activation/Activatable/inactiveGroup/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/inactiveGroup/security.policy @@ -31,4 +31,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/Activatable/lookupActivationSystem/LookupActivationSystem.java b/jdk/test/java/rmi/activation/Activatable/lookupActivationSystem/LookupActivationSystem.java index 4770f298919..8ed9c763b32 100644 --- a/jdk/test/java/rmi/activation/Activatable/lookupActivationSystem/LookupActivationSystem.java +++ b/jdk/test/java/rmi/activation/Activatable/lookupActivationSystem/LookupActivationSystem.java @@ -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 @@ public class LookupActivationSystem implements Remote, Serializable { try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); System.err.println("look up activation system"); diff --git a/jdk/test/java/rmi/activation/Activatable/lookupActivationSystem/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/lookupActivationSystem/rmid.security.policy new file mode 100644 index 00000000000..c488914b790 --- /dev/null +++ b/jdk/test/java/rmi/activation/Activatable/lookupActivationSystem/rmid.security.policy @@ -0,0 +1,4 @@ +grant { + permission java.lang.RuntimePermission "selectorProvider"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; +}; diff --git a/jdk/test/java/rmi/activation/Activatable/nestedActivate/NestedActivate.java b/jdk/test/java/rmi/activation/Activatable/nestedActivate/NestedActivate.java index a1ddf4d9ed4..b1c841dc256 100644 --- a/jdk/test/java/rmi/activation/Activatable/nestedActivate/NestedActivate.java +++ b/jdk/test/java/rmi/activation/Activatable/nestedActivate/NestedActivate.java @@ -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 @@ public class NestedActivate try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff --git a/jdk/test/java/rmi/activation/Activatable/nestedActivate/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/nestedActivate/rmid.security.policy index 0e43c5d37ab..ca4b8e244d9 100644 --- a/jdk/test/java/rmi/activation/Activatable/nestedActivate/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/nestedActivate/rmid.security.policy @@ -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 --git a/jdk/test/java/rmi/activation/Activatable/nestedActivate/security.policy b/jdk/test/java/rmi/activation/Activatable/nestedActivate/security.policy index 7349f99226e..ac03704a625 100644 --- a/jdk/test/java/rmi/activation/Activatable/nestedActivate/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/nestedActivate/security.policy @@ -31,4 +31,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/NonExistentActivatable.java b/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/NonExistentActivatable.java index 1e422e3697a..5074ac52bc5 100644 --- a/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/NonExistentActivatable.java +++ b/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/NonExistentActivatable.java @@ -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 @@ public class NonExistentActivatable try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff --git a/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/rmid.security.policy index 0e43c5d37ab..ca4b8e244d9 100644 --- a/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/rmid.security.policy @@ -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 --git a/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/security.policy b/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/security.policy index 74a40dd36af..c8a24a64de1 100644 --- a/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/nonExistentActivatable/security.policy @@ -32,4 +32,6 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/Activatable/restartCrashedService/RestartCrashedService.java b/jdk/test/java/rmi/activation/Activatable/restartCrashedService/RestartCrashedService.java index 0e8e7003cff..526d142af71 100644 --- a/jdk/test/java/rmi/activation/Activatable/restartCrashedService/RestartCrashedService.java +++ b/jdk/test/java/rmi/activation/Activatable/restartCrashedService/RestartCrashedService.java @@ -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 @@ public class RestartCrashedService try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff --git a/jdk/test/java/rmi/activation/Activatable/restartCrashedService/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/restartCrashedService/rmid.security.policy index 0e43c5d37ab..ca4b8e244d9 100644 --- a/jdk/test/java/rmi/activation/Activatable/restartCrashedService/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/restartCrashedService/rmid.security.policy @@ -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 --git a/jdk/test/java/rmi/activation/Activatable/restartCrashedService/security.policy b/jdk/test/java/rmi/activation/Activatable/restartCrashedService/security.policy index 73fdf10507c..0882def59ad 100644 --- a/jdk/test/java/rmi/activation/Activatable/restartCrashedService/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/restartCrashedService/security.policy @@ -28,4 +28,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/Activatable/restartLatecomer/RestartLatecomer.java b/jdk/test/java/rmi/activation/Activatable/restartLatecomer/RestartLatecomer.java index 1ce28b26d6c..499ef6ce5d9 100644 --- a/jdk/test/java/rmi/activation/Activatable/restartLatecomer/RestartLatecomer.java +++ b/jdk/test/java/rmi/activation/Activatable/restartLatecomer/RestartLatecomer.java @@ -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 @@ public class RestartLatecomer try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff --git a/jdk/test/java/rmi/activation/Activatable/restartLatecomer/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/restartLatecomer/rmid.security.policy index 0e43c5d37ab..ca4b8e244d9 100644 --- a/jdk/test/java/rmi/activation/Activatable/restartLatecomer/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/restartLatecomer/rmid.security.policy @@ -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 --git a/jdk/test/java/rmi/activation/Activatable/restartLatecomer/security.policy b/jdk/test/java/rmi/activation/Activatable/restartLatecomer/security.policy index c30b6e6c9a8..b0aa6518e0f 100644 --- a/jdk/test/java/rmi/activation/Activatable/restartLatecomer/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/restartLatecomer/security.policy @@ -33,4 +33,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/Activatable/restartService/RestartService.java b/jdk/test/java/rmi/activation/Activatable/restartService/RestartService.java index 2d1aa50e56e..792c02f208c 100644 --- a/jdk/test/java/rmi/activation/Activatable/restartService/RestartService.java +++ b/jdk/test/java/rmi/activation/Activatable/restartService/RestartService.java @@ -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 @@ public class RestartService try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); /* Cause activation groups to have a security policy that will diff --git a/jdk/test/java/rmi/activation/Activatable/restartService/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/restartService/rmid.security.policy index fd1a2096bfd..0471fc80946 100644 --- a/jdk/test/java/rmi/activation/Activatable/restartService/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/restartService/rmid.security.policy @@ -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 --git a/jdk/test/java/rmi/activation/Activatable/restartService/security.policy b/jdk/test/java/rmi/activation/Activatable/restartService/security.policy index c30b6e6c9a8..b0aa6518e0f 100644 --- a/jdk/test/java/rmi/activation/Activatable/restartService/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/restartService/security.policy @@ -33,4 +33,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java b/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java index d2c6a454995..743e2338ba5 100644 --- a/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java +++ b/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java @@ -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 @@ public class ShutdownGracefully // 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 --git a/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/rmid.security.policy index c7915ad42ea..b1f98628cf8 100644 --- a/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/rmid.security.policy @@ -2,4 +2,6 @@ grant { 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 --git a/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/security.policy b/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/security.policy index 257bb5369a3..b4418a72c3e 100644 --- a/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/shutdownGracefully/security.policy @@ -25,4 +25,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/Activatable/unregisterInactive/UnregisterInactive.java b/jdk/test/java/rmi/activation/Activatable/unregisterInactive/UnregisterInactive.java index 08f717f78d1..2ff66718bf4 100644 --- a/jdk/test/java/rmi/activation/Activatable/unregisterInactive/UnregisterInactive.java +++ b/jdk/test/java/rmi/activation/Activatable/unregisterInactive/UnregisterInactive.java @@ -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 @@ public class UnregisterInactive try { RMID.removeLog(); - rmid = RMID.createRMID(); + rmid = RMID.createRMIDOnEphemeralPort(); rmid.start(); System.err.println("Creating descriptor"); diff --git a/jdk/test/java/rmi/activation/Activatable/unregisterInactive/rmid.security.policy b/jdk/test/java/rmi/activation/Activatable/unregisterInactive/rmid.security.policy index 0e43c5d37ab..ca4b8e244d9 100644 --- a/jdk/test/java/rmi/activation/Activatable/unregisterInactive/rmid.security.policy +++ b/jdk/test/java/rmi/activation/Activatable/unregisterInactive/rmid.security.policy @@ -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 --git a/jdk/test/java/rmi/activation/Activatable/unregisterInactive/security.policy b/jdk/test/java/rmi/activation/Activatable/unregisterInactive/security.policy index 6fd298d6a2b..63fecad764c 100644 --- a/jdk/test/java/rmi/activation/Activatable/unregisterInactive/security.policy +++ b/jdk/test/java/rmi/activation/Activatable/unregisterInactive/security.policy @@ -28,4 +28,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/ActivateFails.java b/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/ActivateFails.java index efd6c3095ab..604ee9e5a0a 100644 --- a/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/ActivateFails.java +++ b/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/ActivateFails.java @@ -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 @@ public class ActivateFails * 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 --git a/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/rmid.security.policy b/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/rmid.security.policy index 0e43c5d37ab..ca4b8e244d9 100644 --- a/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/rmid.security.policy +++ b/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/rmid.security.policy @@ -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 --git a/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/security.policy b/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/security.policy index 572e29ce309..ef36478e900 100644 --- a/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/security.policy +++ b/jdk/test/java/rmi/activation/ActivateFailedException/activateFails/security.policy @@ -28,4 +28,7 @@ grant { // 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 --git a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java index 272f9f42321..4d27bc8fb0c 100644 --- a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java +++ b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java @@ -51,6 +51,8 @@ import java.rmi.activation.ActivationSystem; 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 @@ public class RmidViaInheritedChannel implements Callback { */ 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 --git a/jdk/test/java/rmi/testlibrary/JavaVM.java b/jdk/test/java/rmi/testlibrary/JavaVM.java index c8099346972..04f1589262d 100644 --- a/jdk/test/java/rmi/testlibrary/JavaVM.java +++ b/jdk/test/java/rmi/testlibrary/JavaVM.java @@ -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 @@ public class JavaVM { 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 @@ public class JavaVM { /** * 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 @@ public class JavaVM { 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 --git a/jdk/test/java/rmi/testlibrary/RMID.java b/jdk/test/java/rmi/testlibrary/RMID.java index 1ae6cf64bab..f83225f4d43 100644 --- a/jdk/test/java/rmi/testlibrary/RMID.java +++ b/jdk/test/java/rmi/testlibrary/RMID.java @@ -49,20 +49,31 @@ public class RMID extends JavaVM { 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 @@ public class RMID extends JavaVM { // 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 @@ public class RMID extends JavaVM { 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 @@ public class RMID extends JavaVM { 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 @@ public class RMID extends JavaVM { 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 @@ public class RMID extends JavaVM { // 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 @@ public class RMID extends JavaVM { 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 class RMID extends JavaVM { */ public void restart() throws IOException { destroy(); + options = makeOptions(port, true); + args = makeArgs(true, port); start(); } diff --git a/jdk/test/java/rmi/testlibrary/RMIDSelectorProvider.java b/jdk/test/java/rmi/testlibrary/RMIDSelectorProvider.java new file mode 100644 index 00000000000..4b9f09264d7 --- /dev/null +++ b/jdk/test/java/rmi/testlibrary/RMIDSelectorProvider.java @@ -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 --git a/jdk/test/java/rmi/testlibrary/TestParams.java b/jdk/test/java/rmi/testlibrary/TestParams.java index 1d98e174084..5f60efbd639 100644 --- a/jdk/test/java/rmi/testlibrary/TestParams.java +++ b/jdk/test/java/rmi/testlibrary/TestParams.java @@ -34,6 +34,7 @@ public class TestParams { /** 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 @@ public class TestParams { 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 --git a/jdk/test/java/security/misc/GetInstanceNullsEmpties.java b/jdk/test/java/security/misc/GetInstanceNullsEmpties.java new file mode 100644 index 00000000000..75089208fa8 --- /dev/null +++ b/jdk/test/java/security/misc/GetInstanceNullsEmpties.java @@ -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 --git a/jdk/test/java/security/testlibrary/Proc.java b/jdk/test/java/security/testlibrary/Proc.java index b59555baf69..ec5fae6800c 100644 --- a/jdk/test/java/security/testlibrary/Proc.java +++ b/jdk/test/java/security/testlibrary/Proc.java @@ -243,16 +243,23 @@ public class Proc { // 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 --git a/jdk/test/java/util/Arrays/ParallelPrefix.java b/jdk/test/java/util/Arrays/ParallelPrefix.java index 1a68329b245..2b3fb70fca1 100644 --- a/jdk/test/java/util/Arrays/ParallelPrefix.java +++ b/jdk/test/java/util/Arrays/ParallelPrefix.java @@ -26,7 +26,6 @@ * @summary unit test for Arrays.ParallelPrefix(). * @author Tristan Yan * @run testng ParallelPrefix - * @key intermittent */ import java.util.Arrays; diff --git a/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.java b/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.java index f32cb2a74ad..13848d91774 100644 --- a/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.java +++ b/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.java @@ -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 @@ public class BreakIteratorProviderTest extends ProviderTest { 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 --git a/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.sh b/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.sh index f927fb16811..aeeb8e8fe03 100644 --- a/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.sh +++ b/jdk/test/java/util/PluggableLocale/BreakIteratorProviderTest.sh @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/MyResources_ja_JP.properties b/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_ja_JP.properties similarity index 100% rename from jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/MyResources_ja_JP.properties rename to jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_ja_JP.properties diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesProvider.java b/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesProvider.java index c9ebc4b837d..3cbbe563368 100644 --- a/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesProvider.java +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesProvider.java @@ -62,9 +62,7 @@ public class MyResourcesProvider extends AbstractResourceBundleProvider { @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 --git a/jdk/test/java/util/Scanner/ScanTest.java b/jdk/test/java/util/Scanner/ScanTest.java index 13397751ad8..0f1abcbd8b5 100644 --- a/jdk/test/java/util/Scanner/ScanTest.java +++ b/jdk/test/java/util/Scanner/ScanTest.java @@ -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.math.*; 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 @@ public class ScanTest { resetTest(); streamCloseTest(); streamComodTest(); + outOfRangeRadixTest(); for (int j = 0; j < NUM_SOURCE_TYPES; j++) { hasNextTest(j); @@ -1509,6 +1511,48 @@ public class ScanTest { 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 --git a/jdk/test/java/util/logging/LogManager/LinkageErrorTest.java b/jdk/test/java/util/logging/LogManager/LinkageErrorTest.java new file mode 100644 index 00000000000..94c1747adc5 --- /dev/null +++ b/jdk/test/java/util/logging/LogManager/LinkageErrorTest.java @@ -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 --git a/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/ThowableHelper.java b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/ThrowableHelper.java similarity index 93% rename from jdk/test/java/util/stream/bootlib/java.base/java/util/stream/ThowableHelper.java rename to jdk/test/java/util/stream/bootlib/java.base/java/util/stream/ThrowableHelper.java index fc7807f6df0..5472e22d9e5 100644 --- a/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/ThowableHelper.java +++ b/jdk/test/java/util/stream/bootlib/java.base/java/util/stream/ThrowableHelper.java @@ -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 @@ -25,7 +25,7 @@ package java.util.stream; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; -public final class ThowableHelper { +public final class ThrowableHelper { public static void checkException(Class ce, Runnable r) { Exception caught = null; diff --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectAndSummaryStatisticsTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectAndSummaryStatisticsTest.java index a869cdf41f3..22d91ba3f84 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectAndSummaryStatisticsTest.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectAndSummaryStatisticsTest.java @@ -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.LongStream; 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 --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectionAndMapModifyStreamTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectionAndMapModifyStreamTest.java index 9a74214a1bb..07911219065 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectionAndMapModifyStreamTest.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectionAndMapModifyStreamTest.java @@ -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 @@ public class CollectionAndMapModifyStreamTest { 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 --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/FlatMapOpTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/FlatMapOpTest.java index afbedc871da..e967893478a 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/FlatMapOpTest.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/FlatMapOpTest.java @@ -49,7 +49,7 @@ import java.util.stream.StreamTestDataProvider; 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 --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IterateTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IterateTest.java index 7843f22563f..efcf4f5d9d4 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IterateTest.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IterateTest.java @@ -38,7 +38,7 @@ import java.util.stream.Stream; 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 --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamBuilderTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamBuilderTest.java index a6fb7e0e398..98fcd480d8e 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamBuilderTest.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamBuilderTest.java @@ -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.Stream; 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 --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamCloseTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamCloseTest.java index d20a6670dac..1073f4fbd63 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamCloseTest.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamCloseTest.java @@ -36,8 +36,8 @@ import java.util.stream.Stream; 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 --git a/jdk/test/javax/imageio/ImageCompressionTypesTest.java b/jdk/test/javax/imageio/ImageCompressionTypesTest.java new file mode 100644 index 00000000000..fd8167b6c7a --- /dev/null +++ b/jdk/test/javax/imageio/ImageCompressionTypesTest.java @@ -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 --git a/jdk/test/javax/imageio/metadata/GetElementsByTagNameTest.java b/jdk/test/javax/imageio/metadata/GetElementsByTagNameTest.java new file mode 100644 index 00000000000..9a03174945c --- /dev/null +++ b/jdk/test/javax/imageio/metadata/GetElementsByTagNameTest.java @@ -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 --git a/jdk/test/javax/imageio/metadata/NthItemNodeListTest.java b/jdk/test/javax/imageio/metadata/NthItemNodeListTest.java new file mode 100644 index 00000000000..e5b74abd1a2 --- /dev/null +++ b/jdk/test/javax/imageio/metadata/NthItemNodeListTest.java @@ -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 --git a/jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java b/jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java index 35f35a5c410..10886497267 100644 --- a/jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java +++ b/jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java @@ -48,10 +48,6 @@ import sun.security.util.HexDumpEncoder; */ 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 @@ public class DTLSOverDatagram { } 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 @@ public class DTLSOverDatagram { boolean finished = produceHandshakePackets( engine, peerAddr, side, packets); + log(side, "Produced " + packets.size() + " packets"); for (DatagramPacket p : packets) { socket.send(p); } @@ -252,14 +250,16 @@ public class DTLSOverDatagram { } 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 @@ public class DTLSOverDatagram { 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 @@ public class DTLSOverDatagram { 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 @@ public class DTLSOverDatagram { 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 --git a/jdk/test/javax/net/ssl/DTLS/PacketLossRetransmission.java b/jdk/test/javax/net/ssl/DTLS/PacketLossRetransmission.java new file mode 100644 index 00000000000..572bf14b27a --- /dev/null +++ b/jdk/test/javax/net/ssl/DTLS/PacketLossRetransmission.java @@ -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 --git a/jdk/test/javax/net/ssl/DTLS/RespondToRetransmit.java b/jdk/test/javax/net/ssl/DTLS/RespondToRetransmit.java new file mode 100644 index 00000000000..0ea0a2d3dea --- /dev/null +++ b/jdk/test/javax/net/ssl/DTLS/RespondToRetransmit.java @@ -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 --git a/jdk/test/javax/net/ssl/SSLEngine/EngineCloseOnAlert.java b/jdk/test/javax/net/ssl/SSLEngine/EngineCloseOnAlert.java new file mode 100644 index 00000000000..ba6751452d1 --- /dev/null +++ b/jdk/test/javax/net/ssl/SSLEngine/EngineCloseOnAlert.java @@ -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 --git a/jdk/test/javax/net/ssl/TLSCommon/SSLEngineTestCase.java b/jdk/test/javax/net/ssl/TLSCommon/SSLEngineTestCase.java index a0d95e026de..844f48f5b91 100644 --- a/jdk/test/javax/net/ssl/TLSCommon/SSLEngineTestCase.java +++ b/jdk/test/javax/net/ssl/TLSCommon/SSLEngineTestCase.java @@ -27,7 +27,9 @@ import javax.net.ssl.SNIMatcher; 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 @@ abstract public class SSLEngineTestCase { 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 @@ abstract public class SSLEngineTestCase { = 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 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 int MAX_HANDSHAKE_LOOPS = 100; + private static final String EXCHANGE_MSG_SENT = "Hello, peer!"; 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 @@ abstract public class SSLEngineTestCase { 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 @@ abstract public class SSLEngineTestCase { 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 @@ abstract public class SSLEngineTestCase { 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 @@ abstract public class SSLEngineTestCase { * 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 @@ abstract public class SSLEngineTestCase { * 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 @@ abstract public class SSLEngineTestCase { * 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 @@ abstract public class SSLEngineTestCase { * 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 @@ abstract public class SSLEngineTestCase { * @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 @@ abstract public class SSLEngineTestCase { * @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 @@ abstract public class SSLEngineTestCase { * 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 @@ abstract public class SSLEngineTestCase { * @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 @@ abstract public class SSLEngineTestCase { * * @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 @@ abstract public class SSLEngineTestCase { 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 @@ abstract public class SSLEngineTestCase { 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 @@ abstract public class SSLEngineTestCase { 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 @@ abstract public class SSLEngineTestCase { } // 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 @@ abstract public class SSLEngineTestCase { 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 @@ abstract public class SSLEngineTestCase { } /** - * 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 @@ abstract public class SSLEngineTestCase { } /** - * 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 @@ abstract public class SSLEngineTestCase { * @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 @@ abstract public class SSLEngineTestCase { * @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 @@ abstract public class SSLEngineTestCase { 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 @@ abstract public class SSLEngineTestCase { 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 @@ abstract public class SSLEngineTestCase { + ciphers.name()); } } + return failedNum; } @@ -919,20 +946,20 @@ abstract public class SSLEngineTestCase { * * @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 @@ abstract public class SSLEngineTestCase { } 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 @@ abstract public class SSLEngineTestCase { } } } - 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 @@ abstract public class SSLEngineTestCase { 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 @@ abstract public class SSLEngineTestCase { netReplicated = netReplicatedServer; } if (netReplicated != null) { - doUnWrap(unwrapingEngine, unwrapper, netReplicated); + doUnWrap(unwrapingEngine, + unwrapper, netReplicated); } else { net.flip(); doUnWrap(unwrapingEngine, unwrapper, net); @@ -994,15 +1031,39 @@ abstract public class SSLEngineTestCase { 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 @@ abstract public class SSLEngineTestCase { 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 --git a/jdk/test/javax/print/attribute/Services_getDocFl.java b/jdk/test/javax/print/attribute/Services_getDocFl.java index e3f0a850e3f..ca926b39928 100644 --- a/jdk/test/javax/print/attribute/Services_getDocFl.java +++ b/jdk/test/javax/print/attribute/Services_getDocFl.java @@ -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 @@ import javax.print.attribute.HashPrintRequestAttributeSet; /* * @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 @@ public class Services_getDocFl { 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 --git a/jdk/test/javax/sound/midi/Devices/MidiDeviceGetReceivers.java b/jdk/test/javax/sound/midi/Devices/MidiDeviceGetReceivers.java new file mode 100644 index 00000000000..a01bcadc25e --- /dev/null +++ b/jdk/test/javax/sound/midi/Devices/MidiDeviceGetReceivers.java @@ -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 --git a/jdk/test/javax/sound/midi/Devices/MidiIO.java b/jdk/test/javax/sound/midi/Devices/MidiIO.java new file mode 100644 index 00000000000..e81920a7404 --- /dev/null +++ b/jdk/test/javax/sound/midi/Devices/MidiIO.java @@ -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 --git a/jdk/test/javax/sound/midi/Devices/MidiOutGetMicrosecondPositionBug.java b/jdk/test/javax/sound/midi/Devices/MidiOutGetMicrosecondPositionBug.java new file mode 100644 index 00000000000..6e1983a0bfa --- /dev/null +++ b/jdk/test/javax/sound/midi/Devices/MidiOutGetMicrosecondPositionBug.java @@ -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 --git a/jdk/test/javax/sound/midi/Devices/OpenClose.java b/jdk/test/javax/sound/midi/Devices/OpenClose.java new file mode 100644 index 00000000000..08be8c00a09 --- /dev/null +++ b/jdk/test/javax/sound/midi/Devices/OpenClose.java @@ -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 --git a/jdk/test/javax/sound/midi/Devices/ReceiverTransmitterAvailable.java b/jdk/test/javax/sound/midi/Devices/ReceiverTransmitterAvailable.java new file mode 100644 index 00000000000..a2d4e835e11 --- /dev/null +++ b/jdk/test/javax/sound/midi/Devices/ReceiverTransmitterAvailable.java @@ -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 --git a/jdk/test/javax/sound/midi/Devices/Reopen.java b/jdk/test/javax/sound/midi/Devices/Reopen.java new file mode 100644 index 00000000000..955c880f314 --- /dev/null +++ b/jdk/test/javax/sound/midi/Devices/Reopen.java @@ -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 --git a/jdk/test/javax/sound/midi/File/SMFCp037.java b/jdk/test/javax/sound/midi/File/SMFCp037.java new file mode 100644 index 00000000000..1779bca7f22 --- /dev/null +++ b/jdk/test/javax/sound/midi/File/SMFCp037.java @@ -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 --git a/jdk/test/javax/sound/midi/File/SMFParserBreak.java b/jdk/test/javax/sound/midi/File/SMFParserBreak.java new file mode 100644 index 00000000000..7162751adc3 --- /dev/null +++ b/jdk/test/javax/sound/midi/File/SMFParserBreak.java @@ -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 --git a/jdk/test/javax/sound/midi/File/WriteRealTimeMessageNPE.java b/jdk/test/javax/sound/midi/File/WriteRealTimeMessageNPE.java new file mode 100644 index 00000000000..8e059c1123c --- /dev/null +++ b/jdk/test/javax/sound/midi/File/WriteRealTimeMessageNPE.java @@ -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 --git a/jdk/test/javax/sound/midi/MetaMessage/MetaMessageClone.java b/jdk/test/javax/sound/midi/MetaMessage/MetaMessageClone.java new file mode 100644 index 00000000000..b52f1fefe57 --- /dev/null +++ b/jdk/test/javax/sound/midi/MetaMessage/MetaMessageClone.java @@ -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 --git a/jdk/test/javax/sound/midi/MidiSystem/6411624/bug6411624.java b/jdk/test/javax/sound/midi/MidiSystem/6411624/bug6411624.java new file mode 100644 index 00000000000..e752057c4cf --- /dev/null +++ b/jdk/test/javax/sound/midi/MidiSystem/6411624/bug6411624.java @@ -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 --git a/jdk/test/javax/sound/midi/MidiSystem/MidiFileTypeUniqueness.java b/jdk/test/javax/sound/midi/MidiSystem/MidiFileTypeUniqueness.java new file mode 100644 index 00000000000..8d2f456a391 --- /dev/null +++ b/jdk/test/javax/sound/midi/MidiSystem/MidiFileTypeUniqueness.java @@ -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 --git a/jdk/test/javax/sound/midi/MidiSystem/ProviderCacheing.java b/jdk/test/javax/sound/midi/MidiSystem/ProviderCacheing.java new file mode 100644 index 00000000000..f9bfd6b2fe6 --- /dev/null +++ b/jdk/test/javax/sound/midi/MidiSystem/ProviderCacheing.java @@ -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 --git a/jdk/test/javax/sound/midi/MidiSystem/testdata/conf/sound.properties b/jdk/test/javax/sound/midi/MidiSystem/testdata/conf/sound.properties new file mode 100644 index 00000000000..638d9f32d11 --- /dev/null +++ b/jdk/test/javax/sound/midi/MidiSystem/testdata/conf/sound.properties @@ -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 --git a/jdk/test/javax/sound/midi/Sequence/GetMicrosecondLength.java b/jdk/test/javax/sound/midi/Sequence/GetMicrosecondLength.java new file mode 100644 index 00000000000..7b1026ca0bd --- /dev/null +++ b/jdk/test/javax/sound/midi/Sequence/GetMicrosecondLength.java @@ -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 --git a/jdk/test/javax/sound/midi/Sequence/MidiSMPTE.java b/jdk/test/javax/sound/midi/Sequence/MidiSMPTE.java new file mode 100644 index 00000000000..66b732f6ce3 --- /dev/null +++ b/jdk/test/javax/sound/midi/Sequence/MidiSMPTE.java @@ -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 --git a/jdk/test/javax/sound/midi/Sequence/SMPTEDuration.java b/jdk/test/javax/sound/midi/Sequence/SMPTEDuration.java new file mode 100644 index 00000000000..7eb7fc85878 --- /dev/null +++ b/jdk/test/javax/sound/midi/Sequence/SMPTEDuration.java @@ -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 --git a/jdk/test/javax/sound/midi/Sequencer/LoopIAE.java b/jdk/test/javax/sound/midi/Sequencer/LoopIAE.java new file mode 100644 index 00000000000..04156331088 --- /dev/null +++ b/jdk/test/javax/sound/midi/Sequencer/LoopIAE.java @@ -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 --git a/jdk/test/javax/sound/midi/Sequencer/Looping.java b/jdk/test/javax/sound/midi/Sequencer/Looping.java new file mode 100644 index 00000000000..9bcc9254653 --- /dev/null +++ b/jdk/test/javax/sound/midi/Sequencer/Looping.java @@ -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 --git a/jdk/test/javax/sound/midi/Sequencer/MetaCallback.java b/jdk/test/javax/sound/midi/Sequencer/MetaCallback.java new file mode 100644 index 00000000000..1c7dc9e1ffc --- /dev/null +++ b/jdk/test/javax/sound/midi/Sequencer/MetaCallback.java @@ -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 --git a/jdk/test/javax/sound/midi/Sequencer/Recording.java b/jdk/test/javax/sound/midi/Sequencer/Recording.java new file mode 100644 index 00000000000..704db75b023 --- /dev/null +++ b/jdk/test/javax/sound/midi/Sequencer/Recording.java @@ -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 --git a/jdk/test/javax/sound/midi/Sequencer/SeqRecordDoesNotCopy.java b/jdk/test/javax/sound/midi/Sequencer/SeqRecordDoesNotCopy.java new file mode 100644 index 00000000000..99d8509c8c7 --- /dev/null +++ b/jdk/test/javax/sound/midi/Sequencer/SeqRecordDoesNotCopy.java @@ -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 --git a/jdk/test/javax/sound/midi/Sequencer/SeqRecordsRealTimeEvents.java b/jdk/test/javax/sound/midi/Sequencer/SeqRecordsRealTimeEvents.java new file mode 100644 index 00000000000..11c240e8843 --- /dev/null +++ b/jdk/test/javax/sound/midi/Sequencer/SeqRecordsRealTimeEvents.java @@ -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 --git a/jdk/test/javax/sound/midi/Sequencer/SeqStartRecording.java b/jdk/test/javax/sound/midi/Sequencer/SeqStartRecording.java new file mode 100644 index 00000000000..423c7a2d69b --- /dev/null +++ b/jdk/test/javax/sound/midi/Sequencer/SeqStartRecording.java @@ -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 --git a/jdk/test/javax/sound/midi/Sequencer/SequencerCacheValues.java b/jdk/test/javax/sound/midi/Sequencer/SequencerCacheValues.java new file mode 100644 index 00000000000..076873fdf04 --- /dev/null +++ b/jdk/test/javax/sound/midi/Sequencer/SequencerCacheValues.java @@ -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 --git a/jdk/test/javax/sound/midi/Sequencer/SequencerState.java b/jdk/test/javax/sound/midi/Sequencer/SequencerState.java new file mode 100644 index 00000000000..acb1bcfe18c --- /dev/null +++ b/jdk/test/javax/sound/midi/Sequencer/SequencerState.java @@ -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 --git a/jdk/test/javax/sound/midi/Sequencer/SetTickPosition.java b/jdk/test/javax/sound/midi/Sequencer/SetTickPosition.java new file mode 100644 index 00000000000..f1ce140af7b --- /dev/null +++ b/jdk/test/javax/sound/midi/Sequencer/SetTickPosition.java @@ -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 --git a/jdk/test/javax/sound/midi/Sequencer/TickLength.java b/jdk/test/javax/sound/midi/Sequencer/TickLength.java new file mode 100644 index 00000000000..a8285278f61 --- /dev/null +++ b/jdk/test/javax/sound/midi/Sequencer/TickLength.java @@ -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 --git a/jdk/test/javax/sound/midi/ShortMessage/FastShortMessage.java b/jdk/test/javax/sound/midi/ShortMessage/FastShortMessage.java new file mode 100644 index 00000000000..7256cbb7373 --- /dev/null +++ b/jdk/test/javax/sound/midi/ShortMessage/FastShortMessage.java @@ -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 --git a/jdk/test/javax/sound/midi/ShortMessage/FastShortMessage2.java b/jdk/test/javax/sound/midi/ShortMessage/FastShortMessage2.java new file mode 100644 index 00000000000..8dec95ec3da --- /dev/null +++ b/jdk/test/javax/sound/midi/ShortMessage/FastShortMessage2.java @@ -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 --git a/jdk/test/javax/sound/midi/Soundbanks/ExtraCharInSoundbank.java b/jdk/test/javax/sound/midi/Soundbanks/ExtraCharInSoundbank.java new file mode 100644 index 00000000000..b7c01fd1e61 --- /dev/null +++ b/jdk/test/javax/sound/midi/Soundbanks/ExtraCharInSoundbank.java @@ -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 --git a/jdk/test/javax/sound/midi/Soundbanks/GetSoundBankIOException.java b/jdk/test/javax/sound/midi/Soundbanks/GetSoundBankIOException.java new file mode 100644 index 00000000000..81445c2a86c --- /dev/null +++ b/jdk/test/javax/sound/midi/Soundbanks/GetSoundBankIOException.java @@ -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 --git a/jdk/test/javax/sound/midi/Synthesizer/AsynchronousMidiChannel.java b/jdk/test/javax/sound/midi/Synthesizer/AsynchronousMidiChannel.java new file mode 100644 index 00000000000..61a5470aac6 --- /dev/null +++ b/jdk/test/javax/sound/midi/Synthesizer/AsynchronousMidiChannel.java @@ -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 --git a/jdk/test/javax/sound/midi/Synthesizer/Receiver/bug6186488.java b/jdk/test/javax/sound/midi/Synthesizer/Receiver/bug6186488.java new file mode 100644 index 00000000000..d2634a306c3 --- /dev/null +++ b/jdk/test/javax/sound/midi/Synthesizer/Receiver/bug6186488.java @@ -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 --git a/jdk/test/javax/sound/midi/Synthesizer/bug4685396.java b/jdk/test/javax/sound/midi/Synthesizer/bug4685396.java new file mode 100644 index 00000000000..43f1470584f --- /dev/null +++ b/jdk/test/javax/sound/midi/Synthesizer/bug4685396.java @@ -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 --git a/jdk/test/javax/sound/midi/Track/TrackAddSameTick.java b/jdk/test/javax/sound/midi/Track/TrackAddSameTick.java new file mode 100644 index 00000000000..cc324722cbb --- /dev/null +++ b/jdk/test/javax/sound/midi/Track/TrackAddSameTick.java @@ -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 --git a/jdk/test/javax/sound/midi/Track/bug6416024.java b/jdk/test/javax/sound/midi/Track/bug6416024.java new file mode 100644 index 00000000000..f507724cd9d --- /dev/null +++ b/jdk/test/javax/sound/midi/Track/bug6416024.java @@ -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 --git a/jdk/test/javax/sound/midi/Transmitter/bug6415669.java b/jdk/test/javax/sound/midi/Transmitter/bug6415669.java new file mode 100644 index 00000000000..a72d62b869b --- /dev/null +++ b/jdk/test/javax/sound/midi/Transmitter/bug6415669.java @@ -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 --git a/jdk/test/javax/sound/sampled/AudioFileFormat/AudioFileFormatToString.java b/jdk/test/javax/sound/sampled/AudioFileFormat/AudioFileFormatToString.java new file mode 100644 index 00000000000..817e69912bb --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioFileFormat/AudioFileFormatToString.java @@ -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 --git a/jdk/test/javax/sound/sampled/AudioFileFormat/Properties.java b/jdk/test/javax/sound/sampled/AudioFileFormat/Properties.java new file mode 100644 index 00000000000..f1795352899 --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioFileFormat/Properties.java @@ -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 --git a/jdk/test/javax/sound/sampled/AudioFileFormat/TypeEquals.java b/jdk/test/javax/sound/sampled/AudioFileFormat/TypeEquals.java new file mode 100644 index 00000000000..b8b75b7b05d --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioFileFormat/TypeEquals.java @@ -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 --git a/jdk/test/javax/sound/sampled/AudioFormat/AudioFormatBitSize.java b/jdk/test/javax/sound/sampled/AudioFormat/AudioFormatBitSize.java new file mode 100644 index 00000000000..58124e1ee9c --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioFormat/AudioFormatBitSize.java @@ -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 --git a/jdk/test/javax/sound/sampled/AudioFormat/EncodingEquals.java b/jdk/test/javax/sound/sampled/AudioFormat/EncodingEquals.java new file mode 100644 index 00000000000..77571ddee3e --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioFormat/EncodingEquals.java @@ -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 --git a/jdk/test/javax/sound/sampled/AudioFormat/Properties.java b/jdk/test/javax/sound/sampled/AudioFormat/Properties.java new file mode 100644 index 00000000000..f50a357482d --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioFormat/Properties.java @@ -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 --git a/jdk/test/javax/sound/sampled/AudioInputStream/AISReadFraction.java b/jdk/test/javax/sound/sampled/AudioInputStream/AISReadFraction.java new file mode 100644 index 00000000000..7d10377fde8 --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioInputStream/AISReadFraction.java @@ -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 --git a/jdk/test/javax/sound/sampled/AudioInputStream/bug6188860.java b/jdk/test/javax/sound/sampled/AudioInputStream/bug6188860.java new file mode 100644 index 00000000000..be35f5849bd --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioInputStream/bug6188860.java @@ -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 --git a/jdk/test/javax/sound/sampled/AudioSystem/AudioFileTypes/AudioFileTypeUniqueness.java b/jdk/test/javax/sound/sampled/AudioSystem/AudioFileTypes/AudioFileTypeUniqueness.java new file mode 100644 index 00000000000..e1fe5ec54c7 --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioSystem/AudioFileTypes/AudioFileTypeUniqueness.java @@ -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 --git a/jdk/test/javax/sound/sampled/AudioSystem/AudioFileTypes/ShowAudioFileTypes.java b/jdk/test/javax/sound/sampled/AudioSystem/AudioFileTypes/ShowAudioFileTypes.java new file mode 100644 index 00000000000..4bc1295b966 --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioSystem/AudioFileTypes/ShowAudioFileTypes.java @@ -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 --git a/jdk/test/javax/sound/sampled/AudioSystem/DefaultMixers.java b/jdk/test/javax/sound/sampled/AudioSystem/DefaultMixers.java new file mode 100644 index 00000000000..f3c236580f6 --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioSystem/DefaultMixers.java @@ -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 --git a/jdk/test/javax/sound/sampled/AudioSystem/DefaultProperties.java b/jdk/test/javax/sound/sampled/AudioSystem/DefaultProperties.java new file mode 100644 index 00000000000..1e383297dd5 --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioSystem/DefaultProperties.java @@ -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 --git a/jdk/test/javax/sound/sampled/AudioSystem/ProviderCacheing.java b/jdk/test/javax/sound/sampled/AudioSystem/ProviderCacheing.java new file mode 100644 index 00000000000..5c77c959d13 --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioSystem/ProviderCacheing.java @@ -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 --git a/jdk/test/javax/sound/sampled/AudioSystem/testdata/conf/sound.properties b/jdk/test/javax/sound/sampled/AudioSystem/testdata/conf/sound.properties new file mode 100644 index 00000000000..172428914fc --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioSystem/testdata/conf/sound.properties @@ -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 --git a/jdk/test/javax/sound/sampled/Clip/ClipCloseLoss.java b/jdk/test/javax/sound/sampled/Clip/ClipCloseLoss.java new file mode 100644 index 00000000000..b7f4fa424bf --- /dev/null +++ b/jdk/test/javax/sound/sampled/Clip/ClipCloseLoss.java @@ -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 --git a/jdk/test/javax/sound/sampled/Clip/ClipFlushCrash.java b/jdk/test/javax/sound/sampled/Clip/ClipFlushCrash.java new file mode 100644 index 00000000000..14a362cd2f8 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Clip/ClipFlushCrash.java @@ -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 --git a/jdk/test/javax/sound/sampled/Clip/Drain/ClipDrain.java b/jdk/test/javax/sound/sampled/Clip/Drain/ClipDrain.java new file mode 100644 index 00000000000..17e58d899c1 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Clip/Drain/ClipDrain.java @@ -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 --git a/jdk/test/javax/sound/sampled/Clip/Duration/ClipDuration.java b/jdk/test/javax/sound/sampled/Clip/Duration/ClipDuration.java new file mode 100644 index 00000000000..8393f1b0d59 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Clip/Duration/ClipDuration.java @@ -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 --git a/jdk/test/javax/sound/sampled/Clip/Endpoint/ClipSetEndPoint.java b/jdk/test/javax/sound/sampled/Clip/Endpoint/ClipSetEndPoint.java new file mode 100644 index 00000000000..13f78e82a9c --- /dev/null +++ b/jdk/test/javax/sound/sampled/Clip/Endpoint/ClipSetEndPoint.java @@ -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 --git a/jdk/test/javax/sound/sampled/Clip/Open/ClipOpenBug.java b/jdk/test/javax/sound/sampled/Clip/Open/ClipOpenBug.java new file mode 100644 index 00000000000..9eaf392d750 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Clip/Open/ClipOpenBug.java @@ -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 --git a/jdk/test/javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java b/jdk/test/javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java new file mode 100644 index 00000000000..15b26416a10 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java @@ -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 --git a/jdk/test/javax/sound/sampled/Clip/bug5070081.java b/jdk/test/javax/sound/sampled/Clip/bug5070081.java new file mode 100644 index 00000000000..8c9206b7f14 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Clip/bug5070081.java @@ -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 --git a/jdk/test/javax/sound/sampled/Clip/bug6251460.java b/jdk/test/javax/sound/sampled/Clip/bug6251460.java new file mode 100644 index 00000000000..0eb627f0ab6 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Clip/bug6251460.java @@ -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 --git a/jdk/test/javax/sound/sampled/Controls/CompoundControl/ToString.java b/jdk/test/javax/sound/sampled/Controls/CompoundControl/ToString.java new file mode 100644 index 00000000000..5ca63ba4291 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Controls/CompoundControl/ToString.java @@ -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 --git a/jdk/test/javax/sound/sampled/Controls/FloatControl/FloatControlBug.java b/jdk/test/javax/sound/sampled/Controls/FloatControl/FloatControlBug.java new file mode 100644 index 00000000000..5816fdfd6c5 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Controls/FloatControl/FloatControlBug.java @@ -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 --git a/jdk/test/javax/sound/sampled/DataLine/DataLineInfoNegBufferSize.java b/jdk/test/javax/sound/sampled/DataLine/DataLineInfoNegBufferSize.java new file mode 100644 index 00000000000..815ecb817e7 --- /dev/null +++ b/jdk/test/javax/sound/sampled/DataLine/DataLineInfoNegBufferSize.java @@ -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 --git a/jdk/test/javax/sound/sampled/DataLine/LineDefFormat.java b/jdk/test/javax/sound/sampled/DataLine/LineDefFormat.java new file mode 100644 index 00000000000..ff918544e04 --- /dev/null +++ b/jdk/test/javax/sound/sampled/DataLine/LineDefFormat.java @@ -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 --git a/jdk/test/javax/sound/sampled/DirectAudio/TickAtEndOfPlay.java b/jdk/test/javax/sound/sampled/DirectAudio/TickAtEndOfPlay.java new file mode 100644 index 00000000000..9eb60b452a7 --- /dev/null +++ b/jdk/test/javax/sound/sampled/DirectAudio/TickAtEndOfPlay.java @@ -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 --git a/jdk/test/javax/sound/sampled/FileTypeExtension/FileTypeExtensionTest.java b/jdk/test/javax/sound/sampled/FileTypeExtension/FileTypeExtensionTest.java new file mode 100644 index 00000000000..0f343755633 --- /dev/null +++ b/jdk/test/javax/sound/sampled/FileTypeExtension/FileTypeExtensionTest.java @@ -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 --git a/jdk/test/javax/sound/sampled/LineEvent/LineInfoNPE.java b/jdk/test/javax/sound/sampled/LineEvent/LineInfoNPE.java new file mode 100644 index 00000000000..ca9842b3cb7 --- /dev/null +++ b/jdk/test/javax/sound/sampled/LineEvent/LineInfoNPE.java @@ -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 --git a/jdk/test/javax/sound/sampled/Lines/16and32KHz/Has16and32KHz.java b/jdk/test/javax/sound/sampled/Lines/16and32KHz/Has16and32KHz.java new file mode 100644 index 00000000000..7da619b4ab1 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Lines/16and32KHz/Has16and32KHz.java @@ -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 --git a/jdk/test/javax/sound/sampled/Lines/BufferSizeCheck.java b/jdk/test/javax/sound/sampled/Lines/BufferSizeCheck.java new file mode 100644 index 00000000000..9694a07f17d --- /dev/null +++ b/jdk/test/javax/sound/sampled/Lines/BufferSizeCheck.java @@ -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 --git a/jdk/test/javax/sound/sampled/Lines/ChangingBuffer.java b/jdk/test/javax/sound/sampled/Lines/ChangingBuffer.java new file mode 100644 index 00000000000..859987296ab --- /dev/null +++ b/jdk/test/javax/sound/sampled/Lines/ChangingBuffer.java @@ -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 --git a/jdk/test/javax/sound/sampled/Lines/ClipOpenException.java b/jdk/test/javax/sound/sampled/Lines/ClipOpenException.java new file mode 100644 index 00000000000..66824558641 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Lines/ClipOpenException.java @@ -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 --git a/jdk/test/javax/sound/sampled/Lines/SourceDataLineDefaultBufferSizeCrash.java b/jdk/test/javax/sound/sampled/Lines/SourceDataLineDefaultBufferSizeCrash.java new file mode 100644 index 00000000000..a40423a6884 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Lines/SourceDataLineDefaultBufferSizeCrash.java @@ -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 --git a/jdk/test/javax/sound/sampled/Lines/StopStart.java b/jdk/test/javax/sound/sampled/Lines/StopStart.java new file mode 100644 index 00000000000..1eec9d6b674 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Lines/StopStart.java @@ -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 --git a/jdk/test/javax/sound/sampled/LinuxBlock/PlaySine.java b/jdk/test/javax/sound/sampled/LinuxBlock/PlaySine.java new file mode 100644 index 00000000000..12c5f594cb8 --- /dev/null +++ b/jdk/test/javax/sound/sampled/LinuxBlock/PlaySine.java @@ -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 --git a/jdk/test/javax/sound/sampled/LinuxCrash/ClipLinuxCrash.java b/jdk/test/javax/sound/sampled/LinuxCrash/ClipLinuxCrash.java new file mode 100644 index 00000000000..41d45b7955c --- /dev/null +++ b/jdk/test/javax/sound/sampled/LinuxCrash/ClipLinuxCrash.java @@ -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 --git a/jdk/test/javax/sound/sampled/LinuxCrash/ClipLinuxCrash2.java b/jdk/test/javax/sound/sampled/LinuxCrash/ClipLinuxCrash2.java new file mode 100644 index 00000000000..eb1f0490391 --- /dev/null +++ b/jdk/test/javax/sound/sampled/LinuxCrash/ClipLinuxCrash2.java @@ -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 --git a/jdk/test/javax/sound/sampled/LinuxCrash/SDLLinuxCrash.java b/jdk/test/javax/sound/sampled/LinuxCrash/SDLLinuxCrash.java new file mode 100644 index 00000000000..54b197e9e8e --- /dev/null +++ b/jdk/test/javax/sound/sampled/LinuxCrash/SDLLinuxCrash.java @@ -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 --git a/jdk/test/javax/sound/sampled/Mixers/BogusMixers.java b/jdk/test/javax/sound/sampled/Mixers/BogusMixers.java new file mode 100644 index 00000000000..c8bae96a7a7 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Mixers/BogusMixers.java @@ -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 --git a/jdk/test/javax/sound/sampled/Mixers/DirectSoundRepeatingBuffer/DirectSoundRepeatingBuffer.java b/jdk/test/javax/sound/sampled/Mixers/DirectSoundRepeatingBuffer/DirectSoundRepeatingBuffer.java new file mode 100644 index 00000000000..8b83baadf6c --- /dev/null +++ b/jdk/test/javax/sound/sampled/Mixers/DirectSoundRepeatingBuffer/DirectSoundRepeatingBuffer.java @@ -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 --git a/jdk/test/javax/sound/sampled/Mixers/DirectSoundRepeatingBuffer/Test4997635.java b/jdk/test/javax/sound/sampled/Mixers/DirectSoundRepeatingBuffer/Test4997635.java new file mode 100644 index 00000000000..e38b5ef9613 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Mixers/DirectSoundRepeatingBuffer/Test4997635.java @@ -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 --git a/jdk/test/javax/sound/sampled/Mixers/DirectSoundUnderrunSilence/DirectSoundUnderrunSilence.java b/jdk/test/javax/sound/sampled/Mixers/DirectSoundUnderrunSilence/DirectSoundUnderrunSilence.java new file mode 100644 index 00000000000..e0a54e7167d --- /dev/null +++ b/jdk/test/javax/sound/sampled/Mixers/DirectSoundUnderrunSilence/DirectSoundUnderrunSilence.java @@ -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 --git a/jdk/test/javax/sound/sampled/Mixers/DirectSoundUnderrunSilence/Test5032020.java b/jdk/test/javax/sound/sampled/Mixers/DirectSoundUnderrunSilence/Test5032020.java new file mode 100644 index 00000000000..2371eeb985c --- /dev/null +++ b/jdk/test/javax/sound/sampled/Mixers/DirectSoundUnderrunSilence/Test5032020.java @@ -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 --git a/jdk/test/javax/sound/sampled/Mixers/DisabledAssertionCrash.java b/jdk/test/javax/sound/sampled/Mixers/DisabledAssertionCrash.java new file mode 100644 index 00000000000..2f03d2eb097 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Mixers/DisabledAssertionCrash.java @@ -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 --git a/jdk/test/javax/sound/sampled/Mixers/NoSimpleInputDevice.java b/jdk/test/javax/sound/sampled/Mixers/NoSimpleInputDevice.java new file mode 100644 index 00000000000..d46a006363a --- /dev/null +++ b/jdk/test/javax/sound/sampled/Mixers/NoSimpleInputDevice.java @@ -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 --git a/jdk/test/javax/sound/sampled/Mixers/PhantomMixers.java b/jdk/test/javax/sound/sampled/Mixers/PhantomMixers.java new file mode 100644 index 00000000000..ce76d9c9410 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Mixers/PhantomMixers.java @@ -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 --git a/jdk/test/javax/sound/sampled/Mixers/PlugHwMonoAnd8bitAvailable.java b/jdk/test/javax/sound/sampled/Mixers/PlugHwMonoAnd8bitAvailable.java new file mode 100644 index 00000000000..9bcd8216467 --- /dev/null +++ b/jdk/test/javax/sound/sampled/Mixers/PlugHwMonoAnd8bitAvailable.java @@ -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 --git a/jdk/test/javax/sound/sampled/Mixers/UnexpectedIAE.java b/jdk/test/javax/sound/sampled/Mixers/UnexpectedIAE.java new file mode 100644 index 00000000000..435fd3bfadb --- /dev/null +++ b/jdk/test/javax/sound/sampled/Mixers/UnexpectedIAE.java @@ -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 --git a/jdk/test/javax/sound/sampled/spi/AudioFileReader/AIFFCp037.java b/jdk/test/javax/sound/sampled/spi/AudioFileReader/AIFFCp037.java new file mode 100644 index 00000000000..e591898efc7 --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/AIFFCp037.java @@ -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 --git a/jdk/test/javax/sound/sampled/spi/AudioFileReader/AIFFLargeHeader.java b/jdk/test/javax/sound/sampled/spi/AudioFileReader/AIFFLargeHeader.java new file mode 100644 index 00000000000..b2963e8087c --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/AIFFLargeHeader.java @@ -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 --git a/jdk/test/javax/sound/sampled/spi/AudioFileReader/Aiff12bit.java b/jdk/test/javax/sound/sampled/spi/AudioFileReader/Aiff12bit.java new file mode 100644 index 00000000000..4e96ee57336 --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/Aiff12bit.java @@ -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 --git a/jdk/test/javax/sound/sampled/spi/AudioFileReader/AuNotSpecified.java b/jdk/test/javax/sound/sampled/spi/AudioFileReader/AuNotSpecified.java new file mode 100644 index 00000000000..297cafffc4b --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/AuNotSpecified.java @@ -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 --git a/jdk/test/javax/sound/sampled/spi/AudioFileReader/AuZeroLength.java b/jdk/test/javax/sound/sampled/spi/AudioFileReader/AuZeroLength.java new file mode 100644 index 00000000000..a78c3cc5b96 --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/AuZeroLength.java @@ -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 --git a/jdk/test/javax/sound/sampled/spi/AudioFileReader/OpenWaveFile.java b/jdk/test/javax/sound/sampled/spi/AudioFileReader/OpenWaveFile.java new file mode 100644 index 00000000000..a88467b3634 --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/OpenWaveFile.java @@ -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 --git a/jdk/test/javax/sound/sampled/spi/AudioFileWriter/AUwithULAW.java b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/AUwithULAW.java new file mode 100644 index 00000000000..6ac3cbf2c12 --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/AUwithULAW.java @@ -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 --git a/jdk/test/javax/sound/sampled/spi/AudioFileWriter/AiffSampleRate.java b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/AiffSampleRate.java new file mode 100644 index 00000000000..8d7349babc7 --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/AiffSampleRate.java @@ -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 --git a/jdk/test/javax/sound/sampled/spi/AudioFileWriter/RIFFHeader.java b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/RIFFHeader.java new file mode 100644 index 00000000000..a4fe713bb9e --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/RIFFHeader.java @@ -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 --git a/jdk/test/javax/sound/sampled/spi/AudioFileWriter/WaveBigEndian.java b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/WaveBigEndian.java new file mode 100644 index 00000000000..141ca20a68a --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/WaveBigEndian.java @@ -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 --git a/jdk/test/javax/sound/sampled/spi/AudioFileWriter/WriteAuUnspecifiedLength.java b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/WriteAuUnspecifiedLength.java new file mode 100644 index 00000000000..d001a3c134d --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/WriteAuUnspecifiedLength.java @@ -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 --git a/jdk/test/javax/sound/sampled/spi/FormatConversionProvider/AlawUlaw.java b/jdk/test/javax/sound/sampled/spi/FormatConversionProvider/AlawUlaw.java new file mode 100644 index 00000000000..7747d7bce22 --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/FormatConversionProvider/AlawUlaw.java @@ -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 --git a/jdk/test/javax/swing/ToolTipManager/7123767/bug7123767.java b/jdk/test/javax/swing/ToolTipManager/7123767/bug7123767.java index 65795494733..1db5dc50d66 100644 --- a/jdk/test/javax/swing/ToolTipManager/7123767/bug7123767.java +++ b/jdk/test/javax/swing/ToolTipManager/7123767/bug7123767.java @@ -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.*; 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 @@ public class bug7123767 extends JFrame { } // 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 @@ public class bug7123767 extends JFrame { } 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 @@ public class bug7123767 extends JFrame { 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 @@ public class bug7123767 extends JFrame { 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 @@ public class bug7123767 extends JFrame { 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); - // Lower left - glide(rect.x + rect.width / 2, rect.y + rect.height / 2, - rect.x + MARGIN, rect.y + rect.height - MARGIN); - robot.waitForIdle(); + // Upper left + glide(rect.x + rect.width / 2, rect.y + rect.height / 2, + rect.x + 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 left + glide(rect.x + rect.width / 2, rect.y + rect.height / 2, + rect.x + 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(); - } + // 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(); } } diff --git a/jdk/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java b/jdk/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java new file mode 100644 index 00000000000..fc53de9dee2 --- /dev/null +++ b/jdk/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java @@ -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 --git a/jdk/test/javax/swing/plaf/motif/8165485/MotifHiDPIIconsTest.java b/jdk/test/javax/swing/plaf/motif/8165485/MotifHiDPIIconsTest.java new file mode 100644 index 00000000000..c3390fba392 --- /dev/null +++ b/jdk/test/javax/swing/plaf/motif/8165485/MotifHiDPIIconsTest.java @@ -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 --git a/jdk/test/javax/swing/text/CSSBorder/6796710/bug6796710.java b/jdk/test/javax/swing/text/CSSBorder/6796710/bug6796710.java index 1cd3c7143e2..e492a62c7de 100644 --- a/jdk/test/javax/swing/text/CSSBorder/6796710/bug6796710.java +++ b/jdk/test/javax/swing/text/CSSBorder/6796710/bug6796710.java @@ -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 @@ public class bug6796710 { } }); - robot.waitForIdle(); + robot.delay(1000); // On Linux platforms realSync doesn't guaranties setSize completion Thread.sleep(1000); diff --git a/jdk/test/javax/swing/text/Caret/8163124/CaretFloatingPointAPITest.java b/jdk/test/javax/swing/text/Caret/8163124/CaretFloatingPointAPITest.java new file mode 100644 index 00000000000..19d6d6a8607 --- /dev/null +++ b/jdk/test/javax/swing/text/Caret/8163124/CaretFloatingPointAPITest.java @@ -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 --git a/jdk/test/javax/swing/text/JTextComponent/8156217/TextSelectionTest.java b/jdk/test/javax/swing/text/JTextComponent/8156217/TextSelectionTest.java new file mode 100644 index 00000000000..73fdf0d1076 --- /dev/null +++ b/jdk/test/javax/swing/text/JTextComponent/8156217/TextSelectionTest.java @@ -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 --git a/jdk/test/javax/swing/text/View/8156217/FPMethodCalledTest.java b/jdk/test/javax/swing/text/View/8156217/FPMethodCalledTest.java new file mode 100644 index 00000000000..ed9693bbb0c --- /dev/null +++ b/jdk/test/javax/swing/text/View/8156217/FPMethodCalledTest.java @@ -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 --git a/langtools/test/jdk/jshell/EditorPadTest.java b/jdk/test/jdk/editpad/EditPadTest.java similarity index 52% rename from langtools/test/jdk/jshell/EditorPadTest.java rename to jdk/test/jdk/editpad/EditPadTest.java index e907aa4625c..8565a0046ce 100644 --- a/langtools/test/jdk/jshell/EditorPadTest.java +++ b/jdk/test/jdk/editpad/EditPadTest.java @@ -23,12 +23,12 @@ /* * @test - * @bug 8139872 + * @bug 8167636 8167639 8168972 * @summary Testing built-in editor. * @modules java.desktop/java.awt - * jdk.jshell/jdk.internal.jshell.tool - * @build ReplToolTesting EditorTestBase - * @run testng EditorPadTest + * jdk.internal.ed/jdk.internal.editor.spi + * jdk.editpad/jdk.editpad + * @run testng EditPadTest */ import java.awt.AWTException; @@ -42,7 +42,10 @@ 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; @@ -57,11 +60,17 @@ 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; -public class EditorPadTest extends EditorTestBase { +@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; @@ -69,14 +78,6 @@ public class EditorPadTest extends EditorTestBase { 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()) { @@ -95,97 +96,187 @@ public class EditorPadTest extends EditorTestBase { executorShutdown(); } - @Override - public void writeSource(String s) { - SwingUtilities.invokeLater(() -> area.setText(s)); + public void testSimple() { + testEdit("abcdef", 1, "xyz", + () -> assertSource("abcdef"), + () -> writeSource("xyz"), + () -> accept(), + () -> assertSource("xyz"), + () -> shutdownEditor()); } - @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); + 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; } } - @Override - public void accept() { + 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); } - @Override - public void exit() { + private void exit() { clickOn(exit); } - @Override - public void cancel() { + private void cancel() { clickOn(cancel); } - @Override - public void shutdownEditor() { + private 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")) { + if (f.getTitle().equals(WINDOW_LABEL)) { frame = (JFrame) f; // workaround frame.setLocation(0, 0); @@ -236,6 +327,11 @@ public class EditorPadTest extends EditorTestBase { } private void clickOn(JButton button) { + waitForIdle(); + waitForIdle(); + waitForIdle(); + waitForIdle(); + waitForIdle(); waitForIdle(); Point p = button.getLocationOnScreen(); Dimension d = button.getSize(); diff --git a/jdk/test/sun/reflect/ReflectionFactory/ReflectionFactoryTest.java b/jdk/test/sun/reflect/ReflectionFactory/ReflectionFactoryTest.java index 82a5000895c..3fac89f81a6 100644 --- a/jdk/test/sun/reflect/ReflectionFactory/ReflectionFactoryTest.java +++ b/jdk/test/sun/reflect/ReflectionFactory/ReflectionFactoryTest.java @@ -45,7 +45,7 @@ import org.testng.TestNG; /* * @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 @@ public class ReflectionFactoryTest { } } + @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 @@ public class ReflectionFactoryTest { 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 @@ public class ReflectionFactoryTest { } } + 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 --git a/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java b/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java index 2c89e2b16b3..438d640c4c7 100644 --- a/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java +++ b/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java @@ -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.ByteArrayOutputStream; 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 @@ public class NoConsoleOutput { 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 @@ public class NoConsoleOutput { 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 @@ public class NoConsoleOutput { 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 @@ public class NoConsoleOutput { 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 class NoConsoleOutput { 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 --git a/jdk/test/sun/security/ec/TestEC.java b/jdk/test/sun/security/ec/TestEC.java index de3783da260..c82e1fdac48 100644 --- a/jdk/test/sun/security/ec/TestEC.java +++ b/jdk/test/sun/security/ec/TestEC.java @@ -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 --git a/jdk/test/sun/security/krb5/auto/ReplayCacheExpunge.java b/jdk/test/sun/security/krb5/auto/ReplayCacheExpunge.java index da68ec3b7e1..68eb970fb29 100644 --- a/jdk/test/sun/security/krb5/auto/ReplayCacheExpunge.java +++ b/jdk/test/sun/security/krb5/auto/ReplayCacheExpunge.java @@ -47,15 +47,15 @@ public class ReplayCacheExpunge { 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 @@ public class ReplayCacheTestProc { "/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()); + } + } + + for (Ex x : result) { + x.run(); + } + + pi.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 @@ public class ReplayCacheTestProc { 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 @@ public class ReplayCacheTestProc { } } - // 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; - } - // 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(); - } - // 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(); + 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(); } + // generates hash of authenticator inside ap-req inside initsectoken - private static String hash(String req) throws Exception { - byte[] data = Base64.getDecoder().decode(req); + private static void record(String label, Req req) throws Exception { + byte[] data = Base64.getDecoder().decode(req.msg); data = Arrays.copyOfRange(data, 17, data.length); - byte[] hash = MessageDigest.getInstance("MD5").digest(new APReq(data).authenticator.getBytes()); + + 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))); + } + } + + // 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()); - if (debug) - System.setProperty("javax.net.debug", "all"); + 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); - /* - * Start the tests. - */ - new AnonCipherWithWantClientAuth(); - } + // Signal the client, the server is ready to accept connection. + test.signalServerReady(); - Thread clientThread = null; - Thread serverThread = null; - - /* - * 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); - } - - /* - * Wait for other side to close down. - */ - if (separateServerThread) { - serverThread.join(); - } else { - clientThread.join(); - } - - /* - * 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; - } - - 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; - } + // 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; } - }; - serverThread.start(); - } else { - doServerSide(); - } - } + SSLTest.print("Server accepted connection"); - 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; + // 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(); + + 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(); } - }; - clientThread.start(); - } else { - doClientSide(); - } + }) + .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); + + InputStream sslIS = socket.getInputStream(); + OutputStream sslOS = socket.getOutputStream(); + + sslOS.write(280); + sslOS.flush(); + sslIS.read(); + }) + .runTest(); } } diff --git a/jdk/test/sun/util/calendar/zi/tzdata/VERSION b/jdk/test/sun/util/calendar/zi/tzdata/VERSION index f587cb7fca7..7009f248679 100644 --- a/jdk/test/sun/util/calendar/zi/tzdata/VERSION +++ b/jdk/test/sun/util/calendar/zi/tzdata/VERSION @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2016g +tzdata2016h diff --git a/jdk/test/sun/util/calendar/zi/tzdata/asia b/jdk/test/sun/util/calendar/zi/tzdata/asia index 65e5f944b0e..71711a946d1 100644 --- a/jdk/test/sun/util/calendar/zi/tzdata/asia +++ b/jdk/test/sun/util/calendar/zi/tzdata/asia @@ -2567,11 +2567,6 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # 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 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # # 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 2011 only - Sep 30 0:00 0 - 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 @@ Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1 # 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. +# 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. # -# 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. -# -# 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 --git a/jdk/test/sun/util/calendar/zi/tzdata/australasia b/jdk/test/sun/util/calendar/zi/tzdata/australasia index 20a40206431..23153b171fa 100644 --- a/jdk/test/sun/util/calendar/zi/tzdata/australasia +++ b/jdk/test/sun/util/calendar/zi/tzdata/australasia @@ -373,7 +373,13 @@ Zone Indian/Cocos 6:27:40 - LMT 1900 # 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 --git a/jdk/test/sun/util/calendar/zi/tzdata/europe b/jdk/test/sun/util/calendar/zi/tzdata/europe index aededb1d253..d182dbb6ba8 100644 --- a/jdk/test/sun/util/calendar/zi/tzdata/europe +++ b/jdk/test/sun/util/calendar/zi/tzdata/europe @@ -1931,7 +1931,7 @@ Zone Europe/Monaco 0:29:32 - LMT 1891 Mar 15 # 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 @@ Zone Europe/Zurich 0:34:08 - LMT 1853 Jul 16 # See above comment. # 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 - Jul 31 0:00 1:00 S 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 --git a/jdk/test/sun/util/calendar/zi/tzdata/northamerica b/jdk/test/sun/util/calendar/zi/tzdata/northamerica index 8ab635d089c..56b089c8fc5 100644 --- a/jdk/test/sun/util/calendar/zi/tzdata/northamerica +++ b/jdk/test/sun/util/calendar/zi/tzdata/northamerica @@ -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 --git a/jdk/test/tools/jar/mmrjar/ConcealedPackage.java b/jdk/test/tools/jar/mmrjar/ConcealedPackage.java new file mode 100644 index 00000000000..cbe449ad4ed --- /dev/null +++ b/jdk/test/tools/jar/mmrjar/ConcealedPackage.java @@ -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 --git a/jdk/test/tools/jar/mmrjar/src/classes/p/Hi.java b/jdk/test/tools/jar/mmrjar/src/classes/p/Hi.java new file mode 100644 index 00000000000..954961c95eb --- /dev/null +++ b/jdk/test/tools/jar/mmrjar/src/classes/p/Hi.java @@ -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 --git a/langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/modulesourcepath/m/p2/C2.java b/jdk/test/tools/jar/mmrjar/src/mr9/module-info.java similarity index 94% rename from langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/modulesourcepath/m/p2/C2.java rename to jdk/test/tools/jar/mmrjar/src/mr9/module-info.java index cb3738cd735..386ac9932df 100644 --- a/langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/modulesourcepath/m/p2/C2.java +++ b/jdk/test/tools/jar/mmrjar/src/mr9/module-info.java @@ -21,6 +21,7 @@ * questions. */ -package p2; +module m1 { + exports p; +} -public class C2 extends p1.C1.InnerDefinition {} diff --git a/jdk/test/tools/jar/mmrjar/src/mr9/p/Hi.java b/jdk/test/tools/jar/mmrjar/src/mr9/p/Hi.java new file mode 100644 index 00000000000..2c4eca1b92d --- /dev/null +++ b/jdk/test/tools/jar/mmrjar/src/mr9/p/Hi.java @@ -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 --git a/langtools/test/tools/javac/diags/examples/XaddreadsMalformedEntry.java b/jdk/test/tools/jar/mmrjar/src/mr9/p/internal/Bar.java similarity index 89% rename from langtools/test/tools/javac/diags/examples/XaddreadsMalformedEntry.java rename to jdk/test/tools/jar/mmrjar/src/mr9/p/internal/Bar.java index b38f4bed7e7..f962af3abab 100644 --- a/langtools/test/tools/javac/diags/examples/XaddreadsMalformedEntry.java +++ b/jdk/test/tools/jar/mmrjar/src/mr9/p/internal/Bar.java @@ -21,8 +21,11 @@ * questions. */ -// key: compiler.err.xaddreads.malformed.entry -// options: --add-reads jdk.compiler +package p.internal; -public class XaddreadsMalformedEntry { +public class Bar { + @Override + public String toString() { + return "p.internal.Bar"; + } } diff --git a/jdk/test/tools/jlink/JLinkPluginsTest.java b/jdk/test/tools/jlink/JLinkPluginsTest.java index da9e112238b..5f0a4537336 100644 --- a/jdk/test/tools/jlink/JLinkPluginsTest.java +++ b/jdk/test/tools/jlink/JLinkPluginsTest.java @@ -83,5 +83,21 @@ public class JLinkPluginsTest { 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 --git a/jdk/test/tools/jlink/JLinkSigningTest.java b/jdk/test/tools/jlink/JLinkSigningTest.java new file mode 100644 index 00000000000..169d3904c41 --- /dev/null +++ b/jdk/test/tools/jlink/JLinkSigningTest.java @@ -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 --git a/jdk/test/tools/jlink/JLinkTest.java b/jdk/test/tools/jlink/JLinkTest.java index 2215bef8ec0..79a920b4be6 100644 --- a/jdk/test/tools/jlink/JLinkTest.java +++ b/jdk/test/tools/jlink/JLinkTest.java @@ -109,19 +109,16 @@ public class JLinkTest { .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 @@ public class JLinkTest { .modulePath(helper.defaultModulePath()) .output(helper.createNewImageDir(moduleName)) .addMods("m") - .option("") .call().assertSuccess(); moduleName = "mod"; jmod = helper.generateDefaultJModule(moduleName).assertSuccess(); @@ -140,7 +136,6 @@ public class JLinkTest { .modulePath(helper.defaultModulePath()) .output(helper.createNewImageDir(moduleName)) .addMods("m") - .option("") .call().assertSuccess(); } @@ -282,18 +277,21 @@ public class JLinkTest { 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 --git a/jdk/test/tools/jlink/multireleasejar/JLinkMultiReleaseJarTest.java b/jdk/test/tools/jlink/multireleasejar/JLinkMultiReleaseJarTest.java new file mode 100644 index 00000000000..874f5ea78c3 --- /dev/null +++ b/jdk/test/tools/jlink/multireleasejar/JLinkMultiReleaseJarTest.java @@ -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 --git a/langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/ServiceDefinitionInner.java b/jdk/test/tools/jlink/multireleasejar/base/m1/module-info.java similarity index 92% rename from langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/ServiceDefinitionInner.java rename to jdk/test/tools/jlink/multireleasejar/base/m1/module-info.java index f519259636d..9a82076cd29 100644 --- a/langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/ServiceDefinitionInner.java +++ b/jdk/test/tools/jlink/multireleasejar/base/m1/module-info.java @@ -21,5 +21,6 @@ * questions. */ -// key: compiler.err.service.definition.is.inner -// key: compiler.err.encl.class.required +module m1 { + exports p; +} diff --git a/jdk/test/tools/jlink/multireleasejar/base/m1/p/Main.java b/jdk/test/tools/jlink/multireleasejar/base/m1/p/Main.java new file mode 100644 index 00000000000..f63d4292202 --- /dev/null +++ b/jdk/test/tools/jlink/multireleasejar/base/m1/p/Main.java @@ -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 --git a/jdk/test/tools/jlink/multireleasejar/rt/m1/module-info.java b/jdk/test/tools/jlink/multireleasejar/rt/m1/module-info.java new file mode 100644 index 00000000000..080b2ef7dd4 --- /dev/null +++ b/jdk/test/tools/jlink/multireleasejar/rt/m1/module-info.java @@ -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 --git a/jdk/test/tools/jlink/multireleasejar/rt/m1/p/Main.java b/jdk/test/tools/jlink/multireleasejar/rt/m1/p/Main.java new file mode 100644 index 00000000000..01512c78d92 --- /dev/null +++ b/jdk/test/tools/jlink/multireleasejar/rt/m1/p/Main.java @@ -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 --git a/jdk/test/tools/jlink/multireleasejar/rt/m1/p/Type.java b/jdk/test/tools/jlink/multireleasejar/rt/m1/p/Type.java new file mode 100644 index 00000000000..19d2c3cdd88 --- /dev/null +++ b/jdk/test/tools/jlink/multireleasejar/rt/m1/p/Type.java @@ -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 --git a/jdk/test/tools/jlink/multireleasejar/rt/m1/q/PublicClass.java b/jdk/test/tools/jlink/multireleasejar/rt/m1/q/PublicClass.java new file mode 100644 index 00000000000..4975b3d754a --- /dev/null +++ b/jdk/test/tools/jlink/multireleasejar/rt/m1/q/PublicClass.java @@ -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 --git a/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java b/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java index a7cd181959f..6e6b57f89dd 100644 --- a/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java +++ b/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java @@ -40,7 +40,7 @@ import tests.Result; /* * @test - * @bug 8152143 8152704 8155649 + * @bug 8152143 8152704 8155649 8165804 * @summary IncludeLocalesPlugin tests * @author Naoto Sato * @library ../../lib @@ -236,6 +236,7 @@ public class IncludeLocalesPluginTest { "/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 @@ public class IncludeLocalesPluginTest { "/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 @@ public class IncludeLocalesPluginTest { 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 --git a/jdk/test/tools/jmod/JmodTest.java b/jdk/test/tools/jmod/JmodTest.java index 5be6a692daf..f3224c26904 100644 --- a/jdk/test/tools/jmod/JmodTest.java +++ b/jdk/test/tools/jmod/JmodTest.java @@ -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 @@ public class JmodTest { 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 --git a/jdk/test/tools/jmod/hashes/HashesTest.java b/jdk/test/tools/jmod/hashes/HashesTest.java index e01ecdb8046..22752e759f1 100644 --- a/jdk/test/tools/jmod/hashes/HashesTest.java +++ b/jdk/test/tools/jmod/hashes/HashesTest.java @@ -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.ModuleDescriptor; 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.Set; 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 @@ public class HashesTest { 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 @@ public class HashesTest { // 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 @@ public class HashesTest { } 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 --git a/jdk/test/tools/jmod/src/apa/jdk/test/apa/Apa.java b/jdk/test/tools/jmod/src/apa/jdk/test/apa/Apa.java new file mode 100644 index 00000000000..7bc7def8d95 --- /dev/null +++ b/jdk/test/tools/jmod/src/apa/jdk/test/apa/Apa.java @@ -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 --git a/jdk/test/tools/jmod/src/apa/module-info.java b/jdk/test/tools/jmod/src/apa/module-info.java new file mode 100644 index 00000000000..ca03826e233 --- /dev/null +++ b/jdk/test/tools/jmod/src/apa/module-info.java @@ -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 --git a/jdk/test/tools/launcher/MiscTests.java b/jdk/test/tools/launcher/MiscTests.java index e9a71e5f224..344730afe28 100644 --- a/jdk/test/tools/launcher/MiscTests.java +++ b/jdk/test/tools/launcher/MiscTests.java @@ -69,8 +69,6 @@ public class MiscTests extends TestHelper { 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 @@ public class MiscTests extends TestHelper { 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 --git a/jdk/test/tools/launcher/modules/classpath/JavaClassPathTest.java b/jdk/test/tools/launcher/modules/classpath/JavaClassPathTest.java new file mode 100644 index 00000000000..72afcb06fc0 --- /dev/null +++ b/jdk/test/tools/launcher/modules/classpath/JavaClassPathTest.java @@ -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 --git a/jdk/test/tools/launcher/modules/classpath/src/m/jdk/test/Main.java b/jdk/test/tools/launcher/modules/classpath/src/m/jdk/test/Main.java new file mode 100644 index 00000000000..41e7cd8717d --- /dev/null +++ b/jdk/test/tools/launcher/modules/classpath/src/m/jdk/test/Main.java @@ -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 --git a/langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/modulesourcepath/m/module-info.java b/jdk/test/tools/launcher/modules/classpath/src/m/module-info.java similarity index 94% rename from langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/modulesourcepath/m/module-info.java rename to jdk/test/tools/launcher/modules/classpath/src/m/module-info.java index 137812f03fb..457c357c5e8 100644 --- a/langtools/test/tools/javac/diags/examples/ServiceDefinitionInner/modulesourcepath/m/module-info.java +++ b/jdk/test/tools/launcher/modules/classpath/src/m/module-info.java @@ -22,6 +22,5 @@ */ module m { - provides p1.C1.InnerDefinition with p2.C2; - exports p1; } + diff --git a/jdk/test/tools/pack200/MultiRelease.java b/jdk/test/tools/pack200/MultiRelease.java index 7b3f8a3b91a..d5e0438544d 100644 --- a/jdk/test/tools/pack200/MultiRelease.java +++ b/jdk/test/tools/pack200/MultiRelease.java @@ -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 @@ public class MultiRelease { } else { System.out.println("All tests(" + pass + ") passes"); } + Utils.cleanup(); } /* diff --git a/jdk/test/tools/pack200/Utils.java b/jdk/test/tools/pack200/Utils.java index 20b18b6fff9..76ab9aaba44 100644 --- a/jdk/test/tools/pack200/Utils.java +++ b/jdk/test/tools/pack200/Utils.java @@ -94,7 +94,7 @@ class Utils { } 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 @@ class Utils { 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 --git a/langtools/.hgtags b/langtools/.hgtags index ab7c768cb4e..cafeca2beaf 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -384,3 +384,5 @@ dd56c243c199a540c9f1fbff4855f0934b32a9d0 jdk-9+137 17a82cb0e4b480e97021691d39917f15e3f7b653 jdk-9+139 6842e63d6c3971172214b411f29965852ca175d1 jdk-9+140 296c875051187918f8f3f87e9432036d13013d39 jdk-9+141 +d245e56f4a79a8a8d18bd143c08f079ee98ab638 jdk-9+142 +6ef8a1453577832626b0efb7f70a3102b721ebbf jdk-9+143 diff --git a/langtools/make/build.xml b/langtools/make/build.xml index 94a9aee474f..864f2cbb90a 100644 --- a/langtools/make/build.xml +++ b/langtools/make/build.xml @@ -84,17 +84,21 @@ - + - + - + @@ -207,7 +211,9 @@ - + + + diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/doclint/Entity.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/doclint/Entity.java index 4b5cf75d5dd..970cb399d53 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/doclint/Entity.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/doclint/Entity.java @@ -297,17 +297,21 @@ public enum Entity { 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java index 384dadc8045..f9c4adadc5d 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java @@ -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 @@ public class JavacTaskImpl extends BasicJavacTask { @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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java index cd729736f88..120a57eb7db 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java @@ -1004,7 +1004,7 @@ public class Types { 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 @@ public class Types { 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java index 5eb09f5c978..2044b29477a 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java @@ -853,9 +853,9 @@ public class Flow { 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 @@ public class Flow { // 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 @@ public class Flow { // 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 @@ public class Flow { // 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java index d2ca305072a..7850faceb62 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java @@ -404,15 +404,11 @@ public class Infer { } 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 @@ public class Infer { 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; - } - //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) { + 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; + } + Type captureOfTo = types.capture(to); /* T is a reference type, but is not a wildcard-parameterized type, and either */ diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java index c9a85ab7ec3..2850e2506f4 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java @@ -36,7 +36,6 @@ import java.util.HashSet; 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.RequiresFlag; 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 @@ public class Modules extends JCTree.Visitor { 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 @@ public class Modules extends JCTree.Visitor { 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 @@ public class Modules extends JCTree.Visitor { 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 @@ public class Modules extends JCTree.Visitor { 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 @@ public class Modules extends JCTree.Visitor { } 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 @@ public class Modules extends JCTree.Visitor { 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 @@ public class Modules extends JCTree.Visitor { 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 @@ public class Modules extends JCTree.Visitor { } 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 @@ public class Modules extends JCTree.Visitor { .filter(systemModulePred.negate().and(observablePred)); break; default: + if (!isValidName(added)) + continue; modules = Stream.of(syms.enterModule(names.fromString(added))); break; } @@ -1141,8 +1152,9 @@ public class Modules extends JCTree.Visitor { 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 @@ public class Modules extends JCTree.Visitor { 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 @@ public class Modules extends JCTree.Visitor { 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 @@ public class Modules extends JCTree.Visitor { 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 @@ public class Modules extends JCTree.Visitor { } } + 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 @@ public class Modules extends JCTree.Visitor { 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 @@ public class Modules extends JCTree.Visitor { } // 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); - ModuleSymbol msym = syms.enterModule(names.fromString(targetName)); - for (String source : sources.split("[ ,]+")) { - ModuleSymbol sourceModule; - if (source.equals("ALL-UNNAMED")) { - sourceModule = syms.unnamedModule; + if (!isValidName(sourceName)) + continue; + + 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 @@ public class Modules extends JCTree.Visitor { } } + private boolean isValidName(CharSequence name) { + return SourceVersion.isName(name, Source.toSourceVersion(source)); + } + // DEBUG private String toString(ModuleSymbol msym) { return msym.name + "[" diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index 49f8489193f..1c55157c683 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -554,7 +554,8 @@ public class Resolve { } 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java index 3e41246db81..843a0e808b2 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java @@ -39,6 +39,7 @@ import java.nio.file.FileSystem; 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 java.util.stream.Stream; 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 @@ public class Locations { } 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index 662bedc71d8..c1e0964aaef 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -1328,7 +1328,7 @@ public class ClassReader { } 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 @@ public class ClassReader { /** 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) - typevars.enter(xs.head.tsym); - } - - protected void enterTypevars(Symbol sym) { - if (sym.owner.kind == MTH) { - enterTypevars(sym.owner); - enterTypevars(sym.owner.owner); + 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); } - enterTypevars(sym.type); } protected ClassSymbol enterClass(Name name) { @@ -2388,7 +2386,7 @@ public class ClassReader { // 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 @@ public class ClassReader { 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java index 5980295444e..9d52eff4027 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java @@ -43,6 +43,7 @@ import java.util.regex.Matcher; 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 @@ public class Arguments { /** * 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 @@ public class Arguments { 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; - } - 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 - } - }); - } + 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; + } + } + } + } + } + } + + 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; - return !errors; + 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; + + 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java index d64b6356280..756b0080bc2 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java @@ -43,6 +43,7 @@ import java.util.Map; 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 @@ public enum Option { 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 @@ public enum Option { 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 @@ public enum Option { 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 enum Option { */ 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); } @@ -1032,6 +1105,15 @@ public enum Option { return false; } + /** + * 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 diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index bdd8fff2a05..0e173fc133d 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -2124,6 +2124,10 @@ compiler.misc.explicit.param.do.not.conform.to.bounds=\ 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} @@ -2765,10 +2769,6 @@ compiler.err.service.implementation.must.be.subtype.of.service.interface=\ compiler.err.service.implementation.is.inner=\ 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.cyclic.requires=\ 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: option name, 1: string +compiler.warn.bad.name.for.option=\ + bad name in value for {0} option: ''{1}'' -# 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: 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.locn.module_path=\ 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties index c7caed84e51..faa6db19881 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties @@ -357,6 +357,10 @@ javac.err.file.not.file=\ 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java index ae82c75737c..0571990a730 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java @@ -48,6 +48,7 @@ import com.sun.tools.javac.code.Type; 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 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Iterators.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Iterators.java index 24e0a02aaca..0cec3142a7e 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Iterators.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Iterators.java @@ -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 class Iterators { } public O next() { - if (!hasNext()) + if (currentIterator == EMPTY && !hasNext()) { throw new NoSuchElementException(); - + } return currentIterator.next(); } diff --git a/langtools/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocFormatter.java b/langtools/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocFormatter.java new file mode 100644 index 00000000000..ba42953d20d --- /dev/null +++ b/langtools/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocFormatter.java @@ -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 --git a/langtools/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocHelper.java b/langtools/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocHelper.java new file mode 100644 index 00000000000..81aa169e10e --- /dev/null +++ b/langtools/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocHelper.java @@ -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 --git a/langtools/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/resources/javadocformatter.properties b/langtools/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/resources/javadocformatter.properties new file mode 100644 index 00000000000..afaaaba6b18 --- /dev/null +++ b/langtools/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/resources/javadocformatter.properties @@ -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 --git a/langtools/src/jdk.compiler/share/classes/module-info.java b/langtools/src/jdk.compiler/share/classes/module-info.java index adbd78224c0..0b66b4d2b1e 100644 --- a/langtools/src/jdk.compiler/share/classes/module-info.java +++ b/langtools/src/jdk.compiler/share/classes/module-info.java @@ -65,6 +65,9 @@ module jdk.compiler { 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 --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java index 87e872e01f8..175ac3fce89 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java @@ -638,6 +638,8 @@ public class Main implements DiagnosticListener { // now the scanning phase + boolean scanStatus = true; + switch (scanMode) { case LIST: for (DeprData dd : deprList) { @@ -661,24 +663,22 @@ public class Main implements DiagnosticListener { 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('.', '/')); - } - - if (!success) { - return false; + s = scan.processClassName(a.replace('.', '/')); } + scanStatus = scanStatus && s; } break; } - return true; + return scanStatus; } /** diff --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Messages.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Messages.java index bd904b053e2..e57e3c15fc4 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Messages.java +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Messages.java @@ -34,6 +34,10 @@ import java.util.ResourceBundle; * 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 @@ public class Messages { 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 --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md index 5875e4efa9a..4dfb6631519 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md @@ -92,6 +92,9 @@ Given a jar file, **jdeprscan** will scan the classes found within 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 --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties index 71b85abfe5c..a5cc3a534b4 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties @@ -14,9 +14,9 @@ options:\n\ 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 @@ Unsupported options:\n\ \ 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.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.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 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 --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/Scan.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/Scan.java index 4088e11841d..3393ee15fd8 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/Scan.java +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/Scan.java @@ -28,6 +28,7 @@ package com.sun.tools.jdeprscan.scan; 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 @@ public class Scan { final boolean verbose; final ClassFinder finder; - boolean error = false; + boolean errorOccurred = false; public Scan(PrintStream out, PrintStream err, @@ -124,73 +125,74 @@ public class Scan { } } - 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))); } - // format should not have a newline - void err(String format, Object... args) { - error = true; - err.print("error: "); - err.printf(format, args); - err.println(); - } - - void printException(Exception ex) { - err.print(Messages.get("error.prefix")); - err.print(" "); + void errorException(Exception ex) { + errorOccurred = true; + err.println(Messages.get("scan.err.exception", ex.toString())); if (verbose) { ex.printStackTrace(err); - } else { - err.print(ex); } } + void errorNoClass(String className) { + errorOccurred = true; + err.println(Messages.get("scan.err.noclass", className)); + } + + 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)); + } + /** * Checks whether a member (method or field) is present in a class. * The checkMethod parameter determines whether this checks for a method @@ -271,7 +273,7 @@ public class Scan { } else { startClass = finder.find(startClassName); if (startClass == null) { - err("can't find class %s", startClassName); + errorNoClass(startClassName); return startClassName; } } @@ -295,7 +297,7 @@ public class Scan { 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 @@ public class Scan { 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 @@ public class Scan { 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 @@ public class Scan { } /** - * 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 @@ public class Scan { * @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, - 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()); - } - + CONSTANT_NameAndType_info nti, + 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 @@ public class Scan { */ void checkFieldRef(ClassFile cf, ConstantPool.CONSTANT_Fieldref_info fri) throws ConstantPoolException { - CONSTANT_NameAndType_info nti = fri.getNameAndTypeInfo(); String clname = fri.getClassName(); + CONSTANT_NameAndType_info nti = fri.getNameAndTypeInfo(); 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 @@ public class Scan { checkSuper(cf); checkInterfaces(cf); - checkTypes(cf, entries); + checkClasses(cf, entries); for (ConstantPool.CONSTANT_Methodref_info mri : entries.methodRefs) { - CONSTANT_NameAndType_info nti = mri.getNameAndTypeInfo(); String clname = mri.getClassName(); - checkMethodRef(cf, nti, clname, "scan.out.usesmethodintype", "scan.out.usesmethod"); + CONSTANT_NameAndType_info nti = mri.getNameAndTypeInfo(); + checkMethodRef(cf, clname, nti, "scan.out.usesmethod"); } for (ConstantPool.CONSTANT_InterfaceMethodref_info imri : entries.intfMethodRefs) { - CONSTANT_NameAndType_info nti = imri.getNameAndTypeInfo(); String clname = imri.getClassName(); - checkMethodRef(cf, nti, clname, "scan.out.usesintfmethodintype", "scan.out.usesintfmethod"); + CONSTANT_NameAndType_info nti = imri.getNameAndTypeInfo(); + checkMethodRef(cf, clname, nti, "scan.out.usesintfmethod"); } for (ConstantPool.CONSTANT_Fieldref_info fri : entries.fieldRefs) { @@ -545,6 +529,7 @@ public class Scan { */ 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 @@ public class Scan { } } return true; + } catch (NoSuchFileException nsfe) { + errorNoFile(jarname); } catch (IOException | ConstantPoolException ex) { - printException(ex); - return false; + errorException(ex); } + return false; } /** @@ -580,12 +567,15 @@ public class Scan { .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 @@ public class Scan { 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 --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DepsAnalyzer.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DepsAnalyzer.java index 2975813c14f..1941c14bfc9 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DepsAnalyzer.java +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DepsAnalyzer.java @@ -50,7 +50,7 @@ import static java.util.stream.Collectors.*; * * 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 @@ public class DepsAnalyzer { // 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 @@ public class DepsAnalyzer { /** * 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 @@ public class DepsAnalyzer { .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 @@ public class DepsAnalyzer { 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 --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java index b6640b1a4ba..02d6bc6ea9b 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java @@ -396,6 +396,11 @@ public class JdepsConfiguration implements AutoCloseable { ? Optional.of(uri) : Optional.empty(); } + @Override + public Stream list() { + return Stream.empty(); + } + @Override public void close() throws IOException { } diff --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java index 585ec524724..5549187b586 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java @@ -41,7 +41,7 @@ import java.util.stream.Stream; * 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 @@ public class JdepsFilter implements Dependency.Filter, Analyzer.Filter { // 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 @@ public class JdepsFilter implements Dependency.Filter, Analyzer.Filter { 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 --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java index 1c3e61dfff1..dca3f476d3c 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java @@ -221,6 +221,12 @@ class JdepsTask { } } }, + 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 @@ class JdepsTask { .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 @@ class JdepsTask { 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 @@ class JdepsTask { .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 @@ class JdepsTask { // 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 @@ class JdepsTask { * 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 @@ class JdepsTask { 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 @@ class JdepsTask { // 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 @@ class JdepsTask { String rootModule; Set addmods = new HashSet<>(); Runtime.Version multiRelease; + boolean showModulesAddExports; + boolean reduced; boolean hasFilter() { return numFilters() > 0; diff --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsWriter.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsWriter.java index fdfb3705e0e..0b7669fcc0e 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsWriter.java +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsWriter.java @@ -50,7 +50,7 @@ public abstract class JdepsWriter { 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 @@ public abstract class JdepsWriter { } // 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 --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java index 4f67a7357e9..810498b6718 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java @@ -126,12 +126,13 @@ class Module extends Archive { * 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 --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleAnalyzer.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleAnalyzer.java index a0030fbac8b..c5a5a971158 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleAnalyzer.java +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleAnalyzer.java @@ -41,10 +41,8 @@ import java.nio.file.Files; 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 @@ public class ModuleAnalyzer { 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(); @@ -276,45 +267,6 @@ public class ModuleAnalyzer { } - /** - * 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. */ diff --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleExportsAnalyzer.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleExportsAnalyzer.java new file mode 100644 index 00000000000..79847e6d6ec --- /dev/null +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleExportsAnalyzer.java @@ -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 --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleGraphBuilder.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleGraphBuilder.java new file mode 100644 index 00000000000..4352963049b --- /dev/null +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleGraphBuilder.java @@ -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 --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties index 7a26794260b..8bff48b92dc 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties @@ -149,6 +149,15 @@ main.opt.jdkinternals=\ \ 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 --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java index fa7fe711e8a..16e9f65bd0c 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java @@ -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 @@ class ConsoleIOContext extends IOContext { 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 @@ class ConsoleIOContext extends IOContext { "\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 --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/EditPad.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/EditPad.java deleted file mode 100644 index 2b2524368f9..00000000000 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/EditPad.java +++ /dev/null @@ -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 --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java index f579bc36020..d2eeff19c02 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java @@ -116,6 +116,10 @@ class Feedback { 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 @@ class Feedback { 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 @@ class Feedback { 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 --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java index f16dbba9727..fee09ef3027 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java @@ -89,6 +89,7 @@ import static java.nio.file.StandardOpenOption.WRITE; 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.FormatErrors; 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 @@ public class JShellTool implements MessageHandler { } /** - * Print using resource bundle look-up and adding prefix and postfix + * Resource bundle look-up * * @param key the resource key */ @@ -523,7 +526,7 @@ public class JShellTool implements MessageHandler { runFile(loadFile, "jshell"); } - if (regenerateOnDeath) { + if (regenerateOnDeath && feedback.shouldDisplayCommandFluff()) { hardmsg("jshell.msg.welcome", version()); } @@ -565,6 +568,8 @@ public class JShellTool implements MessageHandler { 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 @@ public class JShellTool implements MessageHandler { 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 @@ public class JShellTool implements MessageHandler { 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 @@ public class JShellTool implements MessageHandler { 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 @@ public class JShellTool implements MessageHandler { 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 { - ExternalEditor.edit(editor.cmd, errorHandler, src, saveHandler, input, - editor.wait, this::hardrb); + // 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]); + } } 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 @@ public class JShellTool implements MessageHandler { 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 --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties index 2d3b7f98a3b..0630af73bb6 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties @@ -54,10 +54,12 @@ jshell.err.no.such.command.or.snippet.id = No such command or snippet id: {0} 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.the.snippet.cannot.be.used.with.this.command = This command does not 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 @@ help.usage = \ 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 @@ Save any work before using this command 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 @@ jshell valid command and valid snippet in the order they were entered.\n\ 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 @@ startup.feedback = \ /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 --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java index ba5ff7b2ef2..205e9b837af 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java @@ -855,6 +855,8 @@ class Eval { 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 --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java index aa2dfeef901..145ace61827 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java @@ -47,7 +47,7 @@ import java.util.function.Supplier; 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 @@ public class JShell implements AutoCloseable { 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 @@ public class JShell implements AutoCloseable { if (!closed) { closeDown(); executionControl().close(); + if (sourceCodeAnalysis != null) { + sourceCodeAnalysis.close(); + } } } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/MaskCommentsAndModifiers.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/MaskCommentsAndModifiers.java index 72dfb6c9cd8..3cf80d1c2e7 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/MaskCommentsAndModifiers.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/MaskCommentsAndModifiers.java @@ -36,10 +36,14 @@ import java.util.stream.Stream; */ 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 @@ class MaskCommentsAndModifiers { // 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 @@ class MaskCommentsAndModifiers { * 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 @@ class MaskCommentsAndModifiers { } } - 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; + int match = c; + while (read() >= 0 && c != match && c != '\n' && c != '\r') { + write(c); + if (c == '\\') { + write(read()); } - 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); + 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; } - writeMask(c); - return true; - } else { - inside = true; - write('/'); - // read character falls through - } - } - - if (Character.isJavaIdentifierStart(c)) { - if (maskModifiers && !inside) { - StringBuilder sb = new StringBuilder(); + break; + case '@': do { - write(sb, c); - c = read(); + write(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; - } + while (Character.isWhitespace(c)) { + write(c); + read(); } - return next(c); // recurse to handle left-over character - } - } else if (!Character.isWhitespace(c)) { - inside = true; + // 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 --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java index 0a0a05c215c..cd20f77d9f3 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java @@ -63,12 +63,16 @@ public abstract class SourceCodeAnalysis { 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} @@ -265,6 +269,26 @@ public abstract class SourceCodeAnalysis { boolean matchesType(); } + /** + * 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. */ diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java index ce7fd0eb31e..018b524d98a 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java @@ -42,19 +42,17 @@ import com.sun.source.tree.Tree; 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.Matcher; 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.ExecutableType; 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 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { 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 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { } @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 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { "-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 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { 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(); } - if (!isEmptyArgumentsContext(arguments)) { - List actuals = computeActualInvocationTypes(at, arguments, prevPath); - List fullActuals = actuals != null ? actuals : Collections.emptyList(); + List result = Collections.emptyList(); - candidates = - this.filterExecutableTypesByArguments(at, candidates, fullActuals) - .stream() - .filter(method -> parameterType(method.fst, method.snd, fullActuals.size(), true).findAny().isPresent()) - .collect(Collectors.toList()); + 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()"); } - try (SourceCache sourceCache = new SourceCache(at)) { - return Util.stream(candidates) - .map(method -> Util.expunge(element2String(sourceCache, method.fst))) - .collect(joining("\n")); + 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); + } + + 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; + } + + @Override + public String signature() { + return signature; + } + + @Override + public String javadoc() { + return javadoc; + } + } private boolean isEmptyArgumentsContext(List arguments) { @@ -1178,18 +1247,6 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { 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 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { .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 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { 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 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { .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 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { 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 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { } 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 --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIDefaultExecutionControl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java similarity index 97% rename from langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIDefaultExecutionControl.java rename to langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java index 18f8282f93b..45114ac03a6 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIDefaultExecutionControl.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java @@ -60,7 +60,7 @@ import static jdk.jshell.execution.Util.remoteInputOutput; * @author Robert Field * @author Jan Lahoda */ -public class JDIDefaultExecutionControl extends JDIExecutionControl { +public class JdiDefaultExecutionControl extends JdiExecutionControl { private static final String REMOTE_AGENT = RemoteExecutionControl.class.getName(); @@ -117,14 +117,14 @@ public class JDIDefaultExecutionControl extends JDIExecutionControl { int port = listener.getLocalPort(); // Set-up the JDI connection - JDIInitiator jdii = new JDIInitiator(port, + 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 -> { + Util.detectJdiExitEvent(vm, s -> { for (Consumer h : deathListeners) { h.accept(s); } @@ -140,7 +140,7 @@ public class JDIDefaultExecutionControl extends JDIExecutionControl { 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)); + return remoteInputOutput(socket.getInputStream(), out, outputs, input, (objIn, objOut) -> new JdiDefaultExecutionControl(objOut, objIn, vm, process, deathListeners)); } } @@ -150,7 +150,7 @@ public class JDIDefaultExecutionControl extends JDIExecutionControl { * @param cmdout the output for commands * @param cmdin the input for responses */ - private JDIDefaultExecutionControl(ObjectOutput cmdout, ObjectInput cmdin, + private JdiDefaultExecutionControl(ObjectOutput cmdout, ObjectInput cmdin, VirtualMachine vm, Process process, List> deathListeners) { super(cmdout, cmdin); this.vm = vm; diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIEventHandler.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiEventHandler.java similarity index 97% rename from langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIEventHandler.java rename to langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiEventHandler.java index 180216e5ffc..893e671b85d 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIEventHandler.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiEventHandler.java @@ -34,7 +34,7 @@ import com.sun.jdi.event.*; * Adapted from jdb EventHandler. * Only exit and disconnect events processed. */ -class JDIEventHandler implements Runnable { +class JdiEventHandler implements Runnable { private final Thread thread; private volatile boolean connected = true; @@ -49,7 +49,7 @@ class JDIEventHandler implements Runnable { * @param reportVMExit callback to report exit/disconnect * (passed true if the VM has died) */ - JDIEventHandler(VirtualMachine vm, Consumer reportVMExit) { + JdiEventHandler(VirtualMachine vm, Consumer reportVMExit) { this.vm = vm; this.reportVMExit = reportVMExit; this.thread = new Thread(this, "event-handler"); diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIExecutionControl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiExecutionControl.java similarity index 97% rename from langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIExecutionControl.java rename to langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiExecutionControl.java index 1643f5a5445..2d27a3d5f06 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIExecutionControl.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiExecutionControl.java @@ -39,7 +39,7 @@ import static java.util.stream.Collectors.toMap; /** * Abstract JDI implementation of {@link jdk.jshell.spi.ExecutionControl} */ -public abstract class JDIExecutionControl extends StreamingExecutionControl implements ExecutionControl { +public abstract class JdiExecutionControl extends StreamingExecutionControl implements ExecutionControl { /** * Mapping from class names to JDI {@link ReferenceType}. @@ -51,7 +51,7 @@ public abstract class JDIExecutionControl extends StreamingExecutionControl impl * @param out the output from the remote agent * @param in the input to the remote agent */ - protected JDIExecutionControl(ObjectOutput out, ObjectInput in) { + protected JdiExecutionControl(ObjectOutput out, ObjectInput in) { super(out, in); } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIInitiator.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java similarity index 98% rename from langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIInitiator.java rename to langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java index 37d51db8c55..68ebc23717d 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIInitiator.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiInitiator.java @@ -40,7 +40,7 @@ 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 { +public class JdiInitiator { private VirtualMachine vm; private Process process = null; @@ -59,7 +59,7 @@ public class JDIInitiator { * @param host explicit hostname to use, if null use discovered * hostname, applies to listening only (!isLaunch) */ - public JDIInitiator(int port, List remoteVMOptions, String remoteAgent, + public JdiInitiator(int port, List remoteVMOptions, String remoteAgent, boolean isLaunch, String host) { this.remoteAgent = remoteAgent; String connectorName diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java index 8a131422b5a..81eac159b60 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java @@ -41,7 +41,7 @@ import static jdk.jshell.execution.Util.forwardExecutionControlAndIO; * 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 --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/Util.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/Util.java index 3ea2975ca56..1e17319c80d 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/Util.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/Util.java @@ -239,9 +239,9 @@ public class Util { * @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 --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java index 022d3d8bf45..b3f0f7da03c 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java @@ -44,12 +44,13 @@ import java.io.Serializable; * 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 --git a/langtools/src/jdk.jshell/share/classes/module-info.java b/langtools/src/jdk.jshell/share/classes/module-info.java index b9c6e5e2b26..f8d812255f7 100644 --- a/langtools/src/jdk.jshell/share/classes/module-info.java +++ b/langtools/src/jdk.jshell/share/classes/module-info.java @@ -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 --git a/langtools/test/Makefile b/langtools/test/Makefile index e07635cca0a..57792fa9721 100644 --- a/langtools/test/Makefile +++ b/langtools/test/Makefile @@ -253,7 +253,7 @@ JCK_RUNTIME_OUTPUT_DIR = $(ABS_TEST_OUTPUT_DIR)/jck-runtime-Xcompile # 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 --git a/langtools/test/ProblemList.txt b/langtools/test/ProblemList.txt index 8ed5359b3be..f8bdf1f6288 100644 --- a/langtools/test/ProblemList.txt +++ b/langtools/test/ProblemList.txt @@ -55,6 +55,7 @@ tools/javac/annotations/typeAnnotations/referenceinfos/Lambda.java 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 --git a/langtools/test/jdk/internal/shellsupport/doc/JavadocFormatterTest.java b/langtools/test/jdk/internal/shellsupport/doc/JavadocFormatterTest.java new file mode 100644 index 00000000000..e13d237cf9a --- /dev/null +++ b/langtools/test/jdk/internal/shellsupport/doc/JavadocFormatterTest.java @@ -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 --git a/langtools/test/jdk/internal/shellsupport/doc/JavadocHelperTest.java b/langtools/test/jdk/internal/shellsupport/doc/JavadocHelperTest.java new file mode 100644 index 00000000000..39d6cbe57f6 --- /dev/null +++ b/langtools/test/jdk/internal/shellsupport/doc/JavadocHelperTest.java @@ -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 --git a/langtools/test/jdk/jshell/ClassMembersTest.java b/langtools/test/jdk/jshell/ClassMembersTest.java index 88361be5382..22bbbefb36c 100644 --- a/langtools/test/jdk/jshell/ClassMembersTest.java +++ b/langtools/test/jdk/jshell/ClassMembersTest.java @@ -38,6 +38,9 @@ import javax.tools.Diagnostic; 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 @@ public class ClassMembersTest extends KullaTesting { 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 --git a/langtools/test/jdk/jshell/ClassesTest.java b/langtools/test/jdk/jshell/ClassesTest.java index fd629480aac..bcdd597da62 100644 --- a/langtools/test/jdk/jshell/ClassesTest.java +++ b/langtools/test/jdk/jshell/ClassesTest.java @@ -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 class ClassesTest extends KullaTesting { } 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 --git a/langtools/test/jdk/jshell/CompletenessTest.java b/langtools/test/jdk/jshell/CompletenessTest.java index a87f8270109..a435dc3aacb 100644 --- a/langtools/test/jdk/jshell/CompletenessTest.java +++ b/langtools/test/jdk/jshell/CompletenessTest.java @@ -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 @@ public class CompletenessTest extends KullaTesting { "@interface Anno", "void f()", "void f() throws E", + "@A(", }; static final String[] unknown = new String[] { diff --git a/langtools/test/jdk/jshell/CompletionSuggestionTest.java b/langtools/test/jdk/jshell/CompletionSuggestionTest.java index eb21ff65dac..8e355a1bd2b 100644 --- a/langtools/test/jdk/jshell/CompletionSuggestionTest.java +++ b/langtools/test/jdk/jshell/CompletionSuggestionTest.java @@ -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 class CompletionSuggestionTest extends KullaTesting { 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 class CompletionSuggestionTest extends KullaTesting { public void testErroneous() { assertCompletion("Undefined.|"); + assertSignature("does.not.exist|"); } public void testClinit() { @@ -474,59 +475,63 @@ public class CompletionSuggestionTest extends KullaTesting { 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 @@ public class CompletionSuggestionTest extends KullaTesting { 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 @@ public class CompletionSuggestionTest extends KullaTesting { 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 --git a/langtools/test/jdk/jshell/ErrorTranslationTest.java b/langtools/test/jdk/jshell/ErrorTranslationTest.java index 579f31760e7..a24d4ec5497 100644 --- a/langtools/test/jdk/jshell/ErrorTranslationTest.java +++ b/langtools/test/jdk/jshell/ErrorTranslationTest.java @@ -62,12 +62,9 @@ public class ErrorTranslationTest extends ReplToolTesting { public void testWarnings() { 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 --git a/langtools/test/jdk/jshell/FailOverExecutionControlTest.java b/langtools/test/jdk/jshell/FailOverExecutionControlTest.java index 7c34aed67fd..97cffd82579 100644 --- a/langtools/test/jdk/jshell/FailOverExecutionControlTest.java +++ b/langtools/test/jdk/jshell/FailOverExecutionControlTest.java @@ -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 @@ public class FailOverExecutionControlTest extends ExecutionControlTestBase { setUp(builder -> builder.executionEngine(failOverExecutionControlGenerator( new AlwaysFailingGenerator(), new AlwaysFailingGenerator(), - JDIDefaultExecutionControl.launch()))); + JdiDefaultExecutionControl.launch()))); } class AlwaysFailingGenerator implements ExecutionControl.Generator { diff --git a/langtools/test/jdk/jshell/IgnoreTest.java b/langtools/test/jdk/jshell/IgnoreTest.java index 08c648ae4b7..6f27f0f1801 100644 --- a/langtools/test/jdk/jshell/IgnoreTest.java +++ b/langtools/test/jdk/jshell/IgnoreTest.java @@ -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 class IgnoreTest extends KullaTesting { } 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 --git a/langtools/test/jdk/jshell/JavadocTest.java b/langtools/test/jdk/jshell/JavadocTest.java new file mode 100644 index 00000000000..d1b36bd3d81 --- /dev/null +++ b/langtools/test/jdk/jshell/JavadocTest.java @@ -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 --git a/langtools/test/jdk/jshell/JDILaunchingExecutionControlTest.java b/langtools/test/jdk/jshell/JdiLaunchingExecutionControlTest.java similarity index 86% rename from langtools/test/jdk/jshell/JDILaunchingExecutionControlTest.java rename to langtools/test/jdk/jshell/JdiLaunchingExecutionControlTest.java index 3baa5378d7b..3956712a1b8 100644 --- a/langtools/test/jdk/jshell/JDILaunchingExecutionControlTest.java +++ b/langtools/test/jdk/jshell/JdiLaunchingExecutionControlTest.java @@ -27,20 +27,20 @@ * @summary Tests for standard JDI connector (without failover) -- launching * @modules jdk.jshell/jdk.jshell.execution * @build KullaTesting ExecutionControlTestBase - * @run testng JDILaunchingExecutionControlTest + * @run testng JdiLaunchingExecutionControlTest */ import org.testng.annotations.Test; import org.testng.annotations.BeforeMethod; -import jdk.jshell.execution.JDIDefaultExecutionControl; +import jdk.jshell.execution.JdiDefaultExecutionControl; @Test -public class JDILaunchingExecutionControlTest extends ExecutionControlTestBase { +public class JdiLaunchingExecutionControlTest extends ExecutionControlTestBase { @BeforeMethod @Override public void setUp() { - setUp(builder -> builder.executionEngine(JDIDefaultExecutionControl.launch())); + setUp(builder -> builder.executionEngine(JdiDefaultExecutionControl.launch())); } } diff --git a/langtools/test/jdk/jshell/JDIListeningExecutionControlTest.java b/langtools/test/jdk/jshell/JdiListeningExecutionControlTest.java similarity index 86% rename from langtools/test/jdk/jshell/JDIListeningExecutionControlTest.java rename to langtools/test/jdk/jshell/JdiListeningExecutionControlTest.java index 2540b90a1e3..3d80c70b6fe 100644 --- a/langtools/test/jdk/jshell/JDIListeningExecutionControlTest.java +++ b/langtools/test/jdk/jshell/JdiListeningExecutionControlTest.java @@ -27,20 +27,20 @@ * @summary Tests for alternate JDI connector -- listening * @modules jdk.jshell/jdk.jshell.execution * @build KullaTesting ExecutionControlTestBase - * @run testng JDIListeningExecutionControlTest + * @run testng JdiListeningExecutionControlTest */ import org.testng.annotations.Test; import org.testng.annotations.BeforeMethod; -import jdk.jshell.execution.JDIDefaultExecutionControl; +import jdk.jshell.execution.JdiDefaultExecutionControl; @Test -public class JDIListeningExecutionControlTest extends ExecutionControlTestBase { +public class JdiListeningExecutionControlTest extends ExecutionControlTestBase { @BeforeMethod @Override public void setUp() { - setUp(builder -> builder.executionEngine(JDIDefaultExecutionControl.listen(null))); + setUp(builder -> builder.executionEngine(JdiDefaultExecutionControl.listen(null))); } } diff --git a/langtools/test/jdk/jshell/JDIListeningLocalhostExecutionControlTest.java b/langtools/test/jdk/jshell/JdiListeningLocalhostExecutionControlTest.java similarity index 85% rename from langtools/test/jdk/jshell/JDIListeningLocalhostExecutionControlTest.java rename to langtools/test/jdk/jshell/JdiListeningLocalhostExecutionControlTest.java index 52a4487c674..7796e57cdbb 100644 --- a/langtools/test/jdk/jshell/JDIListeningLocalhostExecutionControlTest.java +++ b/langtools/test/jdk/jshell/JdiListeningLocalhostExecutionControlTest.java @@ -27,20 +27,20 @@ * @summary Tests for alternate JDI connector -- listening to "localhost" * @modules jdk.jshell/jdk.jshell.execution * @build KullaTesting ExecutionControlTestBase - * @run testng JDIListeningLocalhostExecutionControlTest + * @run testng JdiListeningLocalhostExecutionControlTest */ import org.testng.annotations.Test; import org.testng.annotations.BeforeMethod; -import jdk.jshell.execution.JDIDefaultExecutionControl; +import jdk.jshell.execution.JdiDefaultExecutionControl; @Test -public class JDIListeningLocalhostExecutionControlTest extends ExecutionControlTestBase { +public class JdiListeningLocalhostExecutionControlTest extends ExecutionControlTestBase { @BeforeMethod @Override public void setUp() { - setUp(builder -> builder.executionEngine(JDIDefaultExecutionControl.listen("localhost"))); + setUp(builder -> builder.executionEngine(JdiDefaultExecutionControl.listen("localhost"))); } } diff --git a/langtools/test/jdk/jshell/KullaTesting.java b/langtools/test/jdk/jshell/KullaTesting.java index 9e73bd7fcf0..80de7b4e7be 100644 --- a/langtools/test/jdk/jshell/KullaTesting.java +++ b/langtools/test/jdk/jshell/KullaTesting.java @@ -72,11 +72,14 @@ import org.testng.annotations.AfterMethod; 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 class KullaTesting { } } - 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 --git a/langtools/test/jdk/jshell/MethodsTest.java b/langtools/test/jdk/jshell/MethodsTest.java index 6d0c3f4b4f9..ad5b4ac590d 100644 --- a/langtools/test/jdk/jshell/MethodsTest.java +++ b/langtools/test/jdk/jshell/MethodsTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8080357 + * @bug 8080357 8167643 * @summary Tests for EvaluationState.methods * @build KullaTesting TestingInputStream ExpectedDiagnostic * @run testng MethodsTest @@ -230,34 +230,33 @@ public class MethodsTest extends KullaTesting { assertActiveKeys(); } + + public void methodsAccessModifierIgnored() { + Snippet f = methodKey(assertEval("public String f() {return null;}", + added(VALID))); + assertNumberOfActiveMethods(1); + assertActiveKeys(); + + 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(); + } + public void methodsWarn() { - Snippet f = assertDeclareWarn1("public String f() {return null;}", + Snippet f = assertDeclareWarn1("static String f() {return null;}", new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 6, 0, -1, -1, Diagnostic.Kind.WARNING), 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), - 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;}", - 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)); - assertNumberOfActiveMethods(1); - assertActiveKeys(); - assertDeclareWarn1("final String f() {return null;}", new ExpectedDiagnostic("jdk.eval.warn.illegal.modifiers", 0, 5, 0, -1, -1, Diagnostic.Kind.WARNING), ste(MAIN_SNIPPET, VALID, VALID, false, null), diff --git a/langtools/test/jdk/jshell/ModifiersTest.java b/langtools/test/jdk/jshell/ModifiersTest.java index 8f7cdf273e1..1b64dd6c6f5 100644 --- a/langtools/test/jdk/jshell/ModifiersTest.java +++ b/langtools/test/jdk/jshell/ModifiersTest.java @@ -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 class ModifiersTest extends KullaTesting { 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 --git a/langtools/test/jdk/jshell/ToolBasicTest.java b/langtools/test/jdk/jshell/ToolBasicTest.java index 88f9e3c010f..4c4ee90d3b3 100644 --- a/langtools/test/jdk/jshell/ToolBasicTest.java +++ b/langtools/test/jdk/jshell/ToolBasicTest.java @@ -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 class ToolBasicTest extends ReplToolTesting { ); } + 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 @@ public class ToolBasicTest extends ReplToolTesting { 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 --git a/langtools/test/jdk/jshell/ToolFormatTest.java b/langtools/test/jdk/jshell/ToolFormatTest.java index 280484553ed..8e60db44941 100644 --- a/langtools/test/jdk/jshell/ToolFormatTest.java +++ b/langtools/test/jdk/jshell/ToolFormatTest.java @@ -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 @@ public class ToolFormatTest extends ReplToolTesting { 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 @@ public class ToolFormatTest extends ReplToolTesting { "/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 --git a/langtools/test/jdk/jshell/ToolRetainTest.java b/langtools/test/jdk/jshell/ToolRetainTest.java index 501d2412d4f..452a3d8dac2 100644 --- a/langtools/test/jdk/jshell/ToolRetainTest.java +++ b/langtools/test/jdk/jshell/ToolRetainTest.java @@ -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 @@ public class ToolRetainTest extends ReplToolTesting { (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 --git a/langtools/test/jdk/jshell/ToolSimpleTest.java b/langtools/test/jdk/jshell/ToolSimpleTest.java index fff509faf81..d97441ddddd 100644 --- a/langtools/test/jdk/jshell/ToolSimpleTest.java +++ b/langtools/test/jdk/jshell/ToolSimpleTest.java @@ -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 class ToolSimpleTest extends ReplToolTesting { } 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 class ToolSimpleTest extends ReplToolTesting { } 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 @@ public class ToolSimpleTest extends ReplToolTesting { .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 --git a/langtools/test/jdk/jshell/UserJDIUserRemoteTest.java b/langtools/test/jdk/jshell/UserJdiUserRemoteTest.java similarity index 95% rename from langtools/test/jdk/jshell/UserJDIUserRemoteTest.java rename to langtools/test/jdk/jshell/UserJdiUserRemoteTest.java index bfd04a1289c..b8d575362c0 100644 --- a/langtools/test/jdk/jshell/UserJDIUserRemoteTest.java +++ b/langtools/test/jdk/jshell/UserJdiUserRemoteTest.java @@ -26,7 +26,7 @@ * @bug 8160128 8159935 * @summary Tests for Aux channel, custom remote agents, custom JDI implementations. * @build KullaTesting ExecutionControlTestBase - * @run testng UserJDIUserRemoteTest + * @run testng UserJdiUserRemoteTest */ import java.io.ByteArrayOutputStream; import org.testng.annotations.Test; @@ -44,8 +44,8 @@ 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.JdiExecutionControl; +import jdk.jshell.execution.JdiInitiator; import jdk.jshell.execution.Util; import java.io.InputStream; import java.io.OutputStream; @@ -64,7 +64,7 @@ import static jdk.jshell.execution.Util.forwardExecutionControlAndIO; import static jdk.jshell.execution.Util.remoteInputOutput; @Test -public class UserJDIUserRemoteTest extends ExecutionControlTestBase { +public class UserJdiUserRemoteTest extends ExecutionControlTestBase { ExecutionControl currentEC; ByteArrayOutputStream auxStream; @@ -115,7 +115,7 @@ public class UserJDIUserRemoteTest extends ExecutionControlTestBase { } } -class MyExecutionControl extends JDIExecutionControl { +class MyExecutionControl extends JdiExecutionControl { private static final String REMOTE_AGENT = MyRemoteExecutionControl.class.getName(); @@ -128,7 +128,7 @@ class MyExecutionControl extends JDIExecutionControl { * * @return the generator */ - public static ExecutionControl.Generator create(UserJDIUserRemoteTest test) { + public static ExecutionControl.Generator create(UserJdiUserRemoteTest test) { return env -> make(env, test); } @@ -145,7 +145,7 @@ class MyExecutionControl extends JDIExecutionControl { * @return the channel * @throws IOException if there are errors in set-up */ - static ExecutionControl make(ExecutionEnv env, UserJDIUserRemoteTest test) throws IOException { + static ExecutionControl make(ExecutionEnv env, UserJdiUserRemoteTest test) throws IOException { try (final ServerSocket listener = new ServerSocket(0)) { // timeout after 60 seconds listener.setSoTimeout(60000); @@ -157,14 +157,14 @@ class MyExecutionControl extends JDIExecutionControl { opts.add(System.getProperty("java.class.path") + System.getProperty("path.separator") + System.getProperty("user.dir")); - JDIInitiator jdii = new JDIInitiator(port, + 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 -> { + Util.detectJdiExitEvent(vm, s -> { for (Consumer h : deathListeners) { h.accept(s); } diff --git a/langtools/test/tools/doclint/moduleTests/bad/module-info.java b/langtools/test/tools/doclint/moduleTests/bad/module-info.java index e9992a94b2a..779fc29cbaf 100644 --- a/langtools/test/tools/doclint/moduleTests/bad/module-info.java +++ b/langtools/test/tools/doclint/moduleTests/bad/module-info.java @@ -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 --git a/langtools/test/tools/doclint/moduleTests/good/module-info.java b/langtools/test/tools/doclint/moduleTests/good/module-info.java index 0c0c1a70e0f..72d3629fc81 100644 --- a/langtools/test/tools/doclint/moduleTests/good/module-info.java +++ b/langtools/test/tools/doclint/moduleTests/good/module-info.java @@ -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 --git a/langtools/test/tools/javac/AnonymousClass/AnonymousCtorExceptionTest.java b/langtools/test/tools/javac/AnonymousClass/AnonymousCtorExceptionTest.java new file mode 100644 index 00000000000..76f2dc79dc1 --- /dev/null +++ b/langtools/test/tools/javac/AnonymousClass/AnonymousCtorExceptionTest.java @@ -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 --git a/langtools/test/tools/javac/T6403466.java b/langtools/test/tools/javac/T6403466.java index 9cf291ea36b..6945d89e200 100644 --- a/langtools/test/tools/javac/T6403466.java +++ b/langtools/test/tools/javac/T6403466.java @@ -58,9 +58,7 @@ public class T6403466 extends AbstractProcessor { 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 --git a/langtools/test/tools/javac/T8132562/ClassPathWithDoubleQuotesTest.java b/langtools/test/tools/javac/T8132562/ClassPathWithDoubleQuotesTest.java new file mode 100644 index 00000000000..ba81593aa90 --- /dev/null +++ b/langtools/test/tools/javac/T8132562/ClassPathWithDoubleQuotesTest.java @@ -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 --git a/langtools/test/tools/javac/diags/examples/BadNameForOption.java b/langtools/test/tools/javac/diags/examples/BadNameForOption.java new file mode 100644 index 00000000000..13bb9f5f7ec --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/BadNameForOption.java @@ -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 --git a/langtools/test/tools/javac/diags/examples/CantFindModule/CantFindModule.java b/langtools/test/tools/javac/diags/examples/ModuleForOptionNotFound.java similarity index 88% rename from langtools/test/tools/javac/diags/examples/CantFindModule/CantFindModule.java rename to langtools/test/tools/javac/diags/examples/ModuleForOptionNotFound.java index 40b78f4c7b3..69fdb4c635a 100644 --- a/langtools/test/tools/javac/diags/examples/CantFindModule/CantFindModule.java +++ b/langtools/test/tools/javac/diags/examples/ModuleForOptionNotFound.java @@ -21,11 +21,12 @@ * questions. */ -// key: compiler.err.cant.find.module +// key: compiler.warn.module.for.option.not.found // key: compiler.err.doesnt.exist -// options: --add-exports undef/undef=ALL-UNNAMED +// options: --add-exports undefModule/undefPackage=ALL-UNNAMED -import undef.Any; +import undefPackage.Any; class Test {} + diff --git a/langtools/test/tools/javac/diags/examples/WrongNumberTypeArgsFragment.java b/langtools/test/tools/javac/diags/examples/WrongNumberTypeArgsFragment.java new file mode 100644 index 00000000000..f8a08d86445 --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/WrongNumberTypeArgsFragment.java @@ -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 --git a/jdk/src/java.base/share/classes/jdk/internal/module/ConfigurableModuleFinder.java b/langtools/test/tools/javac/generics/inference/8168134/T8168134.java similarity index 71% rename from jdk/src/java.base/share/classes/jdk/internal/module/ConfigurableModuleFinder.java rename to langtools/test/tools/javac/generics/inference/8168134/T8168134.java index 914f870044e..a1e4a5735ce 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ConfigurableModuleFinder.java +++ b/langtools/test/tools/javac/generics/inference/8168134/T8168134.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 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 @@ -22,25 +22,20 @@ * 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. +/* + * @test + * @bug 8168134 + * @summary Inference: javac incorrectly propagating inner constraint with primitive target + * @compile T8168134.java */ -public interface ConfigurableModuleFinder extends ModuleFinder { +abstract class T8168134 { + interface W {} + abstract B f(W e); + abstract C g(C b, long i); - public static enum Phase { - RUN_TIME, - LINK_TIME + void h(W i) { + g("", f(i)); } - - /** - * Configures this finder to work in the given phase. - */ - void configurePhase(Phase phase); - } diff --git a/langtools/test/tools/javac/meth/BadPolySig.java b/langtools/test/tools/javac/meth/BadPolySig.java new file mode 100644 index 00000000000..f607f63c258 --- /dev/null +++ b/langtools/test/tools/javac/meth/BadPolySig.java @@ -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 --git a/langtools/test/tools/javac/modules/AddExportsTest.java b/langtools/test/tools/javac/modules/AddExportsTest.java new file mode 100644 index 00000000000..e308aa50764 --- /dev/null +++ b/langtools/test/tools/javac/modules/AddExportsTest.java @@ -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 --git a/langtools/test/tools/javac/modules/AddModulesTest.java b/langtools/test/tools/javac/modules/AddModulesTest.java new file mode 100644 index 00000000000..326d43ca4ef --- /dev/null +++ b/langtools/test/tools/javac/modules/AddModulesTest.java @@ -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 --git a/langtools/test/tools/javac/modules/AddReadsTest.java b/langtools/test/tools/javac/modules/AddReadsTest.java index 1e09bebaae0..65a12116b49 100644 --- a/langtools/test/tools/javac/modules/AddReadsTest.java +++ b/langtools/test/tools/javac/modules/AddReadsTest.java @@ -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.JarTask; import toolbox.JavacTask; import toolbox.JavapTask; import toolbox.Task; -import toolbox.ToolBox; public class AddReadsTest extends ModuleTestBase { @@ -80,8 +80,8 @@ public class AddReadsTest extends ModuleTestBase { .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 @@ public class AddReadsTest extends ModuleTestBase { //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 @@ public class AddReadsTest extends ModuleTestBase { "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 @@ public class AddReadsTest extends ModuleTestBase { .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 --git a/langtools/test/tools/javac/modules/AnnotationProcessorsInModulesTest.java b/langtools/test/tools/javac/modules/AnnotationProcessorsInModulesTest.java index 8fb400daaef..c8c936287b0 100644 --- a/langtools/test/tools/javac/modules/AnnotationProcessorsInModulesTest.java +++ b/langtools/test/tools/javac/modules/AnnotationProcessorsInModulesTest.java @@ -230,8 +230,7 @@ public class AnnotationProcessorsInModulesTest extends ModuleTestBase { .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 --git a/langtools/test/tools/javac/modules/EdgeCases.java b/langtools/test/tools/javac/modules/EdgeCases.java index 13af55f6b60..1997a3da2c8 100644 --- a/langtools/test/tools/javac/modules/EdgeCases.java +++ b/langtools/test/tools/javac/modules/EdgeCases.java @@ -71,21 +71,22 @@ public class EdgeCases extends ModuleTestBase { @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 --git a/langtools/test/tools/javac/modules/LimitModulesTest.java b/langtools/test/tools/javac/modules/LimitModulesTest.java new file mode 100644 index 00000000000..cc489c962c5 --- /dev/null +++ b/langtools/test/tools/javac/modules/LimitModulesTest.java @@ -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 --git a/langtools/test/tools/javac/modules/ModuleTestBase.java b/langtools/test/tools/javac/modules/ModuleTestBase.java index 7ec771cde8d..5d5f20de153 100644 --- a/langtools/test/tools/javac/modules/ModuleTestBase.java +++ b/langtools/test/tools/javac/modules/ModuleTestBase.java @@ -53,4 +53,12 @@ public class ModuleTestBase extends TestRunner { 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 --git a/langtools/test/tools/javac/modules/ProvidesTest.java b/langtools/test/tools/javac/modules/ProvidesTest.java index bb3d84a30f3..cef2f522d9b 100644 --- a/langtools/test/tools/javac/modules/ProvidesTest.java +++ b/langtools/test/tools/javac/modules/ProvidesTest.java @@ -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 java.util.List; import toolbox.JavacTask; import toolbox.Task; +import toolbox.Task.Expect; import toolbox.ToolBox; public class ProvidesTest extends ModuleTestBase { @@ -415,24 +417,13 @@ public class ProvidesTest extends ModuleTestBase { 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 --git a/langtools/test/tools/javac/modules/T8168854/module-info.java b/langtools/test/tools/javac/modules/T8168854/module-info.java new file mode 100644 index 00000000000..696ce037420 --- /dev/null +++ b/langtools/test/tools/javac/modules/T8168854/module-info.java @@ -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 --git a/langtools/test/tools/javac/modules/T8168854/pack1/Outer.java b/langtools/test/tools/javac/modules/T8168854/pack1/Outer.java new file mode 100644 index 00000000000..ff272d594dd --- /dev/null +++ b/langtools/test/tools/javac/modules/T8168854/pack1/Outer.java @@ -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 --git a/langtools/test/tools/javac/modules/T8168854/pack1/Outer1.java b/langtools/test/tools/javac/modules/T8168854/pack1/Outer1.java new file mode 100644 index 00000000000..2710e62d3a3 --- /dev/null +++ b/langtools/test/tools/javac/modules/T8168854/pack1/Outer1.java @@ -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 --git a/langtools/test/tools/javac/modules/XModuleTest.java b/langtools/test/tools/javac/modules/XModuleTest.java index 5dc5d8f35dd..e8ef7ddc2b3 100644 --- a/langtools/test/tools/javac/modules/XModuleTest.java +++ b/langtools/test/tools/javac/modules/XModuleTest.java @@ -223,8 +223,7 @@ public class XModuleTest extends ModuleTestBase { .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 --git a/langtools/test/tools/javac/processing/model/nestedTypeVars/NestedTypeVars.java b/langtools/test/tools/javac/processing/model/nestedTypeVars/NestedTypeVars.java new file mode 100644 index 00000000000..24a62099efb --- /dev/null +++ b/langtools/test/tools/javac/processing/model/nestedTypeVars/NestedTypeVars.java @@ -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 --git a/langtools/test/tools/javac/processing/model/nestedTypeVars/NestedTypeVars.out b/langtools/test/tools/javac/processing/model/nestedTypeVars/NestedTypeVars.out new file mode 100644 index 00000000000..4592fef3528 --- /dev/null +++ b/langtools/test/tools/javac/processing/model/nestedTypeVars/NestedTypeVars.out @@ -0,0 +1,9 @@ +Test$1L1$L2$1L3$L4$L5 +Test$1L1$CCheck +Test$1L1 + test +Test$1CCheck +Test$CCheck +Test + m + test diff --git a/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestLoad.java b/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestLoad.java index cc0e3c5eba3..3440689f5cd 100644 --- a/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestLoad.java +++ b/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestLoad.java @@ -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 --git a/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java b/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java index 7ccffe7d6f3..230ccb91a59 100644 --- a/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java +++ b/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java @@ -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 @@ public class TestScan { 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 --git a/langtools/test/tools/jdeps/lib/JdepsRunner.java b/langtools/test/tools/jdeps/lib/JdepsRunner.java index 5be1892e0fc..5d93f2fbd5a 100644 --- a/langtools/test/tools/jdeps/lib/JdepsRunner.java +++ b/langtools/test/tools/jdeps/lib/JdepsRunner.java @@ -27,16 +27,19 @@ import java.io.PrintWriter; 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 @@ public class JdepsRunner { 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 class JdepsRunner { } 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 --git a/langtools/test/tools/jdeps/listdeps/ListModuleDeps.java b/langtools/test/tools/jdeps/listdeps/ListModuleDeps.java new file mode 100644 index 00000000000..1456fed1e19 --- /dev/null +++ b/langtools/test/tools/jdeps/listdeps/ListModuleDeps.java @@ -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 --git a/langtools/test/tools/jdeps/listdeps/src/lib/Lib.java b/langtools/test/tools/jdeps/listdeps/src/lib/Lib.java new file mode 100644 index 00000000000..abab7a68de5 --- /dev/null +++ b/langtools/test/tools/jdeps/listdeps/src/lib/Lib.java @@ -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 --git a/langtools/test/tools/jdeps/listdeps/src/z/Bar.java b/langtools/test/tools/jdeps/listdeps/src/z/Bar.java new file mode 100644 index 00000000000..66b40fb500b --- /dev/null +++ b/langtools/test/tools/jdeps/listdeps/src/z/Bar.java @@ -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 --git a/langtools/test/tools/jdeps/listdeps/src/z/Foo.java b/langtools/test/tools/jdeps/listdeps/src/z/Foo.java new file mode 100644 index 00000000000..2de179a19ff --- /dev/null +++ b/langtools/test/tools/jdeps/listdeps/src/z/Foo.java @@ -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 --git a/langtools/test/tools/jdeps/listdeps/src/z/UseUnsafe.java b/langtools/test/tools/jdeps/listdeps/src/z/UseUnsafe.java new file mode 100644 index 00000000000..e7980d3d2d4 --- /dev/null +++ b/langtools/test/tools/jdeps/listdeps/src/z/UseUnsafe.java @@ -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 --git a/make/Bundles.gmk b/make/Bundles.gmk index 111d7cea4fa..989eb4aae69 100644 --- a/make/Bundles.gmk +++ b/make/Bundles.gmk @@ -256,7 +256,7 @@ ifneq ($(filter product-bundles, $(MAKECMDGOALS)), ) $(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 @@ ifneq ($(filter test-bundles, $(MAKECMDGOALS)), ) $(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 --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk index d05cfd6d3ae..473d7f98d1b 100644 --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -95,7 +95,7 @@ java.datatransfer_COPY := flavormap.properties ################################################################################ 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.accessibility_ADD_JAVAC_FLAGS := -Xlint:-exports ################################################################################ -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.hotspot.agent_COPY := .gif .png sa.js .properties ################################################################################ +jdk.editpad_COPY := .properties + +################################################################################ + jdk.internal.le_COPY := .properties ################################################################################ @@ -436,10 +440,6 @@ jdk.jdi_EXCLUDE_FILES += jdi-overview.html ################################################################################ -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)) @@ -476,6 +476,13 @@ jdk.localedata_COPY := _dict _th # data files and shouldn't go in the product 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 # diff --git a/make/CreateJmods.gmk b/make/CreateJmods.gmk index 4dcf1635be6..8f3748b6908 100644 --- a/make/CreateJmods.gmk +++ b/make/CreateJmods.gmk @@ -36,6 +36,7 @@ endif ################################################################################ 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 @@ endif # 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 @@ ifeq ($(EXTERNAL_BUILDJDK), false) 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 @@ $(JMODS_DIR)/$(MODULE).jmod: $(DEPS) --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 --git a/make/ExplodedImageOptimize.gmk b/make/ExplodedImageOptimize.gmk index 1a969cf4325..36c27d8ab37 100644 --- a/make/ExplodedImageOptimize.gmk +++ b/make/ExplodedImageOptimize.gmk @@ -39,6 +39,7 @@ ALL_MODULEINFO_CLASSES := $(wildcard $(JDK_OUTPUTDIR)/modules/*/module_info.clas $(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 --git a/jdk/make/GenerateClasslist.gmk b/make/GenerateLinkOptData.gmk similarity index 74% rename from jdk/make/GenerateClasslist.gmk rename to make/GenerateLinkOptData.gmk index 3863a57d670..43e388ddab4 100644 --- a/jdk/make/GenerateClasslist.gmk +++ b/make/GenerateLinkOptData.gmk @@ -31,7 +31,6 @@ default: all include $(SPEC) include MakeBase.gmk -include Tools.gmk include JarArchive.gmk ################################################################################ @@ -48,9 +47,9 @@ TARGETS += $(CLASSLIST_JAR) ################################################################################ -CLASSLIST_FILE := $(SUPPORT_OUTPUTDIR)/classlist/classlist - -JLI_TRACE_FILE := $(SUPPORT_OUTPUTDIR)/classlist/jli_trace.out +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. @@ -59,15 +58,30 @@ ifeq ($(EXTERNAL_BUILDJDK), true) endif $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXE_SUFFIX) $(CLASSLIST_JAR) - $(call MakeDir, $(@D)) - $(call LogInfo, Generating lib/classlist) + $(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) -TARGETS += $(CLASSLIST_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) ################################################################################ diff --git a/make/Images.gmk b/make/Images.gmk index ffe664be8ad..1af9698a218 100644 --- a/make/Images.gmk +++ b/make/Images.gmk @@ -113,8 +113,8 @@ JIMAGE_TARGET_FILE := bin/java$(EXE_SUFFIX) 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 @@ $(JDK_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(JMODS) \ $(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 @@ $(JRE_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(JMODS) \ $(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 @@ -359,25 +359,6 @@ $(JDK_IMAGE_DIR)/src.zip: $(SUPPORT_OUTPUTDIR)/src.zip 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. @@ -385,9 +366,9 @@ 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 --git a/make/InterimImage.gmk b/make/InterimImage.gmk index ba9f5622275..d22a7096be7 100644 --- a/make/InterimImage.gmk +++ b/make/InterimImage.gmk @@ -36,15 +36,15 @@ JIMAGE_TARGET_FILE := bin/java$(EXE_SUFFIX) 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 --git a/make/Javadoc.gmk b/make/Javadoc.gmk index d0a7c430e79..98bf06f2e28 100644 --- a/make/Javadoc.gmk +++ b/make/Javadoc.gmk @@ -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 @@ ALL_MODULE_SOURCE_DIRS := \ $(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 +CORE_INDEX_FILE := $(JAVADOC_OUTPUTDIR)/api/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 +# Symbols +TRADEMARK := ™ +COPYRIGHT_SYMBOL := &$(HASH)x00a9; +COPYRIGHT_TEXT := Copyright +ALL_RIGHTS_RESERVED := All rights reserved. -# Common bottom argument -define CommonBottom # year -
    $(call CopyrightLine,,$1,)
    -endef +# URLs +JAVADOC_BASE_URL := http://docs.oracle.com/javase/$(VERSION_SPECIFICATION)/docs +BUG_SUBMIT_URL := http://bugreport.java.com/bugreport/ -# 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 +################################################################################ +# Text snippets -# Common echo of option -define OptionOnly # opt - if [ "$(strip $1)" != "" ] ; then \ - $(PRINTF) "%s\n" "$(strip $1)"; \ - fi -endef +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 OptionPair # opt arg - $(PRINTF) "%s '%s'\n" "$(strip $1)" '$(strip $2)' -endef +COMMON_BOTTOM_ADDRESS := $(COMPANY_ADDRESS) +COMMON_BOTTOM_TEXT := $(BUG_SUBMIT_LINE)
    $(JAVA_TRADEMARK_LINE) -define OptionTrip # opt arg arg - $(PRINTF) "%s '%s' '%s'\n" "$(strip $1)" '$(strip $2)' '$(strip $3)' -endef - -# Core api bottom argument (with special sauce) -COREAPI_BOTTOM = $(BUG_SUBMIT_LINE)\ +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.
    \ -$(call CopyrightLine,$(COPYRIGHT_URL),$(FIRST_COPYRIGHT_YEAR),)\ -
    +see Java SE \ +Documentation. That documentation contains more detailed, \ +developer-targeted descriptions, with conceptual overviews, definitions of \ +terms, workarounds, and working code examples. -# Common javadoc options used by all bundles - -# This flag may be overridden from a custom makefile -DOCROOTPARENT_FLAG = -Xdocrootparent $(DOCS_BASE_URL) - -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: - -# 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 - - - -# 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 + +# 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. # -# Load custom Javadoc rules +# 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. # - -$(eval $(call IncludeCustomExtension, , Javadoc.gmk)) - -################################################################# - -# -# Default target is same as docs target, create core api and all others it can +# 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 # +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) -all: docs -docs: coredocs otherdocs + 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 -# -# Optional target which bundles all generated javadocs into a zip archive. -# The dependency on docs is handled in Main.gmk. -# + $1_DEPS += $(CORE_INDEX_FILE) + endif -zip-docs: $(JAVADOC_ARCHIVE) + ifneq ($$($1_OVERVIEW), ) + $1_DEPS += $$($1_OVERVIEW) + endif -############################################################# -# -# 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)
    + ifeq ($$($1_ENCODING), ) + $1_ENCODING := ascii + endif -# Overview file for core apis -COREAPI_OVERVIEW = $(JDK_TOPDIR)/src/java.base/share/classes/overview-core.html + ifeq ($$($1_DOCLINT), ) + $1_DOCLINT := all + endif -# The options and packages files -COREAPI_OPTIONS_FILE = $(DOCSTMPDIR)/coredocs.options -COREAPI_PACKAGES_FILE = $(DOCSTMPDIR)/coredocs.packages + ifeq ($$($1_DOC_TITLE), ) + $1_DOC_TITLE := $$($1_TITLE) + endif -# The modules required to be documented -COREAPI_MODULES = java.se.ee + ifeq ($$($1_WINDOW_TITLE), ) + $1_WINDOW_TITLE := $$(strip $$(subst $$(TRADEMARK),, $$($1_TITLE))) + endif -coredocs: $(COREAPI_INDEX_FILE) + ifeq ($$($1_HEADER_TITLE), ) + $1_HEADER_TITLE := $$(strip $$(subst $$(TRADEMARK),, $$($1_TITLE))) + endif + $1_HEADER := $$($1_HEADER_TITLE) -# Set relative location to core api document root -$(COREAPI_INDEX_FILE): GET2DOCSDIR=.. + $1_BOTTOM := $$(call GenerateBottom, $$($1_FIRST_COPYRIGHT_YEAR), \ + $$($1_BOTTOM_COPYRIGHT_URL), $$($1_BOTTOM_ADDRESS), $$($1_BOTTOM_TEXT)) -# 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) + # 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 -# 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)) >> $@ + $1_PACKAGES_VARDEPS := $$($1_PACKAGES) $$($1_PACKAGES_SINGLE_CLASS) + $1_PACKAGES_VARDEPS_FILE := $$(call DependOnVariable, $1_PACKAGES_VARDEPS, \ + $$($1_PACKAGES_FILE).vardeps) + + # 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 -# Create a file with the package names in it -$(COREAPI_PACKAGES_FILE): $(call PackageDependencies,$(CORE_PKGS)) - $(prep-target) - $(call PackageFilter,$(CORE_PKGS)) + # 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) -############################################################# -# -# docletapidocs -# + # 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 -ALL_OTHER_TARGETS += docletapidocs + $1_PACKAGE_DEPS := $$(call CacheFind, $$(wildcard $$(foreach p, \ + $$(subst .,/,$$(strip $$($1_PACKAGES))), \ + $$(addsuffix /$$p, $$(wildcard $$(JAVADOC_SOURCE_DIRS)))))) -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 + # 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) -# 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 output returned will be the index.html file + $1 := $$($1_INDEX_FILE) +endef -# The modules required to be documented -DOCLETAPI_MODULES = jdk.javadoc +################################################################################ -docletapidocs: $(DOCLETAPI_INDEX_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 -# Set relative location to core api document root -$(DOCLETAPI_INDEX_FILE): GET2DOCSDIR=$(DOCLETAPI2COREAPI)/.. +$(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), \ +)) -# 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) +TARGETS += $(coredocs) -# 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)/); \ - ) >> $@ +################################################################################ -# Create a file with the package names in it -$(DOCLETAPI_PACKAGES_FILE): $(call PackageDependencies,$(DOCLETAPI_PKGS)) - $(prep-target) - $(call PackageFilter,$(DOCLETAPI_PKGS)) +$(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), \ +)) -############################################################# -# -# old docletapidocs -# +TARGETS += $(docletapi) -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 +$(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), \ +)) -# 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 +TARGETS += $(old-docletapi) -# The modules required to be documented -OLD_DOCLETAPI_MODULES = jdk.javadoc +################################################################################ -olddocletapidocs: $(OLD_DOCLETAPI_INDEX_FILE) +# 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 -# Set relative location to core api document root -$(OLD_DOCLETAPI_INDEX_FILE): GET2DOCSDIR=$(OLD_DOCLETAPI2COREAPI)/.. +$(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), \ +)) -# 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) +TARGETS += $(tagletapi) -# 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)/); \ - ) >> $@ +################################################################################ -# 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)) +$(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), \ +)) -############################################################# -# -# tagletapidocs -# +TARGETS += $(domapi) -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 +################################################################################ -# 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 +$(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, \ +)) -# The modules required to be documented -TAGLETAPI_MODULES = jdk.javadoc +TARGETS += $(jdi) -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, 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, \ +)) -# 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 += $(jaas) -# 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)" ) > $@ +################################################################################ -############################################################# -# -# domapidocs -# +$(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, \ +)) -ALL_OTHER_TARGETS += domapidocs +TARGETS += $(jgss) -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 +################################################################################ -# 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, 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, \ +)) -# The modules required to be documented -DOMAPI_MODULES = java.xml,jdk.xml.dom +TARGETS += $(smartcardio) -domapidocs: $(DOMAPI_INDEX_FILE) +################################################################################ -# Set relative location to core api document root -$(DOMAPI_INDEX_FILE): GET2DOCSDIR=$(DOMAPI2COREAPI)/.. +$(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, \ +)) -# 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) +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)/); \ - ) >> $@ +################################################################################ -# 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, 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, \ +)) -############################################################# -# -# jpdadocs -# +TARGETS += $(jsobject) -ALL_OTHER_TARGETS += jpdadocs +################################################################################ -jpdadocs: jdidocs jdwpdocs jvmtidocs +$(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, \ +)) -############################################################# -# -# jdidocs -# +TARGETS += $(mgmt) -ALL_OTHER_TARGETS += jdidocs +################################################################################ -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 +$(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, \ +)) -# 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 +TARGETS += $(attach) -# The modules required to be documented -JDI_MODULES = jdk.jdi +################################################################################ -jdidocs: $(JDI_INDEX_FILE) +$(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, \ +)) -# Set relative location to core api document root -$(JDI_INDEX_FILE): GET2DOCSDIR=$(JDI2COREAPI)/.. +TARGETS += $(jconsole) -# 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) +################################################################################ -# 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)/); \ - ) >> $@ +# 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, \ +)) -# Create a file with the package names in it -$(JDI_PACKAGES_FILE): $(call PackageDependencies,$(JDI_PKGS)) - $(prep-target) - $(call PackageFilter,$(JDI_PKGS)) +TARGETS += $(jshellapi) -############################################################# -# -# jdwpdocs -# +################################################################################ -ALL_OTHER_TARGETS += jdwpdocs +$(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, \ +)) -JDWP_DOCDIR = $(PLATFORM_DOCSDIR)/jpda/jdwp +TARGETS += $(treeapi) -jdwpdocs: $(JDWP_DOCDIR)/jdwp-protocol.html -$(JDWP_DOCDIR)/jdwp-protocol.html : $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/jdwp-protocol.html - $(MKDIR) -p $(@D) - $(RM) $@ - $(CP) $< $@ +################################################################################ -############################################################# -# -# jvmtidocs -# +$(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, \ +)) + +TARGETS += $(nashornapi) + +################################################################################ + +$(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) + +################################################################################ + +$(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, \ +)) + +TARGETS += $(jdknet) + +################################################################################ + +# 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) + +################################################################################ +# Copy JDWP html file + +JDWP_HTML := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/jdwp-protocol.html + +$(eval $(call SetupCopyFiles, COPY_JDWP_HTML, \ + FILES := $(JDWP_HTML), \ + DEST := $(JAVADOC_OUTPUTDIR)/platform/jpda/jdwp, \ +)) + +COPY_TARGETS += $(COPY_JDWP_HTML) + +################################################################################ +# Copy JVMTI html file -JVMTI_DOCDIR := $(PLATFORM_DOCSDIR)/jvmti # 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) +COPY_TARGETS += $(COPY_JVMTI_HTML) -############################################################# -# -# jaasdocs -# +################################################################################ +# Optional target which bundles all generated javadocs into a zip archive. +# The dependency on docs is handled in Main.gmk. -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)) - -############################################################# -# -# 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)) - -############################################################# -# -# 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 @@ $(JAVADOC_ARCHIVE): $(COREAPI_INDEX_FILE) $(ZIP) -q -r $(JAVADOC_ARCHIVE) * ; \ popd ; -############################################################# -.PHONY: all docs coredocs otherdocs \ - $(ALL_OTHER_TARGETS) zip-docs +ZIP_TARGETS += $(JAVADOC_ARCHIVE) ################################################################################ -$(eval $(call IncludeCustomExtension, , Javadoc-post.gmk)) +# Hook to include the corresponding custom file, if present. +$(eval $(call IncludeCustomExtension, , Javadoc.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 --git a/make/Main.gmk b/make/Main.gmk index cad7b5b19f5..60c705d011d 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -341,15 +341,15 @@ ALL_TARGETS += source-tips create-hgtip-files bootcycle-images zip-security \ # 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 @@ ALL_TARGETS += create-buildjdk-copy create-buildjdk-interim-image # 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 @@ else # 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 @@ else 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 @@ else 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 @@ else 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 @@ else 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 @@ ifeq ($(OPENJDK_TARGET_OS), macosx) 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_DIRS += demos 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 @@ clean: $(CLEAN_DIR_TARGETS) ($(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 @@ dist-clean: clean ) $(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 --git a/make/MainSupport.gmk b/make/MainSupport.gmk index e5cf8404f8d..efd6b0395b1 100644 --- a/make/MainSupport.gmk +++ b/make/MainSupport.gmk @@ -41,6 +41,15 @@ define RunTests 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 @@ define Clean-include @$(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 --git a/make/ZipSource.gmk b/make/ZipSource.gmk index a83d1d74cbc..1e998c8f756 100644 --- a/make/ZipSource.gmk +++ b/make/ZipSource.gmk @@ -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 @@ default: all 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)) \ + ) \ +) -# 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*))) +TARGETS += $(SRC_ZIP_SRCS) -# 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))) +################################################################################ +# 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, \ + )) + + 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 --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index 5ec0fa43b0d..c54d7f5c640 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -454,7 +454,7 @@ define NamedParamsMacroTemplate 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 @@ RelativePath = \ $($(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 --git a/make/common/Modules.gmk b/make/common/Modules.gmk index 9f1482e0c64..bb1d05979dd 100644 --- a/make/common/Modules.gmk +++ b/make/common/Modules.gmk @@ -108,6 +108,7 @@ PLATFORM_MODULES += \ jdk.charsets \ jdk.crypto.ec \ jdk.crypto.pkcs11 \ + jdk.desktop \ jdk.dynalink \ jdk.jsobject \ jdk.localedata \ @@ -177,6 +178,16 @@ FindAllModuleInfos = \ $(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 @@ FindAllModules = \ $(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 --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk index 3f77173388b..e94ea5e479e 100644 --- a/make/common/NativeCompilation.gmk +++ b/make/common/NativeCompilation.gmk @@ -746,9 +746,10 @@ define SetupNativeCompilationBody # 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 --git a/make/common/ZipArchive.gmk b/make/common/ZipArchive.gmk index 4fdd235c5a7..80fb28f48fe 100644 --- a/make/common/ZipArchive.gmk +++ b/make/common/ZipArchive.gmk @@ -73,6 +73,11 @@ define SetupZipArchiveBody 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 --git a/nashorn/.hgtags b/nashorn/.hgtags index 0204d6b2b1d..edcfefd25c1 100644 --- a/nashorn/.hgtags +++ b/nashorn/.hgtags @@ -375,3 +375,5 @@ f11b8f5c4ccbf9c87d283815abac6c0117fba3c0 jdk-9+136 e3b11296395b39bfeb3364f26c2ef77fa652e300 jdk-9+139 785843878cf78d50cc2959ea2c5a4202bbe885b4 jdk-9+140 a46b7d3867957a868a6cc8ee66c05079b883733a jdk-9+141 +d3f5d7311a1aec3152b17d75046d5d298245a0b4 jdk-9+142 +b4e57ead3fae4939b70dd345d1f6744a1dedfa21 jdk-9+143 diff --git a/nashorn/samples/dynalink/ArrayStreamLinkerExporter.java b/nashorn/samples/dynalink/ArrayStreamLinkerExporter.java index 309f1e66f10..348ef3f9f79 100644 --- a/nashorn/samples/dynalink/ArrayStreamLinkerExporter.java +++ b/nashorn/samples/dynalink/ArrayStreamLinkerExporter.java @@ -38,9 +38,10 @@ import java.util.stream.IntStream; 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 @@ public final class ArrayStreamLinkerExporter extends GuardingDynamicLinkerExport 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 --git a/nashorn/samples/dynalink/BufferIndexingLinkerExporter.java b/nashorn/samples/dynalink/BufferIndexingLinkerExporter.java index 9f49a0cdef0..8fb99c1f090 100644 --- a/nashorn/samples/dynalink/BufferIndexingLinkerExporter.java +++ b/nashorn/samples/dynalink/BufferIndexingLinkerExporter.java @@ -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.nio.ShortBuffer; 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 @@ public final class BufferIndexingLinkerExporter extends GuardingDynamicLinkerExp 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 @@ public final class BufferIndexingLinkerExporter extends GuardingDynamicLinkerExp } 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 --git a/nashorn/samples/dynalink/DOMLinkerExporter.java b/nashorn/samples/dynalink/DOMLinkerExporter.java index 7724fd5b0c3..c544c9b7234 100644 --- a/nashorn/samples/dynalink/DOMLinkerExporter.java +++ b/nashorn/samples/dynalink/DOMLinkerExporter.java @@ -35,9 +35,10 @@ import java.lang.invoke.MethodType; 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 @@ public final class DOMLinkerExporter extends GuardingDynamicLinkerExporter { 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 --git a/nashorn/samples/dynalink/MissingMethodLinkerExporter.java b/nashorn/samples/dynalink/MissingMethodLinkerExporter.java index e68b8d7ba43..2ebb78b4abe 100644 --- a/nashorn/samples/dynalink/MissingMethodLinkerExporter.java +++ b/nashorn/samples/dynalink/MissingMethodLinkerExporter.java @@ -35,9 +35,10 @@ import java.lang.invoke.MethodType; 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 @@ public final class MissingMethodLinkerExporter extends GuardingDynamicLinkerExpo "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 @@ public final class MissingMethodLinkerExporter extends GuardingDynamicLinkerExpo // 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 @@ public final class MissingMethodLinkerExporter extends GuardingDynamicLinkerExpo } 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 --git a/nashorn/samples/dynalink/UnderscoreNameLinkerExporter.java b/nashorn/samples/dynalink/UnderscoreNameLinkerExporter.java index 60251834fd9..fe60aae86e8 100644 --- a/nashorn/samples/dynalink/UnderscoreNameLinkerExporter.java +++ b/nashorn/samples/dynalink/UnderscoreNameLinkerExporter.java @@ -34,9 +34,10 @@ import java.util.List; 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 @@ public final class UnderscoreNameLinkerExporter extends GuardingDynamicLinkerExp 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 @@ public final class UnderscoreNameLinkerExporter extends GuardingDynamicLinkerExp @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 @@ public final class UnderscoreNameLinkerExporter extends GuardingDynamicLinkerExp 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 --git a/nashorn/samples/dynalink/underscore_linker.js b/nashorn/samples/dynalink/underscore_linker.js index 98acd9e3fdb..82ad554de73 100644 --- a/nashorn/samples/dynalink/underscore_linker.js +++ b/nashorn/samples/dynalink/underscore_linker.js @@ -46,5 +46,6 @@ $EXEC.throwOnError=true // but make sure classpath points to the pluggable linker jar! `jjs -cp underscore_linker.jar underscore.js` +print($ERR) print($OUT) diff --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java index 96a8269edfd..e5ada585046 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java @@ -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,43 +150,81 @@ public class CallSiteDescriptor extends SecureLookupSupplier { } /** - * 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, @@ -255,4 +295,16 @@ public class CallSiteDescriptor extends SecureLookupSupplier { 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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/CompositeOperation.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/CompositeOperation.java deleted file mode 100644 index 94581f4d058..00000000000 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/CompositeOperation.java +++ /dev/null @@ -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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java index 8eaa42fcc9c..d2b23369183 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java @@ -88,15 +88,47 @@ import java.util.Objects; /** * 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 final class NamedOperation implements Operation { */ 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"); @@ -138,6 +170,16 @@ public final class NamedOperation implements Operation { return name; } + /** + * 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 diff --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java new file mode 100644 index 00000000000..0785f64bf38 --- /dev/null +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java @@ -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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java new file mode 100644 index 00000000000..26173c88160 --- /dev/null +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java @@ -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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java index 1afdd6ef784..e73e88fa79a 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java @@ -86,14 +86,51 @@ package jdk.dynalink; /** * 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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java new file mode 100644 index 00000000000..af0b25b42bb --- /dev/null +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java @@ -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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java index 7fbc9430ce7..e5acb1b55a0 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java @@ -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, + GET, /** - * Set the value of a property defined on an object. 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, propertyName, 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_PROPERTY, + SET, /** - * Get the value of an element of a collection. 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, value)→void when used with {@link NamedOperation}, - * with all parameters and return type being of any type (either primitive - * or reference). - */ - 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, - /** - * 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 @@ public enum StandardOperation implements Operation { */ 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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java index 75c5065d525..f648a81f0ca 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java @@ -99,9 +99,11 @@ import java.util.List; 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { if (gic != null) { return gic; } - return getNextComponent(req.popOperations()); + return getNextComponent(req.popNamespace()); } private GuardedInvocationComponent createNoSuchMemberHandler( @@ -626,8 +618,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { // 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { @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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java index 3f98c2b82f2..d865ec54ede 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java @@ -92,7 +92,9 @@ import java.util.Collections; 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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL 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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL 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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL 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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java index 4ea49f2e560..5ba5626a443 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java @@ -87,6 +87,7 @@ import java.lang.invoke.MethodHandles.Lookup; 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 @@ import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker; *
      *
    • 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 @@ import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker; *

      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 @@ public class BeansLinker implements GuardingDynamicLinker { /** * 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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java index 9f1cf1ce5b1..3e79926c898 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java @@ -88,6 +88,7 @@ import java.lang.invoke.MethodHandles; 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 @@ import jdk.dynalink.linker.support.Guards; /** * 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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java index 8a3e48acfbb..0e3f8325ab6 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java @@ -87,7 +87,7 @@ import java.lang.invoke.MethodHandle; 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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java index 432b18aee16..748885ac9fa 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java @@ -92,7 +92,7 @@ import jdk.dynalink.StandardOperation; * 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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java index c81e8d1f8d8..94d8eb88c6e 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java @@ -91,7 +91,7 @@ import java.util.Arrays; 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 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker { 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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java index e68bf14f49d..b89f4c2de4d 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java @@ -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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java index e0785e66f32..fdc828b50b1 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java @@ -343,7 +343,7 @@ final class AssignSymbols extends SimpleNodeVisitor implements Loggable { 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java index 06ffe2d5e53..81a05397c45 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java @@ -45,6 +45,7 @@ import jdk.nashorn.internal.ir.BreakNode; 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.JumpToInlinedFinally; 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.SwitchNode; 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.ir.visitor.SimpleNodeVisitor; 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 @@ final class Lower extends NodeOperatorVisitor implements Lo 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 @@ final class Lower extends NodeOperatorVisitor implements Lo this.log = initLogger(compiler.getContext()); this.es6 = compiler.getScriptEnvironment()._es6; + this.source = compiler.getSource(); } @Override @@ -241,6 +249,10 @@ final class Lower extends NodeOperatorVisitor implements Lo } } + if (es6 && expressionStatement.destructuringDeclarationType() != null) { + throwNotImplementedYet("es6.destructuring", expressionStatement); + } + return addStatement(node); } @@ -249,6 +261,14 @@ final class Lower extends NodeOperatorVisitor implements Lo return addStatement(blockStatement); } + @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; @@ -269,6 +289,37 @@ final class Lower extends NodeOperatorVisitor implements Lo return newForNode; } + @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()); @@ -577,6 +628,29 @@ final class Lower extends NodeOperatorVisitor implements Lo return tryNode.setCatchBlocks(lc, newCatchBlocks); } + @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); @@ -608,6 +682,12 @@ final class Lower extends NodeOperatorVisitor implements Lo 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 @@ final class Lower extends NodeOperatorVisitor implements Lo } 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java index 136e5e0bcfd..e3b1edbfbdb 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java @@ -45,7 +45,7 @@ public abstract class NodeOperatorVisitor extends Node } @Override - public final boolean enterUnaryNode(final UnaryNode unaryNode) { + public boolean enterUnaryNode(final UnaryNode unaryNode) { switch (unaryNode.tokenType()) { case ADD: return enterADD(unaryNode); diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java index 0d318adb972..dc172a88683 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java @@ -48,7 +48,6 @@ import java.util.concurrent.ConcurrentHashMap; 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 @@ public final class Global extends Scope { } @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 @@ public final class Global extends Scope { } @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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java index 39ff22fc012..ac90b8bdf44 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java @@ -37,7 +37,6 @@ import java.util.ArrayList; 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 @@ public final class NativeJSAdapter extends ScriptObject { 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 @@ public final class NativeJSAdapter extends ScriptObject { } @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 @@ public final class NativeJSAdapter extends ScriptObject { } } - 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 @@ public final class NativeJSAdapter extends ScriptObject { } } throw typeError("no.such.function", name, ScriptRuntime.safeToString(this)); - default: - break; } - - throw new AssertionError("should not reach here"); } @Override @@ -544,7 +537,7 @@ public final class NativeJSAdapter extends ScriptObject { 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java index de0cabfb36a..72d144f5e20 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java @@ -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.List; 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 @@ public final class NativeObject { }); } + 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 @@ public final class NativeObject { 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 @@ public final class NativeObject { 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 @@ public final class NativeObject { 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 @@ public final class NativeObject { } } - 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java index ec1619e1b88..d91ffa49471 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java @@ -42,7 +42,6 @@ import java.util.List; 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 @@ public final class NativeString extends ScriptObject implements OptimisticBuilti // 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java index 5dfa4691a80..c609a0d18c7 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java @@ -1962,6 +1962,18 @@ public class Parser extends AbstractParser implements Loggable { 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java index 71f7728bd46..3a238dc5d8c 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java @@ -67,7 +67,6 @@ import java.util.Set; 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 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable { * @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 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable { case NEW: return findNewMethod(desc, request); default: + return null; } - return null; } /** @@ -1952,11 +1944,10 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable { * * @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 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable { } 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java index ac1aca5b46d..48a9f9251b4 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java @@ -32,7 +32,6 @@ import java.lang.invoke.MethodHandle; 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 @@ public final class Undefined extends DefaultPropertyAccess { * @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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java index 8caa26058c1..f58fc7de300 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java @@ -97,9 +97,6 @@ public final class WithObject extends Scope { 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 @@ public final class WithObject extends Scope { if (find != null) { link = expression.lookup(desc, request); if (link != null) { - return fixExpressionCallSite(ndesc, link); + return fixExpressionCallSite(desc, link); } } @@ -126,39 +123,30 @@ public final class WithObject extends Scope { // __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 @@ public final class WithObject extends Scope { 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java index 621f789ac36..3578ed80b97 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java @@ -35,7 +35,6 @@ import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObject 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 @@ final class BrowserJSObjectLinker implements TypeBasedGuardingDynamicLinker { 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java index 7471cc46154..af6de3202c7 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java @@ -33,6 +33,7 @@ import java.lang.invoke.MethodType; 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 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker { } 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java index 6629b1ada5d..8d525a7139c 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java @@ -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 @@ final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker { 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 class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker { 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 class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker { 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java index d2a46eae78f..ac2f7cb9b18 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java @@ -35,7 +35,9 @@ import java.lang.reflect.Modifier; 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.LinkerServices; 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 @@ public class NashornBeansLinker implements GuardingDynamicLinker { // 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 @@ public class NashornBeansLinker implements GuardingDynamicLinker { // 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java index d977129c046..bd4ab24fe27 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java @@ -38,7 +38,6 @@ import java.util.function.Supplier; 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 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo 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 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo 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 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java index 25999d1f5df..71f9f47b2f6 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java @@ -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.ConcurrentHashMap; 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 @@ public final class NashornCallSiteDescriptor extends CallSiteDescriptor { // 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 @@ public final class NashornCallSiteDescriptor extends CallSiteDescriptor { return existing; } } - final NamedOperation newOp = new NamedOperation(baseOp, name); + final NamedOperation newOp = baseOp.named(name); namedOps.put(name, new WeakReference<>(newOp)); return newOp; } @@ -287,16 +294,6 @@ public final class NashornCallSiteDescriptor extends CallSiteDescriptor { return super.hashCode() ^ flags; } - /** - * 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 @@ -311,70 +308,63 @@ public final class NashornCallSiteDescriptor extends CallSiteDescriptor { return operation instanceof NamedOperation ? ((NamedOperation)operation).getName().toString() : null; } - /** - * 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. - */ - public StandardOperation getFirstOperation() { - final Operation base = NamedOperation.getBaseOperation(getOperation()); - if (base instanceof CompositeOperation) { - return (StandardOperation)((CompositeOperation)base).getOperation(0); - } - return (StandardOperation)base; + private static StandardNamespace findFirstStandardNamespace(final CallSiteDescriptor desc) { + return StandardNamespace.findFirst(desc.getOperation()); } /** - * Returns the first standard operation in the (potentially composite) - * operation of the passed call site descriptor. + * 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 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 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 @@ public final class NashornCallSiteDescriptor extends CallSiteDescriptor { * @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 final class NashornCallSiteDescriptor extends CallSiteDescriptor { 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java index 4a7c8d7b639..5a321d0d1ed 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java @@ -99,10 +99,8 @@ public final class PrimitiveLookup { 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 @@ public final class PrimitiveLookup { } } break; - case SET_PROPERTY: - case SET_ELEMENT: + case SET: return getPrimitiveSetter(name, guard, wrapFilter, NashornCallSiteDescriptor.isStrict(desc)); default: break; diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java index 7c94ebcfc10..a168fe1b7d0 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java @@ -30,6 +30,7 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 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 @@ final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{ // 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties index 0116fb4d452..2c84781e35f 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties @@ -214,6 +214,7 @@ syntax.error.invalid.json=Invalid JSON: {0} 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 @@ config.error.eagerCompilationConflictsWithOptimisticTypes={0}=false (eager compi 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 --git a/langtools/test/tools/javac/diags/examples/XaddexportsMalformedEntry.java b/nashorn/test/script/basic/es6/class.js similarity index 84% rename from langtools/test/tools/javac/diags/examples/XaddexportsMalformedEntry.java rename to nashorn/test/script/basic/es6/class.js index 326a2b17f87..8897e2571ad 100644 --- a/langtools/test/tools/javac/diags/examples/XaddexportsMalformedEntry.java +++ b/nashorn/test/script/basic/es6/class.js @@ -1,28 +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. */ -// key: compiler.err.xaddexports.malformed.entry -// options: --add-exports jdk.compiler/com.sun.tools.javac.util +/** + * Class declaration is not implemented + * + * @test + * @run + * @option --language=es6 + */ -public class XaddexportsMalformedEntry { +try { + eval("class Foo {}"); +} catch (e) { + print(String(e).replace(/\\/g, "/")) } diff --git a/nashorn/test/script/basic/es6/class.js.EXPECTED b/nashorn/test/script/basic/es6/class.js.EXPECTED new file mode 100644 index 00000000000..0d457c9bcbc --- /dev/null +++ b/nashorn/test/script/basic/es6/class.js.EXPECTED @@ -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 --git a/nashorn/test/script/basic/es6/destructuring.js b/nashorn/test/script/basic/es6/destructuring.js new file mode 100644 index 00000000000..a7f7a59de04 --- /dev/null +++ b/nashorn/test/script/basic/es6/destructuring.js @@ -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 --git a/nashorn/test/script/basic/es6/destructuring.js.EXPECTED b/nashorn/test/script/basic/es6/destructuring.js.EXPECTED new file mode 100644 index 00000000000..65e2eda1dc9 --- /dev/null +++ b/nashorn/test/script/basic/es6/destructuring.js.EXPECTED @@ -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 --git a/nashorn/test/script/basic/es6/generator.js b/nashorn/test/script/basic/es6/generator.js new file mode 100644 index 00000000000..88d8a0fa06b --- /dev/null +++ b/nashorn/test/script/basic/es6/generator.js @@ -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 --git a/nashorn/test/script/basic/es6/generator.js.EXPECTED b/nashorn/test/script/basic/es6/generator.js.EXPECTED new file mode 100644 index 00000000000..fe4b850a1d5 --- /dev/null +++ b/nashorn/test/script/basic/es6/generator.js.EXPECTED @@ -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 --git a/nashorn/test/script/basic/es6/restparam.js b/nashorn/test/script/basic/es6/restparam.js new file mode 100644 index 00000000000..5db7f0b62d8 --- /dev/null +++ b/nashorn/test/script/basic/es6/restparam.js @@ -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 --git a/nashorn/test/script/basic/es6/restparam.js.EXPECTED b/nashorn/test/script/basic/es6/restparam.js.EXPECTED new file mode 100644 index 00000000000..9ccc374acac --- /dev/null +++ b/nashorn/test/script/basic/es6/restparam.js.EXPECTED @@ -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 --git a/nashorn/test/script/basic/es6/spread.js b/nashorn/test/script/basic/es6/spread.js new file mode 100644 index 00000000000..d90236e80a9 --- /dev/null +++ b/nashorn/test/script/basic/es6/spread.js @@ -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 --git a/nashorn/test/script/basic/es6/spread.js.EXPECTED b/nashorn/test/script/basic/es6/spread.js.EXPECTED new file mode 100644 index 00000000000..635f705599a --- /dev/null +++ b/nashorn/test/script/basic/es6/spread.js.EXPECTED @@ -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 --git a/nashorn/test/script/basic/es6/super.js b/nashorn/test/script/basic/es6/super.js new file mode 100644 index 00000000000..612d6cf46ac --- /dev/null +++ b/nashorn/test/script/basic/es6/super.js @@ -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 --git a/nashorn/test/script/basic/es6/super.js.EXPECTED b/nashorn/test/script/basic/es6/super.js.EXPECTED new file mode 100644 index 00000000000..25698576979 --- /dev/null +++ b/nashorn/test/script/basic/es6/super.js.EXPECTED @@ -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 --git a/nashorn/test/script/basic/jsadapter-ids.js b/nashorn/test/script/basic/jsadapter-ids.js index fa2f1a0aef9..9631f4c420d 100644 --- a/nashorn/test/script/basic/jsadapter-ids.js +++ b/nashorn/test/script/basic/jsadapter-ids.js @@ -30,6 +30,7 @@ var obj = new JSAdapter() { __getIds__: function() { + Assert.assertTrue(this === obj); print("__getIds__ called"); return [ "foo", "bar" ]; } diff --git a/nashorn/test/script/basic/jsadapter.js b/nashorn/test/script/basic/jsadapter.js index b4875720558..6755ffa70f5 100644 --- a/nashorn/test/script/basic/jsadapter.js +++ b/nashorn/test/script/basic/jsadapter.js @@ -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(delete obj.prop); 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 --git a/nashorn/test/script/basic/jsadapter.js.EXPECTED b/nashorn/test/script/basic/jsadapter.js.EXPECTED index 081048a793a..691cbf33736 100644 --- a/nashorn/test/script/basic/jsadapter.js.EXPECTED +++ b/nashorn/test/script/basic/jsadapter.js.EXPECTED @@ -20,3 +20,12 @@ js 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 --git a/nashorn/test/script/basic/jsadapterlink.js b/nashorn/test/script/basic/jsadapterlink.js index ed44d61e445..df9148f97f7 100644 --- a/nashorn/test/script/basic/jsadapterlink.js +++ b/nashorn/test/script/basic/jsadapterlink.js @@ -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 --git a/nashorn/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter b/nashorn/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter index f3139f7baa9..b3f34fe1070 100644 --- a/nashorn/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter +++ b/nashorn/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter @@ -1,2 +1,3 @@ jdk.dynalink.test.UntrustedGuardingDynamicLinkerExporter jdk.dynalink.test.TrustedGuardingDynamicLinkerExporter +jdk.dynalink.test.TrustedUnderscoreNameLinkerExporter diff --git a/nashorn/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java b/nashorn/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java index b74f6cc981d..44c009fdc0d 100644 --- a/nashorn/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java +++ b/nashorn/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java @@ -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.MethodHandles; 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 @@ public class BeanLinkerTest { } 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, @@ -208,26 +215,6 @@ public class BeanLinkerTest { Assert.assertEquals((int) cs.getTarget().invoke(new String[33], "length"), 33); } - @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); @@ -364,8 +351,7 @@ public class BeanLinkerTest { @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); @@ -388,24 +374,9 @@ public class BeanLinkerTest { Assert.assertEquals(clz, Date.class); } - @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 @@ public class BeanLinkerTest { 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 @@ public class BeanLinkerTest { // 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 @@ public class BeanLinkerTest { // 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 --git a/nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java b/nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java index 8ef147fab44..c5d28624de0 100644 --- a/nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java +++ b/nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java @@ -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.function.Predicate; 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 @@ public class BeansLinkerTest { @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 @@ public class BeansLinkerTest { @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 @@ public class BeansLinkerTest { @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 @@ public class BeansLinkerTest { @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 @@ public class BeansLinkerTest { @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 class BeansLinkerTest { 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 class BeansLinkerTest { 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 @@ public class BeansLinkerTest { 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 @@ public class BeansLinkerTest { } } - 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 @@ public class BeansLinkerTest { 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 --git a/nashorn/test/src/jdk/dynalink/support/test/CallSiteTest.java b/nashorn/test/src/jdk/dynalink/support/test/CallSiteTest.java index d33aa0abd0b..2649a9940e4 100644 --- a/nashorn/test/src/jdk/dynalink/support/test/CallSiteTest.java +++ b/nashorn/test/src/jdk/dynalink/support/test/CallSiteTest.java @@ -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 java.util.ArrayList; 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 @@ public class CallSiteTest { 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 @@ public class CallSiteTest { 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 @@ public class CallSiteTest { 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 --git a/nashorn/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java b/nashorn/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java index 2addefbb3e4..4199da2cda5 100644 --- a/nashorn/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java +++ b/nashorn/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java @@ -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 javax.script.ScriptEngineManager; 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 @@ import org.testng.annotations.Test; @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 @@ public class DynamicLinkerFactoryTest { 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 @@ public class DynamicLinkerFactoryTest { 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 @@ public class DynamicLinkerFactoryTest { 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 @@ public class DynamicLinkerFactoryTest { 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 @@ public class DynamicLinkerFactoryTest { // 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 --git a/nashorn/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java b/nashorn/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java index 8e2b03b6a67..00b56ba9af8 100644 --- a/nashorn/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java +++ b/nashorn/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java @@ -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 @@ public class LinkedCallSiteLocationTest { 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 --git a/nashorn/test/src/jdk/dynalink/test/TrustedUnderscoreNameLinkerExporter.java b/nashorn/test/src/jdk/dynalink/test/TrustedUnderscoreNameLinkerExporter.java new file mode 100644 index 00000000000..9b21da5022c --- /dev/null +++ b/nashorn/test/src/jdk/dynalink/test/TrustedUnderscoreNameLinkerExporter.java @@ -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 --git a/nashorn/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java b/nashorn/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java index 45d12641f30..56ed51eb148 100644 --- a/nashorn/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java @@ -104,11 +104,11 @@ public class ArrayConversionTest { @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 @@ public class ArrayConversionTest { 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 --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSPrintInfo.java b/nashorn/test/src/jdk/nashorn/api/scripting/test/JDK_8169050_Test.java similarity index 54% rename from jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSPrintInfo.java rename to nashorn/test/src/jdk/nashorn/api/scripting/test/JDK_8169050_Test.java index 7a33fdf22e2..357b7c44951 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/NSPrintInfo.java +++ b/nashorn/test/src/jdk/nashorn/api/scripting/test/JDK_8169050_Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, 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 @@ -22,43 +22,32 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package jdk.nashorn.api.scripting.test; -package sun.lwawt.macosx; +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; -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; + @BeforeClass + public void setupTest() { + engine = new ScriptEngineManager().getEngineByName("js"); } - 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"; + @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 --git a/test/Makefile b/test/Makefile index 41a20170e0e..49a47fd5230 100644 --- a/test/Makefile +++ b/test/Makefile @@ -74,13 +74,14 @@ jdk_% core_%s svc_%: 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 --git a/test/make/TestJavaCompilation.gmk b/test/make/TestJavaCompilation.gmk index f38d02c4327..9cd05b985ab 100644 --- a/test/make/TestJavaCompilation.gmk +++ b/test/make/TestJavaCompilation.gmk @@ -202,9 +202,9 @@ $(eval $(call SetupJarArchive, BUILD_JAR3, \ 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 --git a/test/make/TestMakeBase.gmk b/test/make/TestMakeBase.gmk index 8e40cf4aa81..547041b03f5 100644 --- a/test/make/TestMakeBase.gmk +++ b/test/make/TestMakeBase.gmk @@ -209,9 +209,9 @@ test-vardep: 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